diff options
Diffstat (limited to 'appl/cmd/ls.b')
| -rw-r--r-- | appl/cmd/ls.b | 318 |
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; +} + |
