aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c16
-rw-r--r--shell/hush_test/hush-misc/heredoc_backslash1.right27
-rwxr-xr-xshell/hush_test/hush-misc/heredoc_backslash1.tests54
3 files changed, 92 insertions, 5 deletions
diff --git a/shell/hush.c b/shell/hush.c
index ef46372de..e8aef2d7e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -3162,17 +3162,20 @@ static int redirect_opt_num(o_string *o)
3162static char *fetch_till_str(o_string *as_string, 3162static char *fetch_till_str(o_string *as_string,
3163 struct in_str *input, 3163 struct in_str *input,
3164 const char *word, 3164 const char *word,
3165 int skip_tabs) 3165 int heredoc_flags)
3166{ 3166{
3167 o_string heredoc = NULL_O_STRING; 3167 o_string heredoc = NULL_O_STRING;
3168 int past_EOL = 0; 3168 int past_EOL = 0;
3169 int prev = 0; /* not \ */
3169 int ch; 3170 int ch;
3170 3171
3171 goto jump_in; 3172 goto jump_in;
3172 while (1) { 3173 while (1) {
3173 ch = i_getch(input); 3174 ch = i_getch(input);
3174 nommu_addchr(as_string, ch); 3175 nommu_addchr(as_string, ch);
3175 if (ch == '\n') { 3176 if (ch == '\n'
3177 && ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\')
3178 ) {
3176 if (strcmp(heredoc.data + past_EOL, word) == 0) { 3179 if (strcmp(heredoc.data + past_EOL, word) == 0) {
3177 heredoc.data[past_EOL] = '\0'; 3180 heredoc.data[past_EOL] = '\0';
3178 debug_printf_parse("parsed heredoc '%s'\n", heredoc.data); 3181 debug_printf_parse("parsed heredoc '%s'\n", heredoc.data);
@@ -3185,7 +3188,7 @@ static char *fetch_till_str(o_string *as_string,
3185 do { 3188 do {
3186 ch = i_getch(input); 3189 ch = i_getch(input);
3187 nommu_addchr(as_string, ch); 3190 nommu_addchr(as_string, ch);
3188 } while (skip_tabs && ch == '\t'); 3191 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
3189 } while (ch == '\n'); 3192 } while (ch == '\n');
3190 } 3193 }
3191 if (ch == EOF) { 3194 if (ch == EOF) {
@@ -3194,6 +3197,7 @@ static char *fetch_till_str(o_string *as_string,
3194 } 3197 }
3195 o_addchr(&heredoc, ch); 3198 o_addchr(&heredoc, ch);
3196 nommu_addchr(as_string, ch); 3199 nommu_addchr(as_string, ch);
3200 prev = ch;
3197 } 3201 }
3198} 3202}
3199 3203
@@ -3223,7 +3227,7 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
3223 redir->rd_type = REDIRECT_HEREDOC2; 3227 redir->rd_type = REDIRECT_HEREDOC2;
3224 /* redir->rd_dup is (ab)used to indicate <<- */ 3228 /* redir->rd_dup is (ab)used to indicate <<- */
3225 p = fetch_till_str(&ctx->as_string, input, 3229 p = fetch_till_str(&ctx->as_string, input,
3226 redir->rd_filename, redir->rd_dup & HEREDOC_SKIPTABS); 3230 redir->rd_filename, redir->rd_dup);
3227 if (!p) { 3231 if (!p) {
3228 syntax_error("unexpected EOF in here document"); 3232 syntax_error("unexpected EOF in here document");
3229 return 1; 3233 return 1;
@@ -3778,8 +3782,9 @@ static int parse_stream_dquoted(o_string *as_string,
3778 * only when followed by one of the following characters: 3782 * only when followed by one of the following characters:
3779 * $, `, ", \, or <newline>. A double quote may be quoted 3783 * $, `, ", \, or <newline>. A double quote may be quoted
3780 * within double quotes by preceding it with a backslash." 3784 * within double quotes by preceding it with a backslash."
3785 * NB: in (unquoted) heredoc, above does not apply to ".
3781 */ 3786 */
3782 if (strchr("$`\"\\\n", next) != NULL) { 3787 if (next == dquote_end || strchr("$`\\\n", next) != NULL) {
3783 ch = i_getch(input); 3788 ch = i_getch(input);
3784 if (ch != '\n') { 3789 if (ch != '\n') {
3785 o_addqchr(dest, ch); 3790 o_addqchr(dest, ch);
@@ -4412,6 +4417,7 @@ static char *expand_pseudo_dquoted(const char *str)
4412 o_string dest = NULL_O_STRING; 4417 o_string dest = NULL_O_STRING;
4413 4418
4414 if (!strchr(str, '$') 4419 if (!strchr(str, '$')
4420 && !strchr(str, '\\')
4415#if ENABLE_HUSH_TICK 4421#if ENABLE_HUSH_TICK
4416 && !strchr(str, '`') 4422 && !strchr(str, '`')
4417#endif 4423#endif
diff --git a/shell/hush_test/hush-misc/heredoc_backslash1.right b/shell/hush_test/hush-misc/heredoc_backslash1.right
new file mode 100644
index 000000000..234c0172f
--- /dev/null
+++ b/shell/hush_test/hush-misc/heredoc_backslash1.right
@@ -0,0 +1,27 @@
1Quoted heredoc:
2a\
3 b
4 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
5 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
6c\
7
8Unquoted heredoc:
9a b
10 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
11 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
12cEOF2
13
14Quoted -heredoc:
15a\
16b
17 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
18-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
19c\
20
21Unquoted -heredoc:
22a b
23 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
24-qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
25cEOF4
26
27Done: 0
diff --git a/shell/hush_test/hush-misc/heredoc_backslash1.tests b/shell/hush_test/hush-misc/heredoc_backslash1.tests
new file mode 100755
index 000000000..b70467df8
--- /dev/null
+++ b/shell/hush_test/hush-misc/heredoc_backslash1.tests
@@ -0,0 +1,54 @@
1# Test for correct handling of backslashes.
2# Note that some lines in each heredoc start with a tab.
3
4a=qwerty
5
6echo Quoted heredoc:
7cat <<"EOF1"
8a\
9 b
10 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
11 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
12c\
13EOF1
14echo
15
16echo Unquoted heredoc:
17cat <<EOF2
18a\
19 b
20 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
21 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
22c\
23EOF2
24EOF2
25echo
26
27echo Quoted -heredoc:
28cat <<-"EOF3"
29a\
30 b
31 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
32 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
33c\
34 EOF3
35# In -heredoc case the marker is detected even if it is indented.
36echo
37
38echo Unquoted -heredoc:
39cat <<-EOF4
40a\
41 b
42 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
43 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
44c\
45EOF4
46 EOF4
47# The marker is not detected if preceding line ends in backslash.
48# TODO: marker should be detected even if it is split by line continuation:
49# EOF\
50# 4
51# but currently hush doesn't do it. (Tab before "4" is not allowed, though.)
52echo
53
54echo "Done: $?"