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