137da2899SCharles.Forsythimplement Shellbuiltin; 237da2899SCharles.Forsyth 337da2899SCharles.Forsythinclude "sys.m"; 437da2899SCharles.Forsyth sys: Sys; 537da2899SCharles.Forsythinclude "draw.m"; 637da2899SCharles.Forsythinclude "sh.m"; 737da2899SCharles.Forsyth sh: Sh; 837da2899SCharles.Forsyth Listnode, Context: import sh; 937da2899SCharles.Forsyth myself: Shellbuiltin; 1037da2899SCharles.Forsythinclude "filepat.m"; 1137da2899SCharles.Forsyth filepat: Filepat; 1237da2899SCharles.Forsythinclude "bufio.m"; 1337da2899SCharles.Forsyth bufio: Bufio; 1437da2899SCharles.Forsyth Iobuf: import bufio; 1537da2899SCharles.Forsyth 1637da2899SCharles.Forsythbuiltinnames := array[] of { 1737da2899SCharles.Forsyth "if", "while", "~", "!", "apply", "for", 1837da2899SCharles.Forsyth "status", "pctl", "fn", "subfn", "and", "or", 1937da2899SCharles.Forsyth "raise", "rescue", "flag", "getlines", "no", 2037da2899SCharles.Forsyth}; 2137da2899SCharles.Forsyth 2237da2899SCharles.Forsythsbuiltinnames := array[] of { 2337da2899SCharles.Forsyth "hd", "tl", "index", "split", "join", "pid", "parse", "env", "pipe", 2437da2899SCharles.Forsyth}; 2537da2899SCharles.Forsyth 2637da2899SCharles.Forsythinitbuiltin(ctxt: ref Context, shmod: Sh): string 2737da2899SCharles.Forsyth{ 2837da2899SCharles.Forsyth sys = load Sys Sys->PATH; 2937da2899SCharles.Forsyth sh = shmod; 3037da2899SCharles.Forsyth myself = load Shellbuiltin "$self"; 3137da2899SCharles.Forsyth if (myself == nil) 3237da2899SCharles.Forsyth ctxt.fail("bad module", sys->sprint("std: cannot load self: %r")); 3337da2899SCharles.Forsyth filepat = load Filepat Filepat->PATH; 3437da2899SCharles.Forsyth if (filepat == nil) 3537da2899SCharles.Forsyth ctxt.fail("bad module", 3637da2899SCharles.Forsyth sys->sprint("std: cannot load: %s: %r", Filepat->PATH)); 3737da2899SCharles.Forsyth bufio = load Bufio Bufio->PATH; 3837da2899SCharles.Forsyth if (bufio == nil) 3937da2899SCharles.Forsyth ctxt.fail("bad module", 4037da2899SCharles.Forsyth sys->sprint("std: cannot load: %s: %r", Bufio->PATH)); 4137da2899SCharles.Forsyth names := builtinnames; 4237da2899SCharles.Forsyth for (i := 0; i < len names; i++) 4337da2899SCharles.Forsyth ctxt.addbuiltin(names[i], myself); 4437da2899SCharles.Forsyth names = sbuiltinnames; 4537da2899SCharles.Forsyth for (i = 0; i < len names; i++) 4637da2899SCharles.Forsyth ctxt.addsbuiltin(names[i], myself); 4737da2899SCharles.Forsyth env := ctxt.envlist(); 4837da2899SCharles.Forsyth for (; env != nil; env = tl env) { 4937da2899SCharles.Forsyth (name, val) := hd env; 5037da2899SCharles.Forsyth if (len name > 3 && name[0:3] == "fn-") 5137da2899SCharles.Forsyth fndef(ctxt, name[3:], val, 0); 5237da2899SCharles.Forsyth if (len name > 4 && name[0:4] == "sfn-") 5337da2899SCharles.Forsyth fndef(ctxt, name[4:], val, 1); 5437da2899SCharles.Forsyth } 5537da2899SCharles.Forsyth return nil; 5637da2899SCharles.Forsyth} 5737da2899SCharles.Forsyth 5837da2899SCharles.Forsythwhatis(c: ref Sh->Context, sh: Sh, name: string, wtype: int): string 5937da2899SCharles.Forsyth{ 6037da2899SCharles.Forsyth ename, fname: string; 6137da2899SCharles.Forsyth case wtype { 6237da2899SCharles.Forsyth BUILTIN => 6337da2899SCharles.Forsyth (ename, fname) = ("fn-", "fn "); 6437da2899SCharles.Forsyth SBUILTIN => 6537da2899SCharles.Forsyth (ename, fname) = ("sfn-", "subfn "); 6637da2899SCharles.Forsyth OTHER => 6737da2899SCharles.Forsyth return nil; 6837da2899SCharles.Forsyth } 6937da2899SCharles.Forsyth 7037da2899SCharles.Forsyth val := c.get(ename + name); 7137da2899SCharles.Forsyth if (val != nil) 7237da2899SCharles.Forsyth return fname + name + " " + sh->quoted(hd val :: nil, 0); 7337da2899SCharles.Forsyth return nil; 7437da2899SCharles.Forsyth} 7537da2899SCharles.Forsyth 7637da2899SCharles.Forsythgetself(): Shellbuiltin 7737da2899SCharles.Forsyth{ 7837da2899SCharles.Forsyth return myself; 7937da2899SCharles.Forsyth} 8037da2899SCharles.Forsyth 8137da2899SCharles.Forsythrunbuiltin(c: ref Sh->Context, nil: Sh, 8237da2899SCharles.Forsyth cmd: list of ref Sh->Listnode, last: int): string 8337da2899SCharles.Forsyth{ 8437da2899SCharles.Forsyth status: string; 8537da2899SCharles.Forsyth name := (hd cmd).word; 8637da2899SCharles.Forsyth val := c.get("fn-" + name); 8737da2899SCharles.Forsyth if (val != nil) 8837da2899SCharles.Forsyth return c.run(hd val :: tl cmd, last); 8937da2899SCharles.Forsyth case name { 9037da2899SCharles.Forsyth "if" => status = builtin_if(c, cmd, last); 9137da2899SCharles.Forsyth "while" => status = builtin_while(c, cmd, last); 9237da2899SCharles.Forsyth "and" => status = builtin_and(c, cmd, last); 9337da2899SCharles.Forsyth "apply" => status = builtin_apply(c, cmd, last); 9437da2899SCharles.Forsyth "for" => status = builtin_for(c, cmd, last); 9537da2899SCharles.Forsyth "or" => status = builtin_or(c, cmd, last); 9637da2899SCharles.Forsyth "!" => status = builtin_not(c, cmd, last); 9737da2899SCharles.Forsyth "fn" => status = builtin_fn(c, cmd, last, 0); 9837da2899SCharles.Forsyth "subfn" => status = builtin_fn(c, cmd, last, 1); 9937da2899SCharles.Forsyth "~" => status = builtin_twiddle(c, cmd, last); 10037da2899SCharles.Forsyth "status" => status = builtin_status(c, cmd, last); 10137da2899SCharles.Forsyth "pctl" => status = builtin_pctl(c, cmd, last); 10237da2899SCharles.Forsyth "raise" => status = builtin_raise(c, cmd, last); 10337da2899SCharles.Forsyth "rescue" => status = builtin_rescue(c, cmd, last); 10437da2899SCharles.Forsyth "flag" => status = builtin_flag(c, cmd, last); 10537da2899SCharles.Forsyth "getlines" => status = builtin_getlines(c, cmd, last); 10637da2899SCharles.Forsyth "no" => status = builtin_no(c, cmd, last); 10737da2899SCharles.Forsyth } 10837da2899SCharles.Forsyth return status; 10937da2899SCharles.Forsyth} 11037da2899SCharles.Forsyth 11137da2899SCharles.Forsythrunsbuiltin(c: ref Sh->Context, nil: Sh, 11237da2899SCharles.Forsyth cmd: list of ref Sh->Listnode): list of ref Listnode 11337da2899SCharles.Forsyth{ 11437da2899SCharles.Forsyth name := (hd cmd).word; 11537da2899SCharles.Forsyth val := c.get("sfn-" + name); 11637da2899SCharles.Forsyth if (val != nil) 11737da2899SCharles.Forsyth return runsubfn(c, val, tl cmd); 11837da2899SCharles.Forsyth case name { 11937da2899SCharles.Forsyth "pid" => 12037da2899SCharles.Forsyth return ref Listnode(nil, string sys->pctl(0, nil)) :: nil; 12137da2899SCharles.Forsyth "hd" => 12237da2899SCharles.Forsyth if (tl cmd == nil) 12337da2899SCharles.Forsyth return nil; 12437da2899SCharles.Forsyth return hd tl cmd :: nil; 12537da2899SCharles.Forsyth "tl" => 12637da2899SCharles.Forsyth if (tl cmd == nil) 12737da2899SCharles.Forsyth return nil; 12837da2899SCharles.Forsyth return tl tl cmd; 12937da2899SCharles.Forsyth "index" => 13037da2899SCharles.Forsyth return sbuiltin_index(c, cmd); 13137da2899SCharles.Forsyth "split" => 13237da2899SCharles.Forsyth return sbuiltin_split(c, cmd); 13337da2899SCharles.Forsyth "join" => 13437da2899SCharles.Forsyth return sbuiltin_join(c, cmd); 13537da2899SCharles.Forsyth "parse" => 13637da2899SCharles.Forsyth return sbuiltin_parse(c, cmd); 13737da2899SCharles.Forsyth "env" => 13837da2899SCharles.Forsyth return sbuiltin_env(c, cmd); 13937da2899SCharles.Forsyth "pipe" => 14037da2899SCharles.Forsyth return sbuiltin_pipe(c, cmd); 14137da2899SCharles.Forsyth } 14237da2899SCharles.Forsyth return nil; 14337da2899SCharles.Forsyth} 14437da2899SCharles.Forsyth 14537da2899SCharles.Forsythrunsubfn(ctxt: ref Context, body, args: list of ref Listnode): list of ref Listnode 14637da2899SCharles.Forsyth{ 14737da2899SCharles.Forsyth if (body == nil) 14837da2899SCharles.Forsyth return nil; 14937da2899SCharles.Forsyth ctxt.push(); 15037da2899SCharles.Forsyth { 15137da2899SCharles.Forsyth ctxt.setlocal("result", nil); 15237da2899SCharles.Forsyth ctxt.run(hd body :: args, 0); 15337da2899SCharles.Forsyth result := ctxt.get("result"); 15437da2899SCharles.Forsyth ctxt.pop(); 15537da2899SCharles.Forsyth return result; 15637da2899SCharles.Forsyth } exception e { 15737da2899SCharles.Forsyth "fail:*" => 15837da2899SCharles.Forsyth ctxt.pop(); 15937da2899SCharles.Forsyth raise e; 16037da2899SCharles.Forsyth } 16137da2899SCharles.Forsyth} 16237da2899SCharles.Forsyth 16337da2899SCharles.Forsythsbuiltin_index(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode 16437da2899SCharles.Forsyth{ 16537da2899SCharles.Forsyth if (len val < 2 || (hd tl val).word == nil) 16637da2899SCharles.Forsyth builtinusage(ctxt, "index num list"); 16737da2899SCharles.Forsyth k := int (hd tl val).word - 1; 16837da2899SCharles.Forsyth val = tl tl val; 16937da2899SCharles.Forsyth for (; k > 0 && val != nil; k--) 17037da2899SCharles.Forsyth val = tl val; 17137da2899SCharles.Forsyth if (val != nil) 17237da2899SCharles.Forsyth val = hd val :: nil; 17337da2899SCharles.Forsyth return val; 17437da2899SCharles.Forsyth} 17537da2899SCharles.Forsyth 17637da2899SCharles.Forsyth# return a parsed version of a string, raising a "parse error" exception if 17737da2899SCharles.Forsyth# it fails. the string must be a braced command block. 17837da2899SCharles.Forsythsbuiltin_parse(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode 17937da2899SCharles.Forsyth{ 18037da2899SCharles.Forsyth if (len args != 2) 18137da2899SCharles.Forsyth builtinusage(ctxt, "parse arg"); 18237da2899SCharles.Forsyth args = tl args; 18337da2899SCharles.Forsyth if ((hd args).cmd != nil) 18437da2899SCharles.Forsyth return ref Listnode((hd args).cmd, nil) :: nil; 18537da2899SCharles.Forsyth w := (hd args).word; 18637da2899SCharles.Forsyth if (w == nil || w[0] != '{') #} 18737da2899SCharles.Forsyth ctxt.fail("parse error", "parse: argument must be a braced block"); 18837da2899SCharles.Forsyth (n, err) := sh->parse(w); 18937da2899SCharles.Forsyth if (err != nil) 19037da2899SCharles.Forsyth ctxt.fail("parse error", "parse: " + err); 19137da2899SCharles.Forsyth return ref Listnode(n, nil) :: nil; 19237da2899SCharles.Forsyth} 19337da2899SCharles.Forsyth 19437da2899SCharles.Forsythsbuiltin_env(ctxt: ref Context, nil: list of ref Listnode): list of ref Listnode 19537da2899SCharles.Forsyth{ 19637da2899SCharles.Forsyth vl: list of string; 19737da2899SCharles.Forsyth for (e := ctxt.envlist(); e != nil; e = tl e) { 19837da2899SCharles.Forsyth (n, v) := hd e; 19937da2899SCharles.Forsyth if (v != nil) # XXX this is debatable... someone might want to see null local vars. 20037da2899SCharles.Forsyth vl = n :: vl; 20137da2899SCharles.Forsyth } 20237da2899SCharles.Forsyth return sh->stringlist2list(vl); 20337da2899SCharles.Forsyth} 20437da2899SCharles.Forsyth 20537da2899SCharles.Forsythword(n: ref Listnode): string 20637da2899SCharles.Forsyth{ 20737da2899SCharles.Forsyth if (n.word != nil) 20837da2899SCharles.Forsyth return n.word; 20937da2899SCharles.Forsyth if (n.cmd != nil) 21037da2899SCharles.Forsyth n.word = sh->cmd2string(n.cmd); 21137da2899SCharles.Forsyth return n.word; 21237da2899SCharles.Forsyth} 21337da2899SCharles.Forsyth 21437da2899SCharles.Forsyth# usage: split [separators] value 21537da2899SCharles.Forsythsbuiltin_split(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode 21637da2899SCharles.Forsyth{ 21737da2899SCharles.Forsyth n := len args; 21837da2899SCharles.Forsyth if (n < 2 || n > 3) 21937da2899SCharles.Forsyth builtinusage(ctxt, "split [separators] value"); 22037da2899SCharles.Forsyth seps: string; 22137da2899SCharles.Forsyth if (n == 2) { 22237da2899SCharles.Forsyth ifs := ctxt.get("ifs"); 22337da2899SCharles.Forsyth if (ifs == nil) 22437da2899SCharles.Forsyth ctxt.fail("usage", "split: $ifs not set"); 22537da2899SCharles.Forsyth seps = word(hd ifs); 22637da2899SCharles.Forsyth } else { 22737da2899SCharles.Forsyth args = tl args; 22837da2899SCharles.Forsyth seps = word(hd args); 22937da2899SCharles.Forsyth } 23037da2899SCharles.Forsyth (nil, toks) := sys->tokenize(word(hd tl args), seps); 23137da2899SCharles.Forsyth return sh->stringlist2list(toks); 23237da2899SCharles.Forsyth} 23337da2899SCharles.Forsyth 23437da2899SCharles.Forsythsbuiltin_join(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode 23537da2899SCharles.Forsyth{ 23637da2899SCharles.Forsyth args = tl args; 23737da2899SCharles.Forsyth if (args == nil) 23837da2899SCharles.Forsyth builtinusage(ctxt, "join separator [arg...]"); 23937da2899SCharles.Forsyth seps := word(hd args); 24037da2899SCharles.Forsyth if (tl args == nil) 24137da2899SCharles.Forsyth return ref Listnode(nil, nil) :: nil; 24237da2899SCharles.Forsyth s := word(hd tl args); 24337da2899SCharles.Forsyth for (args = tl tl args; args != nil; args = tl args) 24437da2899SCharles.Forsyth s += seps + word(hd args); 24537da2899SCharles.Forsyth return ref Listnode(nil, s) :: nil; 24637da2899SCharles.Forsyth} 24737da2899SCharles.Forsyth 24837da2899SCharles.Forsythbuiltin_fn(ctxt: ref Context, args: list of ref Listnode, nil: int, issub: int): string 24937da2899SCharles.Forsyth{ 25037da2899SCharles.Forsyth n := len args; 25137da2899SCharles.Forsyth title := (hd args).word; 25237da2899SCharles.Forsyth if (n < 2) 25337da2899SCharles.Forsyth builtinusage(ctxt, title + " [name...] [{body}]"); 25437da2899SCharles.Forsyth for (al := tl args; tl al != nil; al = tl al) 25537da2899SCharles.Forsyth if ((hd al).cmd != nil) 25637da2899SCharles.Forsyth builtinusage(ctxt, title + " [name...] [{body}]"); 25737da2899SCharles.Forsyth if ((hd al).cmd != nil) { 25837da2899SCharles.Forsyth cmd := hd al :: nil; 25937da2899SCharles.Forsyth for (al = tl args; tl al != nil; al = tl al) 26037da2899SCharles.Forsyth fndef(ctxt, (hd al).word, cmd, issub); 26137da2899SCharles.Forsyth } else { 26237da2899SCharles.Forsyth for (al = tl args; al != nil; al = tl al) 26337da2899SCharles.Forsyth fnundef(ctxt, (hd al).word, issub); 26437da2899SCharles.Forsyth } 26537da2899SCharles.Forsyth return nil; 26637da2899SCharles.Forsyth} 26737da2899SCharles.Forsyth 26837da2899SCharles.Forsythfndef(ctxt: ref Context, name: string, cmd: list of ref Listnode, issub: int) 26937da2899SCharles.Forsyth{ 27037da2899SCharles.Forsyth if (cmd == nil) 27137da2899SCharles.Forsyth return; 27237da2899SCharles.Forsyth if (issub) { 27337da2899SCharles.Forsyth ctxt.set("sfn-" + name, cmd); 27437da2899SCharles.Forsyth ctxt.addsbuiltin(name, myself); 27537da2899SCharles.Forsyth } else { 27637da2899SCharles.Forsyth ctxt.set("fn-" + name, cmd); 27737da2899SCharles.Forsyth ctxt.addbuiltin(name, myself); 27837da2899SCharles.Forsyth } 27937da2899SCharles.Forsyth} 28037da2899SCharles.Forsyth 28137da2899SCharles.Forsythfnundef(ctxt: ref Context, name: string, issub: int) 28237da2899SCharles.Forsyth{ 28337da2899SCharles.Forsyth if (issub) { 28437da2899SCharles.Forsyth ctxt.set("sfn-" + name, nil); 28537da2899SCharles.Forsyth ctxt.removesbuiltin(name, myself); 28637da2899SCharles.Forsyth } else { 28737da2899SCharles.Forsyth ctxt.set("fn-" + name, nil); 28837da2899SCharles.Forsyth ctxt.removebuiltin(name, myself); 28937da2899SCharles.Forsyth } 29037da2899SCharles.Forsyth} 29137da2899SCharles.Forsyth 29237da2899SCharles.Forsythbuiltin_flag(ctxt: ref Context, args: list of ref Listnode, nil: int): string 29337da2899SCharles.Forsyth{ 29437da2899SCharles.Forsyth n := len args; 29537da2899SCharles.Forsyth if (n < 2 || n > 3 || len (hd tl args).word != 1) 29637da2899SCharles.Forsyth builtinusage(ctxt, "flag [vxei] [+-]"); 29737da2899SCharles.Forsyth flag := (hd tl args).word[0]; 29837da2899SCharles.Forsyth p := ""; 29937da2899SCharles.Forsyth if (n == 3) 30037da2899SCharles.Forsyth p = (hd tl tl args).word; 30137da2899SCharles.Forsyth mask := 0; 30237da2899SCharles.Forsyth case flag { 30337da2899SCharles.Forsyth 'v' => mask = Context.VERBOSE; 30437da2899SCharles.Forsyth 'x' => mask = Context.EXECPRINT; 30537da2899SCharles.Forsyth 'e' => mask = Context.ERROREXIT; 30637da2899SCharles.Forsyth 'i' => mask = Context.INTERACTIVE; 30737da2899SCharles.Forsyth * => builtinusage(ctxt, "flag [vxei] [+-]"); 30837da2899SCharles.Forsyth } 30937da2899SCharles.Forsyth case p { 31037da2899SCharles.Forsyth "" => if (ctxt.options() & mask) 31137da2899SCharles.Forsyth return nil; 31237da2899SCharles.Forsyth return "not set"; 31337da2899SCharles.Forsyth "-" => ctxt.setoptions(mask, 0); 31437da2899SCharles.Forsyth "+" => ctxt.setoptions(mask, 1); 31537da2899SCharles.Forsyth * => builtinusage(ctxt, "flag [vxei] [+-]"); 31637da2899SCharles.Forsyth } 31737da2899SCharles.Forsyth return nil; 31837da2899SCharles.Forsyth} 31937da2899SCharles.Forsyth 32037da2899SCharles.Forsythbuiltin_no(nil: ref Context, args: list of ref Listnode, nil: int): string 32137da2899SCharles.Forsyth{ 32237da2899SCharles.Forsyth if (tl args != nil) 32337da2899SCharles.Forsyth return "yes"; 32437da2899SCharles.Forsyth return nil; 32537da2899SCharles.Forsyth} 32637da2899SCharles.Forsyth 32737da2899SCharles.Forsythiscmd(n: ref Listnode): int 32837da2899SCharles.Forsyth{ 32937da2899SCharles.Forsyth return n.cmd != nil || (n.word != nil && n.word[0] == '{'); 33037da2899SCharles.Forsyth} 33137da2899SCharles.Forsyth 33237da2899SCharles.Forsythbuiltin_if(ctxt: ref Context, args: list of ref Listnode, nil: int): string 33337da2899SCharles.Forsyth{ 33437da2899SCharles.Forsyth args = tl args; 33537da2899SCharles.Forsyth nargs := len args; 33637da2899SCharles.Forsyth if (nargs < 2) 33737da2899SCharles.Forsyth builtinusage(ctxt, "if {cond} {action} [{cond} {action}]... [{elseaction}]"); 33837da2899SCharles.Forsyth 33937da2899SCharles.Forsyth status: string; 34037da2899SCharles.Forsyth dolstar := ctxt.get("*"); 34137da2899SCharles.Forsyth while (args != nil) { 34237da2899SCharles.Forsyth cmd: ref Listnode = nil; 34337da2899SCharles.Forsyth if (tl args == nil) { 34437da2899SCharles.Forsyth cmd = hd args; 34537da2899SCharles.Forsyth args = tl args; 34637da2899SCharles.Forsyth } else { 34737da2899SCharles.Forsyth if (!iscmd(hd args)) 34837da2899SCharles.Forsyth builtinusage(ctxt, "if [{cond} {action}]... [{elseaction}]"); 34937da2899SCharles.Forsyth 35037da2899SCharles.Forsyth status = ctxt.run(hd args :: dolstar, 0); 35137da2899SCharles.Forsyth if (status == nil) { 35237da2899SCharles.Forsyth cmd = hd tl args; 35337da2899SCharles.Forsyth args = nil; 35437da2899SCharles.Forsyth } else 35537da2899SCharles.Forsyth args = tl tl args; 35637da2899SCharles.Forsyth setstatus(ctxt, status); 35737da2899SCharles.Forsyth } 35837da2899SCharles.Forsyth if (cmd != nil) { 35937da2899SCharles.Forsyth if (!iscmd(cmd)) 36037da2899SCharles.Forsyth builtinusage(ctxt, "if [{cond} {action}]... [{elseaction}]"); 36137da2899SCharles.Forsyth 36237da2899SCharles.Forsyth status = ctxt.run(cmd :: dolstar, 0); 36337da2899SCharles.Forsyth } 36437da2899SCharles.Forsyth } 36537da2899SCharles.Forsyth return status; 36637da2899SCharles.Forsyth} 36737da2899SCharles.Forsyth 36837da2899SCharles.Forsythbuiltin_or(ctxt: ref Context, args: list of ref Listnode, nil: int): string 36937da2899SCharles.Forsyth{ 37037da2899SCharles.Forsyth s: string; 37137da2899SCharles.Forsyth dolstar := ctxt.get("*"); 37237da2899SCharles.Forsyth for (args = tl args; args != nil; args = tl args) { 37337da2899SCharles.Forsyth if (!iscmd(hd args)) 37437da2899SCharles.Forsyth builtinusage(ctxt, "or [{cmd} ...]"); 37537da2899SCharles.Forsyth if ((s = ctxt.run(hd args :: dolstar, 0)) == nil) 37637da2899SCharles.Forsyth return nil; 37737da2899SCharles.Forsyth else 37837da2899SCharles.Forsyth setstatus(ctxt, s); 37937da2899SCharles.Forsyth } 38037da2899SCharles.Forsyth return s; 38137da2899SCharles.Forsyth} 38237da2899SCharles.Forsyth 38337da2899SCharles.Forsythbuiltin_and(ctxt: ref Context, args: list of ref Listnode, nil: int): string 38437da2899SCharles.Forsyth{ 38537da2899SCharles.Forsyth dolstar := ctxt.get("*"); 38637da2899SCharles.Forsyth for (args = tl args; args != nil; args = tl args) { 38737da2899SCharles.Forsyth if (!iscmd(hd args)) 38837da2899SCharles.Forsyth builtinusage(ctxt, "and [{cmd} ...]"); 38937da2899SCharles.Forsyth if ((s := ctxt.run(hd args :: dolstar, 0)) != nil) 39037da2899SCharles.Forsyth return s; 39137da2899SCharles.Forsyth else 39237da2899SCharles.Forsyth setstatus(ctxt, nil); 39337da2899SCharles.Forsyth } 39437da2899SCharles.Forsyth return nil; 39537da2899SCharles.Forsyth} 39637da2899SCharles.Forsyth 39737da2899SCharles.Forsythbuiltin_while(ctxt: ref Context, args: list of ref Listnode, nil: int) : string 39837da2899SCharles.Forsyth{ 39937da2899SCharles.Forsyth args = tl args; 40037da2899SCharles.Forsyth if (len args != 2 || !iscmd(hd args) || !iscmd(hd tl args)) 40137da2899SCharles.Forsyth builtinusage(ctxt, "while {condition} {cmd}"); 40237da2899SCharles.Forsyth 40337da2899SCharles.Forsyth dolstar := ctxt.get("*"); 40437da2899SCharles.Forsyth cond := hd args :: dolstar; 40537da2899SCharles.Forsyth action := hd tl args :: dolstar; 40637da2899SCharles.Forsyth status := ""; 40737da2899SCharles.Forsyth 40837da2899SCharles.Forsyth for(;;){ 40937da2899SCharles.Forsyth { 41037da2899SCharles.Forsyth while (ctxt.run(cond, 0) == nil) 41137da2899SCharles.Forsyth status = setstatus(ctxt, ctxt.run(action, 0)); 41237da2899SCharles.Forsyth return status; 41337da2899SCharles.Forsyth } exception e{ 41437da2899SCharles.Forsyth "fail:*" => 41537da2899SCharles.Forsyth if (loopexcept(e) == BREAK) 41637da2899SCharles.Forsyth return status; 41737da2899SCharles.Forsyth } 41837da2899SCharles.Forsyth } 41937da2899SCharles.Forsyth} 42037da2899SCharles.Forsyth 42137da2899SCharles.Forsythbuiltin_getlines(ctxt: ref Context, argv: list of ref Listnode, nil: int) : string 42237da2899SCharles.Forsyth{ 42337da2899SCharles.Forsyth n := len argv; 42437da2899SCharles.Forsyth if (n < 2 || n > 3) 42537da2899SCharles.Forsyth builtinusage(ctxt, "getlines [separators] {cmd}"); 42637da2899SCharles.Forsyth argv = tl argv; 42737da2899SCharles.Forsyth seps := "\n"; 42837da2899SCharles.Forsyth if (n == 3) { 42937da2899SCharles.Forsyth seps = word(hd argv); 43037da2899SCharles.Forsyth argv = tl argv; 43137da2899SCharles.Forsyth } 43237da2899SCharles.Forsyth if (len seps == 0) 43337da2899SCharles.Forsyth builtinusage(ctxt, "getlines [separators] {cmd}"); 43437da2899SCharles.Forsyth if (!iscmd(hd argv)) 43537da2899SCharles.Forsyth builtinusage(ctxt, "getlines [separators] {cmd}"); 43637da2899SCharles.Forsyth cmd := hd argv :: ctxt.get("*"); 43737da2899SCharles.Forsyth stdin := bufio->fopen(sys->fildes(0), Sys->OREAD); 43837da2899SCharles.Forsyth if (stdin == nil) 43937da2899SCharles.Forsyth ctxt.fail("bad input", sys->sprint("getlines: cannot open stdin: %r")); 44037da2899SCharles.Forsyth status := ""; 44137da2899SCharles.Forsyth ctxt.push(); 44237da2899SCharles.Forsyth for(;;){ 44337da2899SCharles.Forsyth { 44437da2899SCharles.Forsyth for (;;) { 44537da2899SCharles.Forsyth s: string; 44637da2899SCharles.Forsyth if (len seps == 1) 44737da2899SCharles.Forsyth s = stdin.gets(seps[0]); 44837da2899SCharles.Forsyth else 44937da2899SCharles.Forsyth s = stdin.gett(seps); 45037da2899SCharles.Forsyth if (s == nil) 45137da2899SCharles.Forsyth break; 45237da2899SCharles.Forsyth # make sure we don't lose the last unterminated line 45337da2899SCharles.Forsyth lastc := s[len s - 1]; 45437da2899SCharles.Forsyth if (lastc == seps[0]) 45537da2899SCharles.Forsyth s = s[0:len s - 1]; 45637da2899SCharles.Forsyth else for (i := 1; i < len seps; i++) { 45737da2899SCharles.Forsyth if (lastc == seps[i]) { 45837da2899SCharles.Forsyth s = s[0:len s - 1]; 45937da2899SCharles.Forsyth break; 46037da2899SCharles.Forsyth } 46137da2899SCharles.Forsyth } 46237da2899SCharles.Forsyth ctxt.setlocal("line", ref Listnode(nil, s) :: nil); 46337da2899SCharles.Forsyth status = setstatus(ctxt, ctxt.run(cmd, 0)); 46437da2899SCharles.Forsyth } 46537da2899SCharles.Forsyth ctxt.pop(); 46637da2899SCharles.Forsyth return status; 46737da2899SCharles.Forsyth } exception e { 46837da2899SCharles.Forsyth "fail:*" => 46937da2899SCharles.Forsyth ctxt.pop(); 47037da2899SCharles.Forsyth if (loopexcept(e) == BREAK) 47137da2899SCharles.Forsyth return status; 47237da2899SCharles.Forsyth ctxt.push(); 47337da2899SCharles.Forsyth } 47437da2899SCharles.Forsyth } 47537da2899SCharles.Forsyth} 47637da2899SCharles.Forsyth 47737da2899SCharles.Forsyth# usage: raise [name] 47837da2899SCharles.Forsythbuiltin_raise(ctxt: ref Context, args: list of ref Listnode, nil: int) : string 47937da2899SCharles.Forsyth{ 48037da2899SCharles.Forsyth ename: ref Listnode; 48137da2899SCharles.Forsyth if (tl args == nil) { 48237da2899SCharles.Forsyth e := ctxt.get("exception"); 48337da2899SCharles.Forsyth if (e == nil) 48437da2899SCharles.Forsyth ctxt.fail("bad raise context", "raise: no exception found"); 48537da2899SCharles.Forsyth ename = (hd e); 48637da2899SCharles.Forsyth } else 48737da2899SCharles.Forsyth ename = hd tl args; 48837da2899SCharles.Forsyth if (ename.word == nil && ename.cmd != nil) 48937da2899SCharles.Forsyth ctxt.fail("bad raise context", "raise: bad exception name"); 49037da2899SCharles.Forsyth xraise("fail:" + ename.word); 49137da2899SCharles.Forsyth return nil; 49237da2899SCharles.Forsyth} 49337da2899SCharles.Forsyth 49437da2899SCharles.Forsyth# usage: rescue pattern rescuecmd cmd 49537da2899SCharles.Forsythbuiltin_rescue(ctxt: ref Context, args: list of ref Listnode, last: int) : string 49637da2899SCharles.Forsyth{ 49737da2899SCharles.Forsyth args = tl args; 49837da2899SCharles.Forsyth if (len args != 3 || !iscmd(hd tl args) || !iscmd(hd tl tl args)) 49937da2899SCharles.Forsyth builtinusage(ctxt, "rescue pattern {rescuecmd} {cmd}"); 50037da2899SCharles.Forsyth if ((hd args).word == nil && (hd args).cmd != nil) 50137da2899SCharles.Forsyth ctxt.fail("usage", "rescue: bad pattern"); 50237da2899SCharles.Forsyth dolstar := ctxt.get("*"); 50337da2899SCharles.Forsyth handler := hd tl args :: dolstar; 50437da2899SCharles.Forsyth code := hd tl tl args :: dolstar; 50537da2899SCharles.Forsyth { 50637da2899SCharles.Forsyth return ctxt.run(code, 0); 50737da2899SCharles.Forsyth } exception e { 50837da2899SCharles.Forsyth "fail:*" => 50937da2899SCharles.Forsyth ctxt.push(); 51037da2899SCharles.Forsyth ctxt.set("exception", ref Listnode(nil, e[5:]) :: nil); 51137da2899SCharles.Forsyth { 51237da2899SCharles.Forsyth status := ctxt.run(handler, last); 51337da2899SCharles.Forsyth ctxt.pop(); 51437da2899SCharles.Forsyth return status; 515*66f5808bSforsyth } exception { 51637da2899SCharles.Forsyth "fail:*" => 51737da2899SCharles.Forsyth ctxt.pop(); 51837da2899SCharles.Forsyth raise e; 51937da2899SCharles.Forsyth } 52037da2899SCharles.Forsyth } 52137da2899SCharles.Forsyth} 52237da2899SCharles.Forsyth 52337da2899SCharles.Forsythbuiltin_not(ctxt: ref Context, args: list of ref Listnode, last: int): string 52437da2899SCharles.Forsyth{ 52537da2899SCharles.Forsyth # syntax: ! cmd [args...] 52637da2899SCharles.Forsyth args = tl args; 52737da2899SCharles.Forsyth if (args == nil || ctxt.run(args, last) == nil) 52837da2899SCharles.Forsyth return "false"; 52937da2899SCharles.Forsyth return ""; 53037da2899SCharles.Forsyth} 53137da2899SCharles.Forsyth 53237da2899SCharles.Forsythbuiltin_for(ctxt: ref Context, args: list of ref Listnode, nil: int): string 53337da2899SCharles.Forsyth{ 53437da2899SCharles.Forsyth Usage: con "for var in [item...] {cmd}"; 53537da2899SCharles.Forsyth args = tl args; 53637da2899SCharles.Forsyth if (args == nil) 53737da2899SCharles.Forsyth builtinusage(ctxt, Usage); 53837da2899SCharles.Forsyth var := (hd args).word; 53937da2899SCharles.Forsyth if (var == nil) 54037da2899SCharles.Forsyth ctxt.fail("bad assign", "for: bad variable name"); 54137da2899SCharles.Forsyth args = tl args; 54237da2899SCharles.Forsyth if (args == nil || (hd args).word != "in") 54337da2899SCharles.Forsyth builtinusage(ctxt, Usage); 54437da2899SCharles.Forsyth args = tl args; 54537da2899SCharles.Forsyth if (args == nil) 54637da2899SCharles.Forsyth builtinusage(ctxt, Usage); 54737da2899SCharles.Forsyth for (eargs := args; tl eargs != nil; eargs = tl eargs) 54837da2899SCharles.Forsyth ; 54937da2899SCharles.Forsyth cmd := hd eargs; 55037da2899SCharles.Forsyth if (!iscmd(cmd)) 55137da2899SCharles.Forsyth builtinusage(ctxt, Usage); 55237da2899SCharles.Forsyth 55337da2899SCharles.Forsyth status := ""; 55437da2899SCharles.Forsyth dolstar := ctxt.get("*"); 55537da2899SCharles.Forsyth for(;;){ 55637da2899SCharles.Forsyth { 55737da2899SCharles.Forsyth for (; tl args != nil; args = tl args) { 55837da2899SCharles.Forsyth ctxt.setlocal(var, hd args :: nil); 55937da2899SCharles.Forsyth status = setstatus(ctxt, ctxt.run(cmd :: dolstar, 0)); 56037da2899SCharles.Forsyth } 56137da2899SCharles.Forsyth return status; 56237da2899SCharles.Forsyth } exception e { 56337da2899SCharles.Forsyth "fail:*" => 56437da2899SCharles.Forsyth if (loopexcept(e) == BREAK) 56537da2899SCharles.Forsyth return status; 56637da2899SCharles.Forsyth args = tl args; 56737da2899SCharles.Forsyth } 56837da2899SCharles.Forsyth } 56937da2899SCharles.Forsyth} 57037da2899SCharles.Forsyth 57137da2899SCharles.ForsythCONTINUE, BREAK: con iota; 57237da2899SCharles.Forsythloopexcept(ename: string): int 57337da2899SCharles.Forsyth{ 57437da2899SCharles.Forsyth case ename[5:] { 57537da2899SCharles.Forsyth "break" => 57637da2899SCharles.Forsyth return BREAK; 57737da2899SCharles.Forsyth "continue" => 57837da2899SCharles.Forsyth return CONTINUE; 57937da2899SCharles.Forsyth * => 58037da2899SCharles.Forsyth raise ename; 58137da2899SCharles.Forsyth } 58237da2899SCharles.Forsyth return 0; 58337da2899SCharles.Forsyth} 58437da2899SCharles.Forsyth 58537da2899SCharles.Forsythbuiltin_apply(ctxt: ref Context, args: list of ref Listnode, nil: int): string 58637da2899SCharles.Forsyth{ 58737da2899SCharles.Forsyth args = tl args; 58837da2899SCharles.Forsyth if (args == nil || !iscmd(hd args)) 58937da2899SCharles.Forsyth builtinusage(ctxt, "apply {cmd} [val...]"); 59037da2899SCharles.Forsyth 59137da2899SCharles.Forsyth status := ""; 59237da2899SCharles.Forsyth cmd := hd args; 59337da2899SCharles.Forsyth for(;;){ 59437da2899SCharles.Forsyth { 59537da2899SCharles.Forsyth for (args = tl args; args != nil; args = tl args) 59637da2899SCharles.Forsyth status = setstatus(ctxt, ctxt.run(cmd :: hd args :: nil, 0)); 59737da2899SCharles.Forsyth 59837da2899SCharles.Forsyth return status; 59937da2899SCharles.Forsyth } exception e{ 60037da2899SCharles.Forsyth "fail:*" => 60137da2899SCharles.Forsyth if (loopexcept(e) == BREAK) 60237da2899SCharles.Forsyth return status; 60337da2899SCharles.Forsyth } 60437da2899SCharles.Forsyth } 60537da2899SCharles.Forsyth} 60637da2899SCharles.Forsyth 60737da2899SCharles.Forsythbuiltin_status(nil: ref Context, args: list of ref Listnode, nil: int): string 60837da2899SCharles.Forsyth{ 60937da2899SCharles.Forsyth if (tl args != nil) 61037da2899SCharles.Forsyth return (hd tl args).word; 61137da2899SCharles.Forsyth return ""; 61237da2899SCharles.Forsyth} 61337da2899SCharles.Forsyth 61437da2899SCharles.Forsythpctlnames := array[] of { 61537da2899SCharles.Forsyth ("newfd", Sys->NEWFD), 61637da2899SCharles.Forsyth ("forkfd", Sys->FORKFD), 61737da2899SCharles.Forsyth ("newns", Sys->NEWNS), 61837da2899SCharles.Forsyth ("forkns", Sys->FORKNS), 61937da2899SCharles.Forsyth ("newpgrp", Sys->NEWPGRP), 62037da2899SCharles.Forsyth ("nodevs", Sys->NODEVS) 62137da2899SCharles.Forsyth}; 62237da2899SCharles.Forsyth 62337da2899SCharles.Forsythbuiltin_pctl(ctxt: ref Context, argv: list of ref Listnode, nil: int): string 62437da2899SCharles.Forsyth{ 62537da2899SCharles.Forsyth if (len argv < 2) 62637da2899SCharles.Forsyth builtinusage(ctxt, "pctl option... [fdnum...]"); 62737da2899SCharles.Forsyth 62837da2899SCharles.Forsyth finalmask := 0; 62937da2899SCharles.Forsyth fdlist: list of int; 63037da2899SCharles.Forsyth for (argv = tl argv; argv != nil; argv = tl argv) { 63137da2899SCharles.Forsyth w := (hd argv).word; 63237da2899SCharles.Forsyth if (isnum(w)) 63337da2899SCharles.Forsyth fdlist = int w :: fdlist; 63437da2899SCharles.Forsyth else { 63537da2899SCharles.Forsyth for (i := 0; i < len pctlnames; i++) { 63637da2899SCharles.Forsyth (name, mask) := pctlnames[i]; 63737da2899SCharles.Forsyth if (name == w) { 63837da2899SCharles.Forsyth finalmask |= mask; 63937da2899SCharles.Forsyth break; 64037da2899SCharles.Forsyth } 64137da2899SCharles.Forsyth } 64237da2899SCharles.Forsyth if (i == len pctlnames) 64337da2899SCharles.Forsyth ctxt.fail("usage", "pctl: unknown flag " + w); 64437da2899SCharles.Forsyth } 64537da2899SCharles.Forsyth } 64637da2899SCharles.Forsyth sys->pctl(finalmask, fdlist); 64737da2899SCharles.Forsyth return nil; 64837da2899SCharles.Forsyth} 64937da2899SCharles.Forsyth 65037da2899SCharles.Forsyth# usage: ~ value pattern... 65137da2899SCharles.Forsythbuiltin_twiddle(ctxt: ref Context, argv: list of ref Listnode, nil: int): string 65237da2899SCharles.Forsyth{ 65337da2899SCharles.Forsyth argv = tl argv; 65437da2899SCharles.Forsyth if (argv == nil) 65537da2899SCharles.Forsyth builtinusage(ctxt, "~ word [pattern...]"); 65637da2899SCharles.Forsyth if (tl argv == nil) 65737da2899SCharles.Forsyth return "no match"; 65837da2899SCharles.Forsyth w := word(hd argv); 65937da2899SCharles.Forsyth 66037da2899SCharles.Forsyth for (argv = tl argv; argv != nil; argv = tl argv) 66137da2899SCharles.Forsyth if (filepat->match(word(hd argv), w)) 66237da2899SCharles.Forsyth return ""; 66337da2899SCharles.Forsyth 66437da2899SCharles.Forsyth return "no match"; 66537da2899SCharles.Forsyth} 66637da2899SCharles.Forsyth 66737da2899SCharles.Forsyth#builtin_echo(ctxt: ref Context, argv: list of ref Listnode, nil: int): string 66837da2899SCharles.Forsyth#{ 66937da2899SCharles.Forsyth# argv = tl argv; 67037da2899SCharles.Forsyth# nflag := 0; 67137da2899SCharles.Forsyth# if (argv != nil && word(hd argv) == "-n") { 67237da2899SCharles.Forsyth# nflag = 1; 67337da2899SCharles.Forsyth# argv = tl argv; 67437da2899SCharles.Forsyth# } 67537da2899SCharles.Forsyth# s: string; 67637da2899SCharles.Forsyth# if (argv != nil) { 67737da2899SCharles.Forsyth# s = word(hd argv); 67837da2899SCharles.Forsyth# for (argv = tl argv; argv != nil; argv = tl argv) 67937da2899SCharles.Forsyth# s += " " + word(hd argv); 68037da2899SCharles.Forsyth# } 68137da2899SCharles.Forsyth# e: int; 68237da2899SCharles.Forsyth# if (nflag) 68337da2899SCharles.Forsyth# e = sys->print("%s", s); 68437da2899SCharles.Forsyth# else 68537da2899SCharles.Forsyth# e = sys->print("%s\n", s); 68637da2899SCharles.Forsyth# if (e == -1) { 68737da2899SCharles.Forsyth# err := sys->sprint("%r"); 68837da2899SCharles.Forsyth# if (ctxt.options() & ctxt.VERBOSE) 68937da2899SCharles.Forsyth# sys->fprint(sys->fildes(2), "echo: write error: %s\n", err); 69037da2899SCharles.Forsyth# return err; 69137da2899SCharles.Forsyth# } 69237da2899SCharles.Forsyth# return nil; 69337da2899SCharles.Forsyth#} 69437da2899SCharles.Forsyth 69537da2899SCharles.ForsythENOEXIST: con "file does not exist"; 69637da2899SCharles.ForsythTMPDIR: con "/tmp/pipes"; 69737da2899SCharles.Forsythsbuiltin_pipe(ctxt: ref Context, argv: list of ref Listnode): list of ref Listnode 69837da2899SCharles.Forsyth{ 69937da2899SCharles.Forsyth n: int; 70037da2899SCharles.Forsyth if (len argv != 3 || !iscmd(hd tl tl argv)) 70137da2899SCharles.Forsyth builtinusage(ctxt, "pipe (from|to|fdnum) {cmd}"); 70237da2899SCharles.Forsyth s := (hd tl argv).word; 70337da2899SCharles.Forsyth case s { 70437da2899SCharles.Forsyth "from" => 70537da2899SCharles.Forsyth n = 1; 70637da2899SCharles.Forsyth "to" => 70737da2899SCharles.Forsyth n = 0; 70837da2899SCharles.Forsyth * => 70937da2899SCharles.Forsyth if (!isnum(s)) 71037da2899SCharles.Forsyth builtinusage(ctxt, "pipe (from|to|fdnum) {cmd}"); 71137da2899SCharles.Forsyth n = int s; 71237da2899SCharles.Forsyth } 71337da2899SCharles.Forsyth pipeid := ctxt.get("pipeid"); 71437da2899SCharles.Forsyth seq: int; 71537da2899SCharles.Forsyth if (pipeid == nil) 71637da2899SCharles.Forsyth seq = 0; 71737da2899SCharles.Forsyth else 71837da2899SCharles.Forsyth seq = int (hd pipeid).word; 71937da2899SCharles.Forsyth id := "pipe." + string sys->pctl(0, nil) + "." + string seq; 72037da2899SCharles.Forsyth ctxt.set("pipeid", ref Listnode(nil, string ++seq) :: nil); 72137da2899SCharles.Forsyth mkdir(TMPDIR); 72237da2899SCharles.Forsyth d := "/tmp/" + id + "d"; 72337da2899SCharles.Forsyth if (mkdir(d) == -1) 72437da2899SCharles.Forsyth ctxt.fail("bad pipe", sys->sprint("pipe: cannot make %s: %r", d)); 72537da2899SCharles.Forsyth if (sys->bind("#|", d, Sys->MREPL) == -1) { 72637da2899SCharles.Forsyth sys->remove(d); 72737da2899SCharles.Forsyth ctxt.fail("bad pipe", sys->sprint("pipe: cannot bind pipe onto %s: %r", d)); 72837da2899SCharles.Forsyth } 72937da2899SCharles.Forsyth if (rename(d + "/data", id + "x") == -1 || rename(d + "/data1", id + "y")) { 73037da2899SCharles.Forsyth sys->unmount(nil, d); 73137da2899SCharles.Forsyth sys->remove(d); 73237da2899SCharles.Forsyth ctxt.fail("bad pipe", sys->sprint("pipe: cannot rename pipe: %r")); 73337da2899SCharles.Forsyth } 73437da2899SCharles.Forsyth if (sys->bind(d, TMPDIR, Sys->MBEFORE) == -1) { 73537da2899SCharles.Forsyth sys->unmount(nil, d); 73637da2899SCharles.Forsyth sys->remove(d); 73737da2899SCharles.Forsyth ctxt.fail("bad pipe", sys->sprint("pipe: cannot bind pipe dir: %r")); 73837da2899SCharles.Forsyth } 73937da2899SCharles.Forsyth sys->unmount(nil, d); 74037da2899SCharles.Forsyth sys->remove(d); 74137da2899SCharles.Forsyth sync := chan of string; 74237da2899SCharles.Forsyth spawn runpipe(sync, ctxt, n, TMPDIR + "/" + id + "x", hd tl tl argv); 74337da2899SCharles.Forsyth if ((e := <-sync) != nil) 74437da2899SCharles.Forsyth ctxt.fail("bad pipe", e); 74537da2899SCharles.Forsyth return ref Listnode(nil, TMPDIR + "/" + id + "y") :: nil; 74637da2899SCharles.Forsyth} 74737da2899SCharles.Forsyth 74837da2899SCharles.Forsythmkdir(f: string): int 74937da2899SCharles.Forsyth{ 75037da2899SCharles.Forsyth if (sys->create(f, Sys->OREAD, Sys->DMDIR | 8r777) == nil) 75137da2899SCharles.Forsyth return -1; 75237da2899SCharles.Forsyth return 0; 75337da2899SCharles.Forsyth} 75437da2899SCharles.Forsyth 75537da2899SCharles.Forsythrunpipe(sync: chan of string, ctxt: ref Context, fdno: int, p: string, cmd: ref Listnode) 75637da2899SCharles.Forsyth{ 75737da2899SCharles.Forsyth sys->pctl(Sys->FORKFD, nil); 75837da2899SCharles.Forsyth ctxt = ctxt.copy(1); 75937da2899SCharles.Forsyth if ((fd := sys->open(p, Sys->ORDWR)) == nil) { 76037da2899SCharles.Forsyth sync <-= sys->sprint("cannot open %s: %r", p); 76137da2899SCharles.Forsyth exit; 76237da2899SCharles.Forsyth } 76337da2899SCharles.Forsyth sys->dup(fd.fd, fdno); 76437da2899SCharles.Forsyth fd = nil; 76537da2899SCharles.Forsyth sync <-= nil; 76637da2899SCharles.Forsyth ctxt.run(cmd :: ctxt.get("*"), 1); 76737da2899SCharles.Forsyth} 76837da2899SCharles.Forsyth 76937da2899SCharles.Forsythrename(x, y: string): int 77037da2899SCharles.Forsyth{ 77137da2899SCharles.Forsyth (ok, nil) := sys->stat(x); 77237da2899SCharles.Forsyth if (ok == -1) 77337da2899SCharles.Forsyth return -1; 77437da2899SCharles.Forsyth inf := sys->nulldir; 77537da2899SCharles.Forsyth inf.name = y; 77637da2899SCharles.Forsyth if (sys->wstat(x, inf) == -1) 77737da2899SCharles.Forsyth return -1; 77837da2899SCharles.Forsyth return 0; 77937da2899SCharles.Forsyth} 78037da2899SCharles.Forsyth 78137da2899SCharles.Forsythbuiltinusage(ctxt: ref Context, s: string) 78237da2899SCharles.Forsyth{ 78337da2899SCharles.Forsyth ctxt.fail("usage", "usage: " + s); 78437da2899SCharles.Forsyth} 78537da2899SCharles.Forsyth 78637da2899SCharles.Forsythsetstatus(ctxt: ref Context, val: string): string 78737da2899SCharles.Forsyth{ 78837da2899SCharles.Forsyth ctxt.setlocal("status", ref Listnode(nil, val) :: nil); 78937da2899SCharles.Forsyth return val; 79037da2899SCharles.Forsyth} 79137da2899SCharles.Forsyth 79237da2899SCharles.Forsyth# same as sys->raise(), but check that length of error string is 79337da2899SCharles.Forsyth# acceptable, and truncate as appropriate. 79437da2899SCharles.Forsythxraise(s: string) 79537da2899SCharles.Forsyth{ 79637da2899SCharles.Forsyth d := array of byte s; 79737da2899SCharles.Forsyth if (len d > Sys->WAITLEN) 79837da2899SCharles.Forsyth raise string d[0:Sys->WAITLEN]; 79937da2899SCharles.Forsyth else { 80037da2899SCharles.Forsyth d = nil; 80137da2899SCharles.Forsyth raise s; 80237da2899SCharles.Forsyth } 80337da2899SCharles.Forsyth} 80437da2899SCharles.Forsyth 80537da2899SCharles.Forsythisnum(s: string): int 80637da2899SCharles.Forsyth{ 80737da2899SCharles.Forsyth for (i := 0; i < len s; i++) 80837da2899SCharles.Forsyth if (s[i] > '9' || s[i] < '0') 80937da2899SCharles.Forsyth return 0; 81037da2899SCharles.Forsyth return 1; 81137da2899SCharles.Forsyth} 81237da2899SCharles.Forsyth 813