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