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