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