| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: parser.c,v 1.74 2009/01/18 00:30:54 lukem Exp $ */ | | 1 | /* $NetBSD: parser.c,v 1.75 2010/11/14 19:43:38 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.74 2009/01/18 00:30:54 lukem Exp $"); | | 40 | __RCSID("$NetBSD: parser.c,v 1.75 2010/11/14 19:43:38 christos Exp $"); |
41 | #endif | | 41 | #endif |
42 | #endif /* not lint */ | | 42 | #endif /* not lint */ |
43 | | | 43 | |
44 | #include <stdlib.h> | | 44 | #include <stdlib.h> |
45 | | | 45 | |
46 | #include "shell.h" | | 46 | #include "shell.h" |
47 | #include "parser.h" | | 47 | #include "parser.h" |
48 | #include "nodes.h" | | 48 | #include "nodes.h" |
49 | #include "expand.h" /* defines rmescapes() */ | | 49 | #include "expand.h" /* defines rmescapes() */ |
50 | #include "eval.h" /* defines commandname */ | | 50 | #include "eval.h" /* defines commandname */ |
51 | #include "redir.h" /* defines copyfd() */ | | 51 | #include "redir.h" /* defines copyfd() */ |
52 | #include "syntax.h" | | 52 | #include "syntax.h" |
53 | #include "options.h" | | 53 | #include "options.h" |
| @@ -886,69 +886,77 @@ breakloop: | | | @@ -886,69 +886,77 @@ breakloop: |
886 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} | | 886 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} |
887 | #define PARSESUB() {goto parsesub; parsesub_return:;} | | 887 | #define PARSESUB() {goto parsesub; parsesub_return:;} |
888 | #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} | | 888 | #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} |
889 | #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} | | 889 | #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} |
890 | #define PARSEARITH() {goto parsearith; parsearith_return:;} | | 890 | #define PARSEARITH() {goto parsearith; parsearith_return:;} |
891 | | | 891 | |
892 | /* | | 892 | /* |
893 | * Keep track of nested doublequotes in dblquote and doublequotep. | | 893 | * Keep track of nested doublequotes in dblquote and doublequotep. |
894 | * We use dblquote for the first 32 levels, and we expand to a malloc'ed | | 894 | * We use dblquote for the first 32 levels, and we expand to a malloc'ed |
895 | * region for levels above that. Usually we never need to malloc. | | 895 | * region for levels above that. Usually we never need to malloc. |
896 | * This code assumes that an int is 32 bits. We don't use uint32_t, | | 896 | * This code assumes that an int is 32 bits. We don't use uint32_t, |
897 | * because the rest of the code does not. | | 897 | * because the rest of the code does not. |
898 | */ | | 898 | */ |
899 | #define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \ | | 899 | #define VN (varnest - insub) |
900 | (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32)))) | | 900 | #define ISDBLQUOTE() ((VN < 32) ? (dblquote & (1 << VN)) : \ |
| | | 901 | (dblquotep[(VN / 32) - 1] & (1 << (VN % 32)))) |
901 | | | 902 | |
902 | #define SETDBLQUOTE() \ | | 903 | #define SETDBLQUOTE() \ |
903 | if (varnest < 32) \ | | 904 | do { \ |
904 | dblquote |= (1 << varnest); \ | | 905 | TRACE(("setdblquote %d\n", varnest)); \ |
905 | else \ | | 906 | if (varnest < 32) \ |
906 | dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32)) | | 907 | dblquote |= (1 << varnest); \ |
| | | 908 | else \ |
| | | 909 | dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32));\ |
| | | 910 | } while (/*CONSTCOND*/0) |
907 | | | 911 | |
908 | #define CLRDBLQUOTE() \ | | 912 | #define CLRDBLQUOTE() \ |
909 | if (varnest < 32) \ | | 913 | do { \ |
910 | dblquote &= ~(1 << varnest); \ | | 914 | TRACE(("clrdblquote %d\n", varnest)); \ |
911 | else \ | | 915 | if (varnest < 32) \ |
912 | dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32)) | | 916 | dblquote &= ~(1 << varnest); \ |
| | | 917 | else \ |
| | | 918 | dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32)); \ |
| | | 919 | } while (/*CONSTCOND*/0) |
913 | | | 920 | |
914 | STATIC int | | 921 | STATIC int |
915 | readtoken1(int firstc, char const *syn, char *eofmark, int striptabs) | | 922 | readtoken1(int firstc, char const *syn, char *eofmark, int striptabs) |
916 | { | | 923 | { |
917 | char const * volatile syntax = syn; | | 924 | char const * volatile syntax = syn; |
918 | int c = firstc; | | 925 | int c = firstc; |
919 | char * volatile out; | | 926 | char * volatile out; |
920 | int len; | | 927 | int len; |
921 | char line[EOFMARKLEN + 1]; | | 928 | char line[EOFMARKLEN + 1]; |
922 | struct nodelist *bqlist; | | 929 | struct nodelist *bqlist; |
923 | volatile int quotef; | | 930 | volatile int quotef; |
924 | int * volatile dblquotep = NULL; | | 931 | int * volatile dblquotep = NULL; |
925 | volatile size_t maxnest = 32; | | 932 | volatile size_t maxnest = 32; |
926 | volatile int dblquote; | | 933 | volatile int dblquote; |
927 | volatile size_t varnest; /* levels of variables expansion */ | | 934 | volatile size_t varnest; /* levels of variables expansion */ |
928 | volatile int arinest; /* levels of arithmetic expansion */ | | 935 | volatile int arinest; /* levels of arithmetic expansion */ |
929 | volatile int parenlevel; /* levels of parens in arithmetic */ | | 936 | volatile int parenlevel; /* levels of parens in arithmetic */ |
930 | volatile int oldstyle; | | 937 | volatile int oldstyle; |
| | | 938 | volatile int insub; |
931 | char const * volatile prevsyntax; /* syntax before arithmetic */ | | 939 | char const * volatile prevsyntax; /* syntax before arithmetic */ |
932 | #ifdef __GNUC__ | | 940 | #ifdef __GNUC__ |
933 | prevsyntax = NULL; /* XXX gcc4 */ | | 941 | prevsyntax = NULL; /* XXX gcc4 */ |
934 | #endif | | 942 | #endif |
935 | | | 943 | |
936 | startlinno = plinno; | | 944 | startlinno = plinno; |
937 | dblquote = 0; | | 945 | dblquote = 0; |
938 | varnest = 0; | | 946 | varnest = 0; |
939 | if (syntax == DQSYNTAX) { | | 947 | insub = 0; |
| | | 948 | if (syntax == DQSYNTAX) |
940 | SETDBLQUOTE(); | | 949 | SETDBLQUOTE(); |
941 | } | | | |
942 | quotef = 0; | | 950 | quotef = 0; |
943 | bqlist = NULL; | | 951 | bqlist = NULL; |
944 | arinest = 0; | | 952 | arinest = 0; |
945 | parenlevel = 0; | | 953 | parenlevel = 0; |
946 | | | 954 | |
947 | STARTSTACKSTR(out); | | 955 | STARTSTACKSTR(out); |
948 | loop: { /* for each line, until end of word */ | | 956 | loop: { /* for each line, until end of word */ |
949 | #if ATTY | | 957 | #if ATTY |
950 | if (c == '\034' && doprompt | | 958 | if (c == '\034' && doprompt |
951 | && attyset() && ! equal(termval(), "emacs")) { | | 959 | && attyset() && ! equal(termval(), "emacs")) { |
952 | attyline(); | | 960 | attyline(); |
953 | if (syntax == BASESYNTAX) | | 961 | if (syntax == BASESYNTAX) |
954 | return readtoken(); | | 962 | return readtoken(); |
| @@ -984,30 +992,34 @@ readtoken1(int firstc, char const *syn, | | | @@ -984,30 +992,34 @@ readtoken1(int firstc, char const *syn, |
984 | if (c == PEOF) { | | 992 | if (c == PEOF) { |
985 | USTPUTC('\\', out); | | 993 | USTPUTC('\\', out); |
986 | pungetc(); | | 994 | pungetc(); |
987 | break; | | 995 | break; |
988 | } | | 996 | } |
989 | if (c == '\n') { | | 997 | if (c == '\n') { |
990 | if (doprompt) | | 998 | if (doprompt) |
991 | setprompt(2); | | 999 | setprompt(2); |
992 | else | | 1000 | else |
993 | setprompt(0); | | 1001 | setprompt(0); |
994 | break; | | 1002 | break; |
995 | } | | 1003 | } |
996 | quotef = 1; | | 1004 | quotef = 1; |
| | | 1005 | TRACE(("varnest=%d doubleq=%d c=%c\n", |
| | | 1006 | varnest, ISDBLQUOTE(), c)); |
997 | if (ISDBLQUOTE() && c != '\\' && | | 1007 | if (ISDBLQUOTE() && c != '\\' && |
998 | c != '`' && c != '$' && | | 1008 | c != '`' && c != '$' && |
999 | (c != '"' || eofmark != NULL)) | | 1009 | (c != '"' || eofmark != NULL)) { |
1000 | USTPUTC('\\', out); | | 1010 | USTPUTC(CTLESC, out); |
| | | 1011 | USTPUTC(CTLESC, out); |
| | | 1012 | } |
1001 | if (SQSYNTAX[c] == CCTL) | | 1013 | if (SQSYNTAX[c] == CCTL) |
1002 | USTPUTC(CTLESC, out); | | 1014 | USTPUTC(CTLESC, out); |
1003 | else if (eofmark == NULL) { | | 1015 | else if (eofmark == NULL) { |
1004 | USTPUTC(CTLQUOTEMARK, out); | | 1016 | USTPUTC(CTLQUOTEMARK, out); |
1005 | USTPUTC(c, out); | | 1017 | USTPUTC(c, out); |
1006 | if (varnest != 0) | | 1018 | if (varnest != 0) |
1007 | USTPUTC(CTLQUOTEEND, out); | | 1019 | USTPUTC(CTLQUOTEEND, out); |
1008 | break; | | 1020 | break; |
1009 | } | | 1021 | } |
1010 | USTPUTC(c, out); | | 1022 | USTPUTC(c, out); |
1011 | break; | | 1023 | break; |
1012 | case CSQUOTE: | | 1024 | case CSQUOTE: |
1013 | if (syntax != SQSYNTAX) { | | 1025 | if (syntax != SQSYNTAX) { |
| @@ -1058,26 +1070,27 @@ readtoken1(int firstc, char const *syn, | | | @@ -1058,26 +1070,27 @@ readtoken1(int firstc, char const *syn, |
1058 | USTPUTC(CTLQUOTEEND, out); | | 1070 | USTPUTC(CTLQUOTEEND, out); |
1059 | syntax = BASESYNTAX; | | 1071 | syntax = BASESYNTAX; |
1060 | CLRDBLQUOTE(); | | 1072 | CLRDBLQUOTE(); |
1061 | } else { | | 1073 | } else { |
1062 | syntax = DQSYNTAX; | | 1074 | syntax = DQSYNTAX; |
1063 | SETDBLQUOTE(); | | 1075 | SETDBLQUOTE(); |
1064 | USTPUTC(CTLQUOTEMARK, out); | | 1076 | USTPUTC(CTLQUOTEMARK, out); |
1065 | } | | 1077 | } |
1066 | break; | | 1078 | break; |
1067 | case CVAR: /* '$' */ | | 1079 | case CVAR: /* '$' */ |
1068 | PARSESUB(); /* parse substitution */ | | 1080 | PARSESUB(); /* parse substitution */ |
1069 | break; | | 1081 | break; |
1070 | case CENDVAR: /* CLOSEBRACE */ | | 1082 | case CENDVAR: /* CLOSEBRACE */ |
| | | 1083 | insub = 0; |
1071 | if (varnest > 0 && !ISDBLQUOTE()) { | | 1084 | if (varnest > 0 && !ISDBLQUOTE()) { |
1072 | varnest--; | | 1085 | varnest--; |
1073 | USTPUTC(CTLENDVAR, out); | | 1086 | USTPUTC(CTLENDVAR, out); |
1074 | } else { | | 1087 | } else { |
1075 | USTPUTC(c, out); | | 1088 | USTPUTC(c, out); |
1076 | } | | 1089 | } |
1077 | break; | | 1090 | break; |
1078 | case CLP: /* '(' in arithmetic */ | | 1091 | case CLP: /* '(' in arithmetic */ |
1079 | parenlevel++; | | 1092 | parenlevel++; |
1080 | USTPUTC(c, out); | | 1093 | USTPUTC(c, out); |
1081 | break; | | 1094 | break; |
1082 | case CRP: /* ')' in arithmetic */ | | 1095 | case CRP: /* ')' in arithmetic */ |
1083 | if (parenlevel > 0) { | | 1096 | if (parenlevel > 0) { |
| @@ -1330,27 +1343,29 @@ badsub: synerror("Bad substitution"); | | | @@ -1330,27 +1343,29 @@ badsub: synerror("Bad substitution"); |
1330 | subtype++; | | 1343 | subtype++; |
1331 | else | | 1344 | else |
1332 | pungetc(); | | 1345 | pungetc(); |
1333 | break; | | 1346 | break; |
1334 | } | | 1347 | } |
1335 | } | | 1348 | } |
1336 | } else { | | 1349 | } else { |
1337 | pungetc(); | | 1350 | pungetc(); |
1338 | } | | 1351 | } |
1339 | if (ISDBLQUOTE() || arinest) | | 1352 | if (ISDBLQUOTE() || arinest) |
1340 | flags |= VSQUOTE; | | 1353 | flags |= VSQUOTE; |
1341 | *(stackblock() + typeloc) = subtype | flags; | | 1354 | *(stackblock() + typeloc) = subtype | flags; |
1342 | if (subtype != VSNORMAL) { | | 1355 | if (subtype != VSNORMAL) { |
| | | 1356 | TRACE(("varnest=%d subtype=%d\n", varnest, subtype)); |
1343 | varnest++; | | 1357 | varnest++; |
| | | 1358 | insub = 1; |
1344 | if (varnest >= maxnest) { | | 1359 | if (varnest >= maxnest) { |
1345 | dblquotep = ckrealloc(dblquotep, maxnest / 8); | | 1360 | dblquotep = ckrealloc(dblquotep, maxnest / 8); |
1346 | dblquotep[(maxnest / 32) - 1] = 0; | | 1361 | dblquotep[(maxnest / 32) - 1] = 0; |
1347 | maxnest += 32; | | 1362 | maxnest += 32; |
1348 | } | | 1363 | } |
1349 | } | | 1364 | } |
1350 | } | | 1365 | } |
1351 | goto parsesub_return; | | 1366 | goto parsesub_return; |
1352 | } | | 1367 | } |
1353 | | | 1368 | |
1354 | | | 1369 | |
1355 | /* | | 1370 | /* |
1356 | * Called to parse command substitutions. Newstyle is set if the command | | 1371 | * Called to parse command substitutions. Newstyle is set if the command |