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