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