File: dir-tree.c

package info (click to toggle)
grafix 1.4-2
  • links: PTS
  • area: main
  • in suites: slink
  • size: 920 kB
  • ctags: 1,715
  • sloc: ansic: 14,080; makefile: 159; sh: 9
file content (130 lines) | stat: -rw-r--r-- 4,262 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// dir-tree.c 
//            wolf 10/95
// very simple demo for the Tree classes in grafix

#include "tree.h"
#include "files.h"

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

class DirTree;

typedef list <DirTree> Dlist;

// a popup window which appears when directory button is pressed
class dir_popup : public main_window {
  Bool unmapped;
  char entries[10000]; // the whole thing as one string
  int ent;
public:
  dir_popup(char *name, char *path, int ww, int wh, int x, int y) :
  main_window(name,ww,wh,1,x,y) {
    int nc = 0; // should be the length of text !!
    DIR *dirp = opendir(path);
    // if (dirp == 0)  printf("can't open %s\n",path);
    struct dirent *dp; 
    ent = 0; char *ep = entries+1; // why +1 ?????
    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
      int length = strlen(dp->d_name);
      if (dp->d_name[length-1] == '.') continue; 
      // if last char == . not display it ( . or .. )
      char *fina = new char[length+strlen(path)+2];
      sprintf(fina,"%s/%s",path,dp->d_name); // complete path
      struct stat st;
      if (!lstat(fina, &st)) {
	// boundary check for ep should take place
	sprintf(ep,"%8ld %-20s\n",st.st_size,dp->d_name);
	// on stupid SUNs sprintf returns char* instead of int (char count)!!!
	// so ep += sprintf(..) does not work there
	while (*ep) ep++; // get position of string end;
	ent++;
      }
    }
    new text_viewer(*this,ww,wh,0,0,entries,nc); 
    unmapped = True;
  } 
  void toggle() { // toggle between mappd/unmapped state
    int y = (13*ent + 6 <? height); // 13 = font height
    if (y < height) resize(width, y); // -> make window as small as needed
    if (unmapped) RealizeChildren(); else Unmap();
    unmapped = ! unmapped;
  }
};

class DirTree : public Tree {
  char *path;
  dir_popup *dir_pop;
public:
  DirTree(char *name, char *path, DirTree *parent = 0) : 
  Tree(name,parent), path(path) { dir_pop = 0; }
  // popup a window with directory content
  virtual void Press_cb(XButtonEvent *ev) {
    if (dir_pop == 0) {
      char title[200]; sprintf(title,"%s",path); 
      // raise popup just below the button, second press unmaps again
      dir_pop = new dir_popup(title,path, 400, 200, ev->x_root, ev->y_root+20);
    }
    dir_pop->toggle();
  }
  virtual void Enter_cb(window *infw) { infw->clear(); infw->PlaceText(path); }

};

char *help_text[] = { 
  "call with directory name (default = $HOME)","",
  "button press pops up the contents of directory",0 };

class Dir_main : public Tree_main {
public: 
  Dir_main(char * WMName, int w, int h) : 
  Tree_main(WMName,w,h, lin_tree) {
    new help_button(*mb,"help",help_text);
  }
  // virtual void init() { Tree_main::init(); }
};

// recursively read directory tree, parent the parent Node 
void rec_dir(char *path, DirTree* parent) {
  printf("reading directory %s\n",path);
  DIR *dirp = opendir(path);
  if (dirp == 0) printf("can't open %s\n",path);
  struct dirent *dp; 
  for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
    int length = strlen(dp->d_name);
    if (dp->d_name[length-1] != '.') { // not for . or .. file
      int plen = strlen(path); 
      if (path[plen-1] == '/') path[plen-1] = 0; // eliminate tail-slashes
      char *fina = new char[length+strlen(path)+2];
      sprintf(fina,"%s/%s",path,dp->d_name); // complete path
      struct stat st;
      if (!lstat(fina, &st) && S_ISDIR(st.st_mode)) {
	// *** problem with symbolic links : how to exclude ???? ***
	// **********     use 'lstat' instead of 'stat'     ************
	// ********** !!!! because 'stat' follows the links !!! ********
	// printf("reading directory %s %o\n",fina,st.st_mode);
	char *tail = strrchr(fina,'/'); // eliminate trailing path
	if (tail == 0) tail = fina; else tail++;
	DirTree *dt = new DirTree(tail,fina,parent);
	rec_dir(fina,dt);
      }
    }
  }
  closedir(dirp);
}

// if commandline arg given use it as search path, else use ".."
int main(int argc, char* argv[]) {
  char *path = (argc > 1) ? argv[1] : getenv("HOME");
  DirTree *top = new DirTree(path,path);
  rec_dir(path,top);
  Dir_main *mw = new Dir_main(argv[0],400,450);
  mw->init();
  mw->main_loop();

}