home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!rs
- From: rs@uunet.UU.NET (Rich Salz)
- Newsgroups: comp.sources.unix
- Subject: v10i055: An "ls" program
- Message-ID: <646@uunet.UU.NET>
- Date: 16 Jul 87 00:12:10 GMT
- Organization: UUNET Communications Services, Arlington, VA
- Lines: 534
- Approved: rs@uunet.UU.NET
-
- Submitted-by: Guy Middleton <gamiddleton%orchid.waterloo.edu@relay.cs.net>
- Posting-Number: Volume 10, Issue 55
- Archive-name: lc
-
- [ It's nice to get a public ls-type program out on to the net.
- Please send your 52 patches that implement options [a-zA-Z]
- on to Guy so that he can incorporate them. --r$ ]
-
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- #
- # Wrapped by orchid!root on Sat May 16 18:53:36 EDT 1987
- # Contents: Makefile README lc.1 lc.c
-
- echo x - Makefile
- sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
- DESTDIR =
- CFLAGS = -O
-
- lc: lc.c
- ${CC} ${CFLAGS} -o lc lc.c
-
- install: lc
- install -s lc $(DESTDIR)/usr/bin/lc
-
- clean:
- rm -f lc a.out core *.o *.bak
- @//E*O*F Makefile//
- chmod u=rw,g=r,o=r Makefile
-
- echo x - README
- sed 's/^@//' > "README" <<'@//E*O*F README//'
- This is 'lc', the program that everybody here uses instead of ls.
- It may not seem like a big deal, but whenever somebody moves away, they
- realise that lc isn't part of standard Unix, and call back to get a copy.
-
- This is known to work on 4.2, 4.3, and Ultrix 1.2. We don't have any
- SysV machines here, so it may not work there.
- @//E*O*F README//
- chmod u=rw,g=r,o=r README
-
- echo x - lc.1
- sed 's/^@//' > "lc.1" <<'@//E*O*F lc.1//'
- @.TH LC 1 UW
- @.SH NAME
- lc \- list directory and file names in columns
- @.SH SYNOPSIS
- @.B lc
- [
- @.B \-fdbcspan1
- ]
- [ directory ... ]
- @.SH DESCRIPTION
- @.I Lc
- lists the elements of the given directories.
- The elements are
- divided into the five basic types (files, directories, character
- special files, block special files, and pipes)
- and are printed in alphabetical order.
- They are normally printed 5 to a line,
- preceeded by a title indicating the type,
- but the
- @.B \-1
- option can be used to force single-column untitled output.
- @.PP
- If the argument list contains more than one name, the contents of the
- directories named in the list are displayed and all other names
- are ignored.
- If no directory is specified the current working directory is listed
- by default.
- The special entries ``.'' and ``..''
- are normally not listed;
- the
- @.B \-a
- option causes them to be listed as well.
- @.PP
- The
- @.B \-n
- option turns off all output; this is useful when only the exit status is
- wanted.
- (The exit status is 0 if something would have been printed,
- 1 otherwise.)
- @.PP
- If any of the following option arguments are given,
- @.I lc
- lists only those types of entries;
- otherwise, all entries are listed.
- The options and their meanings are:
- @.PP
- @.RS 5n
- @.TP
- @.B f
- list ordinary files
- @.TP
- @.B d
- list directories
- @.TP
- @.B b
- list block special files
- @.TP
- @.B c
- list character special files
- @.TP
- @.B s
- list all special files
- @.TP
- @.B p
- list permanent pipes
- @.RE
- @.PP
- @.I Lc
- may be used with the substitution features of the Shell
- to select particular kinds of files (eg, directories) to
- take part in some processing,
- for example:
- @.PP
- @.RS
- @.B "ls \-l \`lc -1d\`"
- @.RE
- @.PP
- This lists the contents of all sub-directories of the current directory.
- @.SH DIAGNOSTICS
- Symbolic links are normally followed, and each prints under the category
- of the type of thing to which it is linked.
- If the symbolic link points to a nonexistent pathname, or if you do
- not have permission to resolve the pathname,
- @.I lc
- will list the link under the category
- @.IR "Unresolved Symbolic Links" .
- @//E*O*F lc.1//
- chmod u=rwx,g=rx,o=rx lc.1
-
- echo x - lc.c
- sed 's/^@//' > "lc.c" <<'@//E*O*F lc.c//'
- #ifndef lint
- static char *copyright =
- "LC - Copyright University of Waterloo, 1978,1985,1987";
- #endif lint
- /*
- * lc [directory ...]
- */
-
- #include <stdio.h>
- #include <strings.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <sys/dir.h>
- #include <errno.h>
-
- #ifndef MAXPATHLEN
- #define MAXPATHLEN 1024 /* For older systems */
- #endif
-
- /* this assumes that S_IFMT is a mask of contiguous 1s */
- #define IFMT_OFFSET 12 /* may be system-dependent */
- #define IFMT (S_IFMT >> IFMT_OFFSET)
-
- #define MODEX(m) (((m)>>IFMT_OFFSET)&IFMT) /* IFMT to table index */
-
- extern int errno,sys_nerr;
- extern char *strcpy(),*strncpy();
- extern char *sys_errlist[];
- int pstrcmp();
-
- #define NMALLOC 100 /* how much to malloc in growlist() */
- #define COLUMNWIDTH 15 /* number of characters in a column */
- #define INDENT " " /* blanks at beginning of a column */
-
- struct filelist {
- char **names; /* pointer to array of names */
- int size; /* how many elements */
- int end; /* next element to use */
- int flag;
- char *title;
- }
- dlist = {(char **) NULL, 0, 0, 0, "Directories"},
- flist = {(char **) NULL, 0, 0, 0, "Files"},
- plist = {(char **) NULL, 0, 0, 0, "Pipes"},
- blist = {(char **) NULL, 0, 0, 0, "Block Spec. Files"},
- clist = {(char **) NULL, 0, 0, 0, "Char. Spec. Files"},
- mpclist = {(char **) NULL, 0, 0, 0, "MPX Char. Files"},
- mpblist = {(char **) NULL, 0, 0, 0, "MPX Block Files"},
- symlist = {(char **) NULL, 0, 0, 0, "Unsatisfied Symbolic Links"},
- soclist = {(char **) NULL, 0, 0, 0, "Sockets"},
- /* flag is always on for this list */
- goklist = {(char **) NULL, 0, 0, 1, "**GOK"};
-
- struct filelist *printlist[] = {
- &dlist, &flist, &plist, &blist, &clist, &mpclist, &mpblist, &symlist,
- &soclist, &goklist, 0
- };
-
- struct filelist *listtype[IFMT-1];
-
- struct xinit {
- int x_flag;
- struct filelist *x_list;
- } xinit[] ={
- #ifdef S_IPIPE
- S_IPIPE, &plist,
- #endif
- #ifdef S_IFPIP
- S_IFPIP, &plist,
- #endif
- S_IFREG, &flist,
- S_IFDIR, &dlist,
- S_IFCHR, &clist,
- S_IFBLK, &blist,
- #ifdef S_IFMPC
- S_IFMPC, &mpclist,
- #endif
- #ifdef S_IFMPB
- S_IFMPB, &mpblist,
- #endif
- #ifdef S_IFLNK
- S_IFLNK, &symlist,
- #endif
- #ifdef S_IFSOCK
- S_IFSOCK, &soclist,
- #endif
- -1,
- };
-
- int nfl; /* flag; this is not the first line of output */
- int errcall; /* flag; last line of output was error message */
- int notfirst; /* flag; means not the first thing in this directory */
- int nflg; /* flag; no output - just want exit status */
- int ncols = 5; /* number of columns */
- int linewidth;
- int manyflg;
- int anyfound;
- int all = 1;
- char pathbuf[MAXPATHLEN];
- char *fnptr = pathbuf;
- int aflg;
-
- main(argc, argv)
- char *argv[];
- {
- register char *path, *p, *q;
- struct xinit *xp;
- int i;
-
- for (i = 0 ; i < IFMT ; i++)
- listtype[i] = &goklist;
- for (xp = xinit; xp->x_flag != -1; xp++)
- listtype[MODEX(xp->x_flag)] = xp->x_list;
- if(argc >= 2 && argv[1][0] == '-') {
- argv++;
- argc--;
- for(p = &argv[0][1]; *p; p++)
- switch(*p) {
- case 'a':
- aflg++;
- break;
-
- case 'n':
- nflg++;
- break;
-
- case '1':
- ncols=1;
- break;
-
- default:
- switch(*p) {
- case 'f':
- flist.flag++;
- break;
-
- case 'd':
- dlist.flag++;
- break;
-
- case 'b':
- blist.flag++;
- break;
-
- case 'c':
- clist.flag++;
- break;
-
- case 'B':
- mpblist.flag++;
- break;
-
- case 'C':
- mpclist.flag++;
- break;
-
- case 's':
- blist.flag++;
- clist.flag++;
- mpblist.flag++;
- mpclist.flag++;
- break;
-
- case 'p':
- plist.flag++;
- break;
-
- default:
- fprintf(stderr, "Unknown flag: %c\n",
- *p);
- continue;
- }
- all = 0;
- }
- }
-
- if (all)
- flist.flag = dlist.flag = blist.flag = clist.flag
- = mpblist.flag = mpclist.flag
- = symlist.flag = soclist.flag
- = plist.flag = 1;
-
- linewidth = ncols * COLUMNWIDTH;
-
- if(argc < 3) {
- path = argc == 1 ? "." : argv[1];
- listdir(path);
- } else {
- manyflg++;
- while(--argc) {
- path = p = *++argv;
- if(strlen(path) >= MAXPATHLEN) {/* = for '/' */
- errno=ENAMETOOLONG;
- warn(path);
- continue;
- }
- q = pathbuf;
- while(*q++ = *p++);
- q[-1] = '/';
- fnptr = q;
- listdir(path);
- }
- }
- exit(anyfound==0);
- }
-
- listdir(path)
- char *path;
- {
- register char *p;
- struct direct *d;
- struct filelist **pr;
- DIR *u;
- struct stat ibuf;
-
- if(stat(path, &ibuf) < 0) {
- warn(path);
- return;
- }
- if((ibuf.st_mode&S_IFMT) != S_IFDIR) {
- if(!manyflg){
- errno=ENOTDIR;
- warn(path);
- }
- return;
- }
- if((u = opendir(path)) == NULL) {
- warn(path);
- return;
- }
- if(manyflg) {
- if(nfl++)
- putchar('\n');
- printf("%s:\n", path);
- } else
- chdir(path);
- while((d = readdir(u)) != NULL) {
- if(fnptr + d->d_namlen >= &pathbuf[MAXPATHLEN]) {
- errno=ENAMETOOLONG;
- warn(pathbuf);
- /*
- err("%s: Component `%s' makes pathname > %d bytes.\n",
- pathbuf, d->d_name, MAXPATHLEN);
- */
- continue;
- }
- (void)strcpy(fnptr, d->d_name);
- if(stat(pathbuf, &ibuf) < 0 && lstat(pathbuf, &ibuf) < 0) {
- warn(pathbuf);
- continue;
- }
- /*
- * ignore "." and ".."
- */
- if((ibuf.st_mode&S_IFMT) == S_IFDIR && aflg == 0) {
- p = d->d_name;
- if(*p++ == '.' && (*p == '\0'
- || *p++ == '.' && *p == '\0'))
- continue;
- }
-
- build(listtype[MODEX(ibuf.st_mode)], d->d_name);
- }
-
- closedir(u);
- notfirst = 0;
- for(pr = printlist; *pr; pr++)
- if((*pr)->names && (*pr)->end != 0) {
- qsort( (*pr)->names, (*pr)->end,
- sizeof (char *), pstrcmp );
- print(*pr);
- }
- fflush(stdout);
- }
-
- warn(name)
- char *name;
- {
- if(nfl && !errcall)
- putchar('\n');
- if((errno>=0)&&(errno<sys_nerr))
- fprintf(stdout,"%s: %s\n", name,sys_errlist[errno]);
- else
- fprintf(stdout,"%s: unknown error (%d).\n", name,errno);
- fflush(stdout);
- errcall=nfl=1;
- errno=0;
- }
-
- print(list)
- struct filelist *list;
- {
- register int cursor, i;
- register char **p;
-
- if(notfirst++)
- putchar('\n');
- if(ncols!=1) {
- if (manyflg)
- fputs(INDENT, stdout);
- printf("%s:\n", list->title);
- }
- cursor = 0;
- for(p = list->names, i = 0; i < list->end; i++) {
- int len;
- int posused; /* positions used by blanks and filename */
- register char *fname;
-
- fname = p[i];
- len = strlen(fname);
- posused = len + ((cursor == 0) ? 0 : COLUMNWIDTH - cursor%COLUMNWIDTH);
- if ((cursor + posused) > linewidth) {
- printf("\n");
- cursor = 0;
- posused = len;
- }
- if (manyflg && (cursor == 0)) fputs(INDENT, stdout);
- printf("%*s", posused, fname);
- cursor += posused;
- }
- if(cursor != 0)
- printf("\n");
- errcall = 0;
- if (manyflg)
- release(list);
- }
-
- build(list, name)
- struct filelist *list;
- char *name;
- {
- register int n;
-
- if(list->flag == 0)
- return;
- anyfound++;
- if(nflg)
- return;
- if (list->end >= list->size)
- growlist(list);
- n = strlen( name ) + 1;
-
- (list->names)[list->end++] = strncpy( malloc( n ), name, n );
- }
-
- growlist( list )
- struct filelist *list;
- {
- register int oldsize, newsize;
- register char **newlist;
-
- oldsize = list->size * sizeof (char *);
- newsize = oldsize + (NMALLOC * sizeof (char *));
-
- newlist = (char **) malloc( newsize );
-
- if (oldsize != 0) {
- bcopy( list->names, newlist, oldsize );
- free( list->names );
- }
-
- list->names = newlist;
- list->size += NMALLOC;
- }
-
- release( list )
- struct filelist *list;
- {
- register char **p;
- register int i;
-
- for (p = list->names, i = 0; i < list->end; i++)
- free( p[i] );
-
- list->end = 0;
- }
-
- pstrcmp( a, b )
- char **a, **b;
- {
- return (strcmp( *a, *b ));
- }
- @//E*O*F lc.c//
- chmod u=rwx,g=rx,o=rx lc.c
-
- exit 0
- __
- -Guy Middleton, University of Waterloo MFCF/ICR, gamiddleton@watmath
-
-
- --
-
- Rich $alz "Anger is an energy"
- Cronus Project, BBN Labs rsalz@bbn.com
- Moderator, comp.sources.unix sources@uunet.uu.net
- --
-
- Rich $alz "Anger is an energy"
- Cronus Project, BBN Labs rsalz@bbn.com
- Moderator, comp.sources.unix sources@uunet.uu.net
-