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