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