1 /* $NetBSD: parse.c,v 1.21 2020/08/09 00:34:21 dholland 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. 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.
18  *
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.
30  */
31 
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.21 2020/08/09 00:34:21 dholland Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/types.h>
42 
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #include "csh.h"
48 #include "extern.h"
49 
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);
60 
61 #define ALEFT 21              /* max of 20 alias expansions  */
62 #define HLEFT 11              /* max of 10 history expansions          */
63 /*
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.
68  */
69 static int aleft;
70 extern int hleft;
71 
72 void
alias(struct wordent * lexp)73 alias(struct wordent *lexp)
74 {
75     jmp_buf osetexit;
76 
77     aleft = ALEFT;
78     hleft = HLEFT;
79     getexit(osetexit);
80     (void)setexit();
81     if (haderr) {
82           resexit(osetexit);
83           reset();
84     }
85     if (--aleft == 0)
86           stderror(ERR_ALIASLOOP);
87     asyntax(lexp->next, lexp);
88     resexit(osetexit);
89 }
90 
91 static void
asyntax(struct wordent * p1,struct wordent * p2)92 asyntax(struct wordent *p1, struct wordent *p2)
93 {
94     while (p1 != p2)
95           if (any(";&\n", p1->word[0]))
96               p1 = p1->next;
97           else {
98               asyn0(p1, p2);
99               return;
100           }
101 }
102 
103 static void
asyn0(struct wordent * p1,struct wordent * p2)104 asyn0(struct wordent *p1, struct wordent *p2)
105 {
106     struct wordent *p;
107     int l;
108 
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;
133           }
134     if (l == 0)
135           asyn3(p1, p2);
136 }
137 
138 static void
asyn3(struct wordent * p1,struct wordent * p2)139 asyn3(struct wordent *p1, struct wordent *p2)
140 {
141     struct varent *ap;
142     struct wordent alout;
143     int redid;
144 
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;
155     }
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);
168     }
169     if (p1->word[0] && eq(p1->word, alout.next->word)) {
170           Char *cp;
171 
172           cp = alout.next->word;
173           alout.next->word = Strspl(STRQNULL, cp);
174           free(cp);
175     }
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           free(alout.prev->word);
183           free(alout.prev);
184     }
185     reset();                            /* throw! */
186 }
187 
188 static struct wordent *
freenod(struct wordent * p1,struct wordent * p2)189 freenod(struct wordent *p1, struct wordent *p2)
190 {
191     struct wordent *retp;
192 
193     retp = p1->prev;
194     while (p1 != p2) {
195           free(p1->word);
196           p1 = p1->next;
197           free(p1->prev);
198     }
199     retp->next = p2;
200     p2->prev = retp;
201     return (retp);
202 }
203 
204 #define   PHERE     1
205 #define   PIN       2
206 #define   POUT      4
207 #define   PERR      8
208 
209 /*
210  * syntax
211  *        empty
212  *        syn0
213  */
214 struct command *
syntax(struct wordent * p1,struct wordent * p2,int flags)215 syntax(struct wordent *p1, struct wordent *p2, int flags)
216 {
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);
223 }
224 
225 /*
226  * syn0
227  *        syn1
228  *        syn1 & syntax
229  */
230 static struct command *
syn0(struct wordent * p1,struct wordent * p2,int flags)231 syn0(struct wordent *p1, struct wordent *p2, int flags)
232 {
233     struct wordent *p;
234     struct command *t, *t1;
235     int l;
236 
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 = 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;
270               }
271               else
272                     t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
273               t = 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);
279           }
280     if (l == 0)
281           return (syn1(p1, p2, flags));
282     seterror(ERR_TOOMANYLP);
283     return (0);
284 }
285 
286 /*
287  * syn1
288  *        syn1a
289  *        syn1a ; syntax
290  */
291 static struct command *
syn1(struct wordent * p1,struct wordent * p2,int flags)292 syn1(struct wordent *p1, struct wordent *p2, int flags)
293 {
294     struct wordent *p;
295     struct command *t;
296     int l;
297 
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 = 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);
318           }
319     return (syn1a(p1, p2, flags));
320 }
321 
322 /*
323  * syn1a
324  *        syn1b
325  *        syn1b || syn1a
326  */
327 static struct command *
syn1a(struct wordent * p1,struct wordent * p2,int flags)328 syn1a(struct wordent *p1, struct wordent *p2, int flags)
329 {
330     struct wordent *p;
331     struct command *t;
332     int l;
333 
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 = 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);
353               }
354               continue;
355           }
356     return (syn1b(p1, p2, flags));
357 }
358 
359 /*
360  * syn1b
361  *        syn2
362  *        syn2 && syn1b
363  */
364 static struct command *
syn1b(struct wordent * p1,struct wordent * p2,int flags)365 syn1b(struct wordent *p1, struct wordent *p2, int flags)
366 {
367     struct wordent *p;
368     struct command *t;
369     int l;
370 
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 = 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);
388               }
389               continue;
390           }
391     return (syn2(p1, p2, flags));
392 }
393 
394 /*
395  * syn2
396  *        syn3
397  *        syn3 | syn2
398  *        syn3 |& syn2
399  */
400 static struct command *
syn2(struct wordent * p1,struct wordent * p2,int flags)401 syn2(struct wordent *p1, struct wordent *p2, int flags)
402 {
403     struct wordent *p, *pn;
404     struct command *t;
405     int f, l;
406 
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 = 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;
425               }
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);
432           }
433     return (syn3(p1, p2, flags));
434 }
435 
436 static char RELPAR[] = {'<', '>', '(', ')', '\0'};
437 
438 /*
439  * syn3
440  *        ( syn0 ) [ < in  ] [ > out ]
441  *        word word* [ < in ] [ > out ]
442  *        KEYWORD ( word* ) word* [ < in ] [ > out ]
443  *
444  *        KEYWORD = (@ exit foreach if set switch test while)
445  */
446 static struct command *
syn3(struct wordent * p1,struct wordent * p2,int flags)447 syn3(struct wordent *p1, struct wordent *p2, int flags)
448 {
449     struct wordent *lp, *p, *rp;
450     struct command *t;
451     Char **av;
452     int c, l, n;
453     int specp;
454 
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;
474           }
475     }
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;
496               }
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;
508           }
509     if (n < 0)
510           n = 0;
511     t = xcalloc(1, sizeof(*t));
512     /* XXX the cast is needed because n is signed */
513     av = xcalloc((size_t)(n + 1), sizeof(*av));
514     t->t_dcom = av;
515     n = 0;
516     if (p2->word[0] == ')')
517           t->t_dflg = F_NOFORK;
518     lp = 0;
519     rp = 0;
520     l = 0;
521     for (p = p1; p != p2; p = p->next) {
522           c = p->word[0];
523           switch (c) {
524           case '(':
525               if (l == 0) {
526                     if (lp != 0 && !specp)
527                         seterror(ERR_BADPLP);
528                     lp = p->next;
529               }
530               l++;
531               goto savep;
532           case ')':
533               l--;
534               if (l == 0)
535                     rp = p;
536               goto savep;
537           case '>':
538               if (l != 0)
539                     goto savep;
540               if (p->word[1] == '>')
541                     t->t_dflg |= F_APPEND;
542               if (p->next != p2 && eq(p->next->word, STRand)) {
543                     t->t_dflg |= F_STDERR, p = p->next;
544                     if (flags & (POUT | PERR)) {
545                         seterror(ERR_OUTRED);
546                         continue;
547                     }
548               }
549               if (p->next != p2 && eq(p->next->word, STRbang))
550                     t->t_dflg |= F_OVERWRITE, p = p->next;
551               if (p->next == p2) {
552                     seterror(ERR_MISRED);
553                     continue;
554               }
555               p = p->next;
556               if (any(RELPAR, p->word[0])) {
557                     seterror(ERR_MISRED);
558                     continue;
559               }
560               if ((flags & POUT) && ((flags & PERR) == 0 || t->t_drit))
561                     seterror(ERR_OUTRED);
562               else
563                     t->t_drit = Strsave(p->word);
564               continue;
565           case '<':
566               if (l != 0)
567                     goto savep;
568               if (p->word[1] == '<')
569                     t->t_dflg |= F_READ;
570               if (p->next == p2) {
571                     seterror(ERR_MISRED);
572                     continue;
573               }
574               p = p->next;
575               if (any(RELPAR, p->word[0])) {
576                     seterror(ERR_MISRED);
577                     continue;
578               }
579               if ((flags & PHERE) && (t->t_dflg & F_READ))
580                     seterror(ERR_REDPAR);
581               else if ((flags & PIN) || t->t_dlef)
582                     seterror(ERR_INRED);
583               else
584                     t->t_dlef = Strsave(p->word);
585               continue;
586           savep:
587               if (!specp)
588                     continue;
589               /* FALLTHROUGH */
590           default:
591               if (l != 0 && !specp)
592                     continue;
593               if (seterr == 0)
594                     av[n] = Strsave(p->word);
595               n++;
596               continue;
597           }
598     }
599     if (lp != 0 && !specp) {
600           if (n != 0)
601               seterror(ERR_BADPLPS);
602           t->t_dtyp = NODE_PAREN;
603           t->t_dspr = syn0(lp, rp, PHERE);
604     }
605     else {
606           if (n == 0)
607               seterror(ERR_NULLCOM);
608           t->t_dtyp = NODE_COMMAND;
609     }
610     return (t);
611 }
612 
613 void
freesyn(struct command * t)614 freesyn(struct command *t)
615 {
616     Char **v;
617 
618     if (t == 0)
619           return;
620     switch (t->t_dtyp) {
621     case NODE_COMMAND:
622           for (v = t->t_dcom; *v; v++)
623               free(* v);
624           free(t->t_dcom);
625           free(t->t_dlef);
626           free(t->t_drit);
627           break;
628     case NODE_PAREN:
629           freesyn(t->t_dspr);
630           free(t->t_dlef);
631           free(t->t_drit);
632           break;
633     case NODE_AND:
634     case NODE_OR:
635     case NODE_PIPE:
636     case NODE_LIST:
637           freesyn(t->t_dcar), freesyn(t->t_dcdr);
638           break;
639     }
640     free(t);
641 }
642