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