1 /*- 2 * Copyright (c) 1980, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 /*static char sccsid[] = "from: @(#)set.c 5.12 (Berkeley) 6/14/91";*/ 36 static char rcsid[] = "$Id: set.c,v 1.4 1993/08/01 19:00:30 mycroft Exp $"; 37 #endif /* not lint */ 38 39 #include <sys/types.h> 40 #include <stdlib.h> 41 #if __STDC__ 42 # include <stdarg.h> 43 #else 44 # include <varargs.h> 45 #endif 46 47 #include "csh.h" 48 #include "extern.h" 49 50 static Char *getinx __P((Char *, int *)); 51 static void asx __P((Char *, int, Char *)); 52 static struct varent 53 *getvx __P((Char *, int)); 54 static Char *xset __P((Char *, Char ***)); 55 static Char *operate __P((int, Char *, Char *)); 56 static void putn1 __P((int)); 57 static struct varent 58 *madrof __P((Char *, struct varent *)); 59 static void unsetv1 __P((struct varent *)); 60 static void exportpath __P((Char **)); 61 static void balance __P((struct varent *, int, int)); 62 63 64 /* 65 * C Shell 66 */ 67 68 void 69 doset(v) 70 register Char **v; 71 { 72 register Char *p; 73 Char *vp, op; 74 Char **vecp; 75 bool hadsub; 76 int subscr; 77 78 v++; 79 p = *v++; 80 if (p == 0) { 81 prvars(); 82 return; 83 } 84 do { 85 hadsub = 0; 86 vp = p; 87 if (letter(*p)) 88 for (; alnum(*p); p++) 89 continue; 90 if (vp == p || !letter(*vp)) 91 stderror(ERR_NAME | ERR_VARBEGIN); 92 if ((p - vp) > MAXVARLEN) { 93 stderror(ERR_NAME | ERR_VARTOOLONG); 94 return; 95 } 96 if (*p == '[') { 97 hadsub++; 98 p = getinx(p, &subscr); 99 } 100 if (op = *p) { 101 *p++ = 0; 102 if (*p == 0 && *v && **v == '(') 103 p = *v++; 104 } 105 else if (*v && eq(*v, STRequal)) { 106 op = '=', v++; 107 if (*v) 108 p = *v++; 109 } 110 if (op && op != '=') 111 stderror(ERR_NAME | ERR_SYNTAX); 112 if (eq(p, STRLparen)) { 113 register Char **e = v; 114 115 if (hadsub) 116 stderror(ERR_NAME | ERR_SYNTAX); 117 for (;;) { 118 if (!*e) 119 stderror(ERR_NAME | ERR_MISSING, ')'); 120 if (**e == ')') 121 break; 122 e++; 123 } 124 p = *e; 125 *e = 0; 126 vecp = saveblk(v); 127 set1(vp, vecp, &shvhed); 128 *e = p; 129 v = e + 1; 130 } 131 else if (hadsub) 132 asx(vp, subscr, Strsave(p)); 133 else 134 set(vp, Strsave(p)); 135 if (eq(vp, STRpath)) { 136 exportpath(adrof(STRpath)->vec); 137 dohash(); 138 } 139 else if (eq(vp, STRhistchars)) { 140 register Char *pn = value(STRhistchars); 141 142 HIST = *pn++; 143 HISTSUB = *pn; 144 } 145 else if (eq(vp, STRuser)) { 146 Setenv(STRUSER, value(vp)); 147 Setenv(STRLOGNAME, value(vp)); 148 } 149 else if (eq(vp, STRwordchars)) { 150 word_chars = value(vp); 151 } 152 else if (eq(vp, STRterm)) 153 Setenv(STRTERM, value(vp)); 154 else if (eq(vp, STRhome)) { 155 register Char *cp; 156 157 cp = Strsave(value(vp)); /* get the old value back */ 158 159 /* 160 * convert to cononical pathname (possibly resolving symlinks) 161 */ 162 cp = dcanon(cp, cp); 163 164 set(vp, Strsave(cp)); /* have to save the new val */ 165 166 /* and now mirror home with HOME */ 167 Setenv(STRHOME, cp); 168 /* fix directory stack for new tilde home */ 169 dtilde(); 170 xfree((ptr_t) cp); 171 } 172 #ifdef FILEC 173 else if (eq(vp, STRfilec)) 174 filec = 1; 175 #endif 176 } while (p = *v++); 177 } 178 179 static Char * 180 getinx(cp, ip) 181 register Char *cp; 182 register int *ip; 183 { 184 185 *ip = 0; 186 *cp++ = 0; 187 while (*cp && Isdigit(*cp)) 188 *ip = *ip * 10 + *cp++ - '0'; 189 if (*cp++ != ']') 190 stderror(ERR_NAME | ERR_SUBSCRIPT); 191 return (cp); 192 } 193 194 static void 195 asx(vp, subscr, p) 196 Char *vp; 197 int subscr; 198 Char *p; 199 { 200 register struct varent *v = getvx(vp, subscr); 201 202 xfree((ptr_t) v->vec[subscr - 1]); 203 v->vec[subscr - 1] = globone(p, G_APPEND); 204 } 205 206 static struct varent * 207 getvx(vp, subscr) 208 Char *vp; 209 int subscr; 210 { 211 register struct varent *v = adrof(vp); 212 213 if (v == 0) 214 udvar(vp); 215 if (subscr < 1 || subscr > blklen(v->vec)) 216 stderror(ERR_NAME | ERR_RANGE); 217 return (v); 218 } 219 220 void 221 dolet(v) 222 Char **v; 223 { 224 register Char *p; 225 Char *vp, c, op; 226 bool hadsub; 227 int subscr; 228 229 v++; 230 p = *v++; 231 if (p == 0) { 232 prvars(); 233 return; 234 } 235 do { 236 hadsub = 0; 237 vp = p; 238 if (letter(*p)) 239 for (; alnum(*p); p++) 240 continue; 241 if (vp == p || !letter(*vp)) 242 stderror(ERR_NAME | ERR_VARBEGIN); 243 if ((p - vp) > MAXVARLEN) 244 stderror(ERR_NAME | ERR_VARTOOLONG); 245 if (*p == '[') { 246 hadsub++; 247 p = getinx(p, &subscr); 248 } 249 if (*p == 0 && *v) 250 p = *v++; 251 if (op = *p) 252 *p++ = 0; 253 else 254 stderror(ERR_NAME | ERR_ASSIGN); 255 256 if (*p == '\0' && *v == NULL) 257 stderror(ERR_NAME | ERR_ASSIGN); 258 259 vp = Strsave(vp); 260 if (op == '=') { 261 c = '='; 262 p = xset(p, &v); 263 } 264 else { 265 c = *p++; 266 if (any("+-", c)) { 267 if (c != op || *p) 268 stderror(ERR_NAME | ERR_UNKNOWNOP); 269 p = Strsave(STR1); 270 } 271 else { 272 if (any("<>", op)) { 273 if (c != op) 274 stderror(ERR_NAME | ERR_UNKNOWNOP); 275 c = *p++; 276 stderror(ERR_NAME | ERR_SYNTAX); 277 } 278 if (c != '=') 279 stderror(ERR_NAME | ERR_UNKNOWNOP); 280 p = xset(p, &v); 281 } 282 } 283 if (op == '=') 284 if (hadsub) 285 asx(vp, subscr, p); 286 else 287 set(vp, p); 288 else if (hadsub) { 289 struct varent *gv = getvx(vp, subscr); 290 291 asx(vp, subscr, operate(op, gv->vec[subscr - 1], p)); 292 } 293 else 294 set(vp, operate(op, value(vp), p)); 295 if (eq(vp, STRpath)) { 296 exportpath(adrof(STRpath)->vec); 297 dohash(); 298 } 299 xfree((ptr_t) vp); 300 if (c != '=') 301 xfree((ptr_t) p); 302 } while (p = *v++); 303 } 304 305 static Char * 306 xset(cp, vp) 307 Char *cp, ***vp; 308 { 309 register Char *dp; 310 311 if (*cp) { 312 dp = Strsave(cp); 313 --(*vp); 314 xfree((ptr_t) ** vp); 315 **vp = dp; 316 } 317 return (putn(exp(vp))); 318 } 319 320 static Char * 321 operate(op, vp, p) 322 int op; 323 Char *vp, *p; 324 { 325 Char opr[2]; 326 Char *vec[5]; 327 register Char **v = vec; 328 Char **vecp = v; 329 register int i; 330 331 if (op != '=') { 332 if (*vp) 333 *v++ = vp; 334 opr[0] = op; 335 opr[1] = 0; 336 *v++ = opr; 337 if (op == '<' || op == '>') 338 *v++ = opr; 339 } 340 *v++ = p; 341 *v++ = 0; 342 i = exp(&vecp); 343 if (*vecp) 344 stderror(ERR_NAME | ERR_EXPRESSION); 345 return (putn(i)); 346 } 347 348 static Char *putp; 349 350 Char * 351 putn(n) 352 register int n; 353 { 354 int num; 355 static Char number[15]; 356 357 putp = number; 358 if (n < 0) { 359 n = -n; 360 *putp++ = '-'; 361 } 362 num = 2; /* confuse lint */ 363 if (sizeof(int) == num && n == -32768) { 364 *putp++ = '3'; 365 n = 2768; 366 #ifdef pdp11 367 } 368 #else 369 } 370 else { 371 num = 4; /* confuse lint */ 372 if (sizeof(int) == num && n == -2147483648) { 373 *putp++ = '2'; 374 n = 147483648; 375 } 376 } 377 #endif 378 putn1(n); 379 *putp = 0; 380 return (Strsave(number)); 381 } 382 383 static void 384 putn1(n) 385 register int n; 386 { 387 if (n > 9) 388 putn1(n / 10); 389 *putp++ = n % 10 + '0'; 390 } 391 392 int 393 getn(cp) 394 register Char *cp; 395 { 396 register int n; 397 int sign; 398 399 sign = 0; 400 if (cp[0] == '+' && cp[1]) 401 cp++; 402 if (*cp == '-') { 403 sign++; 404 cp++; 405 if (!Isdigit(*cp)) 406 stderror(ERR_NAME | ERR_BADNUM); 407 } 408 n = 0; 409 while (Isdigit(*cp)) 410 n = n * 10 + *cp++ - '0'; 411 if (*cp) 412 stderror(ERR_NAME | ERR_BADNUM); 413 return (sign ? -n : n); 414 } 415 416 Char * 417 value1(var, head) 418 Char *var; 419 struct varent *head; 420 { 421 register struct varent *vp; 422 423 vp = adrof1(var, head); 424 return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]); 425 } 426 427 static struct varent * 428 madrof(pat, vp) 429 Char *pat; 430 register struct varent *vp; 431 { 432 register struct varent *vp1; 433 434 for (; vp; vp = vp->v_right) { 435 if (vp->v_left && (vp1 = madrof(pat, vp->v_left))) 436 return vp1; 437 if (Gmatch(vp->v_name, pat)) 438 return vp; 439 } 440 return vp; 441 } 442 443 struct varent * 444 adrof1(name, v) 445 register Char *name; 446 register struct varent *v; 447 { 448 register cmp; 449 450 v = v->v_left; 451 while (v && ((cmp = *name - *v->v_name) || 452 (cmp = Strcmp(name, v->v_name)))) 453 if (cmp < 0) 454 v = v->v_left; 455 else 456 v = v->v_right; 457 return v; 458 } 459 460 /* 461 * The caller is responsible for putting value in a safe place 462 */ 463 void 464 set(var, val) 465 Char *var, *val; 466 { 467 register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **))); 468 469 vec[0] = val; 470 vec[1] = 0; 471 set1(var, vec, &shvhed); 472 } 473 474 void 475 set1(var, vec, head) 476 Char *var, **vec; 477 struct varent *head; 478 { 479 register Char **oldv = vec; 480 481 gflag = 0; 482 tglob(oldv); 483 if (gflag) { 484 vec = globall(oldv); 485 if (vec == 0) { 486 blkfree(oldv); 487 stderror(ERR_NAME | ERR_NOMATCH); 488 return; 489 } 490 blkfree(oldv); 491 gargv = 0; 492 } 493 setq(var, vec, head); 494 } 495 496 497 void 498 setq(name, vec, p) 499 Char *name, **vec; 500 register struct varent *p; 501 { 502 register struct varent *c; 503 register f; 504 505 f = 0; /* tree hangs off the header's left link */ 506 while (c = p->v_link[f]) { 507 if ((f = *name - *c->v_name) == 0 && 508 (f = Strcmp(name, c->v_name)) == 0) { 509 blkfree(c->vec); 510 goto found; 511 } 512 p = c; 513 f = f > 0; 514 } 515 p->v_link[f] = c = (struct varent *) xmalloc((size_t) sizeof(struct varent)); 516 c->v_name = Strsave(name); 517 c->v_bal = 0; 518 c->v_left = c->v_right = 0; 519 c->v_parent = p; 520 balance(p, f, 0); 521 found: 522 trim(c->vec = vec); 523 } 524 525 void 526 unset(v) 527 Char *v[]; 528 { 529 unset1(v, &shvhed); 530 #ifdef FILEC 531 if (adrof(STRfilec) == 0) 532 filec = 0; 533 #endif 534 if (adrof(STRhistchars) == 0) { 535 HIST = '!'; 536 HISTSUB = '^'; 537 } 538 if (adrof(STRwordchars) == 0) 539 word_chars = STR_WORD_CHARS; 540 } 541 542 void 543 unset1(v, head) 544 register Char *v[]; 545 struct varent *head; 546 { 547 register struct varent *vp; 548 register int cnt; 549 550 while (*++v) { 551 cnt = 0; 552 while (vp = madrof(*v, head->v_left)) 553 unsetv1(vp), cnt++; 554 if (cnt == 0) 555 setname(short2str(*v)); 556 } 557 } 558 559 void 560 unsetv(var) 561 Char *var; 562 { 563 register struct varent *vp; 564 565 if ((vp = adrof1(var, &shvhed)) == 0) 566 udvar(var); 567 unsetv1(vp); 568 } 569 570 static void 571 unsetv1(p) 572 register struct varent *p; 573 { 574 register struct varent *c, *pp; 575 register f; 576 577 /* 578 * Free associated memory first to avoid complications. 579 */ 580 blkfree(p->vec); 581 xfree((ptr_t) p->v_name); 582 /* 583 * If p is missing one child, then we can move the other into where p is. 584 * Otherwise, we find the predecessor of p, which is guaranteed to have no 585 * right child, copy it into p, and move it's left child into it. 586 */ 587 if (p->v_right == 0) 588 c = p->v_left; 589 else if (p->v_left == 0) 590 c = p->v_right; 591 else { 592 for (c = p->v_left; c->v_right; c = c->v_right); 593 p->v_name = c->v_name; 594 p->vec = c->vec; 595 p = c; 596 c = p->v_left; 597 } 598 /* 599 * Move c into where p is. 600 */ 601 pp = p->v_parent; 602 f = pp->v_right == p; 603 if (pp->v_link[f] = c) 604 c->v_parent = pp; 605 /* 606 * Free the deleted node, and rebalance. 607 */ 608 xfree((ptr_t) p); 609 balance(pp, f, 1); 610 } 611 612 void 613 setNS(cp) 614 Char *cp; 615 { 616 set(cp, Strsave(STRNULL)); 617 } 618 619 void 620 shift(v) 621 register Char **v; 622 { 623 register struct varent *argv; 624 register Char *name; 625 626 v++; 627 name = *v; 628 if (name == 0) 629 name = STRargv; 630 else 631 (void) strip(name); 632 argv = adrof(name); 633 if (argv == 0) 634 udvar(name); 635 if (argv->vec[0] == 0) 636 stderror(ERR_NAME | ERR_NOMORE); 637 lshift(argv->vec, 1); 638 } 639 640 static void 641 exportpath(val) 642 Char **val; 643 { 644 Char exppath[BUFSIZ]; 645 646 exppath[0] = 0; 647 if (val) 648 while (*val) { 649 if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) { 650 xprintf("Warning: ridiculously long PATH truncated\n"); 651 break; 652 } 653 (void) Strcat(exppath, *val++); 654 if (*val == 0 || eq(*val, STRRparen)) 655 break; 656 (void) Strcat(exppath, STRcolon); 657 } 658 Setenv(STRPATH, exppath); 659 } 660 661 #ifndef lint 662 /* 663 * Lint thinks these have null effect 664 */ 665 /* macros to do single rotations on node p */ 666 #define rright(p) (\ 667 t = (p)->v_left,\ 668 (t)->v_parent = (p)->v_parent,\ 669 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ 670 (t->v_right = (p))->v_parent = t,\ 671 (p) = t) 672 #define rleft(p) (\ 673 t = (p)->v_right,\ 674 (t)->v_parent = (p)->v_parent,\ 675 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ 676 (t->v_left = (p))->v_parent = t,\ 677 (p) = t) 678 #else 679 struct varent * 680 rleft(p) 681 struct varent *p; 682 { 683 return (p); 684 } 685 struct varent * 686 rright(p) 687 struct varent *p; 688 { 689 return (p); 690 } 691 692 #endif /* ! lint */ 693 694 695 /* 696 * Rebalance a tree, starting at p and up. 697 * F == 0 means we've come from p's left child. 698 * D == 1 means we've just done a delete, otherwise an insert. 699 */ 700 static void 701 balance(p, f, d) 702 register struct varent *p; 703 register int f, d; 704 { 705 register struct varent *pp; 706 707 #ifndef lint 708 register struct varent *t; /* used by the rotate macros */ 709 710 #endif 711 register ff; 712 713 /* 714 * Ok, from here on, p is the node we're operating on; pp is it's parent; f 715 * is the branch of p from which we have come; ff is the branch of pp which 716 * is p. 717 */ 718 for (; pp = p->v_parent; p = pp, f = ff) { 719 ff = pp->v_right == p; 720 if (f ^ d) { /* right heavy */ 721 switch (p->v_bal) { 722 case -1: /* was left 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 right heavy */ 729 switch (p->v_right->v_bal) { 730 case 1: /* sigle rotate */ 731 pp->v_link[ff] = rleft(p); 732 p->v_left->v_bal = 0; 733 p->v_bal = 0; 734 break; 735 case 0: /* single rotate */ 736 pp->v_link[ff] = rleft(p); 737 p->v_left->v_bal = 1; 738 p->v_bal = -1; 739 break; 740 case -1: /* double rotate */ 741 (void) rright(p->v_right); 742 pp->v_link[ff] = rleft(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 else { /* left heavy */ 754 switch (p->v_bal) { 755 case 1: /* was right heavy */ 756 p->v_bal = 0; 757 break; 758 case 0: /* was balanced */ 759 p->v_bal = -1; 760 break; 761 case -1: /* was already left heavy */ 762 switch (p->v_left->v_bal) { 763 case -1: /* single rotate */ 764 pp->v_link[ff] = rright(p); 765 p->v_right->v_bal = 0; 766 p->v_bal = 0; 767 break; 768 case 0: /* signle rotate */ 769 pp->v_link[ff] = rright(p); 770 p->v_right->v_bal = -1; 771 p->v_bal = 1; 772 break; 773 case 1: /* double rotate */ 774 (void) rleft(p->v_left); 775 pp->v_link[ff] = rright(p); 776 p->v_left->v_bal = 777 p->v_bal < 1 ? 0 : -1; 778 p->v_right->v_bal = 779 p->v_bal > -1 ? 0 : 1; 780 p->v_bal = 0; 781 break; 782 } 783 break; 784 } 785 } 786 /* 787 * If from insert, then we terminate when p is balanced. If from 788 * delete, then we terminate when p is unbalanced. 789 */ 790 if ((p->v_bal == 0) ^ d) 791 break; 792 } 793 } 794 795 void 796 plist(p) 797 register struct varent *p; 798 { 799 register struct varent *c; 800 register len; 801 802 if (setintr) 803 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); 804 805 for (;;) { 806 while (p->v_left) 807 p = p->v_left; 808 x: 809 if (p->v_parent == 0) /* is it the header? */ 810 return; 811 len = blklen(p->vec); 812 xprintf(short2str(p->v_name)); 813 xputchar('\t'); 814 if (len != 1) 815 xputchar('('); 816 blkpr(p->vec); 817 if (len != 1) 818 xputchar(')'); 819 xputchar('\n'); 820 if (p->v_right) { 821 p = p->v_right; 822 continue; 823 } 824 do { 825 c = p; 826 p = p->v_parent; 827 } while (p->v_right == c); 828 goto x; 829 } 830 } 831