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