#include "rc.h" #include "exec.h" #include 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"); }