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)
44 panic("pushword but no argv!", 0);
45 w = Newword(wd, runq->argv->words);
46 runq->argv->words = w;
51 newword(char *wd, word *next)
53 return Newword(estrdup(wd), next);
58 return Pushword(estrdup(wd));
66 panic("popword but no argv!", 0);
67 p = runq->argv->words;
69 panic("popword but no word!", 0);
70 runq->argv->words = p->next;
101 panic("poplist but no argv", 0);
103 runq->argv = p->next;
111 for(n = 0;w;n++) w = w->next;
116 pushredir(int type, int from, int to)
118 redir * rp = new(redir);
122 rp->next = runq->redir;
134 runq->redir = rp->next;
135 rp->next = runq->startredir;
136 for(rr = &runq->redir; *rr != rp->next; rr = &((*rr)->next))
142 newvar(char *name, var *next)
145 v->name = estrdup(name);
154 * get command line flags, initialize keywords & traps.
155 * get values from environment.
156 * set $pid, $cflag, $*
157 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
158 * start interpreting code
162 main(int argc, char *argv[])
165 char num[12], *rcmain;
167 argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
169 usage("[file [arg ...]]");
174 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
175 rcmain = flag['m']?flag['m'][0]:Rcmain;
180 inttoascii(num, mypid = getpid());
181 setvar("pid", newword(num, (word *)0));
182 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
184 setvar("rcname", newword(argv[0], (word *)0));
186 bootstrap[i++].i = 1;
187 bootstrap[i++].f = Xmark;
188 bootstrap[i++].f = Xword;
189 bootstrap[i++].s="*";
190 bootstrap[i++].f = Xassign;
191 bootstrap[i++].f = Xmark;
192 bootstrap[i++].f = Xmark;
193 bootstrap[i++].f = Xword;
194 bootstrap[i++].s="*";
195 bootstrap[i++].f = Xdol;
196 bootstrap[i++].f = Xword;
197 bootstrap[i++].s = rcmain;
198 bootstrap[i++].f = Xword;
199 bootstrap[i++].s=".";
200 bootstrap[i++].f = Xsimple;
201 bootstrap[i++].f = Xexit;
203 start(bootstrap, 1, (var *)0);
204 /* prime bootstrap argv */
206 argv0 = estrdup(argv[0]);
207 for(i = argc-1;i!=0;--i) pushword(argv[i]);
212 (*runq->code[runq->pc-1].f)();
219 * Arguments on stack (...)
220 * Arguments in line [...]
221 * Code in line with jump around {...}
223 * Xappend(file)[fd] open file to append
224 * Xassign(name, val) assign val to name
225 * Xasync{... Xexit} make thread for {}, no wait
226 * Xbackq(split){... Xreturn} make thread for {}, push stdout
227 * Xbang complement condition
228 * Xcase(pat, value){...} exec code on match, leave (value) on
230 * Xclose[i] close file descriptor
231 * Xconc(left, right) concatenate, push results
232 * Xcount(name) push var count
233 * Xdelfn(name) delete function definition
234 * Xdeltraps(names) delete named traps
235 * Xdol(name) get variable value
236 * Xqw(list) quote list, push result
237 * Xdup[i j] dup file descriptor
238 * Xexit rc exits with status
239 * Xfalse{...} execute {} if false
240 * Xfn(name){... Xreturn} define function
241 * Xfor(var, list){... Xreturn} for loop
242 * Xglobs[string globsize] push globbing string
244 * Xlocal(name, val) create local variable, assign value
246 * Xmatch(pat, str) match pattern, set status
247 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
249 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
250 * depending on type), push /dev/fd/??
251 * Xpopm(value) pop value from stack
252 * Xrdwr(file)[fd] open file for reading and writing
253 * Xread(file)[fd] open file to read
254 * Xsettraps(names){... Xreturn} define trap functions
255 * Xshowtraps print trap list
256 * Xsimple(args) run command and wait
257 * Xreturn kill thread
258 * Xsubshell{... Xexit} execute {} in a subshell and wait
259 * Xtrue{...} execute {} if true
260 * Xunlocal delete local variable
261 * Xword[string] push string
262 * Xwrite(file)[fd] open file to write
270 switch(count(runq->argv->words)){
272 Xerror1(">> requires singleton");
275 Xerror1(">> requires file");
280 file = runq->argv->words->word;
281 if((f = open(file, 1))<0 && (f = Creat(file))<0){
282 pfmt(err, "%s: ", file);
283 Xerror("can't open");
287 pushredir(ROPEN, f, runq->code[runq->pc].i);
301 setstatus(truestatus()?"false":"");
307 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
314 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
321 if(eflagok && !truestatus()) Xexit();
328 struct word *starval;
329 static int beenhere = 0;
330 if(getpid()==mypid && !beenhere){
331 trapreq = vlook("sigexit");
335 starval = vlook("*")->val;
336 start(trapreq->fn, trapreq->pc, (struct var *)0);
337 runq->local = newvar("*", runq->local);
338 runq->local->val = copywords(starval, (struct word *)0);
339 runq->local->changed = 1;
340 runq->redir = runq->startredir = 0;
350 if(truestatus()) runq->pc = runq->code[runq->pc].i;
353 int ifnot; /* dynamic if not flag */
361 runq->pc = runq->code[runq->pc].i;
367 runq->pc = runq->code[runq->pc].i;
387 switch(count(runq->argv->words)){
389 Xerror1("< requires singleton\n");
392 Xerror1("< requires file\n");
397 file = runq->argv->words->word;
398 if((f = open(file, 0))<0){
399 pfmt(err, "%s: ", file);
400 Xerror("can't open");
403 pushredir(ROPEN, f, runq->code[runq->pc].i);
414 switch(count(runq->argv->words)){
416 Xerror1("<> requires singleton\n");
419 Xerror1("<> requires file\n");
424 file = runq->argv->words->word;
425 if((f = open(file, ORDWR))<0){
426 pfmt(err, "%s: ", file);
427 Xerror("can't open");
430 pushredir(ROPEN, f, runq->code[runq->pc].i);
438 while(runq->redir!=runq->startredir)
445 struct redir *rp = runq->redir;
447 panic("turfredir null!", 0);
448 runq->redir = rp->next;
457 struct thread *p = runq;
459 while(p->argv) poplist();
470 if(truestatus()) runq->pc++;
471 else runq->pc = runq->code[runq->pc].i;
478 if(truestatus()) runq->pc++;
479 else runq->pc = runq->code[runq->pc].i;
491 pushword(runq->code[runq->pc++].s);
497 word *w = pushword(runq->code[runq->pc++].s);
498 w->glob = runq->code[runq->pc++].i;
506 switch(count(runq->argv->words)){
508 Xerror1("> requires singleton\n");
511 Xerror1("> requires file\n");
516 file = runq->argv->words->word;
517 if((f = Creat(file))<0){
518 pfmt(err, "%s: ", file);
519 Xerror("can't open");
522 pushredir(ROPEN, f, runq->code[runq->pc].i);
528 list2str(word *words)
533 for(ap = words;ap;ap = ap->next)
534 len+=1+strlen(ap->word);
535 value = emalloc(len+1);
537 for(ap = words;ap;ap = ap->next){
538 for(t = ap->word;*t;) *s++=*t++;
552 subject = list2str(runq->argv->words);
553 setstatus("no match");
554 for(p = runq->argv->next->words;p;p = p->next)
555 if(match(subject, p->word, '\0')){
570 s = list2str(runq->argv->next->words);
571 for(p = runq->argv->words;p;p = p->next){
572 if(match(s, p->word, '\0')){
581 runq->pc = runq->code[runq->pc].i;
586 conclist(word *lp, word *rp, word *tail)
592 ln = strlen(lp->word), rn = strlen(rp->word);
593 p = Newword(emalloc(ln+rn+1), (word *)0);
594 memmove(p->word, lp->word, ln);
595 memmove(p->word+ln, rp->word, rn+1);
596 if(lp->glob || rp->glob)
597 p->glob = Globsize(p->word);
598 *end = p, end = &p->next;
599 if(lp->next == 0 && rp->next == 0)
601 if(lp->next) lp = lp->next;
602 if(rp->next) rp = rp->next;
611 word *lp = runq->argv->words;
612 word *rp = runq->argv->next->words;
613 word *vp = runq->argv->next->next->words;
614 int lc = count(lp), rc = count(rp);
617 Xerror1("null list in concatenation");
620 if(lc!=1 && rc!=1 && lc!=rc){
621 Xerror1("mismatched list lengths in concatenation");
624 vp = conclist(lp, rp, vp);
628 runq->argv->words = vp;
646 if(count(runq->argv->words)!=1){
647 Xerror1("variable name not singleton!");
650 v = vlook(Str(runq->argv->words));
653 v->val = globlist(runq->argv->words);
655 runq->argv->words = 0;
659 * copy arglist a, adding the copy to the front of tail
663 copywords(word *a, word *tail)
666 for(end=&v;a;a = a->next,end=&(*end)->next)
667 *end = newword(a->word, 0);
678 if(count(runq->argv->words)!=1){
679 Xerror1("variable name not singleton!");
682 s = Str(runq->argv->words);
684 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
685 a = runq->argv->next->words;
687 a = copywords(vlook(s)->val, a);
689 star = vlook("*")->val;
690 if(star && 1<=n && n<=count(star)){
691 while(--n) star = star->next;
692 a = newword(star->word, a);
696 runq->argv->words = a;
705 a = runq->argv->words;
706 if(a && a->next == 0){
707 runq->argv->words = 0;
709 a->next = runq->argv->words;
710 runq->argv->words = a;
719 copynwords(word *a, word *tail, int n)
726 *end = newword(a->word, 0);
735 subwords(word *val, int len, word *sub, word *a)
741 a = subwords(val, len, sub->next, a);
745 while('0'<=*s && *s<='9')
751 while('0'<=*s && *s<='9')
756 if(n<1 || n>len || m<0)
762 return copynwords(val, a, m+1);
770 if(count(runq->argv->next->words)!=1){
771 Xerror1("variable name not singleton!");
774 s = Str(runq->argv->next->words);
775 a = runq->argv->next->next->words;
777 a = subwords(v, count(v), runq->argv->words, a);
780 runq->argv->words = a;
790 if(count(runq->argv->words)!=1){
791 Xerror1("variable name not singleton!");
794 s = Str(runq->argv->words);
796 for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
799 inttoascii(num, count(a));
803 inttoascii(num, a && 1<=n && n<=count(a)?1:0);
812 if(count(runq->argv->words)!=1){
813 Xerror1("variable name must be singleton\n");
816 runq->local = newvar(Str(runq->argv->words), runq->local);
818 runq->local->val = globlist(runq->argv->words);
819 runq->local->changed = 1;
820 runq->argv->words = 0;
827 var *v = runq->local, *hid;
829 panic("Xunlocal: no locals!", 0);
830 runq->local = v->next;
831 hid = vlook(v->name);
856 end = runq->code[runq->pc].i;
857 for(a = globlist(runq->argv->words);a;a = a->next){
861 v->fn = codecopy(runq->code);
874 for(a = runq->argv->words;a;a = a->next){
885 concstatus(char *s, char *t)
887 static char v[NSTATUS+1];
889 strncpy(v, s, NSTATUS);
892 strncpy(v+n+1, t, NSTATUS-n-1);
901 char status[NSTATUS+1];
903 setstatus(concstatus(runq->status, getstatus()));
905 strncpy(status, getstatus(), NSTATUS);
906 status[NSTATUS]='\0';
907 Waitfor(runq->pid, 1);
909 setstatus(concstatus(getstatus(), status));
916 struct thread *p = runq;
920 if(flag['s'] && !truestatus())
921 pfmt(err, "status=%v\n", vlook("status")->val);
923 prompt = vlook("prompt")->val;
925 promptstr = prompt->word;
931 if(!p->iflag || p->eof && !Eintr()){
935 Xreturn(); /* should this be omitted? */
942 --p->pc; /* go back for next command */
946 ntrap = 0; /* avoid double-interrupts during blocked writes */
947 --p->pc; /* re-execute Xrdcmds after codebuf runs */
948 start(codebuf, 1, runq->local);
956 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
957 pfmt(err, "rc: %s: %r\n", s);
959 pfmt(err, "rc (%s): %s: %r\n", argv0, s);
962 while(!runq->iflag) Xreturn();
968 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
969 pfmt(err, "rc: %s\n", s);
971 pfmt(err, "rc (%s): %s\n", argv0, s);
974 while(!runq->iflag) Xreturn();
980 setvar("status", newword(s, (word *)0));
986 var *status = vlook("status");
987 return status->val?status->val->word:"";
994 for(s = getstatus();*s;s++)
995 if(*s!='|' && *s!='0')
1003 Unlink(runq->code[runq->pc++].s);
1009 if(runq->argv->words==0){
1011 runq->pc = runq->code[runq->pc].i;
1014 freelist(runq->local->val);
1015 runq->local->val = runq->argv->words;
1016 runq->local->changed = 1;
1017 runq->argv->words = runq->argv->words->next;
1018 runq->local->val->next = 0;
1026 globlist(runq->argv->words);