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