|
|
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.