fdprintf(2, " '%s'", *argv);
argv++;
}
+ if (command->redirects)
+ fdprintf(2, " {redir}");
fdprintf(2, "\n");
prn++;
}
/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs
* and load them all. There should be exactly heredoc_cnt of them.
*/
-static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_str *input)
+#if BB_MMU
+#define fetch_heredocs(as_string, pi, heredoc_cnt, input) \
+ fetch_heredocs(pi, heredoc_cnt, input)
+#endif
+static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, struct in_str *input)
{
- struct pipe *pi = ctx->list_head;
-
while (pi && heredoc_cnt) {
int i;
struct command *cmd = pi->cmds;
redir->rd_type = REDIRECT_HEREDOC2;
/* redir->rd_dup is (ab)used to indicate <<- */
- p = fetch_till_str(&ctx->as_string, input,
+ p = fetch_till_str(as_string, input,
redir->rd_filename, redir->rd_dup);
if (!p) {
syntax_error("unexpected EOF in here document");
- return 1;
+ return -1;
}
free(redir->rd_filename);
redir->rd_filename = p;
}
redir = redir->next;
}
+ if (cmd->group) {
+ //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
+ heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
+ //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
+ if (heredoc_cnt < 0)
+ return heredoc_cnt; /* error */
+ }
cmd++;
}
pi = pi->next;
}
- /* Should be 0. If it isn't, it's a parse error */
- if (HUSH_DEBUG && heredoc_cnt)
- bb_error_msg_and_die("heredoc BUG 2");
- return 0;
+ return heredoc_cnt;
}
static int run_list(struct pipe *pi);
#if BB_MMU
-#define parse_stream(pstring, input, end_trigger) \
- parse_stream(input, end_trigger)
+#define parse_stream(pstring, heredoc_cnt_ptr, input, end_trigger) \
+ parse_stream(heredoc_cnt_ptr, input, end_trigger)
#endif
static struct pipe *parse_stream(char **pstring,
+ int *heredoc_cnt_ptr,
struct in_str *input,
int end_trigger);
-
+/* Returns number of heredocs not yet consumed,
+ * or -1 on error.
+ */
static int parse_group(struct parse_context *ctx,
- struct in_str *input, int ch)
+ struct in_str *input, int ch)
{
/* ctx->word contains characters seen prior to ( or {.
* Typically it's empty, but for function defs,
char *as_string = NULL;
#endif
struct pipe *pipe_list;
+ int heredoc_cnt = 0;
int endch;
struct command *command = ctx->command;
if (ch == '(' && !ctx->word.has_quoted_part) {
if (ctx->word.length)
if (done_word(ctx))
- return 1;
+ return -1;
if (!command->argv)
goto skip; /* (... */
if (command->argv[1]) { /* word word ... (... */
syntax_error_unexpected_ch('(');
- return 1;
+ return -1;
}
/* it is "word(..." or "word (..." */
do
while (ch == ' ' || ch == '\t');
if (ch != ')') {
syntax_error_unexpected_ch(ch);
- return 1;
+ return -1;
}
nommu_addchr(&ctx->as_string, ch);
do
while (ch == ' ' || ch == '\t' || ch == '\n');
if (ch != '{' && ch != '(') {
syntax_error_unexpected_ch(ch);
- return 1;
+ return -1;
}
nommu_addchr(&ctx->as_string, ch);
command->cmd_type = CMD_FUNCDEF;
|| ctx->word.has_quoted_part /* ""{... */
) {
syntax_error(NULL);
- debug_printf_parse("parse_group return 1: "
+ debug_printf_parse("parse_group return -1: "
"syntax error, groups and arglists don't mix\n");
- return 1;
+ return -1;
}
#endif
&& ch != '(' /* but "{(..." is allowed (without whitespace) */
) {
syntax_error_unexpected_ch(ch);
- return 1;
+ return -1;
}
if (ch != '(') {
ch = i_getch(input);
}
}
- pipe_list = parse_stream(&as_string, input, endch);
+ debug_printf_heredoc("calling parse_stream, heredoc_cnt:%d\n", heredoc_cnt);
+ pipe_list = parse_stream(&as_string, &heredoc_cnt, input, endch);
+ debug_printf_heredoc("parse_stream returned: heredoc_cnt:%d\n", heredoc_cnt);
#if !BB_MMU
if (as_string)
o_addstr(&ctx->as_string, as_string);
/* parse_stream already emitted error msg */
if (!BB_MMU)
free(as_string);
- debug_printf_parse("parse_group return 1: "
+ debug_printf_parse("parse_group return -1: "
"parse_stream returned %p\n", pipe_list);
- return 1;
+ return -1;
}
#if !BB_MMU
as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
command->group = pipe_list;
- debug_printf_parse("parse_group return 0\n");
- return 0;
+ debug_printf_parse("parse_group return %d\n", heredoc_cnt);
+ return heredoc_cnt;
/* command remains "open", available for possible redirects */
#undef as_string
}
* or return ERR_PTR.
*/
static struct pipe *parse_stream(char **pstring,
+ int *heredoc_cnt_ptr,
struct in_str *input,
int end_trigger)
{
else
o_free(&ctx.as_string);
#endif
+ // heredoc_cnt must be 0 here anyway
+ //if (heredoc_cnt_ptr)
+ // *heredoc_cnt_ptr = heredoc_cnt;
debug_leave();
+ debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
debug_printf_parse("parse_stream return %p\n", pi);
return pi;
}
done_pipe(&ctx, PIPE_SEQ);
debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt);
if (heredoc_cnt) {
- if (fetch_heredocs(heredoc_cnt, &ctx, input)) {
+ heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
+ if (heredoc_cnt != 0)
goto parse_error;
- }
- heredoc_cnt = 0;
}
ctx.is_assignment = MAYBE_ASSIGNMENT;
debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
)
#endif
) {
- if (heredoc_cnt) {
- /* This is technically valid:
- * { cat <<HERE; }; echo Ok
- * heredoc
- * heredoc
- * HERE
- * but we don't support this.
- * We require heredoc to be in enclosing {}/(),
- * if any.
- */
- syntax_error_unterm_str("here document");
- goto parse_error;
- }
if (done_word(&ctx)) {
goto parse_error;
}
syntax_error_unexpected_ch(ch);
goto parse_error2;
}
+ if (heredoc_cnt_ptr)
+ *heredoc_cnt_ptr = heredoc_cnt;
+ debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
debug_printf_parse("parse_stream return %p: "
"end_trigger char found\n",
ctx.list_head);
continue; /* get next char */
}
#endif
- case '{':
- if (parse_group(&ctx, input, ch) != 0) {
+ /* fall through */
+ case '{': {
+ int n = parse_group(&ctx, input, ch);
+ if (n < 0) {
goto parse_error;
}
+ debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
+ heredoc_cnt += n;
goto new_cmd;
+ }
case ')':
#if ENABLE_HUSH_CASE
if (ctx.ctx_res_w == RES_MATCH)
goto case_semi;
#endif
+
case '}':
/* proper use of this character is caught by end_trigger:
* if we see {, we call parse_group(..., end_trigger='}')
IF_HAS_KEYWORDS(pctx = p2;)
} while (HAS_KEYWORDS && pctx);
- o_free_and_set_NULL(&ctx.word);
+ o_free(&ctx.word);
#if !BB_MMU
if (pstring)
*pstring = NULL;
debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
}
#endif
- pipe_list = parse_stream(NULL, inp, end_trigger);
+ pipe_list = parse_stream(NULL, NULL, inp, end_trigger);
if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */
/* If we are in "big" script
* (not in `cmd` or something similar)...