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