|
61 | 61 | # "else", and "fi" in if-then-else likewise must not end with "&&", thus
|
62 | 62 | # receives similar treatment.
|
63 | 63 | #
|
| 64 | +# Swallowing here-docs with arbitrary tags requires a bit of finesse. When a |
| 65 | +# line such as "cat <<EOF >out" is seen, the here-doc tag is moved to the front |
| 66 | +# of the line enclosed in angle brackets as a sentinel, giving "<EOF>cat >out". |
| 67 | +# As each subsequent line is read, it is appended to the target line and a |
| 68 | +# (whitespace-loose) back-reference match /^<(.*)>\n\1$/ is attempted to see if |
| 69 | +# the content inside "<...>" matches the entirety of the newly-read line. For |
| 70 | +# instance, if the next line read is "some data", when concatenated with the |
| 71 | +# target line, it becomes "<EOF>cat >out\nsome data", and a match is attempted |
| 72 | +# to see if "EOF" matches "some data". Since it doesn't, the next line is |
| 73 | +# attempted. When a line consisting of only "EOF" (and possible whitespace) is |
| 74 | +# encountered, it is appended to the target line giving "<EOF>cat >out\nEOF", |
| 75 | +# in which case the "EOF" inside "<...>" does match the text following the |
| 76 | +# newline, thus the closing here-doc tag has been found. The closing tag line |
| 77 | +# and the "<...>" prefix on the target line are then discarded, leaving just |
| 78 | +# the target line "cat >out". |
| 79 | +# |
64 | 80 | # To facilitate regression testing (and manual debugging), a ">" annotation is
|
65 | 81 | # applied to the line containing ")" which closes a subshell, ">>" to a line
|
66 | 82 | # closing a nested subshell, and ">>>" to a line closing both at once. This
|
|
78 | 94 |
|
79 | 95 | # here-doc -- swallow it to avoid false hits within its body (but keep the
|
80 | 96 | # command to which it was attached)
|
81 |
| -/<<[ ]*[-\\]*EOF[ ]*/ { |
82 |
| - s/[ ]*<<[ ]*[-\\]*EOF// |
83 |
| - h |
| 97 | +/<<[ ]*[-\\']*[A-Za-z0-9_]/ { |
| 98 | + s/^\(.*\)<<[ ]*[-\\']*\([A-Za-z0-9_][A-Za-z0-9_]*\)'*/<\2>\1<</ |
| 99 | + s/[ ]*<<// |
84 | 100 | :hereslurp
|
85 | 101 | N
|
86 |
| - s/.*\n// |
87 |
| - /^[ ]*EOF[ ]*$/!bhereslurp |
88 |
| - x |
| 102 | + /^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{ |
| 103 | + s/\n.*$// |
| 104 | + bhereslurp |
| 105 | + } |
| 106 | + s/^<[^>]*>// |
| 107 | + s/\n.*$// |
89 | 108 | }
|
90 | 109 |
|
91 | 110 | # one-liner "(...) &&"
|
@@ -132,16 +151,15 @@ s/.*\n//
|
132 | 151 | :slurp
|
133 | 152 | # incomplete line "...\"
|
134 | 153 | /\\$/bincomplete
|
135 |
| -# multi-line quoted string "...\n..." |
136 |
| -/^[^"]*"[^"]*$/bdqstring |
137 |
| -# multi-line quoted string '...\n...' (but not contraction in string "it's so") |
138 |
| -/^[^']*'[^']*$/{ |
| 154 | +# multi-line quoted string "...\n..."? |
| 155 | +/"/bdqstring |
| 156 | +# multi-line quoted string '...\n...'? (but not contraction in string "it's") |
| 157 | +/'/{ |
139 | 158 | /"[^'"]*'[^'"]*"/!bsqstring
|
140 | 159 | }
|
| 160 | +:folded |
141 | 161 | # here-doc -- swallow it
|
142 |
| -/<<[ ]*[-\\]*EOF/bheredoc |
143 |
| -/<<[ ]*[-\\]*EOT/bheredoc |
144 |
| -/<<[ ]*[-\\]*INPUT_END/bheredoc |
| 162 | +/<<[ ]*[-\\']*[A-Za-z0-9_]/bheredoc |
145 | 163 | # comment or empty line -- discard since final non-comment, non-empty line
|
146 | 164 | # before closing ")", "done", "elsif", "else", or "fi" will need to be
|
147 | 165 | # re-visited to drop "suspect" marking since final line of those constructs
|
@@ -199,7 +217,7 @@ s/.*\n//
|
199 | 217 | # "$(...)" -- command substitution; not closing ")"
|
200 | 218 | /\$([^)][^)]*)[^)]*$/bcheckchain
|
201 | 219 | # multi-line "$(...\n...)" -- command substitution; treat as nested subshell
|
202 |
| -/\$([ ]*$/bnest |
| 220 | +/\$([^)]*$/bnest |
203 | 221 | # "=(...)" -- Bash array assignment; not closing ")"
|
204 | 222 | /=(/bcheckchain
|
205 | 223 | # closing "...) &&"
|
|
232 | 250 | s/\\\n//
|
233 | 251 | bslurp
|
234 | 252 |
|
235 |
| -# found multi-line double-quoted string "...\n..." -- slurp until end of string |
| 253 | +# check for multi-line double-quoted string "...\n..." -- fold to one line |
236 | 254 | :dqstring
|
237 |
| -s/"//g |
| 255 | +# remove all quote pairs |
| 256 | +s/"\([^"]*\)"/@!\1@!/g |
| 257 | +# done if no dangling quote |
| 258 | +/"/!bdqdone |
| 259 | +# otherwise, slurp next line and try again |
238 | 260 | N
|
239 | 261 | s/\n//
|
240 |
| -/"/!bdqstring |
241 |
| -bcheckchain |
| 262 | +bdqstring |
| 263 | +:dqdone |
| 264 | +s/@!/"/g |
| 265 | +bfolded |
242 | 266 |
|
243 |
| -# found multi-line single-quoted string '...\n...' -- slurp until end of string |
| 267 | +# check for multi-line single-quoted string '...\n...' -- fold to one line |
244 | 268 | :sqstring
|
245 |
| -s/'//g |
| 269 | +# remove all quote pairs |
| 270 | +s/'\([^']*\)'/@!\1@!/g |
| 271 | +# done if no dangling quote |
| 272 | +/'/!bsqdone |
| 273 | +# otherwise, slurp next line and try again |
246 | 274 | N
|
247 | 275 | s/\n//
|
248 |
| -/'/!bsqstring |
249 |
| -bcheckchain |
| 276 | +bsqstring |
| 277 | +:sqdone |
| 278 | +s/@!/'/g |
| 279 | +bfolded |
250 | 280 |
|
251 | 281 | # found here-doc -- swallow it to avoid false hits within its body (but keep
|
252 |
| -# the command to which it was attached); take care to handle here-docs nested |
253 |
| -# within here-docs by only recognizing closing tag matching outer here-doc |
254 |
| -# opening tag |
| 282 | +# the command to which it was attached) |
255 | 283 | :heredoc
|
256 |
| -/EOF/{ s/[ ]*<<[ ]*[-\\]*EOF//; s/^/EOF/; } |
257 |
| -/EOT/{ s/[ ]*<<[ ]*[-\\]*EOT//; s/^/EOT/; } |
258 |
| -/INPUT_END/{ s/[ ]*<<[ ]*[-\\]*INPUT_END//; s/^/INPUT_END/; } |
| 284 | +s/^\(.*\)<<[ ]*[-\\']*\([A-Za-z0-9_][A-Za-z0-9_]*\)'*/<\2>\1<</ |
| 285 | +s/[ ]*<<// |
259 | 286 | :hereslurpsub
|
260 | 287 | N
|
261 |
| -/^EOF.*\n[ ]*EOF[ ]*$/bhereclose |
262 |
| -/^EOT.*\n[ ]*EOT[ ]*$/bhereclose |
263 |
| -/^INPUT_END.*\n[ ]*INPUT_END[ ]*$/bhereclose |
264 |
| -bhereslurpsub |
265 |
| -:hereclose |
266 |
| -s/^EOF// |
267 |
| -s/^EOT// |
268 |
| -s/^INPUT_END// |
| 288 | +/^<\([^>]*\)>.*\n[ ]*\1[ ]*$/!{ |
| 289 | + s/\n.*$// |
| 290 | + bhereslurpsub |
| 291 | +} |
| 292 | +s/^<[^>]*>// |
269 | 293 | s/\n.*$//
|
270 |
| -bcheckchain |
| 294 | +bfolded |
271 | 295 |
|
272 | 296 | # found "case ... in" -- pass through untouched
|
273 | 297 | :case
|
|
0 commit comments