# # 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; }