1 #include "rc.h" 2 3 extern char *argv0; 4 5 int ifnot; 6 int eflagok; 7 8 /* 9 * Opcode routines 10 * Arguments on stack (...) 11 * Arguments in line [...] 12 * Code in line with jump around {...} 13 * 14 * Xappend(file)[fd] open file to append 15 * Xassign(name, val) assign val to name 16 * Xasync{... Xexit} make thread for {}, no wait 17 * Xbackq{... Xreturn} make thread for {}, push stdout 18 * Xbang complement condition 19 * Xcase(pat, value){...} exec code on match, leave (value) on 20 * stack 21 * Xclose[i] close file descriptor 22 * Xconc(left, right) concatenate, push results 23 * Xcount(name) push var count 24 * Xdelfn(name) delete function definition 25 * Xdeltraps(names) delete named traps 26 * Xdol(name) get variable value 27 * Xqdol(name) concatenate variable components 28 * Xdup[i j] dup file descriptor 29 * Xexit rc exits with status 30 * Xfalse{...} execute {} if false 31 * Xfn(name){... Xreturn} define function 32 * Xfor(var, list){... Xreturn} for loop 33 * Xjump[addr] goto 34 * Xlocal(name, val) create local variable, assign value 35 * Xmark mark stack 36 * Xmatch(pat, str) match pattern, set status 37 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads, 38 * wait for both 39 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output, 40 * depending on type), push /dev/fd/?? 41 * Xpopm(value) pop value from stack 42 * Xread(file)[fd] open file to read 43 * Xsettraps(names){... Xreturn} define trap functions 44 * Xshowtraps print trap list 45 * Xsimple(args) run command and wait 46 * Xreturn kill thread 47 * Xsubshell{... Xexit} execute {} in a subshell and wait 48 * Xtrue{...} execute {} if true 49 * Xunlocal delete local variable 50 * Xword[string] push string 51 * Xwrite(file)[fd] open file to write 52 */ 53 54 static char ** 55 rcargv(char *s) 56 { 57 char *flags; 58 59 if(flag['e']) 60 flags = "-Se"; 61 else 62 flags = "-S"; 63 return procargv(argv0, flags, "-c", s, vlook("*")->val); 64 } 65 66 void 67 Xappend(void) 68 { 69 char *file; 70 int f; 71 72 switch(count(runq->argv->words)){ 73 default: Xerror(">> requires singleton"); return; 74 case 0: Xerror(">> requires file"); return; 75 case 1: break; 76 } 77 file=runq->argv->words->word; 78 if((f=open(file, 1))<0 && (f=create(file, 1, 0666))<0){ 79 Xperror(file); 80 return; 81 } 82 seek(f, 0L, 2); 83 pushredir(ROPEN, f, runq->code[runq->pc].i); 84 runq->pc++; 85 poplist(); 86 } 87 88 void 89 Xassign(void) 90 { 91 Var *v; 92 93 if(count(runq->argv->words)!=1){ 94 Xerror("variable name not singleton!"); 95 return; 96 } 97 deglob(runq->argv->words->word); 98 v=vlook(runq->argv->words->word); 99 poplist(); 100 globlist(); 101 freewords(v->val); 102 v->val=runq->argv->words; 103 v->changed=1; 104 runq->argv->words=0; 105 poplist(); 106 } 107 108 void 109 Xasync(void) 110 { 111 uint pid; 112 char buf[20], **argv; 113 114 updenv(); 115 116 argv = rcargv(runq->code[runq->pc].s); 117 pid = proc(argv, -1, 1, 2); 118 free(argv); 119 120 if(pid == 0) { 121 Xerror("proc failed"); 122 return; 123 } 124 125 runq->pc++; 126 sprint(buf, "%d", pid); 127 setvar("apid", newword(buf, (Word *)0)); 128 } 129 130 void 131 Xbackq(void) 132 { 133 char wd[8193], **argv; 134 int c; 135 char *s, *ewd=&wd[8192], *stop; 136 Io *f; 137 Var *ifs=vlook("ifs"); 138 Word *v, *nextv; 139 int pfd[2]; 140 int pid; 141 142 stop = ifs->val?ifs->val->word:""; 143 if(pipe(pfd)<0){ 144 Xerror("can't make pipe"); 145 return; 146 } 147 148 updenv(); 149 150 argv = rcargv(runq->code[runq->pc].s); 151 pid = proc(argv, -1, pfd[1], 2); 152 free(argv); 153 154 close(pfd[1]); 155 156 if(pid == 0) { 157 Xerror("proc failed"); 158 close(pfd[0]); 159 return; 160 } 161 162 f = openfd(pfd[0]); 163 s = wd; 164 v = 0; 165 while((c=rchr(f))!=EOF){ 166 if(strchr(stop, c) || s==ewd){ 167 if(s!=wd){ 168 *s='\0'; 169 v=newword(wd, v); 170 s=wd; 171 } 172 } 173 else *s++=c; 174 } 175 if(s!=wd){ 176 *s='\0'; 177 v=newword(wd, v); 178 } 179 closeio(f); 180 waitfor(pid); 181 /* v points to reversed arglist -- reverse it onto argv */ 182 while(v){ 183 nextv=v->next; 184 v->next=runq->argv->words; 185 runq->argv->words=v; 186 v=nextv; 187 } 188 runq->pc++; 189 } 190 191 void 192 Xbang(void) 193 { 194 setstatus(truestatus()?"false":""); 195 } 196 197 void 198 Xcase(void) 199 { 200 Word *p; 201 char *s; 202 int ok=0; 203 204 s=list2str(runq->argv->next->words); 205 for(p=runq->argv->words;p;p=p->next){ 206 if(match(s, p->word, '\0')){ 207 ok=1; 208 break; 209 } 210 } 211 free(s); 212 if(ok) 213 runq->pc++; 214 else 215 runq->pc=runq->code[runq->pc].i; 216 poplist(); 217 } 218 219 void 220 Xclose(void) 221 { 222 pushredir(RCLOSE, runq->code[runq->pc].i, 0); 223 runq->pc++; 224 } 225 226 void 227 Xconc(void) 228 { 229 Word *lp=runq->argv->words; 230 Word *rp=runq->argv->next->words; 231 Word *vp=runq->argv->next->next->words; 232 int lc=count(lp), rc=count(rp); 233 234 if(lc!=0 || rc!=0){ 235 if(lc==0 || rc==0){ 236 Xerror("null list in concatenation"); 237 return; 238 } 239 if(lc!=1 && rc!=1 && lc!=rc){ 240 Xerror("mismatched list lengths in concatenation"); 241 return; 242 } 243 vp=conclist(lp, rp, vp); 244 } 245 poplist(); 246 poplist(); 247 runq->argv->words=vp; 248 } 249 250 void 251 Xcount(void) 252 { 253 Word *a; 254 char *s, *t; 255 int n; 256 char num[12]; 257 258 if(count(runq->argv->words)!=1){ 259 Xerror("variable name not singleton!"); 260 return; 261 } 262 s=runq->argv->words->word; 263 deglob(s); 264 n=0; 265 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; 266 if(n==0 || *t){ 267 a=vlook(s)->val; 268 sprint(num, "%d", count(a)); 269 } 270 else{ 271 a=vlook("*")->val; 272 sprint(num, "%d", a && 1<=n && n<=count(a)?1:0); 273 } 274 poplist(); 275 pushword(num); 276 } 277 278 void 279 Xdelfn(void) 280 { 281 Var *v; 282 Word *a; 283 284 for(a=runq->argv->words;a;a=a->next){ 285 v=gvlook(a->word); 286 if(v->fn) 287 codefree(v->fn); 288 v->fn=0; 289 v->fnchanged=1; 290 } 291 poplist(); 292 } 293 294 void 295 Xdelhere(void) 296 { 297 Var *v; 298 Word *a; 299 300 for(a=runq->argv->words;a;a=a->next){ 301 v=gvlook(a->word); 302 if(v->fn) codefree(v->fn); 303 v->fn=0; 304 v->fnchanged=1; 305 } 306 poplist(); 307 } 308 309 void 310 Xdol(void) 311 { 312 Word *a, *star; 313 char *s, *t; 314 int n; 315 316 if(count(runq->argv->words)!=1){ 317 Xerror("variable name not singleton!"); 318 return; 319 } 320 s=runq->argv->words->word; 321 deglob(s); 322 n=0; 323 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; 324 a=runq->argv->next->words; 325 if(n==0 || *t) 326 a=copywords(vlook(s)->val, a); 327 else{ 328 star=vlook("*")->val; 329 if(star && 1<=n && n<=count(star)){ 330 while(--n) star=star->next; 331 a=newword(star->word, a); 332 } 333 } 334 poplist(); 335 runq->argv->words=a; 336 } 337 338 void 339 Xdup(void) 340 { 341 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); 342 runq->pc+=2; 343 } 344 345 void 346 Xeflag(void) 347 { 348 if(eflagok && !truestatus()) 349 Xexit(); 350 } 351 352 void 353 Xexit(void) 354 { 355 Var *trapreq; 356 Word *starval; 357 char *c; 358 static int beenhere=0; 359 360 if(truestatus()) 361 c = ""; 362 else 363 c = getstatus(); 364 365 if(flag['S'] || beenhere) 366 exits(c); 367 368 trapreq=vlook("sigexit"); 369 if(trapreq->fn){ 370 beenhere=1; 371 --runq->pc; 372 starval=vlook("*")->val; 373 start(trapreq->fn, trapreq->pc, (Var*)0); 374 runq->local=newvar(strdup("*"), runq->local); 375 runq->local->val=copywords(starval, (Word*)0); 376 runq->local->changed=1; 377 runq->redir=runq->startredir=0; 378 } 379 380 exits(c); 381 } 382 383 void 384 Xfalse(void) 385 { 386 if(truestatus()) 387 runq->pc=runq->code[runq->pc].i; 388 else 389 runq->pc++; 390 } 391 392 void 393 Xfor(void) 394 { 395 if(runq->argv->words==0) { 396 poplist(); 397 runq->pc=runq->code[runq->pc].i; 398 } else { 399 freelist(runq->local->val); 400 runq->local->val=runq->argv->words; 401 runq->local->changed=1; 402 runq->argv->words=runq->argv->words->next; 403 runq->local->val->next=0; 404 runq->pc++; 405 } 406 } 407 408 void 409 Xfn(void) 410 { 411 Var *v; 412 Word *a; 413 int end; 414 415 end=runq->code[runq->pc].i; 416 for(a=runq->argv->words;a;a=a->next){ 417 v=gvlook(a->word); 418 if(v->fn) 419 codefree(v->fn); 420 v->fn=codecopy(runq->code); 421 v->pc=runq->pc+2; 422 v->fnchanged=1; 423 } 424 runq->pc=end; 425 poplist(); 426 } 427 428 void 429 Xglob(void) 430 { 431 globlist(); 432 } 433 434 void 435 Xif(void) 436 { 437 ifnot=1; 438 if(truestatus()) runq->pc++; 439 else runq->pc=runq->code[runq->pc].i; 440 } 441 442 void 443 Xifnot(void) 444 { 445 if(ifnot) 446 runq->pc++; 447 else 448 runq->pc=runq->code[runq->pc].i; 449 } 450 451 void 452 Xjump(void) 453 { 454 runq->pc=runq->code[runq->pc].i; 455 } 456 457 458 void 459 Xlocal(void) 460 { 461 if(count(runq->argv->words)!=1){ 462 Xerror("variable name must be singleton\n"); 463 return; 464 } 465 deglob(runq->argv->words->word); 466 runq->local=newvar(strdup(runq->argv->words->word), runq->local); 467 runq->local->val=copywords(runq->argv->next->words, 0); 468 runq->local->changed=1; 469 poplist(); 470 poplist(); 471 } 472 473 474 void 475 Xmark(void) 476 { 477 pushlist(); 478 } 479 480 void 481 Xmatch(void) 482 { 483 Word *p; 484 char *subject; 485 486 subject=list2str(runq->argv->words); 487 setstatus("no match"); 488 for(p=runq->argv->next->words;p;p=p->next) { 489 if(match(subject, p->word, '\0')){ 490 setstatus(""); 491 break; 492 } 493 } 494 free(subject); 495 poplist(); 496 poplist(); 497 } 498 499 void 500 Xpipe(void) 501 { 502 Thread *p=runq; 503 int pc=p->pc, pid; 504 int lfd=p->code[pc].i; 505 int rfd=p->code[pc+1].i; 506 int pfd[2]; 507 char **argv; 508 509 if(pipe(pfd)<0){ 510 Xperror("can't get pipe"); 511 return; 512 } 513 514 updenv(); 515 516 argv = rcargv(runq->code[pc+2].s); 517 pid = proc(argv, 0, pfd[1], 2); 518 free(argv); 519 close(pfd[1]); 520 521 if(pid == 0) { 522 Xerror("proc failed"); 523 close(pfd[0]); 524 return; 525 } 526 527 start(p->code, pc+4, runq->local); 528 pushredir(ROPEN, pfd[0], rfd); 529 p->pc=p->code[pc+3].i; 530 p->pid=pid; 531 } 532 533 void 534 Xpipefd(void) 535 { 536 fatal("Xpipefd"); 537 } 538 539 void 540 Xpipewait(void) 541 { 542 char status[NSTATUS+1]; 543 if(runq->pid==-1) 544 setstatus(concstatus(runq->status, getstatus())); 545 else{ 546 strncpy(status, getstatus(), NSTATUS); 547 status[NSTATUS]='\0'; 548 waitfor(runq->pid); 549 runq->pid=-1; 550 setstatus(concstatus(getstatus(), status)); 551 } 552 } 553 554 void 555 Xpopm(void) 556 { 557 poplist(); 558 } 559 560 void 561 Xpopredir(void) 562 { 563 Redir *rp=runq->redir; 564 565 if(rp==0) 566 panic("turfredir null!", 0); 567 runq->redir=rp->next; 568 if(rp->type==ROPEN) 569 close(rp->from); 570 free((char *)rp); 571 } 572 573 void 574 Xqdol(void) 575 { 576 Word *a, *p; 577 char *s; 578 int n; 579 580 if(count(runq->argv->words)!=1){ 581 Xerror("variable name not singleton!"); 582 return; 583 } 584 s=runq->argv->words->word; 585 deglob(s); 586 a=vlook(s)->val; 587 poplist(); 588 n=count(a); 589 if(n==0){ 590 pushword(""); 591 return; 592 } 593 for(p=a;p;p=p->next) n+=strlen(p->word); 594 s=malloc(n); 595 if(a){ 596 strcpy(s, a->word); 597 for(p=a->next;p;p=p->next){ 598 strcat(s, " "); 599 strcat(s, p->word); 600 } 601 } 602 else 603 s[0]='\0'; 604 pushword(s); 605 free(s); 606 } 607 608 void 609 Xrdcmds(void) 610 { 611 Thread *p=runq; 612 Word *prompt; 613 614 flush(err); 615 nerror=0; 616 if(flag['s'] && !truestatus()) 617 pfmt(err, "status=%v\n", vlook("status")->val); 618 if(runq->iflag){ 619 prompt=vlook("prompt")->val; 620 if(prompt) 621 promptstr=prompt->word; 622 else 623 promptstr="% "; 624 } 625 interrupted=0; 626 if(yyparse()) { 627 if(!p->iflag || p->eof /* && !Eintr() */) { 628 if(p->cmdfile) 629 free(p->cmdfile); 630 closeio(p->cmdfd); 631 Xreturn(); /* should this be omitted? */ 632 } else { 633 if(interrupted){ 634 pchr(err, '\n'); 635 p->eof=0; 636 } 637 --p->pc; /* go back for next command */ 638 } 639 } else { 640 --p->pc; /* re-execute Xrdcmds after codebuf runs */ 641 start(codebuf, 1, runq->local); 642 } 643 freenodes(); 644 } 645 646 void 647 Xread(void) 648 { 649 char *file; 650 int f; 651 652 switch(count(runq->argv->words)){ 653 default: Xerror("< requires singleton\n"); return; 654 case 0: Xerror("< requires file\n"); return; 655 case 1: break; 656 } 657 file=runq->argv->words->word; 658 if((f=open(file, 0))<0){ 659 Xperror(file); 660 return; 661 } 662 pushredir(ROPEN, f, runq->code[runq->pc].i); 663 runq->pc++; 664 poplist(); 665 } 666 667 void 668 Xreturn(void) 669 { 670 Thread *p=runq; 671 672 turfredir(); 673 while(p->argv) 674 poplist(); 675 codefree(p->code); 676 runq=p->ret; 677 free(p); 678 if(runq==0) 679 exits(truestatus()?"":getstatus()); 680 } 681 682 void 683 Xsettrue(void) 684 { 685 setstatus(""); 686 } 687 688 689 void 690 Xsub(void) 691 { 692 Word *a, *v; 693 char *s; 694 if(count(runq->argv->next->words)!=1){ 695 Xerror("variable name not singleton!"); 696 return; 697 } 698 s=runq->argv->next->words->word; 699 deglob(s); 700 a=runq->argv->next->next->words; 701 v=vlook(s)->val; 702 a=subwords(v, count(v), runq->argv->words, a); 703 poplist(); 704 poplist(); 705 runq->argv->words=a; 706 } 707 708 void 709 Xsubshell(void) 710 { 711 char **argv; 712 uint pid; 713 714 updenv(); 715 716 argv = rcargv(runq->code[runq->pc].s); 717 pid = proc(argv, -1, 1, 2); 718 free(argv); 719 720 if(pid == 0) { 721 Xerror("proc failed"); 722 return; 723 } 724 725 waitfor(pid); 726 runq->pc++; 727 } 728 729 void 730 Xtrue(void) 731 { 732 if(truestatus()) 733 runq->pc++; 734 else 735 runq->pc=runq->code[runq->pc].i; 736 } 737 738 void 739 Xunlocal(void) 740 { 741 Var *v=runq->local, *hid; 742 743 if(v==0) 744 panic("Xunlocal: no locals!", 0); 745 runq->local=v->next; 746 hid=vlook(v->name); 747 hid->changed=1; 748 free(v->name); 749 freewords(v->val); 750 free(v); 751 } 752 753 void 754 Xwastrue(void) 755 { 756 ifnot=0; 757 } 758 759 void 760 Xwrite(void) 761 { 762 char *file; 763 int f; 764 765 switch(count(runq->argv->words)){ 766 default: Xerror("> requires singleton\n"); return; 767 case 0: Xerror("> requires file\n"); return; 768 case 1: break; 769 } 770 file=runq->argv->words->word; 771 if((f = create(file, 1, 0666))<0){ 772 Xperror(file); 773 return; 774 } 775 pushredir(ROPEN, f, runq->code[runq->pc].i); 776 runq->pc++; 777 poplist(); 778 } 779 780 void 781 Xword(void) 782 { 783 pushword(runq->code[runq->pc++].s); 784 } 785 786 void 787 Xerror(char *s) 788 { 789 pfmt(err, "rcsh: %s\n", s); 790 flush(err); 791 while(!runq->iflag) 792 Xreturn(); 793 } 794 795 void 796 Xperror(char *s) 797 { 798 pfmt(err, "rcsh: %s: %r\n", s); 799 flush(err); 800 while(!runq->iflag) 801 Xreturn(); 802 } 803