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