xref: /csrg-svn/bin/csh/set.c (revision 68576)
147823Sbostic /*-
260765Sbostic  * Copyright (c) 1980, 1991, 1993
360765Sbostic  *	The Regents of the University of California.  All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621942Sdist  */
721942Sdist 
817513Sedward #ifndef lint
9*68576Schristos static char sccsid[] = "@(#)set.c	8.2 (Berkeley) 03/22/95";
1047422Sbostic #endif /* not lint */
111305Sbill 
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <stdlib.h>
1450465Schristos #ifndef SHORT_STRINGS
1550465Schristos #include <string.h>
1650465Schristos #endif /* SHORT_STRINGS */
1750033Schristos #if __STDC__
1850033Schristos # include <stdarg.h>
1950033Schristos #else
2050033Schristos # include <varargs.h>
2150033Schristos #endif
2250033Schristos 
2350023Sbostic #include "csh.h"
2450023Sbostic #include "extern.h"
251305Sbill 
2650024Schristos static Char	*getinx __P((Char *, int *));
2750024Schristos static void	 asx __P((Char *, int, Char *));
2851437Sleres static struct varent
2950026Schristos 		*getvx __P((Char *, int));
3050024Schristos static Char	*xset __P((Char *, Char ***));
3150024Schristos static Char	*operate __P((int, Char *, Char *));
3250024Schristos static void	 putn1 __P((int));
3351437Sleres static struct varent
3450024Schristos 		*madrof __P((Char *, struct varent *));
3550024Schristos static void	 unsetv1 __P((struct varent *));
3650024Schristos static void	 exportpath __P((Char **));
3750024Schristos static void	 balance __P((struct varent *, int, int));
3849992Sbostic 
3949992Sbostic 
401305Sbill /*
411305Sbill  * C Shell
421305Sbill  */
431305Sbill 
4449992Sbostic void
4550439Schristos /*ARGSUSED*/
doset(v,t)4650439Schristos doset(v, t)
4750439Schristos     Char **v;
4850439Schristos     struct command *t;
491305Sbill {
5049992Sbostic     register Char *p;
5149992Sbostic     Char   *vp, op;
5249992Sbostic     Char  **vecp;
5349992Sbostic     bool    hadsub;
5449992Sbostic     int     subscr;
551305Sbill 
5649992Sbostic     v++;
5749992Sbostic     p = *v++;
5849992Sbostic     if (p == 0) {
5949992Sbostic 	prvars();
6049992Sbostic 	return;
6149992Sbostic     }
6249992Sbostic     do {
6349992Sbostic 	hadsub = 0;
6449992Sbostic 	vp = p;
6549992Sbostic 	if (letter(*p))
6649992Sbostic 	    for (; alnum(*p); p++)
6749992Sbostic 		continue;
6849992Sbostic 	if (vp == p || !letter(*vp))
6949992Sbostic 	    stderror(ERR_NAME | ERR_VARBEGIN);
7049992Sbostic 	if ((p - vp) > MAXVARLEN) {
7149992Sbostic 	    stderror(ERR_NAME | ERR_VARTOOLONG);
7249992Sbostic 	    return;
731305Sbill 	}
7449992Sbostic 	if (*p == '[') {
7549992Sbostic 	    hadsub++;
7649992Sbostic 	    p = getinx(p, &subscr);
7749992Sbostic 	}
7860237Schristos 	if ((op = *p) != '\0') {
7949992Sbostic 	    *p++ = 0;
8049992Sbostic 	    if (*p == 0 && *v && **v == '(')
8149992Sbostic 		p = *v++;
8249992Sbostic 	}
8349992Sbostic 	else if (*v && eq(*v, STRequal)) {
8449992Sbostic 	    op = '=', v++;
8549992Sbostic 	    if (*v)
8649992Sbostic 		p = *v++;
8749992Sbostic 	}
8849992Sbostic 	if (op && op != '=')
8949992Sbostic 	    stderror(ERR_NAME | ERR_SYNTAX);
9049992Sbostic 	if (eq(p, STRLparen)) {
9149992Sbostic 	    register Char **e = v;
921305Sbill 
9349992Sbostic 	    if (hadsub)
9449992Sbostic 		stderror(ERR_NAME | ERR_SYNTAX);
9549992Sbostic 	    for (;;) {
9649992Sbostic 		if (!*e)
9749992Sbostic 		    stderror(ERR_NAME | ERR_MISSING, ')');
9849992Sbostic 		if (**e == ')')
9949992Sbostic 		    break;
10049992Sbostic 		e++;
10149992Sbostic 	    }
10249992Sbostic 	    p = *e;
10349992Sbostic 	    *e = 0;
10449992Sbostic 	    vecp = saveblk(v);
10549992Sbostic 	    set1(vp, vecp, &shvhed);
10649992Sbostic 	    *e = p;
10749992Sbostic 	    v = e + 1;
10849992Sbostic 	}
10949992Sbostic 	else if (hadsub)
11049992Sbostic 	    asx(vp, subscr, Strsave(p));
11149992Sbostic 	else
11249992Sbostic 	    set(vp, Strsave(p));
11349992Sbostic 	if (eq(vp, STRpath)) {
11449992Sbostic 	    exportpath(adrof(STRpath)->vec);
11550439Schristos 	    dohash(NULL, NULL);
11649992Sbostic 	}
11749992Sbostic 	else if (eq(vp, STRhistchars)) {
11849992Sbostic 	    register Char *pn = value(STRhistchars);
1191305Sbill 
12049992Sbostic 	    HIST = *pn++;
12149992Sbostic 	    HISTSUB = *pn;
12249992Sbostic 	}
12349992Sbostic 	else if (eq(vp, STRuser)) {
12449992Sbostic 	    Setenv(STRUSER, value(vp));
12549992Sbostic 	    Setenv(STRLOGNAME, value(vp));
12649992Sbostic 	}
12749992Sbostic 	else if (eq(vp, STRwordchars)) {
12849992Sbostic 	    word_chars = value(vp);
12949992Sbostic 	}
13049992Sbostic 	else if (eq(vp, STRterm))
13149992Sbostic 	    Setenv(STRTERM, value(vp));
13249992Sbostic 	else if (eq(vp, STRhome)) {
13349992Sbostic 	    register Char *cp;
13449992Sbostic 
13549992Sbostic 	    cp = Strsave(value(vp));	/* get the old value back */
13649992Sbostic 
13749992Sbostic 	    /*
13849992Sbostic 	     * convert to cononical pathname (possibly resolving symlinks)
13949992Sbostic 	     */
14049992Sbostic 	    cp = dcanon(cp, cp);
14149992Sbostic 
14249992Sbostic 	    set(vp, Strsave(cp));	/* have to save the new val */
14349992Sbostic 
14449992Sbostic 	    /* and now mirror home with HOME */
14549992Sbostic 	    Setenv(STRHOME, cp);
14649992Sbostic 	    /* fix directory stack for new tilde home */
14749992Sbostic 	    dtilde();
14849992Sbostic 	    xfree((ptr_t) cp);
14949992Sbostic 	}
15017513Sedward #ifdef FILEC
15149992Sbostic 	else if (eq(vp, STRfilec))
15249992Sbostic 	    filec = 1;
15317513Sedward #endif
15460237Schristos     } while ((p = *v++) != NULL);
1551305Sbill }
1561305Sbill 
15749992Sbostic static Char *
getinx(cp,ip)1581305Sbill getinx(cp, ip)
15949992Sbostic     register Char *cp;
16049992Sbostic     register int *ip;
1611305Sbill {
1621305Sbill 
16349992Sbostic     *ip = 0;
16449992Sbostic     *cp++ = 0;
16549992Sbostic     while (*cp && Isdigit(*cp))
16649992Sbostic 	*ip = *ip * 10 + *cp++ - '0';
16749992Sbostic     if (*cp++ != ']')
16849992Sbostic 	stderror(ERR_NAME | ERR_SUBSCRIPT);
16949992Sbostic     return (cp);
1701305Sbill }
1711305Sbill 
17249992Sbostic static void
asx(vp,subscr,p)1731305Sbill asx(vp, subscr, p)
17449992Sbostic     Char   *vp;
17549992Sbostic     int     subscr;
17649992Sbostic     Char   *p;
1771305Sbill {
17849992Sbostic     register struct varent *v = getvx(vp, subscr);
1791305Sbill 
18049992Sbostic     xfree((ptr_t) v->vec[subscr - 1]);
18149992Sbostic     v->vec[subscr - 1] = globone(p, G_APPEND);
1821305Sbill }
1831305Sbill 
18449992Sbostic static struct varent *
getvx(vp,subscr)1851305Sbill getvx(vp, subscr)
18649992Sbostic     Char   *vp;
18749992Sbostic     int     subscr;
1881305Sbill {
18949992Sbostic     register struct varent *v = adrof(vp);
1901305Sbill 
19149992Sbostic     if (v == 0)
19249992Sbostic 	udvar(vp);
19349992Sbostic     if (subscr < 1 || subscr > blklen(v->vec))
19449992Sbostic 	stderror(ERR_NAME | ERR_RANGE);
19549992Sbostic     return (v);
1961305Sbill }
1971305Sbill 
19849992Sbostic void
19950439Schristos /*ARGSUSED*/
dolet(v,t)20050439Schristos dolet(v, t)
20150439Schristos     Char **v;
20250439Schristos     struct command *t;
2031305Sbill {
20449992Sbostic     register Char *p;
20549992Sbostic     Char   *vp, c, op;
20649992Sbostic     bool    hadsub;
20749992Sbostic     int     subscr;
2081305Sbill 
20949992Sbostic     v++;
21049992Sbostic     p = *v++;
21149992Sbostic     if (p == 0) {
21249992Sbostic 	prvars();
21349992Sbostic 	return;
21449992Sbostic     }
21549992Sbostic     do {
21649992Sbostic 	hadsub = 0;
21749992Sbostic 	vp = p;
21849992Sbostic 	if (letter(*p))
21949992Sbostic 	    for (; alnum(*p); p++)
22049992Sbostic 		continue;
22149992Sbostic 	if (vp == p || !letter(*vp))
22249992Sbostic 	    stderror(ERR_NAME | ERR_VARBEGIN);
22349992Sbostic 	if ((p - vp) > MAXVARLEN)
22449992Sbostic 	    stderror(ERR_NAME | ERR_VARTOOLONG);
22549992Sbostic 	if (*p == '[') {
22649992Sbostic 	    hadsub++;
22749992Sbostic 	    p = getinx(p, &subscr);
2281305Sbill 	}
22949992Sbostic 	if (*p == 0 && *v)
23049992Sbostic 	    p = *v++;
23160237Schristos 	if ((op = *p) != '\0')
23249992Sbostic 	    *p++ = 0;
23349992Sbostic 	else
23449992Sbostic 	    stderror(ERR_NAME | ERR_ASSIGN);
2351305Sbill 
23649992Sbostic 	if (*p == '\0' && *v == NULL)
23749992Sbostic 	    stderror(ERR_NAME | ERR_ASSIGN);
23849992Sbostic 
23949992Sbostic 	vp = Strsave(vp);
24049992Sbostic 	if (op == '=') {
24149992Sbostic 	    c = '=';
24249992Sbostic 	    p = xset(p, &v);
24349992Sbostic 	}
24449992Sbostic 	else {
24549992Sbostic 	    c = *p++;
24649992Sbostic 	    if (any("+-", c)) {
24749992Sbostic 		if (c != op || *p)
24849992Sbostic 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
24949992Sbostic 		p = Strsave(STR1);
25049992Sbostic 	    }
25149992Sbostic 	    else {
25249992Sbostic 		if (any("<>", op)) {
25349992Sbostic 		    if (c != op)
25449992Sbostic 			stderror(ERR_NAME | ERR_UNKNOWNOP);
25549992Sbostic 		    c = *p++;
25649992Sbostic 		    stderror(ERR_NAME | ERR_SYNTAX);
25717513Sedward 		}
2581305Sbill 		if (c != '=')
25949992Sbostic 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
26049992Sbostic 		p = xset(p, &v);
26149992Sbostic 	    }
26249992Sbostic 	}
26349992Sbostic 	if (op == '=')
26449992Sbostic 	    if (hadsub)
26549992Sbostic 		asx(vp, subscr, p);
26649992Sbostic 	    else
26749992Sbostic 		set(vp, p);
26849992Sbostic 	else if (hadsub) {
26949992Sbostic 	    struct varent *gv = getvx(vp, subscr);
27049992Sbostic 
27149992Sbostic 	    asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
27249992Sbostic 	}
27349992Sbostic 	else
27449992Sbostic 	    set(vp, operate(op, value(vp), p));
27549992Sbostic 	if (eq(vp, STRpath)) {
27649992Sbostic 	    exportpath(adrof(STRpath)->vec);
27750439Schristos 	    dohash(NULL, NULL);
27849992Sbostic 	}
27949992Sbostic 	xfree((ptr_t) vp);
28049992Sbostic 	if (c != '=')
28149992Sbostic 	    xfree((ptr_t) p);
28260237Schristos     } while ((p = *v++) != NULL);
2831305Sbill }
2841305Sbill 
28549992Sbostic static Char *
xset(cp,vp)2861305Sbill xset(cp, vp)
28749992Sbostic     Char   *cp, ***vp;
2881305Sbill {
28949992Sbostic     register Char *dp;
2901305Sbill 
29149992Sbostic     if (*cp) {
29249992Sbostic 	dp = Strsave(cp);
29349992Sbostic 	--(*vp);
29449992Sbostic 	xfree((ptr_t) ** vp);
29549992Sbostic 	**vp = dp;
29649992Sbostic     }
29751009Schristos     return (putn(expr(vp)));
2981305Sbill }
2991305Sbill 
30049992Sbostic static Char *
operate(op,vp,p)3011305Sbill operate(op, vp, p)
30250024Schristos     int    op;
30350024Schristos     Char  *vp, *p;
3041305Sbill {
30549992Sbostic     Char    opr[2];
30649992Sbostic     Char   *vec[5];
30749992Sbostic     register Char **v = vec;
30849992Sbostic     Char  **vecp = v;
30949992Sbostic     register int i;
3101305Sbill 
31149992Sbostic     if (op != '=') {
31249992Sbostic 	if (*vp)
31349992Sbostic 	    *v++ = vp;
31449992Sbostic 	opr[0] = op;
31549992Sbostic 	opr[1] = 0;
31649992Sbostic 	*v++ = opr;
31749992Sbostic 	if (op == '<' || op == '>')
31849992Sbostic 	    *v++ = opr;
31949992Sbostic     }
32049992Sbostic     *v++ = p;
32149992Sbostic     *v++ = 0;
32251009Schristos     i = expr(&vecp);
32349992Sbostic     if (*vecp)
32449992Sbostic 	stderror(ERR_NAME | ERR_EXPRESSION);
32549992Sbostic     return (putn(i));
3261305Sbill }
3271305Sbill 
32849992Sbostic static Char *putp;
32949992Sbostic 
33049992Sbostic Char   *
putn(n)3311305Sbill putn(n)
33249992Sbostic     register int n;
3331305Sbill {
33449992Sbostic     int     num;
33549992Sbostic     static Char number[15];
3361305Sbill 
33749992Sbostic     putp = number;
33849992Sbostic     if (n < 0) {
33949992Sbostic 	n = -n;
34049992Sbostic 	*putp++ = '-';
34149992Sbostic     }
34249992Sbostic     num = 2;			/* confuse lint */
34358877Schristos     if (sizeof(int) == num && ((unsigned int) n) == 0x8000) {
34449992Sbostic 	*putp++ = '3';
34549992Sbostic 	n = 2768;
3461305Sbill #ifdef pdp11
34749992Sbostic     }
3481305Sbill #else
34949992Sbostic     }
35049992Sbostic     else {
35149992Sbostic 	num = 4;		/* confuse lint */
35258877Schristos 	if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) {
35349992Sbostic 	    *putp++ = '2';
35449992Sbostic 	    n = 147483648;
3551305Sbill 	}
35649992Sbostic     }
3571305Sbill #endif
35849992Sbostic     putn1(n);
35949992Sbostic     *putp = 0;
36049992Sbostic     return (Strsave(number));
3611305Sbill }
3621305Sbill 
36349992Sbostic static void
putn1(n)3641305Sbill putn1(n)
36549992Sbostic     register int n;
3661305Sbill {
36749992Sbostic     if (n > 9)
36849992Sbostic 	putn1(n / 10);
36949992Sbostic     *putp++ = n % 10 + '0';
3701305Sbill }
3711305Sbill 
37249992Sbostic int
getn(cp)3731305Sbill getn(cp)
37449992Sbostic     register Char *cp;
3751305Sbill {
37649992Sbostic     register int n;
37749992Sbostic     int     sign;
3781305Sbill 
37949992Sbostic     sign = 0;
38049992Sbostic     if (cp[0] == '+' && cp[1])
38149992Sbostic 	cp++;
38249992Sbostic     if (*cp == '-') {
38349992Sbostic 	sign++;
38449992Sbostic 	cp++;
38549992Sbostic 	if (!Isdigit(*cp))
38649992Sbostic 	    stderror(ERR_NAME | ERR_BADNUM);
38749992Sbostic     }
38849992Sbostic     n = 0;
38949992Sbostic     while (Isdigit(*cp))
39049992Sbostic 	n = n * 10 + *cp++ - '0';
39149992Sbostic     if (*cp)
39249992Sbostic 	stderror(ERR_NAME | ERR_BADNUM);
39349992Sbostic     return (sign ? -n : n);
3941305Sbill }
3951305Sbill 
39649992Sbostic Char   *
value1(var,head)3971305Sbill value1(var, head)
39849992Sbostic     Char   *var;
39949992Sbostic     struct varent *head;
4001305Sbill {
40149992Sbostic     register struct varent *vp;
4021305Sbill 
40349992Sbostic     vp = adrof1(var, head);
40449992Sbostic     return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
4051305Sbill }
4061305Sbill 
40749992Sbostic static struct varent *
madrof(pat,vp)40817513Sedward madrof(pat, vp)
40949992Sbostic     Char   *pat;
41049992Sbostic     register struct varent *vp;
4111305Sbill {
41249992Sbostic     register struct varent *vp1;
4131305Sbill 
41449992Sbostic     for (; vp; vp = vp->v_right) {
41549992Sbostic 	if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
41649992Sbostic 	    return vp1;
41749992Sbostic 	if (Gmatch(vp->v_name, pat))
41849992Sbostic 	    return vp;
41949992Sbostic     }
42049992Sbostic     return vp;
4211305Sbill }
4221305Sbill 
4231305Sbill struct varent *
adrof1(name,v)42417513Sedward adrof1(name, v)
42549992Sbostic     register Char *name;
42649992Sbostic     register struct varent *v;
4271305Sbill {
42849992Sbostic     register cmp;
4291305Sbill 
43049992Sbostic     v = v->v_left;
43149992Sbostic     while (v && ((cmp = *name - *v->v_name) ||
43249992Sbostic 		 (cmp = Strcmp(name, v->v_name))))
43349992Sbostic 	if (cmp < 0)
43449992Sbostic 	    v = v->v_left;
43549992Sbostic 	else
43649992Sbostic 	    v = v->v_right;
43749992Sbostic     return v;
4381305Sbill }
4391305Sbill 
4401305Sbill /*
4411305Sbill  * The caller is responsible for putting value in a safe place
4421305Sbill  */
44349992Sbostic void
set(var,val)44417513Sedward set(var, val)
44549992Sbostic     Char   *var, *val;
4461305Sbill {
44749992Sbostic     register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
4481305Sbill 
44949992Sbostic     vec[0] = val;
45049992Sbostic     vec[1] = 0;
45149992Sbostic     set1(var, vec, &shvhed);
4521305Sbill }
4531305Sbill 
45449992Sbostic void
set1(var,vec,head)4551305Sbill set1(var, vec, head)
45649992Sbostic     Char   *var, **vec;
45749992Sbostic     struct varent *head;
4581305Sbill {
45949992Sbostic     register Char **oldv = vec;
4601305Sbill 
46149992Sbostic     gflag = 0;
46249992Sbostic     tglob(oldv);
46349992Sbostic     if (gflag) {
46449992Sbostic 	vec = globall(oldv);
46549992Sbostic 	if (vec == 0) {
46649992Sbostic 	    blkfree(oldv);
46749992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
46849992Sbostic 	    return;
4691305Sbill 	}
47049992Sbostic 	blkfree(oldv);
47149992Sbostic 	gargv = 0;
47249992Sbostic     }
47349992Sbostic     setq(var, vec, head);
4741305Sbill }
4751305Sbill 
47649992Sbostic 
47749992Sbostic void
setq(name,vec,p)47817513Sedward setq(name, vec, p)
47949992Sbostic     Char   *name, **vec;
48049992Sbostic     register struct varent *p;
4811305Sbill {
48249992Sbostic     register struct varent *c;
48349992Sbostic     register f;
4841305Sbill 
48549992Sbostic     f = 0;			/* tree hangs off the header's left link */
48660237Schristos     while ((c = p->v_link[f]) != NULL) {
48749992Sbostic 	if ((f = *name - *c->v_name) == 0 &&
48849992Sbostic 	    (f = Strcmp(name, c->v_name)) == 0) {
48949992Sbostic 	    blkfree(c->vec);
49049992Sbostic 	    goto found;
4911305Sbill 	}
49249992Sbostic 	p = c;
49349992Sbostic 	f = f > 0;
49449992Sbostic     }
49549992Sbostic     p->v_link[f] = c = (struct varent *) xmalloc((size_t) sizeof(struct varent));
49649992Sbostic     c->v_name = Strsave(name);
49749992Sbostic     c->v_bal = 0;
49849992Sbostic     c->v_left = c->v_right = 0;
49949992Sbostic     c->v_parent = p;
50049992Sbostic     balance(p, f, 0);
50117513Sedward found:
50249992Sbostic     trim(c->vec = vec);
5031305Sbill }
5041305Sbill 
50549992Sbostic void
50650439Schristos /*ARGSUSED*/
unset(v,t)50750439Schristos unset(v, t)
50850439Schristos     Char **v;
50950439Schristos     struct command *t;
5101305Sbill {
51149992Sbostic     unset1(v, &shvhed);
51217513Sedward #ifdef FILEC
51349992Sbostic     if (adrof(STRfilec) == 0)
51449992Sbostic 	filec = 0;
51517513Sedward #endif
51649992Sbostic     if (adrof(STRhistchars) == 0) {
51749992Sbostic 	HIST = '!';
51849992Sbostic 	HISTSUB = '^';
51949992Sbostic     }
52049992Sbostic     if (adrof(STRwordchars) == 0)
52149992Sbostic 	word_chars = STR_WORD_CHARS;
5221305Sbill }
5231305Sbill 
52449992Sbostic void
unset1(v,head)5251305Sbill unset1(v, head)
52649992Sbostic     register Char *v[];
52749992Sbostic     struct varent *head;
5281305Sbill {
52949992Sbostic     register struct varent *vp;
53049992Sbostic     register int cnt;
5311305Sbill 
53249992Sbostic     while (*++v) {
53349992Sbostic 	cnt = 0;
53460237Schristos 	while ((vp = madrof(*v, head->v_left)) != NULL)
53549992Sbostic 	    unsetv1(vp), cnt++;
53649992Sbostic 	if (cnt == 0)
53751589Schristos 	    setname(vis_str(*v));
53849992Sbostic     }
5391305Sbill }
5401305Sbill 
54149992Sbostic void
unsetv(var)5421305Sbill unsetv(var)
54349992Sbostic     Char   *var;
5441305Sbill {
54549992Sbostic     register struct varent *vp;
5461305Sbill 
54749992Sbostic     if ((vp = adrof1(var, &shvhed)) == 0)
54849992Sbostic 	udvar(var);
54949992Sbostic     unsetv1(vp);
5501305Sbill }
5511305Sbill 
55249992Sbostic static void
unsetv1(p)55317513Sedward unsetv1(p)
55449992Sbostic     register struct varent *p;
5551305Sbill {
55649992Sbostic     register struct varent *c, *pp;
55749992Sbostic     register f;
5581305Sbill 
55949992Sbostic     /*
56049992Sbostic      * Free associated memory first to avoid complications.
56149992Sbostic      */
56249992Sbostic     blkfree(p->vec);
56349992Sbostic     xfree((ptr_t) p->v_name);
56449992Sbostic     /*
56549992Sbostic      * If p is missing one child, then we can move the other into where p is.
56649992Sbostic      * Otherwise, we find the predecessor of p, which is guaranteed to have no
56749992Sbostic      * right child, copy it into p, and move it's left child into it.
56849992Sbostic      */
56949992Sbostic     if (p->v_right == 0)
57049992Sbostic 	c = p->v_left;
57149992Sbostic     else if (p->v_left == 0)
57249992Sbostic 	c = p->v_right;
57349992Sbostic     else {
57451437Sleres 	for (c = p->v_left; c->v_right; c = c->v_right)
57551437Sleres 	    continue;
57649992Sbostic 	p->v_name = c->v_name;
57749992Sbostic 	p->vec = c->vec;
57849992Sbostic 	p = c;
57949992Sbostic 	c = p->v_left;
58049992Sbostic     }
58149992Sbostic     /*
58249992Sbostic      * Move c into where p is.
58349992Sbostic      */
58449992Sbostic     pp = p->v_parent;
58549992Sbostic     f = pp->v_right == p;
58660237Schristos     if ((pp->v_link[f] = c) != NULL)
58749992Sbostic 	c->v_parent = pp;
58849992Sbostic     /*
58949992Sbostic      * Free the deleted node, and rebalance.
59049992Sbostic      */
59149992Sbostic     xfree((ptr_t) p);
59249992Sbostic     balance(pp, f, 1);
5931305Sbill }
5941305Sbill 
59549992Sbostic void
setNS(cp)5961305Sbill setNS(cp)
59749992Sbostic     Char   *cp;
5981305Sbill {
59950045Schristos     set(cp, Strsave(STRNULL));
6001305Sbill }
6011305Sbill 
60249992Sbostic void
60350439Schristos /*ARGSUSED*/
shift(v,t)60450439Schristos shift(v, t)
60550439Schristos     Char **v;
60650439Schristos     struct command *t;
6071305Sbill {
60849992Sbostic     register struct varent *argv;
60949992Sbostic     register Char *name;
6101305Sbill 
61149992Sbostic     v++;
61249992Sbostic     name = *v;
61349992Sbostic     if (name == 0)
61449992Sbostic 	name = STRargv;
61549992Sbostic     else
61649992Sbostic 	(void) strip(name);
61749992Sbostic     argv = adrof(name);
61849992Sbostic     if (argv == 0)
61949992Sbostic 	udvar(name);
62049992Sbostic     if (argv->vec[0] == 0)
62149992Sbostic 	stderror(ERR_NAME | ERR_NOMORE);
62249992Sbostic     lshift(argv->vec, 1);
6231305Sbill }
6241305Sbill 
62549992Sbostic static void
exportpath(val)6261305Sbill exportpath(val)
62749992Sbostic     Char  **val;
6281305Sbill {
62949992Sbostic     Char    exppath[BUFSIZ];
6301305Sbill 
63149992Sbostic     exppath[0] = 0;
63249992Sbostic     if (val)
63349992Sbostic 	while (*val) {
63449992Sbostic 	    if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) {
63550439Schristos 		(void) fprintf(csherr,
63650439Schristos 			       "Warning: ridiculously long PATH truncated\n");
63749992Sbostic 		break;
63849992Sbostic 	    }
63953565Schristos 	    if ((**val != '/' || **val == '\0') && (euid == 0 || uid == 0))
64053565Schristos 		    (void) fprintf(csherr,
64153565Schristos 		    "Warning: exported path contains relative components.\n");
64249992Sbostic 	    (void) Strcat(exppath, *val++);
64349992Sbostic 	    if (*val == 0 || eq(*val, STRRparen))
64449992Sbostic 		break;
64549992Sbostic 	    (void) Strcat(exppath, STRcolon);
64649992Sbostic 	}
64749992Sbostic     Setenv(STRPATH, exppath);
6481305Sbill }
64917513Sedward 
65049992Sbostic #ifndef lint
65149992Sbostic  /*
65249992Sbostic   * Lint thinks these have null effect
65349992Sbostic   */
65449992Sbostic  /* macros to do single rotations on node p */
65517513Sedward #define rright(p) (\
65617513Sedward 	t = (p)->v_left,\
65717513Sedward 	(t)->v_parent = (p)->v_parent,\
65817513Sedward 	((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
65917513Sedward 	(t->v_right = (p))->v_parent = t,\
66017513Sedward 	(p) = t)
66117513Sedward #define rleft(p) (\
66217513Sedward 	t = (p)->v_right,\
66317513Sedward 	(t)->v_parent = (p)->v_parent,\
66417513Sedward 	((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
66517513Sedward 	(t->v_left = (p))->v_parent = t,\
66617513Sedward 	(p) = t)
66749992Sbostic #else
66849992Sbostic struct varent *
rleft(p)66949992Sbostic rleft(p)
67049992Sbostic     struct varent *p;
67149992Sbostic {
67249992Sbostic     return (p);
67349992Sbostic }
67449992Sbostic struct varent *
rright(p)67549992Sbostic rright(p)
67649992Sbostic     struct varent *p;
67749992Sbostic {
67849992Sbostic     return (p);
67949992Sbostic }
68017513Sedward 
68149992Sbostic #endif				/* ! lint */
68249992Sbostic 
68349992Sbostic 
68417513Sedward /*
68517513Sedward  * Rebalance a tree, starting at p and up.
68617513Sedward  * F == 0 means we've come from p's left child.
68717513Sedward  * D == 1 means we've just done a delete, otherwise an insert.
68817513Sedward  */
68949992Sbostic static void
balance(p,f,d)69017513Sedward balance(p, f, d)
69149992Sbostic     register struct varent *p;
69249992Sbostic     register int f, d;
69317513Sedward {
69449992Sbostic     register struct varent *pp;
69517513Sedward 
69649992Sbostic #ifndef lint
69749992Sbostic     register struct varent *t;	/* used by the rotate macros */
69849992Sbostic 
69949992Sbostic #endif
70049992Sbostic     register ff;
70149992Sbostic 
70249992Sbostic     /*
70349992Sbostic      * Ok, from here on, p is the node we're operating on; pp is it's parent; f
70449992Sbostic      * is the branch of p from which we have come; ff is the branch of pp which
70549992Sbostic      * is p.
70649992Sbostic      */
70760237Schristos     for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
70849992Sbostic 	ff = pp->v_right == p;
70949992Sbostic 	if (f ^ d) {		/* right heavy */
71049992Sbostic 	    switch (p->v_bal) {
71149992Sbostic 	    case -1:		/* was left heavy */
71249992Sbostic 		p->v_bal = 0;
71349992Sbostic 		break;
71449992Sbostic 	    case 0:		/* was balanced */
71549992Sbostic 		p->v_bal = 1;
71649992Sbostic 		break;
71749992Sbostic 	    case 1:		/* was already right heavy */
71849992Sbostic 		switch (p->v_right->v_bal) {
71949992Sbostic 		case 1:	/* sigle rotate */
72049992Sbostic 		    pp->v_link[ff] = rleft(p);
72149992Sbostic 		    p->v_left->v_bal = 0;
72249992Sbostic 		    p->v_bal = 0;
72349992Sbostic 		    break;
72449992Sbostic 		case 0:	/* single rotate */
72549992Sbostic 		    pp->v_link[ff] = rleft(p);
72649992Sbostic 		    p->v_left->v_bal = 1;
72749992Sbostic 		    p->v_bal = -1;
72849992Sbostic 		    break;
72949992Sbostic 		case -1:	/* double rotate */
73049992Sbostic 		    (void) rright(p->v_right);
73149992Sbostic 		    pp->v_link[ff] = rleft(p);
73249992Sbostic 		    p->v_left->v_bal =
73349992Sbostic 			p->v_bal < 1 ? 0 : -1;
73449992Sbostic 		    p->v_right->v_bal =
73549992Sbostic 			p->v_bal > -1 ? 0 : 1;
73649992Sbostic 		    p->v_bal = 0;
73749992Sbostic 		    break;
73849992Sbostic 		}
73949992Sbostic 		break;
74049992Sbostic 	    }
74149992Sbostic 	}
74249992Sbostic 	else {			/* left heavy */
74349992Sbostic 	    switch (p->v_bal) {
74449992Sbostic 	    case 1:		/* was right heavy */
74549992Sbostic 		p->v_bal = 0;
74649992Sbostic 		break;
74749992Sbostic 	    case 0:		/* was balanced */
74849992Sbostic 		p->v_bal = -1;
74949992Sbostic 		break;
75049992Sbostic 	    case -1:		/* was already left heavy */
75149992Sbostic 		switch (p->v_left->v_bal) {
75249992Sbostic 		case -1:	/* single rotate */
75349992Sbostic 		    pp->v_link[ff] = rright(p);
75449992Sbostic 		    p->v_right->v_bal = 0;
75549992Sbostic 		    p->v_bal = 0;
75649992Sbostic 		    break;
75749992Sbostic 		case 0:	/* signle rotate */
75849992Sbostic 		    pp->v_link[ff] = rright(p);
75949992Sbostic 		    p->v_right->v_bal = -1;
76049992Sbostic 		    p->v_bal = 1;
76149992Sbostic 		    break;
76249992Sbostic 		case 1:	/* double rotate */
76349992Sbostic 		    (void) rleft(p->v_left);
76449992Sbostic 		    pp->v_link[ff] = rright(p);
76549992Sbostic 		    p->v_left->v_bal =
76649992Sbostic 			p->v_bal < 1 ? 0 : -1;
76749992Sbostic 		    p->v_right->v_bal =
76849992Sbostic 			p->v_bal > -1 ? 0 : 1;
76949992Sbostic 		    p->v_bal = 0;
77049992Sbostic 		    break;
77149992Sbostic 		}
77249992Sbostic 		break;
77349992Sbostic 	    }
77449992Sbostic 	}
77517513Sedward 	/*
77649992Sbostic 	 * If from insert, then we terminate when p is balanced. If from
77749992Sbostic 	 * delete, then we terminate when p is unbalanced.
77817513Sedward 	 */
77949992Sbostic 	if ((p->v_bal == 0) ^ d)
78049992Sbostic 	    break;
78149992Sbostic     }
78217513Sedward }
78317513Sedward 
78449992Sbostic void
plist(p)78517513Sedward plist(p)
78649992Sbostic     register struct varent *p;
78717513Sedward {
78849992Sbostic     register struct varent *c;
78949992Sbostic     register len;
790*68576Schristos     sigset_t sigset;
79117513Sedward 
792*68576Schristos     if (setintr) {
793*68576Schristos 	sigemptyset(&sigset);
794*68576Schristos 	sigaddset(&sigset, SIGINT);
795*68576Schristos 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
796*68576Schristos     }
79749992Sbostic 
79849992Sbostic     for (;;) {
79949992Sbostic 	while (p->v_left)
80049992Sbostic 	    p = p->v_left;
80149992Sbostic x:
80249992Sbostic 	if (p->v_parent == 0)	/* is it the header? */
80349992Sbostic 	    return;
80449992Sbostic 	len = blklen(p->vec);
80553565Schristos 	(void) fprintf(cshout, "%s\t", short2str(p->v_name));
80649992Sbostic 	if (len != 1)
80750439Schristos 	    (void) fputc('(', cshout);
80850439Schristos 	blkpr(cshout, p->vec);
80949992Sbostic 	if (len != 1)
81050439Schristos 	    (void) fputc(')', cshout);
81150439Schristos 	(void) fputc('\n', cshout);
81249992Sbostic 	if (p->v_right) {
81349992Sbostic 	    p = p->v_right;
81449992Sbostic 	    continue;
81517513Sedward 	}
81649992Sbostic 	do {
81749992Sbostic 	    c = p;
81849992Sbostic 	    p = p->v_parent;
81949992Sbostic 	} while (p->v_right == c);
82049992Sbostic 	goto x;
82149992Sbostic     }
82217513Sedward }
823