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