|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T h ┃
Length: 8409 (0x20d9) Types: TextFile Names: »hier.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/hier/hier.c«
/* * Show file system hierarchy. * * Usage: see below. * * Unlike ls(1), it sorts files across lines rather than down columns. * Fixing this would be non-trivial, involving saving filenames until it * was time to dump them. * * Also, due to the behavior of sftw() (like ftw()), it never lists "." and * ".." files. * * Warning: If you use ftw() instead of sftw(), -a option will stop working. * * Warning: If you use ftw() instead of sftw(), a bug will appear. This is * because two calls in a row from ftw() to OneFile() may be made for ordinary * files, where the second is in a directory a level above the first one. * OneFile() would have to check to see if each ordinary file's path is * different than the previous one's, indicating a change of directory level. */ #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <ftw.h> #ifdef BSD #include <sys/dir.h> /* for DIRSIZ */ #include <strings.h> #else #include <sys/ndir.h> /* for DIRSIZ */ #include <string.h> #endif /* BSD */ /********************************************************************* * MISCELLANEOUS GLOBAL VALUES: */ #define PROC /* null; easy to find procs */ #define FALSE 0 #define TRUE 1 #define CHNULL ('\0') #define CPNULL ((char *) NULL) #define REG register char *usage[] = { "usage: %s [-adp] [-c columns] [-i indent] [directories...]", "-a include directories and files whose names start with \".\"", "-d show directories only", "-p print filenames packed onto lines, not aligned", "-c set width of display (or use COLUMNS env variable; default = 80)", "-i set indentation per level; default = 4", "Does current directory by default.", CPNULL, }; char *myname; /* how program was invoked */ int aflag = FALSE; /* -a (all files) option */ int dflag = FALSE; /* -d (directories) option */ int pflag = FALSE; /* -p (packed filenames) option */ int columns = 0; /* from -c option or env */ int indent = 0; /* from -i option or default */ #define COLUMNS 80 /* width of display */ #define INDENT 4 /* per directory level */ int startlen; /* of current arg (filename) */ int nextcol = 0; /* column in output line */ /************************************************************************ * M A I N * * Initialize, then call sftw() for each given filename after clearing * global startlen to indicate a new starting file. When done, if global * nextcol != 0 (in the middle of an output line), finish the last line. */ PROC main (argc, argv) int argc; char **argv; { extern int optind; /* from getopt() */ extern char *optarg; /* from getopt() */ REG int option; /* option "letter" */ char *argdef = "."; /* default argument */ char *colstr; /* from environment */ char *getenv(); int OneFile(); /* #define DEPTH (_NFILE - 5) /* for ftw(), but not sftw() */ /* * PARSE ARGUMENTS: */ myname = *argv; while ((option = getopt (argc, argv, "adpc:i:")) != EOF) { switch (option) { case 'a': aflag = TRUE; break; case 'd': dflag = TRUE; break; case 'p': pflag = TRUE; break; case 'c': columns = atoi (optarg); break; case 'i': indent = atoi (optarg); break; default: Usage(); } } if (dflag && pflag) Error ("-d and -p don't make sense together"); /* * FINISH INITIALIZING: */ if ((columns == 0) /* no value given */ && (((colstr = getenv ("COLUMNS")) == CPNULL) /* undefined */ || ((columns = atoi (colstr)) == 0))) /* defined null or zero */ { columns = COLUMNS; /* use default */ } if (indent == 0) /* no value given */ indent = INDENT; /* use default */ argc -= optind; /* skip options */ argv += optind; if (argc == 0) /* no filenames given */ { argc = 1; argv = & argdef; /* use default */ } /* * WALK EACH FILE TREE: */ while (argc-- > 0) { startlen = 0; if (sftw (*argv, OneFile, aflag)) Error ("file tree walk failed for file \"%s\"", *argv); argv++; } if (nextcol) /* last line not finished */ putchar ('\n'); exit (0); } /* main */ /************************************************************************ * O N E F I L E * * Called from sftw() to handle (print) one file, given a filename (starting * file plus sub-file part) and ftw() file type. Always returns zero (all * is well, keep going). * * It's messy because of the need to print multiple non-directory basenames * on one line. Uses global startlen to save time figuring depth beyond * starting file. If currently zero, this is the starting file; print the * fullname, on a line alone, with no indent. * * Use globals startlen, indent, columns, and nextcol. */ PROC int OneFile (filename, statp, type) char *filename; /* name */ struct stat *statp; /* info, unused */ int type; /* ftw() type */ { REG char *basename; /* part of filename */ /* * PRINTING FORMATS (matching ftw() types): */ static char *FMT_D = "%s/\n"; static char *FMT_DNR = "%s/ (not readable)\n"; static char *FMT_NS = "%s (not stat'able)\n"; static char *FMT_F1 = "%s\n"; /* for starting file */ static char *FMT_F2 = "%-*s"; /* for sub-file */ #ifdef BSD #define FILEWIDTH MAXNAMLEN /* for FMT_F2 */ #else #define FILEWIDTH (DIRSIZ + 1) /* for FMT_F2 */ #endif /* BSD */ REG int filewidth = FILEWIDTH; /* if ! pflag */ #define NEWLINE { putchar ('\n'); nextcol = 0; } /* for speed and clarity */ /* * OPTIONALLY IGNORE NON-DIRECTORY (even if named as an input argument): */ if (dflag && (type == FTW_F)) return (0); /* * HANDLE STARTING FILE: */ if (startlen == 0) { startlen = strlen (filename); /* set for later */ if (nextcol) /* end previous line */ NEWLINE; /* sets nextcol == 0 */ printf ((type == FTW_D) ? FMT_D : (type == FTW_DNR) ? FMT_DNR : (type == FTW_NS) ? FMT_NS : FMT_F1, filename); return (0); } /* * SET BASENAME FOR ALL OTHER TYPES: */ basename = ((basename = strrchr (filename, '/')) == CPNULL) ? filename : (basename + 1); /* past "/" if any */ /* * HANDLE NON-DIRECTORY SUB-FILE (print multiple per line): */ if (type == FTW_F) { if (pflag) /* else use preset value */ filewidth = strlen (basename) + 1; if (nextcol && (nextcol + filewidth >= columns)) /* overflow */ NEWLINE; /* sets nextcol == 0 */ if (nextcol == 0) /* start new line with indent */ nextcol = PrintIndent (filename); printf (FMT_F2, filewidth, basename); nextcol += filewidth; return (0); } /* * HANDLE DIRECTORY OR OTHER SUB-FILE (print on line by itself): */ if (nextcol) /* end previous line */ NEWLINE; /* sets nextcol == 0 */ PrintIndent (filename); printf ((type == FTW_D) ? FMT_D : (type == FTW_DNR) ? FMT_DNR : FMT_NS, basename); return (0); } /* OneFile */ /************************************************************************ * P R I N T I N D E N T * * Given a filename and globals startlen and indent, print the total * indentation needed before the name, which is indent times the number of * slashes past startlen (which should be >= 1). Return the indent value. */ PROC int PrintIndent (filename) REG char *filename; { REG int depth = 0; REG int totind; int retval; filename += startlen; /* start of sub-part */ while (*filename != CHNULL) if (*filename++ == '/') depth++; retval = totind = indent * depth; while (totind-- > 0) putchar (' '); return (retval); } /* PrintIndent */ /************************************************************************ * U S A G E * * Print usage messages (char *usage[]) to stderr and exit nonzero. * Each message is followed by a newline. */ PROC Usage() { REG int which = 0; /* current line */ while (usage [which] != CPNULL) { fprintf (stderr, usage [which++], myname); putc ('\n', stderr); } exit (1); } /* Usage */ /************************************************************************ * E R R O R * * Print an error message to stderr and exit nonzero. Message is preceded * by "<myname>: " using global char *myname, and followed by a newline. */ /* VARARGS */ PROC Error (message, arg1, arg2, arg3, arg4) char *message; long arg1, arg2, arg3, arg4; { fprintf (stderr, "%s: ", myname); fprintf (stderr, message, arg1, arg2, arg3, arg4); putc ('\n', stderr); exit (1); } /* Error */