1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980 Regents of the University of California. 11 * All rights reserved. The Berkeley Software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include "sh.h" 18 #include "sh.tconst.h" 19 extern int didchdir; 20 21 /* 22 * C Shell 23 */ 24 25 void asx(tchar *, int, tchar *); 26 void putn1(int); 27 void set(tchar *, tchar *); 28 void set1(tchar *, tchar **, struct varent *); 29 void setq(tchar *, tchar **, struct varent *); 30 void unset1(tchar *[], struct varent *); 31 void unsetv1(struct varent *); 32 void exportpath(tchar **); 33 void balance(struct varent *, int, int); 34 tchar *operate(tchar, tchar *, tchar *); 35 tchar *getinx(tchar *, int *); 36 tchar *xset(tchar *, tchar ***); 37 struct varent *getvx(tchar *, int); 38 39 void 40 doset(tchar **v) 41 { 42 tchar *p; 43 tchar *vp, op; 44 tchar **vecp; 45 bool hadsub; 46 int subscr; 47 tchar *retp; 48 49 #ifdef TRACE 50 tprintf("TRACE- doset()\n"); 51 #endif 52 v++; 53 p = *v++; 54 if (p == 0) { 55 prvars(); 56 return; 57 } 58 do { 59 hadsub = 0; 60 /* 61 * check for proper variable syntax 62 * must be alphanumeric, start with a letter and 63 * be at most 20 characters 64 */ 65 for (vp = p; alnum(*p); p++) 66 continue; 67 if (vp == p || !letter(*vp)) 68 goto setsyn; 69 if ((p - vp) > MAX_VAR_LEN) 70 bferr("Variable name too long"); 71 if (*p == '[') { 72 hadsub++; 73 p = getinx(p, &subscr); 74 } 75 if (op = *p) { 76 *p++ = 0; 77 if (*p == 0 && *v && **v == '(') 78 p = *v++; 79 } else if (*v && eq(*v, S_EQ /* "=" */)) { 80 op = '=', v++; 81 if (*v) 82 p = *v++; 83 } 84 if (op && op != '=') 85 setsyn: 86 bferr("Syntax error"); 87 if (eq(p, S_LPAR /* "(" */)) { 88 tchar **e = v; 89 90 if (hadsub) 91 goto setsyn; 92 for (;;) { 93 if (!*e) 94 bferr("Missing )"); 95 if (**e == ')') 96 break; 97 e++; 98 } 99 p = *e; 100 *e = 0; 101 vecp = saveblk(v); 102 set1(vp, vecp, &shvhed); 103 *e = p; 104 v = e + 1; 105 } else if (hadsub) { 106 retp = savestr(p); 107 asx(vp, subscr, retp); 108 xfree(retp); 109 retp = 0; 110 } else 111 set(vp, savestr(p)); 112 if (eq(vp, S_path /* "path" */)) { 113 exportpath(adrof(S_path /* "path" */)->vec); 114 dohash(xhash); 115 } else if (eq(vp, S_histchars /* "histchars" */)) { 116 tchar *p = value(S_histchars /* "histchars" */); 117 HIST = *p++; 118 HISTSUB = *p; 119 } else if (eq(vp, S_user /* "user" */)) 120 local_setenv(S_USER /* "USER" */, value(vp)); 121 else if (eq(vp, S_term /* "term" */)) 122 local_setenv(S_TERM /* "TERM" */, value(vp)); 123 else if (eq(vp, S_home /* "home" */)) 124 local_setenv(S_HOME /* "HOME" */, value(vp)); 125 #ifdef FILEC 126 else if (eq(vp, S_filec /* "filec" */)) 127 filec = 1; 128 else if (eq(vp, S_cdpath /* "cdpath" */)) 129 dohash(xhash2); 130 #endif 131 } while (p = *v++); 132 } 133 134 tchar * 135 getinx(tchar *cp, int *ip) 136 { 137 138 #ifdef TRACE 139 tprintf("TRACE- getinx()\n"); 140 #endif 141 *ip = 0; 142 *cp++ = 0; 143 while (*cp && digit(*cp)) 144 *ip = *ip * 10 + *cp++ - '0'; 145 if (*cp++ != ']') 146 bferr("Subscript error"); 147 return (cp); 148 } 149 150 void 151 asx(tchar *vp, int subscr, tchar *p) 152 { 153 struct varent *v = getvx(vp, subscr); 154 155 #ifdef TRACE 156 tprintf("TRACE- asx()\n"); 157 #endif 158 xfree(v->vec[subscr - 1]); 159 v->vec[subscr - 1] = globone(p); 160 } 161 162 struct varent * 163 getvx(tchar *vp, int subscr) 164 { 165 struct varent *v = adrof(vp); 166 167 #ifdef TRACE 168 tprintf("TRACE- getvx()\n"); 169 #endif 170 if (v == 0) 171 udvar(vp); 172 if (subscr < 1 || subscr > blklen(v->vec)) 173 bferr("Subscript out of range"); 174 return (v); 175 } 176 177 tchar plusplus[2] = { '1', 0 }; 178 179 void 180 dolet(tchar **v) 181 { 182 tchar *p; 183 tchar *vp, c, op; 184 bool hadsub; 185 int subscr; 186 187 v++; 188 p = *v++; 189 if (p == 0) { 190 prvars(); 191 return; 192 } 193 do { 194 hadsub = 0; 195 for (vp = p; alnum(*p); p++) 196 continue; 197 if (vp == p || !letter(*vp)) 198 goto letsyn; 199 if (*p == '[') { 200 hadsub++; 201 p = getinx(p, &subscr); 202 } 203 if (*p == 0 && *v) 204 p = *v++; 205 if (op = *p) 206 *p++ = 0; 207 else 208 goto letsyn; 209 vp = savestr(vp); 210 if (op == '=') { 211 c = '='; 212 p = xset(p, &v); 213 } else { 214 c = *p++; 215 /* if (any(c, "+-")) { */ 216 if (c == '+' || c == '-') { 217 if (c != op || *p) 218 goto letsyn; 219 p = plusplus; 220 } else { 221 /* if (any(op, "<>")) { */ 222 if (op == '<' || op == '>') { 223 if (c != op) 224 goto letsyn; 225 c = *p++; 226 letsyn: 227 bferr("Syntax error"); 228 } 229 if (c != '=') 230 goto letsyn; 231 p = xset(p, &v); 232 } 233 } 234 if (op == '=') 235 if (hadsub) 236 asx(vp, subscr, p); 237 else 238 set(vp, p); 239 else 240 if (hadsub) 241 #ifndef V6 242 /* avoid bug in vax CC */ 243 { 244 struct varent *gv = getvx(vp, subscr); 245 246 asx(vp, subscr, operate(op, gv->vec[subscr - 1], p)); 247 } 248 #else 249 asx(vp, subscr, operate(op, getvx(vp, subscr)->vec[subscr - 1], p)); 250 #endif 251 else 252 set(vp, operate(op, value(vp), p)); 253 if (eq(vp, S_path /* "path" */)) { 254 exportpath(adrof(S_path /* "path" */)->vec); 255 dohash(xhash); 256 } 257 258 if (eq(vp, S_cdpath /* "cdpath" */)) 259 dohash(xhash2); 260 261 xfree(vp); 262 if (c != '=') 263 xfree(p); 264 } while (p = *v++); 265 } 266 267 tchar * 268 xset(tchar *cp, tchar ***vp) 269 { 270 tchar *dp; 271 272 #ifdef TRACE 273 tprintf("TRACE- xset()\n"); 274 #endif 275 if (*cp) { 276 dp = savestr(cp); 277 --(*vp); 278 xfree(**vp); 279 **vp = dp; 280 } 281 return (putn(exp(vp))); 282 } 283 284 tchar * 285 operate(tchar op, tchar *vp, tchar *p) 286 { 287 tchar opr[2]; 288 tchar *vec[5]; 289 tchar **v = vec; 290 tchar **vecp = v; 291 int i; 292 293 if (op != '=') { 294 if (*vp) 295 *v++ = vp; 296 opr[0] = op; 297 opr[1] = 0; 298 *v++ = opr; 299 if (op == '<' || op == '>') 300 *v++ = opr; 301 } 302 *v++ = p; 303 *v++ = 0; 304 i = exp(&vecp); 305 if (*vecp) 306 bferr("Expression syntax"); 307 return (putn(i)); 308 } 309 310 static tchar *putp; 311 312 tchar * 313 putn(int n) 314 { 315 static tchar number[15]; 316 317 #ifdef TRACE 318 tprintf("TRACE- putn()\n"); 319 #endif 320 putp = number; 321 if (n < 0) { 322 n = -n; 323 *putp++ = '-'; 324 } 325 if (sizeof (int) == 2 && n == -32768) { 326 *putp++ = '3'; 327 n = 2768; 328 #ifdef pdp11 329 } 330 #else 331 } else if (sizeof (int) == 4 && n == 0x80000000) { 332 *putp++ = '2'; 333 n = 147483648; 334 } 335 #endif 336 putn1(n); 337 *putp = 0; 338 return (savestr(number)); 339 } 340 341 void 342 putn1(int n) 343 { 344 #ifdef TRACE 345 tprintf("TRACE- putn1()\n"); 346 #endif 347 if (n > 9) 348 putn1(n / 10); 349 *putp++ = n % 10 + '0'; 350 } 351 352 int 353 getn(tchar *cp) 354 { 355 int n; 356 int sign; 357 358 #ifdef TRACE 359 tprintf("TRACE- getn()\n"); 360 #endif 361 sign = 0; 362 if (cp[0] == '+' && cp[1]) 363 cp++; 364 if (*cp == '-') { 365 sign++; 366 cp++; 367 if (!digit(*cp)) 368 goto badnum; 369 } 370 n = 0; 371 while (digit(*cp)) 372 n = n * 10 + *cp++ - '0'; 373 if (*cp) 374 goto badnum; 375 return (sign ? -n : n); 376 badnum: 377 bferr("Badly formed number"); 378 return (0); 379 } 380 381 tchar * 382 value1(tchar *var, struct varent *head) 383 { 384 struct varent *vp; 385 386 #ifdef TRACE 387 tprintf("TRACE- value1()\n"); 388 #endif 389 vp = adrof1(var, head); 390 return (vp == 0 || vp->vec[0] == 0 ? S_ /* "" */ : vp->vec[0]); 391 } 392 393 struct varent * 394 madrof(tchar *pat, struct varent *vp) 395 { 396 struct varent *vp1; 397 398 #ifdef TRACE 399 tprintf("TRACE- madrof()\n"); 400 #endif 401 for (; vp; vp = vp->v_right) { 402 if (vp->v_left && (vp1 = madrof(pat, vp->v_left))) 403 return vp1; 404 if (Gmatch(vp->v_name, pat)) 405 return vp; 406 } 407 return vp; 408 } 409 410 struct varent * 411 adrof1(tchar *name, struct varent *v) 412 { 413 int cmp; 414 415 #ifdef TRACE 416 tprintf("TRACE- adrof1()\n"); 417 #endif 418 v = v->v_left; 419 while (v && ((cmp = *name - *v->v_name) || 420 (cmp = strcmp_(name, v->v_name)))) 421 if (cmp < 0) 422 v = v->v_left; 423 else 424 v = v->v_right; 425 return v; 426 } 427 428 /* 429 * The caller is responsible for putting value in a safe place 430 */ 431 void 432 set(tchar *var, tchar *val) 433 { 434 tchar **vec = (tchar **)xalloc(2 * sizeof (tchar **)); 435 436 #ifdef TRACE 437 tprintf("TRACE- set()\n"); 438 #endif 439 vec[0] = onlyread(val) ? savestr(val) : val; 440 vec[1] = 0; 441 set1(var, vec, &shvhed); 442 } 443 444 void 445 set1(tchar *var, tchar **vec, struct varent *head) 446 { 447 tchar **oldv = vec; 448 449 #ifdef TRACE 450 tprintf("TRACE- set1()\n"); 451 #endif 452 gflag = 0; 453 /* 454 * If setting cwd variable via "set cwd=/tmp/something" 455 * then do globbing. But if we are setting the cwd 456 * becuz of a cd, chdir, pushd, popd, do not do globbing. 457 */ 458 if ((!(eq(var, S_cwd))) || (eq(var, S_cwd) && (didchdir == 0))) 459 { 460 tglob(oldv); 461 } 462 if (gflag) { 463 vec = glob(oldv); 464 if (vec == 0) { 465 bferr("No match"); 466 blkfree(oldv); 467 return; 468 } 469 blkfree(oldv); 470 gargv = 0; 471 } 472 setq(var, vec, head); 473 } 474 475 void 476 setq(tchar *name, tchar **vec, struct varent *p) 477 { 478 struct varent *c; 479 int f; 480 481 #ifdef TRACE 482 tprintf("TRACE- setq()\n"); 483 #endif 484 f = 0; /* tree hangs off the header's left link */ 485 while (c = p->v_link[f]) { 486 if ((f = *name - *c->v_name) == 0 && 487 (f = strcmp_(name, c->v_name)) == 0) { 488 blkfree(c->vec); 489 goto found; 490 } 491 p = c; 492 f = f > 0; 493 } 494 p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent)); 495 c->v_name = savestr(name); 496 c->v_bal = 0; 497 c->v_left = c->v_right = 0; 498 c->v_parent = p; 499 balance(p, f, 0); 500 found: 501 trim(c->vec = vec); 502 } 503 504 void 505 unset(tchar *v[]) 506 { 507 508 #ifdef TRACE 509 tprintf("TRACE- unset()\n"); 510 #endif 511 unset1(v, &shvhed); 512 if (adrof(S_histchars /* "histchars" */) == 0) { 513 HIST = '!'; 514 HISTSUB = '^'; 515 } 516 #ifdef FILEC 517 if (adrof(S_filec /* "filec" */) == 0) 518 filec = 0; 519 #endif 520 } 521 522 void 523 unset1(tchar *v[], struct varent *head) 524 { 525 struct varent *vp; 526 int cnt; 527 528 #ifdef TRACE 529 tprintf("TRACE- unset1()\n"); 530 #endif 531 while (*++v) { 532 cnt = 0; 533 while (vp = madrof(*v, head->v_left)) 534 unsetv1(vp), cnt++; 535 if (cnt == 0) 536 setname(*v); 537 } 538 } 539 540 void 541 unsetv(tchar *var) 542 { 543 struct varent *vp; 544 545 #ifdef TRACE 546 tprintf("TRACE- unsetv()\n"); 547 #endif 548 if ((vp = adrof1(var, &shvhed)) == 0) 549 udvar(var); 550 unsetv1(vp); 551 } 552 553 void 554 unsetv1(struct varent *p) 555 { 556 struct varent *c, *pp; 557 int f; 558 559 #ifdef TRACE 560 tprintf("TRACE- unsetv1()\n"); 561 #endif 562 /* 563 * Free associated memory first to avoid complications. 564 */ 565 blkfree(p->vec); 566 xfree(p->v_name); 567 /* 568 * If p is missing one child, then we can move the other 569 * into where p is. Otherwise, we find the predecessor 570 * of p, which is guaranteed to have no right child, copy 571 * it into p, and move it's left child into it. 572 */ 573 if (p->v_right == 0) 574 c = p->v_left; 575 else if (p->v_left == 0) 576 c = p->v_right; 577 else { 578 for (c = p->v_left; c->v_right; c = c->v_right) 579 ; 580 p->v_name = c->v_name; 581 p->vec = c->vec; 582 p = c; 583 c = p->v_left; 584 } 585 /* 586 * Move c into where p is. 587 */ 588 pp = p->v_parent; 589 f = pp->v_right == p; 590 if (pp->v_link[f] = c) 591 c->v_parent = pp; 592 /* 593 * Free the deleted node, and rebalance. 594 */ 595 xfree(p); 596 balance(pp, f, 1); 597 } 598 599 void 600 setNS(tchar *cp) 601 { 602 #ifdef TRACE 603 tprintf("TRACE- setNS()\n"); 604 #endif 605 606 set(cp, S_ /* "" */); 607 } 608 609 void 610 shift(tchar **v) 611 { 612 struct varent *argv; 613 tchar *name; 614 615 #ifdef TRACE 616 tprintf("TRACE- shift()\n"); 617 #endif 618 v++; 619 name = *v; 620 if (name == 0) 621 name = S_argv /* "argv" */; 622 else 623 (void) strip(name); 624 argv = adrof(name); 625 if (argv == 0) 626 udvar(name); 627 if (argv->vec[0] == 0) 628 bferr("No more words"); 629 lshift(argv->vec, 1); 630 } 631 632 void 633 exportpath(tchar **val) 634 { 635 tchar exppath[PATHSIZ]; 636 637 #ifdef TRACE 638 tprintf("TRACE- exportpath()\n"); 639 #endif 640 exppath[0] = 0; 641 if (val) 642 while (*val) { 643 if (strlen_(*val) + strlen_(exppath) + 2 > PATHSIZ) { 644 printf("Warning: ridiculously long PATH truncated\n"); 645 break; 646 } 647 (void) strcat_(exppath, *val++); 648 if (*val == 0 || eq(*val, S_RPAR /* ")" */)) 649 break; 650 (void) strcat_(exppath, S_COLON /* ":" */); 651 } 652 local_setenv(S_PATH /* "PATH" */, exppath); 653 } 654 655 /* macros to do single rotations on node p */ 656 #define rright(p) (\ 657 t = (p)->v_left,\ 658 (t)->v_parent = (p)->v_parent,\ 659 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ 660 (t->v_right = (p))->v_parent = t,\ 661 (p) = t) 662 #define rleft(p) (\ 663 t = (p)->v_right,\ 664 (t)->v_parent = (p)->v_parent,\ 665 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ 666 (t->v_left = (p))->v_parent = t,\ 667 (p) = t) 668 669 /* 670 * Rebalance a tree, starting at p and up. 671 * F == 0 means we've come from p's left child. 672 * D == 1 means we've just done a delete, otherwise an insert. 673 */ 674 void 675 balance(struct varent *p, int f, int d) 676 { 677 struct varent *pp; 678 struct varent *t; /* used by the rotate macros */ 679 int ff; 680 681 #ifdef TRACE 682 tprintf("TRACE- balance()\n"); 683 #endif 684 /* 685 * Ok, from here on, p is the node we're operating on; 686 * pp is it's parent; f is the branch of p from which we have come; 687 * ff is the branch of pp which is p. 688 */ 689 for (; pp = p->v_parent; p = pp, f = ff) { 690 ff = pp->v_right == p; 691 if (f ^ d) { /* right heavy */ 692 switch (p->v_bal) { 693 case -1: /* was left heavy */ 694 p->v_bal = 0; 695 break; 696 case 0: /* was balanced */ 697 p->v_bal = 1; 698 break; 699 case 1: /* was already right heavy */ 700 switch (p->v_right->v_bal) { 701 case 1: /* sigle rotate */ 702 pp->v_link[ff] = rleft(p); 703 p->v_left->v_bal = 0; 704 p->v_bal = 0; 705 break; 706 case 0: /* single rotate */ 707 pp->v_link[ff] = rleft(p); 708 p->v_left->v_bal = 1; 709 p->v_bal = -1; 710 break; 711 case -1: /* double rotate */ 712 rright(p->v_right); 713 pp->v_link[ff] = rleft(p); 714 p->v_left->v_bal = 715 p->v_bal < 1 ? 0 : -1; 716 p->v_right->v_bal = 717 p->v_bal > -1 ? 0 : 1; 718 p->v_bal = 0; 719 break; 720 } 721 break; 722 } 723 } else { /* left heavy */ 724 switch (p->v_bal) { 725 case 1: /* was right heavy */ 726 p->v_bal = 0; 727 break; 728 case 0: /* was balanced */ 729 p->v_bal = -1; 730 break; 731 case -1: /* was already left heavy */ 732 switch (p->v_left->v_bal) { 733 case -1: /* single rotate */ 734 pp->v_link[ff] = rright(p); 735 p->v_right->v_bal = 0; 736 p->v_bal = 0; 737 break; 738 case 0: /* signle rotate */ 739 pp->v_link[ff] = rright(p); 740 p->v_right->v_bal = -1; 741 p->v_bal = 1; 742 break; 743 case 1: /* double rotate */ 744 rleft(p->v_left); 745 pp->v_link[ff] = rright(p); 746 p->v_left->v_bal = 747 p->v_bal < 1 ? 0 : -1; 748 p->v_right->v_bal = 749 p->v_bal > -1 ? 0 : 1; 750 p->v_bal = 0; 751 break; 752 } 753 break; 754 } 755 } 756 /* 757 * If from insert, then we terminate when p is balanced. 758 * If from delete, then we terminate when p is unbalanced. 759 */ 760 if ((p->v_bal == 0) ^ d) 761 break; 762 } 763 } 764 765 void 766 plist(struct varent *p) 767 { 768 struct varent *c; 769 int len; 770 771 #ifdef TRACE 772 tprintf("TRACE- plist()\n"); 773 #endif 774 if (setintr) 775 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT)); 776 for (;;) { 777 while (p->v_left) 778 p = p->v_left; 779 x: 780 if (p->v_parent == 0) /* is it the header? */ 781 return; 782 len = blklen(p->vec); 783 printf("%t", p->v_name); 784 Putchar('\t'); 785 if (len != 1) 786 Putchar('('); 787 blkpr(p->vec); 788 if (len != 1) 789 Putchar(')'); 790 Putchar('\n'); 791 if (p->v_right) { 792 p = p->v_right; 793 continue; 794 } 795 do { 796 c = p; 797 p = p->v_parent; 798 } while (p->v_right == c); 799 goto x; 800 } 801 } 802