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