hush: fix backslash and terminator handling in <<[-]["]heredoc["]

function                                             old     new   delta
parse_stream                                        2339    2395     +56
expand_pseudo_dquoted                                104     118     +14
parse_stream_dquoted                                 296     300      +4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 74/0)               Total: 74 bytes

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2010-09-06 11:27:32 +02:00
parent c49d2d9793
commit 77b32ccbf2
3 changed files with 92 additions and 5 deletions

View File

@ -3162,17 +3162,20 @@ static int redirect_opt_num(o_string *o)
static char *fetch_till_str(o_string *as_string, static char *fetch_till_str(o_string *as_string,
struct in_str *input, struct in_str *input,
const char *word, const char *word,
int skip_tabs) int heredoc_flags)
{ {
o_string heredoc = NULL_O_STRING; o_string heredoc = NULL_O_STRING;
int past_EOL = 0; int past_EOL = 0;
int prev = 0; /* not \ */
int ch; int ch;
goto jump_in; goto jump_in;
while (1) { while (1) {
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
if (ch == '\n') { if (ch == '\n'
&& ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\')
) {
if (strcmp(heredoc.data + past_EOL, word) == 0) { if (strcmp(heredoc.data + past_EOL, word) == 0) {
heredoc.data[past_EOL] = '\0'; heredoc.data[past_EOL] = '\0';
debug_printf_parse("parsed heredoc '%s'\n", heredoc.data); debug_printf_parse("parsed heredoc '%s'\n", heredoc.data);
@ -3185,7 +3188,7 @@ static char *fetch_till_str(o_string *as_string,
do { do {
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
} while (skip_tabs && ch == '\t'); } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
} while (ch == '\n'); } while (ch == '\n');
} }
if (ch == EOF) { if (ch == EOF) {
@ -3194,6 +3197,7 @@ static char *fetch_till_str(o_string *as_string,
} }
o_addchr(&heredoc, ch); o_addchr(&heredoc, ch);
nommu_addchr(as_string, 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_type = REDIRECT_HEREDOC2;
/* redir->rd_dup is (ab)used to indicate <<- */ /* redir->rd_dup is (ab)used to indicate <<- */
p = fetch_till_str(&ctx->as_string, input, p = fetch_till_str(&ctx->as_string, input,
redir->rd_filename, redir->rd_dup & HEREDOC_SKIPTABS); redir->rd_filename, redir->rd_dup);
if (!p) { if (!p) {
syntax_error("unexpected EOF in here document"); syntax_error("unexpected EOF in here document");
return 1; return 1;
@ -3778,8 +3782,9 @@ static int parse_stream_dquoted(o_string *as_string,
* only when followed by one of the following characters: * only when followed by one of the following characters:
* $, `, ", \, or <newline>. A double quote may be quoted * $, `, ", \, or <newline>. A double quote may be quoted
* within double quotes by preceding it with a backslash." * 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); ch = i_getch(input);
if (ch != '\n') { if (ch != '\n') {
o_addqchr(dest, ch); o_addqchr(dest, ch);
@ -4412,6 +4417,7 @@ static char *expand_pseudo_dquoted(const char *str)
o_string dest = NULL_O_STRING; o_string dest = NULL_O_STRING;
if (!strchr(str, '$') if (!strchr(str, '$')
&& !strchr(str, '\\')
#if ENABLE_HUSH_TICK #if ENABLE_HUSH_TICK
&& !strchr(str, '`') && !strchr(str, '`')
#endif #endif

View File

@ -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

View File

@ -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: $?"