diff options
Diffstat (limited to 'appl/cmd/sh/arg.b')
| -rw-r--r-- | appl/cmd/sh/arg.b | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/appl/cmd/sh/arg.b b/appl/cmd/sh/arg.b new file mode 100644 index 00000000..a0b57b84 --- /dev/null +++ b/appl/cmd/sh/arg.b @@ -0,0 +1,181 @@ +implement Shellbuiltin; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "sh.m"; + sh: Sh; + Listnode, Context: import sh; + myself: Shellbuiltin; + +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("arg: cannot load self: %r")); + ctxt.addbuiltin("arg", myself); + return nil; +} + +whatis(nil: ref Sh->Context, nil: Sh, nil: string, nil: int): string +{ + return nil; +} + +getself(): Shellbuiltin +{ + return myself; +} + +runbuiltin(ctxt: ref Context, nil: Sh, + argv: list of ref Listnode, last: int): string +{ + case (hd argv).word { + "arg" => + return builtin_arg(ctxt, argv, last); + } + return nil; +} + +runsbuiltin(nil: ref Sh->Context, nil: Sh, + nil: list of ref Listnode): list of ref Listnode +{ + return nil; +} + +argusage(ctxt: ref Context) +{ + ctxt.fail("usage", "usage: arg [opts {command}]... - args"); +} + +builtin_arg(ctxt: ref Context, argv: list of ref Listnode, nil: int): string +{ + for (args := tl argv; args != nil; args = tl tl args) { + if ((hd args).word == "-") + break; + if ((hd args).cmd != nil && (hd args).word == nil) + argusage(ctxt); + if (tl args == nil) + argusage(ctxt); + if ((hd tl args).cmd == nil) + argusage(ctxt); + } + if (args == nil) + args = ctxt.get("*"); + else + args = tl args; + laststatus := ""; + ctxt.push(); + { + arg := Arg.init(args); + while ((opt := arg.opt()) != 0) { + for (argt := tl argv; argt != nil && (hd argt).word != "-"; argt = tl tl argt) { + w := (hd argt).word; + argcount := 0; + for (e := len w - 1; e >= 0; e--) { + if (w[e] != '+') + break; + argcount++; + } + w = w[0:e+1]; + if (w == nil) + continue; + for (i := 0; i < len w; i++) + if (w[i] == opt || w[i] == '*') + break; + if (i < len w) { + optstr := ""; optstr[0] = opt; + ctxt.setlocal("opt", ref Listnode(nil, optstr) :: nil); + args = arg.arg(argcount); + if (argcount > 0 && args == nil) + ctxt.fail("usage", sys->sprint("option -%c requires %d arguments", opt, argcount)); + ctxt.setlocal("arg", args); + laststatus = ctxt.run(hd tl argt :: nil, 0); + break; + } + } + if (argt == nil || (hd argt).word == "-") + ctxt.fail("usage", sys->sprint("unknown option -%c", opt)); + } + ctxt.pop(); + ctxt.set("args", arg.args); # XXX backward compatibility - should go + ctxt.set("*", arg.args); + return laststatus; + } + exception e{ + "fail:*" => + ctxt.pop(); + if (e[5:] == "break") + return laststatus; + raise e; + } +} + +Arg: adt { + args: list of ref Listnode; + curropt: string; + init: fn(argv: list of ref Listnode): ref Arg; + arg: fn(ctxt: self ref Arg, n: int): list of ref Listnode; + opt: fn(ctxt: self ref Arg): int; +}; + + +Arg.init(argv: list of ref Listnode): ref Arg +{ + return ref Arg(argv, nil); +} + +# get next n option arguments (nil list if not enough arguments found) +Arg.arg(ctxt: self ref Arg, n: int): list of ref Listnode +{ + if (n == 0) + return nil; + + args: list of ref Listnode; + while (--n >= 0) { + if (ctxt.curropt != nil) { + args = ref Listnode(nil, ctxt.curropt) :: args; + ctxt.curropt = nil; + } else if (ctxt.args == nil) + return nil; + else { + args = hd ctxt.args :: args; + ctxt.args = tl ctxt.args; + } + } + r: list of ref Listnode; + for (; args != nil; args = tl args) + r = hd args :: r; + return r; +} + +# get next option letter +# return 0 at end of options +Arg.opt(ctxt: self ref Arg): int +{ + if (ctxt.curropt != "") { + opt := ctxt.curropt[0]; + ctxt.curropt = ctxt.curropt[1:]; + return opt; + } + + if (ctxt.args == nil) + return 0; + + nextarg := (hd ctxt.args).word; + if (len nextarg < 2 || nextarg[0] != '-') + return 0; + + if (nextarg == "--") { + ctxt.args = tl ctxt.args; + return 0; + } + + opt := nextarg[1]; + if (len nextarg > 2) + ctxt.curropt = nextarg[2:]; + ctxt.args = tl ctxt.args; + return opt; +} |
