implement Shellbuiltin; include "sys.m"; sys: Sys;include "draw.m";include "sh.m"; sh: Sh; Listnode, Context: import sh; myself: Shellbuiltin;include "filepat.m"; filepat: Filepat;include "bufio.m"; bufio: Bufio; Iobuf: import bufio; builtinnames := array[] of { "if", "while", "~", "!", "apply", "for", "status", "pctl", "fn", "subfn", "and", "or", "raise", "rescue", "flag", "getlines", "no",}; sbuiltinnames := array[] of { "hd", "tl", "index", "split", "join", "pid", "parse", "env", "pipe",}; initbuiltin(ctxt: ref Context, shmod: Sh): string{ sys = load Sys Sys->PATH; sh = shmod; myself = load Shellbuiltin "$self"; if (myself == nil) ctxt.fail("bad module", sys->sprint("std: cannot load self: %r")); filepat = load Filepat Filepat->PATH; if (filepat == nil) ctxt.fail("bad module", sys->sprint("std: cannot load: %s: %r", Filepat->PATH)); bufio = load Bufio Bufio->PATH; if (bufio == nil) ctxt.fail("bad module", sys->sprint("std: cannot load: %s: %r", Bufio->PATH)); names := builtinnames; for (i := 0; i < len names; i++) ctxt.addbuiltin(names[i], myself); names = sbuiltinnames; for (i = 0; i < len names; i++) ctxt.addsbuiltin(names[i], myself); env := ctxt.envlist(); for (; env != nil; env = tl env) { (name, val) := hd env; if (len name > 3 && name[0:3] == "fn-") fndef(ctxt, name[3:], val, 0); if (len name > 4 && name[0:4] == "sfn-") fndef(ctxt, name[4:], val, 1); } return nil;} whatis(c: ref Sh->Context, sh: Sh, name: string, wtype: int): string{ ename, fname: string; case wtype { BUILTIN => (ename, fname) = ("fn-", "fn "); SBUILTIN => (ename, fname) = ("sfn-", "subfn "); OTHER => return nil; } val := c.get(ename + name); if (val != nil) return fname + name + " " + sh->quoted(hd val :: nil, 0); return nil;} getself(): Shellbuiltin{ return myself;} runbuiltin(c: ref Sh->Context, nil: Sh, cmd: list of ref Sh->Listnode, last: int): string{ status: string; name := (hd cmd).word; val := c.get("fn-" + name); if (val != nil) return c.run(hd val :: tl cmd, last); case name { "if" => status = builtin_if(c, cmd, last); "while" => status = builtin_while(c, cmd, last); "and" => status = builtin_and(c, cmd, last); "apply" => status = builtin_apply(c, cmd, last); "for" => status = builtin_for(c, cmd, last); "or" => status = builtin_or(c, cmd, last); "!" => status = builtin_not(c, cmd, last); "fn" => status = builtin_fn(c, cmd, last, 0); "subfn" => status = builtin_fn(c, cmd, last, 1); "~" => status = builtin_twiddle(c, cmd, last); "status" => status = builtin_status(c, cmd, last); "pctl" => status = builtin_pctl(c, cmd, last); "raise" => status = builtin_raise(c, cmd, last); "rescue" => status = builtin_rescue(c, cmd, last); "flag" => status = builtin_flag(c, cmd, last); "getlines" => status = builtin_getlines(c, cmd, last); "no" => status = builtin_no(c, cmd, last); } return status;} runsbuiltin(c: ref Sh->Context, nil: Sh, cmd: list of ref Sh->Listnode): list of ref Listnode{ name := (hd cmd).word; val := c.get("sfn-" + name); if (val != nil) return runsubfn(c, val, tl cmd); case name { "pid" => return ref Listnode(nil, string sys->pctl(0, nil)) :: nil; "hd" => if (tl cmd == nil) return nil; return hd tl cmd :: nil; "tl" => if (tl cmd == nil) return nil; return tl tl cmd; "index" => return sbuiltin_index(c, cmd); "split" => return sbuiltin_split(c, cmd); "join" => return sbuiltin_join(c, cmd); "parse" => return sbuiltin_parse(c, cmd); "env" => return sbuiltin_env(c, cmd); "pipe" => return sbuiltin_pipe(c, cmd); } return nil;} runsubfn(ctxt: ref Context, body, args: list of ref Listnode): list of ref Listnode{ if (body == nil) return nil; ctxt.push(); { ctxt.setlocal("result", nil); ctxt.run(hd body :: args, 0); result := ctxt.get("result"); ctxt.pop(); return result; } exception e { "fail:*" => ctxt.pop(); raise e; }} sbuiltin_index(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode{ if (len val < 2 || (hd tl val).word == nil) builtinusage(ctxt, "index num list"); k := int (hd tl val).word - 1; val = tl tl val; for (; k > 0 && val != nil; k--) val = tl val; if (val != nil) val = hd val :: nil; return val;} # return a parsed version of a string, raising a "parse error" exception if# it fails. the string must be a braced command block.sbuiltin_parse(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode{ if (len args != 2) builtinusage(ctxt, "parse arg"); args = tl args; if ((hd args).cmd != nil) return ref Listnode((hd args).cmd, nil) :: nil; w := (hd args).word; if (w == nil || w[0] != '{') #} ctxt.fail("parse error", "parse: argument must be a braced block"); (n, err) := sh->parse(w); if (err != nil) ctxt.fail("parse error", "parse: " + err); return ref Listnode(n, nil) :: nil;} sbuiltin_env(ctxt: ref Context, nil: list of ref Listnode): list of ref Listnode{ vl: list of string; for (e := ctxt.envlist(); e != nil; e = tl e) { (n, v) := hd e; if (v != nil) # XXX this is debatable... someone might want to see null local vars. vl = n :: vl; } return sh->stringlist2list(vl);} word(n: ref Listnode): string{ if (n.word != nil) return n.word; if (n.cmd != nil) n.word = sh->cmd2string(n.cmd); return n.word;} # usage: split [separators] valuesbuiltin_split(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode{ n := len args; if (n < 2 || n > 3) builtinusage(ctxt, "split [separators] value"); seps: string; if (n == 2) { ifs := ctxt.get("ifs"); if (ifs == nil) ctxt.fail("usage", "split: $ifs not set"); seps = word(hd ifs); } else { args = tl args; seps = word(hd args); } (nil, toks) := sys->tokenize(word(hd tl args), seps); return sh->stringlist2list(toks);} sbuiltin_join(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode{ args = tl args; if (args == nil) builtinusage(ctxt, "join separator [arg...]"); seps := word(hd args); if (tl args == nil) return ref Listnode(nil, nil) :: nil; s := word(hd tl args); for (args = tl tl args; args != nil; args = tl args) s += seps + word(hd args); return ref Listnode(nil, s) :: nil;} builtin_fn(ctxt: ref Context, args: list of ref Listnode, nil: int, issub: int): string{ n := len args; title := (hd args).word; if (n < 2) builtinusage(ctxt, title + " [name...] [{body}]"); for (al := tl args; tl al != nil; al = tl al) if ((hd al).cmd != nil) builtinusage(ctxt, title + " [name...] [{body}]"); if ((hd al).cmd != nil) { cmd := hd al :: nil; for (al = tl args; tl al != nil; al = tl al) fndef(ctxt, (hd al).word, cmd, issub); } else { for (al = tl args; al != nil; al = tl al) fnundef(ctxt, (hd al).word, issub); } return nil;} fndef(ctxt: ref Context, name: string, cmd: list of ref Listnode, issub: int){ if (cmd == nil) return; if (issub) { ctxt.set("sfn-" + name, cmd); ctxt.addsbuiltin(name, myself); } else { ctxt.set("fn-" + name, cmd); ctxt.addbuiltin(name, myself); }} fnundef(ctxt: ref Context, name: string, issub: int){ if (issub) { ctxt.set("sfn-" + name, nil); ctxt.removesbuiltin(name, myself); } else { ctxt.set("fn-" + name, nil); ctxt.removebuiltin(name, myself); }} builtin_flag(ctxt: ref Context, args: list of ref Listnode, nil: int): string{ n := len args; if (n < 2 || n > 3 || len (hd tl args).word != 1) builtinusage(ctxt, "flag [vxei] [+-]"); flag := (hd tl args).word[0]; p := ""; if (n == 3) p = (hd tl tl args).word; mask := 0; case flag { 'v' => mask = Context.VERBOSE; 'x' => mask = Context.EXECPRINT; 'e' => mask = Context.ERROREXIT; 'i' => mask = Context.INTERACTIVE; * => builtinusage(ctxt, "flag [vxei] [+-]"); } case p { "" => if (ctxt.options() & mask) return nil; return "not set"; "-" => ctxt.setoptions(mask, 0); "+" => ctxt.setoptions(mask, 1); * => builtinusage(ctxt, "flag [vxei] [+-]"); } return nil;} builtin_no(nil: ref Context, args: list of ref Listnode, nil: int): string{ if (tl args != nil) return "yes"; return nil;} iscmd(n: ref Listnode): int{ return n.cmd != nil || (n.word != nil && n.word[0] == '{');} builtin_if(ctxt: ref Context, args: list of ref Listnode, nil: int): string{ args = tl args; nargs := len args; if (nargs < 2) builtinusage(ctxt, "if {cond} {action} [{cond} {action}]... [{elseaction}]"); status: string; dolstar := ctxt.get("*"); while (args != nil) { cmd: ref Listnode = nil; if (tl args == nil) { cmd = hd args; args = tl args; } else { if (!iscmd(hd args)) builtinusage(ctxt, "if [{cond} {action}]... [{elseaction}]"); status = ctxt.run(hd args :: dolstar, 0); if (status == nil) { cmd = hd tl args; args = nil; } else args = tl tl args; setstatus(ctxt, status); } if (cmd != nil) { if (!iscmd(cmd)) builtinusage(ctxt, "if [{cond} {action}]... [{elseaction}]"); status = ctxt.run(cmd :: dolstar, 0); } } return status; } builtin_or(ctxt: ref Context, args: list of ref Listnode, nil: int): string{ s: string; dolstar := ctxt.get("*"); for (args = tl args; args != nil; args = tl args) { if (!iscmd(hd args)) builtinusage(ctxt, "or [{cmd} ...]"); if ((s = ctxt.run(hd args :: dolstar, 0)) == nil) return nil; else setstatus(ctxt, s); } return s;} builtin_and(ctxt: ref Context, args: list of ref Listnode, nil: int): string{ dolstar := ctxt.get("*"); for (args = tl args; args != nil; args = tl args) { if (!iscmd(hd args)) builtinusage(ctxt, "and [{cmd} ...]"); if ((s := ctxt.run(hd args :: dolstar, 0)) != nil) return s; else setstatus(ctxt, nil); } return nil;} builtin_while(ctxt: ref Context, args: list of ref Listnode, nil: int) : string{ args = tl args; if (len args != 2 || !iscmd(hd args) || !iscmd(hd tl args)) builtinusage(ctxt, "while {condition} {cmd}"); dolstar := ctxt.get("*"); cond := hd args :: dolstar; action := hd tl args :: dolstar; status := ""; for(;;){ { while (ctxt.run(cond, 0) == nil) status = setstatus(ctxt, ctxt.run(action, 0)); return status; } exception e{ "fail:*" => if (loopexcept(e) == BREAK) return status; } }} builtin_getlines(ctxt: ref Context, argv: list of ref Listnode, nil: int) : string{ n := len argv; if (n < 2 || n > 3) builtinusage(ctxt, "getlines [separators] {cmd}"); argv = tl argv; seps := "\n"; if (n == 3) { seps = word(hd argv); argv = tl argv; } if (len seps == 0) builtinusage(ctxt, "getlines [separators] {cmd}"); if (!iscmd(hd argv)) builtinusage(ctxt, "getlines [separators] {cmd}"); cmd := hd argv :: ctxt.get("*"); stdin := bufio->fopen(sys->fildes(0), Sys->OREAD); if (stdin == nil) ctxt.fail("bad input", sys->sprint("getlines: cannot open stdin: %r")); status := ""; ctxt.push(); for(;;){ { for (;;) { s: string; if (len seps == 1) s = stdin.gets(seps[0]); else s = stdin.gett(seps); if (s == nil) break; # make sure we don't lose the last unterminated line lastc := s[len s - 1]; if (lastc == seps[0]) s = s[0:len s - 1]; else for (i := 1; i < len seps; i++) { if (lastc == seps[i]) { s = s[0:len s - 1]; break; } } ctxt.setlocal("line", ref Listnode(nil, s) :: nil); status = setstatus(ctxt, ctxt.run(cmd, 0)); } ctxt.pop(); return status; } exception e { "fail:*" => ctxt.pop(); if (loopexcept(e) == BREAK) return status; ctxt.push(); } }} # usage: raise [name]builtin_raise(ctxt: ref Context, args: list of ref Listnode, nil: int) : string{ ename: ref Listnode; if (tl args == nil) { e := ctxt.get("exception"); if (e == nil) ctxt.fail("bad raise context", "raise: no exception found"); ename = (hd e); } else ename = hd tl args; if (ename.word == nil && ename.cmd != nil) ctxt.fail("bad raise context", "raise: bad exception name"); xraise("fail:" + ename.word); return nil;} # usage: rescue pattern rescuecmd cmdbuiltin_rescue(ctxt: ref Context, args: list of ref Listnode, last: int) : string{ args = tl args; if (len args != 3 || !iscmd(hd tl args) || !iscmd(hd tl tl args)) builtinusage(ctxt, "rescue pattern {rescuecmd} {cmd}"); if ((hd args).word == nil && (hd args).cmd != nil)Lines 1–500 of 812. Load more
implement Shellbuiltin; include "sys.m"; sys: Sys; include "draw.m"; include "sh.m"; sh: Sh; Listnode, Context: import sh; myself: Shellbuiltin; include "filepat.m"; filepat: Filepat; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; builtinnames := array[] of { "if", "while", "~", "!", "apply", "for", "status", "pctl", "fn", "subfn", "and", "or", "raise", "rescue", "flag", "getlines", "no", }; sbuiltinnames := array[] of { "hd", "tl", "index", "split", "join", "pid", "parse", "env", "pipe", }; initbuiltin(ctxt: ref Context, shmod: Sh): string { sys = load Sys Sys->PATH; sh = shmod; myself = load Shellbuiltin "$self"; if (myself == nil) ctxt.fail("bad module", sys->sprint("std: cannot load self: %r")); filepat = load Filepat Filepat->PATH; if (filepat == nil) ctxt.fail("bad module", sys->sprint("std: cannot load: %s: %r", Filepat->PATH)); bufio = load Bufio Bufio->PATH; if (bufio == nil) ctxt.fail("bad module", sys->sprint("std: cannot load: %s: %r", Bufio->PATH)); names := builtinnames; for (i := 0; i < len names; i++) ctxt.addbuiltin(names[i], myself); names = sbuiltinnames; for (i = 0; i < len names; i++) ctxt.addsbuiltin(names[i], myself); env := ctxt.envlist(); for (; env != nil; env = tl env) { (name, val) := hd env; if (len name > 3 && name[0:3] == "fn-") fndef(ctxt, name[3:], val, 0); if (len name > 4 && name[0:4] == "sfn-") fndef(ctxt, name[4:], val, 1); } return nil; } whatis(c: ref Sh->Context, sh: Sh, name: string, wtype: int): string { ename, fname: string; case wtype { BUILTIN => (ename, fname) = ("fn-", "fn "); SBUILTIN => (ename, fname) = ("sfn-", "subfn "); OTHER => return nil; } val := c.get(ename + name); if (val != nil) return fname + name + " " + sh->quoted(hd val :: nil, 0); return nil; } getself(): Shellbuiltin { return myself; } runbuiltin(c: ref Sh->Context, nil: Sh, cmd: list of ref Sh->Listnode, last: int): string { status: string; name := (hd cmd).word; val := c.get("fn-" + name); if (val != nil) return c.run(hd val :: tl cmd, last); case name { "if" => status = builtin_if(c, cmd, last); "while" => status = builtin_while(c, cmd, last); "and" => status = builtin_and(c, cmd, last); "apply" => status = builtin_apply(c, cmd, last); "for" => status = builtin_for(c, cmd, last); "or" => status = builtin_or(c, cmd, last); "!" => status = builtin_not(c, cmd, last); "fn" => status = builtin_fn(c, cmd, last, 0); "subfn" => status = builtin_fn(c, cmd, last, 1); "~" => status = builtin_twiddle(c, cmd, last); "status" => status = builtin_status(c, cmd, last); "pctl" => status = builtin_pctl(c, cmd, last); "raise" => status = builtin_raise(c, cmd, last); "rescue" => status = builtin_rescue(c, cmd, last); "flag" => status = builtin_flag(c, cmd, last); "getlines" => status = builtin_getlines(c, cmd, last); "no" => status = builtin_no(c, cmd, last); } return status; } runsbuiltin(c: ref Sh->Context, nil: Sh, cmd: list of ref Sh->Listnode): list of ref Listnode { name := (hd cmd).word; val := c.get("sfn-" + name); if (val != nil) return runsubfn(c, val, tl cmd); case name { "pid" => return ref Listnode(nil, string sys->pctl(0, nil)) :: nil; "hd" => if (tl cmd == nil) return nil; return hd tl cmd :: nil; "tl" => if (tl cmd == nil) return nil; return tl tl cmd; "index" => return sbuiltin_index(c, cmd); "split" => return sbuiltin_split(c, cmd); "join" => return sbuiltin_join(c, cmd); "parse" => return sbuiltin_parse(c, cmd); "env" => return sbuiltin_env(c, cmd); "pipe" => return sbuiltin_pipe(c, cmd); } return nil; } runsubfn(ctxt: ref Context, body, args: list of ref Listnode): list of ref Listnode { if (body == nil) return nil; ctxt.push(); { ctxt.setlocal("result", nil); ctxt.run(hd body :: args, 0); result := ctxt.get("result"); ctxt.pop(); return result; } exception e { "fail:*" => ctxt.pop(); raise e; } } sbuiltin_index(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode { if (len val < 2 || (hd tl val).word == nil) builtinusage(ctxt, "index num list"); k := int (hd tl val).word - 1; val = tl tl val; for (; k > 0 && val != nil; k--) val = tl val; if (val != nil) val = hd val :: nil; return val; } # return a parsed version of a string, raising a "parse error" exception if # it fails. the string must be a braced command block. sbuiltin_parse(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode { if (len args != 2) builtinusage(ctxt, "parse arg"); args = tl args; if ((hd args).cmd != nil) return ref Listnode((hd args).cmd, nil) :: nil; w := (hd args).word; if (w == nil || w[0] != '{') #} ctxt.fail("parse error", "parse: argument must be a braced block"); (n, err) := sh->parse(w); if (err != nil) ctxt.fail("parse error", "parse: " + err); return ref Listnode(n, nil) :: nil; } sbuiltin_env(ctxt: ref Context, nil: list of ref Listnode): list of ref Listnode { vl: list of string; for (e := ctxt.envlist(); e != nil; e = tl e) { (n, v) := hd e; if (v != nil) # XXX this is debatable... someone might want to see null local vars. vl = n :: vl; } return sh->stringlist2list(vl); } word(n: ref Listnode): string { if (n.word != nil) return n.word; if (n.cmd != nil) n.word = sh->cmd2string(n.cmd); return n.word; } # usage: split [separators] value sbuiltin_split(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode { n := len args; if (n < 2 || n > 3) builtinusage(ctxt, "split [separators] value"); seps: string; if (n == 2) { ifs := ctxt.get("ifs"); if (ifs == nil) ctxt.fail("usage", "split: $ifs not set"); seps = word(hd ifs); } else { args = tl args; seps = word(hd args); } (nil, toks) := sys->tokenize(word(hd tl args), seps); return sh->stringlist2list(toks); } sbuiltin_join(ctxt: ref Context, args: list of ref Listnode): list of ref Listnode { args = tl args; if (args == nil) builtinusage(ctxt, "join separator [arg...]"); seps := word(hd args); if (tl args == nil) return ref Listnode(nil, nil) :: nil; s := word(hd tl args); for (args = tl tl args; args != nil; args = tl args) s += seps + word(hd args); return ref Listnode(nil, s) :: nil; } builtin_fn(ctxt: ref Context, args: list of ref Listnode, nil: int, issub: int): string { n := len args; title := (hd args).word; if (n < 2) builtinusage(ctxt, title + " [name...] [{body}]"); for (al := tl args; tl al != nil; al = tl al) if ((hd al).cmd != nil) builtinusage(ctxt, title + " [name...] [{body}]"); if ((hd al).cmd != nil) { cmd := hd al :: nil; for (al = tl args; tl al != nil; al = tl al) fndef(ctxt, (hd al).word, cmd, issub); } else { for (al = tl args; al != nil; al = tl al) fnundef(ctxt, (hd al).word, issub); } return nil; } fndef(ctxt: ref Context, name: string, cmd: list of ref Listnode, issub: int) { if (cmd == nil) return; if (issub) { ctxt.set("sfn-" + name, cmd); ctxt.addsbuiltin(name, myself); } else { ctxt.set("fn-" + name, cmd); ctxt.addbuiltin(name, myself); } } fnundef(ctxt: ref Context, name: string, issub: int) { if (issub) { ctxt.set("sfn-" + name, nil); ctxt.removesbuiltin(name, myself); } else { ctxt.set("fn-" + name, nil); ctxt.removebuiltin(name, myself); } } builtin_flag(ctxt: ref Context, args: list of ref Listnode, nil: int): string { n := len args; if (n < 2 || n > 3 || len (hd tl args).word != 1) builtinusage(ctxt, "flag [vxei] [+-]"); flag := (hd tl args).word[0]; p := ""; if (n == 3) p = (hd tl tl args).word; mask := 0; case flag { 'v' => mask = Context.VERBOSE; 'x' => mask = Context.EXECPRINT; 'e' => mask = Context.ERROREXIT; 'i' => mask = Context.INTERACTIVE; * => builtinusage(ctxt, "flag [vxei] [+-]"); } case p { "" => if (ctxt.options() & mask) return nil; return "not set"; "-" => ctxt.setoptions(mask, 0); "+" => ctxt.setoptions(mask, 1); * => builtinusage(ctxt, "flag [vxei] [+-]"); } return nil; } builtin_no(nil: ref Context, args: list of ref Listnode, nil: int): string { if (tl args != nil) return "yes"; return nil; } iscmd(n: ref Listnode): int { return n.cmd != nil || (n.word != nil && n.word[0] == '{'); } builtin_if(ctxt: ref Context, args: list of ref Listnode, nil: int): string { args = tl args; nargs := len args; if (nargs < 2) builtinusage(ctxt, "if {cond} {action} [{cond} {action}]... [{elseaction}]"); status: string; dolstar := ctxt.get("*"); while (args != nil) { cmd: ref Listnode = nil; if (tl args == nil) { cmd = hd args; args = tl args; } else { if (!iscmd(hd args)) builtinusage(ctxt, "if [{cond} {action}]... [{elseaction}]"); status = ctxt.run(hd args :: dolstar, 0); if (status == nil) { cmd = hd tl args; args = nil; } else args = tl tl args; setstatus(ctxt, status); } if (cmd != nil) { if (!iscmd(cmd)) builtinusage(ctxt, "if [{cond} {action}]... [{elseaction}]"); status = ctxt.run(cmd :: dolstar, 0); } } return status; } builtin_or(ctxt: ref Context, args: list of ref Listnode, nil: int): string { s: string; dolstar := ctxt.get("*"); for (args = tl args; args != nil; args = tl args) { if (!iscmd(hd args)) builtinusage(ctxt, "or [{cmd} ...]"); if ((s = ctxt.run(hd args :: dolstar, 0)) == nil) return nil; else setstatus(ctxt, s); } return s; } builtin_and(ctxt: ref Context, args: list of ref Listnode, nil: int): string { dolstar := ctxt.get("*"); for (args = tl args; args != nil; args = tl args) { if (!iscmd(hd args)) builtinusage(ctxt, "and [{cmd} ...]"); if ((s := ctxt.run(hd args :: dolstar, 0)) != nil) return s; else setstatus(ctxt, nil); } return nil; } builtin_while(ctxt: ref Context, args: list of ref Listnode, nil: int) : string { args = tl args; if (len args != 2 || !iscmd(hd args) || !iscmd(hd tl args)) builtinusage(ctxt, "while {condition} {cmd}"); dolstar := ctxt.get("*"); cond := hd args :: dolstar; action := hd tl args :: dolstar; status := ""; for(;;){ { while (ctxt.run(cond, 0) == nil) status = setstatus(ctxt, ctxt.run(action, 0)); return status; } exception e{ "fail:*" => if (loopexcept(e) == BREAK) return status; } } } builtin_getlines(ctxt: ref Context, argv: list of ref Listnode, nil: int) : string { n := len argv; if (n < 2 || n > 3) builtinusage(ctxt, "getlines [separators] {cmd}"); argv = tl argv; seps := "\n"; if (n == 3) { seps = word(hd argv); argv = tl argv; } if (len seps == 0) builtinusage(ctxt, "getlines [separators] {cmd}"); if (!iscmd(hd argv)) builtinusage(ctxt, "getlines [separators] {cmd}"); cmd := hd argv :: ctxt.get("*"); stdin := bufio->fopen(sys->fildes(0), Sys->OREAD); if (stdin == nil) ctxt.fail("bad input", sys->sprint("getlines: cannot open stdin: %r")); status := ""; ctxt.push(); for(;;){ { for (;;) { s: string; if (len seps == 1) s = stdin.gets(seps[0]); else s = stdin.gett(seps); if (s == nil) break; # make sure we don't lose the last unterminated line lastc := s[len s - 1]; if (lastc == seps[0]) s = s[0:len s - 1]; else for (i := 1; i < len seps; i++) { if (lastc == seps[i]) { s = s[0:len s - 1]; break; } } ctxt.setlocal("line", ref Listnode(nil, s) :: nil); status = setstatus(ctxt, ctxt.run(cmd, 0)); } ctxt.pop(); return status; } exception e { "fail:*" => ctxt.pop(); if (loopexcept(e) == BREAK) return status; ctxt.push(); } } } # usage: raise [name] builtin_raise(ctxt: ref Context, args: list of ref Listnode, nil: int) : string { ename: ref Listnode; if (tl args == nil) { e := ctxt.get("exception"); if (e == nil) ctxt.fail("bad raise context", "raise: no exception found"); ename = (hd e); } else ename = hd tl args; if (ename.word == nil && ename.cmd != nil) ctxt.fail("bad raise context", "raise: bad exception name"); xraise("fail:" + ename.word); return nil; } # usage: rescue pattern rescuecmd cmd builtin_rescue(ctxt: ref Context, args: list of ref Listnode, last: int) : string { args = tl args; if (len args != 3 || !iscmd(hd tl args) || !iscmd(hd tl tl args)) builtinusage(ctxt, "rescue pattern {rescuecmd} {cmd}"); if ((hd args).word == nil && (hd args).cmd != nil)