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