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 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(argc==1 && Isatty(0)) flag['i']=flagset; 109 if(argv[0][0]=='-') flag['l']=flagset; 110 if(flag['I']) flag['i']=0; 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 Xperror(file); 205 return; 206 } 207 Seek(f, 0L, 2); 208 pushredir(ROPEN, f, runq->code[runq->pc].i); 209 runq->pc++; 210 poplist(); 211 } 212 void Xasync(void){ 213 int null=open("/dev/null", 0); 214 int pid; 215 char npid[10]; 216 if(null<0){ 217 Xperror("/dev/null"); 218 return; 219 } 220 switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){ 221 case -1: 222 close(null); 223 Xperror("rfork"); 224 break; 225 case 0: 226 pushredir(ROPEN, null, 0); 227 start(runq->code, runq->pc+1, runq->local); 228 runq->ret=0; 229 break; 230 default: 231 close(null); 232 runq->pc=runq->code[runq->pc].i; 233 itoa(npid, pid); 234 setvar("apid", newword(npid, (word *)0)); 235 break; 236 } 237 } 238 void Xsettrue(void){ 239 setstatus(""); 240 } 241 void Xbang(void){ 242 setstatus(truestatus()?"false":""); 243 } 244 void Xclose(void){ 245 pushredir(RCLOSE, runq->code[runq->pc].i, 0); 246 runq->pc++; 247 } 248 void Xdup(void){ 249 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); 250 runq->pc+=2; 251 } 252 void Xeflag(void){ 253 if(eflagok && !truestatus()) Xexit(); 254 } 255 void Xexit(void){ 256 struct var *trapreq; 257 struct word *starval; 258 static int beenhere=0; 259 if(getpid()==mypid && !beenhere){ 260 trapreq=vlook("sigexit"); 261 if(trapreq->fn){ 262 beenhere=1; 263 --runq->pc; 264 starval=vlook("*")->val; 265 start(trapreq->fn, trapreq->pc, (struct var *)0); 266 runq->local=newvar(strdup("*"), runq->local); 267 runq->local->val=copywords(starval, (struct word *)0); 268 runq->local->changed=1; 269 runq->redir=runq->startredir=0; 270 return; 271 } 272 } 273 Exit(getstatus()); 274 } 275 void Xfalse(void){ 276 if(truestatus()) runq->pc=runq->code[runq->pc].i; 277 else runq->pc++; 278 } 279 int ifnot; /* dynamic if not flag */ 280 void Xifnot(void){ 281 if(ifnot) 282 runq->pc++; 283 else 284 runq->pc=runq->code[runq->pc].i; 285 } 286 void Xjump(void){ 287 runq->pc=runq->code[runq->pc].i; 288 } 289 void Xmark(void){ 290 pushlist(); 291 } 292 void Xpopm(void){ 293 poplist(); 294 } 295 void Xread(void){ 296 char *file; 297 int f; 298 switch(count(runq->argv->words)){ 299 default: Xerror("< requires singleton\n"); return; 300 case 0: Xerror("< requires file\n"); return; 301 case 1: break; 302 } 303 file=runq->argv->words->word; 304 if((f=open(file, 0))<0){ 305 Xperror(file); 306 return; 307 } 308 pushredir(ROPEN, f, runq->code[runq->pc].i); 309 runq->pc++; 310 poplist(); 311 } 312 void turfredir(void){ 313 while(runq->redir!=runq->startredir) 314 Xpopredir(); 315 } 316 void Xpopredir(void){ 317 struct redir *rp=runq->redir; 318 if(rp==0) panic("turfredir null!", 0); 319 runq->redir=rp->next; 320 if(rp->type==ROPEN) close(rp->from); 321 efree((char *)rp); 322 } 323 void Xreturn(void){ 324 struct thread *p=runq; 325 turfredir(); 326 while(p->argv) poplist(); 327 codefree(p->code); 328 runq=p->ret; 329 efree((char *)p); 330 if(runq==0) Exit(getstatus()); 331 } 332 void Xtrue(void){ 333 if(truestatus()) runq->pc++; 334 else runq->pc=runq->code[runq->pc].i; 335 } 336 void Xif(void){ 337 ifnot=1; 338 if(truestatus()) runq->pc++; 339 else runq->pc=runq->code[runq->pc].i; 340 } 341 void Xwastrue(void){ 342 ifnot=0; 343 } 344 void Xword(void){ 345 pushword(runq->code[runq->pc++].s); 346 } 347 void Xwrite(void){ 348 char *file; 349 int f; 350 switch(count(runq->argv->words)){ 351 default: Xerror("> requires singleton\n"); return; 352 case 0: Xerror("> requires file\n"); return; 353 case 1: break; 354 } 355 file=runq->argv->words->word; 356 if((f=Creat(file))<0){ 357 Xperror(file); 358 return; 359 } 360 pushredir(ROPEN, f, runq->code[runq->pc].i); 361 runq->pc++; 362 poplist(); 363 } 364 char *list2str(word *words){ 365 char *value, *s, *t; 366 int len=0; 367 word *ap; 368 for(ap=words;ap;ap=ap->next) 369 len+=1+strlen(ap->word); 370 value=emalloc(len+1); 371 s=value; 372 for(ap=words;ap;ap=ap->next){ 373 for(t=ap->word;*t;) *s++=*t++; 374 *s++=' '; 375 } 376 if(s==value) *s='\0'; 377 else s[-1]='\0'; 378 return value; 379 } 380 void Xmatch(void){ 381 word *p; 382 char *subject; 383 subject=list2str(runq->argv->words); 384 setstatus("no match"); 385 for(p=runq->argv->next->words;p;p=p->next) 386 if(match(subject, p->word, '\0')){ 387 setstatus(""); 388 break; 389 } 390 efree(subject); 391 poplist(); 392 poplist(); 393 } 394 void Xcase(void){ 395 word *p; 396 char *s; 397 int ok=0; 398 s=list2str(runq->argv->next->words); 399 for(p=runq->argv->words;p;p=p->next){ 400 if(match(s, p->word, '\0')){ 401 ok=1; 402 break; 403 } 404 } 405 efree(s); 406 if(ok) 407 runq->pc++; 408 else 409 runq->pc=runq->code[runq->pc].i; 410 poplist(); 411 } 412 word *conclist(word *lp, word *rp, word *tail) 413 { 414 char *buf; 415 word *v; 416 if(lp->next || rp->next) 417 tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next, 418 tail); 419 buf=emalloc(strlen(lp->word)+strlen(rp->word)+1); 420 strcpy(buf, lp->word); 421 strcat(buf, rp->word); 422 v=newword(buf, tail); 423 efree(buf); 424 return v; 425 } 426 void Xconc(void){ 427 word *lp=runq->argv->words; 428 word *rp=runq->argv->next->words; 429 word *vp=runq->argv->next->next->words; 430 int lc=count(lp), rc=count(rp); 431 if(lc!=0 || rc!=0){ 432 if(lc==0 || rc==0){ 433 Xerror("null list in concatenation"); 434 return; 435 } 436 if(lc!=1 && rc!=1 && lc!=rc){ 437 Xerror("mismatched list lengths in concatenation"); 438 return; 439 } 440 vp=conclist(lp, rp, vp); 441 } 442 poplist(); 443 poplist(); 444 runq->argv->words=vp; 445 } 446 void Xassign(void){ 447 var *v; 448 if(count(runq->argv->words)!=1){ 449 Xerror("variable name not singleton!"); 450 return; 451 } 452 deglob(runq->argv->words->word); 453 v=vlook(runq->argv->words->word); 454 poplist(); 455 globlist(); 456 freewords(v->val); 457 v->val=runq->argv->words; 458 v->changed=1; 459 runq->argv->words=0; 460 poplist(); 461 } 462 /* 463 * copy arglist a, adding the copy to the front of tail 464 */ 465 word *copywords(word *a, word *tail) 466 { 467 word *v=0, **end; 468 for(end=&v;a;a=a->next,end=&(*end)->next) 469 *end=newword(a->word, 0); 470 *end=tail; 471 return v; 472 } 473 void Xdol(void){ 474 word *a, *star; 475 char *s, *t; 476 int n; 477 if(count(runq->argv->words)!=1){ 478 Xerror("variable name not singleton!"); 479 return; 480 } 481 s=runq->argv->words->word; 482 deglob(s); 483 n=0; 484 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; 485 a=runq->argv->next->words; 486 if(n==0 || *t) 487 a=copywords(vlook(s)->val, a); 488 else{ 489 star=vlook("*")->val; 490 if(star && 1<=n && n<=count(star)){ 491 while(--n) star=star->next; 492 a=newword(star->word, a); 493 } 494 } 495 poplist(); 496 runq->argv->words=a; 497 } 498 void Xqdol(void){ 499 word *a, *p; 500 char *s; 501 int n; 502 if(count(runq->argv->words)!=1){ 503 Xerror("variable name not singleton!"); 504 return; 505 } 506 s=runq->argv->words->word; 507 deglob(s); 508 a=vlook(s)->val; 509 poplist(); 510 n=count(a); 511 if(n==0){ 512 pushword(""); 513 return; 514 } 515 for(p=a;p;p=p->next) n+=strlen(p->word); 516 s=emalloc(n); 517 if(a){ 518 strcpy(s, a->word); 519 for(p=a->next;p;p=p->next){ 520 strcat(s, " "); 521 strcat(s, p->word); 522 } 523 } 524 else 525 s[0]='\0'; 526 pushword(s); 527 efree(s); 528 } 529 word *subwords(word *val, int len, word *sub, word *a) 530 { 531 int n; 532 char *s; 533 if(!sub) return a; 534 a=subwords(val, len, sub->next, a); 535 s=sub->word; 536 deglob(s); 537 n=0; 538 while('0'<=*s && *s<='9') n=n*10+ *s++ -'0'; 539 if(n<1 || len<n) return a; 540 for(;n!=1;--n) val=val->next; 541 return newword(val->word, a); 542 } 543 void Xsub(void){ 544 word *a, *v; 545 char *s; 546 if(count(runq->argv->next->words)!=1){ 547 Xerror("variable name not singleton!"); 548 return; 549 } 550 s=runq->argv->next->words->word; 551 deglob(s); 552 a=runq->argv->next->next->words; 553 v=vlook(s)->val; 554 a=subwords(v, count(v), runq->argv->words, a); 555 poplist(); 556 poplist(); 557 runq->argv->words=a; 558 } 559 void Xcount(void){ 560 word *a; 561 char *s, *t; 562 int n; 563 char num[12]; 564 if(count(runq->argv->words)!=1){ 565 Xerror("variable name not singleton!"); 566 return; 567 } 568 s=runq->argv->words->word; 569 deglob(s); 570 n=0; 571 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; 572 if(n==0 || *t){ 573 a=vlook(s)->val; 574 itoa(num, count(a)); 575 } 576 else{ 577 a=vlook("*")->val; 578 itoa(num, a && 1<=n && n<=count(a)?1:0); 579 } 580 poplist(); 581 pushword(num); 582 } 583 void Xlocal(void){ 584 if(count(runq->argv->words)!=1){ 585 Xerror("variable name must be singleton\n"); 586 return; 587 } 588 deglob(runq->argv->words->word); 589 runq->local=newvar(strdup(runq->argv->words->word), runq->local); 590 runq->local->val=copywords(runq->argv->next->words, (word *)0); 591 runq->local->changed=1; 592 poplist(); 593 poplist(); 594 } 595 void Xunlocal(void){ 596 var *v=runq->local, *hid; 597 if(v==0) panic("Xunlocal: no locals!", 0); 598 runq->local=v->next; 599 hid=vlook(v->name); 600 hid->changed=1; 601 efree(v->name); 602 freewords(v->val); 603 efree((char *)v); 604 } 605 void freewords(word *w) 606 { 607 word *nw; 608 while(w){ 609 efree(w->word); 610 nw=w->next; 611 efree((char *)w); 612 w=nw; 613 } 614 } 615 void Xfn(void){ 616 var *v; 617 word *a; 618 int end; 619 end=runq->code[runq->pc].i; 620 for(a=runq->argv->words;a;a=a->next){ 621 v=gvlook(a->word); 622 if(v->fn) codefree(v->fn); 623 v->fn=codecopy(runq->code); 624 v->pc=runq->pc+2; 625 v->fnchanged=1; 626 } 627 runq->pc=end; 628 poplist(); 629 } 630 void Xdelfn(void){ 631 var *v; 632 word *a; 633 for(a=runq->argv->words;a;a=a->next){ 634 v=gvlook(a->word); 635 if(v->fn) codefree(v->fn); 636 v->fn=0; 637 v->fnchanged=1; 638 } 639 poplist(); 640 } 641 void Xpipe(void){ 642 struct thread *p=runq; 643 int pc=p->pc, forkid; 644 int lfd=p->code[pc++].i; 645 int rfd=p->code[pc++].i; 646 int pfd[2]; 647 if(pipe(pfd)<0){ 648 Xperror("can't get pipe"); 649 return; 650 } 651 switch(forkid=fork()){ 652 case -1: 653 Xperror("can't fork"); 654 break; 655 case 0: 656 start(p->code, pc+2, runq->local); 657 runq->ret=0; 658 close(pfd[PRD]); 659 pushredir(ROPEN, pfd[PWR], lfd); 660 break; 661 default: 662 start(p->code, p->code[pc].i, runq->local); 663 close(pfd[PWR]); 664 pushredir(ROPEN, pfd[PRD], rfd); 665 p->pc=p->code[pc+1].i; 666 p->pid=forkid; 667 break; 668 } 669 } 670 char *concstatus(char *s, char *t) 671 { 672 static char v[NSTATUS+1]; 673 int n=strlen(s); 674 strncpy(v, s, NSTATUS); 675 if(n<NSTATUS){ 676 v[n]='|'; 677 strncpy(v+n+1, t, NSTATUS-n-1); 678 } 679 v[NSTATUS]='\0'; 680 return v; 681 } 682 void Xpipewait(void){ 683 char status[NSTATUS+1]; 684 if(runq->pid==-1) 685 setstatus(concstatus(runq->status, getstatus())); 686 else{ 687 strncpy(status, getstatus(), NSTATUS); 688 status[NSTATUS]='\0'; 689 Waitfor(runq->pid, 1); 690 runq->pid=-1; 691 setstatus(concstatus(getstatus(), status)); 692 } 693 } 694 void Xrdcmds(void){ 695 struct thread *p=runq; 696 word *prompt; 697 flush(err); 698 nerror=0; 699 if(flag['s'] && !truestatus()) 700 pfmt(err, "status=%v\n", vlook("status")->val); 701 if(runq->iflag){ 702 prompt=vlook("prompt")->val; 703 if(prompt) 704 promptstr=prompt->word; 705 else 706 promptstr="% "; 707 } 708 Noerror(); 709 if(yyparse()){ 710 if(!p->iflag || p->eof && !Eintr()){ 711 if(p->cmdfile) efree(p->cmdfile); 712 closeio(p->cmdfd); 713 Xreturn(); /* should this be omitted? */ 714 } 715 else{ 716 if(Eintr()){ 717 pchr(err, '\n'); 718 p->eof=0; 719 } 720 --p->pc; /* go back for next command */ 721 } 722 } 723 else{ 724 --p->pc; /* re-execute Xrdcmds after codebuf runs */ 725 start(codebuf, 1, runq->local); 726 } 727 freenodes(); 728 } 729 void Xerror(char *s) 730 { 731 pfmt(err, "rc: %s\n", s); 732 flush(err); 733 while(!runq->iflag) Xreturn(); 734 } 735 void Xperror(char *s) 736 { 737 pfmt(err, "rc: %s: %s\n", s, Geterrstr()); 738 flush(err); 739 while(!runq->iflag) Xreturn(); 740 } 741 void Xbackq(void){ 742 char wd[8193]; 743 int c; 744 char *s, *ewd=&wd[8192], *stop; 745 struct io *f; 746 var *ifs=vlook("ifs"); 747 word *v, *nextv; 748 int pfd[2]; 749 int pid; 750 stop=ifs->val?ifs->val->word:""; 751 if(pipe(pfd)<0){ 752 Xerror("can't make pipe"); 753 return; 754 } 755 switch(pid=fork()){ 756 case -1: Xerror("try again"); 757 close(pfd[PRD]); 758 close(pfd[PWR]); 759 return; 760 case 0: 761 close(pfd[PRD]); 762 start(runq->code, runq->pc+1, runq->local); 763 pushredir(ROPEN, pfd[PWR], 1); 764 return; 765 default: 766 close(pfd[PWR]); 767 f=openfd(pfd[PRD]); 768 s=wd; 769 v=0; 770 while((c=rchr(f))!=EOF){ 771 if(strchr(stop, c) || s==ewd){ 772 if(s!=wd){ 773 *s='\0'; 774 v=newword(wd, v); 775 s=wd; 776 } 777 } 778 else *s++=c; 779 } 780 if(s!=wd){ 781 *s='\0'; 782 v=newword(wd, v); 783 } 784 closeio(f); 785 Waitfor(pid, 0); 786 /* v points to reversed arglist -- reverse it onto argv */ 787 while(v){ 788 nextv=v->next; 789 v->next=runq->argv->words; 790 runq->argv->words=v; 791 v=nextv; 792 } 793 runq->pc=runq->code[runq->pc].i; 794 return; 795 } 796 } 797 /* 798 * Who should wait for the exit from the fork? 799 */ 800 void Xpipefd(void){ 801 struct thread *p=runq; 802 int pc=p->pc; 803 char name[40]; 804 int pfd[2]; 805 int sidefd, mainfd; 806 if(pipe(pfd)<0){ 807 Xerror("can't get pipe"); 808 return; 809 } 810 if(p->code[pc].i==READ){ 811 sidefd=pfd[PWR]; 812 mainfd=pfd[PRD]; 813 } 814 else{ 815 sidefd=pfd[PRD]; 816 mainfd=pfd[PWR]; 817 } 818 switch(fork()){ 819 case -1: 820 Xerror("try again"); 821 break; 822 case 0: 823 start(p->code, pc+2, runq->local); 824 close(mainfd); 825 pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0); 826 runq->ret=0; 827 break; 828 default: 829 close(sidefd); 830 pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */ 831 strcpy(name, Fdprefix); 832 itoa(name+strlen(name), mainfd); 833 pushword(name); 834 p->pc=p->code[pc+1].i; 835 break; 836 } 837 } 838 void Xsubshell(void){ 839 int pid; 840 switch(pid=fork()){ 841 case -1: 842 Xerror("try again"); 843 break; 844 case 0: 845 start(runq->code, runq->pc+1, runq->local); 846 runq->ret=0; 847 break; 848 default: 849 Waitfor(pid, 1); 850 runq->pc=runq->code[runq->pc].i; 851 break; 852 } 853 } 854 void setstatus(char *s) 855 { 856 setvar("status", newword(s, (word *)0)); 857 } 858 char *getstatus(void){ 859 var *status=vlook("status"); 860 return status->val?status->val->word:""; 861 } 862 int truestatus(void){ 863 char *s; 864 for(s=getstatus();*s;s++) 865 if(*s!='|' && *s!='0') return 0; 866 return 1; 867 } 868 void Xdelhere(void){ 869 Unlink(runq->code[runq->pc++].s); 870 } 871 void Xfor(void){ 872 if(runq->argv->words==0){ 873 poplist(); 874 runq->pc=runq->code[runq->pc].i; 875 } 876 else{ 877 freelist(runq->local->val); 878 runq->local->val=runq->argv->words; 879 runq->local->changed=1; 880 runq->argv->words=runq->argv->words->next; 881 runq->local->val->next=0; 882 runq->pc++; 883 } 884 } 885 void Xglob(void){ 886 globlist(); 887 } 888