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