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