[net.sources] List directories sorted in columns

lvc@cbsck.UUCP (Larry Cipriani) (11/21/85)

If you're as impatient as I am you'll appreciate this program.
It lists files sorted in columns, but, because of it's limited
scope, is much faster than the lsc command.  It runs on every
version of UNIX I know of.
				Larry Cipriani


#!/bin/sh
: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract:
: 'l.c'
echo extracting - 'l.c'
sed 's/^X//' > 'l.c' << 'END_OF_FILE'
X/*
X**  This program lists all the file names in <directory>.  They
X**  are listed in at most five columns.  Directories are listed
X**  with a terminating /, executables with a terminating *.
X**  The current directory is the default directory.
X**
X**  usage: l [-a] [directory]
X*/
X
X#include <stdio.h>	/* standard i/o package */
X#include <sys/types.h>	/* needed for <sys/stat.h> */
X#include <sys/stat.h>	/* stat structure declared */
X#include <sys/dir.h>	/* direct structure declared */
X
X#define TABSIZ=8
X#define MAXCOL=5	/* maximum number of columns = 80/16 */
X			/* 80 = number of columns on terminal */
X			/* 16 = DIRSIZ + 2 blanks for spacing */
X
Xchar *malloc();		/* memory allocator - section 3 */
X
Xint copyn();		/* copies s2 to s1, returns number copied */
Xint error();		/* prints an error message */
Xint namecmp();		/* comparison function for file names */
Xint qsort();		/* quicker sort - section 3 */
X
Xchar *progname;
X
Xmain(argc, argv)
X	int	argc;
X	char	*argv[];
X{
X	int	fd, i, aflg;
X	int	ncols, nrows, nfiles, nstructs, ntabs;
X	int	col, row, filenum, len, pad;
X	char 	filename[DIRSIZ+1], *fmt1, *fmt2;
X	char	iobuf[BUFSIZ];
X	char	*usage = "usage: %s [-a] [directory]\n";
X	char	*cannot = "%s: cannot %s %s\n";
X	char	*dir, *dot;
X	unsigned dirsize;
X	struct	direct *head, **headp;
X	struct	stat stbuf;
X
X	aflg = 0;
X	dir = (char *)0;
X	dot = ".";
X	progname = argv[0];
X
X	if (argc > 3)
X		error(usage, (char *)0, (char *)0);
X
X	for (i = 1; i < argc; i++)
X	{
X		if (strcmp(argv[i], "-a") == 0 && aflg == 0)
X			aflg++;
X		else
X		if (dir == (char *)0)
X			dir = argv[i];
X		else
X			error(usage, (char *)0, (char *)0);
X	}
X
X	if (dir == (char *)0)
X		dir = dot;
X	else
X	if (chdir(dir) == -1)
X		error(cannot, "chdir", dir);
X
X	if ((fd = open(dot , 0)) == -1)
X		error(cannot, "open", dir);
X
X	if (stat(dot, &stbuf) == -1)
X		error(cannot, "stat", dir);
X
X	setbuf(stdout, iobuf);
X
X	dirsize = (unsigned)stbuf.st_size;
X	nstructs = dirsize/sizeof(struct direct);
X	head = (struct direct *)malloc(dirsize);
X	if (read(fd, (char *)head, dirsize) == -1)
X		error(cannot, "read", dir);
X	headp = (struct direct **)malloc(sizeof(struct direct **) * nstructs);
X
X	/* set up pointers only to the files to be listed */
X
X	if (aflg)
X	{
X		for (nfiles = i = 0; i < nstructs; i++)
X			if (head[i].d_ino != (ino_t)0)
X				headp[nfiles++] = &head[i];
X	}
X	else
X	{
X		for (nfiles = i = 0 ; i < nstructs; i++)
X			if (head[i].d_ino != (ino_t)0 &&
X					head[i].d_name[0] != '.')
X				headp[nfiles++] = &head[i];
X	}
X
X	if (nfiles == 0)
X		exit(0);
X
X	/* sort only the pointers */
X
X	qsort((char *)headp, nfiles, (int)sizeof(struct direct **), namecmp);
X
X	nrows  = nfiles / MAXCOL + (nfiles % MAXCOL ? 1 : 0);
X	ncols  = nfiles / nrows  + (nfiles % nrows  ? 1 : 0);
X
X	for (row = 0; row < nrows; row++)
X	{
X		for (col = 0; col < ncols; col++)
X		{
X			if ((filenum = col*nrows + row) >= nfiles)
X				continue;
X
X			len = copyn(filename, headp[filenum]->d_name, DIRSIZ);
X
X			stat(filename, &stbuf);
X
X			if (stbuf.st_mode & S_IFDIR)
X			{
X				pad = 1;
X				fmt1 = "%s/\n";
X				fmt2 = "%.*s/%.*s";
X			}
X			else
X			if (stbuf.st_mode & S_IEXEC)
X			{
X				pad = 1;
X				fmt1 = "%s*\n";
X				fmt2 = "%.*s*%.*s";
X			}
X			else
X			{
X				pad = 2;
X				fmt1 = "%s\n";
X				fmt2 = "%.*s%.*s";
X			}
X
X			if ((col == ncols - 1) || (filenum + nrows >= nfiles))
X				fprintf(stdout, fmt1, filename);
X			else
X			{
X				ntabs = ((DIRSIZ+pad-len) > TABSIZ ? 2 : 1);
X				fprintf(stdout, fmt2, len,
X					filename, ntabs, "\t\t");
X			}
X		}
X		fflush(stdout);	/* write the row out */
X	}
X
X	exit(0);
X}
X
X/*
X**  Sorts the file names in alphabetical order.
X*/
X
Xint namecmp(pp1, pp2)
X	struct direct **pp1, **pp2;
X{
X	register struct direct *p1 = *pp1;
X	register struct direct *p2 = *pp2;
X
X	return(strncmp(&p1->d_name[0], &p2->d_name[0], DIRSIZ));
X}
X
X/*
X**  Copies s2 to s1 until n characters have been copied
X**  or the null of s2 is reached, whichever occurs sooner.
X**  Returns the number of non-null characters copied,
X**  and s1 is null terminated.
X*/
X
Xint copyn(s1, s2, n)
X	register char *s1, *s2;
X	register int n;
X{
X	register int i;
X
X	for (i = 0 ; i < n; i++)
X		if ((*s1++ = *s2++) == '\0')
X			return(i);
X	*s1 = '\0';
X	return(i);
X}
X
Xerror(format, verb, noun)
X	char *format, *verb, *noun;
X{
X	fprintf(stderr, format, progname, verb, noun);
X	exit(-1);
X}
END_OF_FILE

Larry Cipriani cbscc!lvc