Home | History | Annotate | Line # | Download | only in csh
set.c revision 1.12
      1 /*	$NetBSD: set.c,v 1.12 1998/07/28 02:47:21 mycroft Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1980, 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 #if 0
     39 static char sccsid[] = "@(#)set.c	8.1 (Berkeley) 5/31/93";
     40 #else
     41 __RCSID("$NetBSD: set.c,v 1.12 1998/07/28 02:47:21 mycroft Exp $");
     42 #endif
     43 #endif /* not lint */
     44 
     45 #include <sys/types.h>
     46 #include <stdlib.h>
     47 #ifndef SHORT_STRINGS
     48 #include <string.h>
     49 #endif /* SHORT_STRINGS */
     50 #if __STDC__
     51 # include <stdarg.h>
     52 #else
     53 # include <varargs.h>
     54 #endif
     55 
     56 #include "csh.h"
     57 #include "extern.h"
     58 
     59 static Char	*getinx __P((Char *, int *));
     60 static void	 asx __P((Char *, int, Char *));
     61 static struct varent
     62 		*getvx __P((Char *, int));
     63 static Char	*xset __P((Char *, Char ***));
     64 static Char	*operate __P((int, Char *, Char *));
     65 static void	 putn1 __P((int));
     66 static struct varent
     67 		*madrof __P((Char *, struct varent *));
     68 static void	 unsetv1 __P((struct varent *));
     69 static void	 exportpath __P((Char **));
     70 static void	 balance __P((struct varent *, int, int));
     71 
     72 
     73 /*
     74  * C Shell
     75  */
     76 
     77 void
     78 /*ARGSUSED*/
     79 doset(v, t)
     80     Char **v;
     81     struct command *t;
     82 {
     83     Char *p;
     84     Char   *vp, op;
     85     Char  **vecp;
     86     bool    hadsub;
     87     int     subscr;
     88 
     89     v++;
     90     p = *v++;
     91     if (p == 0) {
     92 	prvars();
     93 	return;
     94     }
     95     do {
     96 	hadsub = 0;
     97 	vp = p;
     98 	if (letter(*p))
     99 	    for (; alnum(*p); p++)
    100 		continue;
    101 	if (vp == p || !letter(*vp)) {
    102 	    stderror(ERR_NAME | ERR_VARBEGIN);
    103 	    /* NOTREACHED */
    104 	}
    105 	if ((p - vp) > MAXVARLEN) {
    106 	    stderror(ERR_NAME | ERR_VARTOOLONG);
    107 	    /* NOTREACHED */
    108 	}
    109 	if (*p == '[') {
    110 	    hadsub++;
    111 	    p = getinx(p, &subscr);
    112 	}
    113 	if ((op = *p) != '\0') {
    114 	    *p++ = 0;
    115 	    if (*p == 0 && *v && **v == '(')
    116 		p = *v++;
    117 	}
    118 	else if (*v && eq(*v, STRequal)) {
    119 	    op = '=', v++;
    120 	    if (*v)
    121 		p = *v++;
    122 	}
    123 	if (op && op != '=') {
    124 	    stderror(ERR_NAME | ERR_SYNTAX);
    125 	    /* NOTREACHED */
    126 	}
    127 	if (eq(p, STRLparen)) {
    128 	    Char **e = v;
    129 
    130 	    if (hadsub) {
    131 		stderror(ERR_NAME | ERR_SYNTAX);
    132 		/* NOTREACHED */
    133 	    }
    134 	    for (;;) {
    135 		if (!*e) {
    136 		    stderror(ERR_NAME | ERR_MISSING, ')');
    137 		    /* NOTREACHED */
    138 		}
    139 		if (**e == ')')
    140 		    break;
    141 		e++;
    142 	    }
    143 	    p = *e;
    144 	    *e = 0;
    145 	    vecp = saveblk(v);
    146 	    set1(vp, vecp, &shvhed);
    147 	    *e = p;
    148 	    v = e + 1;
    149 	}
    150 	else if (hadsub)
    151 	    asx(vp, subscr, Strsave(p));
    152 	else
    153 	    set(vp, Strsave(p));
    154 	if (eq(vp, STRpath)) {
    155 	    exportpath(adrof(STRpath)->vec);
    156 	    dohash(NULL, NULL);
    157 	}
    158 	else if (eq(vp, STRhistchars)) {
    159 	    Char *pn = value(STRhistchars);
    160 
    161 	    HIST = *pn++;
    162 	    HISTSUB = *pn;
    163 	}
    164 	else if (eq(vp, STRuser)) {
    165 	    Setenv(STRUSER, value(vp));
    166 	    Setenv(STRLOGNAME, value(vp));
    167 	}
    168 	else if (eq(vp, STRwordchars)) {
    169 	    word_chars = value(vp);
    170 	}
    171 	else if (eq(vp, STRterm))
    172 	    Setenv(STRTERM, value(vp));
    173 	else if (eq(vp, STRhome)) {
    174 	    Char *cp;
    175 
    176 	    cp = Strsave(value(vp));	/* get the old value back */
    177 
    178 	    /*
    179 	     * convert to cononical pathname (possibly resolving symlinks)
    180 	     */
    181 	    cp = dcanon(cp, cp);
    182 
    183 	    set(vp, Strsave(cp));	/* have to save the new val */
    184 
    185 	    /* and now mirror home with HOME */
    186 	    Setenv(STRHOME, cp);
    187 	    /* fix directory stack for new tilde home */
    188 	    dtilde();
    189 	    xfree((ptr_t) cp);
    190 	}
    191 #ifdef FILEC
    192 	else if (eq(vp, STRfilec))
    193 	    filec = 1;
    194 #endif
    195     } while ((p = *v++) != NULL);
    196 }
    197 
    198 static Char *
    199 getinx(cp, ip)
    200     Char *cp;
    201     int *ip;
    202 {
    203 
    204     *ip = 0;
    205     *cp++ = 0;
    206     while (*cp && Isdigit(*cp))
    207 	*ip = *ip * 10 + *cp++ - '0';
    208     if (*cp++ != ']') {
    209 	stderror(ERR_NAME | ERR_SUBSCRIPT);
    210 	/* NOTREACHED */
    211     }
    212     return (cp);
    213 }
    214 
    215 static void
    216 asx(vp, subscr, p)
    217     Char   *vp;
    218     int     subscr;
    219     Char   *p;
    220 {
    221     struct varent *v = getvx(vp, subscr);
    222 
    223     xfree((ptr_t) v->vec[subscr - 1]);
    224     v->vec[subscr - 1] = globone(p, G_APPEND);
    225 }
    226 
    227 static struct varent *
    228 getvx(vp, subscr)
    229     Char   *vp;
    230     int     subscr;
    231 {
    232     struct varent *v = adrof(vp);
    233 
    234     if (v == 0)
    235 	udvar(vp);
    236     if (subscr < 1 || subscr > blklen(v->vec)) {
    237 	stderror(ERR_NAME | ERR_RANGE);
    238 	/* NOTREACHED */
    239     }
    240     return (v);
    241 }
    242 
    243 void
    244 /*ARGSUSED*/
    245 dolet(v, t)
    246     Char **v;
    247     struct command *t;
    248 {
    249     Char *p;
    250     Char   *vp, c, op;
    251     bool    hadsub;
    252     int     subscr;
    253 
    254     v++;
    255     p = *v++;
    256     if (p == 0) {
    257 	prvars();
    258 	return;
    259     }
    260     do {
    261 	hadsub = 0;
    262 	vp = p;
    263 	if (letter(*p))
    264 	    for (; alnum(*p); p++)
    265 		continue;
    266 	if (vp == p || !letter(*vp)) {
    267 	    stderror(ERR_NAME | ERR_VARBEGIN);
    268 	    /* NOTREACHED */
    269 	}
    270 	if ((p - vp) > MAXVARLEN) {
    271 	    stderror(ERR_NAME | ERR_VARTOOLONG);
    272 	    /* NOTREACHED */
    273 	}
    274 	if (*p == '[') {
    275 	    hadsub++;
    276 	    p = getinx(p, &subscr);
    277 	}
    278 	if (*p == 0 && *v)
    279 	    p = *v++;
    280 	if ((op = *p) != '\0')
    281 	    *p++ = 0;
    282 	else {
    283 	    stderror(ERR_NAME | ERR_ASSIGN);
    284 	    /* NOTREACHED */
    285 	}
    286 
    287 	if (*p == '\0' && *v == NULL) {
    288 	    stderror(ERR_NAME | ERR_ASSIGN);
    289 	    /* NOTREACHED */
    290 	}
    291 
    292 	vp = Strsave(vp);
    293 	if (op == '=') {
    294 	    c = '=';
    295 	    p = xset(p, &v);
    296 	}
    297 	else {
    298 	    c = *p++;
    299 	    if (any("+-", c)) {
    300 		if (c != op || *p) {
    301 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
    302 		    /* NOTREACHED */
    303 		}
    304 		p = Strsave(STR1);
    305 	    }
    306 	    else {
    307 		if (any("<>", op)) {
    308 		    if (c != op) {
    309 			stderror(ERR_NAME | ERR_UNKNOWNOP);
    310 			/* NOTREACHED */
    311 		    }
    312 		    c = *p++;
    313 		    stderror(ERR_NAME | ERR_SYNTAX);
    314 		}
    315 		if (c != '=')
    316 		    stderror(ERR_NAME | ERR_UNKNOWNOP);
    317 		/* NOTREACHED */
    318 		p = xset(p, &v);
    319 	    }
    320 	}
    321 	if (op == '=')
    322 	    if (hadsub)
    323 		asx(vp, subscr, p);
    324 	    else
    325 		set(vp, p);
    326 	else if (hadsub) {
    327 	    struct varent *gv = getvx(vp, subscr);
    328 
    329 	    asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
    330 	}
    331 	else
    332 	    set(vp, operate(op, value(vp), p));
    333 	if (eq(vp, STRpath)) {
    334 	    exportpath(adrof(STRpath)->vec);
    335 	    dohash(NULL, NULL);
    336 	}
    337 	xfree((ptr_t) vp);
    338 	if (c != '=')
    339 	    xfree((ptr_t) p);
    340     } while ((p = *v++) != NULL);
    341 }
    342 
    343 static Char *
    344 xset(cp, vp)
    345     Char   *cp, ***vp;
    346 {
    347     Char *dp;
    348 
    349     if (*cp) {
    350 	dp = Strsave(cp);
    351 	--(*vp);
    352 	xfree((ptr_t) ** vp);
    353 	**vp = dp;
    354     }
    355     return (putn(expr(vp)));
    356 }
    357 
    358 static Char *
    359 operate(op, vp, p)
    360     int    op;
    361     Char  *vp, *p;
    362 {
    363     Char    opr[2];
    364     Char   *vec[5];
    365     Char **v = vec;
    366     Char  **vecp = v;
    367     int i;
    368 
    369     if (op != '=') {
    370 	if (*vp)
    371 	    *v++ = vp;
    372 	opr[0] = op;
    373 	opr[1] = 0;
    374 	*v++ = opr;
    375 	if (op == '<' || op == '>')
    376 	    *v++ = opr;
    377     }
    378     *v++ = p;
    379     *v++ = 0;
    380     i = expr(&vecp);
    381     if (*vecp) {
    382 	stderror(ERR_NAME | ERR_EXPRESSION);
    383 	/* NOTREACHED */
    384     }
    385     return (putn(i));
    386 }
    387 
    388 static Char *putp;
    389 
    390 Char   *
    391 putn(n)
    392     int n;
    393 {
    394     int     num;
    395     static Char number[15];
    396 
    397     putp = number;
    398     if (n < 0) {
    399 	n = -n;
    400 	*putp++ = '-';
    401     }
    402     num = 2;			/* confuse lint */
    403     if (sizeof(int) == num && ((unsigned int) n) == 0x8000) {
    404 	*putp++ = '3';
    405 	n = 2768;
    406 #ifdef pdp11
    407     }
    408 #else
    409     }
    410     else {
    411 	num = 4;		/* confuse lint */
    412 	if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) {
    413 	    *putp++ = '2';
    414 	    n = 147483648;
    415 	}
    416     }
    417 #endif
    418     putn1(n);
    419     *putp = 0;
    420     return (Strsave(number));
    421 }
    422 
    423 static void
    424 putn1(n)
    425     int n;
    426 {
    427     if (n > 9)
    428 	putn1(n / 10);
    429     *putp++ = n % 10 + '0';
    430 }
    431 
    432 int
    433 getn(cp)
    434     Char *cp;
    435 {
    436     int n;
    437     int     sign;
    438 
    439     sign = 0;
    440     if (cp[0] == '+' && cp[1])
    441 	cp++;
    442     if (*cp == '-') {
    443 	sign++;
    444 	cp++;
    445 	if (!Isdigit(*cp)) {
    446 	    stderror(ERR_NAME | ERR_BADNUM);
    447 	    /* NOTREACHED */
    448 	}
    449     }
    450     n = 0;
    451     while (Isdigit(*cp))
    452 	n = n * 10 + *cp++ - '0';
    453     if (*cp) {
    454 	stderror(ERR_NAME | ERR_BADNUM);
    455 	/* NOTREACHED */
    456     }
    457     return (sign ? -n : n);
    458 }
    459 
    460 Char   *
    461 value1(var, head)
    462     Char   *var;
    463     struct varent *head;
    464 {
    465     struct varent *vp;
    466 
    467     vp = adrof1(var, head);
    468     return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
    469 }
    470 
    471 static struct varent *
    472 madrof(pat, vp)
    473     Char   *pat;
    474     struct varent *vp;
    475 {
    476     struct varent *vp1;
    477 
    478     for (; vp; vp = vp->v_right) {
    479 	if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
    480 	    return vp1;
    481 	if (Gmatch(vp->v_name, pat))
    482 	    return vp;
    483     }
    484     return vp;
    485 }
    486 
    487 struct varent *
    488 adrof1(name, v)
    489     Char *name;
    490     struct varent *v;
    491 {
    492     int cmp;
    493 
    494     v = v->v_left;
    495     while (v && ((cmp = *name - *v->v_name) ||
    496 		 (cmp = Strcmp(name, v->v_name))))
    497 	if (cmp < 0)
    498 	    v = v->v_left;
    499 	else
    500 	    v = v->v_right;
    501     return v;
    502 }
    503 
    504 /*
    505  * The caller is responsible for putting value in a safe place
    506  */
    507 void
    508 set(var, val)
    509     Char   *var, *val;
    510 {
    511     Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
    512 
    513     vec[0] = val;
    514     vec[1] = 0;
    515     set1(var, vec, &shvhed);
    516 }
    517 
    518 void
    519 set1(var, vec, head)
    520     Char   *var, **vec;
    521     struct varent *head;
    522 {
    523     Char **oldv = vec;
    524 
    525     gflag = 0;
    526     tglob(oldv);
    527     if (gflag) {
    528 	vec = globall(oldv);
    529 	if (vec == 0) {
    530 	    blkfree(oldv);
    531 	    stderror(ERR_NAME | ERR_NOMATCH);
    532 	    /* NOTREACHED */
    533 	}
    534 	blkfree(oldv);
    535 	gargv = 0;
    536     }
    537     setq(var, vec, head);
    538 }
    539 
    540 
    541 void
    542 setq(name, vec, p)
    543     Char   *name, **vec;
    544     struct varent *p;
    545 {
    546     struct varent *c;
    547     int f;
    548 
    549     f = 0;			/* tree hangs off the header's left link */
    550     while ((c = p->v_link[f]) != NULL) {
    551 	if ((f = *name - *c->v_name) == 0 &&
    552 	    (f = Strcmp(name, c->v_name)) == 0) {
    553 	    blkfree(c->vec);
    554 	    goto found;
    555 	}
    556 	p = c;
    557 	f = f > 0;
    558     }
    559     p->v_link[f] = c = (struct varent *) xmalloc((size_t) sizeof(struct varent));
    560     c->v_name = Strsave(name);
    561     c->v_bal = 0;
    562     c->v_left = c->v_right = 0;
    563     c->v_parent = p;
    564     balance(p, f, 0);
    565 found:
    566     trim(c->vec = vec);
    567 }
    568 
    569 void
    570 /*ARGSUSED*/
    571 unset(v, t)
    572     Char **v;
    573     struct command *t;
    574 {
    575     unset1(v, &shvhed);
    576 #ifdef FILEC
    577     if (adrof(STRfilec) == 0)
    578 	filec = 0;
    579 #endif
    580     if (adrof(STRhistchars) == 0) {
    581 	HIST = '!';
    582 	HISTSUB = '^';
    583     }
    584     if (adrof(STRwordchars) == 0)
    585 	word_chars = STR_WORD_CHARS;
    586 }
    587 
    588 void
    589 unset1(v, head)
    590     Char *v[];
    591     struct varent *head;
    592 {
    593     struct varent *vp;
    594     int cnt;
    595 
    596     while (*++v) {
    597 	cnt = 0;
    598 	while ((vp = madrof(*v, head->v_left)) != NULL)
    599 	    unsetv1(vp), cnt++;
    600 	if (cnt == 0)
    601 	    setname(vis_str(*v));
    602     }
    603 }
    604 
    605 void
    606 unsetv(var)
    607     Char   *var;
    608 {
    609     struct varent *vp;
    610 
    611     if ((vp = adrof1(var, &shvhed)) == 0)
    612 	udvar(var);
    613     unsetv1(vp);
    614 }
    615 
    616 static void
    617 unsetv1(p)
    618     struct varent *p;
    619 {
    620     struct varent *c, *pp;
    621     int f;
    622 
    623     /*
    624      * Free associated memory first to avoid complications.
    625      */
    626     blkfree(p->vec);
    627     xfree((ptr_t) p->v_name);
    628     /*
    629      * If p is missing one child, then we can move the other into where p is.
    630      * Otherwise, we find the predecessor of p, which is guaranteed to have no
    631      * right child, copy it into p, and move it's left child into it.
    632      */
    633     if (p->v_right == 0)
    634 	c = p->v_left;
    635     else if (p->v_left == 0)
    636 	c = p->v_right;
    637     else {
    638 	for (c = p->v_left; c->v_right; c = c->v_right)
    639 	    continue;
    640 	p->v_name = c->v_name;
    641 	p->vec = c->vec;
    642 	p = c;
    643 	c = p->v_left;
    644     }
    645     /*
    646      * Move c into where p is.
    647      */
    648     pp = p->v_parent;
    649     f = pp->v_right == p;
    650     if ((pp->v_link[f] = c) != NULL)
    651 	c->v_parent = pp;
    652     /*
    653      * Free the deleted node, and rebalance.
    654      */
    655     xfree((ptr_t) p);
    656     balance(pp, f, 1);
    657 }
    658 
    659 void
    660 setNS(cp)
    661     Char   *cp;
    662 {
    663     set(cp, Strsave(STRNULL));
    664 }
    665 
    666 void
    667 /*ARGSUSED*/
    668 shift(v, t)
    669     Char **v;
    670     struct command *t;
    671 {
    672     struct varent *argv;
    673     Char *name;
    674 
    675     v++;
    676     name = *v;
    677     if (name == 0)
    678 	name = STRargv;
    679     else
    680 	(void) strip(name);
    681     argv = adrof(name);
    682     if (argv == 0)
    683 	udvar(name);
    684     if (argv->vec[0] == 0) {
    685 	stderror(ERR_NAME | ERR_NOMORE);
    686 	/* NOTREACHED */
    687     }
    688     lshift(argv->vec, 1);
    689 }
    690 
    691 static void
    692 exportpath(val)
    693     Char  **val;
    694 {
    695     Char    exppath[BUFSIZ];
    696 
    697     exppath[0] = 0;
    698     if (val)
    699 	while (*val) {
    700 	    if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) {
    701 		(void) fprintf(csherr,
    702 			       "Warning: ridiculously long PATH truncated\n");
    703 		break;
    704 	    }
    705 	    (void) Strcat(exppath, *val++);
    706 	    if (*val == 0 || eq(*val, STRRparen))
    707 		break;
    708 	    (void) Strcat(exppath, STRcolon);
    709 	}
    710     Setenv(STRPATH, exppath);
    711 }
    712 
    713 #ifndef lint
    714  /*
    715   * Lint thinks these have null effect
    716   */
    717  /* macros to do single rotations on node p */
    718 #define rright(p) (\
    719 	t = (p)->v_left,\
    720 	(t)->v_parent = (p)->v_parent,\
    721 	((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
    722 	(t->v_right = (p))->v_parent = t,\
    723 	(p) = t)
    724 #define rleft(p) (\
    725 	t = (p)->v_right,\
    726 	(t)->v_parent = (p)->v_parent,\
    727 	((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
    728 	(t->v_left = (p))->v_parent = t,\
    729 	(p) = t)
    730 #else
    731 struct varent *
    732 rleft(p)
    733     struct varent *p;
    734 {
    735     return (p);
    736 }
    737 struct varent *
    738 rright(p)
    739     struct varent *p;
    740 {
    741     return (p);
    742 }
    743 
    744 #endif				/* ! lint */
    745 
    746 
    747 /*
    748  * Rebalance a tree, starting at p and up.
    749  * F == 0 means we've come from p's left child.
    750  * D == 1 means we've just done a delete, otherwise an insert.
    751  */
    752 static void
    753 balance(p, f, d)
    754     struct varent *p;
    755     int f, d;
    756 {
    757     struct varent *pp;
    758 
    759 #ifndef lint
    760     struct varent *t;	/* used by the rotate macros */
    761 
    762 #endif
    763     int ff;
    764 
    765     /*
    766      * Ok, from here on, p is the node we're operating on; pp is it's parent; f
    767      * is the branch of p from which we have come; ff is the branch of pp which
    768      * is p.
    769      */
    770     for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
    771 	ff = pp->v_right == p;
    772 	if (f ^ d) {		/* right heavy */
    773 	    switch (p->v_bal) {
    774 	    case -1:		/* was left heavy */
    775 		p->v_bal = 0;
    776 		break;
    777 	    case 0:		/* was balanced */
    778 		p->v_bal = 1;
    779 		break;
    780 	    case 1:		/* was already right heavy */
    781 		switch (p->v_right->v_bal) {
    782 		case 1:	/* sigle rotate */
    783 		    pp->v_link[ff] = rleft(p);
    784 		    p->v_left->v_bal = 0;
    785 		    p->v_bal = 0;
    786 		    break;
    787 		case 0:	/* single rotate */
    788 		    pp->v_link[ff] = rleft(p);
    789 		    p->v_left->v_bal = 1;
    790 		    p->v_bal = -1;
    791 		    break;
    792 		case -1:	/* double rotate */
    793 		    (void) rright(p->v_right);
    794 		    pp->v_link[ff] = rleft(p);
    795 		    p->v_left->v_bal =
    796 			p->v_bal < 1 ? 0 : -1;
    797 		    p->v_right->v_bal =
    798 			p->v_bal > -1 ? 0 : 1;
    799 		    p->v_bal = 0;
    800 		    break;
    801 		}
    802 		break;
    803 	    }
    804 	}
    805 	else {			/* left heavy */
    806 	    switch (p->v_bal) {
    807 	    case 1:		/* was right heavy */
    808 		p->v_bal = 0;
    809 		break;
    810 	    case 0:		/* was balanced */
    811 		p->v_bal = -1;
    812 		break;
    813 	    case -1:		/* was already left heavy */
    814 		switch (p->v_left->v_bal) {
    815 		case -1:	/* single rotate */
    816 		    pp->v_link[ff] = rright(p);
    817 		    p->v_right->v_bal = 0;
    818 		    p->v_bal = 0;
    819 		    break;
    820 		case 0:	/* signle rotate */
    821 		    pp->v_link[ff] = rright(p);
    822 		    p->v_right->v_bal = -1;
    823 		    p->v_bal = 1;
    824 		    break;
    825 		case 1:	/* double rotate */
    826 		    (void) rleft(p->v_left);
    827 		    pp->v_link[ff] = rright(p);
    828 		    p->v_left->v_bal =
    829 			p->v_bal < 1 ? 0 : -1;
    830 		    p->v_right->v_bal =
    831 			p->v_bal > -1 ? 0 : 1;
    832 		    p->v_bal = 0;
    833 		    break;
    834 		}
    835 		break;
    836 	    }
    837 	}
    838 	/*
    839 	 * If from insert, then we terminate when p is balanced. If from
    840 	 * delete, then we terminate when p is unbalanced.
    841 	 */
    842 	if ((p->v_bal == 0) ^ d)
    843 	    break;
    844     }
    845 }
    846 
    847 void
    848 plist(p)
    849     struct varent *p;
    850 {
    851     struct varent *c;
    852     int len;
    853     sigset_t sigset;
    854 
    855     if (setintr) {
    856 	sigemptyset(&sigset);
    857 	(void) sigaddset(&sigset, SIGINT);
    858 	(void) sigprocmask(SIG_UNBLOCK, &sigset, NULL);
    859     }
    860 
    861     for (;;) {
    862 	while (p->v_left)
    863 	    p = p->v_left;
    864 x:
    865 	if (p->v_parent == 0)	/* is it the header? */
    866 	    return;
    867 	len = blklen(p->vec);
    868 	(void) fprintf(cshout, "%s\t", short2str(p->v_name));
    869 	if (len != 1)
    870 	    (void) fputc('(', cshout);
    871 	blkpr(cshout, p->vec);
    872 	if (len != 1)
    873 	    (void) fputc(')', cshout);
    874 	(void) fputc('\n', cshout);
    875 	if (p->v_right) {
    876 	    p = p->v_right;
    877 	    continue;
    878 	}
    879 	do {
    880 	    c = p;
    881 	    p = p->v_parent;
    882 	} while (p->v_right == c);
    883 	goto x;
    884     }
    885 }
    886