Blob


1 #include <u.h>
2 #include <signal.h>
3 #if defined(PLAN9PORT) && defined(__sun__)
4 # define BSD_COMP /* sigh. for TIOCNOTTY */
5 #endif
6 #include <sys/ioctl.h>
7 #include "rc.h"
8 #include "getflags.h"
9 #include "exec.h"
10 #include "io.h"
11 #include "fns.h"
12 /*
13 * Start executing the given code at the given pc with the given redirection
14 */
15 char *argv0="rc";
16 void start(code *c, int pc, var *local)
17 {
18 struct thread *p=new(struct thread);
19 p->code=codecopy(c);
20 p->pc=pc;
21 p->argv=0;
22 p->redir=p->startredir=runq?runq->redir:0;
23 p->local=local;
24 p->cmdfile=0;
25 p->cmdfd=0;
26 p->eof=0;
27 p->iflag=0;
28 p->lineno=1;
29 p->pid=-1;
30 p->ret=runq;
31 runq=p;
32 }
33 word *newword(char *wd, word *next)
34 {
35 word *p=new(word);
36 p->word=strdup(wd);
37 p->next=next;
38 return p;
39 }
40 void pushword(char *wd)
41 {
42 if(runq->argv==0) panic("pushword but no argv!", 0);
43 runq->argv->words=newword(wd, runq->argv->words);
44 }
45 void popword(void){
46 word *p;
47 if(runq->argv==0) panic("popword but no argv!", 0);
48 p=runq->argv->words;
49 if(p==0) panic("popword but no word!", 0);
50 runq->argv->words=p->next;
51 efree(p->word);
52 efree((char *)p);
53 }
54 void freelist(word *w)
55 {
56 word *nw;
57 while(w){
58 nw=w->next;
59 efree(w->word);
60 efree((char *)w);
61 w=nw;
62 }
63 }
64 void pushlist(void){
65 list *p=new(list);
66 p->next=runq->argv;
67 p->words=0;
68 runq->argv=p;
69 }
70 void poplist(void){
71 list *p=runq->argv;
72 if(p==0) panic("poplist but no argv", 0);
73 freelist(p->words);
74 runq->argv=p->next;
75 efree((char *)p);
76 }
77 int count(word *w)
78 {
79 int n;
80 for(n=0;w;n++) w=w->next;
81 return n;
82 }
83 void pushredir(int type, int from, int to){
84 redir * rp=new(redir);
85 rp->type=type;
86 rp->from=from;
87 rp->to=to;
88 rp->next=runq->redir;
89 runq->redir=rp;
90 }
91 var *newvar(char *name, var *next)
92 {
93 var *v=new(var);
94 v->name=name;
95 v->val=0;
96 v->fn=0;
97 v->changed=0;
98 v->fnchanged=0;
99 v->next=next;
100 v->changefn = 0;
101 return v;
103 /*
104 * get command line flags, initialize keywords & traps.
105 * get values from environment.
106 * set $pid, $cflag, $*
107 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
108 * start interpreting code
109 */
110 int
111 main(int argc, char *argv[])
113 code bootstrap[32];
114 char num[12], *rcmain;
115 int i;
117 /* needed for rcmain later */
118 putenv("PLAN9", unsharp("#9"));
120 argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
121 if(argc==-1) usage("[file [arg ...]]");
122 if(argv[0][0]=='-') flag['l']=flagset;
123 if(flag['I']) flag['i'] = 0;
124 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
125 rcmain=flag['m']?flag['m'][0]:Rcmain();
126 err=openfd(2);
127 kinit();
128 Trapinit();
129 Vinit();
130 itoa(num, mypid=getpid());
131 pathinit();
132 setvar("pid", newword(num, (word *)0));
133 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
134 :(word *)0);
135 setvar("rcname", newword(argv[0], (word *)0));
136 i=0;
137 bootstrap[i++].i=1;
138 bootstrap[i++].f=Xmark;
139 bootstrap[i++].f=Xword;
140 bootstrap[i++].s="*";
141 bootstrap[i++].f=Xassign;
142 bootstrap[i++].f=Xmark;
143 bootstrap[i++].f=Xmark;
144 bootstrap[i++].f=Xword;
145 bootstrap[i++].s="*";
146 bootstrap[i++].f=Xdol;
147 bootstrap[i++].f=Xword;
148 bootstrap[i++].s=rcmain;
149 bootstrap[i++].f=Xword;
150 bootstrap[i++].s=".";
151 bootstrap[i++].f=Xsimple;
152 bootstrap[i++].f=Xexit;
153 bootstrap[i].i=0;
154 start(bootstrap, 1, (var *)0);
155 /* prime bootstrap argv */
156 pushlist();
157 argv0 = strdup(argv[0]);
158 for(i=argc-1;i!=0;--i) pushword(argv[i]);
159 for(;;){
160 if(flag['r']) pfnc(err, runq);
161 runq->pc++;
162 (*runq->code[runq->pc-1].f)();
163 if(ntrap) dotrap();
166 /*
167 * Opcode routines
168 * Arguments on stack (...)
169 * Arguments in line [...]
170 * Code in line with jump around {...}
172 * Xappend(file)[fd] open file to append
173 * Xassign(name, val) assign val to name
174 * Xasync{... Xexit} make thread for {}, no wait
175 * Xbackq{... Xreturn} make thread for {}, push stdout
176 * Xbang complement condition
177 * Xcase(pat, value){...} exec code on match, leave (value) on
178 * stack
179 * Xclose[i] close file descriptor
180 * Xconc(left, right) concatenate, push results
181 * Xcount(name) push var count
182 * Xdelfn(name) delete function definition
183 * Xdeltraps(names) delete named traps
184 * Xdol(name) get variable value
185 * Xqdol(name) concatenate variable components
186 * Xdup[i j] dup file descriptor
187 * Xexit rc exits with status
188 * Xfalse{...} execute {} if false
189 * Xfn(name){... Xreturn} define function
190 * Xfor(var, list){... Xreturn} for loop
191 * Xjump[addr] goto
192 * Xlocal(name, val) create local variable, assign value
193 * Xmark mark stack
194 * Xmatch(pat, str) match pattern, set status
195 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
196 * wait for both
197 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
198 * depending on type), push /dev/fd/??
199 * Xpopm(value) pop value from stack
200 * Xread(file)[fd] open file to read
201 * Xsettraps(names){... Xreturn} define trap functions
202 * Xshowtraps print trap list
203 * Xsimple(args) run command and wait
204 * Xreturn kill thread
205 * Xsubshell{... Xexit} execute {} in a subshell and wait
206 * Xtrue{...} execute {} if true
207 * Xunlocal delete local variable
208 * Xword[string] push string
209 * Xwrite(file)[fd] open file to write
210 */
211 void Xappend(void){
212 char *file;
213 int f;
214 switch(count(runq->argv->words)){
215 default: Xerror1(">> requires singleton"); return;
216 case 0: Xerror1(">> requires file"); return;
217 case 1: break;
219 file=runq->argv->words->word;
220 if((f=open(file, 1))<0 && (f=Creat(file))<0){
221 pfmt(err, "%s: ", file);
222 Xerror("can't open");
223 return;
225 Seek(f, 0L, 2);
226 pushredir(ROPEN, f, runq->code[runq->pc].i);
227 runq->pc++;
228 poplist();
230 void Xasync(void){
231 int null=open("/dev/null", 0);
232 int tty;
233 int pid;
234 char npid[10];
235 if(null<0){
236 Xerror("Can't open /dev/null\n");
237 return;
239 switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
240 case -1:
241 close(null);
242 Xerror("try again");
243 break;
244 case 0:
245 /*
246 * I don't know what the right thing to do here is,
247 * so this is all experimentally determined.
248 * If we just dup /dev/null onto 0, then running
249 * ssh foo & will reopen /dev/tty, try to read a password,
250 * get a signal, and repeat, in a tight loop, forever.
251 * Arguably this is a bug in ssh (it behaves the same
252 * way under bash as under rc) but I'm fixing it here
253 * anyway. If we dissociate the process from the tty,
254 * then it won't be able to open /dev/tty ever again.
255 * The SIG_IGN on SIGTTOU makes writing the tty
256 * (via fd 1 or 2, for example) succeed even though
257 * our pgrp is not the terminal's controlling pgrp.
258 */
259 if((tty=open("/dev/tty", OREAD)) >= 0){
260 /*
261 * Should make reads of tty fail, writes succeed.
262 */
263 signal(SIGTTIN, SIG_IGN);
264 signal(SIGTTOU, SIG_IGN);
265 ioctl(tty, TIOCNOTTY);
266 close(tty);
268 if(isatty(0))
269 pushredir(ROPEN, null, 0);
270 else
271 close(null);
272 start(runq->code, runq->pc+1, runq->local);
273 runq->ret=0;
274 break;
275 default:
276 close(null);
277 runq->pc=runq->code[runq->pc].i;
278 itoa(npid, pid);
279 setvar("apid", newword(npid, (word *)0));
280 break;
283 void Xsettrue(void){
284 setstatus("");
286 void Xbang(void){
287 setstatus(truestatus()?"false":"");
289 void Xclose(void){
290 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
291 runq->pc++;
293 void Xdup(void){
294 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
295 runq->pc+=2;
297 void Xeflag(void){
298 if(eflagok && !truestatus()) Xexit();
300 void Xexit(void){
301 struct var *trapreq;
302 struct word *starval;
303 static int beenhere=0;
304 if(getpid()==mypid && !beenhere){
305 trapreq=vlook("sigexit");
306 if(trapreq->fn){
307 beenhere=1;
308 --runq->pc;
309 starval=vlook("*")->val;
310 start(trapreq->fn, trapreq->pc, (struct var *)0);
311 runq->local=newvar(strdup("*"), runq->local);
312 runq->local->val=copywords(starval, (struct word *)0);
313 runq->local->changed=1;
314 runq->redir=runq->startredir=0;
315 return;
318 Exit(getstatus());
320 void Xfalse(void){
321 if(truestatus()) runq->pc=runq->code[runq->pc].i;
322 else runq->pc++;
324 int ifnot; /* dynamic if not flag */
325 void Xifnot(void){
326 if(ifnot)
327 runq->pc++;
328 else
329 runq->pc=runq->code[runq->pc].i;
331 void Xjump(void){
332 runq->pc=runq->code[runq->pc].i;
334 void Xmark(void){
335 pushlist();
337 void Xpopm(void){
338 poplist();
340 void Xread(void){
341 char *file;
342 int f;
343 switch(count(runq->argv->words)){
344 default: Xerror1("< requires singleton\n"); return;
345 case 0: Xerror1("< requires file\n"); return;
346 case 1: break;
348 file=runq->argv->words->word;
349 if((f=open(file, 0))<0){
350 pfmt(err, "%s: ", file);
351 Xerror("can't open");
352 return;
354 pushredir(ROPEN, f, runq->code[runq->pc].i);
355 runq->pc++;
356 poplist();
358 void turfredir(void){
359 while(runq->redir!=runq->startredir)
360 Xpopredir();
362 void Xpopredir(void){
363 struct redir *rp=runq->redir;
364 if(rp==0) panic("turfredir null!", 0);
365 runq->redir=rp->next;
366 if(rp->type==ROPEN) close(rp->from);
367 efree((char *)rp);
369 void Xreturn(void){
370 struct thread *p=runq;
371 turfredir();
372 while(p->argv) poplist();
373 codefree(p->code);
374 runq=p->ret;
375 efree((char *)p);
376 if(runq==0) Exit(getstatus());
378 void Xtrue(void){
379 if(truestatus()) runq->pc++;
380 else runq->pc=runq->code[runq->pc].i;
382 void Xif(void){
383 ifnot=1;
384 if(truestatus()) runq->pc++;
385 else runq->pc=runq->code[runq->pc].i;
387 void Xwastrue(void){
388 ifnot=0;
390 void Xword(void){
391 pushword(runq->code[runq->pc++].s);
393 void Xwrite(void){
394 char *file;
395 int f;
396 switch(count(runq->argv->words)){
397 default: Xerror1("> requires singleton\n"); return;
398 case 0: Xerror1("> requires file\n"); return;
399 case 1: break;
401 file=runq->argv->words->word;
402 if((f=Creat(file))<0){
403 pfmt(err, "%s: ", file);
404 Xerror("can't open");
405 return;
407 pushredir(ROPEN, f, runq->code[runq->pc].i);
408 runq->pc++;
409 poplist();
411 char *_list2str(word *words, int c){
412 char *value, *s, *t;
413 int len=0;
414 word *ap;
415 for(ap=words;ap;ap=ap->next)
416 len+=1+strlen(ap->word);
417 value=emalloc(len+1);
418 s=value;
419 for(ap=words;ap;ap=ap->next){
420 for(t=ap->word;*t;) *s++=*t++;
421 *s++=c;
423 if(s==value) *s='\0';
424 else s[-1]='\0';
425 return value;
427 char *list2str(word *words){
428 return _list2str(words, ' ');
430 void Xmatch(void){
431 word *p;
432 char *subject;
433 subject=list2str(runq->argv->words);
434 setstatus("no match");
435 for(p=runq->argv->next->words;p;p=p->next)
436 if(match(subject, p->word, '\0')){
437 setstatus("");
438 break;
440 efree(subject);
441 poplist();
442 poplist();
444 void Xcase(void){
445 word *p;
446 char *s;
447 int ok=0;
448 s=list2str(runq->argv->next->words);
449 for(p=runq->argv->words;p;p=p->next){
450 if(match(s, p->word, '\0')){
451 ok=1;
452 break;
455 efree(s);
456 if(ok)
457 runq->pc++;
458 else
459 runq->pc=runq->code[runq->pc].i;
460 poplist();
462 word *conclist(word *lp, word *rp, word *tail)
464 char *buf;
465 word *v;
466 if(lp->next || rp->next)
467 tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
468 tail);
469 buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
470 strcpy(buf, lp->word);
471 strcat(buf, rp->word);
472 v=newword(buf, tail);
473 efree(buf);
474 return v;
476 void Xconc(void){
477 word *lp=runq->argv->words;
478 word *rp=runq->argv->next->words;
479 word *vp=runq->argv->next->next->words;
480 int lc=count(lp), rc=count(rp);
481 if(lc!=0 || rc!=0){
482 if(lc==0 || rc==0){
483 Xerror1("null list in concatenation");
484 return;
486 if(lc!=1 && rc!=1 && lc!=rc){
487 Xerror1("mismatched list lengths in concatenation");
488 return;
490 vp=conclist(lp, rp, vp);
492 poplist();
493 poplist();
494 runq->argv->words=vp;
496 void Xassign(void){
497 var *v;
498 if(count(runq->argv->words)!=1){
499 Xerror1("variable name not singleton!");
500 return;
502 deglob(runq->argv->words->word);
503 v=vlook(runq->argv->words->word);
504 poplist();
505 globlist();
506 freewords(v->val);
507 v->val=runq->argv->words;
508 v->changed=1;
509 if(v->changefn)
510 v->changefn(v);
511 runq->argv->words=0;
512 poplist();
514 /*
515 * copy arglist a, adding the copy to the front of tail
516 */
517 word *copywords(word *a, word *tail)
519 word *v=0, **end;
520 for(end=&v;a;a=a->next,end=&(*end)->next)
521 *end=newword(a->word, 0);
522 *end=tail;
523 return v;
525 void Xdol(void){
526 word *a, *star;
527 char *s, *t;
528 int n;
529 if(count(runq->argv->words)!=1){
530 Xerror1("variable name not singleton!");
531 return;
533 s=runq->argv->words->word;
534 deglob(s);
535 n=0;
536 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
537 a=runq->argv->next->words;
538 if(n==0 || *t)
539 a=copywords(vlook(s)->val, a);
540 else{
541 star=vlook("*")->val;
542 if(star && 1<=n && n<=count(star)){
543 while(--n) star=star->next;
544 a=newword(star->word, a);
547 poplist();
548 runq->argv->words=a;
550 void Xqdol(void){
551 word *a, *p;
552 char *s;
553 int n;
554 if(count(runq->argv->words)!=1){
555 Xerror1("variable name not singleton!");
556 return;
558 s=runq->argv->words->word;
559 deglob(s);
560 a=vlook(s)->val;
561 poplist();
562 n=count(a);
563 if(n==0){
564 pushword("");
565 return;
567 for(p=a;p;p=p->next) n+=strlen(p->word);
568 s=emalloc(n);
569 if(a){
570 strcpy(s, a->word);
571 for(p=a->next;p;p=p->next){
572 strcat(s, " ");
573 strcat(s, p->word);
576 else
577 s[0]='\0';
578 pushword(s);
579 efree(s);
581 word *subwords(word *val, int len, word *sub, word *a)
583 int n;
584 char *s;
585 if(!sub) return a;
586 a=subwords(val, len, sub->next, a);
587 s=sub->word;
588 deglob(s);
589 n=0;
590 while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
591 if(n<1 || len<n) return a;
592 for(;n!=1;--n) val=val->next;
593 return newword(val->word, a);
595 void Xsub(void){
596 word *a, *v;
597 char *s;
598 if(count(runq->argv->next->words)!=1){
599 Xerror1("variable name not singleton!");
600 return;
602 s=runq->argv->next->words->word;
603 deglob(s);
604 a=runq->argv->next->next->words;
605 v=vlook(s)->val;
606 a=subwords(v, count(v), runq->argv->words, a);
607 poplist();
608 poplist();
609 runq->argv->words=a;
611 void Xcount(void){
612 word *a;
613 char *s, *t;
614 int n;
615 char num[12];
616 if(count(runq->argv->words)!=1){
617 Xerror1("variable name not singleton!");
618 return;
620 s=runq->argv->words->word;
621 deglob(s);
622 n=0;
623 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
624 if(n==0 || *t){
625 a=vlook(s)->val;
626 itoa(num, count(a));
628 else{
629 a=vlook("*")->val;
630 itoa(num, a && 1<=n && n<=count(a)?1:0);
632 poplist();
633 pushword(num);
635 void Xlocal(void){
636 if(count(runq->argv->words)!=1){
637 Xerror1("variable name must be singleton\n");
638 return;
640 deglob(runq->argv->words->word);
641 runq->local=newvar(strdup(runq->argv->words->word), runq->local);
642 runq->local->val=copywords(runq->argv->next->words, (word *)0);
643 runq->local->changed=1;
644 poplist();
645 poplist();
647 void Xunlocal(void){
648 var *v=runq->local, *hid;
649 if(v==0) panic("Xunlocal: no locals!", 0);
650 runq->local=v->next;
651 hid=vlook(v->name);
652 hid->changed=1;
653 efree(v->name);
654 freewords(v->val);
655 efree((char *)v);
657 void freewords(word *w)
659 word *nw;
660 while(w){
661 efree(w->word);
662 nw=w->next;
663 efree((char *)w);
664 w=nw;
667 void Xfn(void){
668 var *v;
669 word *a;
670 int end;
671 end=runq->code[runq->pc].i;
672 for(a=runq->argv->words;a;a=a->next){
673 v=gvlook(a->word);
674 if(v->fn) codefree(v->fn);
675 v->fn=codecopy(runq->code);
676 v->pc=runq->pc+2;
677 v->fnchanged=1;
679 runq->pc=end;
680 poplist();
682 void Xdelfn(void){
683 var *v;
684 word *a;
685 for(a=runq->argv->words;a;a=a->next){
686 v=gvlook(a->word);
687 if(v->fn) codefree(v->fn);
688 v->fn=0;
689 v->fnchanged=1;
691 poplist();
693 void Xpipe(void){
694 struct thread *p=runq;
695 int pc=p->pc, forkid;
696 int lfd=p->code[pc++].i;
697 int rfd=p->code[pc++].i;
698 int pfd[2];
699 if(pipe(pfd)<0){
700 Xerror("can't get pipe");
701 return;
703 switch(forkid=fork()){
704 case -1:
705 Xerror("try again");
706 break;
707 case 0:
708 start(p->code, pc+2, runq->local);
709 runq->ret=0;
710 close(pfd[PRD]);
711 pushredir(ROPEN, pfd[PWR], lfd);
712 break;
713 default:
714 start(p->code, p->code[pc].i, runq->local);
715 close(pfd[PWR]);
716 pushredir(ROPEN, pfd[PRD], rfd);
717 p->pc=p->code[pc+1].i;
718 p->pid=forkid;
719 break;
722 char *concstatus(char *s, char *t)
724 static char v[NSTATUS+1];
725 int n=strlen(s);
726 strncpy(v, s, NSTATUS);
727 if(n<NSTATUS){
728 v[n]='|';
729 strncpy(v+n+1, t, NSTATUS-n-1);
731 v[NSTATUS]='\0';
732 return v;
734 void Xpipewait(void){
735 char status[NSTATUS+1];
736 if(runq->pid==-1)
737 setstatus(concstatus(runq->status, getstatus()));
738 else{
739 strncpy(status, getstatus(), NSTATUS);
740 status[NSTATUS]='\0';
741 Waitfor(runq->pid, 1);
742 runq->pid=-1;
743 setstatus(concstatus(getstatus(), status));
746 void Xrdcmds(void){
747 struct thread *p=runq;
748 word *prompt;
749 flush(err);
750 nerror=0;
751 if(flag['s'] && !truestatus())
752 pfmt(err, "status=%v\n", vlook("status")->val);
753 if(runq->iflag){
754 prompt=vlook("prompt")->val;
755 if(prompt)
756 promptstr=prompt->word;
757 else
758 promptstr="% ";
760 Noerror();
761 if(yyparse()){
762 if(!p->iflag || p->eof && !Eintr()){
763 if(p->cmdfile) efree(p->cmdfile);
764 closeio(p->cmdfd);
765 Xreturn(); /* should this be omitted? */
767 else{
768 if(Eintr()){
769 pchr(err, '\n');
770 p->eof=0;
772 --p->pc; /* go back for next command */
775 else{
776 ntrap = 0; /* avoid double-interrupts during blocked writes */
777 --p->pc; /* re-execute Xrdcmds after codebuf runs */
778 start(codebuf, 1, runq->local);
780 freenodes();
782 void Xerror(char *s)
784 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
785 pfmt(err, "rc: %s: %r\n", s);
786 else
787 pfmt(err, "rc (%s): %s: %r\n", argv0, s);
788 flush(err);
789 setstatus("error");
790 while(!runq->iflag) Xreturn();
792 void Xerror1(char *s)
794 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
795 pfmt(err, "rc: %s\n", s);
796 else
797 pfmt(err, "rc (%s): %s\n", argv0, s);
798 flush(err);
799 setstatus("error");
800 while(!runq->iflag) Xreturn();
802 void Xbackq(void){
803 char wd[8193];
804 int c;
805 char *s, *ewd=&wd[8192], *stop;
806 struct io *f;
807 var *ifs=vlook("ifs");
808 word *v, *nextv;
809 int pfd[2];
810 int pid;
811 stop=ifs->val?ifs->val->word:"";
812 if(pipe(pfd)<0){
813 Xerror("can't make pipe");
814 return;
816 switch(pid=fork()){
817 case -1: Xerror("try again");
818 close(pfd[PRD]);
819 close(pfd[PWR]);
820 return;
821 case 0:
822 close(pfd[PRD]);
823 start(runq->code, runq->pc+1, runq->local);
824 pushredir(ROPEN, pfd[PWR], 1);
825 return;
826 default:
827 close(pfd[PWR]);
828 f=openfd(pfd[PRD]);
829 s=wd;
830 v=0;
831 while((c=rchr(f))!=EOF){
832 if(strchr(stop, c) || s==ewd){
833 if(s!=wd){
834 *s='\0';
835 v=newword(wd, v);
836 s=wd;
839 else *s++=c;
841 if(s!=wd){
842 *s='\0';
843 v=newword(wd, v);
845 closeio(f);
846 Waitfor(pid, 0);
847 /* v points to reversed arglist -- reverse it onto argv */
848 while(v){
849 nextv=v->next;
850 v->next=runq->argv->words;
851 runq->argv->words=v;
852 v=nextv;
854 runq->pc=runq->code[runq->pc].i;
855 return;
858 /*
859 * Who should wait for the exit from the fork?
860 */
861 void Xpipefd(void){
862 struct thread *p=runq;
863 int pc=p->pc;
864 char name[40];
865 int pfd[2];
866 int sidefd, mainfd;
867 if(pipe(pfd)<0){
868 Xerror("can't get pipe");
869 return;
871 if(p->code[pc].i==READ){
872 sidefd=pfd[PWR];
873 mainfd=pfd[PRD];
875 else{
876 sidefd=pfd[PRD];
877 mainfd=pfd[PWR];
879 switch(fork()){
880 case -1:
881 Xerror("try again");
882 break;
883 case 0:
884 start(p->code, pc+2, runq->local);
885 close(mainfd);
886 pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
887 runq->ret=0;
888 break;
889 default:
890 close(sidefd);
891 pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
892 strcpy(name, Fdprefix);
893 itoa(name+strlen(name), mainfd);
894 pushword(name);
895 p->pc=p->code[pc+1].i;
896 break;
899 void Xsubshell(void){
900 int pid;
901 switch(pid=fork()){
902 case -1:
903 Xerror("try again");
904 break;
905 case 0:
906 start(runq->code, runq->pc+1, runq->local);
907 runq->ret=0;
908 break;
909 default:
910 Waitfor(pid, 1);
911 runq->pc=runq->code[runq->pc].i;
912 break;
915 void setstatus(char *s)
917 setvar("status", newword(s, (word *)0));
919 char *getstatus(void){
920 var *status=vlook("status");
921 return status->val?status->val->word:"";
923 int truestatus(void){
924 char *s;
925 for(s=getstatus();*s;s++)
926 if(*s!='|' && *s!='0') return 0;
927 return 1;
929 void Xdelhere(void){
930 Unlink(runq->code[runq->pc++].s);
932 void Xfor(void){
933 if(runq->argv->words==0){
934 poplist();
935 runq->pc=runq->code[runq->pc].i;
937 else{
938 freelist(runq->local->val);
939 runq->local->val=runq->argv->words;
940 runq->local->changed=1;
941 runq->argv->words=runq->argv->words->next;
942 runq->local->val->next=0;
943 runq->pc++;
946 void Xglob(void){
947 globlist();