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