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