peter@baylor.UUCP (Peter da Silva) (08/15/85)
Having recieved numerous (well, 2) requests for "le", here's the source offered without comment. 4.2 people will undoubtedly have to patch it to handle the crufty new directories, but I have done that for a descendent of this (a visual shell) and it's no hassle. V7 people rejoice: it runs under that venerable system. I have never tried to convert it ro its descendents fo SIII/SV, so let me know what luck you have. ---- le.c ----- #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dir.h> #include <pwd.h> #include <grp.h> #include <time.h> #define D_DEV 01 #define D_INO 02 #define D_MODE 04 #define D_LINKS 010 #define D_UID 020 #define D_GID 040 #define D_RDEV 0100 #define D_SIZE 0200 #define D_ATIME 0400 #define D_MTIME 01000 #define D_CTIME 02000 #define D_SMODE 04000 #define D_SUID 010000 #define D_SGID 020000 #define FALSE 0 #define TRUE 1 #define MAXENTS 512 #define MAXID 64 struct entry { struct direct e_dir; char filler; struct stat e_stat; } entries[MAXENTS]; int nentries; char *errname; extern int errno; int xerrno; char *tab=" "; long maxsize; char sizstr[2][10] = {"%6lu%s","%6s%s"}; int dohead=0, dodir=1; int flags = D_MODE|D_LINKS|D_UID|D_SIZE|D_MTIME; char *emesg[3]={ "No such error", #define TOO_MANY 1 "Too many directory entries", 0 }; getdir(dir) char *dir; { int entcmp(); char *nameof(); FILE *fp; int valid; if(!(fp = fopen(dir, "r"))) { errname=dir; return FALSE; } maxsize=0L; for(nentries=0; nentries<MAXENTS && fread(&entries[nentries].e_dir, sizeof entries[nentries].e_dir, 1, fp)>0; nentries += valid) { if(valid=entries[nentries].e_dir.d_ino?1:0) { entries[nentries].filler=0; if(stat(nameof(entries[nentries].e_dir.d_name, dir), &entries[nentries].e_stat )==-1 ) { fclose(fp); errname=nameof(entries[nentries].e_dir.d_name, dir); return FALSE; } if(entries[nentries].e_stat.st_size>maxsize) maxsize=entries[nentries].e_stat.st_size; } } if(nentries>=MAXENTS) { errno=0; xerrno=TOO_MANY; errname=dir; return FALSE; } fclose(fp); qsort(entries, nentries, sizeof(struct entry), entcmp); setsize(maxsize); return TRUE; } setsize(size) long size; { char tmp[32]; int siz; sprintf(tmp, "%lu", size); siz=strlen(tmp); if(siz<6) siz=6; sprintf(sizstr[0], "%%%dlu%%s", siz); sprintf(sizstr[1], "%%%ds%%s", siz); if(dohead) { header(); dohead=0; } } char * nameof(name, dir) char *name, *dir; { char nambuf[BUFSIZ]; if(!dir[0]) return name; if(dir[0]=='.' && !dir[1]) return name; else if(dir[0]=='/' && !dir[1]) { sprintf(nambuf, "/%s", name); return nambuf; } else { sprintf(nambuf, "%s/%s", dir, name); return nambuf; } } pname(name) char *name; { int len = 0; for(;*name; name++) if(*name<' ') { printf("^%c", *name+'@'); len+=2; } else if(*name=='\0177') { printf("^?"); len+=2; } else if(*name>'\0177') { printf("\\%03o", *name); len += 4; } else { putchar(*name); len++; } return len; } entcmp(e1, e2) struct entry *e1, *e2; { return strcmp(e1->e_dir.d_name, e2->e_dir.d_name); } fdump(dir) char *dir; { struct stat sbuf; if(stat(dir, &sbuf)==-1) { errname=dir; return FALSE; } else if(dodir && (sbuf.st_mode&S_IFMT)==S_IFDIR) { if(getdir(dir)) return dump(dir); else return FALSE; } else { setsize(sbuf.st_size); statout(dir, &sbuf, "."); return TRUE; } } dump(dir) char *dir; { int i, j; int chars; if(flags==0) { for(i=0; i<=nentries/5; i++) { chars = 0; for(j=0; j<5; j++) { if(i+j*nentries/5<nentries) chars += pname(entries[i+j*nentries/5].e_dir.d_name); if(chars<8) { putchar('\t'); chars=8; } if(chars<16) { putchar('\t'); chars=16; } else { putchar(' '); chars++; } chars %= 16; } putchar('\n'); } } else for(i=0; i<nentries; i++) statout(entries[i].e_dir.d_name, &entries[i].e_stat, dir); return TRUE; } statout(name, sbuf, dir) char *name; struct stat *sbuf; char *dir; { char *u_name(), *g_name(); if(flags&D_DEV) printf("%3d,%3d%s", major(sbuf->st_dev), minor(sbuf->st_dev), tab); if(flags&D_RDEV) printf("%3d,%3d%s", major(sbuf->st_rdev), minor(sbuf->st_rdev), tab); if(flags&D_INO) printf("%5u%s", sbuf->st_ino, tab); if(flags&D_SMODE) printf("%6o%s", sbuf->st_mode, tab); if(flags&D_MODE) { int mode = sbuf->st_mode; if((mode&S_IFMT)==S_IFCHR) putchar('c'); else if((mode&S_IFMT)==S_IFBLK) putchar('b'); else if((mode&S_IFMT)==S_IFDIR) putchar('d'); else if((mode&S_IFMT)==S_IFREG) putchar('-'); else putchar('?'); triad((mode>>6)&7, mode&S_ISUID, 's'); triad((mode>>3)&7, mode&S_ISGID, 's'); triad(mode&7, mode&S_ISVTX, 't'); printf("%s", tab); } if(flags&D_LINKS) printf("%3u%s", sbuf->st_nlink, tab); if(flags&D_SUID) printf("%3d%s", sbuf->st_uid, tab); if(flags&D_UID) printf("%-8s%s", u_name(sbuf->st_uid), tab); if(flags&D_SGID) printf("%3d%s", sbuf->st_gid, tab); if(flags&D_GID) printf("%-8s%s", g_name(sbuf->st_gid), tab); if(flags&D_SIZE) printf(sizstr[0], sbuf->st_size, tab); if((flags&~(D_ATIME|D_MTIME|D_CTIME)) && (flags&(D_ATIME|D_MTIME|D_CTIME))) putchar(' '); if(flags&D_ATIME) printime(&sbuf->st_atime); if(flags&D_MTIME) printime(&sbuf->st_mtime); if(flags&D_CTIME) printime(&sbuf->st_ctime); pname(nameof(name, dir)); putchar('\n'); } struct idtab { int id_id; char id_name[10]; } u_list[MAXID], g_list[MAXID]; int u_ptr=0, g_ptr=0; char * u_name(uid) int uid; { int i; struct passwd *pwptr, *getpwuid(); for(i=0; i<u_ptr; i++) if(u_list[i].id_id==uid) return u_list[i].id_name; u_list[u_ptr].id_id=uid; if(pwptr=getpwuid(uid)) { for(i=0; pwptr->pw_name[i]>' '; i++) u_list[u_ptr].id_name[i]=pwptr->pw_name[i]; u_list[u_ptr].id_name[i]=0; } else sprintf(u_list[u_ptr].id_name, "%d", uid); return u_list[u_ptr++].id_name; } char * g_name(gid) int gid; { int i; struct group *grptr, *getgrgid(); for(i=0; i<g_ptr; i++) if(g_list[i].id_id==gid) return g_list[i].id_name; g_list[g_ptr].id_id=gid; if(grptr=getgrgid(gid)) { for(i=0; grptr->gr_name[i]>' '; i++) g_list[g_ptr].id_name[i]=grptr->gr_name[i]; g_list[g_ptr].id_name[i]=0; } else sprintf(g_list[g_ptr].id_name, "%d", gid); return g_list[g_ptr++].id_name; } printime(clock) long *clock; { struct tm *tmbuf, *localtime(); static char *months[12]= { "Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec" }; tmbuf=localtime(clock); printf("%2d %3s %02d %2d:%02d %s", tmbuf->tm_mday, months[tmbuf->tm_mon], tmbuf->tm_year, tmbuf->tm_hour, tmbuf->tm_min, tab); } header() { if(flags&D_DEV) printf("%7s%s", "IDev", tab); if(flags&D_RDEV) printf("%7s%s", "Rdev", tab); if(flags&D_INO) printf("%5s%s", "Inode", tab); if(flags&D_SMODE) printf("%6s%s", "Mode", tab); if(flags&D_MODE) printf("%-10s%s", "Long mode", tab); if(flags&D_LINKS) printf("%3s%s", "Lnx", tab); if(flags&D_SUID) printf("%3s%s", "UID", tab); if(flags&D_UID) printf("%-8s%s", "User", tab); if(flags&D_SGID) printf("%3s%s", "GID", tab); if(flags&D_GID) printf("%-8s%s", "Group", tab); if(flags&D_SIZE) printf(sizstr[1], "Size", tab); if((flags&~(D_ATIME|D_MTIME|D_CTIME)) && (flags&(D_ATIME|D_MTIME|D_CTIME))) putchar(' '); if(flags&D_ATIME) printf("%-16s%s", "Access time", tab); if(flags&D_MTIME) printf("%-16s%s", "Modify time", tab); if(flags&D_CTIME) printf("%-16s%s", "Inode time", tab); if(flags) printf("%s\n", "File name"); } triad(bits, special, code) int bits, special; char code; { if(bits&4) putchar('r'); else putchar('-'); if(bits&2) putchar('w'); else putchar('-'); if(special) putchar(code); else if(bits&1) putchar('x'); else putchar('-'); } main(ac, av) int ac; char **av; { int i, j; int exit_status = 0; int filed=0; for(i=1; i<ac; i++) { if(av[i][0]=='-') for(j=1; av[i][j]; j++) switch(av[i][j]) { case 'T': if(av[i][j+1]) tab = &av[i][++j]; else tab = &av[++i][j=0]; while(av[i][j]) j++; j--; break; case 'N': flags = 0; break; case 'A': flags = -1; break; case 'D': dodir=!dodir; break; case 'd': flags ^= D_DEV; break; case 'i': flags ^= D_INO; break; case 'm': flags ^= D_MODE; break; case 'M': flags ^= D_SMODE; break; case 'l': flags ^= D_LINKS; break; case 'u': flags ^= D_UID; break; case 'U': flags ^= D_SUID; break; case 'g': flags ^= D_GID; break; case 'G': flags ^= D_SGID; break; case 'r': flags ^= D_RDEV; break; case 's': flags ^= D_SIZE; break; case 'a': flags ^= D_ATIME; break; case 't': flags ^= D_MTIME; break; case 'c': flags ^= D_CTIME; break; case 'h': dohead=!dohead; break; case 'H': header(); break; default: printf("Unknown option -%c.\n", av[i][j]); printf("\tUsage %s [-A|-N] [-diMmlUuGgrsatc] [-Ttab] [-Hh] [-D] [file]...\n", av[0]); break; } else { filed=1; if(!fdump(av[i])) { fperror(av[0], errname); exit_status=errno?errno:(-xerrno); } } } if(!filed) if(!fdump(".")) { fperror(av[0], errname); exit_status=errno; } if(dohead) header(); exit(exit_status); } fperror(prog, file) char *prog, *file; { fprintf(stderr, "%s -- ", prog); if(errno) perror(file); else fprintf(stderr, "%s: %s\n", file, emesg[xerrno]); } -- Peter da Silva (the mad Australian) UUCP: ...!shell!neuro1!{hyd-ptd,baylor,datafac}!peter MCI: PDASILVA; CIS: 70216,1076
crm@duke.UUCP (Charlie Martin) (08/19/85)
Look, folks, if you're not going to put *any* comments in the source files, and you're not going to send along a man page, and you're not going to give any hints on how to use it in the text before the script, could you *at least* ...PLEASE! ...give us a hint what it does in the Subject line? Mmph. -- Charlie Martin (...mcnc!duke!crm)
peter@baylor.UUCP (Peter da Silva) (08/21/85)
le is an extended ls, designed to please all the people who want to get weird info on a file. It dumps reliable info in reliable positions, for example it won't stick the major/minor device #s in the file size feild of the output. Let me see about the options... Without any flags it outputs the same info as ls... Usage: le [-A|-N] [-diMmlUuGgrsatc] [-Ttab] [-Hh] [-D] [file]... -d Toggle 'dev' flag. -i Toggle 'inode' flag. -m Toggle 'mode' flag. -M Toggle 'short mode' (octal mode) flag. -l Toggle 'links' flag. -u Toggle 'user' flag. -U Toggle 'short user' (userid) flag. -g Toggle 'group' flag. -G Toggle 'short group' (groupid) flag. -r Toggle 'rdev' flag. -s Toggle 'size' flag. -a Toggle 'atime' flag. -t Toggle 'mtime' flag. -c Toggle 'ctime' flag. -h Toggle header. -H Force output of the header. -N (No) Clear all flags. -A (All) Set all flags. -D Dont list directories (like ls -d). -Ttab Use the string 'tab' to seperate feilds instead of space. The flags can be included in any order but having any of [dimMluUgGrsatc] before [AN] is kind of useless, and having [Hh] before [dimMluUgGrsatc] can be misleading. You can intersperse options with files if you want to list different directories differently. I don't see any reason to do this but I also see no good reason to prevent this (no, I don't use getopt). As an example: here is 'ls -al' compared with 'le' Note that feild 7 varies between a time and a year, and that 4 varies between a size and a device #... while this is more useful for humans it's kind of hard on awk... le isn't a replacement for 'ls', just for ls in shell scripts so you can keep awk and relatives happy. % ls -al /dev total 4 c-w--w--w- 2 root 5, 0 Aug 21 13:46 aux1 c-w--w--w- 2 root 5, 1 May 20 09:50 aux2 crw--w--w- 1 root 0, 8 Aug 20 13:52 console ... crw-rw-rw- 1 root 1, 23 Aug 18 1982 hsix7 crw------- 1 root 2, 1 Aug 20 13:52 kmem -rw-rw-r-- 1 root 1635 Jul 11 17:39 lp c-w--w--w- 2 root 5, 0 Aug 21 13:46 lp1 c-w--w--w- 2 root 5, 1 May 20 09:50 lp2 ... crw--w--w- 1 root 0, 15 Jul 23 15:38 tty7 % le /dev drwxr-xr-x 2 root 928 11 Jul 85 16:40 /dev/. drwxr-xr-x 11 root 368 20 Aug 85 13:52 /dev/.. c-w--w--w- 2 root 0 21 Aug 85 13:46 /dev/aux1 c-w--w--w- 2 root 0 20 May 85 9:50 /dev/aux2 crw--w--w- 1 root 0 20 Aug 85 13:52 /dev/console ... crw-rw-rw- 1 root 0 18 Aug 82 11:11 /dev/hsix7 crw------- 1 root 0 20 Aug 85 13:52 /dev/kmem -rw-rw-r-- 1 root 1635 11 Jul 85 17:39 /dev/lp c-w--w--w- 2 root 0 21 Aug 85 13:46 /dev/lp1 c-w--w--w- 2 root 0 20 May 85 9:50 /dev/lp2 ... crw--w--w- 1 root 0 23 Jul 85 15:38 /dev/tty7 There is a problem: le expands control characters to '^X', which may cause problems in some cases... le -N is thus not exactly the equivalent of ls -A. This code can be easily changed if this proves a problem. Don't ask me why /dev/lp is a regular file, I didn't create it... :-> Time to go do some sa-type stuff. -- Peter (Made in Australia) da Silva UUCP: ...!shell!neuro1!{hyd-ptd,baylor,datafac}!peter MCI: PDASILVA; CIS: 70216,1076
peter@baylor.UUCP (Peter da Silva) (08/21/85)
> le is an extended ls, designed to please all the people who want to get > weird info on a file... Forgot to mention: the source was posted a few days ago. I got complaints about posting it without an explanation, so this is the explanation. I hope it helps someone. -- Peter (Made in Australia) da Silva UUCP: ...!shell!neuro1!{hyd-ptd,baylor,datafac}!peter MCI: PDASILVA; CIS: 70216,1076