xref: /netbsd-src/bin/csh/set.c (revision 53d1339bf7f9c7367b35a9e1ebe693f9b047a47b)
1 /* $NetBSD: set.c,v 1.37 2020/01/12 18:42:41 christos 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.37 2020/01/12 18:42:41 christos 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