summaryrefslogtreecommitdiff
path: root/appl/cmd/mash/builtins.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/mash/builtins.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/mash/builtins.b')
-rw-r--r--appl/cmd/mash/builtins.b347
1 files changed, 347 insertions, 0 deletions
diff --git a/appl/cmd/mash/builtins.b b/appl/cmd/mash/builtins.b
new file mode 100644
index 00000000..b4374581
--- /dev/null
+++ b/appl/cmd/mash/builtins.b
@@ -0,0 +1,347 @@
+implement Mashbuiltin;
+
+#
+# "builtins" builtin, defines:
+#
+# env - print environment or individual elements
+# eval - interpret arguments as mash input
+# exit - exit toplevel, eval or subshell
+# load - load a builtin
+# prompt - print or set prompt
+# quote - print arguments quoted as input for mash
+# run - interpret a file as mash input
+# status - report existence of error output
+# time - time the execution of a command
+# whatis - print variable, function and builtin
+#
+
+include "mash.m";
+include "mashparse.m";
+
+mashlib: Mashlib;
+
+Cmd, Env, Stab: import mashlib;
+sys, bufio: import mashlib;
+
+Iobuf: import bufio;
+
+#
+# Interface to catch the use as a command.
+#
+init(nil: ref Draw->Context, nil: list of string)
+{
+ ssys := load Sys Sys->PATH;
+ ssys->fprint(ssys->fildes(2), "builtins: cannot run as a command\n");
+ raise "fail: error";
+}
+
+#
+# Used by whatis.
+#
+name(): string
+{
+ return "builtins";
+}
+
+#
+# Install commands.
+#
+mashinit(nil: list of string, lib: Mashlib, this: Mashbuiltin, e: ref Env)
+{
+ mashlib = lib;
+ e.defbuiltin("env", this);
+ e.defbuiltin("eval", this);
+ e.defbuiltin("exit", this);
+ e.defbuiltin("load", this);
+ e.defbuiltin("prompt", this);
+ e.defbuiltin("quote", this);
+ e.defbuiltin("run", this);
+ e.defbuiltin("status", this);
+ e.defbuiltin("time", this);
+ e.defbuiltin("whatis", this);
+}
+
+#
+# Execute a builtin.
+#
+mashcmd(e: ref Env, l: list of string)
+{
+ case hd l {
+ "env" =>
+ l = tl l;
+ if (l == nil) {
+ out := e.outfile();
+ if (out == nil)
+ return;
+ prsymbs(out, e.global, "=");
+ prsymbs(out, e.local, ":=");
+ out.close();
+ } else
+ e.usage("env");
+ "eval" =>
+ eval(e, tl l);
+ "exit" =>
+ raise mashlib->EXIT;
+ "load" =>
+ l = tl l;
+ if (len l == 1)
+ e.doload(hd l);
+ else
+ e.usage("load file");
+ "prompt" =>
+ l = tl l;
+ case len l {
+ 0 =>
+ mashlib->prprompt(0);
+ 1 =>
+ mashlib->prompt = hd l;
+ 2 =>
+ mashlib->prompt = hd l;
+ mashlib->contin = hd tl l;
+ * =>
+ e.usage("prompt [string]");
+ }
+ "quote" =>
+ l = tl l;
+ if (l != nil) {
+ out := e.outfile();
+ if (out == nil)
+ return;
+ f := 0;
+ while (l != nil) {
+ if (f)
+ out.putc(' ');
+ else
+ f = 1;
+ out.puts(mashlib->quote(hd l));
+ l = tl l;
+ }
+ out.putc('\n');
+ out.close();
+ }
+ "run" =>
+ if (!run(e, tl l))
+ e.usage("run [-] [-denx] file [arg ...]");
+ "status" =>
+ l = tl l;
+ if (l != nil)
+ status(e, l);
+ else
+ e.usage("status cmd [arg ...]");
+ "time" =>
+ l = tl l;
+ if (l != nil)
+ time(e, l);
+ else
+ e.usage("time cmd [arg ...]");
+ "whatis" =>
+ l = tl l;
+ if (l != nil) {
+ out := e.outfile();
+ if (out == nil)
+ return;
+ while (l != nil) {
+ whatis(e, out, hd l);
+ l = tl l;
+ }
+ out.close();
+ }
+ }
+}
+
+#
+# Print a variable and its value.
+#
+prone(out: ref Iobuf, eq, s: string, v: list of string)
+{
+ out.puts(s);
+ out.putc(' ');
+ out.puts(eq);
+ if (v != mashlib->empty) {
+ do {
+ out.putc(' ');
+ out.puts(mashlib->quote(hd v));
+ v = tl v;
+ } while (v != nil);
+ }
+ out.puts(";\n");
+}
+
+#
+# Print the contents of a symbol table.
+#
+prsymbs(out: ref Iobuf, t: ref Stab, eq: string)
+{
+ if (t == nil)
+ return;
+ for (l := t.all(); l != nil; l = tl l) {
+ s := hd l;
+ v := s.value;
+ if (v != nil)
+ prone(out, eq, s.name, v);
+ }
+}
+
+#
+# Print variables, functions and builtins.
+#
+whatis(e: ref Env, out: ref Iobuf, s: string)
+{
+ f := 0;
+ v := e.global.find(s);
+ if (v != nil) {
+ if (v.value != nil)
+ prone(out, "=", s, v.value);
+ if (v.func != nil) {
+ out.puts("fn ");
+ out.puts(s);
+ out.puts(" { ");
+ out.puts(v.func.text());
+ out.puts(" };\n");
+ }
+ if (v.builtin != nil) {
+ out.puts("load ");
+ out.puts(v.builtin->name());
+ out.puts("; ");
+ out.puts(s);
+ out.puts(";\n");
+ }
+ f = 1;
+ }
+ if (e.local != nil) {
+ v = e.local.find(s);
+ if (v != nil) {
+ prone(out, ":=", s, v.value);
+ f = 1;
+ }
+ }
+ if (!f) {
+ out.puts(s);
+ out.puts(": not found\n");
+ }
+}
+
+#
+# Catenate arguments and interpret as mash input.
+#
+eval(e: ref Env, l: list of string)
+{
+ s: string;
+ while (l != nil) {
+ s = s + " " + hd l;
+ l = tl l;
+ }
+ e = e.copy();
+ e.flags &= ~mashlib->EInter;
+ e.sopen(s);
+ mashlib->parse->parse(e);
+}
+
+#
+# Interpret file as mash input.
+#
+run(e: ref Env, l: list of string): int
+{
+ f := 0;
+ if (l == nil)
+ return 0;
+ e = e.copy();
+ s := hd l;
+ while (s[0] == '-') {
+ if (s == "-")
+ f = 1;
+ else {
+ for (i := 1; i < len s; i++) {
+ case s[i] {
+ 'd' =>
+ e.flags |= mashlib->EDumping;
+ 'e' =>
+ e.flags |= mashlib->ERaise;
+ 'n' =>
+ e.flags |= mashlib->ENoxeq;
+ 'x' =>
+ e.flags |= mashlib->EEcho;
+ * =>
+ return 0;
+ }
+ }
+ }
+ l = tl l;
+ if (l == nil)
+ return 0;
+ s = hd l;
+ }
+ fd := sys->open(s, Sys->OREAD);
+ if (fd == nil) {
+ err := mashlib->errstr();
+ if (mashlib->nonexistent(err) && s[0] != '/' && s[0:2] != "./") {
+ fd = sys->open(mashlib->LIB + s, Sys->OREAD);
+ if (fd == nil)
+ err = mashlib->errstr();
+ else
+ s = mashlib->LIB + s;
+ }
+ if (fd == nil) {
+ if (!f)
+ e.report(s + ": " + err);
+ return 1;
+ }
+ }
+ e.local = Stab.new();
+ e.local.assign(mashlib->ARGS, tl l);
+ e.flags &= ~mashlib->EInter;
+ e.fopen(fd, s);
+ mashlib->parse->parse(e);
+ return 1;
+}
+
+#
+# Run a command and report true on no error output.
+#
+status(e: ref Env, l: list of string)
+{
+ in := child(e, l);
+ if (in == nil)
+ return;
+ b := array[256] of byte;
+ n := sys->read(in, b, len b);
+ if (n != 0) {
+ while (n > 0)
+ n = sys->read(in, b, len b);
+ if (n < 0)
+ e.couldnot("read", "pipe");
+ } else
+ e.output(Mashlib->TRUE);
+}
+
+#
+# Status env child.
+#
+child(e: ref Env, l: list of string): ref Sys->FD
+{
+ e = e.copy();
+ fds := e.pipe();
+ if (fds == nil)
+ return nil;
+ if (sys->dup(fds[0].fd, 2) < 0) {
+ e.couldnot("dup", "pipe");
+ return nil;
+ }
+ t := e.stderr;
+ e.stderr = fds[0];
+ e.runit(l, nil, nil, 0);
+ e.stderr = t;
+ sys->dup(t.fd, 2);
+ return fds[1];
+}
+
+#
+# Time the execution of a command.
+#
+time(e: ref Env, l: list of string)
+{
+ t1 := sys->millisec();
+ e.runit(l, nil, nil, 1);
+ t2 := sys->millisec();
+ sys->fprint(e.stderr, "%.4g\n", real (t2 - t1) / 1000.0);
+}