File:  [OS/2 SDKs] / os2sdk / demos / apps / ds / tree.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:26:02 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: os2sdk-1988, HEAD
Microsoft OS/2 SDK 03-01-1988

/*  tree.c - build and maintain directory tree	*/
/*  Created by Microsoft Corp. 1986		*/


#include <malloc.h>
#include <memory.h>
#include <stdio.h>

#include "ds.h"
#include "vars.h"

/*  Local variables */

static int ImageExists=FALSE;		/* TRUE if image has been created */


/***	decorateTree - Decorate directory tree and build screen image
*
*
*/
decorateTree (root)
Directory *root;
{
    LastRow = -1;
    newLine ();
    decorateSubTree (root, 0);
    ImageExists = TRUE; 		/* Set flag for newLine() */
}   /* decorateTree */


/***	decorateSubTree - Recursive portion called by decorateTree
*
*
*/
decorateSubTree (par, level)
Directory *par;
int level;
{
    Directory *p;
    int col,first;

    first = TRUE;
    col = level*D_INDENT;
    p = par->d_child;
    while (p) {
	if (first)		    /* First subdir at this level */
	    first = FALSE;	    /* show on same row as parent */
	else			    /* Not first at this level */
	    newLine();		    /* Show underneath previous one */
	p->d_row = LastRow;
	p->d_col = col;
	addImage (p,level);	    /* Add image for this directory */
	decorateSubTree (p, level+1);  /* Process subtree */
	p = p->d_next;
    }	/* while */
}   /* decorateSubTree */


/***	addImage - add image of one directory into screen image
*
*
*/
addImage (p,level)
Directory *p;
int level;
{
    Directory *par;
    int pLen,bLen,bCol;
    char buf[MAX_COLS+1];
    int parRow;
    int row;
    int col;
    int distance;
    cellType *c;

    par = p->d_parent;			    /* Get parent pointer */
    modLine (p->d_col, p->d_name, color[nameC]); /* Put directory name in image */
    if (level > 0)  {			    /* Draw line to parent */
	distance = p->d_row - par->d_row;
	if (distance == 0) {		    /* Parent on same row */
	    pLen = strlen (par->d_name);
	    bLen = D_INDENT - pLen;	    /* Length of bar */
	    bCol = par->d_col+pLen;
	    buf[bLen] = '\0';		    /* Store string terminator */
	    memset (buf,LR_CHAR,bLen);	    /* Store bar in buffer */
	    modLine (bCol, buf, color[barC]);	   /* Put bar in image */
	}
	else {				    /* Parent is above */
	    bLen = D_INDENT;
	    bCol = par->d_col;
	    buf[bLen] = '\0';		    /* Store string terminator */
	    memset (buf,LR_CHAR,bLen);	    /* Store bar in buffer */
	    buf[0] = RT_CHAR;		    /* Store angle char */
	    modLine (bCol, buf, color[barC]);	   /* Put bar in image */
	    row = LastRow-1;
	    col = par->d_col;
	    parRow = par->d_row;
	    while (row > parRow) {	    /* Finish path */
		c = &DisplayRow[row][col];
		switch (c->theChar) {
		    case ' ':
			c->theChar = BT_CHAR;
			c->theAttr = color[barC];
			row--;
			break;

		    case RT_CHAR:
			c->theChar = BRT_CHAR;
			row = 0;
			break;

		    default:
			row = 0;
			break;
		}   /* switch */
	    }	/* while */
	}   /* else (distance != 0) */
    }	/* if (level > 0) */
}   /* addImage */


/***	newLine - add a new line to the scree image
*
*
*/
newLine ()
{
    cellType *p;
    int i;

    if (++LastRow >= MAX_IMAGE_ROWS) {	    /* Too many image rows */
	fprintf (stderr, "\nDirectory image too large - Internal error.\n");
	exitError (2);
    }
    if (ImageExists)			    /* Get image row pointer */
	p = DisplayRow[LastRow];
    else				    /* Make new image row */
	p = 0;
    if (!p) {				    /* Have to make new image row */
	p = (cellType *) calloc(N_of_Cols,sizeof(cellType));
	if (!p) {
	    fprintf (stderr, "\nOut of memory - Allocating image line\n");
	    exitError (2);
	}
	DisplayRow[LastRow] = p;	    /* Store pointer to image row */
    }	/* if */
    for (i=0; i<N_of_Cols; i++) {	    /* Blank out row */
	p->theChar = ' ';
	p->theAttr = color[blankC];
	p++;
    }
}   /* newLine */


/***	modLine - store string with color in current line
*
*
*/
modLine (col, str, color)
int col;
NPCH str;
int color;
{
    cellType *p;
    char *s;

    s = str;
    p = &DisplayRow[LastRow][col];
    while (*s) {
	p->theChar = *s++;
	p->theAttr = color;
	p++;
    }	/* while */
}   /* modLine */


Canonicalize (fullPath, p, headPath)
NPCH fullPath;
Directory *p;
NPCH headPath;
{
    if (p->d_parent)
	Canonicalize (fullPath, p->d_parent, headPath);
    else
	strcat (fullPath, headPath);
    if (fullPath[strlen(fullPath)-1] != '\\')
	strcat (fullPath, "\\");
    strcat (fullPath, p->d_name);
}


/***	buildTree - scan directories breadth-first to build tree
*
*
*/
buildTree (par,parPath)
Directory *par;
NPCH parPath;
{
    char	 sName[MAX_PATH_LEN];	    /* Search path name */
    Directory	*child;
    int 	 errCode;
    int 	 sLen;
    Attr	 a;
    Cell	 c;
    Directory	*bfsHead;
    Directory	*bfsTail;
    FileSearch	 sBuf;		      /* Find First/Next buffer */
    unsigned	 sCount;	      /* Number of entries to search for */
    HDIR	 sHandle;	      /* Search Handle */

    bfsHead = par;
    bfsTail = par;
    c.ch = ' ';
    c.at = color[blankC];
    a = color[statusC];

    while (bfsHead) {
	sName[0] = '\0';
	Canonicalize (sName, bfsHead, parPath);

	sLen = strlen(sName);
	VioWrtCharStrAtt (chfs(sName), sLen, WINDOW_TOP,0, afs(&a), VioHandle);
	VioWrtNCell (cefs(&c), N_of_Cols-sLen, WINDOW_TOP,sLen, VioHandle);

	if (sName[sLen-1] == '\\')
	    strcat (sName, "*.*");
	else
	    strcat (sName, "\\*.*");
	sHandle = -1;			/* Family API only has one handle */
	sCount = 1;			/* Search for one at a time */
	errCode = DosFindFirst (chfs(sName),
				&sHandle,
				DosAttrSubDir,
				&sBuf,
				sizeof(sBuf),
				ufs(&sCount),
				0L);
	while (!errCode) {
	    if (sBuf.achName[0] != '.') { /* Not a back link */
		if (sBuf.attrFile & DosAttrSubDir) {  /* A subdirectory */
		    newDir (&child, sBuf.achName, bfsHead);
		    insDir (bfsHead, child, &bfsTail);
		    bfsTail->d_link = child;
		    bfsTail = child;
		}
	    }
	    errCode = DosFindNext (sHandle,
				   &sBuf,
				   sizeof(sBuf),
				   ufs(&sCount));
	}
	DosFindClose (sHandle);
	bfsHead = bfsHead->d_link;
    }
}   /* buildTree */


/***	insDir - insert child directory into tree in alphabetical order
*
*
*/
insDir (par,child)
Directory  *par;
Directory  *child;
{
    Directory *p,*q;

    p = par->d_child;			/* p = first child */
    q = 0;				/* q = previous pointer */
    while (p && (strcmp(child->d_name,p->d_name) > 0)) {
	q = p;				/* q = previous node */
	p = p->d_next;			/* p = next node */
    }
    if (!q)				/* Insert at front of list */
	par->d_child = child;
    else				/* Insert at middle or end of list */
	q->d_next = child;

    child->d_prev = q;
    child->d_next = p;

    if (p)				/* Not inserting at end of list */
	p->d_prev = child;
}   /* insDir */


/***	newDir - create a new directory entry for tree
*
*
*/
newDir (dir,name,par)
Directory **dir;
NPCH name;
Directory *par;
{
    Directory *p;

    p = (Directory *) malloc (sizeof(Directory));
    if (!p) {
	fprintf (stderr, "\nOut of memory - Allocating directory node\n");
       exitError (2);
    }
    p->d_name[0]   = '\0';
    strcpy (p->d_name,name);
    p->d_parent    = par;
    p->d_prev	   = 0;
    p->d_next	   = 0;
    p->d_child	   = 0;
    p->d_link	   = 0;

    *dir = p;			    /* Return address of new dir node */
}   /* newDir */


/***	pruneTree - prune subtree that has been deleted
*
*	Called when we discover that a directory no longer exists.
*
*	ENTRY:	root = address of pointer to directory node that has evaporated.
*
*	EXIT:	root = address of pointer to some other node that is "close"
*		       to the evaporated node.	Choose previous, next, or
*		       parent, in that order.
*/
pruneTree (curDir)
Directory **curDir;
{
    Directory *p;			/* Used to traverse tree */
    Directory *q;			/* Used to traverse tree */
    Directory *n;			/* Node to return */

    p = *curDir;			/* p = node to delete */
    if (n = p->d_prev) {		/* n = previous sibling */
	q = p->d_next;			/* q = next for n */
	n->d_next = q;			/* Point new node to new next */
	if (q)				/* Not last sibling */
	    q->d_prev = n;		/* Point next back to new node */
    }
    else				/* No previous sibling */
	if (n = p->d_next) {		/* n = next sibling */
	    n->d_prev = 0;		/* Next sibling is now first */
	    q = n->d_parent;		/* q = parent */
	    q->d_child = n;		/* Point parent to new first child */
	}
	else
	    if (n = p->d_parent)	/* n = parent */
		if (n->d_parent)	/* n is not root */
		    n->d_child = 0;	/* Deleted only child of parent */
		else {
		    fprintf (stderr, "directory tree is empty\n");
		    exit (2);
		}
	    else {
		fprintf (stderr, "directory tree is empty\n");
		exit (2);
	    };

    delDir (p); 			/* Delete subtree */
    decorateTree (root);		/* Re-build tree image */
    stateModified = TRUE;		/* Tree is modified */
    *curDir = n;			/* Return new node */

}   /* pruneTree */


/***	delDir - Delete directory subtree
*
*
*/
delDir (root)
Directory *root;
{
    Directory *p;
    Directory *q;

    p = root->d_child;			/* p = first child */
    while (p) { 			/* Still children to delete */
	q = p;
	p = p->d_next;
	delDir (q);
    }

    free ( (char *) root);

}   /* delDir */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.