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)
125 * get command line flags, initialize keywords & traps.
126 * get values from environment.
127 * set $pid, $cflag, $*
128 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
129 * start interpreting code
133 main(int argc, char *argv[])
136 char num[12], *rcmain;
138 argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
140 usage("[file [arg ...]]");
145 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
146 rcmain = flag['m']?flag['m'][0]:Rcmain;
151 inttoascii(num, mypid = getpid());
152 setvar("pid", newword(num, (word *)0));
153 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
155 setvar("rcname", newword(argv[0], (word *)0));
157 bootstrap[i++].i = 1;
158 bootstrap[i++].f = Xmark;
159 bootstrap[i++].f = Xword;
160 bootstrap[i++].s="*";
161 bootstrap[i++].f = Xassign;
162 bootstrap[i++].f = Xmark;
163 bootstrap[i++].f = Xmark;
164 bootstrap[i++].f = Xword;
165 bootstrap[i++].s="*";
166 bootstrap[i++].f = Xdol;
167 bootstrap[i++].f = Xword;
168 bootstrap[i++].s = rcmain;
169 bootstrap[i++].f = Xword;
170 bootstrap[i++].s=".";
171 bootstrap[i++].f = Xsimple;
172 bootstrap[i++].f = Xexit;
174 start(bootstrap, 1, (var *)0);
175 /* prime bootstrap argv */
177 argv0 = strdup(argv[0]);
178 for(i = argc-1;i!=0;--i) pushword(argv[i]);
183 (*runq->code[runq->pc-1].f)();
190 * Arguments on stack (...)
191 * Arguments in line [...]
192 * Code in line with jump around {...}
194 * Xappend(file)[fd] open file to append
195 * Xassign(name, val) assign val to name
196 * Xasync{... Xexit} make thread for {}, no wait
197 * Xbackq{... Xreturn} make thread for {}, push stdout
198 * Xbang complement condition
199 * Xcase(pat, value){...} exec code on match, leave (value) on
201 * Xclose[i] close file descriptor
202 * Xconc(left, right) concatenate, push results
203 * Xcount(name) push var count
204 * Xdelfn(name) delete function definition
205 * Xdeltraps(names) delete named traps
206 * Xdol(name) get variable value
207 * Xqdol(name) concatenate variable components
208 * Xdup[i j] dup file descriptor
209 * Xexit rc exits with status
210 * Xfalse{...} execute {} if false
211 * Xfn(name){... Xreturn} define function
212 * Xfor(var, list){... Xreturn} for loop
214 * Xlocal(name, val) create local variable, assign value
216 * Xmatch(pat, str) match pattern, set status
217 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
219 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
220 * depending on type), push /dev/fd/??
221 * Xpopm(value) pop value from stack
222 * Xrdwr(file)[fd] open file for reading and writing
223 * Xread(file)[fd] open file to read
224 * Xsettraps(names){... Xreturn} define trap functions
225 * Xshowtraps print trap list
226 * Xsimple(args) run command and wait
227 * Xreturn kill thread
228 * Xsubshell{... Xexit} execute {} in a subshell and wait
229 * Xtrue{...} execute {} if true
230 * Xunlocal delete local variable
231 * Xword[string] push string
232 * Xwrite(file)[fd] open file to write
240 switch(count(runq->argv->words)){
242 Xerror1(">> requires singleton");
245 Xerror1(">> requires file");
250 file = runq->argv->words->word;
251 if((f = open(file, 1))<0 && (f = Creat(file))<0){
252 pfmt(err, "%s: ", file);
253 Xerror("can't open");
257 pushredir(ROPEN, f, runq->code[runq->pc].i);
271 setstatus(truestatus()?"false":"");
277 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
284 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
291 if(eflagok && !truestatus()) Xexit();
298 struct word *starval;
299 static int beenhere = 0;
300 if(getpid()==mypid && !beenhere){
301 trapreq = vlook("sigexit");
305 starval = vlook("*")->val;
306 start(trapreq->fn, trapreq->pc, (struct var *)0);
307 runq->local = newvar(strdup("*"), runq->local);
308 runq->local->val = copywords(starval, (struct word *)0);
309 runq->local->changed = 1;
310 runq->redir = runq->startredir = 0;
320 if(truestatus()) runq->pc = runq->code[runq->pc].i;
323 int ifnot; /* dynamic if not flag */
331 runq->pc = runq->code[runq->pc].i;
337 runq->pc = runq->code[runq->pc].i;
357 switch(count(runq->argv->words)){
359 Xerror1("< requires singleton\n");
362 Xerror1("< requires file\n");
367 file = runq->argv->words->word;
368 if((f = open(file, 0))<0){
369 pfmt(err, "%s: ", file);
370 Xerror("can't open");
373 pushredir(ROPEN, f, runq->code[runq->pc].i);
384 switch(count(runq->argv->words)){
386 Xerror1("<> requires singleton\n");
389 Xerror1("<> requires file\n");
394 file = runq->argv->words->word;
395 if((f = open(file, ORDWR))<0){
396 pfmt(err, "%s: ", file);
397 Xerror("can't open");
400 pushredir(ROPEN, f, runq->code[runq->pc].i);
408 while(runq->redir!=runq->startredir)
415 struct redir *rp = runq->redir;
417 panic("turfredir null!", 0);
418 runq->redir = rp->next;
427 struct thread *p = runq;
429 while(p->argv) poplist();
440 if(truestatus()) runq->pc++;
441 else runq->pc = runq->code[runq->pc].i;
448 if(truestatus()) runq->pc++;
449 else runq->pc = runq->code[runq->pc].i;
461 pushword(runq->code[runq->pc++].s);
469 switch(count(runq->argv->words)){
471 Xerror1("> requires singleton\n");
474 Xerror1("> requires file\n");
479 file = runq->argv->words->word;
480 if((f = Creat(file))<0){
481 pfmt(err, "%s: ", file);
482 Xerror("can't open");
485 pushredir(ROPEN, f, runq->code[runq->pc].i);
491 list2str(word *words)
496 for(ap = words;ap;ap = ap->next)
497 len+=1+strlen(ap->word);
498 value = emalloc(len+1);
500 for(ap = words;ap;ap = ap->next){
501 for(t = ap->word;*t;) *s++=*t++;
515 subject = list2str(runq->argv->words);
516 setstatus("no match");
517 for(p = runq->argv->next->words;p;p = p->next)
518 if(match(subject, p->word, '\0')){
533 s = list2str(runq->argv->next->words);
534 for(p = runq->argv->words;p;p = p->next){
535 if(match(s, p->word, '\0')){
544 runq->pc = runq->code[runq->pc].i;
549 conclist(word *lp, word *rp, word *tail)
553 if(lp->next || rp->next)
554 tail = conclist(lp->next==0? lp: lp->next,
555 rp->next==0? rp: rp->next, tail);
556 buf = emalloc(strlen(lp->word)+strlen((char *)rp->word)+1);
557 strcpy(buf, lp->word);
558 strcat(buf, rp->word);
559 v = newword(buf, tail);
567 word *lp = runq->argv->words;
568 word *rp = runq->argv->next->words;
569 word *vp = runq->argv->next->next->words;
570 int lc = count(lp), rc = count(rp);
573 Xerror1("null list in concatenation");
576 if(lc!=1 && rc!=1 && lc!=rc){
577 Xerror1("mismatched list lengths in concatenation");
580 vp = conclist(lp, rp, vp);
584 runq->argv->words = vp;
591 if(count(runq->argv->words)!=1){
592 Xerror1("variable name not singleton!");
595 deglob(runq->argv->words->word);
596 v = vlook(runq->argv->words->word);
600 v->val = runq->argv->words;
602 runq->argv->words = 0;
606 * copy arglist a, adding the copy to the front of tail
610 copywords(word *a, word *tail)
613 for(end=&v;a;a = a->next,end=&(*end)->next)
614 *end = newword(a->word, 0);
625 if(count(runq->argv->words)!=1){
626 Xerror1("variable name not singleton!");
629 s = runq->argv->words->word;
632 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
633 a = runq->argv->next->words;
635 a = copywords(vlook(s)->val, a);
637 star = vlook("*")->val;
638 if(star && 1<=n && n<=count(star)){
639 while(--n) star = star->next;
640 a = newword(star->word, a);
644 runq->argv->words = a;
653 if(count(runq->argv->words)!=1){
654 Xerror1("variable name not singleton!");
657 s = runq->argv->words->word;
666 for(p = a;p;p = p->next) n+=strlen(p->word);
670 for(p = a->next;p;p = p->next){
682 copynwords(word *a, word *tail, int n)
689 *end = newword(a->word, 0);
698 subwords(word *val, int len, word *sub, word *a)
704 a = subwords(val, len, sub->next, a);
709 while('0'<=*s && *s<='9')
715 while('0'<=*s && *s<='9')
720 if(n<1 || n>len || m<0)
726 return copynwords(val, a, m+1);
734 if(count(runq->argv->next->words)!=1){
735 Xerror1("variable name not singleton!");
738 s = runq->argv->next->words->word;
740 a = runq->argv->next->next->words;
742 a = subwords(v, count(v), runq->argv->words, a);
745 runq->argv->words = a;
755 if(count(runq->argv->words)!=1){
756 Xerror1("variable name not singleton!");
759 s = runq->argv->words->word;
762 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
765 inttoascii(num, count(a));
769 inttoascii(num, a && 1<=n && n<=count(a)?1:0);
778 if(count(runq->argv->words)!=1){
779 Xerror1("variable name must be singleton\n");
782 deglob(runq->argv->words->word);
783 runq->local = newvar(strdup(runq->argv->words->word), runq->local);
786 runq->local->val = runq->argv->words;
787 runq->local->changed = 1;
788 runq->argv->words = 0;
795 var *v = runq->local, *hid;
797 panic("Xunlocal: no locals!", 0);
798 runq->local = v->next;
799 hid = vlook(v->name);
824 end = runq->code[runq->pc].i;
826 for(a = runq->argv->words;a;a = a->next){
830 v->fn = codecopy(runq->code);
843 for(a = runq->argv->words;a;a = a->next){
854 concstatus(char *s, char *t)
856 static char v[NSTATUS+1];
858 strncpy(v, s, NSTATUS);
861 strncpy(v+n+1, t, NSTATUS-n-1);
870 char status[NSTATUS+1];
872 setstatus(concstatus(runq->status, getstatus()));
874 strncpy(status, getstatus(), NSTATUS);
875 status[NSTATUS]='\0';
876 Waitfor(runq->pid, 1);
878 setstatus(concstatus(getstatus(), status));
885 struct thread *p = runq;
889 if(flag['s'] && !truestatus())
890 pfmt(err, "status=%v\n", vlook("status")->val);
892 prompt = vlook("prompt")->val;
894 promptstr = prompt->word;
900 if(!p->iflag || p->eof && !Eintr()){
904 Xreturn(); /* should this be omitted? */
911 --p->pc; /* go back for next command */
915 ntrap = 0; /* avoid double-interrupts during blocked writes */
916 --p->pc; /* re-execute Xrdcmds after codebuf runs */
917 start(codebuf, 1, runq->local);
925 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
926 pfmt(err, "rc: %s: %r\n", s);
928 pfmt(err, "rc (%s): %s: %r\n", argv0, s);
931 while(!runq->iflag) Xreturn();
937 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
938 pfmt(err, "rc: %s\n", s);
940 pfmt(err, "rc (%s): %s\n", argv0, s);
943 while(!runq->iflag) Xreturn();
949 setvar("status", newword(s, (word *)0));
955 var *status = vlook("status");
956 return status->val?status->val->word:"";
963 for(s = getstatus();*s;s++)
964 if(*s!='|' && *s!='0')
972 Unlink(runq->code[runq->pc++].s);
978 if(runq->argv->words==0){
980 runq->pc = runq->code[runq->pc].i;
983 freelist(runq->local->val);
984 runq->local->val = runq->argv->words;
985 runq->local->changed = 1;
986 runq->argv->words = runq->argv->words->next;
987 runq->local->val->next = 0;