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