aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/rc/exec.c')
-rw-r--r--sys/cmd/rc/exec.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
new file mode 100644
index 0000000..868b1dc
--- /dev/null
+++ b/sys/cmd/rc/exec.c
@@ -0,0 +1,576 @@
+#include "rc.h"
+#include "exec.h"
+
+#include <sys/wait.h>
+
+int yyparse(void);
+
+struct Builtin{
+ char *name;
+ void (*func)(void);
+};
+
+// -----------------------------------------------------------------------
+// globals
+
+static Word nullpath = { .str="", .link=nil };
+
+struct Builtin builtin[]={
+ {".", xdot},
+ 0,
+};
+
+/* stub out until we need */
+void Xasync(void){}
+void Xconcatenate(void){}
+void Xexit(void){}
+void Xfunc(void){}
+void Xfor(void){}
+void Xglob(void){}
+void Xjump(void){}
+void Xmatch(void){}
+void Xpipe(void){}
+void Xread(void){}
+// -----------------------------------------------------------------------
+// internal
+
+/* words and lists */
+
+static
+void
+pushword(char *str)
+{
+ if(!shell->args)
+ fatal("attempt to push on empty argument stack");
+
+ shell->args->word = makeword(str, shell->args->word);
+}
+
+static
+void
+popword(void)
+{
+ Word *w;
+ if(!shell->args)
+ fatal("tried to pop word on empty argument stack");
+
+ w = shell->args->word;
+ if(!w)
+ fatal("tried to pop word but nothing there");
+
+ shell->args->word = w->link;
+ efree(w->str);
+ efree(w);
+}
+
+static
+Word*
+copywords(Word *a, Word *tail)
+{
+ Word *v = nil, **end;
+
+ for(end=&v; a; a = a->link,end=&(*end)->link)
+ *end = makeword(a->str, nil);
+ *end = tail;
+
+ return v;
+}
+
+static
+void
+freewords(Word *w)
+{
+ Word *n;
+ while(w){
+ efree(w->str);
+ n = w->link;
+ efree(w);
+ w = n;
+ }
+}
+
+static
+void
+freelist(Word *w)
+{
+ Word *n;
+ while(w){
+ n = w->link;
+ efree(w->str);
+ efree(w);
+ w = n;
+ }
+
+}
+
+static
+void
+pushlist(void)
+{
+ List *stack = emalloc(sizeof(*stack));
+
+ stack->word = nil;
+ stack->link = shell->args;
+
+ shell->args = stack;
+}
+
+static
+void
+poplist(void)
+{
+ List *stack = shell->args;
+ if(!stack)
+ fatal("attempted to pop an empty argument stack");
+
+ freelist(stack->word);
+ shell->args = stack->link;
+ efree(stack);
+}
+
+/* system interop */
+static
+Word*
+path(char *w)
+{
+ Word *path;
+
+ if(strncmp(w, "/", 1)==0
+ || strncmp(w, "./", 2)==0
+ || strncmp(w, "../", 3)==0
+ || (path = var("path")->val)==0)
+ path=&nullpath;
+
+ return path;
+}
+
+static
+void
+xx(void)
+{
+ popword(); // "exec"
+ if(!shell->args->word){
+ Xerror("empty argument list");
+ return;
+ }
+
+ execute(shell->args->word, path(shell->args->word->str));
+ poplist();
+}
+
+static
+int
+xforkx(void)
+{
+ int n, pid;
+ char buf[ERRMAX];
+
+ switch(pid=fork()){
+ case -1:
+ return -1;
+ case 0: // child
+ clearwait();
+ pushword("exec");
+ xx();
+ exit(1);
+ /*unreachable*/
+ default:
+ addwait(pid);
+ return pid;
+ }
+}
+
+/* redirections */
+void
+pushredir(int type, int from, int to)
+{
+ Redir *r = emalloc(sizeof(*r));
+
+ r->type = type;
+ r->from = from;
+ r->to = to;
+ r->link = shell->redir;
+
+ shell->redir = r;
+}
+
+/* byte code */
+static
+void
+run(Code *c, int pc, Var *local)
+{
+ Thread *new = emalloc(sizeof(*new));
+
+ new->code.i = pc;
+ new->code.exe = copycode(c);
+ new->args = nil;
+ new->local = local;
+ new->cmd.path = nil;
+ new->cmd.io = nil;
+ new->flag.eof = 0;
+ new->line = 1;
+ new->link = shell;
+
+ shell = new;
+}
+
+// -----------------------------------------------------------------------
+// exported builtins
+
+// XXX: find a better place for these
+Word*
+makeword(char *str, Word *link)
+{
+ Word *w = emalloc(sizeof(*w));
+
+ w->str = strdup(str);
+ w->link = link;
+
+ return w;
+}
+
+void
+freeword(Word *word)
+{
+ Word *n;
+
+ while(word){
+ efree(word->str);
+ n = word->link;
+ efree(word);
+ word = n;
+ }
+}
+
+int
+count(Word *w)
+{
+ int n;
+ for(n = 0; w; n++)
+ w = w->link;
+ return n;
+}
+
+// -----------------------------------------------------------------------
+// builtins
+
+static Code dotcmd[14] =
+{
+ [0] = {.i = 1},
+ [1] = {.f = Xmark},
+ [2] = {.f = Xword},
+ [3] = {.s = "0"},
+ [4] = {.f = Xlocal},
+ [5] = {.f = Xmark},
+ [6] = {.f = Xword},
+ [7] = {.s = "*"},
+ [8] = {.f = Xlocal},
+ [9] = {.f = Xreadcmd},
+ [10] = {.f = Xunlocal},
+ [11] = {.f = Xunlocal},
+ [12] = {.f = Xreturn},
+};
+
+void
+xdot(void)
+{
+ Word *p;
+ List *argv;
+ char *base;
+ int fd, iflag = 0;
+ Thread *old;
+ char file[512];
+
+ old = shell;
+ popword();
+#if 0
+ if(old->args->word && strcmp(old->args->word->str, "-i")==0){
+ iflag = 1;
+ popword();
+ }
+#endif
+ /* get input file */
+ if(!old->args->word){
+ Xerror("usage: . [-i] file [arg ...]\n");
+ return;
+ }
+
+ base = strdup(old->args->word->str);
+ popword();
+ for(fd=-1, p=path(base); p ; p = p->link){
+ strcpy(file, p->str);
+
+ if(file[0])
+ strcat(file, "/");
+ strcat(file, base);
+
+ if((fd = open(file, 0))>=0)
+ break;
+ }
+
+ if(fd<0){
+ print(errio, "%s: ", base);
+ //setstatus("can't open");
+ Xerror(".: can't open\n");
+ return;
+ }
+ /* set up for a new command loop */
+ run(dotcmd, 1, nil);
+ pushredir(Rclose, fd, 0);
+
+ shell->cmd.path = base;
+ shell->cmd.io = openfd(fd);
+
+ /* push $* value */
+ pushlist();
+ shell->args->word = old->args->word;
+
+ /* free caller's copy of $* */
+ argv = old->args;
+ old->args = argv->link;
+ efree(argv);
+
+ /* push $0 value */
+ pushlist();
+ pushword(base);
+ //ndot++;
+}
+
+void
+xboot(int argc, char *argv[])
+{
+ int i;
+ Code bootstrap[32];
+ char num[12];
+
+ i = 0;
+ bootstrap[i++].i = 1;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xword;
+ bootstrap[i++].s="*";
+ bootstrap[i++].f = Xassign;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xword;
+ bootstrap[i++].s="*";
+ bootstrap[i++].f = Xdollar;
+ bootstrap[i++].f = Xword;
+ bootstrap[i++].s = "/dev/stdin";
+ bootstrap[i++].f = Xword;
+ bootstrap[i++].s=".";
+ bootstrap[i++].f = Xbasic;
+ bootstrap[i++].f = Xexit;
+ bootstrap[i].i = 0;
+
+ run(bootstrap, 1, nil);
+ pushlist(); // prime bootstrap argv
+
+ argv0 = strdup(argv[0]);
+ for(i = argc-1; i > 0; --i)
+ pushword(argv[i]);
+
+ /* interpreter loop */
+ for(;;){
+ shell->code.i++;
+ (*shell->code.exe[shell->code.i-1].f)();
+ }
+}
+
+// -----------------------------------------------------------------------
+// exported interpreter bytecode
+
+void
+Xmark(void)
+{
+ pushlist();
+}
+
+void
+Xerror(char *msg)
+{
+ print(errio, "rc: %s", msg);
+ flush(errio);
+ while(!shell->flag.i)
+ Xreturn();
+}
+
+void
+Xreturn(void)
+{
+ Thread *run = shell;
+
+ printf("returning\n");
+
+ while(run->args)
+ poplist();
+ freecode(run->code.exe);
+
+ shell = run->link;
+ efree(run);
+ if(!shell)
+ exit(0);
+}
+
+void
+Xword(void)
+{
+ pushword(shell->code.exe[shell->code.i++].s);
+}
+
+void
+Xdollar(void)
+{
+ int n;
+ char *s, *t;
+ Word *a, *star;
+
+ if(count(shell->args->word)!=1){
+ Xerror("variable name not singleton!\n");
+ return;
+ }
+ s = shell->args->word->str;
+ // deglob(s);
+ n = 0;
+
+ for(t = s;'0'<=*t && *t<='9';t++)
+ n = n*10+*t-'0';
+
+ a = shell->args->link->word;
+
+ if(n==0 || *t)
+ a = copywords(var(s)->val, a);
+ else{
+ star = var("*")->val;
+ if(star && 1<=n && n<=count(star)){
+ while(--n)
+ star = star->link;
+
+ a = makeword(star->str, a);
+ }
+ }
+
+ poplist();
+ shell->args->word = a;
+}
+
+void
+Xassign(void)
+{
+ Var *v;
+
+ if(count(shell->args->word)!=1){
+ Xerror("variable name not singleton!\n");
+ return;
+ }
+ //deglob(runq->argv->words->word);
+ v = var(shell->args->word->str);
+ poplist();
+
+ //globlist();
+ freewords(v->val);
+ v->val = shell->args->word;
+ v->new = 1;
+ if(v->update)
+ v->update(v);
+
+ shell->args->word = nil;
+ poplist();
+}
+
+
+void
+Xreadcmd(void)
+{
+ Thread *root;
+ Word *prompt;
+
+ flush(errio);
+ root = shell;
+
+ if(yyparse()){
+ exit(1);
+ }else{
+ --root->code.i; /* re-execute Xreadcmd after codebuf runs */
+ run(compiled, 1, root->local);
+ }
+
+ freeparsetree();
+}
+
+void
+Xlocal(void)
+{
+ if(count(shell->args->word)!=1){
+ Xerror("variable name must be singleton\n");
+ return;
+ }
+ //deglob(shell->args->word->str);
+
+ shell->local = makevar(strdup(shell->args->word->str), shell->local);
+ shell->local->val = copywords(shell->args->link->word, nil);
+ shell->local->new = 1;
+
+ poplist();
+ poplist();
+}
+
+void
+Xunlocal(void)
+{
+ Var *v = shell->local, *hide;
+ if(!v)
+ fatal("Xunlocal: no locals!", 0);
+
+ printf("unlocal\n");
+
+ shell->local = v->link;
+ hide = var(v->name);
+ hide->new = 1;
+
+ efree(v->name);
+ freewords(v->val);
+ efree(v);
+}
+
+void
+Xbasic(void)
+{
+ Var *v;
+ Word *arg;
+ int pid, status;
+ struct Builtin *b;
+
+ arg = shell->args->word;
+ if(!arg){
+ Xerror("empty argument list\n");
+ return;
+ }
+ print(errio, "recieved arg: %v\n", arg); // for debugging
+ flush(errio);
+
+ v = var(arg->str);
+ if(v->func){
+ // xfunc(v);
+ return;
+ }
+ // see if it matches a builtin
+ for(b = builtin; b->name; b++){
+ if(strcmp(b->name, arg->str)==0){
+ b->func();
+ return;
+ }
+ }
+
+ // run the external command
+ if((pid = xforkx()) < 0) {
+ Xerror("try again");
+ return;
+ }
+
+ poplist();
+ do{
+ waitpid(pid, &status, 0);
+ } while(!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ printf("done waiting\n");
+}