summaryrefslogtreecommitdiff
path: root/appl/cmd/ls.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/ls.b')
-rw-r--r--appl/cmd/ls.b318
1 files changed, 318 insertions, 0 deletions
diff --git a/appl/cmd/ls.b b/appl/cmd/ls.b
new file mode 100644
index 00000000..3d27d59e
--- /dev/null
+++ b/appl/cmd/ls.b
@@ -0,0 +1,318 @@
+implement Ls;
+
+include "sys.m";
+ sys: Sys;
+ FD, Dir: import Sys;
+
+include "draw.m";
+ Context: import Draw;
+
+include "daytime.m";
+ daytime: Daytime;
+
+include "readdir.m";
+ readdir: Readdir;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "string.m";
+ str: String;
+
+include "arg.m";
+
+Ls: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+PREFIX: con 16r40000000;
+
+dopt := 0;
+eopt := 0;
+lopt := 0;
+mopt := 0;
+nopt := 0;
+popt := 0;
+qopt := 0;
+sopt := 0;
+topt := 0;
+uopt := 0;
+Topt := 0;
+now: int;
+sortby: int;
+
+out: ref Bufio->Iobuf;
+stderr: ref FD;
+
+dwIndex: int;
+dwQueue: array of Dir;
+
+badmodule(p: string)
+{
+ sys->fprint(stderr, "ls: cannot load %s: %r\n", p);
+ raise "fail:bad module";
+}
+
+init(nil: ref Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ bufio = load Bufio Bufio->PATH;
+ if(bufio == nil)
+ badmodule(Bufio->PATH);
+ readdir = load Readdir Readdir->PATH;
+ if(readdir == nil)
+ badmodule(Readdir->PATH);
+ str = load String String->PATH;
+ if(str == nil)
+ badmodule(String->PATH);
+
+ stderr = sys->fildes(2);
+ out = bufio->fopen(sys->fildes(1), Bufio->OWRITE);
+ rev := 0;
+ sortby = Readdir->NAME;
+ compact := 0;
+
+ arg := load Arg Arg->PATH;
+ if(arg == nil)
+ badmodule(Arg->PATH);
+ arg->init(argv);
+ while((o := arg->opt()) != 0){
+ case o {
+ 'l' =>
+ lopt++;
+ daytime = load Daytime Daytime->PATH;
+ if(daytime == nil)
+ badmodule(Daytime->PATH);
+ now = daytime->now();
+ 'p' =>
+ popt++;
+ 'q' =>
+ qopt++;
+ 'd' =>
+ dopt++;
+ 'e' =>
+ eopt++;
+ 'm' =>
+ mopt++;
+ 'n' =>
+ nopt++;
+ 'k' =>
+ sopt++;
+ 't' =>
+ topt++;
+ 'u' =>
+ uopt++;
+ 's' =>
+ sortby = Readdir->SIZE;
+ 'c' =>
+ compact = Readdir->COMPACT;
+ 'r' =>
+ rev = Readdir->DESCENDING;
+ 'T' =>
+ Topt++;
+ * =>
+ sys->fprint(stderr, "usage: ls [-delmnpqrstucT] [files]\n");
+ raise "fail:usage";
+ }
+ }
+ argv = arg->argv();
+ arg = nil;
+
+ if(nopt == 0) {
+ if(topt){
+ if(uopt)
+ sortby = Readdir->ATIME;
+ else
+ sortby = Readdir->MTIME;
+ }
+ } else
+ sortby = Readdir->NONE;
+ sortby |= rev|compact;
+
+ if(argv == nil) {
+ argv = list of {"."};
+ popt++;
+ }
+
+ for(; argv != nil; argv = tl argv)
+ ls(hd argv);
+ delayWrite();
+ out.flush();
+}
+
+ls(file: string)
+{
+ dir: Dir;
+ ok: int;
+
+ (ok, dir) = sys->stat(file);
+ if(ok == -1) {
+ sys->fprint(stderr, "ls: stat %s: %r\n", file);
+ return;
+ }
+ if(dopt || (dir.mode & Sys->DMDIR) == 0) {
+ # delay write: save it in the queue to sort by sortby
+ if(dwIndex == 0)
+ dwQueue = array[30] of Dir;
+ else if(len dwQueue == dwIndex) {
+ # expand dwQueue
+ tmp := array[2 * dwIndex] of Dir;
+ tmp[0:] = dwQueue;
+ dwQueue = tmp;
+ }
+ (dirname, filename) := str->splitstrr(file, "/");
+ if(dirname != "") {
+ dir.name = dirname + filename;
+ dir.dev |= PREFIX;
+ }
+ dwQueue[dwIndex++] = dir;
+ return;
+ }
+
+ delayWrite();
+
+ (d, n) := readdir->init(file, sortby);
+ if( n < 0)
+ sys->fprint(stderr, "ls: Readdir: %s: %r\n", file);
+ else
+ lsprint(file, d[0:n]);
+}
+
+delayWrite()
+{
+ if(dwIndex == 0)
+ return;
+
+ a := array[dwIndex] of ref Dir;
+ for (i := 0; i < dwIndex; i++)
+ a[i] = ref dwQueue[i];
+ (b, n) := readdir->sortdir(a, sortby);
+
+ lsprint("", b[0:n]);
+
+ # reset dwIndex
+ dwIndex = 0;
+ dwQueue = nil;
+}
+
+Widths: adt {
+ vers, dev, uid, gid, muid, length, size: int;
+};
+
+dowidths(dir: array of ref Dir): ref Widths
+{
+ w := Widths(0, 0, 0, 0, 0, 0, 0);
+ for (i := 0; i < len dir; i++) {
+ n: int;
+ d := dir[i];
+ if(sopt)
+ if((n = len string ((d.length+big 1023)/big 1024)) > w.size)
+ w.size = n;
+ if(mopt)
+ if((n = len d.muid+2) > w.muid)
+ w.muid = n;
+ if(qopt)
+ if((n = len string d.qid.vers) > w.vers)
+ w.vers = n;
+ if(lopt) {
+ if((n = len string (d.dev & ~PREFIX)) > w.dev)
+ w.dev = n;
+ if((n = len d.uid) > w.uid)
+ w.uid = n;
+ if((n = len d.gid) > w.gid)
+ w.gid = n;
+ if((n = len string d.length) > w.length)
+ w.length = n;
+ }
+ }
+ return ref w;
+}
+
+
+lsprint(dirname: string, dir: array of ref Dir)
+{
+ w := dowidths(dir);
+
+ for (i := 0; i < len dir; i++)
+ lslineprint(dirname, dir[i].name, dir[i], w);
+}
+
+lslineprint(dirname, name: string, dir: ref Dir, w: ref Widths)
+{
+ if(sopt)
+ out.puts(sys->sprint("%*bd ", w.size, (dir.length+big 1023)/big 1024));
+ if(mopt){
+ out.puts(sys->sprint("[%s] ", dir.muid));
+ for(i := len dir.muid+2; i < w.muid; i++)
+ out.putc(' ');
+ }
+ if(qopt)
+ out.puts(sys->sprint("(%.16bux %*ud %.2ux) ", dir.qid.path, w.vers, dir.qid.vers, dir.qid.qtype));
+ if(Topt){
+ if(dir.mode & Sys->DMTMP)
+ out.puts("t ");
+ else
+ out.puts("- ");
+ }
+
+ file := name;
+ pf := dir.dev & PREFIX;
+ dir.dev &= ~PREFIX;
+ if(popt) {
+ if(pf)
+ (nil, file) = str->splitstrr(dir.name, "/");
+ else
+ file = dir.name;
+ } else if(dirname != "") {
+ if(dirname[len dirname-1] == '/')
+ file = dirname + file;
+ else
+ file = dirname + "/" + file;
+ }
+
+
+ if(lopt) {
+ time := dir.mtime;
+ if(uopt)
+ time = dir.atime;
+ if(eopt)
+ out.puts(sys->sprint("%s %c %*d %*s %*s %*bud %d %s\n",
+ modes(dir.mode), dir.dtype, w.dev, dir.dev,
+ -w.uid, dir.uid, -w.gid, dir.gid, w.length, dir.length,
+ time, file));
+ else
+ out.puts(sys->sprint("%s %c %*d %*s %*s %*bud %s %s\n",
+ modes(dir.mode), dir.dtype, w.dev, dir.dev,
+ -w.uid, dir.uid, -w.gid, dir.gid, w.length, dir.length,
+ daytime->filet(now, time), file));
+ } else
+ out.puts(file+"\n");
+}
+
+mtab := array[] of {
+ "---", "--x", "-w-", "-wx",
+ "r--", "r-x", "rw-", "rwx"
+};
+
+modes(mode: int): string
+{
+ s: string;
+
+ if(mode & Sys->DMDIR)
+ s = "d";
+ else if(mode & Sys->DMAPPEND)
+ s = "a";
+ else if(mode & Sys->DMAUTH)
+ s = "A";
+ else
+ s = "-";
+ if(mode & Sys->DMEXCL)
+ s += "l";
+ else
+ s += "-";
+ s += mtab[(mode>>6)&7]+mtab[(mode>>3)&7]+mtab[mode&7];
+ return s;
+}
+