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.5 1994/09/21 00:11:16 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 if ((**val != '/' || **val == '\0') && (euid == 0 || uid == 0)) 667 (void) fprintf(csherr, 668 "Warning: exported path contains relative components.\n"); 669 (void) Strcat(exppath, *val++); 670 if (*val == 0 || eq(*val, STRRparen)) 671 break; 672 (void) Strcat(exppath, STRcolon); 673 } 674 Setenv(STRPATH, exppath); 675 } 676 677 #ifndef lint 678 /* 679 * Lint thinks these have null effect 680 */ 681 /* macros to do single rotations on node p */ 682 #define rright(p) (\ 683 t = (p)->v_left,\ 684 (t)->v_parent = (p)->v_parent,\ 685 ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ 686 (t->v_right = (p))->v_parent = t,\ 687 (p) = t) 688 #define rleft(p) (\ 689 t = (p)->v_right,\ 690 (t)->v_parent = (p)->v_parent,\ 691 ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ 692 (t->v_left = (p))->v_parent = t,\ 693 (p) = t) 694 #else 695 struct varent * 696 rleft(p) 697 struct varent *p; 698 { 699 return (p); 700 } 701 struct varent * 702 rright(p) 703 struct varent *p; 704 { 705 return (p); 706 } 707 708 #endif /* ! lint */ 709 710 711 /* 712 * Rebalance a tree, starting at p and up. 713 * F == 0 means we've come from p's left child. 714 * D == 1 means we've just done a delete, otherwise an insert. 715 */ 716 static void 717 balance(p, f, d) 718 register struct varent *p; 719 register int f, d; 720 { 721 register struct varent *pp; 722 723 #ifndef lint 724 register struct varent *t; /* used by the rotate macros */ 725 726 #endif 727 register ff; 728 729 /* 730 * Ok, from here on, p is the node we're operating on; pp is it's parent; f 731 * is the branch of p from which we have come; ff is the branch of pp which 732 * is p. 733 */ 734 for (; (pp = p->v_parent) != NULL; p = pp, f = ff) { 735 ff = pp->v_right == p; 736 if (f ^ d) { /* right heavy */ 737 switch (p->v_bal) { 738 case -1: /* was left heavy */ 739 p->v_bal = 0; 740 break; 741 case 0: /* was balanced */ 742 p->v_bal = 1; 743 break; 744 case 1: /* was already right heavy */ 745 switch (p->v_right->v_bal) { 746 case 1: /* sigle rotate */ 747 pp->v_link[ff] = rleft(p); 748 p->v_left->v_bal = 0; 749 p->v_bal = 0; 750 break; 751 case 0: /* single rotate */ 752 pp->v_link[ff] = rleft(p); 753 p->v_left->v_bal = 1; 754 p->v_bal = -1; 755 break; 756 case -1: /* double rotate */ 757 (void) rright(p->v_right); 758 pp->v_link[ff] = rleft(p); 759 p->v_left->v_bal = 760 p->v_bal < 1 ? 0 : -1; 761 p->v_right->v_bal = 762 p->v_bal > -1 ? 0 : 1; 763 p->v_bal = 0; 764 break; 765 } 766 break; 767 } 768 } 769 else { /* left heavy */ 770 switch (p->v_bal) { 771 case 1: /* was right heavy */ 772 p->v_bal = 0; 773 break; 774 case 0: /* was balanced */ 775 p->v_bal = -1; 776 break; 777 case -1: /* was already left heavy */ 778 switch (p->v_left->v_bal) { 779 case -1: /* single rotate */ 780 pp->v_link[ff] = rright(p); 781 p->v_right->v_bal = 0; 782 p->v_bal = 0; 783 break; 784 case 0: /* signle rotate */ 785 pp->v_link[ff] = rright(p); 786 p->v_right->v_bal = -1; 787 p->v_bal = 1; 788 break; 789 case 1: /* double rotate */ 790 (void) rleft(p->v_left); 791 pp->v_link[ff] = rright(p); 792 p->v_left->v_bal = 793 p->v_bal < 1 ? 0 : -1; 794 p->v_right->v_bal = 795 p->v_bal > -1 ? 0 : 1; 796 p->v_bal = 0; 797 break; 798 } 799 break; 800 } 801 } 802 /* 803 * If from insert, then we terminate when p is balanced. If from 804 * delete, then we terminate when p is unbalanced. 805 */ 806 if ((p->v_bal == 0) ^ d) 807 break; 808 } 809 } 810 811 void 812 plist(p) 813 register struct varent *p; 814 { 815 register struct varent *c; 816 register len; 817 818 if (setintr) 819 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); 820 821 for (;;) { 822 while (p->v_left) 823 p = p->v_left; 824 x: 825 if (p->v_parent == 0) /* is it the header? */ 826 return; 827 len = blklen(p->vec); 828 (void) fprintf(cshout, "%s\t", short2str(p->v_name)); 829 if (len != 1) 830 (void) fputc('(', cshout); 831 blkpr(cshout, p->vec); 832 if (len != 1) 833 (void) fputc(')', cshout); 834 (void) fputc('\n', cshout); 835 if (p->v_right) { 836 p = p->v_right; 837 continue; 838 } 839 do { 840 c = p; 841 p = p->v_parent; 842 } while (p->v_right == c); 843 goto x; 844 } 845 } 846