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