added ls - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 6ccdc8cffd953f6dae2692e687d19ac6e58a7e2b | |
parent b7abc7dd08640a98b0af92b05bb0a57e614f3160 | |
Author: Anselm R. Garbe <[email protected]> | |
Date: Tue, 31 Jan 2006 20:37:59 +0200 | |
added ls | |
Diffstat: | |
M Makefile | 4 ++-- | |
M config.mk | 2 +- | |
A ls/Makefile | 7 +++++++ | |
A ls/ls.1 | 172 ++++++++++++++++++++++++++++++ | |
A ls/ls.c | 309 +++++++++++++++++++++++++++++… | |
5 files changed, 491 insertions(+), 3 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -3,8 +3,8 @@ | |
include config.mk | |
-SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep mk \ | |
- rc read sed seq sleep sort tee test touch tr uniq | |
+SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep ls \ | |
+ mk rc read sed seq sleep sort tee test touch tr uniq | |
all: | |
@echo 9base build options: | |
diff --git a/config.mk b/config.mk | |
@@ -4,7 +4,7 @@ | |
PREFIX = /usr/local/9 | |
MANPREFIX = ${PREFIX}/share/man | |
-VERSION = 2 | |
+VERSION = 20060129 | |
# Linux/BSD | |
CFLAGS = -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -c -I. -D… | |
diff --git a/ls/Makefile b/ls/Makefile | |
@@ -0,0 +1,7 @@ | |
+# ls - ls unix port from plan9 | |
+# | |
+# Depends on ../lib9 | |
+ | |
+TARG = ls | |
+ | |
+include ../std.mk | |
diff --git a/ls/ls.1 b/ls/ls.1 | |
@@ -0,0 +1,172 @@ | |
+.TH LS 1 | |
+.SH NAME | |
+ls, lc \- list contents of directory | |
+.SH SYNOPSIS | |
+.B ls | |
+[ | |
+.B -dlmnpqrstuFQ | |
+] | |
+.I name ... | |
+.PP | |
+.B lc | |
+[ | |
+.B -dlmnpqrstuFQ | |
+] | |
+.I name ... | |
+.SH DESCRIPTION | |
+For each directory argument, | |
+.I ls | |
+lists the contents of the directory; | |
+for each file argument, | |
+.I ls | |
+repeats its name and any other information requested. | |
+When no argument is given, the current directory is listed. | |
+By default, the output is sorted alphabetically by name. | |
+.PP | |
+.I Lc | |
+is the same as | |
+.IR ls , | |
+but sets the | |
+.B -p | |
+option and pipes the output through | |
+.IR mc (1). | |
+.PP | |
+There are a number of options: | |
+.TP | |
+.B -d | |
+If argument is a directory, list it, not | |
+its contents. | |
+.TP | |
+.B -l | |
+List in long format, giving mode (see below), file system type | |
+(e.g., for devices, the | |
+.B # | |
+code letter that names it; see | |
+.IR intro (3)), | |
+the instance or subdevice number, owner, group, | |
+size in bytes, and time of last modification | |
+for each file. | |
+.TP | |
+.B -m | |
+List the name of the user who most recently modified the file. | |
+.TP | |
+.B -n | |
+Don't sort the listing. | |
+.TP | |
+.B -p | |
+Print only the final path element of each file name. | |
+.TP | |
+.B -q | |
+List the | |
+.I qid | |
+(see | |
+.IR stat (3)) | |
+of each file; the printed fields are in the order | |
+path, version, and type. | |
+.TP | |
+.B -r | |
+Reverse the order of sort. | |
+.TP | |
+.B -s | |
+Give size in Kbytes for each entry. | |
+.TP | |
+.B -t | |
+Sort by time modified (latest first) instead of | |
+by name. | |
+.TP | |
+.B -u | |
+Under | |
+.B -t | |
+sort by time of last access; | |
+under | |
+.B -l | |
+print time of last access. | |
+.TP | |
+.B -F | |
+Add the character | |
+.B / | |
+after all directory names | |
+and the character | |
+.B * | |
+after all executable files. | |
+.TP | |
+.B -L | |
+Print the character | |
+.B t | |
+before each file if it has the temporary flag set, and | |
+.B - | |
+otherwise. | |
+.TP | |
+.B -Q | |
+By default, printed file names are quoted if they contain characters special to | |
+.IR rc (1). | |
+The | |
+.B -Q | |
+flag disables this behavior. | |
+.PP | |
+The mode printed under the | |
+.B -l | |
+option contains 11 characters, | |
+interpreted | |
+as follows: | |
+the first character is | |
+.TP | |
+.B d | |
+if the entry is a directory; | |
+.TP | |
+.B a | |
+if the entry is an append-only file; | |
+.TP | |
+.B D | |
+if the entry is a Unix device; | |
+.TP | |
+.B L | |
+if the entry is a symbolic link; | |
+.TP | |
+.B P | |
+if the entry is a named pipe; | |
+.TP | |
+.B S | |
+if the entry is a socket; | |
+.TP | |
+.B - | |
+if the entry is a plain file. | |
+.PD | |
+.PP | |
+The next letter is | |
+.B l | |
+if the file is exclusive access (one writer or reader at a time). | |
+.PP | |
+The last 9 characters are interpreted | |
+as three sets of three bits each. | |
+The first set refers to owner permissions; | |
+the next to permissions to others in the same user-group; | |
+and the last to all others. | |
+Within each set the three characters indicate | |
+permission respectively to read, to write, or to | |
+execute the file as a program. | |
+For a directory, `execute' permission is interpreted | |
+to mean permission to search the directory | |
+for a specified file. | |
+The permissions are indicated as follows: | |
+.TP 3 | |
+.B r | |
+if the file is readable; | |
+.PD 0 | |
+.TP 3 | |
+.B w | |
+if the file is writable; | |
+.TP 3 | |
+.B x | |
+if the file is executable; | |
+.TP 3 | |
+.B - | |
+if none of the above permissions is granted. | |
+.PD | |
+.SH SOURCE | |
+.B \*9/src/cmd/ls.c | |
+.br | |
+.B \*9/bin/lc | |
+.SH SEE ALSO | |
+.IR stat (3), | |
+.IR mc (1) | |
diff --git a/ls/ls.c b/ls/ls.c | |
@@ -0,0 +1,309 @@ | |
+#include <u.h> | |
+#include <libc.h> | |
+#include <bio.h> | |
+ | |
+#define dirbuf p9dirbuf /* avoid conflict on sun */ | |
+ | |
+typedef struct NDir NDir; | |
+struct NDir | |
+{ | |
+ Dir *d; | |
+ char *prefix; | |
+}; | |
+ | |
+int errs = 0; | |
+int dflag; | |
+int lflag; | |
+int mflag; | |
+int nflag; | |
+int pflag; | |
+int qflag; | |
+int Qflag; | |
+int rflag; | |
+int sflag; | |
+int tflag; | |
+int uflag; | |
+int Fflag; | |
+int ndirbuf; | |
+int ndir; | |
+NDir* dirbuf; | |
+int ls(char*, int); | |
+int compar(NDir*, NDir*); | |
+char* asciitime(long); | |
+char* darwx(long); | |
+void rwx(long, char*); | |
+void growto(long); | |
+void dowidths(Dir*); | |
+void format(Dir*, char*); | |
+void output(void); | |
+ulong clk; | |
+int swidth; /* max width of -s size */ | |
+int qwidth; /* max width of -q version */ | |
+int vwidth; /* max width of dev */ | |
+int uwidth; /* max width of userid */ | |
+int mwidth; /* max width of muid */ | |
+int glwidth; /* max width of groupid and length */ | |
+Biobuf bin; | |
+ | |
+void | |
+main(int argc, char *argv[]) | |
+{ | |
+ int i; | |
+ | |
+ Binit(&bin, 1, OWRITE); | |
+ ARGBEGIN{ | |
+ case 'F': Fflag++; break; | |
+ case 'd': dflag++; break; | |
+ case 'l': lflag++; break; | |
+ case 'm': mflag++; break; | |
+ case 'n': nflag++; break; | |
+ case 'p': pflag++; break; | |
+ case 'q': qflag++; break; | |
+ case 'Q': Qflag++; break; | |
+ case 'r': rflag++; break; | |
+ case 's': sflag++; break; | |
+ case 't': tflag++; break; | |
+ case 'u': uflag++; break; | |
+ default: fprint(2, "usage: ls [-dlmnpqrstuFQ] [file ...]\n"); | |
+ exits("usage"); | |
+ }ARGEND | |
+ | |
+ doquote = needsrcquote; | |
+ quotefmtinstall(); | |
+ fmtinstall('M', dirmodefmt); | |
+ | |
+ if(lflag) | |
+ clk = time(0); | |
+ if(argc == 0) | |
+ errs = ls(".", 0); | |
+ else for(i=0; i<argc; i++) | |
+ errs |= ls(argv[i], 1); | |
+ output(); | |
+ exits(errs? "errors" : 0); | |
+} | |
+ | |
+int | |
+ls(char *s, int multi) | |
+{ | |
+ int fd; | |
+ long i, n; | |
+ char *p; | |
+ Dir *db; | |
+ | |
+ for(;;) { | |
+ p = utfrrune(s, '/'); | |
+ if(p == 0 || p[1] != 0 || p == s) | |
+ break; | |
+ *p = 0; | |
+ } | |
+ db = dirstat(s); | |
+ if(db == nil){ | |
+ error: | |
+ fprint(2, "ls: %s: %r\n", s); | |
+ return 1; | |
+ } | |
+ if(db->qid.type&QTDIR && dflag==0){ | |
+ free(db); | |
+ db = nil; | |
+ output(); | |
+ fd = open(s, OREAD); | |
+ if(fd == -1) | |
+ goto error; | |
+ n = dirreadall(fd, &db); | |
+ if(n < 0) | |
+ goto error; | |
+ growto(ndir+n); | |
+ for(i=0; i<n; i++){ | |
+ dirbuf[ndir+i].d = db+i; | |
+ dirbuf[ndir+i].prefix = multi? s : 0; | |
+ } | |
+ ndir += n; | |
+ close(fd); | |
+ output(); | |
+ }else{ | |
+ growto(ndir+1); | |
+ dirbuf[ndir].d = db; | |
+ dirbuf[ndir].prefix = 0; | |
+ p = utfrrune(s, '/'); | |
+ if(p){ | |
+ dirbuf[ndir].prefix = s; | |
+ *p = 0; | |
+ /* restore original name; don't use result of stat */ | |
+ dirbuf[ndir].d->name = strdup(p+1); | |
+ } | |
+ ndir++; | |
+ } | |
+ return 0; | |
+} | |
+ | |
+void | |
+output(void) | |
+{ | |
+ int i; | |
+ char buf[4096]; | |
+ char *s; | |
+ | |
+ if(!nflag) | |
+ qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(const void*, co… | |
+ for(i=0; i<ndir; i++) | |
+ dowidths(dirbuf[i].d); | |
+ for(i=0; i<ndir; i++) { | |
+ if(!pflag && (s = dirbuf[i].prefix)) { | |
+ if(strcmp(s, "/") ==0) /* / is a special case */ | |
+ s = ""; | |
+ sprint(buf, "%s/%s", s, dirbuf[i].d->name); | |
+ format(dirbuf[i].d, buf); | |
+ } else | |
+ format(dirbuf[i].d, dirbuf[i].d->name); | |
+ } | |
+ ndir = 0; | |
+ Bflush(&bin); | |
+} | |
+ | |
+void | |
+dowidths(Dir *db) | |
+{ | |
+ char buf[256]; | |
+ int n; | |
+ | |
+ if(sflag) { | |
+ n = sprint(buf, "%llud", (db->length+1023)/1024); | |
+ if(n > swidth) | |
+ swidth = n; | |
+ } | |
+ if(qflag) { | |
+ n = sprint(buf, "%lud", db->qid.vers); | |
+ if(n > qwidth) | |
+ qwidth = n; | |
+ } | |
+ if(mflag) { | |
+ n = snprint(buf, sizeof buf, "[%s]", db->muid); | |
+ if(n > mwidth) | |
+ mwidth = n; | |
+ } | |
+ if(lflag) { | |
+ n = sprint(buf, "%ud", db->dev); | |
+ if(n > vwidth) | |
+ vwidth = n; | |
+ n = strlen(db->uid); | |
+ if(n > uwidth) | |
+ uwidth = n; | |
+ n = sprint(buf, "%llud", db->length); | |
+ n += strlen(db->gid); | |
+ if(n > glwidth) | |
+ glwidth = n; | |
+ } | |
+} | |
+ | |
+char* | |
+fileflag(Dir *db) | |
+{ | |
+ if(Fflag == 0) | |
+ return ""; | |
+ if(QTDIR & db->qid.type) | |
+ return "/"; | |
+ if(0111 & db->mode) | |
+ return "*"; | |
+ return ""; | |
+} | |
+ | |
+void | |
+format(Dir *db, char *name) | |
+{ | |
+ int i; | |
+ | |
+ if(sflag) | |
+ Bprint(&bin, "%*llud ", | |
+ swidth, (db->length+1023)/1024); | |
+ if(mflag){ | |
+ Bprint(&bin, "[%s] ", db->muid); | |
+ for(i=2+strlen(db->muid); i<mwidth; i++) | |
+ Bprint(&bin, " "); | |
+ } | |
+ if(qflag) | |
+ Bprint(&bin, "(%.16llux %*lud %.2ux) ", | |
+ db->qid.path, | |
+ qwidth, db->qid.vers, | |
+ db->qid.type); | |
+ if(lflag) | |
+ Bprint(&bin, | |
+ Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*u… | |
+ db->mode, db->type, | |
+ vwidth, db->dev, | |
+ -uwidth, db->uid, | |
+ db->gid, | |
+ (int)(glwidth-strlen(db->gid)), db->length, | |
+ asciitime(uflag? db->atime : db->mtime), name); | |
+ else | |
+ Bprint(&bin, | |
+ Qflag? "%s%s\n" : "%q%s\n", | |
+ name, fileflag(db)); | |
+} | |
+ | |
+void | |
+growto(long n) | |
+{ | |
+ if(n <= ndirbuf) | |
+ return; | |
+ ndirbuf = n; | |
+ dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir)); | |
+ if(dirbuf == 0){ | |
+ fprint(2, "ls: malloc fail\n"); | |
+ exits("malloc fail"); | |
+ } | |
+} | |
+ | |
+int | |
+compar(NDir *a, NDir *b) | |
+{ | |
+ long i; | |
+ Dir *ad, *bd; | |
+ | |
+ ad = a->d; | |
+ bd = b->d; | |
+ | |
+ if(tflag){ | |
+ if(uflag) | |
+ i = bd->atime-ad->atime; | |
+ else | |
+ i = bd->mtime-ad->mtime; | |
+ }else{ | |
+ if(a->prefix && b->prefix){ | |
+ i = strcmp(a->prefix, b->prefix); | |
+ if(i == 0) | |
+ i = strcmp(ad->name, bd->name); | |
+ }else if(a->prefix){ | |
+ i = strcmp(a->prefix, bd->name); | |
+ if(i == 0) | |
+ i = 1; /* a is longer than b */ | |
+ }else if(b->prefix){ | |
+ i = strcmp(ad->name, b->prefix); | |
+ if(i == 0) | |
+ i = -1; /* b is longer than a */ | |
+ }else | |
+ i = strcmp(ad->name, bd->name); | |
+ } | |
+ if(i == 0) | |
+ i = (ad<bd? -1 : 1); | |
+ if(rflag) | |
+ i = -i; | |
+ return i; | |
+} | |
+ | |
+char* | |
+asciitime(long l) | |
+{ | |
+ static char buf[32]; | |
+ char *t; | |
+ | |
+ t = ctime(l); | |
+ /* 6 months in the past or a day in the future */ | |
+ if(l<clk-180L*24*60*60 || clk+24L*60*60<l){ | |
+ memmove(buf, t+4, 7); /* month and day */ | |
+ memmove(buf+7, t+23, 5); /* year */ | |
+ }else | |
+ memmove(buf, t+4, 12); /* skip day of week */ | |
+ buf[12] = 0; | |
+ return buf; | |
+} | |
+ |