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