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