aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ls.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2014-11-17 11:21:06 -0500
committerRuss Cox <rsc@swtch.com>2014-11-17 11:21:06 -0500
commitc9ed52730b352448c7c644f6942d310dd3509bf6 (patch)
treed9723cd78c8b632e76e90f51ae43bd65c2139116 /src/cmd/ls.c
parent08e793723cad1c7aed2e8cb16c8592aba5ad05e9 (diff)
downloadplan9port-c9ed52730b352448c7c644f6942d310dd3509bf6.tar.gz
plan9port-c9ed52730b352448c7c644f6942d310dd3509bf6.tar.bz2
plan9port-c9ed52730b352448c7c644f6942d310dd3509bf6.zip
cmd: rename *.C to *.c
These were *.C back in 2003, before the 9 script, to avoid conflicts with the system utilities. A later change renamed them, but that change seems to have been lost during the hg->git conversion because I ran the conversion on a case-insensitive file system. Change-Id: Id32c99cb9571ef0e185c3cc9e8c8d6d5b48ca195
Diffstat (limited to 'src/cmd/ls.c')
-rw-r--r--src/cmd/ls.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/src/cmd/ls.c b/src/cmd/ls.c
new file mode 100644
index 00000000..60615059
--- /dev/null
+++ b/src/cmd/ls.c
@@ -0,0 +1,308 @@
+#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*, const void*))compar);
+ 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,
+ "%M %C %*ud %*s %s %*llud %s ",
+ 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));
+ 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;
+}
+