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."