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