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