tree dumper
George Bogatko
bogatko at lzga.ATT.COM
Thu Aug 23 11:21:46 AEST 1990
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) );
}
More information about the Alt.sources
mailing list