[net.sources] dir.c and dir.1l

emigh@ecsvax.UUCP (09/27/83)

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting dir.1l'
sed 's/^X//' <<'//go.sysin dd *' >dir.1l
X.TH DIR 1
X.SH NAME
DIR - Version 1.0 by Richard Conn
X.SH SYNOPSIS
X.nf
Usage:
        dir path        <-- List Files Along Path
        dir -a path     <-- List Files Along Path with Attributes
        dir -h path     <-- List Files Along Path, Including Hidden
        dir -ah path    <-- -a and -h Combined
X.fi

X.SH DESCRIPTION
	DIR is designed to provide a "clean" directory display to the user.
It lists the matching files in a double column format, alphabetizing the
entries down the columns.  File names and sizes are included in the listing,
as well as a total at the bottom of the screen.  If a file is a directory,
it is preceeded by the letter "D".

	If the -a option is used, the attributes (read, write, and execute)
are listed as well.

	If the -h option is used, hidden files (those whose names start
with a dot) are listed in addition to the other files.

X.SH EXAMPLES
	The following directory displays illustrate the various
options of DIR.  Comments are included in these displays, and they
are denoted by "<--" and extend from this symbol to the end of the line.

X.nf
$ dir $HOME/.src        <-- Display non-hidden files in $HOME/.src

  -- Filename --  - Size -      -- Filename --  - Size -
  c.c                  921      menu.c             10421
  chario.c            1498      setek.c              637
  comhex.c            2067      type.c              2611
  cpmunix.c           2490      uc.c               30629
  cpmutl7.c          32032      umodem.c           42252
  crc.c               1752      unixcpm.c           1264
  crck.c              1254      unixcpm.lbr       139904
  dir.c               7485      unixcpm.txt         1361
  dirtest.c           1325      xsq107.c           21521
  lar.c              13787      xtype107.c          6292
  lss.c                711      xusq107.c           6281
  mcheck.c            3186
           -- 23 Entries Displayed, 331681 Bytes --

$ dir -a $HOME/.src     <-- Display non-hidden files in $HOME/.src
                        <-- with Attributes

  -- Filename --  - Size -  Atr      -- Filename --  - Size -  Atr
  c.c                  921  rw-      menu.c             10421  rw-
  chario.c            1498  rw-      setek.c              637  rw-
  comhex.c            2067  rw-      type.c              2611  rw-
  cpmunix.c           2490  rw-      uc.c               30629  rw-
  cpmutl7.c          32032  rw-      umodem.c           42252  rw-
  crc.c               1752  rw-      unixcpm.c           1264  rw-
  crck.c              1254  rw-      unixcpm.lbr       139904  rw-
  dir.c               7485  rw-      unixcpm.txt         1361  rw-
  dirtest.c           1325  rw-      xsq107.c           21521  rw-
  lar.c              13787  rw-      xtype107.c          6292  rw-
  lss.c                711  rw-      xusq107.c           6281  rw-
  mcheck.c            3186  rw-
           -- 23 Entries Displayed, 331681 Bytes --

$ dir -a $HOME/.src/*.c <-- Display non-hidden files matching *.c
                        <-- in $HOME/.src with Attributes

  -- Filename --  - Size -  Atr      -- Filename --  - Size -  Atr
  c.c                  921  rw-      mcheck.c            3186  rw-
  chario.c            1498  rw-      menu.c             10421  rw-
  comhex.c            2067  rw-      setek.c              637  rw-
  cpmunix.c           2490  rw-      type.c              2611  rw-
  cpmutl7.c          32032  rw-      uc.c               30629  rw-
  crc.c               1752  rw-      umodem.c           42252  rw-
  crck.c              1254  rw-      unixcpm.c           1264  rw-
  dir.c               7485  rw-      xsq107.c           21521  rw-
  dirtest.c           1325  rw-      xtype107.c          6292  rw-
  lar.c              13787  rw-      xusq107.c           6281  rw-
  lss.c                711  rw-
           -- 21 Entries Displayed, 190416 Bytes --

$ dir -a $HOME          <-- Display non-hidden files in $HOME
                        <-- with Attributes

  -- Filename --  - Size -  Atr
  uc.log                 0  rw-
           -- 1 Entries Displayed, 0 Bytes --

$ dir -ah $HOME         <-- Display all files in $HOME with
                        <-- Attributes

  -- Filename --  - Size -  Atr      -- Filename --  - Size -  Atr
D .                    224  rwx      .profile              75  rw-
D ..                   160  rwx    D .sh                   80  rwx
D .bin                 320  rwx    D .src                 480  rwx
D .c                   464  rwx      .stmenu              225  rw-
D .doc                 224  rwx      .ucsetup             123  rw-
D .man                 432  rwx      uc.log                 0  rw-
D .new                  32  rwx
           -- 13 Entries Displayed, 2839 Bytes --
X.fi

X.SH FILES
dir.c     <-- source code

X.SH DIAGNOSTICS
	DIR issues only two diagnostic messages:
X.sp 2
1.  Dynamic Memory Overflow
X.br
	While DIR is running, it dynamically allocates memory for the
directory entries as it identifies them.  This message means the the
operating system has run out of dynamic memory to give to DIR.  This
error is fatal and non-recoverable.  I have never seen it occur.
X.sp 2
2.  Can't find filename
X.br
	DIR cannot locate a file as identified by the user.  This occurs
if the file unambigously specified by the user does not exist in the
directory searched.

X.SH BUGS
	No known bugs exist within DIR.

X.SH AUTHOR
Richard Conn
X.sp 2
DDN Addresses:  rconn@BRL, rconn@SIMTEL20
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dir.1l
	/bin/echo -n '	'; /bin/ls -ld dir.1l
fi
/bin/echo 'Extracting dir.c'
sed 's/^X//' <<'//go.sysin dd *' >dir.c
X/*
 *  DIR Version 1.0 by Richard Conn
 *
 *	DIR is an enhanced directory display utility for UNIX.
 * It produces a sorted listing of file names and sizes in two columns,
 * and the files are sorted down the columns.  If a file is a directory,
 * its name is prefixed with a "D".  File count and size totals are displayed
 * at the bottom of the listing.
 *
 */

X/*  C Libraries  */
#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#define	BUFSIZE	256

X/*  Structure of a Directory Element as Stored for DIR  */
struct dirnode {
	char name[DIRSIZ];	/* Name of File */
	int dir;		/* Dir or Not? */
	off_t size;		/* Size in Bytes */
	short mode;		/* R/W/X */
	struct dirnode *next;	/* Ptr to Next File */
};

X/*  Global Environment */
struct environ {
	int showhid;		/* Show Hidden Files? */
	int showrwx;		/* Show Attributes? */
	int filecnt;		/* Number of Files in List */
	off_t totsize;		/* Sum of All File Sizes */
	struct dirnode *first;	/* Ptr to First Elt in List */
	struct dirnode *last;	/* Ptr to Last Elt in List */
};

main(argc,argv)
char *argv[];
{
	char buf[BUFSIZE];
	struct environ env;
	int i, first;

	/* Init Environment */
	env.first = NULL;	/* No First Entry */
	env.showhid = 0;	/* No Hidden Files */
	env.showrwx = 0;	/* No R/W/X */
	env.filecnt = 0;	/* No Files */
	env.totsize = 0;	/* Accumulated File Size */

	/* Build Linked List of DIR Elements */
	if (argc == 1) build(".",&env,0);	/* current dir */
	else {
		first = 1;				/* first file is 1 */
		if (*argv[1] == '-') {
			first = 2;			/* first file is 2 */
			opts(argv[1],&env);
			if (argc == 2) build(".",&env,0);	/* curr dir */
		}
		for (i=first; i<argc; i++) build(argv[i],&env,0);	/* ea */
	}

	/* Sort Linked List of DIR Elements */
	sort(&env);

	/* Display Results */
	display(&env);
}

X/*  Process Command Options  */
opts(cmdstr,env)
char *cmdstr;
struct environ *env;
{
	while (*cmdstr != '\0')
		switch (*cmdstr++) {
		case 'A' :
		case 'a' :
			env->showrwx = 1;	/* show file attributes */
			break;
		case 'H' :
		case 'h' :
			env->showhid = 1;	/* show hidden files */
		default :
			break;
		}
}

X/*  Display Entries in Linked List  */
display(env)
struct environ *env;
{
	struct dirnode *lptr, *rptr, *elt();
	char *fname;
	int i;

	if (env->filecnt > 0) {
		printf("  -- Filename --  - Size -");
		if (env->showrwx) printf("  Atr");
	}
	if (env->filecnt > 1) {
		printf("      -- Filename --  - Size -");
		if (env->showrwx) printf("  Atr");
	}
	printf("\n");
	lptr = elt(0,env);	/* Pt to first element in left col */
	rptr = elt(env->filecnt%2 ? env->filecnt/2+1 : env->filecnt/2, env);
	for (i=0; i < env->filecnt/2; i++) {
		prelt(lptr,env);	/* Print Left Element */
		prelt(rptr,env);	/* Print Right Element */
		printf("\n");	/* New Line */
		lptr = lptr->next;	/* Pt to next */
		rptr = rptr->next;
	}
	if (env->filecnt%2) {
		prelt(lptr,env);	/* Print Odd Element */
		printf("\n");
	}
	printf("           -- %d Entries Displayed, %ld Bytes --\n",
	env->filecnt, env->totsize);
}

X/*  Print Element Pointed To  */
prelt(ptr,env)
struct dirnode *ptr;
struct environ *env;
{
	char *fname;
	int j;

	if (ptr->dir) printf("D ");			/* Print Dir Flag */
	else printf("  ");
	fname = ptr->name;
	for (j=0; j < DIRSIZ; j++)			/* Print File Name */
		if (*fname == '\0') putchar(' ');
		else putchar(*fname++);
	printf("  %8ld", ptr->size);			/* Print File Size */
	if (env->showrwx) printf("  %c%c%c",		/* Print RWX Flags */
	(ptr->mode & S_IREAD)  ? 'r' : '-',
	(ptr->mode & S_IWRITE) ? 'w' : '-',
	(ptr->mode & S_IEXEC)  ? 'x' : '-');
	printf("    ");
}

X/*  Shell Sort Directory Entries (See Pg 108 of K&R for Algorithm)  */
sort(env)
struct environ *env;
{
	int gap, i, j;
	struct dirnode dir, *eltj, *eltjg, *elt();

	for (gap = env->filecnt/2; gap > 0; gap /= 2)
		for (i = gap; i < env->filecnt; i++)
			for (j = i-gap; j >= 0; j -= gap) {
				eltj = elt(j,env);	/* pt to elt j */
				eltjg = elt(j+gap,env);	/* pt to elt j+gap */
				if (strcmp(eltj->name,eltjg->name) <= 0)
					break;
				/* temp = v[j] */
				*dir.name = '\0';	/* clear str */
				strcat(dir.name,eltj->name);
				dir.dir = eltj->dir;
				dir.size = eltj->size;
				dir.mode = eltj->mode;
				/* v[j] = v[j+gap] */
				*eltj->name = '\0';	/* clear str */
				strcat(eltj->name,eltjg->name);
				eltj->dir = eltjg->dir;
				eltj->size = eltjg->size;
				eltj->mode = eltjg->mode;
				/* v[j+gap] = temp */
				*eltjg->name = '\0';	/* clear str */
				strcat(eltjg->name,dir.name);
				eltjg->dir = dir.dir;
				eltjg->size = dir.size;
				eltjg->mode = dir.mode;
			}
}

X/* Point to Nth (Starting at 0) Element in Linked List */
struct dirnode *elt(n,env)
int n;
struct environ *env;
{
	struct dirnode *rover;
	int i;

	rover = env->first;	/* pt to first element */
	for (i=0; i<n; i++) rover = rover->next;	/* adv thru list */
	return (rover);
}

X/* Build Linked List Structure Containing Directory Entries */
build(name,env,level)
char *name;
struct environ *env;
int level;
{
	struct stat stbuf;
	struct dirnode dir;
	struct dirnode *calloc();
	char *nameptr;
	int i, ccnt;

	/* Check for File Existence */
	if (stat(name,&stbuf) == -1) {
		fprintf(stderr,"Can't find %s\n", name);
		return;
	}

	/* Check to See if File is a Directory */
	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {	/* we have a dir */
		directory(name,env,level);
		if (!level) return;
	}

	/*  Check Hidden Entries */
	if (*name == '.' && !(env->showhid)) return;

	/*  Store Entry in Memory  */
	if (env->first == NULL) {	/* First Entry Processing */
		env->first = calloc(1, sizeof(dir));
		env->last = env->first;
	}
	else {				/* Nth Entry Processing */
		(*env->last).next = calloc(1, sizeof(dir));
		env->last = (*env->last).next;
	}
	if (env->last == NULL) {
		fprintf(stderr, "Dynamic Memory Overflow\n");
		exit(0);
	}

	/* Store Entry Values */
	env->filecnt++;		/* Increment File Count */
	(*env->last).next = NULL;
	nameptr = name;		/* Pt to first char of file name */
	ccnt = strlen(name);	/* Number of chars in file name */
	for (i=0; i < ccnt; i++)	/* Find Last Part of Name */
		if (*name++ == '/') nameptr = name;
	strcat((*env->last).name,nameptr);	/* Save File Name */
	(*env->last).size = stbuf.st_size;	/* Save File Size */
	(*env->last).mode = stbuf.st_mode;	/* Save Mode Bits */
	env->totsize += stbuf.st_size;		/* Increment Total Sizes */
	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) 	/* Set Dir Flag */
		(*env->last).dir = 1;
	else (*env->last).dir = 0;
}

X/* Process All Entries in a Directory */
directory(name,env,level)
char *name;
struct environ *env;
int level;
{
	struct direct dirbuf;
	char *nbp, *nep;
	char dirname[BUFSIZE];
	char filename[DIRSIZ];
	int i,fd;

	if (level) return;	/* don't recurse */

	/* Build Name of Directory into DIRNAME */
	nep = dirname;
	nbp = name;
	while (*nbp != '\0') *nep++ = *nbp++;
	*nep = '\0';	/* terminate string */
	if (nep+DIRSIZ+2 >= dirname+BUFSIZE)	/* name too long */
		return;

	/* Log Into Directory */
	if (chdir(dirname)) {
		fprintf(stderr, "Directory %s Not Found\n", dirname);
		return;
	}

	/* Open Directory File */
	if ((fd = open(".",0)) == -1) return;

	/* Read Through the Elements in the Directory */
	while (read(fd, (char *)&dirbuf, sizeof(dirbuf)) > 0) {
		if (dirbuf.d_ino == 0)	/* slot not in use */
			continue;
		for (i=0, nep=filename; i<DIRSIZ; i++)	/* build file name */
			*nep++ = dirbuf.d_name[i];
		*nep++ = '\0';
		build(filename,env,level+1);	/* reenter build for new file */
	}
	close(fd);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dir.c
	/bin/echo -n '	'; /bin/ls -ld dir.c
fi