treeD --- Unix file system diagrammer
Istvan Mohos
istvan at hhb.UUCP
Fri May 4 04:56:24 AEST 1990
The utmost conceptual simplicity of file system trees belies the
difficulty of memorizing actual nodal layouts of specific trees.
In spite a plain topological essence of TREE no two trees are
the same; and most users would have an equal chance of being able
to recall the exact twig arrangement of last year's Christmas tree
as they would in describing a 30 Meg Unix subdirectory.
Recursive listers such as 'find' obscure the tree structure by the
one-dimensionality of their output: standard output mediums of
pinfeed paper or the scrollable screen rigidly limit the width,
while allowing infinitely long lists.
The treeD file system diagrammer erases the width limitation of
the output medium, and constructs true two-dimensional maps of
file systems. To realize a hardcopy of a map, the internal diagram
is output as equal-sized pages, each page bearing a letter/number
coordinate analogous to lettered, numbered grids on a street map.
Command line options fine tune the format of the output, control
non-default grid sizes and the depth of the directory search.
-DREALUNIX should be enabled in the makefile when compiling under
System V. The 'man page' is in the file treeD.tex, and should be
processed with "tex treeD" (assuming TeX capability at the site).
The Bourne script treeX converts treeD's character-graphics
depicting branching, to bold lines under plain TeX.
===============================cut here===========================
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file". (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# globals.h i.h ilib.h
# goaway.c iego.c ierror.c illistn.c init.c iopt.c iread.c
# listfiles.c mapper.c package.c split.c tile.c treeD.c
# makefile treeX treeD.tex README
echo x - globals.h
cat > "globals.h" << '//E*O*F globals.h//'
/* globals.h */
#include "ilib.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BLANK 0
#define SINGLE 1
#define DOUBLE 2
#define TRIPLE 3
#define LEAF 4
#define BUD 5
#define JOINT 6
#define TWIG 7
#define SPAN 8
#define TAP 9
#define TIP 10
#define MAXFN 15 /* fourteen name chars, 1 type char */
#define SPACE 32 /* ASCII value */
#define ZERO ((char *)NULL)
#define TSIZ (sizeof (struct tile))
#define BAILOUT sprintf (Msg, "error at line %d of %s",\
__LINE__, __FILE__), goaway()
int goaway();
int fstat();
int stat();
char *malloc();
char *gets();
struct tile {
int ver;
int hor;
int linkc;
char line1[17];
char line2[17];
char line3[17];
};
#ifdef MAIN
char Listfile[IQUARTK]; /* /tmp file for listing of current dir */
char Tiles[IQUARTK]; /* /tmp filename for sequential output */
char Msg[IQUARTK]; /* buffer for reporting errors to user */
struct tile **Mp; /* base of tile pointer matrix */
int Td; /* Tile descriptor */
int Tx; /* horizontal tile position */
int Ty = -1; /* vertical tile position */
int Deepest; /* greatest vertical depth reached */
int Wid = 72; /* max column width of printed page */
int Lin = 66; /* max lines on printed page */
int Widemod; /* number of tiles/page horizontally */
int Deepmod; /* number of tiles/page vertically */
int Depth; /* max. recursion depth; 0=infty */
int Fstop; /* max. file list page; 0=infty */
int Printblank; /* print page even if no tiles on it */
unsigned int Mcount; /* width*height of rectangular tile matrix */
struct tile Blank; /* one of each tile, initialized in init.c */
struct tile Single;
struct tile Double;
struct tile Triple;
struct tile Leaf;
struct tile Bud;
struct tile Joint;
struct tile Twig;
struct tile Span;
struct tile Tap;
struct tile Tip;
#else
extern char Listfile[];
extern char Tiles[];
extern char Msg[];
extern struct tile **Mp;
extern int Td;
extern int Tx;
extern int Ty;
extern int Deepest;
extern int Lin;
extern int Wid;
extern int Widemod;
extern int Deepmod;
extern int Depth;
extern int Fstop;
extern int Printblank;
extern unsigned int Mcount;
extern struct tile Blank;
extern struct tile Single;
extern struct tile Double;
extern struct tile Triple;
extern struct tile Leaf;
extern struct tile Bud;
extern struct tile Joint;
extern struct tile Twig;
extern struct tile Span;
extern struct tile Tap;
extern struct tile Tip;
#endif
//E*O*F globals.h//
echo x - i.h
cat > "i.h" << '//E*O*F i.h//'
/* i.h */
/**************************************
* local include file for ilib functions
* Istvan Mohos, 1987
***************************************/
#ifdef pyr
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef X_OK
# ifdef REALUNIX
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
# include <fcntl.h>
# else
# include <sys/file.h>
# endif
#endif
#define NUL 0 /* the ASCII 0 byte */
#define MAXSTR 1892
#define BIGBUFSIZ 4096
#define SHORTSTR 256
#define IFOURK 4096
#define ITWOK 2048
#define IONEK 1024
#define IHALFK 512
#define IQUARTK 256
#define BADCHARP(p) ((p) == (char *)NULL || *(p) == '\0')
#define NULCHARP(p) ((p) == (char *)NULL)
#define WHITE(c) ((c) < 33)
#define BLACK(c) ((c) > 32)
#define SMALL(c) ((c) < 32)
#define INITOKF 1 /* setup forward parsing */
#define INITOKR -1 /* setup reverse parsing */
#define ITOKF 2 /* forward parse */
#define ITOKR -2 /* reverse parse */
int fstat();
int stat();
char *malloc();
char *calloc();
long lseek();
long time();
struct tm *_igetdate();
char *ctime();
char *iwhich();
char *getenv();
char *ilast();
char *ianytok();
char *ialntok();
char *ictok();
int ierror();
int ifamily();
int ilongest();
int itexrect();
int iread();
extern int errno, sys_nerr;
extern char *sys_errlist[];
#ifndef IAMIERROR
extern char ierbuf[];
extern int ierflag;
#endif
//E*O*F i.h//
echo x - ilib.h
cat > "ilib.h" << '//E*O*F ilib.h//'
/* ilib.h */
/*********************************************************************
* This is the client's #include file for accessing functions in ilib.a
* Istvan Mohos, 1987 --- in the Public Domain
**********************************************************************/
/* functions archived in ilib.a: */
char * ialntok();
char * ianymatch();
char * ianytok();
int ibcmp();
void ibcopy();
void iblank();
int ibreakl();
char * ictok();
char * icopy();
int icount();
void icue();
int idamage();
char * idate();
void idump();
int iego();
int ierror();
int iexpect();
int ifamily();
int ifilter();
int igroup();
int ihash();
int ihasharg();
char * ihms();
int iinput();
char * ilast();
int iline();
int ilist();
int ilistn();
int illistn();
int ilongest();
int ilower();
char * imatch();
int imode();
int imonth();
int inest();
char * inl();
char * inull();
int inumsearch();
void inumsort();
int inumstrcmp();
char * inextl();
int ioctal();
int iopt();
int iread();
int irotate();
int iround();
int isearch();
void isort();
char * istartl();
int istripcom();
int istripdq();
int istripsq();
int istripstr();
int iswap();
int itexrect();
int itoday();
int itohour();
int itok();
int itomin();
int itomonth();
int itosec();
int itoyear();
int itran();
void itwin();
int iuniq();
int iuniqa();
int iupper();
char * iwhich();
int iwrite();
int iwritopn();
char * ixmatch();
int ixsearch();
int ixswap();
char * malloc();
char * calloc();
long lseek();
#include <stdio.h>
#ifndef X_OK
# ifdef REALUNIX
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
# include <fcntl.h>
# else
# include <sys/file.h>
# endif
#endif
extern char ierbuf[];
extern int ierflag;
/* imode symbolic constants, modeled after stat.h list */
#define ISSOCK 0140000 /* socket */
#define ISLNK 0120000 /* symbolic link */
#define ISREG 0100000 /* regular */
#define ISBLK 0060000 /* block special */
#define ISDIR 0040000 /* directory */
#define ISCHR 0020000 /* character special */
#define ISFIFO 0010000 /* named pipe */
#define ISUID 0004000 /* set uid on execution */
#define ISGID 0002000 /* set gid on execution */
#define ISSTICK 0001000 /* keep text in memory (sticky bit) */
#define ISROWN 0000400 /* read, owner */
#define ISWOWN 0000200 /* write, owner */
#define ISXOWN 0000100 /* execute/search, owner */
#define ISRGRP 0000040 /* read, group */
#define ISWGRP 0000020 /* write, group */
#define ISXGRP 0000010 /* execute/search, group */
#define ISRALL 0000004 /* read, others */
#define ISWALL 0000002 /* write, others */
#define ISXALL 0000001 /* execute/search, others */
#define INITOKF 1 /* setup forward parsing */
#define INITOKR -1 /* setup reverse parsing */
#define ITOKF 2 /* forward parse */
#define ITOKR -2 /* reverse parse */
#define DOUNCOUN(x,y) (y) = (x); --(y) >= 0
#define BADCHARP(p) ((p) == (char *)NULL || *(p) == '\0')
#define NULCHARP(p) ((p) == (char *)NULL)
#define ZPT (char *)NULL
#define IANYTOK 0
#define IALNTOK 1
#define ICTOK 2
#define SPACE_LINE -1
#define LINE_ONLY 0
#define LINE_SPACE 1
#define IROTR 1 /* rotate 90 deg. to right */
#define IROTL -1 /* rotate 90 deg. to left */
#define IROTOR 3 /* rotate 180 deg. over and 90 deg. to right */
#define IROTOL -3 /* rotate 180 deg. over and 90 deg. to left */
#define SHORTMO 0 /* idate format: Jun 23 1988 */
#define SHORTUPMO 1 /* idate format: JUN 23 1988 */
#define LONGMO 2 /* idate format: June 23, 1988 */
#define LONGUPMO 3 /* idate format: JUNE 23, 1988 */
#define WHITE(c) ((c) < 33)
#define BLACK(c) ((c) > 32)
#define TONEXWHITE(p) while (*(p) && (*(p)>32)) (p)++
#define TONEXBLACK(p) while (*(p) && (*(p)<33)) (p)++
#define IFOURK 4096
#define ITWOK 2048
#define IONEK 1024
#define IHALFK 512
#define IQUARTK 256
//E*O*F ilib.h//
echo x - goaway.c
cat > "goaway.c" << '//E*O*F goaway.c//'
/* goaway.c */
#include "globals.h"
goaway ()
{
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
unlink (Tiles);
unlink (Listfile);
if (*Msg)
fprintf(stderr, "%s\n", Msg), exit (1);
exit (0);
}
//E*O*F goaway.c//
echo x - iego.c
cat > "iego.c" << '//E*O*F iego.c//'
/* iego.c */
/*******************************************************
* return file name in buf without path or .ext component
* Istvan Mohos, 1987 --- in the Public Domain
*******************************************************/
#include "i.h"
int
iego (ptr, wbuf, delim, ext)
char *ptr, *wbuf, delim, ext;
{
char *fr, *to, *mark;
if (BADCHARP(ptr))
return (ierror ("iego: invalid name pointer"));
if (delim == 0)
delim = '/';
to = wbuf;
*to = '\0';
for (fr = ptr; *fr++;);
for (--fr; --fr > ptr;) {
if (*fr == delim) {
++fr;
break;
}
}
if (*fr == delim)
++fr;
if (ext == 0)
for (mark = ptr; mark < fr; *to++ = *mark++);
else
for (;*fr && *fr != ext;)
*to++ = *fr++;
*to = '\0';
return (strlen (wbuf));
}
//E*O*F iego.c//
echo x - ierror.c
cat > "ierror.c" << '//E*O*F ierror.c//'
/* ierror.c */
/****************************************
* report error via "ierbuf" and "ierflag"
* Istvan Mohos, 1987 --- in the Public Domain
****************************************/
#define IAMIERROR
#include "i.h"
char ierbuf[IHALFK];
int ierflag;
int
ierror (ustr)
char *ustr;
{
if (errno > 0 && errno < sys_nerr) { /* system error */
ierflag = -errno;
if (NULCHARP (ustr))
strcpy(ierbuf, sys_errlist[errno]);
else
sprintf(ierbuf, "%s --- %.*s", sys_errlist[errno],
IHALFK - strlen (sys_errlist[errno]) - 6, ustr);
errno = 0;
return (ierflag);
}
ierflag = -sys_nerr; /* user error */
if (NULCHARP (ustr))
strcpy (ierbuf, "Error");
else
strncpy (ierbuf, ustr, IHALFK-1);
errno = 0;
return (ierflag);
}
//E*O*F ierror.c//
echo x - illistn.c
cat > "illistn.c" << '//E*O*F illistn.c//'
/* illistn.c */
/********************************************
* create array of pointers to lines in buffer
* Istvan Mohos, 1987 --- in the Public Domain
*********************************************/
#include "i.h"
int
illistn (start, end, ptrlist)
char *start;
char *end;
char **ptrlist;
{
int ri;
char *rp;
char *savp, **work;
if (end <= start || NULCHARP (start))
return (ierror ("illistn: zero-size or invalid buffer"));
*(end -1) = '\n'; /* just in case */
for (ri = 0, rp = end; --rp >= start;)
if (*rp == '\n')
++ri;
if (NULCHARP(savp=malloc((unsigned int)(ri*sizeof(char *)))))
return(ierror("illistn: can't allocate pointer array"));
/* start one character to left of last byte in buffer */
*(end -1) = 0;
for (work=(char **)savp+ri, rp=end-1; --rp >= start;)
if (*rp == '\n')
*rp = 0, *--work = rp+1;
/* rp == start-1 */
*--work = ++rp;
*ptrlist = savp;
return(ri);
}
//E*O*F illistn.c//
echo x - init.c
cat > "init.c" << '//E*O*F init.c//'
/* init.c */
#include "globals.h"
init ()
{
char *mktemp();
struct tile *tp;
/******************
* *
* *
* *
******************/
tp = &Blank;
strcpy (tp->line1, " ");
strcpy (tp->line2, " ");
strcpy (tp->line3, " ");
/******************
*string1 *
* *
* *
******************/
tp = &Single;
strcpy (tp->line2, " ");
strcpy (tp->line3, " ");
/******************
*string1 *
*string2 *
* *
******************/
tp = &Double;
strcpy (tp->line3, " ");
/******************
*string1 *
*string2 * Triple
*string3 *
******************/
/******************
* | *
*string1 *
*string2 *
******************/
tp = &Leaf;
strcpy (tp->line1, " | ");
/******************
* | *
*string1 *
* *
******************/
tp = &Bud;
strcpy (tp->line1, " | ");
strcpy (tp->line3, " ");
/******************
* | *
*string1 *
* | *
******************/
tp = &Joint;
strcpy (tp->line1, " | ");
strcpy (tp->line3, " | ");
/******************
* | *
*string1~~~~~~~~~*
* | *
******************/
tp = &Twig;
strcpy (tp->line1, " | ");
strcpy (tp->line3, " | ");
/******************
* *
*~~~~~~~~~~~~~~~~*
* *
******************/
tp = &Span;
strcpy (tp->line1, " ");
strcpy (tp->line2, "~~~~~~~~~~~~~~~~");
strcpy (tp->line3, " ");
/******************
* *
*~~~~~~~~~~~~~~~~*
* | *
******************/
tp = &Tap;
strcpy (tp->line1, " ");
strcpy (tp->line2, "~~~~~~~~~~~~~~~~");
strcpy (tp->line3, " | ");
/******************
* *
*~~> *
* | *
******************/
tp = &Tip;
strcpy (tp->line1, " ");
strcpy (tp->line2, "~~> ");
strcpy (tp->line3, " | ");
strcpy (Tiles, "/tmp/");
strcat (Tiles, mktemp ("treeDTXXXXXX"));
if ((Td = open (Tiles, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
fprintf (stderr, "can't write to %s\n", Tiles), exit (1);
strcpy (Listfile, "/tmp/");
strcat (Listfile, mktemp ("treeDLXXXXXX"));
if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
signal(SIGHUP, goaway);
if (signal(SIGINT, SIG_IGN) == SIG_DFL)
signal(SIGINT, goaway);
if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
signal(SIGTERM, goaway);
if (signal(SIGQUIT, SIG_IGN) == SIG_DFL)
signal(SIGQUIT, goaway);
Widemod = (Wid-3)/16;
Deepmod = (Lin-3)/3;
}
//E*O*F init.c//
echo x - iopt.c
cat > "iopt.c" << '//E*O*F iopt.c//'
/* iopt.c */
/*********************************************
* command line option manager
* Istvan Mohos, 1987 --- in the Public Domain
*********************************************/
#include "i.h"
int
iopt (ptr)
char ***ptr;
{
char *rp;
static char **olist;
static int first = 1;
int optlen;
if (first) {
olist = *ptr;
first = 0;
}
rp = *olist;
if (rp == NULL || *rp != '-') { /* no more options */
*ptr = olist; /* set to first non-option */
first = 1; /* automatically re-init */
return (0);
}
optlen = strlen (rp);
if (optlen > 2) { /* flag, value combined */
rp += 2;
*olist = rp; /* right past '-c' flag */
*ptr = olist;
++olist; /* pre-increment for next time */
return (*--rp);
}
if (optlen == 1) { /* '-' by itself */
*ptr = olist;
++olist; /* pre-increment for next time */
return (*rp);
}
/* else (optlen == 2): normal '-c' flag */
++rp;
++olist;
if (*olist == NULL || **olist == 0) { /* no option value */
--olist;
*ptr = olist; /* cough up entire option flag */
first = 1; /* automatically re-init */
return (0);
}
*ptr = olist;
++olist; /* pre-increment for next time */
return (*rp);
}
//E*O*F iopt.c//
echo x - iread.c
cat > "iread.c" << '//E*O*F iread.c//'
/* iread.c */
/*************************************************
* read file into malloc'd buffer, return file size
* Istvan Mohos, 1987 --- in the Public Domain
**************************************************/
#include "i.h"
int
iread (fname, mallocp)
char *fname;
char **mallocp;
{
struct stat sbuf;
int checkval, fd;
int count;
if (BADCHARP (fname))
return (ierror ("iread: invalid file name"));
if (mallocp == (char **) NULL) {
if (access (fname, R_OK) == -1)
return (-1); /* can't read it */
return (0);
}
if ((fd = open (fname, 0)) == -1)
return (ierror ("iread: no file access"));
if ((checkval = fstat (fd, &sbuf)) == -1)
return (ierror ("iread: fstat read error"));
if ((count = (int)sbuf.st_size) == 0)
return (ierror ("iread: zero length file"));
if (NULCHARP (*mallocp = malloc ((unsigned int) count+1)))
return (ierror ("iread: can't allocate read buffer"));
if ((checkval = read (fd, *mallocp, count)) != count) {
sprintf (ierbuf+200,
"iread: expected: %d, read: %d", count, checkval);
return (ierror (ierbuf+200));
}
close (fd);
*(*mallocp + count) = 0;
return (checkval);
}
//E*O*F iread.c//
echo x - listfiles.c
cat > "listfiles.c" << '//E*O*F listfiles.c//'
/* listfiles.c */
#include "globals.h"
listfiles (ptr, ptrcount, fcount)
char **ptr;
int ptrcount, fcount;
{
int fdeep;
int maxpgdeep;
int qi;
char *s1, *s2, *s3;
static char *more = "--- more ---";
if ((fdeep = Ty + 1) > Deepest)
Deepest = fdeep;
if (Fstop) {
maxpgdeep = Deepest / Deepmod +1; /* 1, 2... */
if (maxpgdeep < Fstop)
maxpgdeep = Fstop;
}
/* list files only, skip directories; null out file names */
if (fcount == 1) {
for (DOUNCOUN (ptrcount, qi); ptr++) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
tile (fdeep, BUD, 0, *ptr, ZERO, ZERO);
**ptr = 0;
return;
}
}
}
qi = ptrcount;
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
s1 = *ptr;
ptr++;
break;
}
ptr++;
}
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
if (Fstop && fcount && ((fdeep+1)/Deepmod >= maxpgdeep)) {
s2 = more;
tile (fdeep, LEAF, 0, s1, s2, ZERO);
*s1 = 0;
**ptr = 0;
while (qi--) {
++ptr;
if (*(*ptr + strlen (*ptr) -1) != '/')
**ptr = 0;
}
return;
}
s2 = *ptr;
ptr++;
break;
}
ptr++;
}
tile (fdeep, LEAF, 0, s1, s2, ZERO);
*s1 = *s2 = 0;
while (fcount >= 3) {
if (++fdeep > Deepest)
Deepest = fdeep;
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
s1 = *ptr;
ptr++;
break;
}
ptr++;
}
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
s2 = *ptr;
ptr++;
break;
}
ptr++;
}
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
if (Fstop && fcount && ((fdeep+1)/Deepmod >= maxpgdeep)) {
s3 = more;
tile (fdeep, TRIPLE, 0, s1, s2, s3);
*s1 = *s2 = 0;
**ptr = 0;
while (qi--) {
++ptr;
if (*(*ptr + strlen (*ptr) -1) != '/')
**ptr = 0;
}
return;
}
s3 = *ptr;
ptr++;
break;
}
ptr++;
}
tile (fdeep, TRIPLE, 0, s1, s2, s3);
*s1 = *s2 = *s3 = 0;
}
if (fcount == 2) {
if (++fdeep > Deepest)
Deepest = fdeep;
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
s1 = *ptr;
ptr++;
break;
}
ptr++;
}
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
s2 = *ptr;
ptr++;
break;
}
ptr++;
}
tile (fdeep, DOUBLE, 0, s1, s2, ZERO);
*s1 = *s2 = 0;
}
else if (fcount == 1) {
if (++fdeep > Deepest)
Deepest = fdeep;
while (qi--) {
if (*(*ptr + strlen (*ptr) -1) != '/') {
--fcount;
s1 = *ptr;
ptr++;
break;
}
ptr++;
}
tile (fdeep, SINGLE, 0, s1, ZERO, ZERO);
*s1 = 0;
}
}
//E*O*F listfiles.c//
echo x - mapper.c
cat > "mapper.c" << '//E*O*F mapper.c//'
/* mapper.c */
#include "globals.h"
extern int errno;
mapper (dirname)
char *dirname;
{
char dirego[IQUARTK];
char cmd[IHALFK];
char newpath[IONEK];
char *pathptr;
char *filebuf;
char *fileend;
char *ptrbuf;
char **ptr;
int ccount;
int fcount;
int dcount;
int ptrcount;
int qi;
int flush;
if (++Ty > Deepest)
Deepest = Ty;
sprintf (cmd, "/bin/ls -aFq %s > %s",dirname, Listfile);
errno = 0;
system (cmd);
if (errno)
BAILOUT;
iego (dirname, dirego, '/', '/');
if ((ccount = iread (Listfile, &filebuf)) < 1)
goaway();
fileend = filebuf + ccount;
if ((ptrcount = illistn (filebuf, fileend, &ptrbuf)) < 1)
BAILOUT;
/* count files and directories */
ptr = (char **)ptrbuf;
for (dcount = fcount = 0, DOUNCOUN (ptrcount, qi); ptr++)
(*(*ptr + strlen (*ptr) -1) == '/') ? ++dcount : ++fcount;
if (dcount < 2) {
strcat (dirego, "!");
tile (Ty, BUD, 0, dirego, ZERO, ZERO);
free (filebuf);
return;
}
if (dcount == 2 && !fcount) {
strcat (dirego, "/");
tile (Ty, BUD, 0, dirego, ZERO, ZERO);
free (filebuf);
return;
}
/* At this point, the next tile is a Twig if dirname contains
both files and directories, or no files and multiple dirs.
The next tile is a Joint if dirname contains files only, or
a single directory.
*/
if (dcount == 2) {
strcat (dirego, "/");
tile (Ty, JOINT, 0, dirego, ZERO, ZERO);
ptr = (char **)ptrbuf;
listfiles (ptr, ptrcount, fcount);
free (filebuf);
return;
}
if (dcount == 3 && !fcount) {
strcat (dirego, "/");
tile (Ty, JOINT, 0, dirego, ZERO, ZERO);
strcpy (newpath, dirname);
pathptr = newpath + strlen (newpath);
*pathptr++ = '/';
ptr = (char **)ptrbuf;
for (DOUNCOUN (ptrcount, qi); ptr++) {
if (strcmp (*ptr, "./") && strcmp (*ptr, "../")) {
if (!Depth || Ty < (Depth-1)) {
*(*ptr + strlen (*ptr) -1) = 0;
strcpy (pathptr, *ptr);
mapper (newpath);
Ty--;
}
else {
*(*ptr + strlen (*ptr) -1) = '!';
tile (Ty+1, BUD, 0, *ptr, ZERO, ZERO);
if (Ty+1 > Deepest)
Deepest = Ty+1;
}
free (filebuf);
return;
}
}
}
if (fcount) { /* and dcount > 2 */
strcat (dirego, "/");
tile (Ty, TWIG, dcount-2, dirego, ZERO, ZERO);
ptr = (char **)ptrbuf;
listfiles (ptr, ptrcount, fcount);
strcpy (newpath, dirname);
pathptr = newpath + strlen (newpath);
*pathptr++ = '/';
ptr = (char **)ptrbuf;
for (DOUNCOUN (ptrcount, qi); ptr++) {
if (**ptr) { /* not a file */
if (strcmp (*ptr, "./") && strcmp (*ptr, "../")) {
++Tx;
if (!Depth || Ty < (Depth-1)) {
*(*ptr + strlen (*ptr) -1) = 0;
strcpy (pathptr, *ptr);
mapper (newpath);
Ty--;
}
else {
*(*ptr + strlen (*ptr) -1) = '!';
tile (Ty+1, BUD, 0, *ptr, ZERO, ZERO);
if (Ty+1 > Deepest)
Deepest = Ty+1;
}
}
}
}
free (filebuf);
return;
}
/* no files, multiple dirs */
strcat (dirego, "/");
tile (Ty, TWIG, dcount-3, dirego, ZERO, ZERO);
flush = 1;
strcpy (newpath, dirname);
pathptr = newpath + strlen (newpath);
*pathptr++ = '/';
ptr = (char **)ptrbuf;
for (DOUNCOUN (ptrcount, qi); ptr++) {
if (strcmp (*ptr, "./") && strcmp (*ptr, "../")) {
flush ? (flush = 0) : ++Tx;
if (!Depth || Ty < (Depth-1)) {
*(*ptr + strlen (*ptr) -1) = 0;
strcpy (pathptr, *ptr);
mapper (newpath);
Ty--;
}
else {
*(*ptr + strlen (*ptr) -1) = '!';
tile (Ty+1, BUD, 0, *ptr, ZERO, ZERO);
if (Ty+1 > Deepest)
Deepest = Ty+1;
}
}
}
free (filebuf);
return;
}
//E*O*F mapper.c//
echo x - package.c
cat > "package.c" << '//E*O*F package.c//'
/* package.c */
#include "globals.h"
package ()
{
char *buf;
struct tile *tp;
struct tile **tmp;
int tcount;
int linkc;
int depth = Deepest +1;
int qi, qj;
close (Td);
if ((tcount = iread (Tiles, &buf)) < 1)
BAILOUT;
tcount /= TSIZ;
Mcount = depth * (Tx+1);
if ((Mp = (struct tile **)malloc (Mcount * sizeof (struct tile **)))
== (struct tile **) NULL)
BAILOUT;
/* init all locations to Blank */
for (tmp = Mp, DOUNCOUN (Mcount, qi); tmp++)
*tmp = &Blank;
/* remap tcount tiles in buf into a rectangular array, Y first:
line 0: 0,0 /0,1 /0,2
line 1: 1,0 / 1,1 / 1,2
(6 deep) 2,0 / 2,1 / 2,2
line 3: 3,0 / 3,1 / 3,2
line 4: 4,0 / 4,1 / 4,2
Deepest: 5,0/ 5,1/ 5,2
*/
tp = (struct tile *)buf;
for (DOUNCOUN (tcount, qi); tp++)
Mp[tp->hor * depth + tp->ver] = tp;
/* blank out leader to first tile (root) only */
tp = Mp[0];
strcpy (tp->line1, " ");
/* Find and complete every Twig, line-by-line left-to-right.
Do not look for Twig in bottom line or at right edge.
To right of each Twig, substitute Twig->linkc number of Blank
tiles with Tap tiles (or Tip at the terminal tile).
Tap or Tip tiles must be installed directly above non-blank
tiles only: if next horizontal position is located above a Blank,
a Span tile is laid instead.
*/
for (qi = 0; qi < Deepest; qi++) { /* Y loop */
for (qj = 0; qj < Tx; qj++) { /* X loop */
if (linkc = (Mp[qj*depth+qi])->linkc) { /* a Twig? */
++qj; /* next hor. tile */
for (--linkc; linkc; qj++) { /* not incl. Tip */
if (Mp[qj*depth+qi+1] == &Blank) {
Mp[qj*depth+qi] = &Span;
continue;
}
Mp[qj*depth+qi] = &Tap;
linkc--;
}
while (Mp[qj*depth+qi+1] == &Blank) {
Mp[qj*depth+qi] = &Span;
qj++;
}
Mp[qj*depth+qi] = &Tip;
}
}
}
/***** To print matrix data:
for (tmp = Mp, DOUNCOUN (Mcount, qi); tmp++)
printf ("%s]\n%s]\n%s]\n................\n",
(*tmp)->line1, (*tmp)->line2, (*tmp)->line3);
*/
/***** To print file data:
tp = (struct tile *)buf;
for (qi = tcount; qi--; tp++)
printf ("Y:%d X:%d B:%d\n%s]\n%s]\n%s]\n................\n",
tp->ver, tp->hor, tp->linkc, tp->line1, tp->line2, tp->line3);
*/
}
//E*O*F package.c//
echo x - split.c
cat > "split.c" << '//E*O*F split.c//'
/* split.c */
#include "globals.h"
split ()
{
static char alpha[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
char counter[32]; /* horiz. numerical id of page */
char pad[4]; /* 0, 1, or 2 newlines at end of page */
char verid[4]; /* vertical, alpha id of page */
char topline[IONEK]; /* top border of page */
char botline[IONEK]; /* bottom border of page */
char blankline[IONEK];
char strip[3*IONEK]; /* 3 lines: a horiz. strip of tiles */
struct tile *tp;
char *s1, *s2, *s3;
char *pp;
int depth = Deepest +1;
int width = Tx +1;
int darktile; /* any tile except Blank */
int skip = 0; /* count of blank pages skipped */
int thishor; /* number of tiles horiz. on this page */
int thisver; /* number of tiles vert. on this page */
int horpcnt; /* number of horizontal pages of data */
int verpcnt; /* number of vertical pages of data */
int padline; /* pad page at bottom with blank lines */
int realcols; /* actual number of cols printed/page */
int stripsiz; /* characters printed per strip */
int qy, qx;
int ty, tx;
padline = Lin % 3;
horpcnt = Tx/Widemod +1;
verpcnt = Deepest/Deepmod +1;
realcols = Widemod * 16 +3 +1; /* newline at end */
stripsiz = realcols * 3;
fprintf (stderr, "Matrix of %d horizontal %s @ %d %s per list.\n",
verpcnt, (verpcnt > 1) ? "lists" : "list",
horpcnt, (horpcnt > 1) ? "pages" : "page");
pp = topline;
*pp++ = SPACE;
*pp++ = SPACE;
for (DOUNCOUN (realcols-4, qx); *pp++ = ':');
*pp = '\n';
pp = botline;
*pp++ = SPACE;
*pp++ = SPACE;
for (DOUNCOUN (realcols-4, qx); *pp++ = ';');
*pp = '\n';
pp = blankline;
*pp++ = SPACE;
*pp++ = '(';
for (DOUNCOUN (realcols-4, qx); *pp++ = SPACE);
*pp++ = ')';
*pp = '\n';
if (padline)
strcpy (pad, ((padline == 1) ? "\n" : "\n\n"));
/* Output pages with number X coordinates and letter Y coordinates.
Output pages in horizontal order first.
*/
for (thisver = Deepmod, qy = 0; qy < verpcnt; qy++) {
if (verpcnt < 26) { /* one-character alpha coordinate */
verid[0] = alpha[qy];
verid[1] = SPACE;
verid[2] = SPACE;
}
else if (verpcnt < 676) { /* two-character alpha coordinate */
ty = qy % 676; /* a number between 0 and 675 */
tx = ty / 26; /* a number between 0 and 25 */
verid[0] = alpha[tx];
tx = qy % 26; /* a number between 0 and 25 */
verid[1] = alpha[tx];
verid[2] = SPACE;
}
else { /* three-character alpha coordinate */
qx = qy % 17576; /* a number between 0 and 17575 */
tx = qx / 676; /* a number between 0 and 25 */
verid[0] = alpha[tx];
ty = qx % 676; /* a number between 0 and 675 */
tx = ty / 26; /* a number between 0 and 25 */
verid[1] = alpha[tx];
tx = qx % 26; /* a number between 0 and 25 */
verid[2] = alpha[tx];
}
/* Each horizontal pagelist already output contained
width * Deepmod tiles. When on the last pagelist, the
remaining tilecount divided by the width of the tile matrix
gives the count of tiles to print vertically.
*/
if (qy+1 == verpcnt)
thisver = (Mcount - qy * width * Deepmod) / width;
for (thishor = Widemod, qx = 0; qx < horpcnt; qx++) {
/* When on the last page of the horizontal pagelist,
the number of horizontal tiles to print on the page is
width % Widemod (if there is a remainder), or
Widemod (if there is no remainder).
*/
if (qx+1 == horpcnt)
if (!(thishor = width % Widemod))
thishor = Widemod;
for (darktile = ty = 0; ty < thisver; ty++) {
for (tx = 0; tx < thishor; tx++) {
tp = Mp[qx*depth*Widemod+tx*depth+qy*Deepmod+ty];
if (tp != &Blank)
darktile = 1;
if (darktile)
break;
}
if (darktile)
break;
}
if (!Printblank && !darktile) {
++skip;
goto skippage;
}
sprintf (counter, " %d\n", qx +1);
write (1, counter, strlen (counter));
write (1, topline, realcols-1);
for (ty = 0; ty < thisver; ty++) {
s1 = strip;
s2 = s1 + realcols;
s3 = s2 + realcols;
if (ty == 0) {
*s1++ = verid[0];
*s2++ = verid[1];
*s3++ = verid[2];
}
else {
*s1++ = SPACE;
*s2++ = SPACE;
*s3++ = SPACE;
}
*s1++ = '(';
*s2++ = '(';
*s3++ = '(';
for (tx = 0; tx < thishor; tx++) {
/* Each previous column (qx) of pages advanced the
Mp index of the current tile column by
depth * Widemod. Each previous tile column on
this page advanced the Mp index by depth. The
current pointer is the offset from the current
tile column start, by the current depth.
*/
tp = Mp[qx*depth*Widemod+tx*depth+qy*Deepmod+ty];
strcpy (s1, tp->line1);
s1 += 16;
strcpy (s2, tp->line2);
s2 += 16;
strcpy (s3, tp->line3);
s3 += 16;
}
if (thishor < Widemod) {
for (tp = &Blank; tx < Widemod; tx++) {
strcpy (s1, tp->line1);
s1 += 16;
strcpy (s2, tp->line2);
s2 += 16;
strcpy (s3, tp->line3);
s3 += 16;
}
}
*s1++ = ')';
*s2++ = ')';
*s3++ = ')';
*s1 = '\n';
*s2 = '\n';
*s3 = '\n';
write (1, strip, stripsiz);
}
if (thisver < Deepmod)
for (ty = 3 * (Deepmod-thisver); ty; ty--)
write (1, blankline, realcols);
write (1, botline, realcols-1);
if (padline)
write (1, pad, padline);
skippage:;
}
}
if (skip)
fprintf (stderr, "Skipped %d blank pages.\n", skip);
}
//E*O*F split.c//
echo x - tile.c
cat > "tile.c" << '//E*O*F tile.c//'
/* tile.c */
#include "globals.h"
tile (ver, kind, linkc, str1, str2, str3)
int kind, linkc;
char *str1, *str2, *str3;
{
char *sp, *lim;
struct tile *tp;
int q1, q2, q3;
if (!NULCHARP (str1) && ((q1 = strlen (str1)) > MAXFN)) {
*(str1 + MAXFN -1) = '<';
*(str1 + MAXFN) = 0;
q1 = MAXFN;
}
if (!NULCHARP (str2) && ((q2 = strlen (str2)) > MAXFN)) {
*(str2 + MAXFN -1) = '<';
*(str2 + MAXFN) = 0;
q2 = MAXFN;
}
if (!NULCHARP (str3) && ((q3 = strlen (str3)) > MAXFN)) {
*(str3 + MAXFN -1) = '<';
*(str3 + MAXFN) = 0;
q3 = MAXFN;
}
switch (kind) {
default:
case BLANK:
tp = &Blank;
break;
case SINGLE:
tp = &Single;
strcpy (tp->line1 , str1);
lim = tp->line1 + MAXFN +1;
sp = tp->line1 + q1;
while (sp < lim)
*sp++ = SPACE;
break;
case DOUBLE:
tp = &Double;
strcpy (tp->line1 , str1);
lim = tp->line1 + MAXFN +1;
sp = tp->line1 + q1;
while (sp < lim)
*sp++ = SPACE;
strcpy (tp->line2 , str2);
lim = tp->line2 + MAXFN +1;
sp = tp->line2 + q2;
while (sp < lim)
*sp++ = SPACE;
break;
case TRIPLE:
tp = &Triple;
strcpy (tp->line1 , str1);
lim = tp->line1 + MAXFN +1;
sp = tp->line1 + q1;
while (sp < lim)
*sp++ = SPACE;
strcpy (tp->line2 , str2);
lim = tp->line2 + MAXFN +1;
sp = tp->line2 + q2;
while (sp < lim)
*sp++ = SPACE;
strcpy (tp->line3 , str3);
lim = tp->line3 + MAXFN +1;
sp = tp->line3 + q3;
while (sp < lim)
*sp++ = SPACE;
break;
case LEAF:
tp = &Leaf;
strcpy (tp->line2 , str1);
lim = tp->line2 + MAXFN +1;
sp = tp->line2 + q1;
while (sp < lim)
*sp++ = SPACE;
strcpy (tp->line3 , str2);
lim = tp->line3 + MAXFN +1;
sp = tp->line3 + q2;
while (sp < lim)
*sp++ = SPACE;
break;
case BUD:
tp = &Bud;
strcpy (tp->line2 , str1);
lim = tp->line2 + MAXFN +1;
sp = tp->line2 + q1;
while (sp < lim)
*sp++ = SPACE;
break;
case JOINT:
tp = &Joint;
strcpy (tp->line2 , str1);
lim = tp->line2 + MAXFN +1;
sp = tp->line2 + q1;
while (sp < lim)
*sp++ = SPACE;
break;
case TWIG:
tp = &Joint;
strcpy (tp->line2 , str1);
lim = tp->line2 + MAXFN +1;
sp = tp->line2 + q1;
while (sp < lim)
*sp++ = '~';
break;
}
tp->ver = ver;
tp->hor = Tx;
tp->linkc = linkc;
if (write (Td, tp, TSIZ) != TSIZ)
BAILOUT;
}
//E*O*F tile.c//
echo x - treeD.c
cat > "treeD.c" << '//E*O*F treeD.c//'
/* treeD.c --- Unix file system diagrammer */
/******************************
* Author: Istvan Mohos
* March 1990
******************************/
#define MAIN
#include "globals.h"
main (argc, argv)
int argc;
char *argv[];
{
int optchar;
char **opt;
if (argc == 1)
cmderr:
fprintf(stderr,
"Usage: %s [-wN] [-lN] [-dN] [-fN] [-blank] dir\n%s%s%s%s%s", argv[0],
"\t-w N maximum printable column width of page (min.19, max.1023)\n",
"\t-l N maximum count of lines per page (min.6)\n",
"\t-d N limit directory recursion to N depth\n",
"\t-f N truncate long file lists beyond the Nth vertical page\n",
"\t-blank force the printing of blank pages (suppressed by default)\n"),
exit(1);
opt = &(argv[1]);
while (optchar = iopt (&opt)) {
switch (optchar) {
default:
goto cmderr;
case 'w':
if ((Wid = atoi (*opt)) < 19 || Wid > 1023)
fprintf(stderr,
"page width: 19 -- 1023 columns\n"), exit(1);
break;
case 'l':
if ((Lin = atoi (*opt)) < 6)
fprintf(stderr,
"page length: minimum 6 lines\n"), exit(1);
break;
case 'd':
if ((Depth = atoi (*opt)) < 1)
fprintf(stderr,
"minimum depth: 1 level\n"), exit(1);
break;
case 'f':
if ((Fstop = atoi (*opt)) < 1)
fprintf(stderr,
"minimum depth: 1 page\n"), exit(1);
break;
case 'b':
Printblank = 1;
break;
}
}
init();
mapper (*opt);
package();
split();
goaway();
}
//E*O*F treeD.c//
echo x - makefile
cat > "makefile" << '//E*O*F makefile//'
#
CC=/bin/cc
# PC6300+ SysV
#CFLAGS=-O -DREALUNIX -DPLUS6300
# BSD
CFLAGS=-O
#.SILENT:
IFILES= iopt.o iego.o ierror.o iread.o illistn.o
FILES= treeD.o init.o tile.o listfiles.o mapper.o package.o goaway.o split.o
treeD: ${FILES} ${IFILES}
$(CC) -o $@ ${FILES} ${IFILES}
${IFILES}:i.h
${FILES}: globals.h
//E*O*F makefile//
echo x - treeX
cat > "treeX" << '//E*O*F treeX//'
#!/bin/sh
# Istvan Mohos, May 1990
if test $# -eq 0
then echo "Usage: $0 dirname"
exit 1
fi
name=`basename $0`
treeD -l79 -w115 -f1 $* > /tmp/$$.tex
tail -50 $0 > $name.tex
echo \\listing\{/tmp/$$.tex\} >> $name.tex
echo \\bye >> $name.tex
tex $name.tex
/bin/rm /tmp/$$.tex
exit 0
% TeX input begins here
\vsize 9.9in
\hsize 7.5in
\font\stt=cmtt8
\raggedbottom \nopagenumbers \stt
\baselineskip 9pt
% verbatim macros from Appendix D (pages 381, 391) of The TeXbook
% redefined ( ) : ; ~ > | for char graphics
\def\uncatcodespecials{\def\do##1{\catcode`##1=12 }\dospecials}
\def\setupverbatim{\stt
\def\par{\leavevmode\egroup\box0\endgraf}
\obeylines \uncatcodespecials \obeyspaces
\catcode`\`=\active \catcode`\^^I=\active
\catcode`(=\active \catcode`)=\active
\catcode`:=\active \catcode`;=\active
\catcode`\~=\active \catcode`>=\active \catcode`|=\active
\everypar{\startbox}}
\newdimen\w \setbox0=\hbox{\stt\space} \w=4\wd0 % width of tab
\def\startbox{\setbox0=\hbox\bgroup}
{\catcode`\`=\active \gdef`{\relax\lq}}
{\catcode`\^^I=\active
\gdef^^I{\leavevmode\egroup
\dimen0=\wd0 % the width so far, or since the previous tab
\divide\dimen0 by\w
\multiply\dimen0 by\w % compute previous multiple of \w
\advance\dimen0 by\w % advance to next multiple of \w
\wd0=\dimen0 \box0 \startbox}}
{\obeyspaces\global\let =\ } % let active space become control space
\def\listing#1{\par\begingroup\setupverbatim\input#1 \endgroup}
%
\newdimen\vsz % \vsz dimensions are relative to \baselineskip
\vsz=9pt
\newdimen\hsz % \hsz dimensions are a function of char width
\setbox0=\hbox{\stt m}
\hsz=\wd0
%
{\catcode`(=\active % vertical left border
\gdef({\kern.6\hsz\vrule width.1\hsz height.8\vsz depth.2\vsz\kern.3\hsz}}
{\catcode`)=\active % vertical right border
\gdef){\kern.2\hsz\vrule width.1\hsz height.8\vsz depth.2\vsz\kern.7\hsz}}
{\catcode`:=\active % horizontal upper border
\gdef:{\kern-.4\hsz\vrule width1.7\hsz height-.17\vsz depth.22\vsz\kern-.3\hsz}}
{\catcode`;=\active % horizontal lower border
\gdef;{\kern-.4\hsz\vrule width1.7\hsz height.78\vsz depth-.73\vsz\kern-.3\hsz}}
{\catcode`\~=\active % horizontal branch
\gdef~{\vrule width1\hsz height0\vsz depth.2\vsz}}
{\catcode`>=\active % elbow (knob) moving horizontal branch to vertical
\gdef>{\vrule width.7\hsz height0\vsz depth.2\vsz\kern.3\hsz}}
{\catcode`|=\active % vertical branch
\gdef|{\kern.3\hsz\vrule width.4\hsz height.8\vsz depth.2\vsz\kern.3\hsz}}
//E*O*F treeX//
echo x - treeD.tex
cat > "treeD.tex" << '//E*O*F treeD.tex//'
% XREF treeD treeX
\font\myit=cmti9
\font\mytt=cmtt9
\font\myletr=cmssq8
\font\bb=cmssbx10
\def\date{{\myletr May 4, 1990}}
\def\vers{{\myletr Version 1.1}}
\def\mansection{USER (1)}
\def\name{treeD}
\def\IT{{\bb treeD}}
\def\ALT{{\bb treeX}}
\hsize 5.6in
\vsize 8in
\raggedbottom
\parskip 0pt
\parindent 0pt
\myletr
% to enclose a horizontal upper-case string in a rectangle
\def\dx#1{\kern -.15em\setbox0=\hbox{\thinspace{#1}\thinspace}
\dimen0=\ht0 \advance\dimen0 by 2pt
\dimen1=\dimen0 \advance\dimen1 by -.3pt
\dimen3=\dp0 \advance\dimen3 by 2.3pt
\dimen4=\dimen3 \advance\dimen4 by -.3pt
\vrule height \dimen0 depth \dimen3 width .3pt
\vrule height \dimen0 depth -\dimen1 width \wd0
\vrule width -\wd0
\vrule height -\dimen4 depth \dimen3 width \wd0
\vrule width -\wd0
\box0
\vrule height \dimen0 depth \dimen3 width .3pt
}
% to enclose a single \tt key in a square
\def\key#1{\setbox0=\hbox{\thinspace{\mytt#1}\thinspace}
\dimen0=2ex \dimen1=\dimen0 \advance\dimen1 by -.3pt
\dimen3=.5ex \dimen4=\dimen3 \advance\dimen4 by -.3pt
\dimen5=\wd0
\vrule height \dimen0 depth \dimen3 width .3pt % left vertical
\vrule height \dimen0 depth -\dimen1 width 1.05em % top horiz
\vrule width -1.05em % backup to left
\box0 % install text
\vrule width -\dimen5 % backup to left
\vrule height -\dimen4 depth \dimen3 width 1.05em % bottom horiz
\vrule height \dimen0 depth \dimen3 width .3pt % right vertical
\thinspace
}
\def\bs{{\char92}} % \
\def\ul{{\char95}} % _
\def\pipe{{\char124}} % |
\def\lc{{\char123}} % {
\def\rc{{\char125}} % }
\def\lbrac{{\char91}} % [
\def\rbrac{{\char93}} % ]
\def\langle{{\char60}} % <
\def\rangle{{\char62}} % >
\def\circum{{\char94}} % ^
\def\caret{{\char94}} % ^
\def\tilde{{\char126}} % ~
\def\dollar{{\char36}} % $
\def\at{{\char64}} % @
\headline={{\myletr\name\hfil\mansection\hfil\name}}
\footline={\ifodd\pageno\rightfoot\else\leftfoot\fi}
\def\leftfoot{\rlap{\myletr\folio}\hfil{\vers\ --- \date}\hfil}
\def\rightfoot{\hfil{\vers\ --- \date}\hfil\llap{\myletr\folio}}
\def\S#1{\leftline{}\par\leftskip=-20pt{\bb#1}\smallskip\leftskip=0pt}
\def\SU#1{\par\leftskip=-20pt{\bb#1}\smallskip\leftskip=0pt}
\def\L{\par\leftline{}\par}
\def\I#1{\leftskip=20pt{#1}\par\leftskip=0pt}
\S{NAME}
\IT\ --- Unix file system diagrammer
\ALT\ --- produce a file system diagram in \TeX
\S{SYNOPSIS}
\IT\
\lbrac --w N\rbrac\
\lbrac --l N\rbrac\
\lbrac --d N\rbrac\
\lbrac --f N\rbrac\
\lbrac --blank\rbrac\
dirname
\ALT\ dirname
\S{DESCRIPTION}
The \IT\ file system diagrammer bypasses text width limitations imposed
by fan-fold paper or scrollable screen output mediums, and
constructs a true two-dimensional map of the file
system ``{\myit dirname\/}'' specified on the command line.
To realize a hardcopy of this map, the internal diagram is
output in the form of
equal-sized pages, each page bearing a letter/number
coordinate analogous to lettered, numbered grids on a street map.
Command line options fine tune the format of the output, control
non-default grid sizes and the depth of the directory search
as follows:
\L
\item{{\bb --w} N}
specifies that the maximum printing width of a physical page
is N character columns. The internal width of individual
grid rectangles will be expanded or reduced to the
nearest number of columns not greater
than N that will permit printing
full 16-column vertical file lists in parallel. Each page must
be wide enough to contain at least one fixed width vertical file list,
two additional bytes per page for the vertical
grid boundary markers, and one leftmost byte for the vertical character
coordinate stamp of the grid: 19 bytes minimum. The default page width
is nominally 72 bytes, 67 bytes of which is used to print a grid
rectangle.
\L
\item{{\bb --l} N}
specifies the maximum number of lines N, that can be printed on
a physical page. Vertical lists of the map are arranged in
{\myit tiles\/}, each tile three lines in depth. The smallest page
must be able to contain one tile, plus two lines for the top and bottom
horizontal grid markers, and a topmost line for the numerical
coordinate stamp of the grid: a minimum of 6 lines. The default
page length is 66 lines, containing 21 tiles.
\L
\item{{\bb --d} N}
instructs \IT\ to halt directory recursion at N depth. That is,
the command
\dx{treeD --d1 ../usr}\ results in diagramming the file structure of
{\myit ../usr\/}, but without descending into or listing the contents
of any of the
subdirectories. The default N depth (zero) specifies infinite descent.
\L
\item{{\bb --f} N}
results in truncating long file lists beyond the Nth vertical page.
The default depth page can display 21 directory levels or
63 plain files. The structure of even complex file systems can often
be contained on a single horizontal grid strip, branches using up
map width much more readily than depth. One or two directories with
many plain files may necessitate vertical expansion to show
excessively deep file lists; and can double or triple the total size of
the map while contributing little to the structural information. The
{\myit --f\/} option truncates such long (plain) file lists beyond the
specified vertical page.
\L
\item{{\bb --blank}}
forces \IT\ to output blank ``filler'' pages. If both the width and
the depth of the map is more than one grid rectangle,
the map may contain blank grids.
By default, such pages are not output. With the {\myit --blank\/}
option any blank grids are also printed, each otherwise blank page
containing the number and letter coordinates and the outline
of the grid.
\L
The \IT\ process lists the files of the examined directories via the
\dx{ls -aFq}\ command, producing also the names of ``hidden files'',
and appending a single ``file type'' character to names of
directories, executable files, and a number of special files
(differently between System~V and BSD). \IT\ does not display the
\key{.} and \key{..}
special directory links. File names longer than
14 characters are truncated in the map at 14 bytes, and the
``name too long''
file type marker \key{\langle} is added as the fifteenth
character. The file type marker of inaccessible directories
is changed from \key{/} to \key{!}, also in the cases when the
directory was made unreadable by the {\myit --d\/} option limiting
the descent. The sixteenth byte of a printed plain filename is
always a space.
\L
The \ALT\ Bourne shell script first executes the
\smallskip
\I{\mytt treeD \ -l 79 \ -w 115 \ -f1 \ \dollar *}
\smallskip
command to diagram the directory specified on its command line,
then converts the output of the \IT\ command to
plain \TeX\ input. Grid borders originally
marked by vertical \key{(} \key{)} and
horizontal \key{:} \key{;} characters are converted to
thin vertical and horizontal lines; file branch markers
\key{\tilde} \key{\pipe} \key{\rangle} are converted to
bold lines. The {\myit treeX.tex\/} file thus produced, is then input
to \TeX, and yields the device independent output
{\myit treeX.dvi\/}, ready for printing. The \IT\ command line
options embedded within \ALT\ can be overridden by specifying new
options on \ALT's command line before the final ``{\myit dirname\/}'',
however the \TeX\ format is expecting the exact 115-byte width and
79-line pages shown above.
\bye
//E*O*F treeD.tex//
echo x - README
cat > "README" << '//E*O*F README//'
treeD --- Unix file system diagrammer
The utmost conceptual simplicity of file system trees belies the
difficulty of memorizing actual nodal layouts of specific trees.
In spite a plain topological essence of TREE no two trees are
the same; and most users would have an equal chance of being able
to recall the exact twig arrangement of last year's Christmas tree
as they would in describing a 30 Meg Unix subdirectory.
Recursive listers such as 'find' obscure the tree structure by the
one-dimensionality of their output: standard output mediums of
pinfeed paper or the scrollable screen rigidly limit the width,
while allowing infinitely long lists.
The treeD file system diagrammer erases the width limitation of
the output medium, and constructs true two-dimensional maps of
file systems. To realize a hardcopy of a map, the internal diagram
is output as equal-sized pages, each page bearing a letter/number
coordinate analogous to lettered, numbered grids on a street map.
Command line options fine tune the format of the output, control
non-default grid sizes and the depth of the directory search.
-DREALUNIX should be enabled in the makefile when compiling under
System V. The 'man page' is in the file treeD.tex, and should be
processed with "tex treeD" (assuming TeX capability at the site).
The Bourne script treeX converts treeD's character-graphics
depicting branching, to bold lines under plain TeX.
//E*O*F README//
echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
105 398 2671 globals.h
78 213 1596 i.h
160 591 4205 ilib.h
19 30 262 goaway.c
40 120 749 iego.c
35 99 744 ierror.c
40 137 914 illistn.c
138 298 2905 init.c
58 206 1330 iopt.c
47 162 1143 iread.c
153 457 2655 listfiles.c
161 556 3553 mapper.c
88 364 2351 package.c
192 918 5652 split.c
125 421 2371 tile.c
64 198 1428 treeD.c
19 38 311 makefile
65 249 2480 treeX
188 1047 7408 treeD.tex
27 225 1419 README
1802 6727 46147 total
!!!
wc globals.h i.h ilib.h \
goaway.c iego.c ierror.c illistn.c init.c iopt.c iread.c \
listfiles.c mapper.c package.c split.c tile.c treeD.c \
makefile treeX treeD.tex README | sed 's=[^ ]*/==' | diff -b $temp -
exit 0
--
Istvan Mohos
...uunet!pyrdc!pyrnj!hhb!istvan
RACAL-REDAC/HHB 1000 Wyckoff Ave. Mahwah NJ 07430 201-848-8000
======================================================================
More information about the Alt.sources
mailing list