1implement Ls; 2 3include "sys.m"; 4 sys: Sys; 5 FD, Dir: import Sys; 6 7include "draw.m"; 8 Context: import Draw; 9 10include "daytime.m"; 11 daytime: Daytime; 12 13include "readdir.m"; 14 readdir: Readdir; 15 16include "bufio.m"; 17 bufio: Bufio; 18 Iobuf: import bufio; 19 20include "string.m"; 21 str: String; 22 23include "arg.m"; 24 25Ls: module 26{ 27 init: fn(ctxt: ref Context, argv: list of string); 28}; 29 30PREFIX: con 16r40000000; 31 32dopt := 0; 33eopt := 0; 34lopt := 0; 35mopt := 0; 36nopt := 0; 37popt := 0; 38qopt := 0; 39sopt := 0; 40topt := 0; 41uopt := 0; 42Fopt := 0; 43Topt := 0; 44now: int; 45sortby: int; 46 47out: ref Bufio->Iobuf; 48stderr: ref FD; 49 50delaydir: array of ref Dir; 51delayindex: int; 52 53badmodule(p: string) 54{ 55 sys->fprint(stderr, "ls: cannot load %s: %r\n", p); 56 raise "fail:bad module"; 57} 58 59init(nil: ref Context, argv: list of string) 60{ 61 sys = load Sys Sys->PATH; 62 bufio = load Bufio Bufio->PATH; 63 if(bufio == nil) 64 badmodule(Bufio->PATH); 65 readdir = load Readdir Readdir->PATH; 66 if(readdir == nil) 67 badmodule(Readdir->PATH); 68 str = load String String->PATH; 69 if(str == nil) 70 badmodule(String->PATH); 71 72 stderr = sys->fildes(2); 73 out = bufio->fopen(sys->fildes(1), Bufio->OWRITE); 74 rev := 0; 75 sortby = Readdir->NAME; 76 compact := 0; 77 78 arg := load Arg Arg->PATH; 79 if(arg == nil) 80 badmodule(Arg->PATH); 81 arg->init(argv); 82 while((o := arg->opt()) != 0){ 83 case o { 84 'l' => 85 lopt++; 86 daytime = load Daytime Daytime->PATH; 87 if(daytime == nil) 88 badmodule(Daytime->PATH); 89 now = daytime->now(); 90 'p' => 91 popt++; 92 'q' => 93 qopt++; 94 'd' => 95 dopt++; 96 'e' => 97 eopt++; 98 'm' => 99 mopt++; 100 'n' => 101 nopt++; 102 'k' => 103 sopt++; 104 't' => 105 topt++; 106 'u' => 107 uopt++; 108 's' => 109 sortby = Readdir->SIZE; 110 'c' => 111 compact = Readdir->COMPACT; 112 'r' => 113 rev = Readdir->DESCENDING; 114 'T' => 115 Topt++; 116 'F' => 117 Fopt++; 118 * => 119 sys->fprint(stderr, "usage: ls [-delmnpqrstucFT] [files]\n"); 120 raise "fail:usage"; 121 } 122 } 123 argv = arg->argv(); 124 arg = nil; 125 126 if(nopt == 0) { 127 if(topt){ 128 if(uopt) 129 sortby = Readdir->ATIME; 130 else 131 sortby = Readdir->MTIME; 132 } 133 } else 134 sortby = Readdir->NONE; 135 sortby |= rev|compact; 136 137 if(argv == nil) { 138 argv = list of {"."}; 139 popt++; 140 } 141 142 errs := 0; 143 for(; argv != nil; argv = tl argv) 144 errs |= !ls(hd argv); 145 delaywrite(); 146 out.flush(); 147 if(errs != 0) 148 raise "fail:errors"; 149} 150 151ls(file: string): int 152{ 153 dir: Dir; 154 ok: int; 155 156 (ok, dir) = sys->stat(file); 157 if(ok == -1) { 158 sys->fprint(stderr, "ls: %s: %r\n", file); 159 return 0; 160 } 161 if(dopt || (dir.mode & Sys->DMDIR) == 0) { 162 # delay write: save it in the queue to sort by sortby 163 if(delayindex == 0) 164 delaydir = array[30] of ref Dir; 165 else if(len delaydir == delayindex) { 166 tmp := array[2 * delayindex] of ref Dir; 167 tmp[0:] = delaydir; 168 delaydir = tmp; 169 } 170 (dirname, filename) := str->splitstrr(file, "/"); 171 if(dirname != "") { 172 dir.name = dirname + filename; 173 dir.dev |= PREFIX; 174 } 175 delaydir[delayindex++] = ref dir; 176 return 1; 177 } 178 179 delaywrite(); 180 181 (d, n) := readdir->init(file, sortby); 182 if(n < 0){ 183 sys->fprint(stderr, "ls: %s: %r\n", file); 184 return 0; 185 } 186 lsprint(file, d[0:n]); 187 return 1; 188} 189 190delaywrite() 191{ 192 if(delayindex == 0) 193 return; 194 195 (b, n) := readdir->sortdir(delaydir[0:delayindex], sortby); 196 197 lsprint("", b[0:n]); 198 199 delayindex = 0; 200 delaydir = nil; 201} 202 203Widths: adt { 204 vers, dev, uid, gid, muid, length, size: int; 205}; 206 207dowidths(dir: array of ref Dir): ref Widths 208{ 209 w := Widths(0, 0, 0, 0, 0, 0, 0); 210 for (i := 0; i < len dir; i++) { 211 n: int; 212 d := dir[i]; 213 if(sopt) 214 if((n = len string ((d.length+big 1023)/big 1024)) > w.size) 215 w.size = n; 216 if(mopt) 217 if((n = len d.muid+2) > w.muid) 218 w.muid = n; 219 if(qopt) 220 if((n = len string d.qid.vers) > w.vers) 221 w.vers = n; 222 if(lopt) { 223 if((n = len string (d.dev & ~PREFIX)) > w.dev) 224 w.dev = n; 225 if((n = len d.uid) > w.uid) 226 w.uid = n; 227 if((n = len d.gid) > w.gid) 228 w.gid = n; 229 if((n = len string d.length) > w.length) 230 w.length = n; 231 } 232 } 233 return ref w; 234} 235 236 237lsprint(dirname: string, dir: array of ref Dir) 238{ 239 w := dowidths(dir); 240 241 for (i := 0; i < len dir; i++) 242 lslineprint(dirname, dir[i].name, dir[i], w); 243} 244 245lslineprint(dirname, name: string, dir: ref Dir, w: ref Widths) 246{ 247 if(sopt) 248 out.puts(sys->sprint("%*bd ", w.size, (dir.length+big 1023)/big 1024)); 249 if(mopt){ 250 out.puts(sys->sprint("[%s] ", dir.muid)); 251 for(i := len dir.muid+2; i < w.muid; i++) 252 out.putc(' '); 253 } 254 if(qopt) 255 out.puts(sys->sprint("(%.16bux %*ud %.2ux) ", dir.qid.path, w.vers, dir.qid.vers, dir.qid.qtype)); 256 if(Topt){ 257 if(dir.mode & Sys->DMTMP) 258 out.puts("t "); 259 else 260 out.puts("- "); 261 } 262 263 file := name; 264 pf := dir.dev & PREFIX; 265 dir.dev &= ~PREFIX; 266 if(popt) { 267 if(pf) 268 (nil, file) = str->splitstrr(dir.name, "/"); 269 else 270 file = dir.name; 271 } else if(dirname != "") { 272 if(dirname[len dirname-1] == '/') 273 file = dirname + file; 274 else 275 file = dirname + "/" + file; 276 } 277 if(Fopt) 278 file += fileflag(dir); 279 280 281 if(lopt) { 282 time := dir.mtime; 283 if(uopt) 284 time = dir.atime; 285 if(eopt) 286 out.puts(sys->sprint("%s %c %*d %*s %*s %*bud %d %s\n", 287 modes(dir.mode), dir.dtype, w.dev, dir.dev, 288 -w.uid, dir.uid, -w.gid, dir.gid, w.length, dir.length, 289 time, file)); 290 else 291 out.puts(sys->sprint("%s %c %*d %*s %*s %*bud %s %s\n", 292 modes(dir.mode), dir.dtype, w.dev, dir.dev, 293 -w.uid, dir.uid, -w.gid, dir.gid, w.length, dir.length, 294 daytime->filet(now, time), file)); 295 } else 296 out.puts(file+"\n"); 297} 298 299fileflag(dir: ref Dir): string 300{ 301 if(dir.qid.qtype & Sys->QTDIR) 302 return "/"; 303 if(dir.mode & 8r111) 304 return "*"; 305 return ""; 306} 307 308mtab := array[] of { 309 "---", "--x", "-w-", "-wx", 310 "r--", "r-x", "rw-", "rwx" 311}; 312 313modes(mode: int): string 314{ 315 s: string; 316 317 if(mode & Sys->DMDIR) 318 s = "d"; 319 else if(mode & Sys->DMAPPEND) 320 s = "a"; 321 else if(mode & Sys->DMAUTH) 322 s = "A"; 323 else 324 s = "-"; 325 if(mode & Sys->DMEXCL) 326 s += "l"; 327 else 328 s += "-"; 329 s += mtab[(mode>>6)&7]+mtab[(mode>>3)&7]+mtab[mode&7]; 330 return s; 331} 332 333