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