Home | History | Annotate | Download | only in csh
      1    0   stevel /*
      2  356   muffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
      3    0   stevel  * Use is subject to license terms.
      4    0   stevel  */
      5    0   stevel 
      6    0   stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7    0   stevel /*	  All Rights Reserved  	*/
      8    0   stevel 
      9    0   stevel /*
     10    0   stevel  * Copyright (c) 1980 Regents of the University of California.
     11    0   stevel  * All rights reserved. The Berkeley Software License Agreement
     12    0   stevel  * specifies the terms and conditions for redistribution.
     13    0   stevel  */
     14    0   stevel 
     15    0   stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     16    0   stevel 
     17    0   stevel #include "sh.h"
     18    0   stevel #include "sh.tconst.h"
     19  356   muffin extern int	didchdir;
     20    0   stevel 
     21    0   stevel /*
     22    0   stevel  * C Shell
     23    0   stevel  */
     24    0   stevel 
     25  356   muffin void	asx(tchar *, int, tchar *);
     26  356   muffin void	putn1(int);
     27  356   muffin void	set(tchar *, tchar *);
     28  356   muffin void	set1(tchar *, tchar **, struct varent *);
     29  356   muffin void	setq(tchar *, tchar **, struct varent *);
     30  356   muffin void	unset1(tchar *[], struct varent *);
     31  356   muffin void	unsetv1(struct varent *);
     32  356   muffin void	exportpath(tchar **);
     33  356   muffin void	balance(struct varent *, int, int);
     34  356   muffin tchar	*operate(tchar, tchar *, tchar *);
     35  356   muffin tchar	*getinx(tchar *, int *);
     36  356   muffin tchar	*xset(tchar *, tchar ***);
     37  356   muffin struct varent	*getvx(tchar *, int);
     38  356   muffin 
     39  356   muffin void
     40  356   muffin doset(tchar **v)
     41    0   stevel {
     42  356   muffin 	tchar *p;
     43    0   stevel 	tchar *vp, op;
     44    0   stevel 	tchar **vecp;
     45    0   stevel 	bool hadsub;
     46    0   stevel 	int subscr;
     47    0   stevel 	tchar *retp;
     48    0   stevel 
     49    0   stevel #ifdef TRACE
     50    0   stevel 	tprintf("TRACE- doset()\n");
     51    0   stevel #endif
     52    0   stevel 	v++;
     53    0   stevel 	p = *v++;
     54    0   stevel 	if (p == 0) {
     55    0   stevel 		prvars();
     56    0   stevel 		return;
     57    0   stevel 	}
     58    0   stevel 	do {
     59    0   stevel 		hadsub = 0;
     60    0   stevel 		/*
     61    0   stevel 		 * check for proper variable syntax
     62    0   stevel 		 * must be alphanumeric, start with a letter and
     63    0   stevel 		 * be at most 20 characters
     64    0   stevel 		 */
     65    0   stevel 		for (vp = p; alnum(*p); p++)
     66    0   stevel 			continue;
     67    0   stevel 		if (vp == p || !letter(*vp))
     68    0   stevel 			goto setsyn;
     69  559  nakanon 		if ((p - vp) > MAX_VAR_LEN)
     70    0   stevel 			bferr("Variable name too long");
     71    0   stevel 		if (*p == '[') {
     72    0   stevel 			hadsub++;
     73    0   stevel 			p = getinx(p, &subscr);
     74    0   stevel 		}
     75    0   stevel 		if (op = *p) {
     76    0   stevel 			*p++ = 0;
     77    0   stevel 			if (*p == 0 && *v && **v == '(')
     78    0   stevel 				p = *v++;
     79  559  nakanon 		} else if (*v && eq(*v, S_EQ /* "=" */)) {
     80    0   stevel 			op = '=', v++;
     81    0   stevel 			if (*v)
     82    0   stevel 				p = *v++;
     83    0   stevel 		}
     84    0   stevel 		if (op && op != '=')
     85    0   stevel setsyn:
     86    0   stevel 			bferr("Syntax error");
     87  559  nakanon 		if (eq(p, S_LPAR /* "(" */)) {
     88  356   muffin 			tchar **e = v;
     89    0   stevel 
     90    0   stevel 			if (hadsub)
     91    0   stevel 				goto setsyn;
     92    0   stevel 			for (;;) {
     93    0   stevel 				if (!*e)
     94    0   stevel 					bferr("Missing )");
     95    0   stevel 				if (**e == ')')
     96    0   stevel 					break;
     97    0   stevel 				e++;
     98    0   stevel 			}
     99    0   stevel 			p = *e;
    100    0   stevel 			*e = 0;
    101    0   stevel 			vecp = saveblk(v);
    102    0   stevel 			set1(vp, vecp, &shvhed);
    103    0   stevel 			*e = p;
    104    0   stevel 			v = e + 1;
    105    0   stevel 		} else if (hadsub) {
    106    0   stevel 			retp = savestr(p);
    107    0   stevel 			asx(vp, subscr, retp);
    108    0   stevel 			xfree(retp);
    109    0   stevel 			retp = 0;
    110    0   stevel 		} else
    111    0   stevel 			set(vp, savestr(p));
    112  559  nakanon 		if (eq(vp, S_path /* "path" */)) {
    113  559  nakanon 			exportpath(adrof(S_path /* "path" */)->vec);
    114    0   stevel 			dohash(xhash);
    115  559  nakanon 		} else if (eq(vp, S_histchars /* "histchars" */)) {
    116  559  nakanon 			tchar *p = value(S_histchars /* "histchars" */);
    117    0   stevel 			HIST = *p++;
    118    0   stevel 			HISTSUB = *p;
    119  559  nakanon 		} else if (eq(vp, S_user /* "user" */))
    120  559  nakanon 			local_setenv(S_USER /* "USER" */, value(vp));
    121  559  nakanon 		else if (eq(vp, S_term /* "term" */))
    122  559  nakanon 			local_setenv(S_TERM /* "TERM" */, value(vp));
    123  559  nakanon 		else if (eq(vp, S_home /* "home" */))
    124  559  nakanon 			local_setenv(S_HOME /* "HOME" */, value(vp));
    125    0   stevel #ifdef FILEC
    126  559  nakanon 		else if (eq(vp, S_filec /* "filec" */))
    127    0   stevel 			filec = 1;
    128  559  nakanon 		else if (eq(vp, S_cdpath /* "cdpath" */))
    129    0   stevel 			dohash(xhash2);
    130    0   stevel #endif
    131    0   stevel 	} while (p = *v++);
    132    0   stevel }
    133    0   stevel 
    134    0   stevel tchar *
    135  356   muffin getinx(tchar *cp, int *ip)
    136    0   stevel {
    137    0   stevel 
    138    0   stevel #ifdef TRACE
    139    0   stevel 	tprintf("TRACE- getinx()\n");
    140    0   stevel #endif
    141    0   stevel 	*ip = 0;
    142    0   stevel 	*cp++ = 0;
    143    0   stevel 	while (*cp && digit(*cp))
    144    0   stevel 		*ip = *ip * 10 + *cp++ - '0';
    145    0   stevel 	if (*cp++ != ']')
    146    0   stevel 		bferr("Subscript error");
    147    0   stevel 	return (cp);
    148    0   stevel }
    149    0   stevel 
    150  356   muffin void
    151  356   muffin asx(tchar *vp, int subscr, tchar *p)
    152    0   stevel {
    153  356   muffin 	struct varent *v = getvx(vp, subscr);
    154    0   stevel 
    155    0   stevel #ifdef TRACE
    156    0   stevel 	tprintf("TRACE- asx()\n");
    157    0   stevel #endif
    158    0   stevel 	xfree(v->vec[subscr - 1]);
    159    0   stevel 	v->vec[subscr - 1] = globone(p);
    160    0   stevel }
    161    0   stevel 
    162    0   stevel struct varent *
    163  356   muffin getvx(tchar *vp, int subscr)
    164    0   stevel {
    165  356   muffin 	struct varent *v = adrof(vp);
    166    0   stevel 
    167    0   stevel #ifdef TRACE
    168    0   stevel 	tprintf("TRACE- getvx()\n");
    169    0   stevel #endif
    170    0   stevel 	if (v == 0)
    171    0   stevel 		udvar(vp);
    172    0   stevel 	if (subscr < 1 || subscr > blklen(v->vec))
    173    0   stevel 		bferr("Subscript out of range");
    174    0   stevel 	return (v);
    175    0   stevel }
    176    0   stevel 
    177    0   stevel tchar plusplus[2] = { '1', 0 };
    178    0   stevel 
    179  356   muffin void
    180  356   muffin dolet(tchar **v)
    181    0   stevel {
    182  356   muffin 	tchar *p;
    183    0   stevel 	tchar *vp, c, op;
    184    0   stevel 	bool hadsub;
    185    0   stevel 	int subscr;
    186    0   stevel 
    187    0   stevel 	v++;
    188    0   stevel 	p = *v++;
    189    0   stevel 	if (p == 0) {
    190    0   stevel 		prvars();
    191    0   stevel 		return;
    192    0   stevel 	}
    193    0   stevel 	do {
    194    0   stevel 		hadsub = 0;
    195    0   stevel 		for (vp = p; alnum(*p); p++)
    196    0   stevel 			continue;
    197    0   stevel 		if (vp == p || !letter(*vp))
    198    0   stevel 			goto letsyn;
    199    0   stevel 		if (*p == '[') {
    200    0   stevel 			hadsub++;
    201    0   stevel 			p = getinx(p, &subscr);
    202    0   stevel 		}
    203    0   stevel 		if (*p == 0 && *v)
    204    0   stevel 			p = *v++;
    205    0   stevel 		if (op = *p)
    206    0   stevel 			*p++ = 0;
    207    0   stevel 		else
    208    0   stevel 			goto letsyn;
    209    0   stevel 		vp = savestr(vp);
    210    0   stevel 		if (op == '=') {
    211    0   stevel 			c = '=';
    212    0   stevel 			p = xset(p, &v);
    213    0   stevel 		} else {
    214    0   stevel 			c = *p++;
    215    0   stevel 			/* if (any(c, "+-")) { */
    216    0   stevel 			if (c == '+' || c == '-') {
    217    0   stevel 				if (c != op || *p)
    218    0   stevel 					goto letsyn;
    219    0   stevel 				p = plusplus;
    220    0   stevel 			} else {
    221  559  nakanon 				/* if (any(op, "<>")) { */
    222    0   stevel 				if (op == '<' || op == '>') {
    223    0   stevel 					if (c != op)
    224    0   stevel 						goto letsyn;
    225    0   stevel 					c = *p++;
    226    0   stevel letsyn:
    227    0   stevel 					bferr("Syntax error");
    228    0   stevel 				}
    229    0   stevel 				if (c != '=')
    230    0   stevel 					goto letsyn;
    231    0   stevel 				p = xset(p, &v);
    232    0   stevel 			}
    233    0   stevel 		}
    234    0   stevel 		if (op == '=')
    235    0   stevel 			if (hadsub)
    236    0   stevel 				asx(vp, subscr, p);
    237    0   stevel 			else
    238    0   stevel 				set(vp, p);
    239    0   stevel 		else
    240    0   stevel 			if (hadsub)
    241    0   stevel #ifndef V6
    242    0   stevel 				/* avoid bug in vax CC */
    243    0   stevel 				{
    244    0   stevel 					struct varent *gv = getvx(vp, subscr);
    245    0   stevel 
    246    0   stevel 					asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
    247    0   stevel 				}
    248    0   stevel #else
    249    0   stevel 				asx(vp, subscr, operate(op, getvx(vp, subscr)->vec[subscr - 1], p));
    250    0   stevel #endif
    251    0   stevel 			else
    252    0   stevel 				set(vp, operate(op, value(vp), p));
    253  559  nakanon 		if (eq(vp, S_path /* "path" */)) {
    254  559  nakanon 			exportpath(adrof(S_path /* "path" */)->vec);
    255    0   stevel 			dohash(xhash);
    256    0   stevel 		}
    257    0   stevel 
    258  559  nakanon 		if (eq(vp, S_cdpath /* "cdpath" */))
    259    0   stevel 			dohash(xhash2);
    260    0   stevel 
    261  559  nakanon 		xfree(vp);
    262    0   stevel 		if (c != '=')
    263  559  nakanon 			xfree(p);
    264    0   stevel 	} while (p = *v++);
    265    0   stevel }
    266    0   stevel 
    267    0   stevel tchar *
    268  356   muffin xset(tchar *cp, tchar ***vp)
    269    0   stevel {
    270  356   muffin 	tchar *dp;
    271    0   stevel 
    272    0   stevel #ifdef TRACE
    273    0   stevel 	tprintf("TRACE- xset()\n");
    274    0   stevel #endif
    275    0   stevel 	if (*cp) {
    276    0   stevel 		dp = savestr(cp);
    277    0   stevel 		--(*vp);
    278    0   stevel 		xfree(**vp);
    279    0   stevel 		**vp = dp;
    280    0   stevel 	}
    281    0   stevel 	return (putn(exp(vp)));
    282    0   stevel }
    283    0   stevel 
    284    0   stevel tchar *
    285  356   muffin operate(tchar op, tchar *vp, tchar *p)
    286    0   stevel {
    287    0   stevel 	tchar opr[2];
    288    0   stevel 	tchar *vec[5];
    289  356   muffin 	tchar **v = vec;
    290    0   stevel 	tchar **vecp = v;
    291  356   muffin 	int i;
    292    0   stevel 
    293    0   stevel 	if (op != '=') {
    294    0   stevel 		if (*vp)
    295    0   stevel 			*v++ = vp;
    296    0   stevel 		opr[0] = op;
    297    0   stevel 		opr[1] = 0;
    298    0   stevel 		*v++ = opr;
    299    0   stevel 		if (op == '<' || op == '>')
    300    0   stevel 			*v++ = opr;
    301    0   stevel 	}
    302    0   stevel 	*v++ = p;
    303    0   stevel 	*v++ = 0;
    304    0   stevel 	i = exp(&vecp);
    305    0   stevel 	if (*vecp)
    306    0   stevel 		bferr("Expression syntax");
    307    0   stevel 	return (putn(i));
    308    0   stevel }
    309    0   stevel 
    310    0   stevel static tchar *putp;
    311  559  nakanon 
    312    0   stevel tchar *
    313  356   muffin putn(int n)
    314    0   stevel {
    315    0   stevel 	static tchar number[15];
    316    0   stevel 
    317    0   stevel #ifdef TRACE
    318    0   stevel 	tprintf("TRACE- putn()\n");
    319    0   stevel #endif
    320    0   stevel 	putp = number;
    321    0   stevel 	if (n < 0) {
    322    0   stevel 		n = -n;
    323    0   stevel 		*putp++ = '-';
    324    0   stevel 	}
    325    0   stevel 	if (sizeof (int) == 2 && n == -32768) {
    326    0   stevel 		*putp++ = '3';
    327    0   stevel 		n = 2768;
    328    0   stevel #ifdef pdp11
    329    0   stevel 	}
    330    0   stevel #else
    331    0   stevel 	} else if (sizeof (int) == 4 && n == 0x80000000) {
    332    0   stevel 		*putp++ = '2';
    333    0   stevel 		n = 147483648;
    334    0   stevel 	}
    335    0   stevel #endif
    336    0   stevel 	putn1(n);
    337    0   stevel 	*putp = 0;
    338    0   stevel 	return (savestr(number));
    339    0   stevel }
    340    0   stevel 
    341  356   muffin void
    342  356   muffin putn1(int n)
    343    0   stevel {
    344    0   stevel #ifdef TRACE
    345    0   stevel 	tprintf("TRACE- putn1()\n");
    346    0   stevel #endif
    347    0   stevel 	if (n > 9)
    348    0   stevel 		putn1(n / 10);
    349    0   stevel 	*putp++ = n % 10 + '0';
    350    0   stevel }
    351    0   stevel 
    352  356   muffin int
    353  356   muffin getn(tchar *cp)
    354    0   stevel {
    355  356   muffin 	int n;
    356    0   stevel 	int sign;
    357    0   stevel 
    358    0   stevel #ifdef TRACE
    359    0   stevel 	tprintf("TRACE- getn()\n");
    360    0   stevel #endif
    361    0   stevel 	sign = 0;
    362    0   stevel 	if (cp[0] == '+' && cp[1])
    363    0   stevel 		cp++;
    364    0   stevel 	if (*cp == '-') {
    365    0   stevel 		sign++;
    366    0   stevel 		cp++;
    367    0   stevel 		if (!digit(*cp))
    368    0   stevel 			goto badnum;
    369    0   stevel 	}
    370    0   stevel 	n = 0;
    371    0   stevel 	while (digit(*cp))
    372    0   stevel 		n = n * 10 + *cp++ - '0';
    373    0   stevel 	if (*cp)
    374    0   stevel 		goto badnum;
    375    0   stevel 	return (sign ? -n : n);
    376    0   stevel badnum:
    377    0   stevel 	bferr("Badly formed number");
    378    0   stevel 	return (0);
    379    0   stevel }
    380    0   stevel 
    381    0   stevel tchar *
    382  356   muffin value1(tchar *var, struct varent *head)
    383    0   stevel {
    384  356   muffin 	struct varent *vp;
    385    0   stevel 
    386    0   stevel #ifdef TRACE
    387    0   stevel 	tprintf("TRACE- value1()\n");
    388    0   stevel #endif
    389    0   stevel 	vp = adrof1(var, head);
    390  559  nakanon 	return (vp == 0 || vp->vec[0] == 0 ? S_ /* "" */ : vp->vec[0]);
    391    0   stevel }
    392    0   stevel 
    393    0   stevel struct varent *
    394  356   muffin madrof(tchar *pat, struct varent *vp)
    395    0   stevel {
    396  356   muffin 	struct varent *vp1;
    397    0   stevel 
    398    0   stevel #ifdef TRACE
    399    0   stevel 	tprintf("TRACE- madrof()\n");
    400    0   stevel #endif
    401    0   stevel 	for (; vp; vp = vp->v_right) {
    402    0   stevel 		if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
    403    0   stevel 			return vp1;
    404    0   stevel 		if (Gmatch(vp->v_name, pat))
    405    0   stevel 			return vp;
    406    0   stevel 	}
    407    0   stevel 	return vp;
    408    0   stevel }
    409    0   stevel 
    410    0   stevel struct varent *
    411  356   muffin adrof1(tchar *name, struct varent *v)
    412    0   stevel {
    413  356   muffin 	int cmp;
    414    0   stevel 
    415    0   stevel #ifdef TRACE
    416    0   stevel 	tprintf("TRACE- adrof1()\n");
    417    0   stevel #endif
    418    0   stevel 	v = v->v_left;
    419    0   stevel 	while (v && ((cmp = *name - *v->v_name) ||
    420  559  nakanon 	    (cmp = strcmp_(name, v->v_name))))
    421    0   stevel 		if (cmp < 0)
    422    0   stevel 			v = v->v_left;
    423    0   stevel 		else
    424    0   stevel 			v = v->v_right;
    425    0   stevel 	return v;
    426    0   stevel }
    427    0   stevel 
    428    0   stevel /*
    429    0   stevel  * The caller is responsible for putting value in a safe place
    430    0   stevel  */
    431  356   muffin void
    432  356   muffin set(tchar *var, tchar *val)
    433    0   stevel {
    434  559  nakanon 	tchar **vec =  (tchar **)xalloc(2 * sizeof (tchar **));
    435    0   stevel 
    436    0   stevel #ifdef TRACE
    437    0   stevel 	tprintf("TRACE- set()\n");
    438    0   stevel #endif
    439    0   stevel 	vec[0] = onlyread(val) ? savestr(val) : val;
    440    0   stevel 	vec[1] = 0;
    441    0   stevel 	set1(var, vec, &shvhed);
    442    0   stevel }
    443    0   stevel 
    444  356   muffin void
    445  356   muffin set1(tchar *var, tchar **vec, struct varent *head)
    446    0   stevel {
    447  356   muffin 	tchar **oldv = vec;
    448    0   stevel 
    449    0   stevel #ifdef TRACE
    450    0   stevel 	tprintf("TRACE- set1()\n");
    451    0   stevel #endif
    452    0   stevel 	gflag = 0;
    453  559  nakanon 	/*
    454  559  nakanon 	 * If setting cwd variable via "set cwd=/tmp/something"
    455    0   stevel 	 * then do globbing.  But if we are setting the cwd
    456  559  nakanon 	 * becuz of a cd, chdir, pushd, popd, do not do globbing.
    457    0   stevel 	 */
    458  559  nakanon 	if ((!(eq(var, S_cwd))) || (eq(var, S_cwd) && (didchdir == 0)))
    459    0   stevel 		{
    460  559  nakanon 		tglob(oldv);
    461    0   stevel 		}
    462    0   stevel 	if (gflag) {
    463    0   stevel 		vec = glob(oldv);
    464    0   stevel 		if (vec == 0) {
    465    0   stevel 			bferr("No match");
    466    0   stevel 			blkfree(oldv);
    467    0   stevel 			return;
    468    0   stevel 		}
    469    0   stevel 		blkfree(oldv);
    470    0   stevel 		gargv = 0;
    471    0   stevel 	}
    472    0   stevel 	setq(var, vec, head);
    473    0   stevel }
    474    0   stevel 
    475  356   muffin void
    476  356   muffin setq(tchar *name, tchar **vec, struct varent *p)
    477    0   stevel {
    478  356   muffin 	struct varent *c;
    479  356   muffin 	int f;
    480    0   stevel 
    481    0   stevel #ifdef TRACE
    482    0   stevel 	tprintf("TRACE- setq()\n");
    483    0   stevel #endif
    484    0   stevel 	f = 0;			/* tree hangs off the header's left link */
    485    0   stevel 	while (c = p->v_link[f]) {
    486    0   stevel 		if ((f = *name - *c->v_name) == 0 &&
    487    0   stevel 		    (f = strcmp_(name, c->v_name)) == 0) {
    488    0   stevel 			blkfree(c->vec);
    489    0   stevel 			goto found;
    490    0   stevel 		}
    491    0   stevel 		p = c;
    492    0   stevel 		f = f > 0;
    493    0   stevel 	}
    494    0   stevel 	p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent));
    495    0   stevel 	c->v_name = savestr(name);
    496    0   stevel 	c->v_bal = 0;
    497    0   stevel 	c->v_left = c->v_right = 0;
    498    0   stevel 	c->v_parent = p;
    499    0   stevel 	balance(p, f, 0);
    500    0   stevel found:
    501    0   stevel 	trim(c->vec = vec);
    502    0   stevel }
    503    0   stevel 
    504  356   muffin void
    505  356   muffin unset(tchar *v[])
    506    0   stevel {
    507    0   stevel 
    508    0   stevel #ifdef TRACE
    509    0   stevel 	tprintf("TRACE- unset()\n");
    510    0   stevel #endif
    511    0   stevel 	unset1(v, &shvhed);
    512  559  nakanon 	if (adrof(S_histchars /* "histchars" */) == 0) {
    513    0   stevel 		HIST = '!';
    514    0   stevel 		HISTSUB = '^';
    515    0   stevel 	}
    516    0   stevel #ifdef FILEC
    517  559  nakanon 	if (adrof(S_filec /* "filec" */) == 0)
    518    0   stevel 		filec = 0;
    519    0   stevel #endif
    520    0   stevel }
    521    0   stevel 
    522  356   muffin void
    523  356   muffin unset1(tchar *v[], struct varent *head)
    524    0   stevel {
    525  356   muffin 	struct varent *vp;
    526  356   muffin 	int cnt;
    527    0   stevel 
    528    0   stevel #ifdef TRACE
    529    0   stevel 	tprintf("TRACE- unset1()\n");
    530    0   stevel #endif
    531    0   stevel 	while (*++v) {
    532    0   stevel 		cnt = 0;
    533    0   stevel 		while (vp = madrof(*v, head->v_left))
    534    0   stevel 			unsetv1(vp), cnt++;
    535    0   stevel 		if (cnt == 0)
    536    0   stevel 			setname(*v);
    537    0   stevel 	}
    538    0   stevel }
    539    0   stevel 
    540  356   muffin void
    541  356   muffin unsetv(tchar *var)
    542    0   stevel {
    543  356   muffin 	struct varent *vp;
    544    0   stevel 
    545    0   stevel #ifdef TRACE
    546    0   stevel 	tprintf("TRACE- unsetv()\n");
    547    0   stevel #endif
    548    0   stevel 	if ((vp = adrof1(var, &shvhed)) == 0)
    549    0   stevel 		udvar(var);
    550    0   stevel 	unsetv1(vp);
    551    0   stevel }
    552    0   stevel 
    553  356   muffin void
    554  356   muffin unsetv1(struct varent *p)
    555    0   stevel {
    556  356   muffin 	struct varent *c, *pp;
    557  356   muffin 	int f;
    558    0   stevel 
    559    0   stevel #ifdef TRACE
    560    0   stevel 	tprintf("TRACE- unsetv1()\n");
    561    0   stevel #endif
    562    0   stevel 	/*
    563    0   stevel 	 * Free associated memory first to avoid complications.
    564    0   stevel 	 */
    565    0   stevel 	blkfree(p->vec);
    566  559  nakanon 	xfree(p->v_name);
    567    0   stevel 	/*
    568    0   stevel 	 * If p is missing one child, then we can move the other
    569    0   stevel 	 * into where p is.  Otherwise, we find the predecessor
    570    0   stevel 	 * of p, which is guaranteed to have no right child, copy
    571    0   stevel 	 * it into p, and move it's left child into it.
    572    0   stevel 	 */
    573    0   stevel 	if (p->v_right == 0)
    574    0   stevel 		c = p->v_left;
    575    0   stevel 	else if (p->v_left == 0)
    576    0   stevel 		c = p->v_right;
    577    0   stevel 	else {
    578    0   stevel 		for (c = p->v_left; c->v_right; c = c->v_right)
    579    0   stevel 			;
    580    0   stevel 		p->v_name = c->v_name;
    581    0   stevel 		p->vec = c->vec;
    582    0   stevel 		p = c;
    583    0   stevel 		c = p->v_left;
    584    0   stevel 	}
    585    0   stevel 	/*
    586    0   stevel 	 * Move c into where p is.
    587    0   stevel 	 */
    588    0   stevel 	pp = p->v_parent;
    589    0   stevel 	f = pp->v_right == p;
    590    0   stevel 	if (pp->v_link[f] = c)
    591    0   stevel 		c->v_parent = pp;
    592    0   stevel 	/*
    593    0   stevel 	 * Free the deleted node, and rebalance.
    594    0   stevel 	 */
    595  559  nakanon 	xfree(p);
    596    0   stevel 	balance(pp, f, 1);
    597    0   stevel }
    598    0   stevel 
    599  356   muffin void
    600  356   muffin setNS(tchar *cp)
    601    0   stevel {
    602    0   stevel #ifdef TRACE
    603    0   stevel 	tprintf("TRACE- setNS()\n");
    604    0   stevel #endif
    605    0   stevel 
    606  559  nakanon 	set(cp, S_ /* "" */);
    607    0   stevel }
    608    0   stevel 
    609  356   muffin void
    610  356   muffin shift(tchar **v)
    611    0   stevel {
    612  356   muffin 	struct varent *argv;
    613  356   muffin 	tchar *name;
    614    0   stevel 
    615    0   stevel #ifdef TRACE
    616    0   stevel 	tprintf("TRACE- shift()\n");
    617    0   stevel #endif
    618    0   stevel 	v++;
    619    0   stevel 	name = *v;
    620    0   stevel 	if (name == 0)
    621  559  nakanon 		name = S_argv /* "argv" */;
    622    0   stevel 	else
    623    0   stevel 		(void) strip(name);
    624    0   stevel 	argv = adrof(name);
    625    0   stevel 	if (argv == 0)
    626    0   stevel 		udvar(name);
    627    0   stevel 	if (argv->vec[0] == 0)
    628    0   stevel 		bferr("No more words");
    629    0   stevel 	lshift(argv->vec, 1);
    630    0   stevel }
    631    0   stevel 
    632  356   muffin void
    633  356   muffin exportpath(tchar **val)
    634    0   stevel {
    635    0   stevel 	tchar exppath[PATHSIZ];
    636    0   stevel 
    637    0   stevel #ifdef TRACE
    638    0   stevel 	tprintf("TRACE- exportpath()\n");
    639    0   stevel #endif
    640    0   stevel 	exppath[0] = 0;
    641    0   stevel 	if (val)
    642    0   stevel 		while (*val) {
    643    0   stevel 			if (strlen_(*val) + strlen_(exppath) + 2 > PATHSIZ) {
    644    0   stevel 				printf("Warning: ridiculously long PATH truncated\n");
    645    0   stevel 				break;
    646    0   stevel 			}
    647    0   stevel 			(void) strcat_(exppath, *val++);
    648  559  nakanon 			if (*val == 0 || eq(*val, S_RPAR /* ")" */))
    649    0   stevel 				break;
    650  559  nakanon 			(void) strcat_(exppath, S_COLON /* ":" */);
    651    0   stevel 		}
    652  559  nakanon 	local_setenv(S_PATH /* "PATH" */, exppath);
    653    0   stevel }
    654    0   stevel 
    655    0   stevel 	/* macros to do single rotations on node p */
    656  559  nakanon #define	rright(p) (\
    657    0   stevel 	t = (p)->v_left,\
    658    0   stevel 	(t)->v_parent = (p)->v_parent,\
    659    0   stevel 	((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
    660    0   stevel 	(t->v_right = (p))->v_parent = t,\
    661    0   stevel 	(p) = t)
    662  559  nakanon #define	rleft(p) (\
    663    0   stevel 	t = (p)->v_right,\
    664    0   stevel 	(t)->v_parent = (p)->v_parent,\
    665    0   stevel 	((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
    666    0   stevel 	(t->v_left = (p))->v_parent = t,\
    667    0   stevel 	(p) = t)
    668    0   stevel 
    669    0   stevel /*
    670    0   stevel  * Rebalance a tree, starting at p and up.
    671    0   stevel  * F == 0 means we've come from p's left child.
    672    0   stevel  * D == 1 means we've just done a delete, otherwise an insert.
    673    0   stevel  */
    674  356   muffin void
    675  356   muffin balance(struct varent *p, int f, int d)
    676    0   stevel {
    677  356   muffin 	struct varent *pp;
    678  356   muffin 	struct varent *t;		/* used by the rotate macros */
    679  356   muffin 	int ff;
    680    0   stevel 
    681    0   stevel #ifdef TRACE
    682    0   stevel 	tprintf("TRACE- balance()\n");
    683    0   stevel #endif
    684    0   stevel 	/*
    685    0   stevel 	 * Ok, from here on, p is the node we're operating on;
    686    0   stevel 	 * pp is it's parent; f is the branch of p from which we have come;
    687    0   stevel 	 * ff is the branch of pp which is p.
    688    0   stevel 	 */
    689    0   stevel 	for (; pp = p->v_parent; p = pp, f = ff) {
    690    0   stevel 		ff = pp->v_right == p;
    691    0   stevel 		if (f ^ d) {		/* right heavy */
    692    0   stevel 			switch (p->v_bal) {
    693    0   stevel 			case -1:		/* was left heavy */
    694    0   stevel 				p->v_bal = 0;
    695    0   stevel 				break;
    696    0   stevel 			case 0:			/* was balanced */
    697    0   stevel 				p->v_bal = 1;
    698    0   stevel 				break;
    699    0   stevel 			case 1:			/* was already right heavy */
    700    0   stevel 				switch (p->v_right->v_bal) {
    701    0   stevel 				case 1:			/* sigle rotate */
    702    0   stevel 					pp->v_link[ff] = rleft(p);
    703    0   stevel 					p->v_left->v_bal = 0;
    704    0   stevel 					p->v_bal = 0;
    705    0   stevel 					break;
    706    0   stevel 				case 0:			/* single rotate */
    707    0   stevel 					pp->v_link[ff] = rleft(p);
    708    0   stevel 					p->v_left->v_bal = 1;
    709    0   stevel 					p->v_bal = -1;
    710    0   stevel 					break;
    711    0   stevel 				case -1:		/* double rotate */
    712    0   stevel 					rright(p->v_right);
    713    0   stevel 					pp->v_link[ff] = rleft(p);
    714    0   stevel 					p->v_left->v_bal =
    715    0   stevel 						p->v_bal < 1 ? 0 : -1;
    716    0   stevel 					p->v_right->v_bal =
    717    0   stevel 						p->v_bal > -1 ? 0 : 1;
    718    0   stevel 					p->v_bal = 0;
    719    0   stevel 					break;
    720    0   stevel 				}
    721    0   stevel 				break;
    722    0   stevel 			}
    723    0   stevel 		} else {		/* left heavy */
    724    0   stevel 			switch (p->v_bal) {
    725    0   stevel 			case 1:			/* was right heavy */
    726    0   stevel 				p->v_bal = 0;
    727    0   stevel 				break;
    728    0   stevel 			case 0:			/* was balanced */
    729    0   stevel 				p->v_bal = -1;
    730    0   stevel 				break;
    731    0   stevel 			case -1:		/* was already left heavy */
    732    0   stevel 				switch (p->v_left->v_bal) {
    733    0   stevel 				case -1:		/* single rotate */
    734    0   stevel 					pp->v_link[ff] = rright(p);
    735    0   stevel 					p->v_right->v_bal = 0;
    736    0   stevel 					p->v_bal = 0;
    737    0   stevel 					break;
    738    0   stevel 				case 0:			/* signle rotate */
    739    0   stevel 					pp->v_link[ff] = rright(p);
    740    0   stevel 					p->v_right->v_bal = -1;
    741    0   stevel 					p->v_bal = 1;
    742    0   stevel 					break;
    743    0   stevel 				case 1:			/* double rotate */
    744    0   stevel 					rleft(p->v_left);
    745    0   stevel 					pp->v_link[ff] = rright(p);
    746    0   stevel 					p->v_left->v_bal =
    747    0   stevel 						p->v_bal < 1 ? 0 : -1;
    748    0   stevel 					p->v_right->v_bal =
    749    0   stevel 						p->v_bal > -1 ? 0 : 1;
    750    0   stevel 					p->v_bal = 0;
    751    0   stevel 					break;
    752    0   stevel 				}
    753    0   stevel 				break;
    754    0   stevel 			}
    755    0   stevel 		}
    756    0   stevel 		/*
    757    0   stevel 		 * If from insert, then we terminate when p is balanced.
    758    0   stevel 		 * If from delete, then we terminate when p is unbalanced.
    759    0   stevel 		 */
    760    0   stevel 		if ((p->v_bal == 0) ^ d)
    761    0   stevel 			break;
    762    0   stevel 	}
    763    0   stevel }
    764    0   stevel 
    765  356   muffin void
    766  356   muffin plist(struct varent *p)
    767    0   stevel {
    768  356   muffin 	struct varent *c;
    769  356   muffin 	int len;
    770    0   stevel 
    771    0   stevel #ifdef TRACE
    772    0   stevel 	tprintf("TRACE- plist()\n");
    773    0   stevel #endif
    774    0   stevel 	if (setintr)
    775    0   stevel 		(void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
    776    0   stevel 	for (;;) {
    777    0   stevel 		while (p->v_left)
    778    0   stevel 			p = p->v_left;
    779    0   stevel 	x:
    780    0   stevel 		if (p->v_parent == 0)		/* is it the header? */
    781    0   stevel 			return;
    782    0   stevel 		len = blklen(p->vec);
    783    0   stevel 		printf("%t", p->v_name);
    784    0   stevel 		Putchar('\t');
    785    0   stevel 		if (len != 1)
    786    0   stevel 			Putchar('(');
    787    0   stevel 		blkpr(p->vec);
    788    0   stevel 		if (len != 1)
    789    0   stevel 			Putchar(')');
    790    0   stevel 		Putchar('\n');
    791    0   stevel 		if (p->v_right) {
    792    0   stevel 			p = p->v_right;
    793    0   stevel 			continue;
    794    0   stevel 		}
    795    0   stevel 		do {
    796    0   stevel 			c = p;
    797    0   stevel 			p = p->v_parent;
    798    0   stevel 		} while (p->v_right == c);
    799    0   stevel 		goto x;
    800    0   stevel 	}
    801    0   stevel }
    802