| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: parser.c,v 1.111 2016/03/27 14:39:33 christos Exp $ */ | | 1 | /* $NetBSD: parser.c,v 1.112 2016/03/27 14:40:20 christos Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1991, 1993 | | 4 | * Copyright (c) 1991, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Kenneth Almquist. | | 8 | * Kenneth Almquist. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -27,27 +27,27 @@ | | | @@ -27,27 +27,27 @@ |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | #ifndef lint | | 36 | #ifndef lint |
37 | #if 0 | | 37 | #if 0 |
38 | static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; | | 38 | static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; |
39 | #else | | 39 | #else |
40 | __RCSID("$NetBSD: parser.c,v 1.111 2016/03/27 14:39:33 christos Exp $"); | | 40 | __RCSID("$NetBSD: parser.c,v 1.112 2016/03/27 14:40:20 christos Exp $"); |
41 | #endif | | 41 | #endif |
42 | #endif /* not lint */ | | 42 | #endif /* not lint */ |
43 | | | 43 | |
44 | #include <stdio.h> | | 44 | #include <stdio.h> |
45 | #include <stdlib.h> | | 45 | #include <stdlib.h> |
46 | #include <limits.h> | | 46 | #include <limits.h> |
47 | | | 47 | |
48 | #include "shell.h" | | 48 | #include "shell.h" |
49 | #include "parser.h" | | 49 | #include "parser.h" |
50 | #include "nodes.h" | | 50 | #include "nodes.h" |
51 | #include "expand.h" /* defines rmescapes() */ | | 51 | #include "expand.h" /* defines rmescapes() */ |
52 | #include "eval.h" /* defines commandname */ | | 52 | #include "eval.h" /* defines commandname */ |
53 | #include "redir.h" /* defines copyfd() */ | | 53 | #include "redir.h" /* defines copyfd() */ |
| @@ -1169,27 +1169,26 @@ drop_state_level(VSS *stack) | | | @@ -1169,27 +1169,26 @@ drop_state_level(VSS *stack) |
1169 | --stack->cur; | | 1169 | --stack->cur; |
1170 | return stack; | | 1170 | return stack; |
1171 | } | | 1171 | } |
1172 | | | 1172 | |
1173 | static inline void | | 1173 | static inline void |
1174 | cleanup_state_stack(VSS *stack) | | 1174 | cleanup_state_stack(VSS *stack) |
1175 | { | | 1175 | { |
1176 | while (stack->prev != NULL) { | | 1176 | while (stack->prev != NULL) { |
1177 | stack->cur = 0; | | 1177 | stack->cur = 0; |
1178 | stack = drop_state_level(stack); | | 1178 | stack = drop_state_level(stack); |
1179 | } | | 1179 | } |
1180 | } | | 1180 | } |
1181 | | | 1181 | |
1182 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} | | | |
1183 | #define PARSESUB() {goto parsesub; parsesub_return:;} | | 1182 | #define PARSESUB() {goto parsesub; parsesub_return:;} |
1184 | #define PARSEARITH() {goto parsearith; parsearith_return:;} | | 1183 | #define PARSEARITH() {goto parsearith; parsearith_return:;} |
1185 | | | 1184 | |
1186 | /* | | 1185 | /* |
1187 | * The following macros all assume the existance of a local var "stack" | | 1186 | * The following macros all assume the existance of a local var "stack" |
1188 | * which contains a pointer to the current struct stackstate | | 1187 | * which contains a pointer to the current struct stackstate |
1189 | */ | | 1188 | */ |
1190 | | | 1189 | |
1191 | /* | | 1190 | /* |
1192 | * These are macros rather than inline funcs to avoid code churn as much | | 1191 | * These are macros rather than inline funcs to avoid code churn as much |
1193 | * as possible - they replace macros of the same name used previously. | | 1192 | * as possible - they replace macros of the same name used previously. |
1194 | */ | | 1193 | */ |
1195 | #define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS) | | 1194 | #define ISDBLQUOTE() (currentstate(stack)->ts_quoted & QS) |
| @@ -1360,26 +1359,114 @@ done: | | | @@ -1360,26 +1359,114 @@ done: |
1360 | sstr = str = NULL; | | 1359 | sstr = str = NULL; |
1361 | INTON; | | 1360 | INTON; |
1362 | } | | 1361 | } |
1363 | parsebackquote = savepbq; | | 1362 | parsebackquote = savepbq; |
1364 | handler = savehandler; | | 1363 | handler = savehandler; |
1365 | if (arinest || ISDBLQUOTE()) | | 1364 | if (arinest || ISDBLQUOTE()) |
1366 | USTPUTC(CTLBACKQ | CTLQUOTE, out); | | 1365 | USTPUTC(CTLBACKQ | CTLQUOTE, out); |
1367 | else | | 1366 | else |
1368 | USTPUTC(CTLBACKQ, out); | | 1367 | USTPUTC(CTLBACKQ, out); |
1369 | | | 1368 | |
1370 | return out; | | 1369 | return out; |
1371 | } | | 1370 | } |
1372 | | | 1371 | |
| | | 1372 | /* |
| | | 1373 | * Parse a redirection operator. The parameter "out" points to a string |
| | | 1374 | * specifying the fd to be redirected. It is guaranteed to be either "" |
| | | 1375 | * or a numeric string (for now anyway). The parameter "c" contains the |
| | | 1376 | * first character of the redirection operator. |
| | | 1377 | * |
| | | 1378 | * Note the string "out" is on the stack, which we are about to clobber, |
| | | 1379 | * so process it first... |
| | | 1380 | */ |
| | | 1381 | |
| | | 1382 | static void |
| | | 1383 | parseredir(const char *out, int c) |
| | | 1384 | { |
| | | 1385 | union node *np; |
| | | 1386 | int fd; |
| | | 1387 | |
| | | 1388 | fd = (*out == '\0') ? -1 : atoi(out); |
| | | 1389 | |
| | | 1390 | np = stalloc(sizeof(struct nfile)); |
| | | 1391 | if (c == '>') { |
| | | 1392 | if (fd < 0) |
| | | 1393 | fd = 1; |
| | | 1394 | c = pgetc(); |
| | | 1395 | if (c == '>') |
| | | 1396 | np->type = NAPPEND; |
| | | 1397 | else if (c == '|') |
| | | 1398 | np->type = NCLOBBER; |
| | | 1399 | else if (c == '&') |
| | | 1400 | np->type = NTOFD; |
| | | 1401 | else { |
| | | 1402 | np->type = NTO; |
| | | 1403 | pungetc(); |
| | | 1404 | } |
| | | 1405 | } else { /* c == '<' */ |
| | | 1406 | if (fd < 0) |
| | | 1407 | fd = 0; |
| | | 1408 | switch (c = pgetc()) { |
| | | 1409 | case '<': |
| | | 1410 | if (sizeof (struct nfile) != sizeof (struct nhere)) { |
| | | 1411 | np = stalloc(sizeof(struct nhere)); |
| | | 1412 | np->nfile.fd = 0; |
| | | 1413 | } |
| | | 1414 | np->type = NHERE; |
| | | 1415 | heredoc = stalloc(sizeof(struct heredoc)); |
| | | 1416 | heredoc->here = np; |
| | | 1417 | if ((c = pgetc()) == '-') { |
| | | 1418 | heredoc->striptabs = 1; |
| | | 1419 | } else { |
| | | 1420 | heredoc->striptabs = 0; |
| | | 1421 | pungetc(); |
| | | 1422 | } |
| | | 1423 | break; |
| | | 1424 | |
| | | 1425 | case '&': |
| | | 1426 | np->type = NFROMFD; |
| | | 1427 | break; |
| | | 1428 | |
| | | 1429 | case '>': |
| | | 1430 | np->type = NFROMTO; |
| | | 1431 | break; |
| | | 1432 | |
| | | 1433 | default: |
| | | 1434 | np->type = NFROM; |
| | | 1435 | pungetc(); |
| | | 1436 | break; |
| | | 1437 | } |
| | | 1438 | } |
| | | 1439 | np->nfile.fd = fd; |
| | | 1440 | |
| | | 1441 | redirnode = np; /* this is the "value" of TRENODE */ |
| | | 1442 | } |
| | | 1443 | |
| | | 1444 | |
| | | 1445 | /* |
| | | 1446 | * The lowest level basic tokenizer. |
| | | 1447 | * |
| | | 1448 | * The next input byte (character) is in firstc, syn says which |
| | | 1449 | * syntax tables we are to use (basic, single or double quoted, or arith) |
| | | 1450 | * and magicq (used with sqsyntax and dqsyntax only) indicates that the |
| | | 1451 | * quote character itself is not special (used parsing here docs and similar) |
| | | 1452 | * |
| | | 1453 | * The result is the type of the next token (its value, when there is one, |
| | | 1454 | * is saved in the relevant global var - must fix that someday!) which is |
| | | 1455 | * also saved for re-reading ("lasttoken"). |
| | | 1456 | * |
| | | 1457 | * Overall, this routine does far more parsing than it is supposed to. |
| | | 1458 | * That will also need fixing, someday... |
| | | 1459 | */ |
1373 | STATIC int | | 1460 | STATIC int |
1374 | readtoken1(int firstc, char const *syn, int magicq) | | 1461 | readtoken1(int firstc, char const *syn, int magicq) |
1375 | { | | 1462 | { |
1376 | int c = firstc; | | 1463 | int c = firstc; |
1377 | char * out; | | 1464 | char * out; |
1378 | int len; | | 1465 | int len; |
1379 | struct nodelist *bqlist; | | 1466 | struct nodelist *bqlist; |
1380 | int quotef; | | 1467 | int quotef; |
1381 | VSS static_stack; | | 1468 | VSS static_stack; |
1382 | VSS *stack = &static_stack; | | 1469 | VSS *stack = &static_stack; |
1383 | | | 1470 | |
1384 | stack->prev = NULL; | | 1471 | stack->prev = NULL; |
1385 | stack->cur = 0; | | 1472 | stack->cur = 0; |
| @@ -1563,108 +1650,43 @@ endword: | | | @@ -1563,108 +1650,43 @@ endword: |
1563 | if (varnest != 0) { | | 1650 | if (varnest != 0) { |
1564 | cleanup_state_stack(stack); | | 1651 | cleanup_state_stack(stack); |
1565 | startlinno = plinno; | | 1652 | startlinno = plinno; |
1566 | /* { */ | | 1653 | /* { */ |
1567 | synerror("Missing '}'"); | | 1654 | synerror("Missing '}'"); |
1568 | } | | 1655 | } |
1569 | USTPUTC('\0', out); | | 1656 | USTPUTC('\0', out); |
1570 | len = out - stackblock(); | | 1657 | len = out - stackblock(); |
1571 | out = stackblock(); | | 1658 | out = stackblock(); |
1572 | if (!magicq) { | | 1659 | if (!magicq) { |
1573 | if ((c == '<' || c == '>') | | 1660 | if ((c == '<' || c == '>') |
1574 | && quotef == 0 | | 1661 | && quotef == 0 |
1575 | && (*out == '\0' || is_number(out))) { | | 1662 | && (*out == '\0' || is_number(out))) { |
1576 | PARSEREDIR(); | | 1663 | parseredir(out, c); |
1577 | cleanup_state_stack(stack); | | 1664 | cleanup_state_stack(stack); |
1578 | return lasttoken = TREDIR; | | 1665 | return lasttoken = TREDIR; |
1579 | } else { | | 1666 | } else { |
1580 | pungetc(); | | 1667 | pungetc(); |
1581 | } | | 1668 | } |
1582 | } | | 1669 | } |
1583 | quoteflag = quotef; | | 1670 | quoteflag = quotef; |
1584 | backquotelist = bqlist; | | 1671 | backquotelist = bqlist; |
1585 | grabstackblock(len); | | 1672 | grabstackblock(len); |
1586 | wordtext = out; | | 1673 | wordtext = out; |
1587 | cleanup_state_stack(stack); | | 1674 | cleanup_state_stack(stack); |
1588 | return lasttoken = TWORD; | | 1675 | return lasttoken = TWORD; |
1589 | /* end of readtoken routine */ | | 1676 | /* end of readtoken routine */ |
1590 | | | 1677 | |
1591 | | | 1678 | |
1592 | /* | | 1679 | /* |
1593 | * Parse a redirection operator. The variable "out" points to a string | | | |
1594 | * specifying the fd to be redirected. The variable "c" contains the | | | |
1595 | * first character of the redirection operator. | | | |
1596 | */ | | | |
1597 | | | | |
1598 | parseredir: { | | | |
1599 | char fd[64]; | | | |
1600 | union node *np; | | | |
1601 | strlcpy(fd, out, sizeof(fd)); | | | |
1602 | | | | |
1603 | np = stalloc(sizeof(struct nfile)); | | | |
1604 | if (c == '>') { | | | |
1605 | np->nfile.fd = 1; | | | |
1606 | c = pgetc(); | | | |
1607 | if (c == '>') | | | |
1608 | np->type = NAPPEND; | | | |
1609 | else if (c == '|') | | | |
1610 | np->type = NCLOBBER; | | | |
1611 | else if (c == '&') | | | |
1612 | np->type = NTOFD; | | | |
1613 | else { | | | |
1614 | np->type = NTO; | | | |
1615 | pungetc(); | | | |
1616 | } | | | |
1617 | } else { /* c == '<' */ | | | |
1618 | np->nfile.fd = 0; | | | |
1619 | switch (c = pgetc()) { | | | |
1620 | case '<': | | | |
1621 | if (sizeof (struct nfile) != sizeof (struct nhere)) { | | | |
1622 | np = stalloc(sizeof(struct nhere)); | | | |
1623 | np->nfile.fd = 0; | | | |
1624 | } | | | |
1625 | np->type = NHERE; | | | |
1626 | heredoc = stalloc(sizeof(struct heredoc)); | | | |
1627 | heredoc->here = np; | | | |
1628 | if ((c = pgetc()) == '-') { | | | |
1629 | heredoc->striptabs = 1; | | | |
1630 | } else { | | | |
1631 | heredoc->striptabs = 0; | | | |
1632 | pungetc(); | | | |
1633 | } | | | |
1634 | break; | | | |
1635 | | | | |
1636 | case '&': | | | |
1637 | np->type = NFROMFD; | | | |
1638 | break; | | | |
1639 | | | | |
1640 | case '>': | | | |
1641 | np->type = NFROMTO; | | | |
1642 | break; | | | |
1643 | | | | |
1644 | default: | | | |
1645 | np->type = NFROM; | | | |
1646 | pungetc(); | | | |
1647 | break; | | | |
1648 | } | | | |
1649 | } | | | |
1650 | if (*fd != '\0') | | | |
1651 | np->nfile.fd = number(fd); | | | |
1652 | redirnode = np; | | | |
1653 | goto parseredir_return; | | | |
1654 | } | | | |
1655 | | | | |
1656 | | | | |
1657 | /* | | | |
1658 | * Parse a substitution. At this point, we have read the dollar sign | | 1680 | * Parse a substitution. At this point, we have read the dollar sign |
1659 | * and nothing else. | | 1681 | * and nothing else. |
1660 | */ | | 1682 | */ |
1661 | | | 1683 | |
1662 | parsesub: { | | 1684 | parsesub: { |
1663 | char buf[10]; | | 1685 | char buf[10]; |
1664 | int subtype; | | 1686 | int subtype; |
1665 | int typeloc; | | 1687 | int typeloc; |
1666 | int flags; | | 1688 | int flags; |
1667 | char *p; | | 1689 | char *p; |
1668 | static const char types[] = "}-+?="; | | 1690 | static const char types[] = "}-+?="; |
1669 | int i; | | 1691 | int i; |
1670 | int linno; | | 1692 | int linno; |