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