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