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