sh.set.c revision 59243
125540Sdfr/* $Header: /src/pub/tcsh/sh.set.c,v 3.35 1998/10/25 15:10:26 christos Exp $ */
225540Sdfr/*
325540Sdfr * sh.set.c: Setting and Clearing of variables
425540Sdfr */
525540Sdfr/*-
625540Sdfr * Copyright (c) 1980, 1991 The Regents of the University of California.
725540Sdfr * All rights reserved.
825540Sdfr *
925540Sdfr * Redistribution and use in source and binary forms, with or without
1025540Sdfr * modification, are permitted provided that the following conditions
1125540Sdfr * are met:
1225540Sdfr * 1. Redistributions of source code must retain the above copyright
1325540Sdfr *    notice, this list of conditions and the following disclaimer.
1425540Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1525540Sdfr *    notice, this list of conditions and the following disclaimer in the
1625540Sdfr *    documentation and/or other materials provided with the distribution.
1725540Sdfr * 3. All advertising materials mentioning features or use of this software
1825540Sdfr *    must display the following acknowledgement:
1925540Sdfr *	This product includes software developed by the University of
2025540Sdfr *	California, Berkeley and its contributors.
2125540Sdfr * 4. Neither the name of the University nor the names of its contributors
2225540Sdfr *    may be used to endorse or promote products derived from this software
2325540Sdfr *    without specific prior written permission.
2425540Sdfr *
2525540Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2650476Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2725540Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28294624Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2925540Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3025540Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3125540Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3225540Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3325540Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3425540Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3568960Sru * SUCH DAMAGE.
36294624Strasz */
37261032Sbapt#include "sh.h"
3825540Sdfr
39297023SjulianRCSID("$Id: sh.set.c,v 3.35 1998/10/25 15:10:26 christos Exp $")
4025540Sdfr
41145861Sfjoe#include "ed.h"
42145861Sfjoe#include "tw.h"
43150497Spjd
44297023Sjulianextern Char HistLit;
45145861Sfjoeextern bool GotTermCaps;
4625540Sdfr
4725540Sdfrstatic	void		 update_vars	__P((Char *));
4825540Sdfrstatic	Char		*getinx		__P((Char *, int *));
4962327Spsstatic	void		 asx		__P((Char *, int, Char *));
5062327Spsstatic	struct varent 	*getvx		__P((Char *, int));
5125540Sdfrstatic	Char		*xset		__P((Char *, Char ***));
5232270Scharnierstatic	Char		*operate	__P((int, Char *, Char *));
5341108Sobrienstatic	void	 	 putn1		__P((int));
54294624Straszstatic	struct varent	*madrof		__P((Char *, struct varent *));
55294624Straszstatic	void		 unsetv1	__P((struct varent *));
56294624Straszstatic	void		 exportpath	__P((Char **));
5725540Sdfrstatic	void		 balance	__P((struct varent *, int, int));
5862327Sps
59297023Sjulian/*
60297023Sjulian * C Shell
6125540Sdfr */
6225540Sdfr
63145861Sfjoestatic void
64145861Sfjoeupdate_vars(vp)
65150497Spjd    Char *vp;
66150497Spjd{
67145861Sfjoe    if (eq(vp, STRpath)) {
68145861Sfjoe	exportpath(adrof(STRpath)->vec);
6925540Sdfr	dohash(NULL, NULL);
70140368Sru    }
71140368Sru    else if (eq(vp, STRhistchars)) {
7225540Sdfr	register Char *pn = varval(vp);
7350847Schris
7425540Sdfr	HIST = *pn++;
7525540Sdfr	HISTSUB = *pn;
7630627Sjmg    }
7730627Sjmg    else if (eq(vp, STRpromptchars)) {
7830627Sjmg	register Char *pn = varval(vp);
7999501Scharnier
8041108Sobrien	PRCH = *pn++;
8141108Sobrien	PRCHROOT = *pn;
82166690Sbrueffer    }
8341108Sobrien    else if (eq(vp, STRhistlit)) {
8434673Scharnier	HistLit = 1;
85267667Sbapt    }
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*/
185void
186doset(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
288static Char *
289getinx(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
302static void
303asx(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
316static struct varent *
317getvx(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*/
331void
332dolet(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
420static Char *
421xset(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
435static Char *
436operate(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
463static Char *putp, nbuf[50];
464
465Char   *
466putn(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
497static void
498putn1(n)
499    register int n;
500{
501    if (n > 9)
502	putn1(n / 10);
503    *putp++ = n % 10 + '0';
504}
505
506int
507getn(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
533Char   *
534value1(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
547static struct varent *
548madrof(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
563struct varent *
564adrof1(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 */
583void
584set(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
595void
596set1(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
670void
671setq(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*/
704void
705unset(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
750void
751unset1(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
770void
771unsetv(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
781static void
782unsetv1(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
826void
827setNS(cp)
828    Char   *cp;
829{
830    set(cp, Strsave(STRNULL), VAR_READWRITE);
831}
832
833/*ARGSUSED*/
834void
835shift(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
858static Char STRsep[2] = { PATHSEP, '\0' };
859
860static void
861exportpath(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
909static struct varent *
910rleft(p)
911    struct varent *p;
912{
913    return (p);
914}
915static struct varent *
916rright(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 */
930static void
931balance(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
1035void
1036plist(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;
1053x:
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)
1079bool dspmbyte_ls;
1080
1081void
1082update_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 */
1182void
1183autoset_dspmbyte(pcp)
1184    Char *pcp;
1185{
1186    int i;
1187    struct dspm_autoset_Table {
1188	Char *n;
1189	Char *v;
1190    } dspmt[] = {
1191	{ STRLANGEUC, STRKEUC },
1192	{ STRLANGEUCB, STRKEUC },
1193	{ STRLANGSJIS, STRKSJIS },
1194	{ STRLANGSJISB, STRKSJIS },
1195	{ NULL, NULL }
1196    };
1197
1198    if (*pcp == '\0')
1199	return;
1200
1201    for (i = 0; dspmt[i].n; i++) {
1202	if (eq(pcp, dspmt[i].n)) {
1203	    set(CHECK_MBYTEVAR, Strsave(dspmt[i].v), VAR_READWRITE);
1204	    update_dspmbyte_vars();
1205	    break;
1206	}
1207    }
1208}
1209#endif
1210