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