xref: /freebsd/contrib/tcsh/sh.set.c (revision 193d9e768ba63fcfb187cfd17f461f7d41345048)
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 
35 RCSID("$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 
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		(tcsh_number_t);
54 static	struct varent	*madrof		(Char *, struct varent *);
55 static	void		 unsetv1	(struct varent *);
56 static	void		 exportpath	(Char **);
57 static	void		 balance	(struct varent *, int, int);
58 
59 /*
60  * C Shell
61  */
62 
63 static void
64 update_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*/
230 void
231 doset(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 
333 static Char *
334 getinx(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 
345 static void
346 asx(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 
359 static struct varent *
360 getvx(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*/
372 void
373 dolet(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 
469 static Char *
470 xset(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 
483 static Char *
484 operate(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 
509 static Char *putp;
510 
511 Char *
512 putn(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 
526 static void
527 putn1(tcsh_number_t n)
528 {
529     if (n > 9)
530 	putn1(n / 10);
531     *putp++ = (Char)(n % 10 + '0');
532 }
533 
534 tcsh_number_t
535 getn(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 
571 Char   *
572 value1(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 
584 static struct varent *
585 madrof(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 
598 struct varent *
599 adrof1(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 
613 void
614 setcopy(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  */
628 void
629 setv(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 
638 void
639 set1(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 
709 void
710 setq(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*/
740 void
741 unset(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 
802 void
803 unset1(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 
820 void
821 unsetv(Char *var)
822 {
823     struct varent *vp;
824 
825     if ((vp = adrof1(var, &shvhed)) == 0)
826 	udvar(var);
827     unsetv1(vp);
828 }
829 
830 static void
831 unsetv1(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. */
875 void
876 setNS(const Char *varName)
877 {
878     setcopy(varName, STRNULL, VAR_READWRITE);
879 }
880 
881 /*ARGSUSED*/
882 void
883 shift(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 
904 static void
905 exportpath(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
943 static struct varent *
944 rleft(struct varent *p)
945 {
946     return (p);
947 }
948 static struct varent *
949 rright(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  */
962 static void
963 balance(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 
1065 void
1066 plist(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;
1074 x:
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)
1107 extern int dspmbyte_ls;
1108 
1109 void
1110 update_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 */
1223 void
1224 autoset_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)
1282 void
1283 autoset_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
1304