summaryrefslogtreecommitdiff
path: root/appl/cmd/mash/misc.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/mash/misc.b')
-rw-r--r--appl/cmd/mash/misc.b313
1 files changed, 313 insertions, 0 deletions
diff --git a/appl/cmd/mash/misc.b b/appl/cmd/mash/misc.b
new file mode 100644
index 00000000..749f8be2
--- /dev/null
+++ b/appl/cmd/mash/misc.b
@@ -0,0 +1,313 @@
+#
+# Miscellaneous routines.
+#
+
+Cmd.cmd1(op: int, l: ref Cmd): ref Cmd
+{
+ return ref Cmd(op, nil, l, nil, nil, nil, nil, 0);
+}
+
+Cmd.cmd2(op: int, l, r: ref Cmd): ref Cmd
+{
+ return ref Cmd(op, nil, l, r, nil, nil, nil, 0);
+}
+
+Cmd.cmd1i(op: int, l: ref Cmd, i: ref Item): ref Cmd
+{
+ return ref Cmd(op, nil, l, nil, i, nil, nil, 0);
+}
+
+Cmd.cmd1w(op: int, l: ref Cmd, w: list of ref Item): ref Cmd
+{
+ return ref Cmd(op, w, l, nil, nil, nil, nil, 0);
+}
+
+Cmd.cmde(c: self ref Cmd, op: int, l, r: ref Cmd): ref Cmd
+{
+ c.op = op;
+ c.left = l;
+ c.right = r;
+ return c;
+}
+
+Cmd.cmdiw(op: int, i: ref Item, w: list of ref Item): ref Cmd
+{
+ return ref Cmd(op, revitems(w), nil, nil, i, nil, nil, 0);
+}
+
+Pin, Pout: con 1 << iota;
+
+rdmap := array[] of
+{
+ Rin => Pin,
+ Rout or Rappend => Pout,
+ Rinout => Pin | Pout,
+};
+
+rdsymbs := array[] of
+{
+ Rin => "<",
+ Rout => ">",
+ Rappend => ">>",
+ Rinout => "<>",
+};
+
+ionames := array[] of
+{
+ Pin => "input",
+ Pout => "ouput",
+ Pin | Pout => "input/output",
+};
+
+#
+# Check a pipeline for ambiguities.
+#
+Cmd.checkpipe(c: self ref Cmd, e: ref Env, f: int): int
+{
+ if (c.error)
+ return 0;
+ if (c.op == Cpipe) {
+ if (!c.left.checkpipe(e, f | Pout))
+ return 0;
+ if (!c.right.checkpipe(e, f | Pin))
+ return 0;
+ }
+ if (f) {
+ t := 0;
+ for (l := c.redirs; l != nil; l = tl l)
+ t |= rdmap[(hd l).op];
+ f &= t;
+ if (f) {
+ e.report(sys->sprint("%s redirection conflicts with pipe", ionames[f]));
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#
+# Update a command with another redirection.
+#
+Cmd.cmdio(c: self ref Cmd, e: ref Env, i: ref Item)
+{
+ f := 0;
+ for (l := c.redirs; l != nil; l = tl l)
+ f |= rdmap[(hd l).op];
+ r := i.redir;
+ f &= rdmap[r.op];
+ if (f != 0) {
+ e.report(sys->sprint("repeat %s redirection", ionames[f]));
+ c.error = 1;
+ }
+ c.redirs = r :: c.redirs;
+}
+
+#
+# Make a basic command.
+#
+Cmd.mkcmd(c: self ref Cmd, e: ref Env, async: int): ref Cmd
+{
+ if (!c.checkpipe(e, 0))
+ return nil;
+ if (async)
+ return ref Cmd(Casync, nil, c, nil, nil, nil, nil, 0);
+ else
+ return c;
+}
+
+#
+# Rotate parse tree of cases.
+#
+Cmd.rotcases(c: self ref Cmd): ref Cmd
+{
+ l := c;
+ c = nil;
+ while (l != nil) {
+ t := l.right;
+ l.right = c;
+ c = l;
+ l = l.left;
+ c.left = t;
+ }
+ return c;
+}
+
+Item.item1(op: int, l: ref Item): ref Item
+{
+ return ref Item(op, nil, l, nil, nil, nil);
+}
+
+Item.item2(op: int, l, r: ref Item): ref Item
+{
+ return ref Item(op, nil, l, r, nil, nil);
+}
+
+Item.itemc(op: int, c: ref Cmd): ref Item
+{
+ return ref Item(op, nil, nil, nil, c, nil);
+}
+
+#
+# Make an item from a list of strings.
+#
+Item.iteml(l: list of string): ref Item
+{
+ if (l != nil && tl l == nil)
+ return Item.itemw(hd l);
+ r: list of string;
+ while (l != nil) {
+ r = (hd l) :: r;
+ l = tl l;
+ }
+ c := ref Cmd;
+ c.op = Clist;
+ c.value = revstrs(r);
+ return Item.itemc(Iexpr, c);
+}
+
+Item.itemr(op: int, i: ref Item): ref Item
+{
+ return ref Item(Iredir, nil, nil, nil, nil, ref Redir(op, i));
+}
+
+qword: Word = (nil, Wquoted, (0, nil));
+
+Item.itemw(s: string): ref Item
+{
+ w := ref qword;
+ w.text = s;
+ return ref Item(Iword, w, nil, nil, nil, nil);
+}
+
+revitems(l: list of ref Item): list of ref Item
+{
+ r: list of ref Item;
+ while (l != nil) {
+ r = (hd l) :: r;
+ l = tl l;
+ }
+ return r;
+}
+
+revstrs(l: list of string): list of string
+{
+ r: list of string;
+ while (l != nil) {
+ r = (hd l) :: r;
+ l = tl l;
+ }
+ return r;
+}
+
+prepend(l: list of string, r: list of string): list of string
+{
+ while (r != nil) {
+ l = (hd r) :: l;
+ r = tl r;
+ }
+ return l;
+}
+
+concat(l: list of string): string
+{
+ s := hd l;
+ for (;;) {
+ l = tl l;
+ if (l == nil)
+ return s;
+ s += " ";
+ s += hd l;
+ }
+}
+
+#
+# Make an item list, no redirections allowed.
+#
+Env.mklist(e: self ref Env, l: list of ref Item): list of ref Item
+{
+ r: list of ref Item;
+ while (l != nil) {
+ i := hd l;
+ if (i.op == Iredir)
+ e.report("redirection in list");
+ else
+ r = i :: r;
+ l = tl l;
+ }
+ return r;
+}
+
+#
+# Make a simple command.
+#
+Env.mksimple(e: self ref Env, l: list of ref Item): ref Cmd
+{
+ r: list of ref Item;
+ c := ref Cmd;
+ c.op = Csimple;
+ c.error = 0;
+ while (l != nil) {
+ i := hd l;
+ if (i.op == Iredir)
+ c.cmdio(e, i);
+ else
+ r = i :: r;
+ l = tl l;
+ }
+ c.words = r;
+ return c;
+}
+
+Env.diag(e: self ref Env, s: string): string
+{
+ return where(e) + s;
+}
+
+Env.usage(e: self ref Env, s: string)
+{
+ e.report("usage: " + s);
+}
+
+Env.report(e: self ref Env, s: string)
+{
+ sys->fprint(e.stderr, "%s\n", e.diag(s));
+ if (e.flags & ERaise)
+ exits("error");
+}
+
+Env.error(e: self ref Env, s: string)
+{
+ e.report(s);
+ cleanup();
+}
+
+panic(s: string)
+{
+ raise "panic: " + s;
+}
+
+prprompt(n: int)
+{
+ case n {
+ 0 =>
+ sys->print("%s", prompt);
+ 1 =>
+ sys->print("%s", contin);
+ }
+}
+
+Env.couldnot(e: self ref Env, what, who: string)
+{
+ sys->fprint(e.stderr, "could not %s %s: %r\n", what, who);
+ exits("system error");
+}
+
+cleanup()
+{
+ exit;
+}
+
+exits(s: string)
+{
+ raise "fail: mash " + s;
+}