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