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