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.17 (Berkeley) 11/06/91"; 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) { 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++); 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) 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++); 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 && n == -32768) { 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 && n == -2147483648) { 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]) { 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)) 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) 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 (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(p) 667 struct varent *p; 668 { 669 return (p); 670 } 671 struct varent * 672 rright(p) 673 struct varent *p; 674 { 675 return (p); 676 } 677 678 #endif /* ! lint */ 679 680 681 /* 682 * Rebalance a tree, starting at p and up. 683 * F == 0 means we've come from p's left child. 684 * D == 1 means we've just done a delete, otherwise an insert. 685 */ 686 static void 687 balance(p, f, d) 688 register struct varent *p; 689 register int f, d; 690 { 691 register struct varent *pp; 692 693 #ifndef lint 694 register struct varent *t; /* used by the rotate macros */ 695 696 #endif 697 register ff; 698 699 /* 700 * Ok, from here on, p is the node we're operating on; pp is it's parent; f 701 * is the branch of p from which we have come; ff is the branch of pp which 702 * is p. 703 */ 704 for (; pp = p->v_parent; p = pp, f = ff) { 705 ff = pp->v_right == p; 706 if (f ^ d) { /* right heavy */ 707 switch (p->v_bal) { 708 case -1: /* was left heavy */ 709 p->v_bal = 0; 710 break; 711 case 0: /* was balanced */ 712 p->v_bal = 1; 713 break; 714 case 1: /* was already right heavy */ 715 switch (p->v_right->v_bal) { 716 case 1: /* sigle rotate */ 717 pp->v_link[ff] = rleft(p); 718 p->v_left->v_bal = 0; 719 p->v_bal = 0; 720 break; 721 case 0: /* single rotate */ 722 pp->v_link[ff] = rleft(p); 723 p->v_left->v_bal = 1; 724 p->v_bal = -1; 725 break; 726 case -1: /* double rotate */ 727 (void) rright(p->v_right); 728 pp->v_link[ff] = rleft(p); 729 p->v_left->v_bal = 730 p->v_bal < 1 ? 0 : -1; 731 p->v_right->v_bal = 732 p->v_bal > -1 ? 0 : 1; 733 p->v_bal = 0; 734 break; 735 } 736 break; 737 } 738 } 739 else { /* left heavy */ 740 switch (p->v_bal) { 741 case 1: /* was right heavy */ 742 p->v_bal = 0; 743 break; 744 case 0: /* was balanced */ 745 p->v_bal = -1; 746 break; 747 case -1: /* was already left heavy */ 748 switch (p->v_left->v_bal) { 749 case -1: /* single rotate */ 750 pp->v_link[ff] = rright(p); 751 p->v_right->v_bal = 0; 752 p->v_bal = 0; 753 break; 754 case 0: /* signle rotate */ 755 pp->v_link[ff] = rright(p); 756 p->v_right->v_bal = -1; 757 p->v_bal = 1; 758 break; 759 case 1: /* double rotate */ 760 (void) rleft(p->v_left); 761 pp->v_link[ff] = rright(p); 762 p->v_left->v_bal = 763 p->v_bal < 1 ? 0 : -1; 764 p->v_right->v_bal = 765 p->v_bal > -1 ? 0 : 1; 766 p->v_bal = 0; 767 break; 768 } 769 break; 770 } 771 } 772 /* 773 * If from insert, then we terminate when p is balanced. If from 774 * delete, then we terminate when p is unbalanced. 775 */ 776 if ((p->v_bal == 0) ^ d) 777 break; 778 } 779 } 780 781 void 782 plist(p) 783 register struct varent *p; 784 { 785 register struct varent *c; 786 register len; 787 788 if (setintr) 789 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); 790 791 for (;;) { 792 while (p->v_left) 793 p = p->v_left; 794 x: 795 if (p->v_parent == 0) /* is it the header? */ 796 return; 797 len = blklen(p->vec); 798 (void) fprintf(cshout, short2str(p->v_name)); 799 (void) fputc('\t', cshout); 800 if (len != 1) 801 (void) fputc('(', cshout); 802 blkpr(cshout, p->vec); 803 if (len != 1) 804 (void) fputc(')', cshout); 805 (void) fputc('\n', cshout); 806 if (p->v_right) { 807 p = p->v_right; 808 continue; 809 } 810 do { 811 c = p; 812 p = p->v_parent; 813 } while (p->v_right == c); 814 goto x; 815 } 816 } 817