[comp.sources.misc] VTREE - draws directory tree structure

lee@minnow.UUCP (Gene Lee ) (07/30/87)

[MUNCH]

----------------------------- cut here ----------------------------------

/*
             VTREE

	"vtree path" draws the directory tree structure starting at the path
	given as the parameter.

	Gene Lee  UUCP: ...ihnp4!{meccts,dayton,rosevax}!ems!minnow!lee
	UNISYS Corporation     ATT:  (612) 635-6334
*/

#include <stdio.h>
#include <ftw.h>
#include <sys/types.h> /* included because <sys/stat.h> needs it */
#include <sys/stat.h>  /* included to use STAT(2) structure in fn() */
#include <errno.h>     /* included to pick up error number */
#include <string.h>   /* included to use string functions */

int fn();
char *tail();

#define MAXDEPTH 100     /* maximum directory depth allowed */
#define DIRNAME_LENGTH 15 /* maximum number of chars in a directory name */
#define LEADGAP 5	  /* number of spaces in to start drawing first col */
#define CONNECT_CHAR "_" /* char used to connect node names in drawing */
#define BLANK_CHAR " "   /* char used to draw blanks when drawing */
#define BRANCH_CHAR "L"  /* char used to draw branch from parent node */
#define NEWLINE_CHAR "\n" /* char used to perform a line feed-carriage ret */
#define VERT_CONNECT "|"  /* char used to draw vertical lines */

main(argc,argv)
int argc;
char *argv[];
{
	int ftw_stat;
	int i;

	if (argc != 2) {
		fprintf(stderr, "Call: vtree path\n");
		exit(-1);
	}

	fprintf(stdout, "VTREE\n\n\n%s\n", argv[1]);
	for (i=0; i < strlen(argv[1]); i++)
		fprintf(stdout, "_");
	fprintf(stdout, "\n%s\n%s", VERT_CONNECT, VERT_CONNECT);

	ftw_stat = ftw(argv[1], fn, 10);
	fprintf(stdout, "%s%s", NEWLINE_CHAR, NEWLINE_CHAR);

	if (ftw_stat != 0)
		printf("FTW error = %d\n",errno);

}

/*_________________________________________________________________________*/

int fn(name,ptr,type)
char *name;          /* name of the directory entity */
struct stat *ptr;    /* pointer to a STAT(2) structure */
int type;            /* entity type according to <ftw.h> */
{
	static char table[MAXDEPTH][DIRNAME_LENGTH];
	static int tablecount=0;  /* count of how many entries in the table
			are currently valid */
	static int column=0;  /* what column are we printing output in */
	static match_found;  /* has a match been found yet */
	static firsttime=1;  /* the first time this routine is called */

	switch (type) {
	case FTW_D:
		/* printf("%s\n",name); */
		break;
	case FTW_DNR:
		/* printf("%s",name);
		printf("    directory that can't be read\n"); */
		break;
	default:
		return(0);  /* other types of entity need no processing */
	}

	if (firsttime) {
		loadtable(table, &tablecount, name);
		firsttime =0;
		return(0);
	}

	match_found=0;
	do {
		/* if this path is a extension of the last path */
		if (tablecount == 0 || match(table,tablecount, name) ==0) {
			strcpy(table[tablecount++], tail(name)); /* add last node to
								table */
			column++;  /* were going to print new name in next column */
			drawlevel(column, tail(name));
			match_found =1;  /* we just found a new directory level */
		} else {
			tablecount--;  /* back up one node level and try again */
			column--;	/* printout column goes back with dir level */
		}
	if (tablecount < 0) {
		fprintf(stderr, "Internal Program Error\n");
		exit(-1);
	}	
	} while (!match_found);

	return(0);
}

/* _________________________________________________________________________ */

/*
  This function returns a pointer into path of the last node in the path 
*/
char *tail(path)
char *path;
{
	char *ptr;

	if ((ptr =strrchr(path,'/')) == NULL)
		return(path);      /* it didn't have a path seperator */
	else
		return(ptr +1);   /* return pointer to last node in path */
}

/* _________________________________________________________________________ */

/*
	match checks to see if the first nodes in the path name match to 
	node names in the table
*/
int match(table,tablecount,name)
char table[MAXDEPTH][DIRNAME_LENGTH];
int tablecount;    /* how many entries in the table are valid and need to be
checked */

char *name;        /* the directory path of node names */
{
	int i;
	char *ptr;
	char path[200];   /* make a copy of their pathname to strtok on */

	strcpy(path, name);

	/* check first node name against first table entry */
	if (strcmp(table[0], (ptr =strtok(path,"/"))) != 0) {
		return(-1); /* return no match */
	}

	/* check the rest of the table up to the last valid entry against
		each node name in the path */
	for (i=1; i < tablecount; i++)
		if (strcmp(table[i], strtok(NULL, "/")) != 0)
			return(-1);      /* return no match */

	return(0);
}

/* ______________________________________________________________________ */

loadtable(table, tablecount, name)
char table[MAXDEPTH][DIRNAME_LENGTH];
int *tablecount;
char *name;
{
	char path[160];   /* make a copy of the path so as not to chg it */
	char *ptr;

	strcpy(path, name);

	*tablecount =0;		/* nothing in the table yet */

	if ((ptr = strtok(path, "/")) == NULL)  /* if only a '/' for ex */
		return;
	else {
		strcpy(table[*tablecount], ptr); /* load table entry */
		(*tablecount)++;  /* add the node name found to the count */
	}

	while ((ptr = strtok(NULL, "/")) != NULL) { /* while a node name is
	found */
		strcpy(table[*tablecount], ptr);
		(*tablecount)++;
	}
}

/* ______________________________________________________________________ */

drawlevel(column,name)
int column;   /* column to print nodename in */
char *name;   /* nodename to print */
{
	static int lastcolumn=MAXDEPTH;  /* last column a name was printed in */
	static int lastlength;   /* length of last nodename printed */

	if (column <= lastcolumn)    /* this means we need to start a new row */
		startnewrow(column, name);
	else   			     /* add name to end of last row */
		addtorow(lastlength, name);

	lastcolumn =column;      /* remember the last column printed in */
	lastlength =strlen(name); /* remember length of last name printed */
}

/*_________________________________________________________________________*/

addtorow(lastlength, name)
int lastlength;      /* length of the previously printed name */
char *name; 		/* name to be printed */
{
	int i;

	/* move over and print it */
	for (i=0; i < DIRNAME_LENGTH +1 -lastlength; i++)  
		fprintf(stdout, CONNECT_CHAR);

	fprintf(stdout, name);    /* print the node name */
}

/*_________________________________________________________________________*/

startnewrow(column, name)
int column;   /* column to print nodename in */
char *name;   /* nodename to print */
{
	int i,j;

	fprintf(stdout, NEWLINE_CHAR);   /* start the new line */

	   /* move away from left edge */
	if (column ==1) {  /* if printing in first column */
		fprintf(stdout, BRANCH_CHAR);  /* char along left edge */
		for (i=0; i < LEADGAP -1; i++)  
			fprintf(stdout, CONNECT_CHAR);
	} else {
		fprintf(stdout, VERT_CONNECT);  /* char along left edge */
		for (i=0; i < LEADGAP -1; i++)  
			fprintf(stdout, BLANK_CHAR);
	}

	/* move over to its parents column in above row */
	for (i=0; i < (column -2); i++) 
		for (j=0; j < DIRNAME_LENGTH +1; j++)
			fprintf(stdout, BLANK_CHAR);

	if (column > 1) {  /* LEADGAP did this already for column ones */
		fprintf(stdout, BRANCH_CHAR); /* branch down from prev row */
		for (i=0; i < DIRNAME_LENGTH; i++)
			fprintf(stdout, CONNECT_CHAR);
	}

	fprintf(stdout, name);    /* print the node name */
}

/*  ----------------- end of source ------------------------------------ */

-- 
Gene Lee  UUCP: ...ihnp4!{meccts,dayton,rosevax}!ems!minnow!lee
UNISYS Corporation     ATT:  (612) 635-6334
If not for the courage of the fearless crew, the minnow would be lost.