386BSD 0.1 development
[unix-history] / usr / src / bin / csh / parse.c
CommitLineData
5a9d2163
WJ
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
35static char sccsid[] = "@(#)parse.c 5.11 (Berkeley) 6/8/91";
36#endif /* not lint */
37
38#include <sys/types.h>
39#include <stdlib.h>
40#include <string.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
50static void asyntax __P((struct wordent *, struct wordent *));
51static void asyn0 __P((struct wordent *, struct wordent *));
52static void asyn3 __P((struct wordent *, struct wordent *));
53static struct wordent
54 *freenod __P((struct wordent *, struct wordent *));
55static struct command
56 *syn0 __P((struct wordent *, struct wordent *, int));
57static struct command
58 *syn1 __P((struct wordent *, struct wordent *, int));
59static struct command
60 *syn1a __P((struct wordent *, struct wordent *, int));
61static struct command
62 *syn1b __P((struct wordent *, struct wordent *, int));
63static struct command
64 *syn2 __P((struct wordent *, struct wordent *, int));
65static struct command
66 *syn3 __P((struct wordent *, struct wordent *, int));
67
68#define ALEFT 21 /* max of 20 alias expansions */
69#define HLEFT 11 /* max of 10 history expansions */
70/*
71 * Perform aliasing on the word list lex
72 * Do a (very rudimentary) parse to separate into commands.
73 * If word 0 of a command has an alias, do it.
74 * Repeat a maximum of 20 times.
75 */
76static int aleft;
77extern int hleft;
78void
79alias(lex)
80 register struct wordent *lex;
81{
82 jmp_buf osetexit;
83
84 aleft = ALEFT;
85 hleft = HLEFT;
86 getexit(osetexit);
87 (void) setexit();
88 if (haderr) {
89 resexit(osetexit);
90 reset();
91 }
92 if (--aleft == 0)
93 stderror(ERR_ALIASLOOP);
94 asyntax(lex->next, lex);
95 resexit(osetexit);
96}
97
98static void
99asyntax(p1, p2)
100 register struct wordent *p1, *p2;
101{
102 while (p1 != p2)
103 if (any(";&\n", p1->word[0]))
104 p1 = p1->next;
105 else {
106 asyn0(p1, p2);
107 return;
108 }
109}
110
111static void
112asyn0(p1, p2)
113 struct wordent *p1;
114 register struct wordent *p2;
115{
116 register struct wordent *p;
117 register int l = 0;
118
119 for (p = p1; p != p2; p = p->next)
120 switch (p->word[0]) {
121
122 case '(':
123 l++;
124 continue;
125
126 case ')':
127 l--;
128 if (l < 0)
129 stderror(ERR_TOOMANYRP);
130 continue;
131
132 case '>':
133 if (p->next != p2 && eq(p->next->word, STRand))
134 p = p->next;
135 continue;
136
137 case '&':
138 case '|':
139 case ';':
140 case '\n':
141 if (l != 0)
142 continue;
143 asyn3(p1, p);
144 asyntax(p->next, p2);
145 return;
146 }
147 if (l == 0)
148 asyn3(p1, p2);
149}
150
151static void
152asyn3(p1, p2)
153 struct wordent *p1;
154 register struct wordent *p2;
155{
156 register struct varent *ap;
157 struct wordent alout;
158 register bool redid;
159
160 if (p1 == p2)
161 return;
162 if (p1->word[0] == '(') {
163 for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
164 if (p2 == p1)
165 return;
166 if (p2 == p1->next)
167 return;
168 asyn0(p1->next, p2);
169 return;
170 }
171 ap = adrof1(p1->word, &aliases);
172 if (ap == 0)
173 return;
174 alhistp = p1->prev;
175 alhistt = p2;
176 alvec = ap->vec;
177 redid = lex(&alout);
178 alhistp = alhistt = 0;
179 alvec = 0;
180 if (seterr) {
181 freelex(&alout);
182 stderror(ERR_OLD);
183 }
184 if (p1->word[0] && eq(p1->word, alout.next->word)) {
185 Char *cp = alout.next->word;
186
187 alout.next->word = Strspl(STRQNULL, cp);
188 xfree((ptr_t) cp);
189 }
190 p1 = freenod(p1, redid ? p2 : p1->next);
191 if (alout.next != &alout) {
192 p1->next->prev = alout.prev->prev;
193 alout.prev->prev->next = p1->next;
194 alout.next->prev = p1;
195 p1->next = alout.next;
196 xfree((ptr_t) alout.prev->word);
197 xfree((ptr_t) (alout.prev));
198 }
199 reset(); /* throw! */
200}
201
202static struct wordent *
203freenod(p1, p2)
204 register struct wordent *p1, *p2;
205{
206 register struct wordent *retp = p1->prev;
207
208 while (p1 != p2) {
209 xfree((ptr_t) p1->word);
210 p1 = p1->next;
211 xfree((ptr_t) (p1->prev));
212 }
213 retp->next = p2;
214 p2->prev = retp;
215 return (retp);
216}
217
218#define PHERE 1
219#define PIN 2
220#define POUT 4
221#define PDIAG 8
222
223/*
224 * syntax
225 * empty
226 * syn0
227 */
228struct command *
229syntax(p1, p2, flags)
230 register struct wordent *p1, *p2;
231 int flags;
232{
233
234 while (p1 != p2)
235 if (any(";&\n", p1->word[0]))
236 p1 = p1->next;
237 else
238 return (syn0(p1, p2, flags));
239 return (0);
240}
241
242/*
243 * syn0
244 * syn1
245 * syn1 & syntax
246 */
247static struct command *
248syn0(p1, p2, flags)
249 struct wordent *p1, *p2;
250 int flags;
251{
252 register struct wordent *p;
253 register struct command *t, *t1;
254 int l;
255
256 l = 0;
257 for (p = p1; p != p2; p = p->next)
258 switch (p->word[0]) {
259
260 case '(':
261 l++;
262 continue;
263
264 case ')':
265 l--;
266 if (l < 0)
267 seterror(ERR_TOOMANYRP);
268 continue;
269
270 case '|':
271 if (p->word[1] == '|')
272 continue;
273 /* fall into ... */
274
275 case '>':
276 if (p->next != p2 && eq(p->next->word, STRand))
277 p = p->next;
278 continue;
279
280 case '&':
281 if (l != 0)
282 break;
283 if (p->word[1] == '&')
284 continue;
285 t1 = syn1(p1, p, flags);
286 if (t1->t_dtyp == NODE_LIST ||
287 t1->t_dtyp == NODE_AND ||
288 t1->t_dtyp == NODE_OR) {
289 t = (struct command *) xcalloc(1, sizeof(*t));
290 t->t_dtyp = NODE_PAREN;
291 t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
292 t->t_dspr = t1;
293 t1 = t;
294 }
295 else
296 t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
297 t = (struct command *) xcalloc(1, sizeof(*t));
298 t->t_dtyp = NODE_LIST;
299 t->t_dflg = 0;
300 t->t_dcar = t1;
301 t->t_dcdr = syntax(p, p2, flags);
302 return (t);
303 }
304 if (l == 0)
305 return (syn1(p1, p2, flags));
306 seterror(ERR_TOOMANYLP);
307 return (0);
308}
309
310/*
311 * syn1
312 * syn1a
313 * syn1a ; syntax
314 */
315static struct command *
316syn1(p1, p2, flags)
317 struct wordent *p1, *p2;
318 int flags;
319{
320 register struct wordent *p;
321 register struct command *t;
322 int l;
323
324 l = 0;
325 for (p = p1; p != p2; p = p->next)
326 switch (p->word[0]) {
327
328 case '(':
329 l++;
330 continue;
331
332 case ')':
333 l--;
334 continue;
335
336 case ';':
337 case '\n':
338 if (l != 0)
339 break;
340 t = (struct command *) xcalloc(1, sizeof(*t));
341 t->t_dtyp = NODE_LIST;
342 t->t_dcar = syn1a(p1, p, flags);
343 t->t_dcdr = syntax(p->next, p2, flags);
344 if (t->t_dcdr == 0)
345 t->t_dcdr = t->t_dcar, t->t_dcar = 0;
346 return (t);
347 }
348 return (syn1a(p1, p2, flags));
349}
350
351/*
352 * syn1a
353 * syn1b
354 * syn1b || syn1a
355 */
356static struct command *
357syn1a(p1, p2, flags)
358 struct wordent *p1, *p2;
359 int flags;
360{
361 register struct wordent *p;
362 register struct command *t;
363 register int l = 0;
364
365 for (p = p1; p != p2; p = p->next)
366 switch (p->word[0]) {
367
368 case '(':
369 l++;
370 continue;
371
372 case ')':
373 l--;
374 continue;
375
376 case '|':
377 if (p->word[1] != '|')
378 continue;
379 if (l == 0) {
380 t = (struct command *) xcalloc(1, sizeof(*t));
381 t->t_dtyp = NODE_OR;
382 t->t_dcar = syn1b(p1, p, flags);
383 t->t_dcdr = syn1a(p->next, p2, flags);
384 t->t_dflg = 0;
385 return (t);
386 }
387 continue;
388 }
389 return (syn1b(p1, p2, flags));
390}
391
392/*
393 * syn1b
394 * syn2
395 * syn2 && syn1b
396 */
397static struct command *
398syn1b(p1, p2, flags)
399 struct wordent *p1, *p2;
400 int flags;
401{
402 register struct wordent *p;
403 register struct command *t;
404 register int l = 0;
405
406 for (p = p1; p != p2; p = p->next)
407 switch (p->word[0]) {
408
409 case '(':
410 l++;
411 continue;
412
413 case ')':
414 l--;
415 continue;
416
417 case '&':
418 if (p->word[1] == '&' && l == 0) {
419 t = (struct command *) xcalloc(1, sizeof(*t));
420 t->t_dtyp = NODE_AND;
421 t->t_dcar = syn2(p1, p, flags);
422 t->t_dcdr = syn1b(p->next, p2, flags);
423 t->t_dflg = 0;
424 return (t);
425 }
426 continue;
427 }
428 return (syn2(p1, p2, flags));
429}
430
431/*
432 * syn2
433 * syn3
434 * syn3 | syn2
435 * syn3 |& syn2
436 */
437static struct command *
438syn2(p1, p2, flags)
439 struct wordent *p1, *p2;
440 int flags;
441{
442 register struct wordent *p, *pn;
443 register struct command *t;
444 register int l = 0;
445 int f;
446
447 for (p = p1; p != p2; p = p->next)
448 switch (p->word[0]) {
449
450 case '(':
451 l++;
452 continue;
453
454 case ')':
455 l--;
456 continue;
457
458 case '|':
459 if (l != 0)
460 continue;
461 t = (struct command *) xcalloc(1, sizeof(*t));
462 f = flags | POUT;
463 pn = p->next;
464 if (pn != p2 && pn->word[0] == '&') {
465 f |= PDIAG;
466 t->t_dflg |= F_STDERR;
467 }
468 t->t_dtyp = NODE_PIPE;
469 t->t_dcar = syn3(p1, p, f);
470 if (pn != p2 && pn->word[0] == '&')
471 p = pn;
472 t->t_dcdr = syn2(p->next, p2, flags | PIN);
473 return (t);
474 }
475 return (syn3(p1, p2, flags));
476}
477
478static char RELPAR[] = {'<', '>', '(', ')', '\0'};
479
480/*
481 * syn3
482 * ( syn0 ) [ < in ] [ > out ]
483 * word word* [ < in ] [ > out ]
484 * KEYWORD ( word* ) word* [ < in ] [ > out ]
485 *
486 * KEYWORD = (@ exit foreach if set switch test while)
487 */
488static struct command *
489syn3(p1, p2, flags)
490 struct wordent *p1, *p2;
491 int flags;
492{
493 register struct wordent *p;
494 struct wordent *lp, *rp;
495 register struct command *t;
496 register int l;
497 Char **av;
498 int n, c;
499 bool specp = 0;
500
501 if (p1 != p2) {
502 p = p1;
503again:
504 switch (srchx(p->word)) {
505
506 case T_ELSE:
507 p = p->next;
508 if (p != p2)
509 goto again;
510 break;
511
512 case T_EXIT:
513 case T_FOREACH:
514 case T_IF:
515 case T_LET:
516 case T_SET:
517 case T_SWITCH:
518 case T_WHILE:
519 specp = 1;
520 break;
521 }
522 }
523 n = 0;
524 l = 0;
525 for (p = p1; p != p2; p = p->next)
526 switch (p->word[0]) {
527
528 case '(':
529 if (specp)
530 n++;
531 l++;
532 continue;
533
534 case ')':
535 if (specp)
536 n++;
537 l--;
538 continue;
539
540 case '>':
541 case '<':
542 if (l != 0) {
543 if (specp)
544 n++;
545 continue;
546 }
547 if (p->next == p2)
548 continue;
549 if (any(RELPAR, p->next->word[0]))
550 continue;
551 n--;
552 continue;
553
554 default:
555 if (!specp && l != 0)
556 continue;
557 n++;
558 continue;
559 }
560 if (n < 0)
561 n = 0;
562 t = (struct command *) xcalloc(1, sizeof(*t));
563 av = (Char **) xcalloc((size_t) (n + 1), sizeof(Char **));
564 t->t_dcom = av;
565 n = 0;
566 if (p2->word[0] == ')')
567 t->t_dflg = F_NOFORK;
568 lp = 0;
569 rp = 0;
570 l = 0;
571 for (p = p1; p != p2; p = p->next) {
572 c = p->word[0];
573 switch (c) {
574
575 case '(':
576 if (l == 0) {
577 if (lp != 0 && !specp)
578 seterror(ERR_BADPLP);
579 lp = p->next;
580 }
581 l++;
582 goto savep;
583
584 case ')':
585 l--;
586 if (l == 0)
587 rp = p;
588 goto savep;
589
590 case '>':
591 if (l != 0)
592 goto savep;
593 if (p->word[1] == '>')
594 t->t_dflg |= F_APPEND;
595 if (p->next != p2 && eq(p->next->word, STRand)) {
596 t->t_dflg |= F_STDERR, p = p->next;
597 if (flags & (POUT | PDIAG)) {
598 seterror(ERR_OUTRED);
599 continue;
600 }
601 }
602 if (p->next != p2 && eq(p->next->word, STRbang))
603 t->t_dflg |= F_OVERWRITE, p = p->next;
604 if (p->next == p2) {
605 seterror(ERR_MISRED);
606 continue;
607 }
608 p = p->next;
609 if (any(RELPAR, p->word[0])) {
610 seterror(ERR_MISRED);
611 continue;
612 }
613 if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit)
614 seterror(ERR_OUTRED);
615 else
616 t->t_drit = Strsave(p->word);
617 continue;
618
619 case '<':
620 if (l != 0)
621 goto savep;
622 if (p->word[1] == '<')
623 t->t_dflg |= F_READ;
624 if (p->next == p2) {
625 seterror(ERR_MISRED);
626 continue;
627 }
628 p = p->next;
629 if (any(RELPAR, p->word[0])) {
630 seterror(ERR_MISRED);
631 continue;
632 }
633 if ((flags & PHERE) && (t->t_dflg & F_READ))
634 seterror(ERR_REDPAR);
635 else if ((flags & PIN) || t->t_dlef)
636 seterror(ERR_INRED);
637 else
638 t->t_dlef = Strsave(p->word);
639 continue;
640
641 savep:
642 if (!specp)
643 continue;
644 default:
645 if (l != 0 && !specp)
646 continue;
647 if (seterr == 0)
648 av[n] = Strsave(p->word);
649 n++;
650 continue;
651 }
652 }
653 if (lp != 0 && !specp) {
654 if (n != 0)
655 seterror(ERR_BADPLPS);
656 t->t_dtyp = NODE_PAREN;
657 t->t_dspr = syn0(lp, rp, PHERE);
658 }
659 else {
660 if (n == 0)
661 seterror(ERR_NULLCOM);
662 t->t_dtyp = NODE_COMMAND;
663 }
664 return (t);
665}
666
667void
668freesyn(t)
669 register struct command *t;
670{
671 register Char **v;
672
673 if (t == 0)
674 return;
675 switch (t->t_dtyp) {
676
677 case NODE_COMMAND:
678 for (v = t->t_dcom; *v; v++)
679 xfree((ptr_t) * v);
680 xfree((ptr_t) (t->t_dcom));
681 xfree((ptr_t) t->t_dlef);
682 xfree((ptr_t) t->t_drit);
683 break;
684 case NODE_PAREN:
685 freesyn(t->t_dspr);
686 xfree((ptr_t) t->t_dlef);
687 xfree((ptr_t) t->t_drit);
688 break;
689
690 case NODE_AND:
691 case NODE_OR:
692 case NODE_PIPE:
693 case NODE_LIST:
694 freesyn(t->t_dcar), freesyn(t->t_dcdr);
695 break;
696 }
697 xfree((ptr_t) t);
698}