1*37da2899SCharles.Forsythimplement Sh; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "sys.m"; 4*37da2899SCharles.Forsyth sys: Sys; 5*37da2899SCharles.Forsyth FD: import Sys; 6*37da2899SCharles.Forsyth 7*37da2899SCharles.Forsythinclude "draw.m"; 8*37da2899SCharles.Forsyth Context: import Draw; 9*37da2899SCharles.Forsyth 10*37da2899SCharles.Forsythinclude "filepat.m"; 11*37da2899SCharles.Forsyth filepat: Filepat; 12*37da2899SCharles.Forsyth nofilepat := 0; # true if load Filepat has failed. 13*37da2899SCharles.Forsyth 14*37da2899SCharles.Forsythinclude "bufio.m"; 15*37da2899SCharles.Forsyth bufio: Bufio; 16*37da2899SCharles.Forsyth Iobuf: import bufio; 17*37da2899SCharles.Forsyth 18*37da2899SCharles.Forsythinclude "env.m"; 19*37da2899SCharles.Forsyth env: Env; 20*37da2899SCharles.Forsyth 21*37da2899SCharles.Forsythstdin: ref FD; 22*37da2899SCharles.Forsythstderr: ref FD; 23*37da2899SCharles.Forsythwaitfd: ref FD; 24*37da2899SCharles.Forsyth 25*37da2899SCharles.ForsythQuoted: con '\uFFF0'; 26*37da2899SCharles.ForsythstringQuoted: con "\uFFF0"; 27*37da2899SCharles.Forsyth 28*37da2899SCharles.ForsythSh: module 29*37da2899SCharles.Forsyth{ 30*37da2899SCharles.Forsyth init: fn(ctxt: ref Context, argv: list of string); 31*37da2899SCharles.Forsyth}; 32*37da2899SCharles.Forsyth 33*37da2899SCharles.ForsythCommand: adt 34*37da2899SCharles.Forsyth{ 35*37da2899SCharles.Forsyth args: list of string; 36*37da2899SCharles.Forsyth inf, outf: string; 37*37da2899SCharles.Forsyth append: int; 38*37da2899SCharles.Forsyth}; 39*37da2899SCharles.Forsyth 40*37da2899SCharles.ForsythAsync, Seq: con iota; 41*37da2899SCharles.Forsyth 42*37da2899SCharles.ForsythPipeline: adt 43*37da2899SCharles.Forsyth{ 44*37da2899SCharles.Forsyth cmds: list of ref Command; 45*37da2899SCharles.Forsyth term: int; 46*37da2899SCharles.Forsyth}; 47*37da2899SCharles.Forsyth 48*37da2899SCharles.Forsythusage() 49*37da2899SCharles.Forsyth{ 50*37da2899SCharles.Forsyth sys->fprint(stderr, "Usage: sh [-n] [-c cmd] [file]\n"); 51*37da2899SCharles.Forsyth} 52*37da2899SCharles.Forsyth 53*37da2899SCharles.Forsythinit(ctxt: ref Context, argv: list of string) 54*37da2899SCharles.Forsyth{ 55*37da2899SCharles.Forsyth n: int; 56*37da2899SCharles.Forsyth arg: list of string; 57*37da2899SCharles.Forsyth buf := array[1024] of byte; 58*37da2899SCharles.Forsyth 59*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 60*37da2899SCharles.Forsyth env = load Env Env->PATH; 61*37da2899SCharles.Forsyth 62*37da2899SCharles.Forsyth stderr = sys->fildes(2); 63*37da2899SCharles.Forsyth 64*37da2899SCharles.Forsyth waitfd = sys->open("#p/"+string sys->pctl(0, nil)+"/wait", sys->OREAD); 65*37da2899SCharles.Forsyth if(waitfd == nil){ 66*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: open wait: %r\n"); 67*37da2899SCharles.Forsyth return; 68*37da2899SCharles.Forsyth } 69*37da2899SCharles.Forsyth 70*37da2899SCharles.Forsyth eflag := nflag := lflag := 0; 71*37da2899SCharles.Forsyth cmd: string; 72*37da2899SCharles.Forsyth if(argv != nil) 73*37da2899SCharles.Forsyth argv = tl argv; 74*37da2899SCharles.Forsyth for(; argv != nil && len hd argv && (hd argv)[0]=='-'; argv = tl argv) 75*37da2899SCharles.Forsyth case hd argv { 76*37da2899SCharles.Forsyth "-e" => 77*37da2899SCharles.Forsyth eflag = 1; 78*37da2899SCharles.Forsyth "-n" => 79*37da2899SCharles.Forsyth nflag = 1; 80*37da2899SCharles.Forsyth "-l" => 81*37da2899SCharles.Forsyth lflag = 1; 82*37da2899SCharles.Forsyth "-c" => 83*37da2899SCharles.Forsyth argv = tl argv; 84*37da2899SCharles.Forsyth if(len argv != 1){ 85*37da2899SCharles.Forsyth usage(); 86*37da2899SCharles.Forsyth return; 87*37da2899SCharles.Forsyth } 88*37da2899SCharles.Forsyth cmd = hd argv; 89*37da2899SCharles.Forsyth * => 90*37da2899SCharles.Forsyth usage(); 91*37da2899SCharles.Forsyth return; 92*37da2899SCharles.Forsyth } 93*37da2899SCharles.Forsyth 94*37da2899SCharles.Forsyth if (lflag) 95*37da2899SCharles.Forsyth startup(ctxt); 96*37da2899SCharles.Forsyth 97*37da2899SCharles.Forsyth if(eflag == 0) 98*37da2899SCharles.Forsyth sys->pctl(sys->FORKENV, nil); 99*37da2899SCharles.Forsyth if(nflag == 0) 100*37da2899SCharles.Forsyth sys->pctl(sys->FORKNS, nil); 101*37da2899SCharles.Forsyth if(cmd != nil){ 102*37da2899SCharles.Forsyth arg = tokenize(cmd+"\n"); 103*37da2899SCharles.Forsyth if(arg != nil) 104*37da2899SCharles.Forsyth runit(ctxt, parseit(arg)); 105*37da2899SCharles.Forsyth return; 106*37da2899SCharles.Forsyth } 107*37da2899SCharles.Forsyth if(argv != nil){ 108*37da2899SCharles.Forsyth script(ctxt, hd argv); 109*37da2899SCharles.Forsyth return; 110*37da2899SCharles.Forsyth } 111*37da2899SCharles.Forsyth 112*37da2899SCharles.Forsyth stdin = sys->fildes(0); 113*37da2899SCharles.Forsyth 114*37da2899SCharles.Forsyth prompt := sysname() + "$ "; 115*37da2899SCharles.Forsyth for(;;){ 116*37da2899SCharles.Forsyth sys->print("%s", prompt); 117*37da2899SCharles.Forsyth n = sys->read(stdin, buf, len buf); 118*37da2899SCharles.Forsyth if(n <= 0) 119*37da2899SCharles.Forsyth break; 120*37da2899SCharles.Forsyth arg = tokenize(string buf[0:n]); 121*37da2899SCharles.Forsyth if(arg != nil) 122*37da2899SCharles.Forsyth runit(ctxt, parseit(arg)); 123*37da2899SCharles.Forsyth } 124*37da2899SCharles.Forsyth} 125*37da2899SCharles.Forsyth 126*37da2899SCharles.Forsythrev(arg: list of string): list of string 127*37da2899SCharles.Forsyth{ 128*37da2899SCharles.Forsyth ret: list of string; 129*37da2899SCharles.Forsyth 130*37da2899SCharles.Forsyth while(arg != nil){ 131*37da2899SCharles.Forsyth ret = hd arg :: ret; 132*37da2899SCharles.Forsyth arg = tl arg; 133*37da2899SCharles.Forsyth } 134*37da2899SCharles.Forsyth return ret; 135*37da2899SCharles.Forsyth} 136*37da2899SCharles.Forsyth 137*37da2899SCharles.Forsythwaitfor(pid: int) 138*37da2899SCharles.Forsyth{ 139*37da2899SCharles.Forsyth if(pid <= 0) 140*37da2899SCharles.Forsyth return; 141*37da2899SCharles.Forsyth buf := array[sys->WAITLEN] of byte; 142*37da2899SCharles.Forsyth status := ""; 143*37da2899SCharles.Forsyth for(;;){ 144*37da2899SCharles.Forsyth n := sys->read(waitfd, buf, len buf); 145*37da2899SCharles.Forsyth if(n < 0){ 146*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: read wait: %r\n"); 147*37da2899SCharles.Forsyth return; 148*37da2899SCharles.Forsyth } 149*37da2899SCharles.Forsyth status = string buf[0:n]; 150*37da2899SCharles.Forsyth if(status[len status-1] != ':') 151*37da2899SCharles.Forsyth sys->fprint(stderr, "%s\n", status); 152*37da2899SCharles.Forsyth who := int status; 153*37da2899SCharles.Forsyth if(who != 0){ 154*37da2899SCharles.Forsyth if(who == pid) 155*37da2899SCharles.Forsyth return; 156*37da2899SCharles.Forsyth } 157*37da2899SCharles.Forsyth } 158*37da2899SCharles.Forsyth} 159*37da2899SCharles.Forsyth 160*37da2899SCharles.Forsythmkprog(ctxt: ref Context, arg: list of string, infd, outfd: ref Sys->FD, waitpid: chan of int) 161*37da2899SCharles.Forsyth{ 162*37da2899SCharles.Forsyth fds := list of {0, 1, 2}; 163*37da2899SCharles.Forsyth if(infd != nil) 164*37da2899SCharles.Forsyth fds = infd.fd :: fds; 165*37da2899SCharles.Forsyth if(outfd != nil) 166*37da2899SCharles.Forsyth fds = outfd.fd :: fds; 167*37da2899SCharles.Forsyth pid := sys->pctl(sys->NEWFD, fds); 168*37da2899SCharles.Forsyth console := sys->fildes(2); 169*37da2899SCharles.Forsyth 170*37da2899SCharles.Forsyth if(infd != nil){ 171*37da2899SCharles.Forsyth sys->dup(infd.fd, 0); 172*37da2899SCharles.Forsyth infd = nil; 173*37da2899SCharles.Forsyth } 174*37da2899SCharles.Forsyth if(outfd != nil){ 175*37da2899SCharles.Forsyth sys->dup(outfd.fd, 1); 176*37da2899SCharles.Forsyth outfd = nil; 177*37da2899SCharles.Forsyth } 178*37da2899SCharles.Forsyth 179*37da2899SCharles.Forsyth waitpid <-= pid; 180*37da2899SCharles.Forsyth 181*37da2899SCharles.Forsyth if(pid < 0 || arg == nil) 182*37da2899SCharles.Forsyth return; 183*37da2899SCharles.Forsyth 184*37da2899SCharles.Forsyth { 185*37da2899SCharles.Forsyth exec(ctxt, arg, console); 186*37da2899SCharles.Forsyth }exception{ 187*37da2899SCharles.Forsyth "fail:*" => 188*37da2899SCharles.Forsyth #sys->fprint(console, "%s:%s\n", hd arg, e.name[5:]); 189*37da2899SCharles.Forsyth exit; 190*37da2899SCharles.Forsyth "write on closed pipe" => 191*37da2899SCharles.Forsyth #sys->fprint(console, "%s: %s\n", hd arg, e.name); 192*37da2899SCharles.Forsyth exit; 193*37da2899SCharles.Forsyth } 194*37da2899SCharles.Forsyth} 195*37da2899SCharles.Forsyth 196*37da2899SCharles.Forsythexec(ctxt: ref Context, args: list of string, console: ref Sys->FD) 197*37da2899SCharles.Forsyth{ 198*37da2899SCharles.Forsyth if (args == nil) 199*37da2899SCharles.Forsyth return; 200*37da2899SCharles.Forsyth cmd := hd args; 201*37da2899SCharles.Forsyth file := cmd; 202*37da2899SCharles.Forsyth 203*37da2899SCharles.Forsyth if(len file<4 || file[len file-4:]!=".dis") 204*37da2899SCharles.Forsyth file += ".dis"; 205*37da2899SCharles.Forsyth 206*37da2899SCharles.Forsyth c := load Sh file; 207*37da2899SCharles.Forsyth if(c == nil) { 208*37da2899SCharles.Forsyth err := sys->sprint("%r"); 209*37da2899SCharles.Forsyth if(err != "permission denied" && err != "access permission denied" && file[0]!='/' && file[0:2]!="./"){ 210*37da2899SCharles.Forsyth c = load Sh "/dis/"+file; 211*37da2899SCharles.Forsyth if(c == nil) 212*37da2899SCharles.Forsyth err = sys->sprint("%r"); 213*37da2899SCharles.Forsyth } 214*37da2899SCharles.Forsyth if(c == nil){ 215*37da2899SCharles.Forsyth sys->fprint(console, "%s: %s\n", cmd, err); 216*37da2899SCharles.Forsyth return; 217*37da2899SCharles.Forsyth } 218*37da2899SCharles.Forsyth } 219*37da2899SCharles.Forsyth 220*37da2899SCharles.Forsyth c->init(ctxt, args); 221*37da2899SCharles.Forsyth} 222*37da2899SCharles.Forsyth 223*37da2899SCharles.Forsythscript(ctxt: ref Context, src: string) 224*37da2899SCharles.Forsyth{ 225*37da2899SCharles.Forsyth bufio = load Bufio Bufio->PATH; 226*37da2899SCharles.Forsyth if(bufio == nil){ 227*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: load bufio: %r\n"); 228*37da2899SCharles.Forsyth return; 229*37da2899SCharles.Forsyth } 230*37da2899SCharles.Forsyth 231*37da2899SCharles.Forsyth f := bufio->open(src, Bufio->OREAD); 232*37da2899SCharles.Forsyth if(f == nil){ 233*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: open %s: %r\n", src); 234*37da2899SCharles.Forsyth return; 235*37da2899SCharles.Forsyth } 236*37da2899SCharles.Forsyth for(;;){ 237*37da2899SCharles.Forsyth s := f.gets('\n'); 238*37da2899SCharles.Forsyth if(s == nil) 239*37da2899SCharles.Forsyth break; 240*37da2899SCharles.Forsyth arg := tokenize(s); 241*37da2899SCharles.Forsyth if(arg != nil) 242*37da2899SCharles.Forsyth runit(ctxt, parseit(arg)); 243*37da2899SCharles.Forsyth } 244*37da2899SCharles.Forsyth} 245*37da2899SCharles.Forsyth 246*37da2899SCharles.Forsythsysname(): string 247*37da2899SCharles.Forsyth{ 248*37da2899SCharles.Forsyth fd := sys->open("#c/sysname", sys->OREAD); 249*37da2899SCharles.Forsyth if(fd == nil) 250*37da2899SCharles.Forsyth return "anon"; 251*37da2899SCharles.Forsyth buf := array[128] of byte; 252*37da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 253*37da2899SCharles.Forsyth if(n < 0) 254*37da2899SCharles.Forsyth return "anon"; 255*37da2899SCharles.Forsyth return string buf[0:n]; 256*37da2899SCharles.Forsyth} 257*37da2899SCharles.Forsyth 258*37da2899SCharles.Forsyth# Lexer. 259*37da2899SCharles.Forsyth 260*37da2899SCharles.Forsythtokenize(s: string): list of string 261*37da2899SCharles.Forsyth{ 262*37da2899SCharles.Forsyth tok: list of string; 263*37da2899SCharles.Forsyth token := ""; 264*37da2899SCharles.Forsyth instring := 0; 265*37da2899SCharles.Forsyth 266*37da2899SCharles.Forsythloop: 267*37da2899SCharles.Forsyth for(i:=0; i<len s; i++) { 268*37da2899SCharles.Forsyth if(instring) { 269*37da2899SCharles.Forsyth if(s[i] != '\'') 270*37da2899SCharles.Forsyth token = addchar(token, s[i]); 271*37da2899SCharles.Forsyth else if(i == len s-1 || s[i+1] != '\'') { 272*37da2899SCharles.Forsyth if(i == len s-1 || s[i+1] == ' ' || s[i+1] == '\t' || s[i+1] == '\n'){ 273*37da2899SCharles.Forsyth tok = token :: tok; 274*37da2899SCharles.Forsyth token = ""; 275*37da2899SCharles.Forsyth } 276*37da2899SCharles.Forsyth instring = 0; 277*37da2899SCharles.Forsyth } else { 278*37da2899SCharles.Forsyth token[len token] = '\''; 279*37da2899SCharles.Forsyth i++; 280*37da2899SCharles.Forsyth } 281*37da2899SCharles.Forsyth continue; 282*37da2899SCharles.Forsyth } 283*37da2899SCharles.Forsyth case s[i] { 284*37da2899SCharles.Forsyth ' ' or '\t' or '\n' or '#' or 285*37da2899SCharles.Forsyth '\'' or '|' or '&' or ';' or 286*37da2899SCharles.Forsyth '>' or '<' or '\r' => 287*37da2899SCharles.Forsyth if(token != "" && s[i]!='\''){ 288*37da2899SCharles.Forsyth tok = token :: tok; 289*37da2899SCharles.Forsyth token = ""; 290*37da2899SCharles.Forsyth } 291*37da2899SCharles.Forsyth case s[i] { 292*37da2899SCharles.Forsyth '#' => 293*37da2899SCharles.Forsyth break loop; 294*37da2899SCharles.Forsyth '\'' => 295*37da2899SCharles.Forsyth instring = 1; 296*37da2899SCharles.Forsyth '>' => 297*37da2899SCharles.Forsyth ss := ""; 298*37da2899SCharles.Forsyth ss[0] = s[i]; 299*37da2899SCharles.Forsyth if(i<len s-1 && s[i+1]==s[i]) 300*37da2899SCharles.Forsyth ss[1] = s[i++]; 301*37da2899SCharles.Forsyth tok = ss :: tok; 302*37da2899SCharles.Forsyth '|' or '&' or ';' or '<' => 303*37da2899SCharles.Forsyth ss := ""; 304*37da2899SCharles.Forsyth ss[0] = s[i]; 305*37da2899SCharles.Forsyth tok = ss :: tok; 306*37da2899SCharles.Forsyth } 307*37da2899SCharles.Forsyth * => 308*37da2899SCharles.Forsyth token[len token] = s[i]; 309*37da2899SCharles.Forsyth } 310*37da2899SCharles.Forsyth } 311*37da2899SCharles.Forsyth if(instring){ 312*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: unmatched quote\n"); 313*37da2899SCharles.Forsyth return nil; 314*37da2899SCharles.Forsyth } 315*37da2899SCharles.Forsyth return rev(tok); 316*37da2899SCharles.Forsyth} 317*37da2899SCharles.Forsyth 318*37da2899SCharles.Forsythismeta(char: int): int 319*37da2899SCharles.Forsyth{ 320*37da2899SCharles.Forsyth case char { 321*37da2899SCharles.Forsyth '*' or '[' or '?' or 322*37da2899SCharles.Forsyth '#' or '\'' or '|' or 323*37da2899SCharles.Forsyth '&' or ';' or '>' or 324*37da2899SCharles.Forsyth '<' => 325*37da2899SCharles.Forsyth return 1; 326*37da2899SCharles.Forsyth } 327*37da2899SCharles.Forsyth return 0; 328*37da2899SCharles.Forsyth} 329*37da2899SCharles.Forsyth 330*37da2899SCharles.Forsythaddchar(token: string, char: int): string 331*37da2899SCharles.Forsyth{ 332*37da2899SCharles.Forsyth if(ismeta(char) && (len token==0 || token[0]!=Quoted)) 333*37da2899SCharles.Forsyth token = stringQuoted + token; 334*37da2899SCharles.Forsyth token[len token] = char; 335*37da2899SCharles.Forsyth return token; 336*37da2899SCharles.Forsyth} 337*37da2899SCharles.Forsyth 338*37da2899SCharles.Forsyth# Parser. 339*37da2899SCharles.Forsyth 340*37da2899SCharles.Forsythgetcommand(words: list of string): (ref Command, list of string) 341*37da2899SCharles.Forsyth{ 342*37da2899SCharles.Forsyth args: list of string; 343*37da2899SCharles.Forsyth word: string; 344*37da2899SCharles.Forsyth si, so: string; 345*37da2899SCharles.Forsyth append := 0; 346*37da2899SCharles.Forsyth 347*37da2899SCharles.Forsythgather: 348*37da2899SCharles.Forsyth do { 349*37da2899SCharles.Forsyth word = hd words; 350*37da2899SCharles.Forsyth 351*37da2899SCharles.Forsyth case word { 352*37da2899SCharles.Forsyth ">" or ">>" => 353*37da2899SCharles.Forsyth if(so != nil) 354*37da2899SCharles.Forsyth return (nil, nil); 355*37da2899SCharles.Forsyth 356*37da2899SCharles.Forsyth words = tl words; 357*37da2899SCharles.Forsyth 358*37da2899SCharles.Forsyth if(words == nil) 359*37da2899SCharles.Forsyth return (nil, nil); 360*37da2899SCharles.Forsyth 361*37da2899SCharles.Forsyth so = hd words; 362*37da2899SCharles.Forsyth if(len so>0 && so[0]==Quoted) 363*37da2899SCharles.Forsyth so = so[1:]; 364*37da2899SCharles.Forsyth if(word == ">>") 365*37da2899SCharles.Forsyth append = 1; 366*37da2899SCharles.Forsyth "<" => 367*37da2899SCharles.Forsyth if(si != nil) 368*37da2899SCharles.Forsyth return (nil, nil); 369*37da2899SCharles.Forsyth 370*37da2899SCharles.Forsyth words = tl words; 371*37da2899SCharles.Forsyth 372*37da2899SCharles.Forsyth if(words == nil) 373*37da2899SCharles.Forsyth return (nil, nil); 374*37da2899SCharles.Forsyth 375*37da2899SCharles.Forsyth si = hd words; 376*37da2899SCharles.Forsyth if(len si>0 && si[0]==Quoted) 377*37da2899SCharles.Forsyth si = si[1:]; 378*37da2899SCharles.Forsyth "|" or ";" or "&" => 379*37da2899SCharles.Forsyth break gather; 380*37da2899SCharles.Forsyth * => 381*37da2899SCharles.Forsyth files := doexpand(word); 382*37da2899SCharles.Forsyth while(files != nil){ 383*37da2899SCharles.Forsyth args = hd files :: args; 384*37da2899SCharles.Forsyth files = tl files; 385*37da2899SCharles.Forsyth } 386*37da2899SCharles.Forsyth } 387*37da2899SCharles.Forsyth 388*37da2899SCharles.Forsyth words = tl words; 389*37da2899SCharles.Forsyth } while (words != nil); 390*37da2899SCharles.Forsyth 391*37da2899SCharles.Forsyth return (ref Command(rev(args), si, so, append), words); 392*37da2899SCharles.Forsyth} 393*37da2899SCharles.Forsyth 394*37da2899SCharles.Forsythdoexpand(file: string): list of string 395*37da2899SCharles.Forsyth{ 396*37da2899SCharles.Forsyth if(file == nil) 397*37da2899SCharles.Forsyth return file :: nil; 398*37da2899SCharles.Forsyth if(len file>0 && file[0]==Quoted) 399*37da2899SCharles.Forsyth return file[1:] :: nil; 400*37da2899SCharles.Forsyth if (nofilepat) 401*37da2899SCharles.Forsyth return file :: nil; 402*37da2899SCharles.Forsyth for(i:=0; i<len file; i++) 403*37da2899SCharles.Forsyth if(file[i]=='*' || file[i]=='[' || file[i]=='?'){ 404*37da2899SCharles.Forsyth if(filepat == nil) { 405*37da2899SCharles.Forsyth if ((filepat = load Filepat Filepat->PATH) == nil) { 406*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: warning: cannot load %s: %r\n", 407*37da2899SCharles.Forsyth Filepat->PATH); 408*37da2899SCharles.Forsyth nofilepat = 1; 409*37da2899SCharles.Forsyth return file :: nil; 410*37da2899SCharles.Forsyth } 411*37da2899SCharles.Forsyth } 412*37da2899SCharles.Forsyth files := filepat->expand(file); 413*37da2899SCharles.Forsyth if(files != nil) 414*37da2899SCharles.Forsyth return files; 415*37da2899SCharles.Forsyth break; 416*37da2899SCharles.Forsyth } 417*37da2899SCharles.Forsyth return file :: nil; 418*37da2899SCharles.Forsyth} 419*37da2899SCharles.Forsyth 420*37da2899SCharles.Forsythrevc(arg: list of ref Command): list of ref Command 421*37da2899SCharles.Forsyth{ 422*37da2899SCharles.Forsyth ret: list of ref Command; 423*37da2899SCharles.Forsyth while(arg != nil) { 424*37da2899SCharles.Forsyth ret = hd arg :: ret; 425*37da2899SCharles.Forsyth arg = tl arg; 426*37da2899SCharles.Forsyth } 427*37da2899SCharles.Forsyth return ret; 428*37da2899SCharles.Forsyth} 429*37da2899SCharles.Forsyth 430*37da2899SCharles.Forsythgetpipe(words: list of string): (ref Pipeline, list of string) 431*37da2899SCharles.Forsyth{ 432*37da2899SCharles.Forsyth cmds: list of ref Command; 433*37da2899SCharles.Forsyth cur: ref Command; 434*37da2899SCharles.Forsyth word: string; 435*37da2899SCharles.Forsyth 436*37da2899SCharles.Forsyth term := Seq; 437*37da2899SCharles.Forsythgather: 438*37da2899SCharles.Forsyth while(words != nil) { 439*37da2899SCharles.Forsyth word = hd words; 440*37da2899SCharles.Forsyth 441*37da2899SCharles.Forsyth if(word == "|") 442*37da2899SCharles.Forsyth return (nil, nil); 443*37da2899SCharles.Forsyth 444*37da2899SCharles.Forsyth (cur, words) = getcommand(words); 445*37da2899SCharles.Forsyth 446*37da2899SCharles.Forsyth if(cur == nil) 447*37da2899SCharles.Forsyth return (nil, nil); 448*37da2899SCharles.Forsyth 449*37da2899SCharles.Forsyth cmds = cur :: cmds; 450*37da2899SCharles.Forsyth 451*37da2899SCharles.Forsyth if(words == nil) 452*37da2899SCharles.Forsyth break gather; 453*37da2899SCharles.Forsyth 454*37da2899SCharles.Forsyth word = hd words; 455*37da2899SCharles.Forsyth words = tl words; 456*37da2899SCharles.Forsyth 457*37da2899SCharles.Forsyth case word { 458*37da2899SCharles.Forsyth ";" => 459*37da2899SCharles.Forsyth break gather; 460*37da2899SCharles.Forsyth "&" => 461*37da2899SCharles.Forsyth term = Async; 462*37da2899SCharles.Forsyth break gather; 463*37da2899SCharles.Forsyth "|" => 464*37da2899SCharles.Forsyth continue gather; 465*37da2899SCharles.Forsyth } 466*37da2899SCharles.Forsyth return (nil, nil); 467*37da2899SCharles.Forsyth } 468*37da2899SCharles.Forsyth 469*37da2899SCharles.Forsyth if(word == "|") 470*37da2899SCharles.Forsyth return (nil, nil); 471*37da2899SCharles.Forsyth 472*37da2899SCharles.Forsyth return (ref Pipeline(revc(cmds), term), words); 473*37da2899SCharles.Forsyth} 474*37da2899SCharles.Forsyth 475*37da2899SCharles.Forsythrevp(arg: list of ref Pipeline): list of ref Pipeline 476*37da2899SCharles.Forsyth{ 477*37da2899SCharles.Forsyth ret: list of ref Pipeline; 478*37da2899SCharles.Forsyth 479*37da2899SCharles.Forsyth while(arg != nil) { 480*37da2899SCharles.Forsyth ret = hd arg :: ret; 481*37da2899SCharles.Forsyth arg = tl arg; 482*37da2899SCharles.Forsyth } 483*37da2899SCharles.Forsyth return ret; 484*37da2899SCharles.Forsyth} 485*37da2899SCharles.Forsyth 486*37da2899SCharles.Forsythparseit(words: list of string): list of ref Pipeline 487*37da2899SCharles.Forsyth{ 488*37da2899SCharles.Forsyth ret: list of ref Pipeline; 489*37da2899SCharles.Forsyth cur: ref Pipeline; 490*37da2899SCharles.Forsyth 491*37da2899SCharles.Forsyth while(words != nil) { 492*37da2899SCharles.Forsyth (cur, words) = getpipe(words); 493*37da2899SCharles.Forsyth if(cur == nil){ 494*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: syntax error\n"); 495*37da2899SCharles.Forsyth return nil; 496*37da2899SCharles.Forsyth } 497*37da2899SCharles.Forsyth ret = cur :: ret; 498*37da2899SCharles.Forsyth } 499*37da2899SCharles.Forsyth return revp(ret); 500*37da2899SCharles.Forsyth} 501*37da2899SCharles.Forsyth 502*37da2899SCharles.Forsyth# Runner. 503*37da2899SCharles.Forsyth 504*37da2899SCharles.Forsythrunpipeline(ctx: ref Context, pipeline: ref Pipeline) 505*37da2899SCharles.Forsyth{ 506*37da2899SCharles.Forsyth if(pipeline.term == Async) 507*37da2899SCharles.Forsyth sys->pctl(sys->NEWPGRP, nil); 508*37da2899SCharles.Forsyth pid := startpipeline(ctx, pipeline); 509*37da2899SCharles.Forsyth if(pid < 0) 510*37da2899SCharles.Forsyth return; 511*37da2899SCharles.Forsyth if(pipeline.term == Seq) 512*37da2899SCharles.Forsyth waitfor(pid); 513*37da2899SCharles.Forsyth} 514*37da2899SCharles.Forsyth 515*37da2899SCharles.Forsythstartpipeline(ctx: ref Context, pipeline: ref Pipeline): int 516*37da2899SCharles.Forsyth{ 517*37da2899SCharles.Forsyth pid := 0; 518*37da2899SCharles.Forsyth cmds := pipeline.cmds; 519*37da2899SCharles.Forsyth first := 1; 520*37da2899SCharles.Forsyth inpipe, outpipe: ref Sys->FD; 521*37da2899SCharles.Forsyth while(cmds != nil) { 522*37da2899SCharles.Forsyth last := tl cmds == nil; 523*37da2899SCharles.Forsyth cmd := hd cmds; 524*37da2899SCharles.Forsyth 525*37da2899SCharles.Forsyth infd: ref Sys->FD; 526*37da2899SCharles.Forsyth if(!first) 527*37da2899SCharles.Forsyth infd = inpipe; 528*37da2899SCharles.Forsyth else if(cmd.inf != nil){ 529*37da2899SCharles.Forsyth infd = sys->open(cmd.inf, Sys->OREAD); 530*37da2899SCharles.Forsyth if(infd == nil){ 531*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: can't open %s: %r\n", cmd.inf); 532*37da2899SCharles.Forsyth return -1; 533*37da2899SCharles.Forsyth } 534*37da2899SCharles.Forsyth } 535*37da2899SCharles.Forsyth 536*37da2899SCharles.Forsyth outfd: ref Sys->FD; 537*37da2899SCharles.Forsyth if(!last){ 538*37da2899SCharles.Forsyth fds := array[2] of ref Sys->FD; 539*37da2899SCharles.Forsyth if(sys->pipe(fds) < 0){ 540*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: can't make pipe: %r\n"); 541*37da2899SCharles.Forsyth return -1; 542*37da2899SCharles.Forsyth } 543*37da2899SCharles.Forsyth outpipe = fds[0]; 544*37da2899SCharles.Forsyth outfd = fds[1]; 545*37da2899SCharles.Forsyth fds = nil; 546*37da2899SCharles.Forsyth }else if(cmd.outf != nil){ 547*37da2899SCharles.Forsyth if(cmd.append){ 548*37da2899SCharles.Forsyth outfd = sys->open(cmd.outf, Sys->OWRITE); 549*37da2899SCharles.Forsyth if(outfd != nil) 550*37da2899SCharles.Forsyth sys->seek(outfd, big 0, Sys->SEEKEND); 551*37da2899SCharles.Forsyth } 552*37da2899SCharles.Forsyth if(outfd == nil) 553*37da2899SCharles.Forsyth outfd = sys->create(cmd.outf, Sys->OWRITE, 8r666); 554*37da2899SCharles.Forsyth if(outfd == nil){ 555*37da2899SCharles.Forsyth sys->fprint(stderr, "sh: can't open %s: %r\n", cmd.outf); 556*37da2899SCharles.Forsyth return -1; 557*37da2899SCharles.Forsyth } 558*37da2899SCharles.Forsyth } 559*37da2899SCharles.Forsyth 560*37da2899SCharles.Forsyth rpid := chan of int; 561*37da2899SCharles.Forsyth spawn mkprog(ctx, cmd.args, infd, outfd, rpid); 562*37da2899SCharles.Forsyth pid = <-rpid; 563*37da2899SCharles.Forsyth infd = nil; 564*37da2899SCharles.Forsyth outfd = nil; 565*37da2899SCharles.Forsyth 566*37da2899SCharles.Forsyth inpipe = outpipe; 567*37da2899SCharles.Forsyth outpipe = nil; 568*37da2899SCharles.Forsyth 569*37da2899SCharles.Forsyth first = 0; 570*37da2899SCharles.Forsyth cmds = tl cmds; 571*37da2899SCharles.Forsyth } 572*37da2899SCharles.Forsyth return pid; 573*37da2899SCharles.Forsyth} 574*37da2899SCharles.Forsyth 575*37da2899SCharles.Forsythrunit(ctx: ref Context, pipes: list of ref Pipeline) 576*37da2899SCharles.Forsyth{ 577*37da2899SCharles.Forsyth while(pipes != nil) { 578*37da2899SCharles.Forsyth pipeline := hd pipes; 579*37da2899SCharles.Forsyth pipes = tl pipes; 580*37da2899SCharles.Forsyth if(pipeline.term == Seq) 581*37da2899SCharles.Forsyth runpipeline(ctx, pipeline); 582*37da2899SCharles.Forsyth else 583*37da2899SCharles.Forsyth spawn runpipeline(ctx, pipeline); 584*37da2899SCharles.Forsyth } 585*37da2899SCharles.Forsyth} 586*37da2899SCharles.Forsyth 587*37da2899SCharles.Forsythstrchr(s: string, c: int): int 588*37da2899SCharles.Forsyth{ 589*37da2899SCharles.Forsyth ln := len s; 590*37da2899SCharles.Forsyth for (i := 0; i < ln; i++) 591*37da2899SCharles.Forsyth if (s[i] == c) 592*37da2899SCharles.Forsyth return i; 593*37da2899SCharles.Forsyth return -1; 594*37da2899SCharles.Forsyth} 595*37da2899SCharles.Forsyth 596*37da2899SCharles.Forsyth# PROFILE: con "/lib/profile"; 597*37da2899SCharles.ForsythPROFILE: con "/lib/infernoinit"; 598*37da2899SCharles.Forsyth 599*37da2899SCharles.Forsythstartup(ctxt: ref Context) 600*37da2899SCharles.Forsyth{ 601*37da2899SCharles.Forsyth if (env == nil) 602*37da2899SCharles.Forsyth return; 603*37da2899SCharles.Forsyth # if (env->getenv("home") != nil) 604*37da2899SCharles.Forsyth # return; 605*37da2899SCharles.Forsyth home := gethome(); 606*37da2899SCharles.Forsyth env->setenv("home", home); 607*37da2899SCharles.Forsyth escript(ctxt, PROFILE); 608*37da2899SCharles.Forsyth escript(ctxt, home + PROFILE); 609*37da2899SCharles.Forsyth} 610*37da2899SCharles.Forsyth 611*37da2899SCharles.Forsythescript(ctxt: ref Context, file: string) 612*37da2899SCharles.Forsyth{ 613*37da2899SCharles.Forsyth fd := sys->open(file, Sys->OREAD); 614*37da2899SCharles.Forsyth if (fd != nil) 615*37da2899SCharles.Forsyth script(ctxt, file); 616*37da2899SCharles.Forsyth} 617*37da2899SCharles.Forsyth 618*37da2899SCharles.Forsythgethome(): string 619*37da2899SCharles.Forsyth{ 620*37da2899SCharles.Forsyth fd := sys->open("/dev/user", sys->OREAD); 621*37da2899SCharles.Forsyth if(fd == nil) 622*37da2899SCharles.Forsyth return "/"; 623*37da2899SCharles.Forsyth buf := array[128] of byte; 624*37da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 625*37da2899SCharles.Forsyth if(n < 0) 626*37da2899SCharles.Forsyth return "/"; 627*37da2899SCharles.Forsyth return "/usr/" + string buf[0:n]; 628*37da2899SCharles.Forsyth} 629