No empty .Rs/.Re
[netbsd-mini2440.git] / bin / csh / parse.c
blob49c43d37a51af18bd6b439fdd21c9a2daeed1f44
1 /* $NetBSD: parse.c,v 1.16 2007/07/16 14:07:01 christos Exp $ */
3 /*-
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: parse.c,v 1.16 2007/07/16 14:07:01 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include <sys/types.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
47 #include "csh.h"
48 #include "extern.h"
50 static void asyntax(struct wordent *, struct wordent *);
51 static void asyn0(struct wordent *, struct wordent *);
52 static void asyn3(struct wordent *, struct wordent *);
53 static struct wordent *freenod(struct wordent *, struct wordent *);
54 static struct command *syn0(struct wordent *, struct wordent *, int);
55 static struct command *syn1(struct wordent *, struct wordent *, int);
56 static struct command *syn1a(struct wordent *, struct wordent *, int);
57 static struct command *syn1b(struct wordent *, struct wordent *, int);
58 static struct command *syn2(struct wordent *, struct wordent *, int);
59 static struct command *syn3(struct wordent *, struct wordent *, int);
61 #define ALEFT 21 /* max of 20 alias expansions */
62 #define HLEFT 11 /* max of 10 history expansions */
64 * Perform aliasing on the word list lex
65 * Do a (very rudimentary) parse to separate into commands.
66 * If word 0 of a command has an alias, do it.
67 * Repeat a maximum of 20 times.
69 static int aleft;
70 extern int hleft;
72 void
73 alias(struct wordent *lexp)
75 jmp_buf osetexit;
77 aleft = ALEFT;
78 hleft = HLEFT;
79 getexit(osetexit);
80 (void)setexit();
81 if (haderr) {
82 resexit(osetexit);
83 reset();
85 if (--aleft == 0)
86 stderror(ERR_ALIASLOOP);
87 asyntax(lexp->next, lexp);
88 resexit(osetexit);
91 static void
92 asyntax(struct wordent *p1, struct wordent *p2)
94 while (p1 != p2)
95 if (any(";&\n", p1->word[0]))
96 p1 = p1->next;
97 else {
98 asyn0(p1, p2);
99 return;
103 static void
104 asyn0(struct wordent *p1, struct wordent *p2)
106 struct wordent *p;
107 int l;
109 l = 0;
110 for (p = p1; p != p2; p = p->next)
111 switch (p->word[0]) {
112 case '(':
113 l++;
114 continue;
115 case ')':
116 l--;
117 if (l < 0)
118 stderror(ERR_TOOMANYRP);
119 continue;
120 case '>':
121 if (p->next != p2 && eq(p->next->word, STRand))
122 p = p->next;
123 continue;
124 case '&':
125 case '|':
126 case ';':
127 case '\n':
128 if (l != 0)
129 continue;
130 asyn3(p1, p);
131 asyntax(p->next, p2);
132 return;
134 if (l == 0)
135 asyn3(p1, p2);
138 static void
139 asyn3(struct wordent *p1, struct wordent *p2)
141 struct varent *ap;
142 struct wordent alout;
143 int redid;
145 if (p1 == p2)
146 return;
147 if (p1->word[0] == '(') {
148 for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
149 if (p2 == p1)
150 return;
151 if (p2 == p1->next)
152 return;
153 asyn0(p1->next, p2);
154 return;
156 ap = adrof1(p1->word, &aliases);
157 if (ap == 0)
158 return;
159 alhistp = p1->prev;
160 alhistt = p2;
161 alvec = ap->vec;
162 redid = lex(&alout);
163 alhistp = alhistt = 0;
164 alvec = 0;
165 if (seterr) {
166 freelex(&alout);
167 stderror(ERR_OLD);
169 if (p1->word[0] && eq(p1->word, alout.next->word)) {
170 Char *cp;
172 cp = alout.next->word;
173 alout.next->word = Strspl(STRQNULL, cp);
174 xfree((ptr_t) cp);
176 p1 = freenod(p1, redid ? p2 : p1->next);
177 if (alout.next != &alout) {
178 p1->next->prev = alout.prev->prev;
179 alout.prev->prev->next = p1->next;
180 alout.next->prev = p1;
181 p1->next = alout.next;
182 xfree((ptr_t)alout.prev->word);
183 xfree((ptr_t)(alout.prev));
185 reset(); /* throw! */
188 static struct wordent *
189 freenod(struct wordent *p1, struct wordent *p2)
191 struct wordent *retp;
193 retp = p1->prev;
194 while (p1 != p2) {
195 xfree((ptr_t)p1->word);
196 p1 = p1->next;
197 xfree((ptr_t) (p1->prev));
199 retp->next = p2;
200 p2->prev = retp;
201 return (retp);
204 #define PHERE 1
205 #define PIN 2
206 #define POUT 4
207 #define PERR 8
210 * syntax
211 * empty
212 * syn0
214 struct command *
215 syntax(struct wordent *p1, struct wordent *p2, int flags)
217 while (p1 != p2)
218 if (any(";&\n", p1->word[0]))
219 p1 = p1->next;
220 else
221 return (syn0(p1, p2, flags));
222 return (0);
226 * syn0
227 * syn1
228 * syn1 & syntax
230 static struct command *
231 syn0(struct wordent *p1, struct wordent *p2, int flags)
233 struct wordent *p;
234 struct command *t, *t1;
235 int l;
237 l = 0;
238 for (p = p1; p != p2; p = p->next)
239 switch (p->word[0]) {
240 case '(':
241 l++;
242 continue;
243 case ')':
244 l--;
245 if (l < 0)
246 seterror(ERR_TOOMANYRP);
247 continue;
248 case '|':
249 if (p->word[1] == '|')
250 continue;
251 /* FALLTHROUGH */
252 case '>':
253 if (p->next != p2 && eq(p->next->word, STRand))
254 p = p->next;
255 continue;
256 case '&':
257 if (l != 0)
258 break;
259 if (p->word[1] == '&')
260 continue;
261 t1 = syn1(p1, p, flags);
262 if (t1->t_dtyp == NODE_LIST ||
263 t1->t_dtyp == NODE_AND ||
264 t1->t_dtyp == NODE_OR) {
265 t = (struct command *)xcalloc(1, sizeof(*t));
266 t->t_dtyp = NODE_PAREN;
267 t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
268 t->t_dspr = t1;
269 t1 = t;
271 else
272 t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
273 t = (struct command *)xcalloc(1, sizeof(*t));
274 t->t_dtyp = NODE_LIST;
275 t->t_dflg = 0;
276 t->t_dcar = t1;
277 t->t_dcdr = syntax(p, p2, flags);
278 return (t);
280 if (l == 0)
281 return (syn1(p1, p2, flags));
282 seterror(ERR_TOOMANYLP);
283 return (0);
287 * syn1
288 * syn1a
289 * syn1a ; syntax
291 static struct command *
292 syn1(struct wordent *p1, struct wordent *p2, int flags)
294 struct wordent *p;
295 struct command *t;
296 int l;
298 l = 0;
299 for (p = p1; p != p2; p = p->next)
300 switch (p->word[0]) {
301 case '(':
302 l++;
303 continue;
304 case ')':
305 l--;
306 continue;
307 case ';':
308 case '\n':
309 if (l != 0)
310 break;
311 t = (struct command *) xcalloc(1, sizeof(*t));
312 t->t_dtyp = NODE_LIST;
313 t->t_dcar = syn1a(p1, p, flags);
314 t->t_dcdr = syntax(p->next, p2, flags);
315 if (t->t_dcdr == 0)
316 t->t_dcdr = t->t_dcar, t->t_dcar = 0;
317 return (t);
319 return (syn1a(p1, p2, flags));
323 * syn1a
324 * syn1b
325 * syn1b || syn1a
327 static struct command *
328 syn1a(struct wordent *p1, struct wordent *p2, int flags)
330 struct wordent *p;
331 struct command *t;
332 int l;
334 l = 0;
335 for (p = p1; p != p2; p = p->next)
336 switch (p->word[0]) {
337 case '(':
338 l++;
339 continue;
340 case ')':
341 l--;
342 continue;
343 case '|':
344 if (p->word[1] != '|')
345 continue;
346 if (l == 0) {
347 t = (struct command *)xcalloc(1, sizeof(*t));
348 t->t_dtyp = NODE_OR;
349 t->t_dcar = syn1b(p1, p, flags);
350 t->t_dcdr = syn1a(p->next, p2, flags);
351 t->t_dflg = 0;
352 return (t);
354 continue;
356 return (syn1b(p1, p2, flags));
360 * syn1b
361 * syn2
362 * syn2 && syn1b
364 static struct command *
365 syn1b(struct wordent *p1, struct wordent *p2, int flags)
367 struct wordent *p;
368 struct command *t;
369 int l;
371 l = 0;
372 for (p = p1; p != p2; p = p->next)
373 switch (p->word[0]) {
374 case '(':
375 l++;
376 continue;
377 case ')':
378 l--;
379 continue;
380 case '&':
381 if (p->word[1] == '&' && l == 0) {
382 t = (struct command *)xcalloc(1, sizeof(*t));
383 t->t_dtyp = NODE_AND;
384 t->t_dcar = syn2(p1, p, flags);
385 t->t_dcdr = syn1b(p->next, p2, flags);
386 t->t_dflg = 0;
387 return (t);
389 continue;
391 return (syn2(p1, p2, flags));
395 * syn2
396 * syn3
397 * syn3 | syn2
398 * syn3 |& syn2
400 static struct command *
401 syn2(struct wordent *p1, struct wordent *p2, int flags)
403 struct wordent *p, *pn;
404 struct command *t;
405 int f, l;
407 l = 0;
408 for (p = p1; p != p2; p = p->next)
409 switch (p->word[0]) {
410 case '(':
411 l++;
412 continue;
413 case ')':
414 l--;
415 continue;
416 case '|':
417 if (l != 0)
418 continue;
419 t = (struct command *)xcalloc(1, sizeof(*t));
420 f = flags | POUT;
421 pn = p->next;
422 if (pn != p2 && pn->word[0] == '&') {
423 f |= PERR;
424 t->t_dflg |= F_STDERR;
426 t->t_dtyp = NODE_PIPE;
427 t->t_dcar = syn3(p1, p, f);
428 if (pn != p2 && pn->word[0] == '&')
429 p = pn;
430 t->t_dcdr = syn2(p->next, p2, flags | PIN);
431 return (t);
433 return (syn3(p1, p2, flags));
436 static char RELPAR[] = {'<', '>', '(', ')', '\0'};
439 * syn3
440 * ( syn0 ) [ < in ] [ > out ]
441 * word word* [ < in ] [ > out ]
442 * KEYWORD ( word* ) word* [ < in ] [ > out ]
444 * KEYWORD = (@ exit foreach if set switch test while)
446 static struct command *
447 syn3(struct wordent *p1, struct wordent *p2, int flags)
449 struct wordent *lp, *p, *rp;
450 struct command *t;
451 Char **av;
452 int c, l, n;
453 int specp;
455 specp = 0;
456 if (p1 != p2) {
457 p = p1;
458 again:
459 switch (srchx(p->word)) {
460 case T_ELSE:
461 p = p->next;
462 if (p != p2)
463 goto again;
464 break;
465 case T_EXIT:
466 case T_FOREACH:
467 case T_IF:
468 case T_LET:
469 case T_SET:
470 case T_SWITCH:
471 case T_WHILE:
472 specp = 1;
473 break;
476 n = 0;
477 l = 0;
478 for (p = p1; p != p2; p = p->next)
479 switch (p->word[0]) {
480 case '(':
481 if (specp)
482 n++;
483 l++;
484 continue;
485 case ')':
486 if (specp)
487 n++;
488 l--;
489 continue;
490 case '>':
491 case '<':
492 if (l != 0) {
493 if (specp)
494 n++;
495 continue;
497 if (p->next == p2)
498 continue;
499 if (any(RELPAR, p->next->word[0]))
500 continue;
501 n--;
502 continue;
503 default:
504 if (!specp && l != 0)
505 continue;
506 n++;
507 continue;
509 if (n < 0)
510 n = 0;
511 t = (struct command *)xcalloc(1, sizeof(*t));
512 av = (Char **)xcalloc((size_t)(n + 1), sizeof(Char **));
513 t->t_dcom = av;
514 n = 0;
515 if (p2->word[0] == ')')
516 t->t_dflg = F_NOFORK;
517 lp = 0;
518 rp = 0;
519 l = 0;
520 for (p = p1; p != p2; p = p->next) {
521 c = p->word[0];
522 switch (c) {
523 case '(':
524 if (l == 0) {
525 if (lp != 0 && !specp)
526 seterror(ERR_BADPLP);
527 lp = p->next;
529 l++;
530 goto savep;
531 case ')':
532 l--;
533 if (l == 0)
534 rp = p;
535 goto savep;
536 case '>':
537 if (l != 0)
538 goto savep;
539 if (p->word[1] == '>')
540 t->t_dflg |= F_APPEND;
541 if (p->next != p2 && eq(p->next->word, STRand)) {
542 t->t_dflg |= F_STDERR, p = p->next;
543 if (flags & (POUT | PERR)) {
544 seterror(ERR_OUTRED);
545 continue;
548 if (p->next != p2 && eq(p->next->word, STRbang))
549 t->t_dflg |= F_OVERWRITE, p = p->next;
550 if (p->next == p2) {
551 seterror(ERR_MISRED);
552 continue;
554 p = p->next;
555 if (any(RELPAR, p->word[0])) {
556 seterror(ERR_MISRED);
557 continue;
559 if ((flags & POUT) && ((flags & PERR) == 0 || t->t_drit))
560 seterror(ERR_OUTRED);
561 else
562 t->t_drit = Strsave(p->word);
563 continue;
564 case '<':
565 if (l != 0)
566 goto savep;
567 if (p->word[1] == '<')
568 t->t_dflg |= F_READ;
569 if (p->next == p2) {
570 seterror(ERR_MISRED);
571 continue;
573 p = p->next;
574 if (any(RELPAR, p->word[0])) {
575 seterror(ERR_MISRED);
576 continue;
578 if ((flags & PHERE) && (t->t_dflg & F_READ))
579 seterror(ERR_REDPAR);
580 else if ((flags & PIN) || t->t_dlef)
581 seterror(ERR_INRED);
582 else
583 t->t_dlef = Strsave(p->word);
584 continue;
585 savep:
586 if (!specp)
587 continue;
588 /* FALLTHROUGH */
589 default:
590 if (l != 0 && !specp)
591 continue;
592 if (seterr == 0)
593 av[n] = Strsave(p->word);
594 n++;
595 continue;
598 if (lp != 0 && !specp) {
599 if (n != 0)
600 seterror(ERR_BADPLPS);
601 t->t_dtyp = NODE_PAREN;
602 t->t_dspr = syn0(lp, rp, PHERE);
604 else {
605 if (n == 0)
606 seterror(ERR_NULLCOM);
607 t->t_dtyp = NODE_COMMAND;
609 return (t);
612 void
613 freesyn(struct command *t)
615 Char **v;
617 if (t == 0)
618 return;
619 switch (t->t_dtyp) {
620 case NODE_COMMAND:
621 for (v = t->t_dcom; *v; v++)
622 xfree((ptr_t) * v);
623 xfree((ptr_t)(t->t_dcom));
624 xfree((ptr_t)t->t_dlef);
625 xfree((ptr_t)t->t_drit);
626 break;
627 case NODE_PAREN:
628 freesyn(t->t_dspr);
629 xfree((ptr_t)t->t_dlef);
630 xfree((ptr_t)t->t_drit);
631 break;
632 case NODE_AND:
633 case NODE_OR:
634 case NODE_PIPE:
635 case NODE_LIST:
636 freesyn(t->t_dcar), freesyn(t->t_dcdr);
637 break;
639 xfree((ptr_t)t);