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