|
|
1.1 root 1: /* tree.c - build and maintain directory tree */
2:
3: #include <malloc.h>
4: #include <memory.h>
5: #include <stdio.h>
6:
7: #include "ds.h"
8: #include "vars.h"
9:
10: /* Local variables */
11:
12: static int ImageExists=FALSE; /* TRUE if image has been created */
13:
14:
15: /*** decorateTree - Decorate directory tree and build screen image
16: *
17: *
18: */
19: decorateTree (root)
20: Directory *root;
21: {
22: LastRow = -1;
23: newLine ();
24: decorateSubTree (root, 0);
25: ImageExists = TRUE; /* Set flag for newLine() */
26: } /* decorateTree */
27:
28:
29: /*** decorateSubTree - Recursive portion called by decorateTree
30: *
31: *
32: */
33: decorateSubTree (par, level)
34: Directory *par;
35: int level;
36: {
37: Directory *p;
38: int col,first;
39:
40: first = TRUE;
41: col = level*D_INDENT;
42: p = par->d_child;
43: while (p) {
44: if (first) /* First subdir at this level */
45: first = FALSE; /* show on same row as parent */
46: else /* Not first at this level */
47: newLine(); /* Show underneath previous one */
48: p->d_row = LastRow;
49: p->d_col = col;
50: addImage (p,level); /* Add image for this directory */
51: decorateSubTree (p, level+1); /* Process subtree */
52: p = p->d_next;
53: } /* while */
54: } /* decorateSubTree */
55:
56:
57: /*** addImage - add image of one directory into screen image
58: *
59: *
60: */
61: addImage (p,level)
62: Directory *p;
63: int level;
64: {
65: Directory *par;
66: int pLen,bLen,bCol;
67: char buf[MAX_COLS+1];
68: int parRow;
69: int row;
70: int col;
71: int distance;
72: cellType *c;
73:
74: par = p->d_parent; /* Get parent pointer */
75: modLine (p->d_col, p->d_name, color[nameC]); /* Put directory name in image */
76: if (level > 0) { /* Draw line to parent */
77: distance = p->d_row - par->d_row;
78: if (distance == 0) { /* Parent on same row */
79: pLen = strlen (par->d_name);
80: bLen = D_INDENT - pLen; /* Length of bar */
81: bCol = par->d_col+pLen;
82: buf[bLen] = '\0'; /* Store string terminator */
83: memset (buf,LR_CHAR,bLen); /* Store bar in buffer */
84: modLine (bCol, buf, color[barC]); /* Put bar in image */
85: }
86: else { /* Parent is above */
87: bLen = D_INDENT;
88: bCol = par->d_col;
89: buf[bLen] = '\0'; /* Store string terminator */
90: memset (buf,LR_CHAR,bLen); /* Store bar in buffer */
91: buf[0] = RT_CHAR; /* Store angle char */
92: modLine (bCol, buf, color[barC]); /* Put bar in image */
93: row = LastRow-1;
94: col = par->d_col;
95: parRow = par->d_row;
96: while (row > parRow) { /* Finish path */
97: c = &DisplayRow[row][col];
98: switch (c->theChar) {
99: case ' ':
100: c->theChar = BT_CHAR;
101: c->theAttr = color[barC];
102: row--;
103: break;
104:
105: case RT_CHAR:
106: c->theChar = BRT_CHAR;
107: row = 0;
108: break;
109:
110: default:
111: row = 0;
112: break;
113: } /* switch */
114: } /* while */
115: } /* else (distance != 0) */
116: } /* if (level > 0) */
117: } /* addImage */
118:
119:
120: /*** newLine - add a new line to the scree image
121: *
122: *
123: */
124: newLine ()
125: {
126: cellType *p;
127: int i;
128:
129: if (++LastRow >= MAX_IMAGE_ROWS) { /* Too many image rows */
130: fprintf (stderr, "\nDirectory image too large - Internal error.\n");
131: exitError (2);
132: }
133: if (ImageExists) /* Get image row pointer */
134: p = DisplayRow[LastRow];
135: else /* Make new image row */
136: p = 0;
137: if (!p) { /* Have to make new image row */
138: p = (cellType *) calloc(N_of_Cols,sizeof(cellType));
139: if (!p) {
140: fprintf (stderr, "\nOut of memory - Allocating image line\n");
141: exitError (2);
142: }
143: DisplayRow[LastRow] = p; /* Store pointer to image row */
144: } /* if */
145: for (i=0; i<N_of_Cols; i++) { /* Blank out row */
146: p->theChar = ' ';
147: p->theAttr = color[blankC];
148: p++;
149: }
150: } /* newLine */
151:
152:
153: /*** modLine - store string with color in current line
154: *
155: *
156: */
157: modLine (col, str, color)
158: int col;
159: char *str;
160: int color;
161: {
162: cellType *p;
163: char *s;
164:
165: s = str;
166: p = &DisplayRow[LastRow][col];
167: while (*s) {
168: p->theChar = *s++;
169: p->theAttr = color;
170: p++;
171: } /* while */
172: } /* modLine */
173:
174:
175: Canonicalize (fullPath, p, headPath)
176: char *fullPath;
177: Directory *p;
178: char *headPath;
179: {
180: if (p->d_parent)
181: Canonicalize (fullPath, p->d_parent, headPath);
182: else
183: strcat (fullPath, headPath);
184: if (fullPath[strlen(fullPath)-1] != '\\')
185: strcat (fullPath, "\\");
186: strcat (fullPath, p->d_name);
187: }
188:
189:
190: /*** buildTree - scan directories breadth-first to build tree
191: *
192: *
193: */
194: buildTree (par,parPath)
195: Directory *par;
196: char *parPath;
197: {
198: char sName[MAX_PATH_LEN]; /* Search path name */
199: Directory *child;
200: int errCode;
201: int sLen;
202: Attr a;
203: Cell c;
204: Directory *bfsHead;
205: Directory *bfsTail;
206: FileSearch sBuf; /* Find First/Next buffer */
207: unsigned sCount; /* Number of entries to search for */
208: unsigned sHandle; /* Search Handle */
209:
210: bfsHead = par;
211: bfsTail = par;
212: c.ch = ' ';
213: c.at = color[blankC];
214: a = color[statusC];
215:
216: while (bfsHead) {
217: sName[0] = '\0';
218: Canonicalize (sName, bfsHead, parPath);
219:
220: sLen = strlen(sName);
221: VIOWRTCHARSTRATT (chfs(sName), sLen, WINDOW_TOP,0, afs(&a), VioHandle);
222: VIOWRTNCELL (cefs(&c), N_of_Cols-sLen, WINDOW_TOP,sLen, VioHandle);
223:
224: if (sName[sLen-1] == '\\')
225: strcat (sName, "*.*");
226: else
227: strcat (sName, "\\*.*");
228: sHandle = -1; /* Family API only has one handle */
229: sCount = 1; /* Search for one at a time */
230: errCode = DOSFINDFIRST (chfs(sName),
231: ufs(&sHandle),
232: DosAttrSubDir,
233: (FileSearch far *) &sBuf,
234: sizeof(sBuf),
235: ufs(&sCount),
236: 0L);
237: while (!errCode) {
238: if (sBuf.file_name[0] != '.') { /* Not a back link */
239: if (sBuf.attributes & DosAttrSubDir) { /* A subdirectory */
240: newDir (&child, sBuf.file_name, bfsHead);
241: insDir (bfsHead, child, &bfsTail);
242: bfsTail->d_link = child;
243: bfsTail = child;
244: }
245: }
246: errCode = DOSFINDNEXT (sHandle,
247: (FileSearch far *) &sBuf,
248: sizeof(sBuf),
249: ufs(&sCount));
250: }
251: DOSFINDCLOSE (sHandle);
252: bfsHead = bfsHead->d_link;
253: }
254: } /* buildTree */
255:
256:
257: /*** insDir - insert child directory into tree in alphabetical order
258: *
259: *
260: */
261: insDir (par,child)
262: Directory *par;
263: Directory *child;
264: {
265: Directory *p,*q;
266:
267: p = par->d_child; /* p = first child */
268: q = 0; /* q = previous pointer */
269: while (p && (strcmp(child->d_name,p->d_name) > 0)) {
270: q = p; /* q = previous node */
271: p = p->d_next; /* p = next node */
272: }
273: if (!q) /* Insert at front of list */
274: par->d_child = child;
275: else /* Insert at middle or end of list */
276: q->d_next = child;
277:
278: child->d_prev = q;
279: child->d_next = p;
280:
281: if (p) /* Not inserting at end of list */
282: p->d_prev = child;
283: } /* insDir */
284:
285:
286: /*** newDir - create a new directory entry for tree
287: *
288: *
289: */
290: newDir (dir,name,par)
291: Directory **dir;
292: char *name;
293: Directory *par;
294: {
295: Directory *p;
296:
297: p = (Directory *) malloc (sizeof(Directory));
298: if (!p) {
299: fprintf (stderr, "\nOut of memory - Allocating directory node\n");
300: exitError (2);
301: }
302: p->d_name[0] = '\0';
303: strcpy (p->d_name,name);
304: p->d_parent = par;
305: p->d_prev = 0;
306: p->d_next = 0;
307: p->d_child = 0;
308: p->d_link = 0;
309:
310: *dir = p; /* Return address of new dir node */
311: } /* newDir */
312:
313:
314: /*** pruneTree - prune subtree that has been deleted
315: *
316: * Called when we discover that a directory no longer exists.
317: *
318: * ENTRY: root = address of pointer to directory node that has evaporated.
319: *
320: * EXIT: root = address of pointer to some other node that is "close"
321: * to the evaporated node. Choose previous, next, or
322: * parent, in that order.
323: */
324: pruneTree (curDir)
325: Directory **curDir;
326: {
327: Directory *p; /* Used to traverse tree */
328: Directory *q; /* Used to traverse tree */
329: Directory *n; /* Node to return */
330:
331: p = *curDir; /* p = node to delete */
332: if (n = p->d_prev) { /* n = previous sibling */
333: q = p->d_next; /* q = next for n */
334: n->d_next = q; /* Point new node to new next */
335: if (q) /* Not last sibling */
336: q->d_prev = n; /* Point next back to new node */
337: }
338: else /* No previous sibling */
339: if (n = p->d_next) { /* n = next sibling */
340: n->d_prev = 0; /* Next sibling is now first */
341: q = n->d_parent; /* q = parent */
342: q->d_child = n; /* Point parent to new first child */
343: }
344: else
345: if (n = p->d_parent) /* n = parent */
346: if (n->d_parent) /* n is not root */
347: n->d_child = 0; /* Deleted only child of parent */
348: else {
349: fprintf (stderr, "directory tree is empty\n");
350: exit (2);
351: }
352: else {
353: fprintf (stderr, "directory tree is empty\n");
354: exit (2);
355: };
356:
357: delDir (p); /* Delete subtree */
358: decorateTree (root); /* Re-build tree image */
359: stateModified = TRUE; /* Tree is modified */
360: *curDir = n; /* Return new node */
361:
362: } /* pruneTree */
363:
364:
365: /*** delDir - Delete directory subtree
366: *
367: *
368: */
369: delDir (root)
370: Directory *root;
371: {
372: Directory *p;
373: Directory *q;
374:
375: p = root->d_child; /* p = first child */
376: while (p) { /* Still children to delete */
377: q = p;
378: p = p->d_next;
379: delDir (q);
380: }
381:
382: free ( (char *) root);
383:
384: } /* delDir */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.