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