Metropoli BBS
VIEWER: tree.c MODE: TEXT (ASCII)
/*
 * TREE command for MS-DOS
 *
 * This command is virtually identical to the MS-DOS TREE command,
 * except that it expands the current directory path instead of
 * showing '.' in the display.
 *
 * Copyright 1995 Dave Dunfield
 * Freely distributable.
 */
#include <stdio.h>
#include <file.h>

#define	DIRS	500				/* Depth of directory stacking */
#define	DEPTH	50				/* Depth of scanner recursion */

char
	*parg = 0,					/* Path argument */
	path[66],					/* Final path specification */
	full = 0,					/* Full listing specified */
	dirstack[DIRS][13],			/* Stack of directory names */
	*actstack[DEPTH];			/* Stack of active levels */

char
	*Vline = "\xB3\x20\x20",	/* Vertical line */
	*Vtee  = "\xC3\xC4\xC4",	/* Vertical/Horizonal tee */
	*Corn  = "\xC0\xC4\xC4",	/* Vertical/Horizontal corner */
	*Hline = "\xC4\xC4\xC4";	/* Horisontal line */

unsigned
	dirptr = 0,					/* Directory stacking level */
	level = 0;					/* Function recursion level */

static char help_text[] = { "\n\
Graphically displays the directory structure of a drive or path.\n\n\
TREE [drive:][path] [/F] [/A]\n\n\
  /F   Displays the names of the files in each directory.\n\
  /A   Uses ASCII instead of extended characters.\n\n\
Copyright 1995 Dave Dunfield - Freely distributable.\n" };

/*
 * Handle a single directory, recurse to do others
 */
void tree_path(void)
{
	unsigned plen, dirbase, i, j, k, attrs;
	char name[13], *ptr;

	/* Get all sibdirectory names in this dir */
	dirbase = dirptr;
	plen = strlen(path);
	strcpy(path+plen, "*.*");
	if(!find_first(path, -1, name, &k, &k, &attrs, &k, &k)) do {
		if((attrs & DIRECTORY) && (*name != '.')) {
			strcpy(dirstack[dirptr++], name);
			continue; } }
	while(!find_next(name, &k, &k, &attrs, &k, &k));

	/* Display files in this dir if required */
	actstack[level++] = (dirbase == dirptr) ? "   " : Vline;
	if(full) {
		i = 0;
		if(!find_first(path, -1, name, &k, &k, &attrs, &k, &k))  do {
			if(attrs & (DIRECTORY|VOLUME))
				continue;
			for(j=0; j < level; ++j)
				fputs(actstack[j], stdout);
			i = -1;
			printf("%s\n", name); }
		while(!find_next(name, &k, &k, &attrs, &k, &k));
		if(i) {
			for(j=0; j < level; ++j)
				fputs(actstack[j], stdout);
			putc('\n', stdout); } }

	/* Report of no subdirectories exist */
	if((dirbase == dirptr) && (level == 1))
		printf("No sub-directories exist\n");

	/* Recurse into subdirectories */
	for(i=dirbase; i < dirptr; ++i) {
		actstack[level-1] = ((i+1) != dirptr) ? Vtee : Corn;
		for(j=0; j < level; ++j)
			fputs(actstack[j], stdout);
		actstack[level-1] = ((i+1) != dirptr) ? Vline : "   ";
		printf("%s\n", ptr = dirstack[i]);
		strcpy(path+plen, ptr);
		strcat(path, "\\");
		tree_path(); }

	/* Restore entry conditions and exit */
	path[plen] = 0;
	dirptr = dirbase;
	--level;
}

/*
 * Main program - parse arguments & start recursive procedure
 */
main(int argc, char *argv[])
{
	int i;
	char *ptr, c;

	for(i=1; i < argc; ++i) {
		ptr = argv[i];
		while(*ptr) switch (c = *ptr++) {
			case '/' :		/* Option switch */
				switch(c = toupper(*ptr++)) {
					case 'A' :		/* Ascii - switch BOX characters */
						Vline = "|  ";
						Vtee  = "+--";
						Corn  = "\\--";
						Hline = "---";
						continue;
					case 'F' :		/* Select FULL mode */
						full = -1;
						continue;
					case '?' :		/* Help request */
						fputs(help_text, stdout);
						exit(0); }
				printf("Invalid switch - /%c\n", c);
				exit(-1);
			default:				/* Pathname */
				if(parg) {
					printf("Too many parameters - %s\n", argv[i]);
					exit(-1); }
				parg = argv[i];
				ptr = ""; } }

	/* If no path specified, default to current */
	if(!parg) {
		*(parg = help_text) = '\\';
		getdir(help_text+1); }

	/* If no drive name specified, obtain current drive */
	if(parg[1] == ':')
		strcpy(path, parg);
	else {
		*path = get_drive() + 'A';
		path[1] = ':';
		strcpy(path+2, parg); }

	/* Display volume label of disk */
	printf("Directory PATH listing");
	*help_text = *path;
	strcpy(help_text+1, ":\\*.*");
	if(!find_first(help_text, VOLUME, ptr = help_text, &i, &i, &i, &i, &i))  {
		printf(" for volume ");
		while(c = *ptr++)
			if(c != '.')
				putc(c, stdout); }

	/* Display path and append backslash if not given */
	printf("\n%s\n", path);
	switch(path[strlen(path)-1]) {
		default:
			strcat(path, "\\");
		case ':' :
		case '\\' : }

	/* Perform recursive function */
	tree_path();
}
[ RETURN TO DIRECTORY ]