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