PageRenderTime 83ms CodeModel.GetById 17ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/tcsh/sh.set.c

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