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