1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
BASH PATCH REPORT
=================
Bash-Release: 4.0
Patch-ID: bash40-001
Bug-Reported-by: Mike Frysinger <vapier@gentoo.org>
Bug-Reference-ID: <200902211821.42188.vapier@gentoo.org>
Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2009-02/msg00147.html
Bug-Description:
Bash has problems parsing certain constructs inside Posix-style $(...)
command substitutions, mostly with backslash-quoting and reserved word
recognition. This is an issue because the contents are parsed at the
time the word containing the command substitution is read.
Patch:
*** ../bash-4.0/parse.y 2009-01-08 08:29:12.000000000 -0500
--- parse.y 2009-03-06 20:32:35.000000000 -0500
***************
*** 2928,2931 ****
--- 2932,2936 ----
#define LEX_HEREDELIM 0x100 /* reading here-doc delimiter */
#define LEX_STRIPDOC 0x200 /* <<- strip tabs from here doc delim */
+ #define LEX_INWORD 0x400
#define COMSUB_META(ch) ((ch) == ';' || (ch) == '&' || (ch) == '|')
***************
*** 3180,3184 ****
int *lenp, flags;
{
! int count, ch, peekc, tflags, lex_rwlen, lex_firstind;
int nestlen, ttranslen, start_lineno;
char *ret, *nestret, *ttrans, *heredelim;
--- 3188,3192 ----
int *lenp, flags;
{
! int count, ch, peekc, tflags, lex_rwlen, lex_wlen, lex_firstind;
int nestlen, ttranslen, start_lineno;
char *ret, *nestret, *ttrans, *heredelim;
***************
*** 3201,3205 ****
start_lineno = line_number;
! lex_rwlen = 0;
heredelim = 0;
--- 3209,3213 ----
start_lineno = line_number;
! lex_rwlen = lex_wlen = 0;
heredelim = 0;
***************
*** 3268,3271 ****
--- 3276,3319 ----
}
+ if (tflags & LEX_PASSNEXT) /* last char was backslash */
+ {
+ /*itrace("parse_comsub:%d: lex_passnext -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+ tflags &= ~LEX_PASSNEXT;
+ if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
+ {
+ if (retind > 0)
+ retind--; /* swallow previously-added backslash */
+ continue;
+ }
+
+ RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+ if MBTEST(ch == CTLESC || ch == CTLNUL)
+ ret[retind++] = CTLESC;
+ ret[retind++] = ch;
+ continue;
+ }
+
+ /* If this is a shell break character, we are not in a word. If not,
+ we either start or continue a word. */
+ if MBTEST(shellbreak (ch))
+ {
+ tflags &= ~LEX_INWORD;
+ /*itrace("parse_comsub:%d: lex_inword -> 0 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+ }
+ else
+ {
+ if (tflags & LEX_INWORD)
+ {
+ lex_wlen++;
+ /*itrace("parse_comsub:%d: lex_inword == 1 ch = `%c' lex_wlen = %d (%d)", line_number, ch, lex_wlen, __LINE__);*/
+ }
+ else
+ {
+ /*itrace("parse_comsub:%d: lex_inword -> 1 ch = `%c' (%d)", line_number, ch, __LINE__);*/
+ tflags |= LEX_INWORD;
+ lex_wlen = 0;
+ }
+ }
+
/* Skip whitespace */
if MBTEST(shellblank (ch) && lex_rwlen == 0)
***************
*** 3400,3428 ****
}
else
! ch = peekc; /* fall through and continue XXX - this skips comments if peekc == '#' */
}
! /* Not exactly right yet, should handle shell metacharacters, too. If
! any changes are made to this test, make analogous changes to subst.c:
! extract_delimited_string(). */
! else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (retind == 0 || ret[retind-1] == '\n' || shellblank (ret[retind - 1])))
tflags |= LEX_INCOMMENT;
! if (tflags & LEX_PASSNEXT) /* last char was backslash */
! {
! tflags &= ~LEX_PASSNEXT;
! if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
! {
! if (retind > 0)
! retind--; /* swallow previously-added backslash */
! continue;
! }
!
! RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
! if MBTEST(ch == CTLESC || ch == CTLNUL)
! ret[retind++] = CTLESC;
! ret[retind++] = ch;
! continue;
! }
! else if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */
{
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
--- 3442,3454 ----
}
else
! ch = peekc; /* fall through and continue XXX */
}
! else if MBTEST((tflags & LEX_CKCOMMENT) && (tflags & LEX_INCOMMENT) == 0 && ch == '#' && (((tflags & LEX_RESWDOK) && lex_rwlen == 0) || ((tflags & LEX_INWORD) && lex_wlen == 0)))
! {
! /*itrace("parse_comsub:%d: lex_incomment -> 1 (%d)", line_number, __LINE__);*/
tflags |= LEX_INCOMMENT;
+ }
! if MBTEST(ch == CTLESC || ch == CTLNUL) /* special shell escapes */
{
RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
*** ../bash-4.0/patchlevel.h 2009-01-04 14:32:40.000000000 -0500
--- patchlevel.h 2009-02-22 16:11:31.000000000 -0500
***************
*** 26,30 ****
looks for to find the patch level (for the sccs version string). */
! #define PATCHLEVEL 0
#endif /* _PATCHLEVEL_H_ */
--- 26,30 ----
looks for to find the patch level (for the sccs version string). */
! #define PATCHLEVEL 1
#endif /* _PATCHLEVEL_H_ */
|