Home | History | Annotate | Line # | Download | only in csh
      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
     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
     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
    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
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    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
    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