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