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