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 /* If setting cwd variable via "set cwd=/tmp/something" 454 * then do globbing. But if we are setting the cwd 455 * becuz of a cd, chdir, pushd, popd, do not do globbing. 456 */ 457 if ( (!(eq(var,S_cwd))) || (eq(var,S_cwd) && (didchdir == 0)) ) 458 { 459 tglob(oldv); 460 } 461 if (gflag) { 462 vec = glob(oldv); 463 if (vec == 0) { 464 bferr("No match"); 465 blkfree(oldv); 466 return; 467 } 468 blkfree(oldv); 469 gargv = 0; 470 } 471 setq(var, vec, head); 472 } 473 474 void 475 setq(tchar *name, tchar **vec, struct varent *p) 476 { 477 struct varent *c; 478 int f; 479 480 #ifdef TRACE 481 tprintf("TRACE- setq()\n"); 482 #endif 483 f = 0; /* tree hangs off the header's left link */ 484 while (c = p->v_link[f]) { 485 if ((f = *name - *c->v_name) == 0 && 486 (f = strcmp_(name, c->v_name)) == 0) { 487 blkfree(c->vec); 488 goto found; 489 } 490 p = c; 491 f = f > 0; 492 } 493 p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent)); 494 c->v_name = savestr(name); 495 c->v_bal = 0; 496 c->v_left = c->v_right = 0; 497 c->v_parent = p; 498 balance(p, f, 0); 499 found: 500 trim(c->vec = vec); 501 } 502 503 void 504 unset(tchar *v[]) 505 { 506 507 #ifdef TRACE 508 tprintf("TRACE- unset()\n"); 509 #endif 510 unset1(v, &shvhed); 511 if (adrof(S_histchars/*"histchars"*/) == 0) { 512 HIST = '!'; 513 HISTSUB = '^'; 514 } 515 #ifdef FILEC 516 if (adrof(S_filec/*"filec"*/) == 0) 517 filec = 0; 518 #endif 519 } 520 521 void 522 unset1(tchar *v[], struct varent *head) 523 { 524 struct varent *vp; 525 int cnt; 526 527 #ifdef TRACE 528 tprintf("TRACE- unset1()\n"); 529 #endif 530 while (*++v) { 531 cnt = 0; 532 while (vp = madrof(*v, head->v_left)) 533 unsetv1(vp), cnt++; 534 if (cnt == 0) 535 setname(*v); 536 } 537 } 538 539 void 540 unsetv(tchar *var) 541 { 542 struct varent *vp; 543 544 #ifdef TRACE 545 tprintf("TRACE- unsetv()\n"); 546 #endif 547 if ((vp = adrof1(var, &shvhed)) == 0) 548 udvar(var); 549 unsetv1(vp); 550 } 551 552 void 553 unsetv1(struct varent *p) 554 { 555 struct varent *c, *pp; 556 int f; 557 558 #ifdef TRACE 559 tprintf("TRACE- unsetv1()\n"); 560 #endif 561 /* 562 * Free associated memory first to avoid complications. 563 */ 564 blkfree(p->vec); 565 XFREE(p->v_name); 566 /* 567 * If p is missing one child, then we can move the other 568 * into where p is. Otherwise, we find the predecessor 569 * of p, which is guaranteed to have no right child, copy 570 * it into p, and move it's left child into it. 571 */ 572 if (p->v_right == 0) 573 c = p->v_left; 574 else if (p->v_left == 0) 575 c = p->v_right; 576 else { 577 for (c = p->v_left; c->v_right; c = c->v_right) 578 ; 579 p->v_name = c->v_name; 580 p->vec = c->vec; 581 p = c; 582 c = p->v_left; 583 } 584 /* 585 * Move c into where p is. 586 */ 587 pp = p->v_parent; 588 f = pp->v_right == p; 589 if (pp->v_link[f] = c) 590 c->v_parent = pp; 591 /* 592 * Free the deleted node, and rebalance. 593 */ 594 XFREE( (tchar *)p); 595 balance(pp, f, 1); 596 } 597 598 void 599 setNS(tchar *cp) 600 { 601 #ifdef TRACE 602 tprintf("TRACE- setNS()\n"); 603 #endif 604 605 set(cp, S_/*""*/); 606 } 607 608 void 609 shift(tchar **v) 610 { 611 struct varent *argv; 612 tchar *name; 613 614 #ifdef TRACE 615 tprintf("TRACE- shift()\n"); 616 #endif 617 v++; 618 name = *v; 619 if (name == 0) 620 name = S_argv/*"argv"*/; 621 else 622 (void) strip(name); 623 argv = adrof(name); 624 if (argv == 0) 625 udvar(name); 626 if (argv->vec[0] == 0) 627 bferr("No more words"); 628 lshift(argv->vec, 1); 629 } 630 631 void 632 exportpath(tchar **val) 633 { 634 tchar exppath[PATHSIZ]; 635 636 #ifdef TRACE 637 tprintf("TRACE- exportpath()\n"); 638 #endif 639 exppath[0] = 0; 640 if (val) 641 while (*val) { 642 if (strlen_(*val) + strlen_(exppath) + 2 > PATHSIZ) { 643 printf("Warning: ridiculously long PATH truncated\n"); 644 break; 645 } 646 (void) strcat_(exppath, *val++); 647 if (*val == 0 || eq(*val, S_RPAR/*")"*/)) 648 break; 649 (void) strcat_(exppath, S_COLON/*":"*/); 650 } 651 local_setenv(S_PATH/*"PATH"*/, exppath); 652 } 653 654 /* macros to do single rotations on node p */ 655 #define rright(p) (\ 656 t = (p)->v_left,\ 657 (t)->v_parent = (p)->v_parent,\ 658 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ 659 (t->v_right = (p))->v_parent = t,\ 660 (p) = t) 661 #define rleft(p) (\ 662 t = (p)->v_right,\ 663 (t)->v_parent = (p)->v_parent,\ 664 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ 665 (t->v_left = (p))->v_parent = t,\ 666 (p) = t) 667 668 /* 669 * Rebalance a tree, starting at p and up. 670 * F == 0 means we've come from p's left child. 671 * D == 1 means we've just done a delete, otherwise an insert. 672 */ 673 void 674 balance(struct varent *p, int f, int d) 675 { 676 struct varent *pp; 677 struct varent *t; /* used by the rotate macros */ 678 int ff; 679 680 #ifdef TRACE 681 tprintf("TRACE- balance()\n"); 682 #endif 683 /* 684 * Ok, from here on, p is the node we're operating on; 685 * pp is it's parent; f is the branch of p from which we have come; 686 * ff is the branch of pp which is p. 687 */ 688 for (; pp = p->v_parent; p = pp, f = ff) { 689 ff = pp->v_right == p; 690 if (f ^ d) { /* right heavy */ 691 switch (p->v_bal) { 692 case -1: /* was left heavy */ 693 p->v_bal = 0; 694 break; 695 case 0: /* was balanced */ 696 p->v_bal = 1; 697 break; 698 case 1: /* was already right heavy */ 699 switch (p->v_right->v_bal) { 700 case 1: /* sigle rotate */ 701 pp->v_link[ff] = rleft(p); 702 p->v_left->v_bal = 0; 703 p->v_bal = 0; 704 break; 705 case 0: /* single rotate */ 706 pp->v_link[ff] = rleft(p); 707 p->v_left->v_bal = 1; 708 p->v_bal = -1; 709 break; 710 case -1: /* double rotate */ 711 rright(p->v_right); 712 pp->v_link[ff] = rleft(p); 713 p->v_left->v_bal = 714 p->v_bal < 1 ? 0 : -1; 715 p->v_right->v_bal = 716 p->v_bal > -1 ? 0 : 1; 717 p->v_bal = 0; 718 break; 719 } 720 break; 721 } 722 } else { /* left heavy */ 723 switch (p->v_bal) { 724 case 1: /* was right heavy */ 725 p->v_bal = 0; 726 break; 727 case 0: /* was balanced */ 728 p->v_bal = -1; 729 break; 730 case -1: /* was already left heavy */ 731 switch (p->v_left->v_bal) { 732 case -1: /* single rotate */ 733 pp->v_link[ff] = rright(p); 734 p->v_right->v_bal = 0; 735 p->v_bal = 0; 736 break; 737 case 0: /* signle rotate */ 738 pp->v_link[ff] = rright(p); 739 p->v_right->v_bal = -1; 740 p->v_bal = 1; 741 break; 742 case 1: /* double rotate */ 743 rleft(p->v_left); 744 pp->v_link[ff] = rright(p); 745 p->v_left->v_bal = 746 p->v_bal < 1 ? 0 : -1; 747 p->v_right->v_bal = 748 p->v_bal > -1 ? 0 : 1; 749 p->v_bal = 0; 750 break; 751 } 752 break; 753 } 754 } 755 /* 756 * If from insert, then we terminate when p is balanced. 757 * If from delete, then we terminate when p is unbalanced. 758 */ 759 if ((p->v_bal == 0) ^ d) 760 break; 761 } 762 } 763 764 void 765 plist(struct varent *p) 766 { 767 struct varent *c; 768 int len; 769 770 #ifdef TRACE 771 tprintf("TRACE- plist()\n"); 772 #endif 773 if (setintr) 774 (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT)); 775 for (;;) { 776 while (p->v_left) 777 p = p->v_left; 778 x: 779 if (p->v_parent == 0) /* is it the header? */ 780 return; 781 len = blklen(p->vec); 782 printf("%t", p->v_name); 783 Putchar('\t'); 784 if (len != 1) 785 Putchar('('); 786 blkpr(p->vec); 787 if (len != 1) 788 Putchar(')'); 789 Putchar('\n'); 790 if (p->v_right) { 791 p = p->v_right; 792 continue; 793 } 794 do { 795 c = p; 796 p = p->v_parent; 797 } while (p->v_right == c); 798 goto x; 799 } 800 } 801