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