[comp.sources.misc] Display Tree for 4.3bsd

mikep@ism780c.UUCP (Michael A. Petonic) (06/24/87)

I spent an hour hacking this utility out because I was looking
for something like it but couldn't find one.  I guess you could
put together something in shell-script that does something similar,
but I don't like waiting that long for code to run. Also could
use find, I guess.....

This utility recursively descends a directory tree and prints
the structure of it.  I know that "ls -R" will do something
similar, but it doesn't leave out normal files.  This is a
heck of a lot more flexible in what it does, anyway.

The *real* reason that I wrote this was because I wanted to
learn more about the 4.3bsd file system (like symbolic links)
and also the directory reading calls.  I've been modifying
programs that use the directory reading calls, and I wanted
to write something original.

Took more time to figure out how to write a manual entry than
it did to code....


:
# This is a shar file.  Delete everything above the line with ":" and
# run it through the shell like this:
#    $ sh file
# This will extract the following files
#		dt.1	- manual entry for dt
#		dt.c	- source code for 4.3bsd display tree program
# 
# Send any comments to   {seismo|sdcrdcf}!ism780c!mikep
#
# Author	:	Michael A. Petonic
#
# NOTE: The source was written with ":set ts=3" and ":set sw=3" in vi.
#	For the benefit of most people, I have expanded the tabs to 3 spaces
#	each so that it looks semi decent.
#
#
echo x - dt.1
sed 's/^X//' >dt.1 <<'*-*-END-of-dt.1-*-*'
X'\" %W% - %E%
X.TH DS 1 %I% %P%
X.SH NAME
Xdt \- display tree
X.SH SYNOPSIS
X.B dt 
X[
X.B -vs
X]
X[
X.B -i n
X] dir ...
X.SH DESCRIPTION
X\fIDt\fR recursively descends a directory tree printing out only the
Xsubdirectories.  If no directories are specified, then the current
Xworking directory is taken as a default.
X.P
XThe \fB-v\fR switch is used to specify verbose output (can't open a
Xdirectory, etc.).  Directories that are actually symbolic links are
Xnot descended and marked by an "(s)" after their name 
Xunless the \fB-s\fR switch is specifed.
X.P
XEach level in the tree is separated with tabs unless \fB-i\fR is specified,
Xthen \fBn\fR spaces are output instead.
X.SH SEE ALSO
Xls(1),du(1)
X.SH BUGS
XCurrently, \fIDt\fR lists the directories in the order that they are
Xstored, not alphabetical.
*-*-END-of-dt.1-*-*
echo x - dt.c
sed 's/^X//' >dt.c <<'*-*-END-of-dt.c-*-*'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
X#define INDENT_STR   3
X#define MAXFILES     20
Xextern int errno;
X
Xchar *pn;      /* program name */
X
Xint vflag = 0;       /* verbose flag */
Xint sflag = 0;       /* include symbolic links? */
Xint tflag = 1;       /* use tabs instead of spaces???? */
Xint in_size = 0;     /* indent size */
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X   char *dir;
X   struct stat sb;
X   register char c;
X   int errflag = 0;
X   extern char *optarg;
X   extern int optind;
X
X   pn = argv[0];
X
X
X   while((c = getopt(argc,argv,"vi:s")) != EOF)
X      switch(c) {
X      case 'v':
X         vflag = 1;
X         break;
X      case 's':
X         sflag = 1;
X         break;
X      case 'i':
X         if(!(in_size = atoi(optarg))) {
X            fprintf(stderr,"%s: invalid indent size \"%s\"\n",pn,optarg);
X            ++errflag;
X         }
X         tflag = 0;
X         break;
X      case '?':
X      default:
X         ++errflag;
X      }
X
X   if(errflag || (tflag && in_size)) {
X      fprintf(stderr,"Usage:  %s [-vs] [-i n] <dir> [<dir>...]\n",pn);
X      exit(99);
X   }
X
X   if(optind == argc) {
X      dir = ".";
X      descend(dir,0);
X      exit(0);
X   }
X
X   
X   for(;optind<argc;++optind)
X      descend(argv[optind],0);
X   
X   exit(0);
X}
X
X
Xdescend(path,level)
Xchar *path;
Xint level;
X{
X   register DIR *dirp;
X   register struct direct *dent;
X   long offset = 0L;
X   struct stat sb;
X   char ts[80];
X
X   if(chdir(path) < 0) {
X      if(vflag) {
X         sprintf(ts,"<%s>!cd\n",path);
X         pout(ts,level);
X      }
X      return;
X   }
X   pout(path,level);
X
X   if((dirp = opendir(".")) == NULL) {
X      fprintf(stderr,"%s: can't open \".\"\n",pn);
X      exit(2);
X   }
X
X   errno = 0;
X   while(dent=readdir(dirp)) {
X      if(!strcmp(dent->d_name,".") || !strcmp(dent->d_name,".."))
X         continue;
X      if(stat(dent->d_name,&sb) < 0) {
X         if(vflag) {
X            sprintf(ts,"<%s>!stat",dent->d_name);
X            pout(ts,level);
X         }
X         continue;
X      }
X      if((sb.st_mode&S_IFMT) != S_IFDIR)
X         continue;
X
X      /* check for symbolic link */
X      if(lstat(dent->d_name,&sb) < 0) {
X         if(vflag) {
X            sprintf(ts,"<%s>!lstat",dent->d_name);
X            pout(ts,level);
X         }
X         continue;
X      }
X      if(((sb.st_mode&S_IFMT) == S_IFLNK) && (!sflag)) {
X         sprintf(ts,"%s(s)",dent->d_name);
X         pout(ts,level+1);
X         continue;
X      }
X      if(dirp->dd_fd >= MAXFILES-1) {
X         offset = telldir(dirp);
X         closedir(dirp);
X         dirp = NULL;
X      }
X      descend(dent->d_name,level+1);
X      if(!dirp) {
X         if((dirp = opendir(".")) == NULL) {
X            fprintf(stderr,"%s: can't reopen \".\"\n",pn);
X            exit(9);
X         }
X         seekdir(offset);
X      }
X   }
X
X   closedir(dirp);
X   if(chdir("..") < 0) {
X      fprintf(stderr,"%s: can't change to \"..\"\n",pn);
X      exit(99);
X   }
X   return;
X}
X
X
X
Xpout(name,indent)
Xchar *name;
Xint indent;
X{
X   int i;
X
X   if(tflag) {
X      for(i=0;i<indent;++i)
X         putchar('\t');
X      puts(name);
X   } 
X   else {
X      if(indent*in_size)
X         printf("%*s%s\n",in_size*indent," ",name);
X      else
X         puts(name);
X   }
X   return;
X}
*-*-END-of-dt.c-*-*
exit
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
THE *REAL* STORY: The company, my associates, friends and ESPECIALLY the 
   government put me up to say all this useless trash.
{seismo|sdcrdcf}!ism780c!mikep     "Some of my best friends are bigots."