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