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