bogatko@lzga.ATT.COM (George Bogatko) (08/23/90)
HI: Yeah, I know, another directory tree dumper. But THIS one is smaller, *FAR* less complicated then some that I've seen, and did precisely what I wanted, namely generate a directory tree that I could then comment into a "where everything is" document. GB ****** CUT HERE ****** CUT HERE ****** CUT HERE ****** CUT HERE ****** CUT HERE /****************************************************************************** * * * tree.c * * * ******************************************************************************/ /*-------------------------- INITIAL CODING DATE ----------------------------- Wed Aug 22 20:03:03 EDT 1990 by George M. Bogatko -------------------------------- HEADER FILES -----------------------------*/ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <string.h> #include <malloc.h> #include <errno.h> /*------------------ TYPEDEF'S, DEFINES, STRUCTURE DEF'S ------------------*/ #define INCR BUFSIZ #define USAGE fprintf(stderr, usage, argv[0]) /*---------------- IMPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ extern char *calloc(); extern char *optarg; extern int getopt(); extern int optind; extern char *sys_errlist[]; /*---------------- EXPORTED GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ /*---------------- INTERNAL GLOBAL VARIABLE/FUNCTION DEF'S ----------------*/ #ident "@(#)tree.c 1.1 8/22/90 - George M. Bogatko -" char *arg1; char *seperator="\t"; char *usage = "usage: %s [-t(abstr)] directory\n"; char dirname[BUFSIZ]; char tbuf[BUFSIZ]; extern char **grabmem(); extern int compar(); extern void addmore(); extern void addname(); extern void delname(); extern void tab(); int tlevel = -1; /*----------------------------------------------------------------------------- SYNOPSIS: tree [-t(abstr)] directory DESCRIPTION: TREE prints a directory tree similar to the one that MS-DOS supplies, with the following additions for UNIX. When the file name is printed, it is appended with: ALL SYSTEMS: / - if the file is a directory * - if the file is a regular file, and is executable # - if the file is a FIFO BSD SYSTEMS: @ - if the file is a symbolic link = - if the file is a socket. If a subdirectory cannot be entered, the directory name will be followed with "(cannot open)". If the directory can be entered, but cannot be read, the name will be followed with a "(cannot read)". Following that is the UNIX error. OPTIONS: The one option, '-t' allows you to supply a different indent string. The default is a TAB character ("\t"). One suggestion is "| ", which will show a visual link with the parent directory CAVEATS: Compile with -DBSD for BSD systems to get the defines for symbolic links and sockets. Otherwise just compile straight. COMMENTS: Suggestions for improvements are welcome as long as they are not of the 'kitchen sink' or 'second system' variety. =============================================================================*/ main(argc, argv) int argc; char *argv[]; { int c; while( (c = getopt(argc, argv, "t:")) != EOF ) { switch(c) { case 't': seperator = strdup(optarg); break; case '?': USAGE; exit(-1); } } if(optind == argc) { USAGE; exit(-1); } arg1=argv[optind]; if( access(arg1,05) == -1 ) { fprintf(stderr, "%s: %s\n", arg1, sys_errlist[errno]); exit(-1); } chdir(arg1); dumpdir(); return 0; } int dumpdir() { DIR *dirp; char **dnames; char **fnames; char *str; int dnameoff=0; int dnamesz=INCR; int fnameoff=0; int fnamesz=INCR; int i; int tl; int x = 0; struct dirent *dp; struct stat sbuf; dnames = grabmem(dnamesz); fnames = grabmem(fnamesz); /* * increment the tab level (see tab() ) */ tlevel++; /* * try to open the directory */ if( (dirp = opendir(".")) == (DIR *)NULL ) return -1; /* * KLUDGE number 1. See the line with the printf statement * "printf("%s%s/",arg1,dirname);". This is how we print * the (cannot open) statements, and then get a carrage return */ putchar('\n'); /* * read the directory to the end */ while( (dp = readdir (dirp)) != NULL ) { /* * gather some file statistics */ if( stat(dp->d_name, &sbuf) == -1 ) { perror("stat"); return -1; } /* * If the file is a directory, remember the name, in the directory * names bucket. */ if((sbuf.st_mode & S_IFMT) == S_IFDIR) { dnames[dnameoff++] = strdup(dp->d_name); if( dnameoff > dnamesz ) addmore(&dnames, &dnamesz); dnames[dnameoff+1] = (char *)NULL; } else { /* * else it is some other file. Put the name in another bucket. Add * the mneumonic character (#=@*). */ str = ""; if((sbuf.st_mode & S_IFMT) == S_IFIFO) str = "#"; else if((sbuf.st_mode & S_IFMT) == S_IFREG) { if(sbuf.st_mode & S_IXUSR) str="*"; } #if pyr || BSD else if((sbuf.st_mode & S_IFMT) == S_IFLNK) str = "@"; else if((sbuf.st_mode & S_IFMT) == S_IFSOCK) str = "="; #endif sprintf(tbuf, "%s%s",dp->d_name,str); fnames[fnameoff++]=strdup(tbuf); if( fnameoff >= fnamesz ) addmore(&fnames, &fnamesz); fnames[fnameoff+1] = (char *)NULL; } } /* * sort the buckets */ qsort(fnames, fnameoff, sizeof(char *), compar); qsort(dnames, dnameoff, sizeof(char *), compar); /* * dump the sorted list of non directory files */ for(i=0; fnames[i] != (char *)NULL; i++) { tab(); printf("%s\n",fnames[i]); } /* * go through the sorted list of directory files. */ for(i=0; dnames[i] != (char *)NULL; i++) { if( strcmp(dnames[i], ".") && strcmp(dnames[i], "..") ) { /* * build up the pathname */ addname(dnames[i]); tab(); /* * print it out */ printf("%s%s/",arg1,dirname); /* * chdir to the directory, and recurse. */ if( chdir(dnames[i]) == -1 ) { printf(" (cannot open: %s)\n", sys_errlist[errno]); delname(); } else if( dumpdir() == -1 ) { printf(" (cannot read: %s)\n", sys_errlist[errno]); tlevel--; chdir(".."); delname(); } } } /* * cleanup the mallocs, close the files, decrement the tab level, * and go back up a level */ for(i=0; dnames[i] != (char *)NULL; i++) { free(dnames[i]); } free(dnames); for(i=0; fnames[i] != (char *)NULL; i++) { free(fnames[i]); } free(fnames); tlevel--; closedir(dirp); delname(); chdir(".."); return 0; } /* * indent according to current tab level */ void tab() { int tl = tlevel; while(tl--) printf("%s",seperator); return; } /* * add a name to the current path name */ void addname(s) char *s; { strcat(dirname,"/"); strcat(dirname,s); return; } /* * delete a name from the current path name */ void delname() { char *ps; if( ps = strrchr(dirname, '/') ) *ps = '\0'; return; } /* * allocate memory */ char **grabmem(size) unsigned size; { char **s; if( (s = (char **)calloc((size+2), sizeof(char **))) == (char **)NULL ) { perror("calloc"); exit(-1); } return s; } /* * grow memory */ void addmore(s, size) char ***s; unsigned *size; { *size += INCR; if( (*s = (char **)realloc(*s, ((*size+2) * sizeof(char **)) )) == (char **)NULL ) { perror("realloc"); exit(-1); } return; } /* * function for qsort */ int compar(s1,s2) char **s1, **s2; { return( strcmp(*s1, *s2) ); }