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