summaryrefslogtreecommitdiff
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 ef46372..e8aef2d 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -3162,17 +3162,20 @@ static int redirect_opt_num(o_string *o)
static char *fetch_till_str(o_string *as_string,
struct in_str *input,
const char *word,
- int skip_tabs)
+ int heredoc_flags)
{
o_string heredoc = NULL_O_STRING;
int past_EOL = 0;
+ int prev = 0; /* not \ */
int ch;
goto jump_in;
while (1) {
ch = i_getch(input);
nommu_addchr(as_string, ch);
- if (ch == '\n') {
+ if (ch == '\n'
+ && ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\')
+ ) {
if (strcmp(heredoc.data + past_EOL, word) == 0) {
heredoc.data[past_EOL] = '\0';
debug_printf_parse("parsed heredoc '%s'\n", heredoc.data);
@@ -3185,7 +3188,7 @@ static char *fetch_till_str(o_string *as_string,
do {
ch = i_getch(input);
nommu_addchr(as_string, ch);
- } while (skip_tabs && ch == '\t');
+ } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
} while (ch == '\n');
}
if (ch == EOF) {
@@ -3194,6 +3197,7 @@ static char *fetch_till_str(o_string *as_string,
}
o_addchr(&heredoc, ch);
nommu_addchr(as_string, ch);
+ prev = ch;
}
}
@@ -3223,7 +3227,7 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
redir->rd_type = REDIRECT_HEREDOC2;
/* redir->rd_dup is (ab)used to indicate <<- */
p = fetch_till_str(&ctx->as_string, input,
- redir->rd_filename, redir->rd_dup & HEREDOC_SKIPTABS);
+ redir->rd_filename, redir->rd_dup);
if (!p) {
syntax_error("unexpected EOF in here document");
return 1;
@@ -3778,8 +3782,9 @@ static int parse_stream_dquoted(o_string *as_string,
* only when followed by one of the following characters:
* $, `, ", \, or <newline>. A double quote may be quoted
* within double quotes by preceding it with a backslash."
+ * NB: in (unquoted) heredoc, above does not apply to ".
*/
- if (strchr("$`\"\\\n", next) != NULL) {
+ if (next == dquote_end || strchr("$`\\\n", next) != NULL) {
ch = i_getch(input);
if (ch != '\n') {
o_addqchr(dest, ch);
@@ -4412,6 +4417,7 @@ static char *expand_pseudo_dquoted(const char *str)
o_string dest = NULL_O_STRING;
if (!strchr(str, '$')
+ && !strchr(str, '\\')
#if ENABLE_HUSH_TICK
&& !strchr(str, '`')
#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 0000000..234c017
--- /dev/null
+++ b/shell/hush_test/hush-misc/heredoc_backslash1.right
@@ -0,0 +1,27 @@
+Quoted heredoc:
+a\
+ b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+c\
+
+Unquoted heredoc:
+a b
+ 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+ -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+cEOF2
+
+Quoted -heredoc:
+a\
+b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+c\
+
+Unquoted -heredoc:
+a b
+ 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+-qwerty-\t-\-\"-\'-`-\--\z-\*-\?-
+cEOF4
+
+Done: 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 0000000..b70467d
--- /dev/null
+++ b/shell/hush_test/hush-misc/heredoc_backslash1.tests
@@ -0,0 +1,54 @@
+# Test for correct handling of backslashes.
+# Note that some lines in each heredoc start with a tab.
+
+a=qwerty
+
+echo Quoted heredoc:
+cat <<"EOF1"
+a\
+ b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+c\
+EOF1
+echo
+
+echo Unquoted heredoc:
+cat <<EOF2
+a\
+ b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+c\
+EOF2
+EOF2
+echo
+
+echo Quoted -heredoc:
+cat <<-"EOF3"
+a\
+ b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+c\
+ EOF3
+# In -heredoc case the marker is detected even if it is indented.
+echo
+
+echo Unquoted -heredoc:
+cat <<-EOF4
+a\
+ b
+ 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+ -$a-\t-\\-\"-\'-\`-\--\z-\*-\?-
+c\
+EOF4
+ EOF4
+# The marker is not detected if preceding line ends in backslash.
+# TODO: marker should be detected even if it is split by line continuation:
+# EOF\
+# 4
+# but currently hush doesn't do it. (Tab before "4" is not allowed, though.)
+echo
+
+echo "Done: $?"