[comp.os.minix] vtree

dono@killer.DALLAS.TX.US (Don OConnell) (01/08/89)

Here is a program that prints a tree of directory structs(graphical or non-gr)
as well as printing sizes of directories(similar to du).

Enjoy!
------------------------------Cut Here-------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  compile.bat customize.h hash.c hash.h makefile
#   patchlevel.h readme vtree.1 vtree.c vtree.man
# Wrapped by dono@killer on Sat Jan  7 14:50:55 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f compile.bat -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"compile.bat\"
else
echo shar: Extracting \"compile.bat\" \(213 characters\)
sed "s/^X//" >compile.bat <<'END_OF_compile.bat'
Xtcc -mt -I\minix\include -G -O -r -Z -1 -c *.c
Xif errorlevel 1 goto end
Xtlink /m/n/c/d  \minix\lib\crtso vtree hash,vtree,,\minix\lib\tminix
Xif errorlevel 1 goto end
Xecho dos2out
X..\commands\dos2out -d vtree
X:end
END_OF_compile.bat
if test 213 -ne `wc -c <compile.bat`; then
    echo shar: \"compile.bat\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f customize.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"customize.h\"
else
echo shar: Extracting \"customize.h\" \(429 characters\)
sed "s/^X//" >customize.h <<'END_OF_customize.h'
X/* agef
X  
X   SCCS ID	@(#)customize.h	1.6	7/9/87
X  
X   This is the customizations file.  It changes our ideas of
X   how to read directories.
X*/
X
X/*#define FLOAT_FORMAT	"%d %#4.1fM"	/* if your printf does %# */
X#define FLOAT_FORMAT	"%d %4.1fM" /* if it doesn't do %# */
X
X#define NAMELEN 255     /* max size of a full pathname */
X
X#   include     <dir.h>
X#	define	OPEN	DIR
X#	define	READ	struct direct
X#	define	NAME(x)	((x).d_name)
END_OF_customize.h
if test 429 -ne `wc -c <customize.h`; then
    echo shar: \"customize.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f hash.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"hash.c\"
else
echo shar: Extracting \"hash.c\" \(4351 characters\)
sed "s/^X//" >hash.c <<'END_OF_hash.c'
X/* hash.c
X  
X   SCCS ID	@(#)hash.c	1.6	7/9/87
X  
X * Hash table routines for AGEF.  These routines keep the program from
X * counting the same inode twice.  This can happen in the case of a
X * file with multiple links, as in a news article posted to several
X * groups.  The use of a hashing scheme was suggested by Anders
X * Andersson of Uppsala University, Sweden.  (enea!kuling!andersa) 
X */
X
X/* hash.c change history:
X 28 March 1987		David S. Hayes (merlin@hqda-ai.UUCP)
X	Initial version.
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "hash.h"
X
X
Xstatic struct htable *tables[TABLES];
X
X/* These are for statistical use later on. */
Xstatic int      hs_tables = 0,	/* number of tables allocated */
X                hs_duplicates = 0,	/* number of OLD's returned */
X                hs_buckets = 0,	/* number of buckets allocated */
X                hs_extensions = 0,	/* number of bucket extensions */
X                hs_searches = 0,/* number of searches */
X                hs_compares = 0,/* total key comparisons */
X                hs_longsearch = 0;	/* longest search */
X
X
X /*
X  * This routine takes in a device/inode, and tells whether it's been
X  * entered in the table before.  If it hasn't, then the inode is added
X  * to the table.  A separate table is maintained for each major device
X  * number, so separate file systems each have their own table. 
X  */
X
Xh_enter(dev, ino)
X    dev_t           dev;
X    ino_t           ino;
X{
X    static struct htable *tablep = (struct htable *) 0;
X    register struct hbucket *bucketp;
X    register ino_t *keyp;
X    int             i;
X
X    hs_searches++;		/* stat, total number of calls */
X
X    /*
X     * Find the hash table for this device. We keep the table pointer
X     * around between calls to h_enter, so that we don't have to locate
X     * the correct hash table every time we're called.  I don't expect
X     * to jump from device to device very often. 
X     */
X    if (!tablep || tablep->device != dev) {
X	for (i = 0; tables[i] && tables[i]->device != dev;)
X	    i++;
X	if (!tables[i]) {
X	    tables[i] = (struct htable *) malloc(sizeof(struct htable));
X	    if (tables[i] == NULL) {
X		perror("can't malloc hash table");
X		return NEW;
X	    };
X/*	    bzero(tables[i], sizeof(struct htable)); */
X	    memset((char *) tables[i], '\0', sizeof (struct htable));
X	    tables[i]->device = dev;
X	    hs_tables++;	/* stat, new table allocated */
X	};
X	tablep = tables[i];
X    };
X
X    /* Which bucket is this inode assigned to? */
X    bucketp = &tablep->buckets[ino % BUCKETS];
X
X    /*
X     * Now check the key list for that bucket.  Just a simple linear
X     * search. 
X     */
X    keyp = bucketp->keys;
X    for (i = 0; i < bucketp->filled && *keyp != ino;)
X	i++, keyp++;
X
X    hs_compares += i + 1;	/* stat, total key comparisons */
X
X    if (i && *keyp == ino) {
X	hs_duplicates++;	/* stat, duplicate inodes */
X	return OLD;
X    };
X
X    /* Longest search.  Only new entries could be the longest. */
X    if (bucketp->filled >= hs_longsearch)
X	hs_longsearch = bucketp->filled + 1;
X
X    /* Make room at the end of the bucket's key list. */
X    if (bucketp->filled == bucketp->length) {
X	/* No room, extend the key list. */
X	if (!bucketp->length) {
X	    bucketp->keys = (ino_t *) calloc(EXTEND, sizeof(ino_t));
X	    if (bucketp->keys == NULL) {
X		perror("can't malloc hash bucket");
X		return NEW;
X	    };
X	    hs_buckets++;
X	} else {
X	    bucketp->keys = (ino_t *)
X		realloc(bucketp->keys,
X			(EXTEND + bucketp->length) * sizeof(ino_t));
X	    if (bucketp->keys == NULL) {
X		perror("can't extend hash bucket");
X		return NEW;
X	    };
X	    hs_extensions++;
X	};
X	bucketp->length += EXTEND;
X    };
X
X    bucketp->keys[++(bucketp->filled)] = ino;
X    return NEW;
X}
X
X
X /* Buffer statistics functions.  Print 'em out. */
X
X#ifdef HSTATS
Xvoid
Xh_stats()
X{
X    fprintf(stderr, "\nHash table management statistics:\n");
X    fprintf(stderr, "  Tables allocated: %d\n", hs_tables);
X    fprintf(stderr, "  Buckets used: %d\n", hs_buckets);
X    fprintf(stderr, "  Bucket extensions: %d\n\n", hs_extensions);
X    fprintf(stderr, "  Total searches: %d\n", hs_searches);
X    fprintf(stderr, "  Duplicate keys found: %d\n", hs_duplicates);
X    if (hs_searches)
X	fprintf(stderr, "  Average key search: %d\n",
X		hs_compares / hs_searches);
X    fprintf(stderr, "  Longest key search: %d\n", hs_longsearch);
X    fflush(stderr);
X}
X
X#endif
END_OF_hash.c
if test 4351 -ne `wc -c <hash.c`; then
    echo shar: \"hash.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f hash.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"hash.h\"
else
echo shar: Extracting \"hash.h\" \(625 characters\)
sed "s/^X//" >hash.h <<'END_OF_hash.h'
X/* Defines for the agef hashing functions.
X
X   SCCS ID	@(#)hash.h	1.6	7/9/87
X */
X
X#define BUCKETS		257	/* buckets per hash table */
X#define TABLES		50	/* hash tables */
X#define EXTEND		100	/* how much space to add to a bucket */
X
Xstruct hbucket {
X    int             length;	/* key space allocated */
X    int             filled;	/* key space used */
X    ino_t          *keys;
X};
X
Xstruct htable {
X    dev_t           device;	/* device this table is for */
X    struct hbucket  buckets[BUCKETS];	/* the buckets of the table */
X};
X
X#define OLD	0		/* inode was in hash already */
X#define NEW	1		/* inode has been added to hash */
END_OF_hash.h
if test 625 -ne `wc -c <hash.h`; then
    echo shar: \"hash.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"makefile\"
else
echo shar: Extracting \"makefile\" \(1504 characters\)
sed "s/^X//" >makefile <<'END_OF_makefile'
X#	Build VTREE
X#
X#	Define the type of system we're working with.  Three
X# choices:
X#
X#   1.	BSD Unix 4.2 or 4.3.  Directory read support in the
X# standard library, so we don't have to do much.  Select BSD.
X#
X#   2.	System V.  I depend on Doug Gwyn's directory reading
X# routines.  They were posted to Usenet "comp.sources" early in
X# May 1987.  They're worth the effort to get, if you don't have
X# them already.  Select SYS_V.  Be sure to define NLIB to be the
X# 'cc' option to include the directory library.
X#
X#   3.  System III, or machines without any directory read
X# packages.  I have a minimal kludge.  Select SYS_III.
X#
X
X# Case 1:
X#SYS=	-DBSD
X#NLIB=
X
X# Case 2:
XSYS=	-DSYS_V
XNLIB=	-lndir
X
X# Case 3:
X#SYS=	-DSYS_III
X#NLIB=
X
X
X#	Standard things you may wish to change:
X#
X#	INSTALL		directory to install vtree in
X
XINSTALL	=	/usr/local/bin
X
X
X#	The following OPTIONS may be defined:
X#
X#	LSTAT		we have the lstat(2) system call (BSD only)
X#	HSTATS		print hashing statistics at end of run
X#
X#	Define LSTAT, HSTATS here
X
XOPTIONS	= 
X
X#  END OF USER-DEFINED OPTIONS
X
X
XCFLAGS=	-O $(SYS) $(OPTIONS)
XSRCS=		vtree.c	hash.c	direct.c	\
X		hash.h	customize.h	patchlevel.h
XOBJS=		vtree.o	hash.o
X
Xvtree:		$(OBJS)
X		cc -o vtree $(CFLAGS) $(OBJS) $(NLIB)
X
Xinstall:	vtree
X		cp vtree $(INSTALL)
X		chown local $(INSTALL)/vtree
X		chgrp pd $(INSTALL)/vtree
X		chmod 755 $(INSTALL)/vtree
X
Xclean:
X		rm -f $(OBJS) vtree *~
X
Xvtree.o:	vtree.c direct.c hash.h customize.h patchlevel.h
X
Xhash.o:		hash.c hash.h customize.h patchlevel.h
END_OF_makefile
if test 1504 -ne `wc -c <makefile`; then
    echo shar: \"makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f patchlevel.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"patchlevel.h\"
else
echo shar: Extracting \"patchlevel.h\" \(93 characters\)
sed "s/^X//" >patchlevel.h <<'END_OF_patchlevel.h'
X/* Patchlevel for VTREE
X
X*/
X
X#define PATCHLEVEL 	V1.0
X#define	VERSION		"VTREE	1.0	4/26/88\n"
END_OF_patchlevel.h
if test 93 -ne `wc -c <patchlevel.h`; then
    echo shar: \"patchlevel.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f readme -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"readme\"
else
echo shar: Extracting \"readme\" \(1130 characters\)
sed "s/^X//" >readme <<'END_OF_readme'
X	This is the first release of the VTREE (please pronounce this
XV-TREE, for "visual files") program.  The program is designed to show
Xthe layout of a directory tree or filesystem.  It has options to show
Xthe amount of storage being taken up in each directory, count the number
Xof inodes, etc.
X
X	VTREE is dependent on the UCB directory reading routines. 
XPublic-domain routines for System V have been released to the Usenet
X(comp.sources.unix) by Doug Gwyn (gwyn@brl.mil).  If you don't have
Xthem, they're worth your trouble to get.  Still, you may be able to use
Xthe System III configuration of the Makefile as a stopgap measure. 
X
X
X	The program was originally the program AGEF, written by David S.
XHayes.  As it stands now the hashing routines are untouched by myself,
Xbut most of the rest of the program is different.  The System III
Xroutines are also his.
X
X
X	I hope this program will be useful to you.  If you find bugs in
Xit or have any suggestions for improvements, I'd like to hear about
Xthem.
X
XJonathan B. Bayer
XIntelligent Software Products, Inc.
XRockville Centre, NY   11570
XPhone: (516) 766-2867
Xusenet:	uunet!ispi!root
X
END_OF_readme
if test 1130 -ne `wc -c <readme`; then
    echo shar: \"readme\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f vtree.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"vtree.1\"
else
echo shar: Extracting \"vtree.1\" \(1478 characters\)
sed "s/^X//" >vtree.1 <<'END_OF_vtree.1'
X.TH VTREE 1 local
X.SH NAME
Xvtree \- print a visual tree of a directory structure
X.SH SYNOPSIS
X.B vtree
X[ \-d] [ \-h # ] [ \-i ] [ \-s ] [ \-q ] [ \-v ] [ \-V ] 
X.SH DESCRIPTION
X.IP 
XVtree is a program which scans directories/filesystems and displays the structure on the
Xstandard output.   Normally it will ignore duplicate inodes.
X.IP "\-d "
XInstructs the program to include the duplicate inodes in the totals.
X.PP
X.IP "\-h #"
XSpecifies how many levels down to display.
X.PP
X.IP \-i 
Xdisplays the number of inodes (excluding directories) in each directory 
X.PP
X.IP \-s 
XInstructs the program to continue counting inodes and file sizes when it
Xhas exceeded the levels specified.
X.PP
X.IP \-t 
XDisplays totals at the end of the report
X.PP
X.IP \-q
XQuick display.  No totals of any kind are kept.
X.PP
X.IP \-v
XVisual display.  Normally the program displays one directory on a line,
Xindenting lines to indicate subdirectories.  The visual display builds
Xa tree on the screen showing the actual directory structure.  This method
Xof display excludes any totals other than the final totals.
X.PP
X.IP \-V
XShows current version.  Specifying 2 Vs (-VV) will also show all options in
Xforce.
X.SH AUTHOR
XJonathan B. Bayer
X.PP
XIntelligent Software Products, Inc.
X.PP
XRockville Centre, NY   11570
X.SH ACKNOWLEDGMENTS
XThe program uses the directory routines written and released to the
Xpublic domain by Doug Gwyn.
XThe program is originally based on a program called AGEF written by
XDavid S. Hayes.
END_OF_vtree.1
if test 1478 -ne `wc -c <vtree.1`; then
    echo shar: \"vtree.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f vtree.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"vtree.c\"
else
echo shar: Extracting \"vtree.c\" \(9639 characters\)
sed "s/^X//" >vtree.c <<'END_OF_vtree.c'
X/* vtree
X  
X   +=======================================+
X   | This program is in the public domain. |
X   +=======================================+
X  
X   This program shows the directory structure of a filesystem or 
X   part of one.  It also shows the amount of space taken up by files
X   in each subdirectory. 
X  
X   Call via
X  
X	vtree fn1 fn2 fn3 ...
X  
X   If any of the given filenames is a directory (the usual case),
X   vtree will recursively descend into it, and the output line will
X   reflect the accumulated totals for all files in the directory.
X   
X   This program is based upon "agef" written by David S. Hayes at the 
X   Army Artificial Intelligence Center at the Pentagon.
X   
X   This program is dependent upon the new directory routines written by
X   Douglas A. Gwyn at the US Army Ballistic Research Laboratory at the
X   Aberdeen Proving Ground in Maryland.
X*/
X
X#include "patchlevel.h"
X
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X
X#include "customize.h"
X#include "hash.h"
X
X#define SAME		0	/* for strcmp */
X#define BLOCKSIZE	512	/* size of a disk block */
X
X#define K(x)		((x + 1023)/1024)	/* convert stat(2) blocks into
X					 * k's.  On my machine, a block
X					 * is 512 bytes. */
X
X#define	TRUE	1
X#define	FALSE	0
X#define	V_CHAR	"|"	/*	Vertical character	*/
X#define	H_CHAR	"-"	/*	Horizontal character	*/
X#define	A_CHAR	">"	/*	Arrow char		*/
X#define	T_CHAR	"+"	/*	Tee char		*/
X#define	L_CHAR	"\\"	/*	L char, bottom of a branch	*/
X
X#define	MAX_COL_WIDTH	15
X#define	MAX_V_DEPTH	256		/* max depth for visual display */
X
Xint		indent = 0,		/* current indent */
X		depth = 9999,		/* max depth */
X		cur_depth = 0,	
X		sum = FALSE,		/* sum the subdirectories */
X		dup = FALSE,		/* use duplicate inodes */
X		cnt_inodes = FALSE,	/* count inodes */
X		quick = FALSE;		/* quick display */
Xint     visual = FALSE;     /* visual display */
Xint     version = 0;        /* = 1 display version, = 2 show options */
X        sub_dirs[MAX_V_DEPTH];
X
Xstruct	stat	stb;			/* Normally not a good idea, but */
X					/* this structure is used through- */
X					/* out the program		   */
X
Xextern char    *optarg;			/* from getopt(3) */
Xextern int      optind,
X                opterr;
X
X
Xchar           *Program;		/* our name */
Xshort           sw_follow_links = 1;	/* follow symbolic links */
Xshort           sw_summary;		/* print Grand Total line */
X
Xint             total_inodes, inodes;	/* inode count */
Xlong            total_sizes, sizes;	/* block count */
X
Xchar            topdir[NAMELEN];	/* our starting directory */
X
X
X /*
X  * We ran into a subdirectory.  Go down into it, and read everything
X  * in there. 
X  */
Xint	indented = FALSE;	/* These had to be global since they */
Xint	last_indent = 0;	/* determine what gets displayed during */
X				/* the visual display */
X
Xdown(subdir)
Xchar	*subdir;
X{
XOPEN	*dp;			/* stream from a directory */
XOPEN	*opendir ();
Xchar	cwd[NAMELEN];
XREAD	*file;			/* directory entry */
XREAD	*readdir ();
Xint	i;
Xstruct	stat	stb;
X
X	if ( (cur_depth == depth) && (!sum) )
X		return;
X
X/* display the tree */
X
X	if (cur_depth < depth) {
X		if (visual) {
X			if (!indented) {
X				for (i = 1; i <cur_depth; i++) {
X					if (sub_dirs[i]) {
X						printf("%*s%s   ",MAX_COL_WIDTH-4," ",V_CHAR);
X					}
X					else printf("%*s   ",MAX_COL_WIDTH-3," ");
X				}
X				if (cur_depth>0) {
X					if (sub_dirs[cur_depth] == 0) {
X						printf("%*s%s%s%s ",MAX_COL_WIDTH-4," ",L_CHAR,H_CHAR,A_CHAR);
X					}
X					else printf("%*s%s%s%s ",MAX_COL_WIDTH-4," ",T_CHAR,H_CHAR,A_CHAR);
X				}
X			} else {
X				for (i = 1; i<MAX_COL_WIDTH-last_indent-3; i++)
X					printf("%s",H_CHAR);
X				printf("%s%s%s ",T_CHAR,H_CHAR,A_CHAR);
X			}
X
X/* This will only happen on the first entry into this routine */
X
X			if (strlen(subdir) > MAX_COL_WIDTH - 4) {
X				printf("%s\n",subdir);
X				printf("%s ",&subdir[strlen(subdir)-MAX_COL_WIDTH+5]);
X				last_indent = MAX_COL_WIDTH - 4;
X			}
X			else {
X				printf("%s ",subdir);
X				last_indent = strlen(subdir)+1;
X			}
X			indented = TRUE;
X		}
X		else printf("%*s%s",indent," ",subdir);
X	}
X
X/* open subdirectory */
X
X	if ((dp = opendir(subdir)) == NULL) {
X		printf(" - can't read %s\n", subdir);
X		indented = FALSE;
X		return;
X	}
X
X	cur_depth++;
X	indent+=3;
X
X	getcwd(cwd, sizeof(cwd));		/* remember where we are */
X	chdir(subdir);				/* go into subdir */
X	if ( (!quick) && (!visual) ) {
X
X/* accumulate total sizes and inodes in current directory */
X
X		for (file = readdir(dp); file != NULL; file = readdir(dp))
X			if (strcmp(NAME(*file), "..") != SAME) 
X				get_data(NAME(*file),FALSE);
X
X		if (cur_depth<depth) {
X			if (cnt_inodes) printf("   %d",inodes);
X			printf(" : %ld\n",sizes);
X			total_sizes += sizes;
X			total_inodes += inodes;
X			sizes = 0;
X			inodes = 0;
X		}
X		rewinddir(dp);
X	} else if (!visual) printf("\n");
X
X	if (visual) {
X
X/* count subdirectories */
X
X		for (file = readdir(dp); file != NULL; file = readdir(dp)) {
X			if ( (strcmp(NAME(*file), "..") != SAME) &&
X			     (strcmp(NAME(*file), ".") != SAME) ) {
X				if (chk_4_dir(NAME(*file))) {
X					sub_dirs[cur_depth]++;
X				}
X			}
X		}
X		rewinddir(dp);
X	}
X	
X/* go down into the subdirectory */
X
X	for (file = readdir(dp); file != NULL; file = readdir(dp)) {
X		if ( (strcmp(NAME(*file), "..") != SAME) &&
X		     (strcmp(NAME(*file), ".") != SAME) ) {
X			if (chk_4_dir(NAME(*file))) 
X				sub_dirs[cur_depth]--;
X			get_data(NAME(*file),TRUE);
X		     }
X	}
X
X	if ( (!quick) && (!visual) ) {
X
X/* print totals */
X
X		if (cur_depth == depth) {
X			if (cnt_inodes) printf("   %d",inodes);
X			printf(" : %ld\n",sizes);
X			total_sizes += sizes;
X			total_inodes += inodes;
X			sizes = 0;
X			inodes = 0;
X		}
X	} else if (visual && indented) {
X		printf("\n");
X		indented = FALSE;
X	}
X
X	indent-=3;
X	sub_dirs[cur_depth] = 0;
X	cur_depth--;
X
X	chdir(cwd);			/* go back where we were */
X	closedir(dp);			/* shut down the directory */
X} /* down */
X
X
X
Xint	chk_4_dir(path)
Xchar	*path;
X{
X	if (is_directory(path)) return TRUE;
X	else return FALSE;
X		
X} /* chk_4_dir */
X
X
X
X/* Is the specified path a directory ? */
X
Xint	is_directory(path)
Xchar           *path;
X{
X
X#ifdef LSTAT
X	if (sw_follow_links)
X		stat(path, &stb);	/* follows symbolic links */
X	else
X		lstat(path, &stb);	/* doesn't follow symbolic links */
X#else
X	stat(path, &stb);
X#endif
X
X	if ((stb.st_mode & S_IFMT) == S_IFDIR)
X		return TRUE;
X	else return FALSE;
X} /* is_directory */
X
X
X
X /*
X  * Get the aged data on a file whose name is given.  If the file is a
X  * directory, go down into it, and get the data from all files inside. 
X  */
X
Xget_data(path,cont)
Xchar           *path;
Xint		cont;    
X{
X/* struct	stat	stb; */
Xint		i;
X
X	if (cont) { 
X		if (is_directory(path)) 
X			down(path);
X	}
X	else {
X		if (is_directory(path)) return;
X
X		    /* Don't do it again if we've already done it once. */
X
X		if ( (h_enter(stb.st_dev, stb.st_ino) == OLD) && (!dup) )
X			return;
X		inodes++;
X		sizes+= K(stb.st_size);
X	}
X} /* get_data */
X
X
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
Xint	i,
X	j,
X	err = FALSE;
Xint	option;
Xint	user_file_list_supplied = 0;
X
X	Program = *argv;		/* save our name for error messages */
X
X    /* Pick up options from command line */
X
X	while ((option = getopt(argc, argv, "dh:istqvV")) != EOF) {
X		switch (option) {
X			case 'h':	depth = atoi(optarg);
X					while (*optarg) {
X						if (!isdigit(*optarg)) {
X							err = TRUE;
X							break;
X						}
X						optarg++;
X					}
X					break;
X			case 'd':	dup = TRUE;
X					break;	
X			case 'i':	cnt_inodes = TRUE;
X					break;		
X			case 's':	sum = TRUE;
X					break;
X			case 't':	sw_summary = TRUE;
X					break;
X			case 'q':	quick = TRUE;
X					dup = FALSE;
X					sum = FALSE;
X					cnt_inodes = FALSE;
X					break;
X			case 'v':	visual = TRUE;
X					break;
X			case 'V':	version++;
X					break;
X			default:	err = TRUE;
X		}
X		if (err) {
X			fprintf(stderr,"%s: [ -d ] [ -h # ] [ -i ] [ -s ] [ -q ] [ -v ] [ -V ]\n",Program);
X			fprintf(stderr,"	-d	count duplicate inodes\n");
X			fprintf(stderr,"	-h #	height of tree to look at\n");
X			fprintf(stderr,"	-i	count inodes\n");
X			fprintf(stderr,"	-s	include subdirectories not shown due to -h option\n");
X			fprintf(stderr,"	-t	totals at the end\n");
X			fprintf(stderr,"	-q	quick display, no counts\n");
X			fprintf(stderr,"	-v	visual display\n");
X			fprintf(stderr,"	-V	show current version\n");
X			fprintf(stderr,"		(2 Vs shows specified options)\n");
X			exit(-1);
X		}
X	
X	}
X
X	if (version > 0 ) {
X		printf("%s",VERSION);
X		if (version>1) {
X			printf("Tree height:	%d\n",depth);
X			if (dup) printf("Include duplicate inodes\n");
X			if (cnt_inodes) printf("Count inodes\n");
X			if (sum) printf("Include unseen subdirectories in totals\n");
X			if (sw_summary) printf("Print totals at end\n");
X			if (quick) printf("Quick display only\n");
X			if (visual) printf("Visual tree\n");
X		}
X	}
X	
X    /* If user didn't specify targets, inspect current directory. */
X
X	if (optind >= argc) {
X		user_file_list_supplied = 0;
X	} else {
X		user_file_list_supplied = 1;
X	}
X
X	getcwd(topdir, sizeof (topdir));		/* find out where we are */
X
X    /* Zero out grand totals */
X	total_inodes = total_sizes = 0;
X    /* Zero out sub_dirs */
X	for (i=0; i<=MAX_V_DEPTH; i++) {
X		sub_dirs[i] = 0;
X	}
X		
X    /* Inspect each argument */
X	for (i = optind; i < argc || (!user_file_list_supplied && i == argc); i++) {
X		cur_depth = inodes = sizes = 0;
X
X		chdir(topdir);		/* be sure to start from the same place */
X		get_data(user_file_list_supplied?argv[i] : topdir, TRUE);/* this may change our cwd */
X
X		total_inodes += inodes;
X		total_sizes += sizes;
X	}
X
X	if (sw_summary) {
X		printf("\n\nTotal space used: %ld\n",total_sizes);
X		if (cnt_inodes) printf("Total inodes: %d\n",inodes);
X	}
X	
X#ifdef HSTATS
X	fflush(stdout);
X	h_stats();
X#endif
X
X	exit(0);
X} /* main */
X
X
END_OF_vtree.c
if test 9639 -ne `wc -c <vtree.c`; then
    echo shar: \"vtree.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f vtree.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"vtree.man\"
else
echo shar: Extracting \"vtree.man\" \(1898 characters\)
sed "s/^X//" >vtree.man <<'END_OF_vtree.man'
X
X
X
X     VTREE(1)                UNIX 5.0 (local)                 VTREE(1)
X
X
X
X     NAME
X          vtree - print a visual tree of a directory structure
X
X     SYNOPSIS
X          vtree [ -d] [ -h # ] [ -i ] [ -s ] [ -q ] [ -v ] [ -V ]
X
X     DESCRIPTION
X               Vtree is a program which scans directories/filesystems
X               and displays the structure on the standard output.
X               Normally it will ignore duplicate inodes.
X
X          -d   Instructs the program to include the duplicate inodes
X               in the totals.
X
X          -h # Specifies how many levels down to display.
X
X          -i   displays the number of inodes (excluding directories)
X               in each directory
X
X          -s   Instructs the program to continue counting inodes and
X               file sizes when it has exceeded the levels specified.
X
X          -t   Displays totals at the end of the report
X
X          -q   Quick display.  No totals of any kind are kept.
X
X          -v   Visual display.  Normally the program displays one
X               directory on a line, indenting lines to indicate
X               subdirectories.  The visual display builds a tree on
X               the screen showing the actual directory structure.
X               This method of display excludes any totals other than
X               the final totals.
X
X          -V   Shows current version.  Specifying 2 Vs (-VV) will also
X               show all options in force.
X
X     AUTHOR
X          Jonathan B. Bayer
X
X          Intelligent Software Products, Inc.
X
X          Rockville Centre, NY   11570
X
X     ACKNOWLEDGMENTS
X          The program uses the directory routines written and released
X          to the public domain by Doug Gwyn.  The program is
X          originally based on a program called AGEF written by David
X          S. Hayes.
X
X
X
X
X
X
X
X     Page 1                                         (printed 12/27/88)
X
X
X
X
END_OF_vtree.man
if test 1898 -ne `wc -c <vtree.man`; then
    echo shar: \"vtree.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0