Blob


1 #include "rc.h"
2 #include "getflags.h"
3 #include "exec.h"
4 #include "io.h"
5 #include "fns.h"
6 /*
7 * Start executing the given code at the given pc with the given redirection
8 */
9 char *argv0="rc";
10 void start(code *c, int pc, var *local)
11 {
12 struct thread *p=new(struct thread);
13 p->code=codecopy(c);
14 p->pc=pc;
15 p->argv=0;
16 p->redir=p->startredir=runq?runq->redir:0;
17 p->local=local;
18 p->cmdfile=0;
19 p->cmdfd=0;
20 p->eof=0;
21 p->iflag=0;
22 p->lineno=1;
23 p->pid=-1;
24 p->ret=runq;
25 runq=p;
26 }
27 word *newword(char *wd, word *next)
28 {
29 word *p=new(word);
30 p->word=strdup(wd);
31 p->next=next;
32 return p;
33 }
34 void pushword(char *wd)
35 {
36 if(runq->argv==0) panic("pushword but no argv!", 0);
37 runq->argv->words=newword(wd, runq->argv->words);
38 }
39 void popword(void){
40 word *p;
41 if(runq->argv==0) panic("popword but no argv!", 0);
42 p=runq->argv->words;
43 if(p==0) panic("popword but no word!", 0);
44 runq->argv->words=p->next;
45 efree(p->word);
46 efree((char *)p);
47 }
48 void freelist(word *w)
49 {
50 word *nw;
51 while(w){
52 nw=w->next;
53 efree(w->word);
54 efree((char *)w);
55 w=nw;
56 }
57 }
58 void pushlist(void){
59 list *p=new(list);
60 p->next=runq->argv;
61 p->words=0;
62 runq->argv=p;
63 }
64 void poplist(void){
65 list *p=runq->argv;
66 if(p==0) panic("poplist but no argv", 0);
67 freelist(p->words);
68 runq->argv=p->next;
69 efree((char *)p);
70 }
71 int count(word *w)
72 {
73 int n;
74 for(n=0;w;n++) w=w->next;
75 return n;
76 }
77 void pushredir(int type, int from, int to){
78 redir * rp=new(redir);
79 rp->type=type;
80 rp->from=from;
81 rp->to=to;
82 rp->next=runq->redir;
83 runq->redir=rp;
84 }
85 var *newvar(char *name, var *next)
86 {
87 var *v=new(var);
88 v->name=name;
89 v->val=0;
90 v->fn=0;
91 v->changed=0;
92 v->fnchanged=0;
93 v->next=next;
94 v->changefn = 0;
95 return v;
96 }
97 /*
98 * get command line flags, initialize keywords & traps.
99 * get values from environment.
100 * set $pid, $cflag, $*
101 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
102 * start interpreting code
103 */
104 int
105 main(int argc, char *argv[])
107 code bootstrap[32];
108 char num[12], *rcmain;
109 int i;
111 argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
112 if(argc==-1) usage("[file [arg ...]]");
113 if(argv[0][0]=='-') flag['l']=flagset;
114 if(flag['I']) flag['i'] = 0;
115 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
116 rcmain=flag['m']?flag['m'][0]:Rcmain();
117 err=openfd(2);
118 kinit();
119 Trapinit();
120 Vinit();
121 itoa(num, mypid=getpid());
122 pathinit();
123 setvar("pid", newword(num, (word *)0));
124 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
125 :(word *)0);
126 setvar("rcname", newword(argv[0], (word *)0));
127 i=0;
128 bootstrap[i++].i=1;
129 bootstrap[i++].f=Xmark;
130 bootstrap[i++].f=Xword;
131 bootstrap[i++].s="*";
132 bootstrap[i++].f=Xassign;
133 bootstrap[i++].f=Xmark;
134 bootstrap[i++].f=Xmark;
135 bootstrap[i++].f=Xword;
136 bootstrap[i++].s="*";
137 bootstrap[i++].f=Xdol;
138 bootstrap[i++].f=Xword;
139 bootstrap[i++].s=rcmain;
140 bootstrap[i++].f=Xword;
141 bootstrap[i++].s=".";
142 bootstrap[i++].f=Xsimple;
143 bootstrap[i++].f=Xexit;
144 bootstrap[i].i=0;
145 start(bootstrap, 1, (var *)0);
146 /* prime bootstrap argv */
147 pushlist();
148 argv0 = strdup(argv[0]);
149 for(i=argc-1;i!=0;--i) pushword(argv[i]);
150 for(;;){
151 if(flag['r']) pfnc(err, runq);
152 runq->pc++;
153 (*runq->code[runq->pc-1].f)();
154 if(ntrap) dotrap();
157 /*
158 * Opcode routines
159 * Arguments on stack (...)
160 * Arguments in line [...]
161 * Code in line with jump around {...}
163 * Xappend(file)[fd] open file to append
164 * Xassign(name, val) assign val to name
165 * Xasync{... Xexit} make thread for {}, no wait
166 * Xbackq{... Xreturn} make thread for {}, push stdout
167 * Xbang complement condition
168 * Xcase(pat, value){...} exec code on match, leave (value) on
169 * stack
170 * Xclose[i] close file descriptor
171 * Xconc(left, right) concatenate, push results
172 * Xcount(name) push var count
173 * Xdelfn(name) delete function definition
174 * Xdeltraps(names) delete named traps
175 * Xdol(name) get variable value
176 * Xqdol(name) concatenate variable components
177 * Xdup[i j] dup file descriptor
178 * Xexit rc exits with status
179 * Xfalse{...} execute {} if false
180 * Xfn(name){... Xreturn} define function
181 * Xfor(var, list){... Xreturn} for loop
182 * Xjump[addr] goto
183 * Xlocal(name, val) create local variable, assign value
184 * Xmark mark stack
185 * Xmatch(pat, str) match pattern, set status
186 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
187 * wait for both
188 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
189 * depending on type), push /dev/fd/??
190 * Xpopm(value) pop value from stack
191 * Xread(file)[fd] open file to read
192 * Xsettraps(names){... Xreturn} define trap functions
193 * Xshowtraps print trap list
194 * Xsimple(args) run command and wait
195 * Xreturn kill thread
196 * Xsubshell{... Xexit} execute {} in a subshell and wait
197 * Xtrue{...} execute {} if true
198 * Xunlocal delete local variable
199 * Xword[string] push string
200 * Xwrite(file)[fd] open file to write
201 */
202 void Xappend(void){
203 char *file;
204 int f;
205 switch(count(runq->argv->words)){
206 default: Xerror1(">> requires singleton"); return;
207 case 0: Xerror1(">> requires file"); return;
208 case 1: break;
210 file=runq->argv->words->word;
211 if((f=open(file, 1))<0 && (f=Creat(file))<0){
212 pfmt(err, "%s: ", file);
213 Xerror("can't open");
214 return;
216 Seek(f, 0L, 2);
217 pushredir(ROPEN, f, runq->code[runq->pc].i);
218 runq->pc++;
219 poplist();
221 void Xasync(void){
222 int null=open("/dev/null", 0);
223 int pid;
224 char npid[10];
225 if(null<0){
226 Xerror("Can't open /dev/null\n");
227 return;
229 switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
230 case -1:
231 close(null);
232 Xerror("try again");
233 break;
234 case 0:
235 pushredir(ROPEN, null, 0);
236 start(runq->code, runq->pc+1, runq->local);
237 runq->ret=0;
238 break;
239 default:
240 close(null);
241 runq->pc=runq->code[runq->pc].i;
242 itoa(npid, pid);
243 setvar("apid", newword(npid, (word *)0));
244 break;
247 void Xsettrue(void){
248 setstatus("");
250 void Xbang(void){
251 setstatus(truestatus()?"false":"");
253 void Xclose(void){
254 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
255 runq->pc++;
257 void Xdup(void){
258 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
259 runq->pc+=2;
261 void Xeflag(void){
262 if(eflagok && !truestatus()) Xexit();
264 void Xexit(void){
265 struct var *trapreq;
266 struct word *starval;
267 static int beenhere=0;
268 if(getpid()==mypid && !beenhere){
269 trapreq=vlook("sigexit");
270 if(trapreq->fn){
271 beenhere=1;
272 --runq->pc;
273 starval=vlook("*")->val;
274 start(trapreq->fn, trapreq->pc, (struct var *)0);
275 runq->local=newvar(strdup("*"), runq->local);
276 runq->local->val=copywords(starval, (struct word *)0);
277 runq->local->changed=1;
278 runq->redir=runq->startredir=0;
279 return;
282 Exit(getstatus());
284 void Xfalse(void){
285 if(truestatus()) runq->pc=runq->code[runq->pc].i;
286 else runq->pc++;
288 int ifnot; /* dynamic if not flag */
289 void Xifnot(void){
290 if(ifnot)
291 runq->pc++;
292 else
293 runq->pc=runq->code[runq->pc].i;
295 void Xjump(void){
296 runq->pc=runq->code[runq->pc].i;
298 void Xmark(void){
299 pushlist();
301 void Xpopm(void){
302 poplist();
304 void Xread(void){
305 char *file;
306 int f;
307 switch(count(runq->argv->words)){
308 default: Xerror1("< requires singleton\n"); return;
309 case 0: Xerror1("< requires file\n"); return;
310 case 1: break;
312 file=runq->argv->words->word;
313 if((f=open(file, 0))<0){
314 pfmt(err, "%s: ", file);
315 Xerror("can't open");
316 return;
318 pushredir(ROPEN, f, runq->code[runq->pc].i);
319 runq->pc++;
320 poplist();
322 void turfredir(void){
323 while(runq->redir!=runq->startredir)
324 Xpopredir();
326 void Xpopredir(void){
327 struct redir *rp=runq->redir;
328 if(rp==0) panic("turfredir null!", 0);
329 runq->redir=rp->next;
330 if(rp->type==ROPEN) close(rp->from);
331 efree((char *)rp);
333 void Xreturn(void){
334 struct thread *p=runq;
335 turfredir();
336 while(p->argv) poplist();
337 codefree(p->code);
338 runq=p->ret;
339 efree((char *)p);
340 if(runq==0) Exit(getstatus());
342 void Xtrue(void){
343 if(truestatus()) runq->pc++;
344 else runq->pc=runq->code[runq->pc].i;
346 void Xif(void){
347 ifnot=1;
348 if(truestatus()) runq->pc++;
349 else runq->pc=runq->code[runq->pc].i;
351 void Xwastrue(void){
352 ifnot=0;
354 void Xword(void){
355 pushword(runq->code[runq->pc++].s);
357 void Xwrite(void){
358 char *file;
359 int f;
360 switch(count(runq->argv->words)){
361 default: Xerror1("> requires singleton\n"); return;
362 case 0: Xerror1("> requires file\n"); return;
363 case 1: break;
365 file=runq->argv->words->word;
366 if((f=Creat(file))<0){
367 pfmt(err, "%s: ", file);
368 Xerror("can't open");
369 return;
371 pushredir(ROPEN, f, runq->code[runq->pc].i);
372 runq->pc++;
373 poplist();
375 char *_list2str(word *words, int c){
376 char *value, *s, *t;
377 int len=0;
378 word *ap;
379 for(ap=words;ap;ap=ap->next)
380 len+=1+strlen(ap->word);
381 value=emalloc(len+1);
382 s=value;
383 for(ap=words;ap;ap=ap->next){
384 for(t=ap->word;*t;) *s++=*t++;
385 *s++=c;
387 if(s==value) *s='\0';
388 else s[-1]='\0';
389 return value;
391 char *list2str(word *words){
392 return _list2str(words, ' ');
394 void Xmatch(void){
395 word *p;
396 char *subject;
397 subject=list2str(runq->argv->words);
398 setstatus("no match");
399 for(p=runq->argv->next->words;p;p=p->next)
400 if(match(subject, p->word, '\0')){
401 setstatus("");
402 break;
404 efree(subject);
405 poplist();
406 poplist();
408 void Xcase(void){
409 word *p;
410 char *s;
411 int ok=0;
412 s=list2str(runq->argv->next->words);
413 for(p=runq->argv->words;p;p=p->next){
414 if(match(s, p->word, '\0')){
415 ok=1;
416 break;
419 efree(s);
420 if(ok)
421 runq->pc++;
422 else
423 runq->pc=runq->code[runq->pc].i;
424 poplist();
426 word *conclist(word *lp, word *rp, word *tail)
428 char *buf;
429 word *v;
430 if(lp->next || rp->next)
431 tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
432 tail);
433 buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
434 strcpy(buf, lp->word);
435 strcat(buf, rp->word);
436 v=newword(buf, tail);
437 efree(buf);
438 return v;
440 void Xconc(void){
441 word *lp=runq->argv->words;
442 word *rp=runq->argv->next->words;
443 word *vp=runq->argv->next->next->words;
444 int lc=count(lp), rc=count(rp);
445 if(lc!=0 || rc!=0){
446 if(lc==0 || rc==0){
447 Xerror1("null list in concatenation");
448 return;
450 if(lc!=1 && rc!=1 && lc!=rc){
451 Xerror1("mismatched list lengths in concatenation");
452 return;
454 vp=conclist(lp, rp, vp);
456 poplist();
457 poplist();
458 runq->argv->words=vp;
460 void Xassign(void){
461 var *v;
462 if(count(runq->argv->words)!=1){
463 Xerror1("variable name not singleton!");
464 return;
466 deglob(runq->argv->words->word);
467 v=vlook(runq->argv->words->word);
468 poplist();
469 globlist();
470 freewords(v->val);
471 v->val=runq->argv->words;
472 v->changed=1;
473 if(v->changefn)
474 v->changefn(v);
475 runq->argv->words=0;
476 poplist();
478 /*
479 * copy arglist a, adding the copy to the front of tail
480 */
481 word *copywords(word *a, word *tail)
483 word *v=0, **end;
484 for(end=&v;a;a=a->next,end=&(*end)->next)
485 *end=newword(a->word, 0);
486 *end=tail;
487 return v;
489 void Xdol(void){
490 word *a, *star;
491 char *s, *t;
492 int n;
493 if(count(runq->argv->words)!=1){
494 Xerror1("variable name not singleton!");
495 return;
497 s=runq->argv->words->word;
498 deglob(s);
499 n=0;
500 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
501 a=runq->argv->next->words;
502 if(n==0 || *t)
503 a=copywords(vlook(s)->val, a);
504 else{
505 star=vlook("*")->val;
506 if(star && 1<=n && n<=count(star)){
507 while(--n) star=star->next;
508 a=newword(star->word, a);
511 poplist();
512 runq->argv->words=a;
514 void Xqdol(void){
515 word *a, *p;
516 char *s;
517 int n;
518 if(count(runq->argv->words)!=1){
519 Xerror1("variable name not singleton!");
520 return;
522 s=runq->argv->words->word;
523 deglob(s);
524 a=vlook(s)->val;
525 poplist();
526 n=count(a);
527 if(n==0){
528 pushword("");
529 return;
531 for(p=a;p;p=p->next) n+=strlen(p->word);
532 s=emalloc(n);
533 if(a){
534 strcpy(s, a->word);
535 for(p=a->next;p;p=p->next){
536 strcat(s, " ");
537 strcat(s, p->word);
540 else
541 s[0]='\0';
542 pushword(s);
543 efree(s);
545 word *subwords(word *val, int len, word *sub, word *a)
547 int n;
548 char *s;
549 if(!sub) return a;
550 a=subwords(val, len, sub->next, a);
551 s=sub->word;
552 deglob(s);
553 n=0;
554 while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
555 if(n<1 || len<n) return a;
556 for(;n!=1;--n) val=val->next;
557 return newword(val->word, a);
559 void Xsub(void){
560 word *a, *v;
561 char *s;
562 if(count(runq->argv->next->words)!=1){
563 Xerror1("variable name not singleton!");
564 return;
566 s=runq->argv->next->words->word;
567 deglob(s);
568 a=runq->argv->next->next->words;
569 v=vlook(s)->val;
570 a=subwords(v, count(v), runq->argv->words, a);
571 poplist();
572 poplist();
573 runq->argv->words=a;
575 void Xcount(void){
576 word *a;
577 char *s, *t;
578 int n;
579 char num[12];
580 if(count(runq->argv->words)!=1){
581 Xerror1("variable name not singleton!");
582 return;
584 s=runq->argv->words->word;
585 deglob(s);
586 n=0;
587 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
588 if(n==0 || *t){
589 a=vlook(s)->val;
590 itoa(num, count(a));
592 else{
593 a=vlook("*")->val;
594 itoa(num, a && 1<=n && n<=count(a)?1:0);
596 poplist();
597 pushword(num);
599 void Xlocal(void){
600 if(count(runq->argv->words)!=1){
601 Xerror1("variable name must be singleton\n");
602 return;
604 deglob(runq->argv->words->word);
605 runq->local=newvar(strdup(runq->argv->words->word), runq->local);
606 runq->local->val=copywords(runq->argv->next->words, (word *)0);
607 runq->local->changed=1;
608 poplist();
609 poplist();
611 void Xunlocal(void){
612 var *v=runq->local, *hid;
613 if(v==0) panic("Xunlocal: no locals!", 0);
614 runq->local=v->next;
615 hid=vlook(v->name);
616 hid->changed=1;
617 efree(v->name);
618 freewords(v->val);
619 efree((char *)v);
621 void freewords(word *w)
623 word *nw;
624 while(w){
625 efree(w->word);
626 nw=w->next;
627 efree((char *)w);
628 w=nw;
631 void Xfn(void){
632 var *v;
633 word *a;
634 int end;
635 end=runq->code[runq->pc].i;
636 for(a=runq->argv->words;a;a=a->next){
637 v=gvlook(a->word);
638 if(v->fn) codefree(v->fn);
639 v->fn=codecopy(runq->code);
640 v->pc=runq->pc+2;
641 v->fnchanged=1;
643 runq->pc=end;
644 poplist();
646 void Xdelfn(void){
647 var *v;
648 word *a;
649 for(a=runq->argv->words;a;a=a->next){
650 v=gvlook(a->word);
651 if(v->fn) codefree(v->fn);
652 v->fn=0;
653 v->fnchanged=1;
655 poplist();
657 void Xpipe(void){
658 struct thread *p=runq;
659 int pc=p->pc, forkid;
660 int lfd=p->code[pc++].i;
661 int rfd=p->code[pc++].i;
662 int pfd[2];
663 if(pipe(pfd)<0){
664 Xerror("can't get pipe");
665 return;
667 switch(forkid=fork()){
668 case -1:
669 Xerror("try again");
670 break;
671 case 0:
672 start(p->code, pc+2, runq->local);
673 runq->ret=0;
674 close(pfd[PRD]);
675 pushredir(ROPEN, pfd[PWR], lfd);
676 break;
677 default:
678 start(p->code, p->code[pc].i, runq->local);
679 close(pfd[PWR]);
680 pushredir(ROPEN, pfd[PRD], rfd);
681 p->pc=p->code[pc+1].i;
682 p->pid=forkid;
683 break;
686 char *concstatus(char *s, char *t)
688 static char v[NSTATUS+1];
689 int n=strlen(s);
690 strncpy(v, s, NSTATUS);
691 if(n<NSTATUS){
692 v[n]='|';
693 strncpy(v+n+1, t, NSTATUS-n-1);
695 v[NSTATUS]='\0';
696 return v;
698 void Xpipewait(void){
699 char status[NSTATUS+1];
700 if(runq->pid==-1)
701 setstatus(concstatus(runq->status, getstatus()));
702 else{
703 strncpy(status, getstatus(), NSTATUS);
704 status[NSTATUS]='\0';
705 Waitfor(runq->pid, 1);
706 runq->pid=-1;
707 setstatus(concstatus(getstatus(), status));
710 void Xrdcmds(void){
711 struct thread *p=runq;
712 word *prompt;
713 flush(err);
714 nerror=0;
715 if(flag['s'] && !truestatus())
716 pfmt(err, "status=%v\n", vlook("status")->val);
717 if(runq->iflag){
718 prompt=vlook("prompt")->val;
719 if(prompt)
720 promptstr=prompt->word;
721 else
722 promptstr="% ";
724 Noerror();
725 if(yyparse()){
726 if(!p->iflag || p->eof && !Eintr()){
727 if(p->cmdfile) efree(p->cmdfile);
728 closeio(p->cmdfd);
729 Xreturn(); /* should this be omitted? */
731 else{
732 if(Eintr()){
733 pchr(err, '\n');
734 p->eof=0;
736 --p->pc; /* go back for next command */
739 else{
740 ntrap = 0; /* avoid double-interrupts during blocked writes */
741 --p->pc; /* re-execute Xrdcmds after codebuf runs */
742 start(codebuf, 1, runq->local);
744 freenodes();
746 void Xerror(char *s)
748 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
749 pfmt(err, "rc: %s: %r\n", s);
750 else
751 pfmt(err, "rc (%s): %s: %r\n", argv0, s);
752 flush(err);
753 while(!runq->iflag) Xreturn();
755 void Xerror1(char *s)
757 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
758 pfmt(err, "rc: %s\n", s);
759 else
760 pfmt(err, "rc (%s): %s\n", argv0, s);
761 flush(err);
762 while(!runq->iflag) Xreturn();
764 void Xbackq(void){
765 char wd[8193];
766 int c;
767 char *s, *ewd=&wd[8192], *stop;
768 struct io *f;
769 var *ifs=vlook("ifs");
770 word *v, *nextv;
771 int pfd[2];
772 int pid;
773 stop=ifs->val?ifs->val->word:"";
774 if(pipe(pfd)<0){
775 Xerror("can't make pipe");
776 return;
778 switch(pid=fork()){
779 case -1: Xerror("try again");
780 close(pfd[PRD]);
781 close(pfd[PWR]);
782 return;
783 case 0:
784 close(pfd[PRD]);
785 start(runq->code, runq->pc+1, runq->local);
786 pushredir(ROPEN, pfd[PWR], 1);
787 return;
788 default:
789 close(pfd[PWR]);
790 f=openfd(pfd[PRD]);
791 s=wd;
792 v=0;
793 while((c=rchr(f))!=EOF){
794 if(strchr(stop, c) || s==ewd){
795 if(s!=wd){
796 *s='\0';
797 v=newword(wd, v);
798 s=wd;
801 else *s++=c;
803 if(s!=wd){
804 *s='\0';
805 v=newword(wd, v);
807 closeio(f);
808 Waitfor(pid, 0);
809 /* v points to reversed arglist -- reverse it onto argv */
810 while(v){
811 nextv=v->next;
812 v->next=runq->argv->words;
813 runq->argv->words=v;
814 v=nextv;
816 runq->pc=runq->code[runq->pc].i;
817 return;
820 /*
821 * Who should wait for the exit from the fork?
822 */
823 void Xpipefd(void){
824 struct thread *p=runq;
825 int pc=p->pc;
826 char name[40];
827 int pfd[2];
828 int sidefd, mainfd;
829 if(pipe(pfd)<0){
830 Xerror("can't get pipe");
831 return;
833 if(p->code[pc].i==READ){
834 sidefd=pfd[PWR];
835 mainfd=pfd[PRD];
837 else{
838 sidefd=pfd[PRD];
839 mainfd=pfd[PWR];
841 switch(fork()){
842 case -1:
843 Xerror("try again");
844 break;
845 case 0:
846 start(p->code, pc+2, runq->local);
847 close(mainfd);
848 pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
849 runq->ret=0;
850 break;
851 default:
852 close(sidefd);
853 pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
854 strcpy(name, Fdprefix);
855 itoa(name+strlen(name), mainfd);
856 pushword(name);
857 p->pc=p->code[pc+1].i;
858 break;
861 void Xsubshell(void){
862 int pid;
863 switch(pid=fork()){
864 case -1:
865 Xerror("try again");
866 break;
867 case 0:
868 start(runq->code, runq->pc+1, runq->local);
869 runq->ret=0;
870 break;
871 default:
872 Waitfor(pid, 1);
873 runq->pc=runq->code[runq->pc].i;
874 break;
877 void setstatus(char *s)
879 setvar("status", newword(s, (word *)0));
881 char *getstatus(void){
882 var *status=vlook("status");
883 return status->val?status->val->word:"";
885 int truestatus(void){
886 char *s;
887 for(s=getstatus();*s;s++)
888 if(*s!='|' && *s!='0') return 0;
889 return 1;
891 void Xdelhere(void){
892 Unlink(runq->code[runq->pc++].s);
894 void Xfor(void){
895 if(runq->argv->words==0){
896 poplist();
897 runq->pc=runq->code[runq->pc].i;
899 else{
900 freelist(runq->local->val);
901 runq->local->val=runq->argv->words;
902 runq->local->changed=1;
903 runq->argv->words=runq->argv->words->next;
904 runq->local->val->next=0;
905 runq->pc++;
908 void Xglob(void){
909 globlist();