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