summaryrefslogtreecommitdiff
path: root/appl/cmd/sh/arg.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/sh/arg.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/sh/arg.b')
-rw-r--r--appl/cmd/sh/arg.b181
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;
+}