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