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