Sun Nov 14 19:43:38 2010 UTC ()
- Fix a couple of bugs to make the following two echo statements print the
  same output as they should:

    line='#define bindir "/usr/bin" /* comment */'
    echo "${line%%/\**}"
    echo ${line%%/\**}

1. ISDBLQUOTE() was not working properly for non VSNORMAL expansions because
   varnest was incremented before the variable was completely parsed. Add
   an insub adjustment to keep track of that.
2. When we have a quoted backslash, we need to escape twice, because one
   level of escaping will be stripped later. (XXX: Do that when insub == 1
   only?)

- Make macros statements


(christos)
diff -r1.74 -r1.75 src/bin/sh/parser.c

cvs diff -r1.74 -r1.75 src/bin/sh/parser.c (expand / switch to unified diff)

--- src/bin/sh/parser.c 2009/01/18 00:30:54 1.74
+++ src/bin/sh/parser.c 2010/11/14 19:43:38 1.75
@@ -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
38static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; 38static 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
914STATIC int 921STATIC int
915readtoken1(int firstc, char const *syn, char *eofmark, int striptabs) 922readtoken1(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