7 * Start executing the given code at the given pc with the given redirection
12 start(code *c, int pc, var *local)
14 struct thread *p = new(struct thread);
16 p->code = codecopy(c);
19 p->redir = p->startredir = runq?runq->redir:0;
31 newword(char *wd, word *next)
43 panic("pushword but no argv!", 0);
44 runq->argv->words = newword(wd, runq->argv->words);
52 panic("popword but no argv!", 0);
53 p = runq->argv->words;
55 panic("popword but no word!", 0);
56 runq->argv->words = p->next;
87 panic("poplist but no argv", 0);
97 for(n = 0;w;n++) w = w->next;
102 pushredir(int type, int from, int to)
104 redir * rp = new(redir);
108 rp->next = runq->redir;
113 newvar(char *name, var *next)
126 * get command line flags, initialize keywords & traps.
127 * get values from environment.
128 * set $pid, $cflag, $*
129 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
130 * start interpreting code
133 main(int argc, char *argv[])
136 char num[12], *rcmain;
139 /* needed for rcmain later */
140 putenv("PLAN9", unsharp("#9"));
142 argc = getflags(argc, argv, "DSYsrdiIlxepvVc:1m:1[command]", 1);
144 usage("[file [arg ...]]");
149 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
150 rcmain = flag['m'] ? flag['m'][0] : Rcmain();
155 inttoascii(num, mypid = getpid());
157 setvar("pid", newword(num, (word *)0));
158 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
160 setvar("rcname", newword(argv[0], (word *)0));
162 bootstrap[i++].i = 1;
163 bootstrap[i++].f = Xmark;
164 bootstrap[i++].f = Xword;
165 bootstrap[i++].s="*";
166 bootstrap[i++].f = Xassign;
167 bootstrap[i++].f = Xmark;
168 bootstrap[i++].f = Xmark;
169 bootstrap[i++].f = Xword;
170 bootstrap[i++].s="*";
171 bootstrap[i++].f = Xdol;
172 bootstrap[i++].f = Xword;
173 bootstrap[i++].s = rcmain;
174 bootstrap[i++].f = Xword;
175 bootstrap[i++].s=".";
176 bootstrap[i++].f = Xsimple;
177 bootstrap[i++].f = Xexit;
179 start(bootstrap, 1, (var *)0);
180 /* prime bootstrap argv */
182 argv0 = strdup(argv[0]);
183 for(i = argc-1;i!=0;--i) pushword(argv[i]);
188 (*runq->code[runq->pc-1].f)();
192 return 0; /* not reached; silence OS X Lion gcc */
196 * Arguments on stack (...)
197 * Arguments in line [...]
198 * Code in line with jump around {...}
200 * Xappend(file)[fd] open file to append
201 * Xassign(name, val) assign val to name
202 * Xasync{... Xexit} make thread for {}, no wait
203 * Xbackq{... Xreturn} make thread for {}, push stdout
204 * Xbang complement condition
205 * Xcase(pat, value){...} exec code on match, leave (value) on
207 * Xclose[i] close file descriptor
208 * Xconc(left, right) concatenate, push results
209 * Xcount(name) push var count
210 * Xdelfn(name) delete function definition
211 * Xdeltraps(names) delete named traps
212 * Xdol(name) get variable value
213 * Xqdol(name) concatenate variable components
214 * Xdup[i j] dup file descriptor
215 * Xexit rc exits with status
216 * Xfalse{...} execute {} if false
217 * Xfn(name){... Xreturn} define function
218 * Xfor(var, list){... Xreturn} for loop
220 * Xlocal(name, val) create local variable, assign value
222 * Xmatch(pat, str) match pattern, set status
223 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
225 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
226 * depending on type), push /dev/fd/??
227 * Xpopm(value) pop value from stack
228 * Xrdwr(file)[fd] open file for reading and writing
229 * Xread(file)[fd] open file to read
230 * Xsettraps(names){... Xreturn} define trap functions
231 * Xshowtraps print trap list
232 * Xsimple(args) run command and wait
233 * Xreturn kill thread
234 * Xsubshell{... Xexit} execute {} in a subshell and wait
235 * Xtrue{...} execute {} if true
236 * Xunlocal delete local variable
237 * Xword[string] push string
238 * Xwrite(file)[fd] open file to write
246 switch(count(runq->argv->words)){
248 Xerror1(">> requires singleton");
251 Xerror1(">> requires file");
256 file = runq->argv->words->word;
257 if((f = open(file, 1))<0 && (f = Creat(file))<0){
258 pfmt(err, "%s: ", file);
259 Xerror("can't open");
263 pushredir(ROPEN, f, runq->code[runq->pc].i);
277 setstatus(truestatus()?"false":"");
283 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
290 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
297 if(eflagok && !truestatus()) Xexit();
304 struct word *starval;
305 static int beenhere = 0;
306 if(getpid()==mypid && !beenhere){
307 trapreq = vlook("sigexit");
311 starval = vlook("*")->val;
312 start(trapreq->fn, trapreq->pc, (struct var *)0);
313 runq->local = newvar(strdup("*"), runq->local);
314 runq->local->val = copywords(starval, (struct word *)0);
315 runq->local->changed = 1;
316 runq->redir = runq->startredir = 0;
326 if(truestatus()) runq->pc = runq->code[runq->pc].i;
329 int ifnot; /* dynamic if not flag */
337 runq->pc = runq->code[runq->pc].i;
343 runq->pc = runq->code[runq->pc].i;
363 switch(count(runq->argv->words)){
365 Xerror1("< requires singleton\n");
368 Xerror1("< requires file\n");
373 file = runq->argv->words->word;
374 if((f = open(file, 0))<0){
375 pfmt(err, "%s: ", file);
376 Xerror("can't open");
379 pushredir(ROPEN, f, runq->code[runq->pc].i);
390 switch(count(runq->argv->words)){
392 Xerror1("<> requires singleton\n");
395 Xerror1("<> requires file\n");
400 file = runq->argv->words->word;
401 if((f = open(file, ORDWR))<0){
402 pfmt(err, "%s: ", file);
403 Xerror("can't open");
406 pushredir(ROPEN, f, runq->code[runq->pc].i);
414 while(runq->redir!=runq->startredir)
421 struct redir *rp = runq->redir;
423 panic("turfredir null!", 0);
424 runq->redir = rp->next;
433 struct thread *p = runq;
435 while(p->argv) poplist();
446 if(truestatus()) runq->pc++;
447 else runq->pc = runq->code[runq->pc].i;
454 if(truestatus()) runq->pc++;
455 else runq->pc = runq->code[runq->pc].i;
467 pushword(runq->code[runq->pc++].s);
475 switch(count(runq->argv->words)){
477 Xerror1("> requires singleton\n");
480 Xerror1("> requires file\n");
485 file = runq->argv->words->word;
486 if((f = Creat(file))<0){
487 pfmt(err, "%s: ", file);
488 Xerror("can't open");
491 pushredir(ROPEN, f, runq->code[runq->pc].i);
497 list2str(word *words)
502 for(ap = words;ap;ap = ap->next)
503 len+=1+strlen(ap->word);
504 value = emalloc(len+1);
506 for(ap = words;ap;ap = ap->next){
507 for(t = ap->word;*t;) *s++=*t++;
521 subject = list2str(runq->argv->words);
522 setstatus("no match");
523 for(p = runq->argv->next->words;p;p = p->next)
524 if(match(subject, p->word, '\0')){
539 s = list2str(runq->argv->next->words);
540 for(p = runq->argv->words;p;p = p->next){
541 if(match(s, p->word, '\0')){
550 runq->pc = runq->code[runq->pc].i;
555 conclist(word *lp, word *rp, word *tail)
559 if(lp->next || rp->next)
560 tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
562 buf = emalloc(strlen(lp->word)+strlen(rp->word)+1);
563 strcpy(buf, lp->word);
564 strcat(buf, rp->word);
565 v = newword(buf, tail);
573 word *lp = runq->argv->words;
574 word *rp = runq->argv->next->words;
575 word *vp = runq->argv->next->next->words;
576 int lc = count(lp), rc = count(rp);
579 Xerror1("null list in concatenation");
582 if(lc!=1 && rc!=1 && lc!=rc){
583 Xerror1("mismatched list lengths in concatenation");
586 vp = conclist(lp, rp, vp);
590 runq->argv->words = vp;
597 if(count(runq->argv->words)!=1){
598 Xerror1("variable name not singleton!");
601 deglob(runq->argv->words->word);
602 v = vlook(runq->argv->words->word);
606 v->val = runq->argv->words;
610 runq->argv->words = 0;
614 * copy arglist a, adding the copy to the front of tail
618 copywords(word *a, word *tail)
621 for(end=&v;a;a = a->next,end=&(*end)->next)
622 *end = newword(a->word, 0);
633 if(count(runq->argv->words)!=1){
634 Xerror1("variable name not singleton!");
637 s = runq->argv->words->word;
640 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
641 a = runq->argv->next->words;
643 a = copywords(vlook(s)->val, a);
645 star = vlook("*")->val;
646 if(star && 1<=n && n<=count(star)){
647 while(--n) star = star->next;
648 a = newword(star->word, a);
652 runq->argv->words = a;
661 if(count(runq->argv->words)!=1){
662 Xerror1("variable name not singleton!");
665 s = runq->argv->words->word;
674 for(p = a;p;p = p->next) n+=strlen(p->word);
678 for(p = a->next;p;p = p->next){
690 copynwords(word *a, word *tail, int n)
697 *end = newword(a->word, 0);
706 subwords(word *val, int len, word *sub, word *a)
712 a = subwords(val, len, sub->next, a);
717 while('0'<=*s && *s<='9')
723 while('0'<=*s && *s<='9')
728 if(n<1 || n>len || m<0)
734 return copynwords(val, a, m+1);
742 if(count(runq->argv->next->words)!=1){
743 Xerror1("variable name not singleton!");
746 s = runq->argv->next->words->word;
748 a = runq->argv->next->next->words;
750 a = subwords(v, count(v), runq->argv->words, a);
753 runq->argv->words = a;
763 if(count(runq->argv->words)!=1){
764 Xerror1("variable name not singleton!");
767 s = runq->argv->words->word;
770 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
773 inttoascii(num, count(a));
777 inttoascii(num, a && 1<=n && n<=count(a)?1:0);
786 if(count(runq->argv->words)!=1){
787 Xerror1("variable name must be singleton\n");
790 deglob(runq->argv->words->word);
791 runq->local = newvar(strdup(runq->argv->words->word), runq->local);
792 runq->local->val = copywords(runq->argv->next->words, (word *)0);
793 runq->local->changed = 1;
801 var *v = runq->local, *hid;
803 panic("Xunlocal: no locals!", 0);
804 runq->local = v->next;
805 hid = vlook(v->name);
830 end = runq->code[runq->pc].i;
831 for(a = runq->argv->words;a;a = a->next){
835 v->fn = codecopy(runq->code);
848 for(a = runq->argv->words;a;a = a->next){
859 concstatus(char *s, char *t)
861 static char v[NSTATUS+1];
863 strncpy(v, s, NSTATUS);
866 strncpy(v+n+1, t, NSTATUS-n-1);
875 char status[NSTATUS+1];
877 setstatus(concstatus(runq->status, getstatus()));
879 strncpy(status, getstatus(), NSTATUS);
880 status[NSTATUS]='\0';
881 Waitfor(runq->pid, 1);
883 setstatus(concstatus(getstatus(), status));
890 struct thread *p = runq;
894 if(flag['s'] && !truestatus())
895 pfmt(err, "status=%v\n", vlook("status")->val);
897 prompt = vlook("prompt")->val;
899 promptstr = prompt->word;
904 if((flag['Y'] ? yyparse : parse)()){
905 if(!p->iflag || p->eof && !Eintr()){
909 Xreturn(); /* should this be omitted? */
916 --p->pc; /* go back for next command */
920 ntrap = 0; /* avoid double-interrupts during blocked writes */
921 --p->pc; /* re-execute Xrdcmds after codebuf runs */
922 start(codebuf, 1, runq->local);
930 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
931 pfmt(err, "rc: %s: %r\n", s);
933 pfmt(err, "rc (%s): %s: %r\n", argv0, s);
936 while(!runq->iflag) Xreturn();
942 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
943 pfmt(err, "rc: %s\n", s);
945 pfmt(err, "rc (%s): %s\n", argv0, s);
948 while(!runq->iflag) Xreturn();
954 setvar("status", newword(s, (word *)0));
960 var *status = vlook("status");
961 return status->val?status->val->word:"";
968 for(s = getstatus();*s;s++)
969 if(*s!='|' && *s!='0')
977 Unlink(runq->code[runq->pc++].s);
983 if(runq->argv->words==0){
985 runq->pc = runq->code[runq->pc].i;
988 freelist(runq->local->val);
989 runq->local->val = runq->argv->words;
990 runq->local->changed = 1;
991 runq->argv->words = runq->argv->words->next;
992 runq->local->val->next = 0;