ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/ls.b/
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;
Fopt := 0;
Topt := 0;
now: int;
sortby: int;
out: ref Bufio->Iobuf;
stderr: ref FD;
delaydir: array of ref Dir;
delayindex: int;
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++;
'F' =>
Fopt++;
* =>
sys->fprint(stderr, "usage: ls [-delmnpqrstucFT] [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++;
}
errs := 0;
for(; argv != nil; argv = tl argv)
errs |= !ls(hd argv);
delaywrite();
out.flush();
if(errs != 0)
raise "fail:errors";
}
ls(file: string): int
{
dir: Dir;
ok: int;
(ok, dir) = sys->stat(file);
if(ok == -1) {
sys->fprint(stderr, "ls: %s: %r\n", file);
return 0;
}
if(dopt || (dir.mode & Sys->DMDIR) == 0) {
# delay write: save it in the queue to sort by sortby
if(delayindex == 0)
delaydir = array[30] of ref Dir;
else if(len delaydir == delayindex) {
tmp := array[2 * delayindex] of ref Dir;
tmp[0:] = delaydir;
delaydir = tmp;
}
(dirname, filename) := str->splitstrr(file, "/");
if(dirname != "") {
dir.name = dirname + filename;
dir.dev |= PREFIX;
}
delaydir[delayindex++] = ref dir;
return 1;
}
delaywrite();
(d, n) := readdir->init(file, sortby);
if(n < 0){
sys->fprint(stderr, "ls: %s: %r\n", file);
return 0;
}
lsprint(file, d[0:n]);
return 1;
}
delaywrite()
{
if(delayindex == 0)
return;
(b, n) := readdir->sortdir(delaydir[0:delayindex], sortby);
lsprint("", b[0:n]);
delayindex = 0;
delaydir = 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(Fopt)
file += fileflag(dir);
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");
}
fileflag(dir: ref Dir): string
{
if(dir.qid.qtype & Sys->QTDIR)
return "/";
if(dir.mode & 8r111)
return "*";
return "";
}
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;
}