1 /* 2 * sh.set.c: Setting and Clearing of variables 3 */ 4 /*- 5 * Copyright (c) 1980, 1991 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 #include "sh.h" 33 #include "ed.h" 34 #include "tw.h" 35 36 #ifdef HAVE_NL_LANGINFO 37 #include <langinfo.h> 38 #endif 39 40 extern int GotTermCaps; 41 int numeof = 0; 42 43 static void update_vars (Char *); 44 static Char *getinx (Char *, int *); 45 static void asx (Char *, int, Char *); 46 static struct varent *getvx (Char *, int); 47 static Char *xset (Char *, Char ***); 48 static Char *operate (int, Char *, Char *); 49 static void putn1 (tcsh_number_t); 50 static struct varent *madrof (Char *, struct varent *); 51 static void unsetv1 (struct varent *); 52 static void balance (struct varent *, int, int); 53 static int set_noclobber (Char **); 54 55 /* 56 * C Shell 57 */ 58 59 static void 60 update_vars(Char *vp) 61 { 62 if (eq(vp, STRpath)) { 63 struct varent *p = adrof(STRpath); 64 if (p == NULL) 65 stderror(ERR_NAME | ERR_UNDVAR); 66 else { 67 exportpath(p->vec); 68 dohash(NULL, NULL); 69 } 70 } 71 else if (eq(vp, STRnoclobber)) { 72 struct varent *p = adrof(STRnoclobber); 73 if (p == NULL) 74 stderror(ERR_NAME | ERR_UNDVAR); 75 else 76 no_clobber = set_noclobber(p->vec); 77 } 78 else if (eq(vp, STRhistchars)) { 79 Char *pn = varval(vp); 80 81 HIST = *pn++; 82 if (HIST) 83 HISTSUB = *pn; 84 else 85 HISTSUB = HIST; 86 } 87 else if (eq(vp, STRpromptchars)) { 88 Char *pn = varval(vp); 89 90 PRCH = *pn++; 91 if (PRCH) 92 PRCHROOT = *pn; 93 else 94 PRCHROOT = PRCH; 95 } 96 else if (eq(vp, STRhistlit)) { 97 HistLit = 1; 98 } 99 else if (eq(vp, STRuser)) { 100 tsetenv(STRKUSER, varval(vp)); 101 tsetenv(STRLOGNAME, varval(vp)); 102 } 103 else if (eq(vp, STRgroup)) { 104 tsetenv(STRKGROUP, varval(vp)); 105 } 106 else if (eq(vp, STRwordchars)) { 107 word_chars = varval(vp); 108 } 109 else if (eq(vp, STRloginsh)) { 110 loginsh = 1; 111 } 112 else if (eq(vp, STRanyerror)) { 113 anyerror = 1; 114 } 115 else if (eq(vp, STRsymlinks)) { 116 Char *pn = varval(vp); 117 118 if (eq(pn, STRignore)) 119 symlinks = SYM_IGNORE; 120 else if (eq(pn, STRexpand)) 121 symlinks = SYM_EXPAND; 122 else if (eq(pn, STRchase)) 123 symlinks = SYM_CHASE; 124 else 125 symlinks = 0; 126 } 127 else if (eq(vp, STRterm)) { 128 Char *cp = varval(vp); 129 tsetenv(STRKTERM, cp); 130 #ifdef DOESNT_WORK_RIGHT 131 cp = getenv("TERMCAP"); 132 if (cp && (*cp != '/')) /* if TERMCAP and not a path */ 133 Unsetenv(STRTERMCAP); 134 #endif /* DOESNT_WORK_RIGHT */ 135 GotTermCaps = 0; 136 if (noediting && Strcmp(cp, STRnetwork) != 0 && 137 Strcmp(cp, STRunknown) != 0 && Strcmp(cp, STRdumb) != 0) { 138 editing = 1; 139 noediting = 0; 140 setNS(STRedit); 141 } 142 ed_Init(); /* reset the editor */ 143 } 144 else if (eq(vp, STRhome)) { 145 Char *cp, *canon; 146 147 cp = Strsave(varval(vp)); /* get the old value back */ 148 /* 149 * convert to cononical pathname (possibly resolving symlinks) 150 */ 151 canon = dcanon(cp, cp); 152 cleanup_push(canon, xfree); 153 154 setcopy(vp, canon, VAR_READWRITE); /* have to save the new val */ 155 156 /* and now mirror home with HOME */ 157 tsetenv(STRKHOME, canon); 158 /* fix directory stack for new tilde home */ 159 dtilde(); 160 cleanup_until(canon); 161 } 162 else if (eq(vp, STRedit)) { 163 editing = 1; 164 noediting = 0; 165 /* PWP: add more stuff in here later */ 166 } 167 else if (eq(vp, STRvimode)) { 168 VImode = 1; 169 update_wordchars(); 170 } 171 else if (eq(vp, STRshlvl)) { 172 tsetenv(STRKSHLVL, varval(vp)); 173 } 174 else if (eq(vp, STRignoreeof)) { 175 Char *cp; 176 numeof = 0; 177 for ((cp = varval(STRignoreeof)); cp && *cp; cp++) { 178 if (!Isdigit(*cp)) { 179 numeof = 0; 180 break; 181 } 182 numeof = numeof * 10 + *cp - '0'; 183 } 184 if (numeof <= 0) numeof = 26; /* Sanity check */ 185 } 186 else if (eq(vp, STRbackslash_quote)) { 187 bslash_quote = 1; 188 } 189 else if (eq(vp, STRcompat_expr)) { 190 compat_expr = 1; 191 } 192 else if (eq(vp, STRdirstack)) { 193 dsetstack(); 194 } 195 else if (eq(vp, STRrecognize_only_executables)) { 196 tw_cmd_free(); 197 } 198 else if (eq(vp, STRkillring)) { 199 SetKillRing((int)getn(varval(vp))); 200 } 201 else if (eq(vp, STRhistory)) { 202 sethistory((int)getn(varval(vp))); 203 } 204 #ifndef HAVENOUTMP 205 else if (eq(vp, STRwatch)) { 206 resetwatch(); 207 } 208 #endif /* HAVENOUTMP */ 209 else if (eq(vp, STRimplicitcd)) { 210 implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1); 211 } 212 else if (eq(vp, STRcdtohome)) { 213 cdtohome = 1; 214 } 215 #ifdef COLOR_LS_F 216 else if (eq(vp, STRcolor)) { 217 set_color_context(); 218 } 219 #endif /* COLOR_LS_F */ 220 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 221 else if (eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) { 222 update_dspmbyte_vars(); 223 } 224 #endif 225 #ifdef NLS_CATALOGS 226 else if (eq(vp, STRcatalog)) { 227 nlsclose(); 228 nlsinit(); 229 } 230 #if defined(FILEC) && defined(TIOCSTI) 231 else if (eq(vp, STRfilec)) 232 filec = 1; 233 #endif 234 #endif /* NLS_CATALOGS */ 235 } 236 237 238 /*ARGSUSED*/ 239 void 240 doset(Char **v, struct command *c) 241 { 242 Char *p; 243 Char *vp; 244 Char **vecp; 245 int hadsub; 246 int subscr; 247 int flags = VAR_READWRITE; 248 int first_match = 0; 249 int last_match = 0; 250 int changed = 0; 251 252 USE(c); 253 v++; 254 do { 255 changed = 0; 256 /* 257 * Readonly addition From: Tim P. Starrin <noid@cyborg.larc.nasa.gov> 258 */ 259 if (*v && eq(*v, STRmr)) { 260 flags = VAR_READONLY; 261 v++; 262 changed = 1; 263 } 264 if (*v && eq(*v, STRmf) && !last_match) { 265 first_match = 1; 266 v++; 267 changed = 1; 268 } 269 if (*v && eq(*v, STRml) && !first_match) { 270 last_match = 1; 271 v++; 272 changed = 1; 273 } 274 } while (changed); 275 p = *v++; 276 if (p == 0) { 277 plist(&shvhed, flags); 278 return; 279 } 280 do { 281 hadsub = 0; 282 vp = p; 283 if (!letter(*p)) 284 stderror(ERR_NAME | ERR_VARBEGIN); 285 do { 286 p++; 287 } while (alnum(*p)); 288 if (*p == '[') { 289 hadsub++; 290 p = getinx(p, &subscr); 291 } 292 if (*p != '\0' && *p != '=') 293 stderror(ERR_NAME | ERR_VARALNUM); 294 if (*p == '=') { 295 *p++ = '\0'; 296 if (*p == '\0' && *v != NULL && **v == '(') 297 p = *v++; 298 } 299 else if (*v && eq(*v, STRequal)) { 300 if (*++v != NULL) 301 p = *v++; 302 } 303 if (eq(p, STRLparen)) { 304 Char **e = v; 305 306 if (hadsub) 307 stderror(ERR_NAME | ERR_SYNTAX); 308 for (;;) { 309 if (!*e) 310 stderror(ERR_NAME | ERR_MISSING, ')'); 311 if (**e == ')') 312 break; 313 e++; 314 } 315 p = *e; 316 *e = 0; 317 vecp = saveblk(v); 318 if (first_match) 319 flags |= VAR_FIRST; 320 else if (last_match) 321 flags |= VAR_LAST; 322 323 set1(vp, vecp, &shvhed, flags); 324 *e = p; 325 v = e + 1; 326 } 327 else if (hadsub) { 328 Char *copy; 329 330 copy = Strsave(p); 331 cleanup_push(copy, xfree); 332 asx(vp, subscr, copy); 333 cleanup_ignore(copy); 334 cleanup_until(copy); 335 } 336 else 337 setv(vp, Strsave(p), flags); 338 update_vars(vp); 339 } while ((p = *v++) != NULL); 340 } 341 342 static Char * 343 getinx(Char *cp, int *ip) 344 { 345 *ip = 0; 346 *cp++ = 0; 347 while (*cp && Isdigit(*cp)) 348 *ip = *ip * 10 + *cp++ - '0'; 349 if (*cp++ != ']') 350 stderror(ERR_NAME | ERR_SUBSCRIPT); 351 return (cp); 352 } 353 354 static void 355 asx(Char *vp, int subscr, Char *p) 356 { 357 struct varent *v = getvx(vp, subscr); 358 Char *prev; 359 360 if (v->v_flags & VAR_READONLY) 361 stderror(ERR_READONLY|ERR_NAME, v->v_name); 362 prev = v->vec[subscr - 1]; 363 cleanup_push(prev, xfree); 364 v->vec[subscr - 1] = globone(p, G_APPEND); 365 cleanup_until(prev); 366 } 367 368 static struct varent * 369 getvx(Char *vp, int subscr) 370 { 371 struct varent *v = adrof(vp); 372 373 if (v == 0) 374 udvar(vp); 375 if (subscr < 1 || subscr > blklen(v->vec)) 376 stderror(ERR_NAME | ERR_RANGE); 377 return (v); 378 } 379 380 /*ARGSUSED*/ 381 void 382 dolet(Char **v, struct command *dummy) 383 { 384 Char *p; 385 Char *vp, c, op; 386 int hadsub; 387 int subscr; 388 389 USE(dummy); 390 v++; 391 p = *v++; 392 if (p == 0) { 393 prvars(); 394 return; 395 } 396 do { 397 hadsub = 0; 398 vp = p; 399 if (letter(*p)) 400 for (; alnum(*p); p++) 401 continue; 402 if (vp == p || !letter(*vp)) 403 stderror(ERR_NAME | ERR_VARBEGIN); 404 if (*p == '[') { 405 hadsub++; 406 p = getinx(p, &subscr); 407 } 408 if (*p == 0 && *v) 409 p = *v++; 410 if ((op = *p) != 0) 411 *p++ = 0; 412 else 413 stderror(ERR_NAME | ERR_ASSIGN); 414 415 /* 416 * if there is no expression after the '=' then print a "Syntax Error" 417 * message - strike 418 */ 419 if (*p == '\0' && *v == NULL) 420 stderror(ERR_NAME | ERR_ASSIGN); 421 422 vp = Strsave(vp); 423 cleanup_push(vp, xfree); 424 if (op == '=') { 425 c = '='; 426 p = xset(p, &v); 427 } 428 else { 429 c = *p++; 430 if (any("+-", c)) { 431 if (c != op || *p) 432 stderror(ERR_NAME | ERR_UNKNOWNOP); 433 p = Strsave(STR1); 434 } 435 else { 436 if (any("<>", op)) { 437 if (c != op) 438 stderror(ERR_NAME | ERR_UNKNOWNOP); 439 stderror(ERR_NAME | ERR_SYNTAX); 440 } 441 if (c != '=') 442 stderror(ERR_NAME | ERR_UNKNOWNOP); 443 p = xset(p, &v); 444 } 445 } 446 cleanup_push(p, xfree); 447 if (op == '=') { 448 if (hadsub) 449 asx(vp, subscr, p); 450 else 451 setv(vp, p, VAR_READWRITE); 452 cleanup_ignore(p); 453 } 454 else if (hadsub) { 455 struct varent *gv = getvx(vp, subscr); 456 Char *val; 457 458 val = operate(op, gv->vec[subscr - 1], p); 459 cleanup_push(val, xfree); 460 asx(vp, subscr, val); 461 cleanup_ignore(val); 462 cleanup_until(val); 463 } 464 else { 465 Char *val; 466 467 val = operate(op, varval(vp), p); 468 cleanup_push(val, xfree); 469 setv(vp, val, VAR_READWRITE); 470 cleanup_ignore(val); 471 cleanup_until(val); 472 } 473 update_vars(vp); 474 cleanup_until(vp); 475 } while ((p = *v++) != NULL); 476 } 477 478 static Char * 479 xset(Char *cp, Char ***vp) 480 { 481 Char *dp; 482 483 if (*cp) { 484 dp = Strsave(cp); 485 --(*vp); 486 xfree(** vp); 487 **vp = dp; 488 } 489 return (putn(expr(vp))); 490 } 491 492 static Char * 493 operate(int op, Char *vp, Char *p) 494 { 495 Char opr[2]; 496 Char *vec[5]; 497 Char **v = vec; 498 Char **vecp = v; 499 tcsh_number_t i; 500 501 if (op != '=') { 502 if (*vp) 503 *v++ = vp; 504 opr[0] = op; 505 opr[1] = 0; 506 *v++ = opr; 507 if (op == '<' || op == '>') 508 *v++ = opr; 509 } 510 *v++ = p; 511 *v++ = 0; 512 i = expr(&vecp); 513 if (*vecp) 514 stderror(ERR_NAME | ERR_EXPRESSION); 515 return (putn(i)); 516 } 517 518 static Char *putp; 519 520 Char * 521 putn(tcsh_number_t n) 522 { 523 Char nbuf[1024]; /* Enough even for octal */ 524 525 putp = nbuf; 526 if (n < 0) { 527 n = -n; 528 *putp++ = '-'; 529 } 530 putn1(n); 531 *putp = 0; 532 return (Strsave(nbuf)); 533 } 534 535 static void 536 putn1(tcsh_number_t n) 537 { 538 if (n > 9) 539 putn1(n / 10); 540 *putp++ = (Char)(n % 10 + '0'); 541 } 542 543 tcsh_number_t 544 getn(const Char *cp) 545 { 546 tcsh_number_t n; 547 int sign; 548 int base; 549 550 if (!cp) /* PWP: extra error checking */ 551 stderror(ERR_NAME | ERR_BADNUM); 552 553 sign = 0; 554 if (cp[0] == '+' && cp[1]) 555 cp++; 556 if (*cp == '-') { 557 sign++; 558 cp++; 559 if (!Isdigit(*cp)) 560 stderror(ERR_NAME | ERR_BADNUM); 561 } 562 563 if (cp[0] == '0' && cp[1] && is_set(STRparseoctal)) 564 base = 8; 565 else 566 base = 10; 567 568 n = 0; 569 while (Isdigit(*cp)) 570 { 571 if (base == 8 && *cp >= '8') 572 stderror(ERR_NAME | ERR_BADNUM); 573 n = n * base + *cp++ - '0'; 574 } 575 if (*cp) 576 stderror(ERR_NAME | ERR_BADNUM); 577 return (sign ? -n : n); 578 } 579 580 Char * 581 value1(Char *var, struct varent *head) 582 { 583 struct varent *vp; 584 585 if (!var || !head) /* PWP: extra error checking */ 586 return (STRNULL); 587 588 vp = adrof1(var, head); 589 return ((vp == NULL || vp->vec == NULL || vp->vec[0] == NULL) ? 590 STRNULL : vp->vec[0]); 591 } 592 593 static struct varent * 594 madrof(Char *pat, struct varent *vp) 595 { 596 struct varent *vp1; 597 598 for (vp = vp->v_left; vp; vp = vp->v_right) { 599 if (vp->v_left && (vp1 = madrof(pat, vp)) != NULL) 600 return vp1; 601 if (Gmatch(vp->v_name, pat)) 602 return vp; 603 } 604 return vp; 605 } 606 607 struct varent * 608 adrof1(const Char *name, struct varent *v) 609 { 610 int cmp; 611 612 v = v->v_left; 613 while (v && ((cmp = *name - *v->v_name) != 0 || 614 (cmp = Strcmp(name, v->v_name)) != 0)) 615 if (cmp < 0) 616 v = v->v_left; 617 else 618 v = v->v_right; 619 return v; 620 } 621 622 void 623 setcopy(const Char *var, const Char *val, int flags) 624 { 625 Char *copy; 626 627 copy = Strsave(val); 628 cleanup_push(copy, xfree); 629 setv(var, copy, flags); 630 cleanup_ignore(copy); 631 cleanup_until(copy); 632 } 633 634 /* 635 * The caller is responsible for putting value in a safe place 636 */ 637 void 638 setv(const Char *var, Char *val, int flags) 639 { 640 Char **vec = xmalloc(2 * sizeof(Char **)); 641 642 vec[0] = val; 643 vec[1] = 0; 644 set1(var, vec, &shvhed, flags); 645 } 646 647 void 648 set1(const Char *var, Char **vec, struct varent *head, int flags) 649 { 650 Char **oldv = vec; 651 652 if ((flags & VAR_NOGLOB) == 0) { 653 int gflag; 654 655 gflag = tglob(oldv); 656 if (gflag) { 657 vec = globall(oldv, gflag); 658 if (vec == NULL) { 659 blkfree(oldv); 660 stderror(ERR_NAME | ERR_NOMATCH); 661 } 662 blkfree(oldv); 663 } 664 } 665 /* 666 * Uniqueness addition from: Michael Veksler <mveksler@vnet.ibm.com> 667 */ 668 if ( flags & (VAR_FIRST | VAR_LAST) ) { 669 /* 670 * Code for -f (VAR_FIRST) and -l (VAR_LAST) options. 671 * Method: 672 * Delete all duplicate words leaving "holes" in the word array (vec). 673 * Then remove the "holes", keeping the order of the words unchanged. 674 */ 675 if (vec[0] && vec[1]) { /* more than one word ? */ 676 int i, j; 677 int num_items; 678 679 for (num_items = 0; vec[num_items]; num_items++) 680 continue; 681 if (flags & VAR_FIRST) { 682 /* delete duplications, keeping first occurance */ 683 for (i = 1; i < num_items; i++) 684 for (j = 0; j < i; j++) 685 /* If have earlier identical item, remove i'th item */ 686 if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) { 687 xfree(vec[i]); 688 vec[i] = NULL; 689 break; 690 } 691 } else if (flags & VAR_LAST) { 692 /* delete duplications, keeping last occurance */ 693 for (i = 0; i < num_items - 1; i++) 694 for (j = i + 1; j < num_items; j++) 695 /* If have later identical item, remove i'th item */ 696 if (vec[i] && vec[j] && Strcmp(vec[j], vec[i]) == 0) { 697 /* remove identical item (the first) */ 698 xfree(vec[i]); 699 vec[i] = NULL; 700 } 701 } 702 /* Compress items - remove empty items */ 703 for (j = i = 0; i < num_items; i++) 704 if (vec[i]) 705 vec[j++] = vec[i]; 706 707 /* NULL-fy remaining items */ 708 for (; j < num_items; j++) 709 vec[j] = NULL; 710 } 711 /* don't let the attribute propagate */ 712 flags &= ~(VAR_FIRST|VAR_LAST); 713 } 714 setq(var, vec, head, flags); 715 } 716 717 718 void 719 setq(const Char *name, Char **vec, struct varent *p, int flags) 720 { 721 struct varent *c; 722 int f; 723 724 f = 0; /* tree hangs off the header's left link */ 725 while ((c = p->v_link[f]) != 0) { 726 if ((f = *name - *c->v_name) == 0 && 727 (f = Strcmp(name, c->v_name)) == 0) { 728 if (c->v_flags & VAR_READONLY) { 729 if (flags & VAR_NOERROR) 730 return; 731 stderror(ERR_READONLY|ERR_NAME, c->v_name); 732 } 733 blkfree(c->vec); 734 c->v_flags = flags; 735 trim(c->vec = vec); 736 return; 737 } 738 p = c; 739 f = f > 0; 740 } 741 p->v_link[f] = c = xmalloc(sizeof(struct varent)); 742 c->v_name = Strsave(name); 743 c->v_flags = flags; 744 c->v_bal = 0; 745 c->v_left = c->v_right = 0; 746 c->v_parent = p; 747 balance(p, f, 0); 748 trim(c->vec = vec); 749 } 750 751 /*ARGSUSED*/ 752 void 753 unset(Char **v, struct command *c) 754 { 755 int did_roe, did_edit; 756 757 USE(c); 758 did_roe = adrof(STRrecognize_only_executables) != NULL; 759 did_edit = adrof(STRedit) != NULL; 760 unset1(v, &shvhed); 761 762 #if defined(FILEC) && defined(TIOCSTI) 763 if (adrof(STRfilec) == 0) 764 filec = 0; 765 #endif /* FILEC && TIOCSTI */ 766 767 if (adrof(STRhistchars) == 0) { 768 HIST = '!'; 769 HISTSUB = '^'; 770 } 771 if (adrof(STRignoreeof) == 0) 772 numeof = 0; 773 if (adrof(STRpromptchars) == 0) { 774 PRCH = tcsh ? '>' : '%'; 775 PRCHROOT = '#'; 776 } 777 if (adrof(STRnoclobber) == 0) 778 no_clobber = 0; 779 if (adrof(STRhistlit) == 0) 780 HistLit = 0; 781 if (adrof(STRloginsh) == 0) 782 loginsh = 0; 783 if (adrof(STRanyerror) == 0) 784 anyerror = 0; 785 if (adrof(STRwordchars) == 0) 786 word_chars = STR_WORD_CHARS; 787 if (adrof(STRedit) == 0) 788 editing = 0; 789 if (adrof(STRbackslash_quote) == 0) 790 bslash_quote = 0; 791 if (adrof(STRcompat_expr) == 0) 792 compat_expr = 0; 793 if (adrof(STRsymlinks) == 0) 794 symlinks = 0; 795 if (adrof(STRimplicitcd) == 0) 796 implicit_cd = 0; 797 if (adrof(STRcdtohome) == 0) 798 cdtohome = 0; 799 if (adrof(STRkillring) == 0) 800 SetKillRing(0); 801 if (did_edit && noediting && adrof(STRedit) == 0) 802 noediting = 0; 803 if (adrof(STRvimode) == 0) 804 VImode = 0; 805 if (did_roe && adrof(STRrecognize_only_executables) == 0) 806 tw_cmd_free(); 807 if (adrof(STRhistory) == 0) 808 sethistory(0); 809 #ifdef COLOR_LS_F 810 if (adrof(STRcolor) == 0) 811 set_color_context(); 812 #endif /* COLOR_LS_F */ 813 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 814 update_dspmbyte_vars(); 815 #endif 816 update_wordchars(); 817 #ifdef NLS_CATALOGS 818 nlsclose(); 819 nlsinit(); 820 #endif /* NLS_CATALOGS */ 821 } 822 823 void 824 unset1(Char *v[], struct varent *head) 825 { 826 struct varent *vp; 827 int cnt; 828 829 while (*++v) { 830 cnt = 0; 831 while ((vp = madrof(*v, head)) != NULL) 832 if (vp->v_flags & VAR_READONLY) 833 stderror(ERR_READONLY|ERR_NAME, vp->v_name); 834 else 835 unsetv1(vp), cnt++; 836 if (cnt == 0) 837 setname(short2str(*v)); 838 } 839 } 840 841 void 842 unsetv(Char *var) 843 { 844 struct varent *vp; 845 846 if ((vp = adrof1(var, &shvhed)) == 0) 847 udvar(var); 848 unsetv1(vp); 849 } 850 851 static void 852 unsetv1(struct varent *p) 853 { 854 struct varent *c, *pp; 855 int f; 856 857 /* 858 * Free associated memory first to avoid complications. 859 */ 860 blkfree(p->vec); 861 xfree(p->v_name); 862 /* 863 * If p is missing one child, then we can move the other into where p is. 864 * Otherwise, we find the predecessor of p, which is guaranteed to have no 865 * right child, copy it into p, and move it's left child into it. 866 */ 867 if (p->v_right == 0) 868 c = p->v_left; 869 else if (p->v_left == 0) 870 c = p->v_right; 871 else { 872 for (c = p->v_left; c->v_right; c = c->v_right) 873 continue; 874 p->v_name = c->v_name; 875 p->v_flags = c->v_flags; 876 p->vec = c->vec; 877 p = c; 878 c = p->v_left; 879 } 880 881 /* 882 * Move c into where p is. 883 */ 884 pp = p->v_parent; 885 f = pp->v_right == p; 886 if ((pp->v_link[f] = c) != 0) 887 c->v_parent = pp; 888 /* 889 * Free the deleted node, and rebalance. 890 */ 891 xfree(p); 892 balance(pp, f, 1); 893 } 894 895 /* Set variable name to NULL. */ 896 void 897 setNS(const Char *varName) 898 { 899 setcopy(varName, STRNULL, VAR_READWRITE); 900 } 901 902 /*ARGSUSED*/ 903 void 904 shift(Char **v, struct command *c) 905 { 906 struct varent *argv; 907 Char *name; 908 909 USE(c); 910 v++; 911 name = *v; 912 if (name == 0) 913 name = STRargv; 914 else 915 (void) strip(name); 916 argv = adrof(name); 917 if (argv == NULL || argv->vec == NULL) 918 udvar(name); 919 if (argv->vec[0] == 0) 920 stderror(ERR_NAME | ERR_NOMORE); 921 lshift(argv->vec, 1); 922 update_vars(name); 923 } 924 925 void 926 exportpath(Char **val) 927 { 928 struct Strbuf buf = Strbuf_INIT; 929 Char *exppath; 930 931 if (val) 932 while (*val) { 933 Strbuf_append(&buf, *val++); 934 if (*val == 0 || eq(*val, STRRparen)) 935 break; 936 Strbuf_append1(&buf, PATHSEP); 937 } 938 exppath = Strbuf_finish(&buf); 939 cleanup_push(exppath, xfree); 940 tsetenv(STRKPATH, exppath); 941 cleanup_until(exppath); 942 } 943 944 static int 945 set_noclobber(Char **val) 946 { 947 Char *option; 948 int nc = NOCLOBBER_DEFAULT; 949 950 if (val == NULL) 951 return nc; 952 while (*val) { 953 if (*val == 0 || eq(*val, STRRparen)) 954 return nc; 955 956 option = *val++; 957 958 if (eq(option, STRnotempty)) 959 nc |= NOCLOBBER_NOTEMPTY; 960 else if (eq(option, STRask)) 961 nc |= NOCLOBBER_ASK; 962 } 963 return nc; 964 } 965 966 #ifndef lint 967 /* 968 * Lint thinks these have null effect 969 */ 970 /* macros to do single rotations on node p */ 971 # define rright(p) (\ 972 t = (p)->v_left,\ 973 (t)->v_parent = (p)->v_parent,\ 974 (((p)->v_left = t->v_right) != NULL) ?\ 975 (t->v_right->v_parent = (p)) : 0,\ 976 (t->v_right = (p))->v_parent = t,\ 977 (p) = t) 978 # define rleft(p) (\ 979 t = (p)->v_right,\ 980 ((t)->v_parent = (p)->v_parent,\ 981 ((p)->v_right = t->v_left) != NULL) ? \ 982 (t->v_left->v_parent = (p)) : 0,\ 983 (t->v_left = (p))->v_parent = t,\ 984 (p) = t) 985 #else 986 static struct varent * 987 rleft(struct varent *p) 988 { 989 return (p); 990 } 991 static struct varent * 992 rright(struct varent *p) 993 { 994 return (p); 995 } 996 997 #endif /* ! lint */ 998 999 1000 /* 1001 * Rebalance a tree, starting at p and up. 1002 * F == 0 means we've come from p's left child. 1003 * D == 1 means we've just done a delete, otherwise an insert. 1004 */ 1005 static void 1006 balance(struct varent *p, int f, int d) 1007 { 1008 struct varent *pp; 1009 1010 #ifndef lint 1011 struct varent *t; /* used by the rotate macros */ 1012 #endif /* !lint */ 1013 int ff; 1014 #ifdef lint 1015 ff = 0; /* Sun's lint is dumb! */ 1016 #endif 1017 1018 /* 1019 * Ok, from here on, p is the node we're operating on; pp is it's parent; f 1020 * is the branch of p from which we have come; ff is the branch of pp which 1021 * is p. 1022 */ 1023 for (; (pp = p->v_parent) != 0; p = pp, f = ff) { 1024 ff = pp->v_right == p; 1025 if (f ^ d) { /* right heavy */ 1026 switch (p->v_bal) { 1027 case -1: /* was left heavy */ 1028 p->v_bal = 0; 1029 break; 1030 case 0: /* was balanced */ 1031 p->v_bal = 1; 1032 break; 1033 case 1: /* was already right heavy */ 1034 switch (p->v_right->v_bal) { 1035 case 1: /* single rotate */ 1036 pp->v_link[ff] = rleft(p); 1037 p->v_left->v_bal = 0; 1038 p->v_bal = 0; 1039 break; 1040 case 0: /* single rotate */ 1041 pp->v_link[ff] = rleft(p); 1042 p->v_left->v_bal = 1; 1043 p->v_bal = -1; 1044 break; 1045 case -1: /* double rotate */ 1046 (void) rright(p->v_right); 1047 pp->v_link[ff] = rleft(p); 1048 p->v_left->v_bal = 1049 p->v_bal < 1 ? 0 : -1; 1050 p->v_right->v_bal = 1051 p->v_bal > -1 ? 0 : 1; 1052 p->v_bal = 0; 1053 break; 1054 default: 1055 break; 1056 } 1057 break; 1058 default: 1059 break; 1060 } 1061 } 1062 else { /* left heavy */ 1063 switch (p->v_bal) { 1064 case 1: /* was right heavy */ 1065 p->v_bal = 0; 1066 break; 1067 case 0: /* was balanced */ 1068 p->v_bal = -1; 1069 break; 1070 case -1: /* was already left heavy */ 1071 switch (p->v_left->v_bal) { 1072 case -1: /* single rotate */ 1073 pp->v_link[ff] = rright(p); 1074 p->v_right->v_bal = 0; 1075 p->v_bal = 0; 1076 break; 1077 case 0: /* single rotate */ 1078 pp->v_link[ff] = rright(p); 1079 p->v_right->v_bal = -1; 1080 p->v_bal = 1; 1081 break; 1082 case 1: /* double rotate */ 1083 (void) rleft(p->v_left); 1084 pp->v_link[ff] = rright(p); 1085 p->v_left->v_bal = 1086 p->v_bal < 1 ? 0 : -1; 1087 p->v_right->v_bal = 1088 p->v_bal > -1 ? 0 : 1; 1089 p->v_bal = 0; 1090 break; 1091 default: 1092 break; 1093 } 1094 break; 1095 default: 1096 break; 1097 } 1098 } 1099 /* 1100 * If from insert, then we terminate when p is balanced. If from 1101 * delete, then we terminate when p is unbalanced. 1102 */ 1103 if ((p->v_bal == 0) ^ d) 1104 break; 1105 } 1106 } 1107 1108 void 1109 plist(struct varent *p, int what) 1110 { 1111 struct varent *c; 1112 int len; 1113 1114 for (;;) { 1115 while (p->v_left) 1116 p = p->v_left; 1117 x: 1118 if (p->v_parent == 0) /* is it the header? */ 1119 break; 1120 if ((p->v_flags & what) != 0) { 1121 if (setintr) { 1122 int old_pintr_disabled; 1123 1124 pintr_push_enable(&old_pintr_disabled); 1125 cleanup_until(&old_pintr_disabled); 1126 } 1127 len = blklen(p->vec); 1128 xprintf("%" TCSH_S "\t", p->v_name); 1129 if (len != 1) 1130 xputchar('('); 1131 blkpr(p->vec); 1132 if (len != 1) 1133 xputchar(')'); 1134 xputchar('\n'); 1135 } 1136 if (p->v_right) { 1137 p = p->v_right; 1138 continue; 1139 } 1140 do { 1141 c = p; 1142 p = p->v_parent; 1143 } while (p->v_right == c); 1144 goto x; 1145 } 1146 } 1147 1148 #if defined(KANJI) 1149 # if defined(SHORT_STRINGS) && defined(DSPMBYTE) 1150 extern int dspmbyte_ls; 1151 1152 void 1153 update_dspmbyte_vars(void) 1154 { 1155 int lp, iskcode; 1156 Char *dstr1; 1157 struct varent *vp; 1158 1159 /* if variable "nokanji" is set, multi-byte display is disabled */ 1160 if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) { 1161 _enable_mbdisp = 1; 1162 dstr1 = vp->vec[0]; 1163 if (eq (dstr1, STRsjis)) 1164 iskcode = 1; 1165 else if (eq(dstr1, STReuc)) 1166 iskcode = 2; 1167 else if (eq(dstr1, STRbig5)) 1168 iskcode = 3; 1169 else if (eq(dstr1, STRutf8)) 1170 iskcode = 4; 1171 else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) { 1172 iskcode = 0; 1173 } 1174 else { 1175 xprintf(CGETS(18, 2, 1176 "Warning: unknown multibyte display; using default(euc(JP))\n")); 1177 iskcode = 2; 1178 } 1179 if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls)) 1180 dspmbyte_ls = 1; 1181 else 1182 dspmbyte_ls = 0; 1183 for (lp = 0; lp < 256 && iskcode > 0; lp++) { 1184 switch (iskcode) { 1185 case 1: 1186 /* Shift-JIS */ 1187 _cmap[lp] = _cmap_mbyte[lp]; 1188 _mbmap[lp] = _mbmap_sjis[lp]; 1189 break; 1190 case 2: 1191 /* 2 ... euc */ 1192 _cmap[lp] = _cmap_mbyte[lp]; 1193 _mbmap[lp] = _mbmap_euc[lp]; 1194 break; 1195 case 3: 1196 /* 3 ... big5 */ 1197 _cmap[lp] = _cmap_mbyte[lp]; 1198 _mbmap[lp] = _mbmap_big5[lp]; 1199 break; 1200 case 4: 1201 /* 4 ... utf8 */ 1202 _cmap[lp] = _cmap_mbyte[lp]; 1203 _mbmap[lp] = _mbmap_utf8[lp]; 1204 break; 1205 default: 1206 xprintf(CGETS(18, 3, 1207 "Warning: unknown multibyte code %d; multibyte disabled\n"), 1208 iskcode); 1209 _cmap[lp] = _cmap_c[lp]; 1210 _mbmap[lp] = 0; /* Default map all 0 */ 1211 _enable_mbdisp = 0; 1212 break; 1213 } 1214 } 1215 if (iskcode == 0) { 1216 /* check original table */ 1217 if (Strlen(dstr1) != 256) { 1218 xprintf(CGETS(18, 4, 1219 "Warning: Invalid multibyte table length (%d); multibyte disabled\n"), 1220 Strlen(dstr1)); 1221 _enable_mbdisp = 0; 1222 } 1223 for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) { 1224 if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) { 1225 xprintf(CGETS(18, 4, 1226 "Warning: bad multibyte code at offset +%d; multibyte diabled\n"), 1227 lp); 1228 _enable_mbdisp = 0; 1229 break; 1230 } 1231 } 1232 /* set original table */ 1233 for (lp = 0; lp < 256; lp++) { 1234 if (_enable_mbdisp == 1) { 1235 _cmap[lp] = _cmap_mbyte[lp]; 1236 _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f); 1237 } 1238 else { 1239 _cmap[lp] = _cmap_c[lp]; 1240 _mbmap[lp] = 0; /* Default map all 0 */ 1241 } 1242 } 1243 } 1244 } 1245 else { 1246 for (lp = 0; lp < 256; lp++) { 1247 _cmap[lp] = _cmap_c[lp]; 1248 _mbmap[lp] = 0; /* Default map all 0 */ 1249 } 1250 _enable_mbdisp = 0; 1251 dspmbyte_ls = 0; 1252 } 1253 #ifdef MBYTEDEBUG /* Sorry, use for beta testing */ 1254 { 1255 Char mbmapstr[300]; 1256 for (lp = 0; lp < 256; lp++) 1257 mbmapstr[lp] = _mbmap[lp] + '0'; 1258 mbmapstr[lp] = 0; 1259 setcopy(STRmbytemap, mbmapstr, VAR_READWRITE); 1260 } 1261 #endif /* MBYTEMAP */ 1262 } 1263 1264 /* dspkanji/dspmbyte autosetting */ 1265 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 1266 void 1267 autoset_dspmbyte(const Char *pcp) 1268 { 1269 int i; 1270 static const struct dspm_autoset_Table { 1271 Char *n; 1272 Char *v; 1273 } dspmt[] = { 1274 { STRLANGEUCJP, STReuc }, 1275 { STRLANGEUCKR, STReuc }, 1276 { STRLANGEUCZH, STReuc }, 1277 { STRLANGEUCJPB, STReuc }, 1278 { STRLANGEUCKRB, STReuc }, 1279 { STRLANGEUCZHB, STReuc }, 1280 #ifdef __linux__ 1281 { STRLANGEUCJPC, STReuc }, 1282 #endif 1283 { STRLANGSJIS, STRsjis }, 1284 { STRLANGSJISB, STRsjis }, 1285 { STRLANGBIG5, STRbig5 }, 1286 { STRstarutfstar8, STRutf8 }, 1287 { NULL, NULL } 1288 }; 1289 #if defined(HAVE_NL_LANGINFO) && defined(CODESET) 1290 static const struct dspm_autoset_Table dspmc[] = { 1291 { STRstarutfstar8, STRutf8 }, 1292 { STReuc, STReuc }, 1293 { STRGB2312, STReuc }, 1294 { STRLANGBIG5, STRbig5 }, 1295 { NULL, NULL } 1296 }; 1297 Char *codeset; 1298 1299 codeset = str2short(nl_langinfo(CODESET)); 1300 if (*codeset != '\0') { 1301 for (i = 0; dspmc[i].n; i++) { 1302 const Char *estr; 1303 if (dspmc[i].n[0] && t_pmatch(pcp, dspmc[i].n, &estr, 0) > 0) { 1304 setcopy(CHECK_MBYTEVAR, dspmc[i].v, VAR_READWRITE); 1305 update_dspmbyte_vars(); 1306 return; 1307 } 1308 } 1309 } 1310 #endif 1311 1312 if (*pcp == '\0') 1313 return; 1314 1315 for (i = 0; dspmt[i].n; i++) { 1316 const Char *estr; 1317 if (dspmt[i].n[0] && t_pmatch(pcp, dspmt[i].n, &estr, 0) > 0) { 1318 setcopy(CHECK_MBYTEVAR, dspmt[i].v, VAR_READWRITE); 1319 update_dspmbyte_vars(); 1320 break; 1321 } 1322 } 1323 } 1324 # elif defined(AUTOSET_KANJI) 1325 void 1326 autoset_kanji(void) 1327 { 1328 char *codeset = nl_langinfo(CODESET); 1329 1330 if (*codeset == '\0') { 1331 if (adrof(STRnokanji) == NULL) 1332 setNS(STRnokanji); 1333 return; 1334 } 1335 1336 if (strcasestr(codeset, "SHIFT_JIS") == (char*)0) { 1337 if (adrof(STRnokanji) == NULL) 1338 setNS(STRnokanji); 1339 return; 1340 } 1341 1342 if (adrof(STRnokanji) != NULL) 1343 unsetv(STRnokanji); 1344 } 1345 #endif 1346 #endif 1347 1348 void 1349 update_wordchars(void) 1350 { 1351 if ((word_chars == STR_WORD_CHARS) || (word_chars == STR_WORD_CHARS_VI)) { 1352 word_chars = (VImode ? STR_WORD_CHARS_VI : STR_WORD_CHARS); 1353 } 1354 } 1355 1356 void 1357 setstrstatus(Char *str) 1358 { 1359 setv(STRstatus, str, VAR_READWRITE|VAR_NOERROR); 1360 } 1361 1362 void 1363 setstatus(int n) 1364 { 1365 setcopy(STRstatus, n ? STR1 : STR0, VAR_READWRITE|VAR_NOERROR); 1366 } 1367 1368 int 1369 getstatus(void) 1370 { 1371 return getn(varval(STRstatus)); 1372 } 1373