aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-03 16:49:04 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-03 16:49:04 +0000
commitb6e6556b31e76afdbe956886e45b1168d4a49de6 (patch)
tree91e5660b6751ecd8a28661ccc8f84419cd3b13ad /shell
parent240c255d8b349f06c94cb3afc24c85b6c38b6608 (diff)
downloadbusybox-w32-b6e6556b31e76afdbe956886e45b1168d4a49de6.tar.gz
busybox-w32-b6e6556b31e76afdbe956886e45b1168d4a49de6.tar.bz2
busybox-w32-b6e6556b31e76afdbe956886e45b1168d4a49de6.zip
hush: improve parse_stream: does not require parsing context struct;
cleans up on syntax errors (we used to leak memory in this case); much simplified interface to the rest of hush. function old new delta parse_stream 1204 1447 +243 done_word 658 669 +11 static_get 22 28 +6 builtin_source 84 89 +5 parse_and_run_file 27 30 +3 parse_and_run_string 31 27 -4 builtin_eval 55 50 -5 hush_main 991 985 -6 free_pipe_list 39 31 -8 free_pipe 210 189 -21 expand_variables 2242 2199 -43 parse_and_run_stream 289 153 -136 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/7 up/down: 268/-223) Total: 45 bytes
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c496
-rw-r--r--shell/hush_test/hush-misc/syntax_err_negate.right2
2 files changed, 268 insertions, 230 deletions
diff --git a/shell/hush.c b/shell/hush.c
index aa05e3a83..e0c1fde6b 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -217,24 +217,24 @@ void xxfree(void *ptr);
217void *xxmalloc(int lineno, size_t size) 217void *xxmalloc(int lineno, size_t size)
218{ 218{
219 void *ptr = xmalloc((size + 0xff) & ~0xff); 219 void *ptr = xmalloc((size + 0xff) & ~0xff);
220 fprintf(stderr, "line %d: malloc %p\n", lineno, ptr); 220 fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
221 return ptr; 221 return ptr;
222} 222}
223void *xxrealloc(int lineno, void *ptr, size_t size) 223void *xxrealloc(int lineno, void *ptr, size_t size)
224{ 224{
225 ptr = xrealloc(ptr, (size + 0xff) & ~0xff); 225 ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
226 fprintf(stderr, "line %d: realloc %p\n", lineno, ptr); 226 fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
227 return ptr; 227 return ptr;
228} 228}
229char *xxstrdup(int lineno, const char *str) 229char *xxstrdup(int lineno, const char *str)
230{ 230{
231 char *ptr = xstrdup(str); 231 char *ptr = xstrdup(str);
232 fprintf(stderr, "line %d: strdup %p\n", lineno, ptr); 232 fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
233 return ptr; 233 return ptr;
234} 234}
235void xxfree(void *ptr) 235void xxfree(void *ptr)
236{ 236{
237 fprintf(stderr, "free %p\n", ptr); 237 fdprintf(2, "free %p\n", ptr);
238 free(ptr); 238 free(ptr);
239} 239}
240#define xmalloc(s) xxmalloc(__LINE__, s) 240#define xmalloc(s) xxmalloc(__LINE__, s)
@@ -244,12 +244,13 @@ void xxfree(void *ptr)
244#endif 244#endif
245 245
246 246
247#define ERR_PTR ((void*)(long)1)
248
247static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR; 249static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;
248 250
249#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 251#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
250 252
251#define SPECIAL_VAR_SYMBOL 3 253#define SPECIAL_VAR_SYMBOL 3
252#define PARSEFLAG_EXIT_FROM_LOOP 1
253 254
254typedef enum redir_type { 255typedef enum redir_type {
255 REDIRECT_INPUT = 1, 256 REDIRECT_INPUT = 1,
@@ -1209,8 +1210,10 @@ static void arith_set_local_var(const char *name, const char *val, int flags)
1209static int static_get(struct in_str *i) 1210static int static_get(struct in_str *i)
1210{ 1211{
1211 int ch = *i->p++; 1212 int ch = *i->p++;
1212 if (ch == '\0') return EOF; 1213 if (ch != '\0')
1213 return ch; 1214 return ch;
1215 i->p--;
1216 return EOF;
1214} 1217}
1215 1218
1216static int static_peek(struct in_str *i) 1219static int static_peek(struct in_str *i)
@@ -2147,18 +2150,18 @@ static void restore_redirects(int squirrel[])
2147#define free_pipe_list(head, indent) free_pipe_list(head) 2150#define free_pipe_list(head, indent) free_pipe_list(head)
2148#define free_pipe(pi, indent) free_pipe(pi) 2151#define free_pipe(pi, indent) free_pipe(pi)
2149#endif 2152#endif
2150static int free_pipe_list(struct pipe *head, int indent); 2153static void free_pipe_list(struct pipe *head, int indent);
2151 2154
2152/* return code is the exit status of the pipe */ 2155/* return code is the exit status of the pipe */
2153static int free_pipe(struct pipe *pi, int indent) 2156static void free_pipe(struct pipe *pi, int indent)
2154{ 2157{
2155 char **p; 2158 char **p;
2156 struct command *command; 2159 struct command *command;
2157 struct redir_struct *r, *rnext; 2160 struct redir_struct *r, *rnext;
2158 int a, i, ret_code = 0; 2161 int a, i;
2159 2162
2160 if (pi->stopped_cmds > 0) 2163 if (pi->stopped_cmds > 0)
2161 return ret_code; 2164 return;
2162 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid()); 2165 debug_printf_clean("%s run pipe: (pid %d)\n", indenter(indent), getpid());
2163 for (i = 0; i < pi->num_cmds; i++) { 2166 for (i = 0; i < pi->num_cmds; i++) {
2164 command = &pi->cmds[i]; 2167 command = &pi->cmds[i];
@@ -2169,12 +2172,13 @@ static int free_pipe(struct pipe *pi, int indent)
2169 } 2172 }
2170 free_strings(command->argv); 2173 free_strings(command->argv);
2171 command->argv = NULL; 2174 command->argv = NULL;
2172 } else if (command->group) { 2175 }
2176 /* not "else if": on syntax error, we may have both! */
2177 if (command->group) {
2173 debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type); 2178 debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type);
2174 ret_code = free_pipe_list(command->group, indent+3); 2179 free_pipe_list(command->group, indent+3);
2175 debug_printf_clean("%s end group\n", indenter(indent)); 2180 debug_printf_clean("%s end group\n", indenter(indent));
2176 } else { 2181 command->group = NULL;
2177 debug_printf_clean("%s (nil)\n", indenter(indent));
2178 } 2182 }
2179 for (r = command->redirects; r; r = rnext) { 2183 for (r = command->redirects; r; r = rnext) {
2180 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); 2184 debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
@@ -2199,25 +2203,22 @@ static int free_pipe(struct pipe *pi, int indent)
2199 free(pi->cmdtext); 2203 free(pi->cmdtext);
2200 pi->cmdtext = NULL; 2204 pi->cmdtext = NULL;
2201#endif 2205#endif
2202 return ret_code;
2203} 2206}
2204 2207
2205static int free_pipe_list(struct pipe *head, int indent) 2208static void free_pipe_list(struct pipe *head, int indent)
2206{ 2209{
2207 int rcode = 0; /* if list has no members */
2208 struct pipe *pi, *next; 2210 struct pipe *pi, *next;
2209 2211
2210 for (pi = head; pi; pi = next) { 2212 for (pi = head; pi; pi = next) {
2211#if HAS_KEYWORDS 2213#if HAS_KEYWORDS
2212 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); 2214 debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
2213#endif 2215#endif
2214 rcode = free_pipe(pi, indent); 2216 free_pipe(pi, indent);
2215 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); 2217 debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
2216 next = pi->next; 2218 next = pi->next;
2217 /*pi->next = NULL;*/ 2219 /*pi->next = NULL;*/
2218 free(pi); 2220 free(pi);
2219 } 2221 }
2220 return rcode;
2221} 2222}
2222 2223
2223 2224
@@ -3412,7 +3413,6 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
3412 new_p = new_pipe(); 3413 new_p = new_pipe();
3413 ctx->pipe->next = new_p; 3414 ctx->pipe->next = new_p;
3414 ctx->pipe = new_p; 3415 ctx->pipe = new_p;
3415 ctx->command = NULL; /* needed! */
3416 /* RES_THEN, RES_DO etc are "sticky" - 3416 /* RES_THEN, RES_DO etc are "sticky" -
3417 * they remain set for commands inside if/while. 3417 * they remain set for commands inside if/while.
3418 * This is used to control execution. 3418 * This is used to control execution.
@@ -3428,6 +3428,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
3428 if (ctx->ctx_res_w == RES_MATCH) 3428 if (ctx->ctx_res_w == RES_MATCH)
3429 ctx->ctx_res_w = RES_CASEI; 3429 ctx->ctx_res_w = RES_CASEI;
3430#endif 3430#endif
3431 ctx->command = NULL; /* trick done_command below */
3431 /* Create the memory for command, roughly: 3432 /* Create the memory for command, roughly:
3432 * ctx->pipe->cmds = new struct command; 3433 * ctx->pipe->cmds = new struct command;
3433 * ctx->command = &ctx->pipe->cmds[0]; 3434 * ctx->command = &ctx->pipe->cmds[0];
@@ -3542,21 +3543,21 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3542#endif 3543#endif
3543 if (r->flag == 0) { /* '!' */ 3544 if (r->flag == 0) { /* '!' */
3544 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ 3545 if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
3545 syntax(NULL); 3546 syntax("! ! command");
3546 IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;) 3547 IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
3547 } 3548 }
3548 ctx->ctx_inverted = 1; 3549 ctx->ctx_inverted = 1;
3549 return 1; 3550 return 1;
3550 } 3551 }
3551 if (r->flag & FLAG_START) { 3552 if (r->flag & FLAG_START) {
3552 struct parse_context *new; 3553 struct parse_context *old;
3553 debug_printf("push stack\n"); 3554 old = xmalloc(sizeof(*old));
3554 new = xmalloc(sizeof(*new)); 3555 debug_printf_parse("push stack %p\n", old);
3555 *new = *ctx; /* physical copy */ 3556 *old = *ctx; /* physical copy */
3556 initialize_context(ctx); 3557 initialize_context(ctx);
3557 ctx->stack = new; 3558 ctx->stack = old;
3558 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { 3559 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
3559 syntax(NULL); 3560 syntax(word->data);
3560 ctx->ctx_res_w = RES_SNTX; 3561 ctx->ctx_res_w = RES_SNTX;
3561 return 1; 3562 return 1;
3562 } 3563 }
@@ -3564,8 +3565,8 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3564 ctx->old_flag = r->flag; 3565 ctx->old_flag = r->flag;
3565 if (ctx->old_flag & FLAG_END) { 3566 if (ctx->old_flag & FLAG_END) {
3566 struct parse_context *old; 3567 struct parse_context *old;
3567 debug_printf("pop stack\n");
3568 done_pipe(ctx, PIPE_SEQ); 3568 done_pipe(ctx, PIPE_SEQ);
3569 debug_printf_parse("pop stack %p\n", ctx->stack);
3569 old = ctx->stack; 3570 old = ctx->stack;
3570 old->command->group = ctx->list_head; 3571 old->command->group = ctx->list_head;
3571 old->command->grp_type = GRP_NORMAL; 3572 old->command->grp_type = GRP_NORMAL;
@@ -3577,10 +3578,10 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3577} 3578}
3578#endif 3579#endif
3579 3580
3580//TODO: many, many callers don't check error from done_word()
3581
3582/* Word is complete, look at it and update parsing context. 3581/* Word is complete, look at it and update parsing context.
3583 * Normal return is 0. Syntax errors return 1. */ 3582 * Normal return is 0. Syntax errors return 1.
3583 * Note: on return, word is reset, but not o_free'd!
3584 */
3584static int done_word(o_string *word, struct parse_context *ctx) 3585static int done_word(o_string *word, struct parse_context *ctx)
3585{ 3586{
3586 struct command *command = ctx->command; 3587 struct command *command = ctx->command;
@@ -3610,10 +3611,14 @@ static int done_word(o_string *word, struct parse_context *ctx)
3610 debug_printf("word stored in rd_filename: '%s'\n", word->data); 3611 debug_printf("word stored in rd_filename: '%s'\n", word->data);
3611 } else { 3612 } else {
3612 /* "{ echo foo; } echo bar" - bad */ 3613 /* "{ echo foo; } echo bar" - bad */
3613 /* NB: bash allows e.g. "if true; then { echo foo; } fi". TODO? */ 3614 /* NB: bash allows e.g.:
3615 * if true; then { echo foo; } fi
3616 * while if false; then false; fi do break; done
3617 * TODO? */
3614 if (command->group) { 3618 if (command->group) {
3615 syntax(NULL); 3619 syntax(word->data);
3616 debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); 3620 debug_printf_parse("done_word return 1: syntax error, "
3621 "groups and arglists don't mix\n");
3617 return 1; 3622 return 1;
3618 } 3623 }
3619#if HAS_KEYWORDS 3624#if HAS_KEYWORDS
@@ -3716,8 +3721,7 @@ static int redirect_opt_num(o_string *o)
3716 return num; 3721 return num;
3717} 3722}
3718 3723
3719static int parse_stream(o_string *dest, struct parse_context *ctx, 3724static struct pipe *parse_stream(struct in_str *input, int end_trigger);
3720 struct in_str *input0, int end_trigger);
3721 3725
3722#if ENABLE_HUSH_TICK 3726#if ENABLE_HUSH_TICK
3723static FILE *generate_stream_from_list(struct pipe *head) 3727static FILE *generate_stream_from_list(struct pipe *head)
@@ -3767,24 +3771,25 @@ static int process_command_subs(o_string *dest,
3767 struct in_str *input) 3771 struct in_str *input)
3768{ 3772{
3769 int retcode, ch, eol_cnt; 3773 int retcode, ch, eol_cnt;
3770 o_string result = NULL_O_STRING; 3774 struct pipe *pipe_list;
3771 struct parse_context inner;
3772 FILE *p; 3775 FILE *p;
3773 struct in_str pipe_str; 3776 struct in_str pipe_str;
3774 3777
3775 /* Recursion to generate command */ 3778 /* Recursion to generate command */
3776 retcode = parse_stream(&result, &inner, input, '\0'); 3779 pipe_list = parse_stream(input, '\0');
3777 if (retcode != 0) 3780 if (pipe_list == NULL)
3778 return retcode; /* syntax error or EOF */ 3781 return 0; /* EOF: empty `cmd`: ``, ` ` etc */
3779 o_free(&result); 3782 if (pipe_list == ERR_PTR)
3780 3783 return 1; /* parse error. can this really happen? */
3781 p = generate_stream_from_list(inner.list_head); 3784
3785 p = generate_stream_from_list(pipe_list);
3786 free_pipe_list(pipe_list, /* indent: */ 0);
3782 if (p == NULL) 3787 if (p == NULL)
3783 return 1; 3788 return 1;
3784 close_on_exec_on(fileno(p)); 3789 close_on_exec_on(fileno(p));
3785 setup_file_in_str(&pipe_str, p);
3786 3790
3787 /* Now send results of command back into original context */ 3791 /* Now send results of command back into original context */
3792 setup_file_in_str(&pipe_str, p);
3788 eol_cnt = 0; 3793 eol_cnt = 0;
3789 while ((ch = i_getch(&pipe_str)) != EOF) { 3794 while ((ch = i_getch(&pipe_str)) != EOF) {
3790 if (ch == '\n') { 3795 if (ch == '\n') {
@@ -3805,7 +3810,6 @@ static int process_command_subs(o_string *dest,
3805 * echo `echo Hi; exec 1>&-; sleep 2` 3810 * echo `echo Hi; exec 1>&-; sleep 2`
3806 */ 3811 */
3807 retcode = fclose(p); 3812 retcode = fclose(p);
3808 free_pipe_list(inner.list_head, /* indent: */ 0);
3809 debug_printf("closed FILE from child, retcode=%d\n", retcode); 3813 debug_printf("closed FILE from child, retcode=%d\n", retcode);
3810 return retcode; 3814 return retcode;
3811} 3815}
@@ -3817,9 +3821,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
3817 /* dest contains characters seen prior to ( or {. 3821 /* dest contains characters seen prior to ( or {.
3818 * Typically it's empty, but for function defs, 3822 * Typically it's empty, but for function defs,
3819 * it contains function name (without '()'). */ 3823 * it contains function name (without '()'). */
3820 int rcode; 3824 struct pipe *pipe_list;
3821 int endch; 3825 int endch;
3822 struct parse_context sub;
3823 struct command *command = ctx->command; 3826 struct command *command = ctx->command;
3824 3827
3825 debug_printf_parse("parse_group entered\n"); 3828 debug_printf_parse("parse_group entered\n");
@@ -3845,12 +3848,16 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
3845 endch = ')'; 3848 endch = ')';
3846 command->grp_type = GRP_SUBSHELL; 3849 command->grp_type = GRP_SUBSHELL;
3847 } 3850 }
3848 rcode = parse_stream(dest, &sub, input, endch); 3851 pipe_list = parse_stream(input, endch);
3849 if (rcode == 0) { 3852 /* empty ()/{} or parse error? */
3850 command->group = sub.list_head; 3853 if (!pipe_list || pipe_list == ERR_PTR) {
3854 syntax(NULL);
3855 debug_printf_parse("parse_group return 1: parse_stream returned %p\n", pipe_list);
3856 return 1;
3851 } 3857 }
3852 debug_printf_parse("parse_group return %d\n", rcode); 3858 command->group = pipe_list;
3853 return rcode; 3859 debug_printf_parse("parse_group return 0\n");
3860 return 0;
3854 /* command remains "open", available for possible redirects */ 3861 /* command remains "open", available for possible redirects */
3855} 3862}
3856 3863
@@ -4211,17 +4218,18 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote
4211 goto again; 4218 goto again;
4212} 4219}
4213 4220
4214/* Initalize ctx (i.e. caller does not need to do that). 4221/*
4215 * Scan input, call done_word() whenever full IFS delimited word was seen. 4222 * Scan input until EOF or end_trigger char.
4216 * Call done_pipe if '\n' was seen (and end_trigger != NULL). 4223 * Return a list of pipes to execute, or NULL on EOF
4217 * Return code is 0 if end_trigger char is met, 4224 * or if end_trigger character is met.
4218 * -1 on EOF (but if end_trigger == NULL then return 0), 4225 * On syntax error, exit is shell is not interactive,
4219 * 1 for syntax error 4226 * reset parsing machinery and start parsing anew,
4220 * Net result is a list of pipes in ctx->list_head. 4227 * or return ERR_PTR.
4221 */ 4228 */
4222static int parse_stream(o_string *dest, struct parse_context *ctx, 4229static struct pipe *parse_stream(struct in_str *input, int end_trigger)
4223 struct in_str *input, int end_trigger)
4224{ 4230{
4231 struct parse_context ctx;
4232 o_string dest = NULL_O_STRING;
4225 int ch, m; 4233 int ch, m;
4226 int redir_fd; 4234 int redir_fd;
4227 redir_type redir_style; 4235 redir_type redir_style;
@@ -4232,18 +4240,22 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4232 * A single-quote triggers a bypass of the main loop until its mate is 4240 * A single-quote triggers a bypass of the main loop until its mate is
4233 * found. When recursing, quote state is passed in via dest->o_escape. */ 4241 * found. When recursing, quote state is passed in via dest->o_escape. */
4234 4242
4235 debug_printf_parse("parse_stream entered, end_trigger='%c' " 4243 debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
4236 "dest->o_assignment:%d\n", end_trigger ? : 'X' 4244 end_trigger ? : 'X');
4237 , dest->o_assignment);
4238 4245
4239 dest->o_assignment = MAYBE_ASSIGNMENT; 4246 reset:
4240 initialize_context(ctx); 4247#if ENABLE_HUSH_INTERACTIVE
4241 is_in_dquote = dest->o_escape; 4248 input->promptmode = 0; /* PS1 */
4249#endif
4250 /* dest.o_assignment = MAYBE_ASSIGNMENT; - already is */
4251 initialize_context(&ctx);
4252 is_in_dquote = 0;
4242 while (1) { 4253 while (1) {
4243 if (is_in_dquote) { 4254 if (is_in_dquote) {
4244 if (parse_stream_dquoted(dest, input, '"')) 4255 if (parse_stream_dquoted(&dest, input, '"')) {
4245 return 1; /* propagate parse error */ 4256 goto parse_error;
4246 /* If we're here, we reached closing '"' */ 4257 }
4258 /* We reached closing '"' */
4247 is_in_dquote = 0; 4259 is_in_dquote = 0;
4248 } 4260 }
4249 m = CHAR_IFS; 4261 m = CHAR_IFS;
@@ -4256,15 +4268,15 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4256 } 4268 }
4257 } 4269 }
4258 debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", 4270 debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n",
4259 ch, ch, m, dest->o_escape); 4271 ch, ch, m, dest.o_escape);
4260 if (m == CHAR_ORDINARY) { 4272 if (m == CHAR_ORDINARY) {
4261 o_addQchr(dest, ch); 4273 o_addQchr(&dest, ch);
4262 if ((dest->o_assignment == MAYBE_ASSIGNMENT 4274 if ((dest.o_assignment == MAYBE_ASSIGNMENT
4263 || dest->o_assignment == WORD_IS_KEYWORD) 4275 || dest.o_assignment == WORD_IS_KEYWORD)
4264 && ch == '=' 4276 && ch == '='
4265 && is_assignment(dest->data) 4277 && is_assignment(dest.data)
4266 ) { 4278 ) {
4267 dest->o_assignment = DEFINITELY_ASSIGNMENT; 4279 dest.o_assignment = DEFINITELY_ASSIGNMENT;
4268 } 4280 }
4269 continue; 4281 continue;
4270 } 4282 }
@@ -4272,25 +4284,40 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4272 /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */ 4284 /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
4273 4285
4274 if (m == CHAR_IFS) { 4286 if (m == CHAR_IFS) {
4275 if (ch == EOF) 4287 if (ch == EOF) {
4276 goto ret_EOF; 4288 struct pipe *pi;
4277 if (done_word(dest, ctx)) { 4289 if (done_word(&dest, &ctx)) {
4278 debug_printf_parse("parse_stream return 1: done_word!=0\n"); 4290 goto parse_error;
4279 return 1; 4291 }
4292 o_free(&dest);
4293 done_pipe(&ctx, PIPE_SEQ);
4294 /* If we got nothing... */
4295 pi = ctx.list_head;
4296 if (pi->num_cmds == 0
4297 && pi->res_word == RES_NONE
4298 ) {
4299 free_pipe_list(pi, 0);
4300 pi = NULL;
4301 }
4302 debug_printf_parse("parse_stream return %p\n", pi);
4303 return pi;
4304 }
4305 if (done_word(&dest, &ctx)) {
4306 goto parse_error;
4280 } 4307 }
4281 if (ch == '\n') { 4308 if (ch == '\n') {
4282#if ENABLE_HUSH_CASE 4309#if ENABLE_HUSH_CASE
4283 /* "case ... in <newline> word) ..." - 4310 /* "case ... in <newline> word) ..." -
4284 * newlines are ignored (but ';' wouldn't be) */ 4311 * newlines are ignored (but ';' wouldn't be) */
4285 if (ctx->command->argv == NULL 4312 if (ctx.command->argv == NULL
4286 && ctx->ctx_res_w == RES_MATCH 4313 && ctx.ctx_res_w == RES_MATCH
4287 ) { 4314 ) {
4288 continue; 4315 continue;
4289 } 4316 }
4290#endif 4317#endif
4291 /* Treat newline as a command separator. */ 4318 /* Treat newline as a command separator. */
4292 done_pipe(ctx, PIPE_SEQ); 4319 done_pipe(&ctx, PIPE_SEQ);
4293 dest->o_assignment = MAYBE_ASSIGNMENT; 4320 dest.o_assignment = MAYBE_ASSIGNMENT;
4294 ch = ';'; 4321 ch = ';';
4295 /* note: if (m == CHAR_IFS) continue; 4322 /* note: if (m == CHAR_IFS) continue;
4296 * will still trigger for us */ 4323 * will still trigger for us */
@@ -4298,15 +4325,20 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4298 } 4325 }
4299 if (end_trigger && end_trigger == ch) { 4326 if (end_trigger && end_trigger == ch) {
4300//TODO: disallow "{ cmd }" without semicolon 4327//TODO: disallow "{ cmd }" without semicolon
4301 done_word(dest, ctx); 4328 if (done_word(&dest, &ctx)) {
4302 done_pipe(ctx, PIPE_SEQ); 4329 goto parse_error;
4303 dest->o_assignment = MAYBE_ASSIGNMENT; 4330 }
4331 done_pipe(&ctx, PIPE_SEQ);
4332 dest.o_assignment = MAYBE_ASSIGNMENT;
4304 /* Do we sit outside of any if's, loops or case's? */ 4333 /* Do we sit outside of any if's, loops or case's? */
4305 if (!HAS_KEYWORDS 4334 if (!HAS_KEYWORDS
4306 IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0)) 4335 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
4307 ) { 4336 ) {
4308 debug_printf_parse("parse_stream return 0: end_trigger char found\n"); 4337 debug_printf_parse("parse_stream return %p: "
4309 return 0; 4338 "end_trigger char found\n",
4339 ctx.list_head);
4340 o_free(&dest);
4341 return ctx.list_head;
4310 } 4342 }
4311 } 4343 }
4312 if (m == CHAR_IFS) 4344 if (m == CHAR_IFS)
@@ -4314,15 +4346,15 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4314 4346
4315 /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */ 4347 /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */
4316 4348
4317 if (dest->o_assignment == MAYBE_ASSIGNMENT) { 4349 if (dest.o_assignment == MAYBE_ASSIGNMENT) {
4318 /* ch is a special char and thus this word 4350 /* ch is a special char and thus this word
4319 * cannot be an assignment */ 4351 * cannot be an assignment */
4320 dest->o_assignment = NOT_ASSIGNMENT; 4352 dest.o_assignment = NOT_ASSIGNMENT;
4321 } 4353 }
4322 4354
4323 switch (ch) { 4355 switch (ch) {
4324 case '#': 4356 case '#':
4325 if (dest->length == 0) { 4357 if (dest.length == 0) {
4326 while (1) { 4358 while (1) {
4327 ch = i_peek(input); 4359 ch = i_peek(input);
4328 if (ch == EOF || ch == '\n') 4360 if (ch == EOF || ch == '\n')
@@ -4330,61 +4362,61 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4330 i_getch(input); 4362 i_getch(input);
4331 } 4363 }
4332 } else { 4364 } else {
4333 o_addQchr(dest, ch); 4365 o_addQchr(&dest, ch);
4334 } 4366 }
4335 break; 4367 break;
4336 case '\\': 4368 case '\\':
4337 if (next == EOF) { 4369 if (next == EOF) {
4338 syntax("\\<eof>"); 4370 syntax("\\<eof>");
4339 debug_printf_parse("parse_stream return 1: \\<eof>\n"); 4371 goto parse_error;
4340 return 1;
4341 } 4372 }
4342 o_addchr(dest, '\\'); 4373 o_addchr(&dest, '\\');
4343 o_addchr(dest, i_getch(input)); 4374 o_addchr(&dest, i_getch(input));
4344 break; 4375 break;
4345 case '$': 4376 case '$':
4346 if (handle_dollar(dest, input) != 0) { 4377 if (handle_dollar(&dest, input) != 0) {
4347 debug_printf_parse("parse_stream return 1: handle_dollar returned non-0\n"); 4378 debug_printf_parse("parse_stream parse error: handle_dollar returned non-0\n");
4348 return 1; 4379 goto parse_error;
4349 } 4380 }
4350 break; 4381 break;
4351 case '\'': 4382 case '\'':
4352 dest->nonnull = 1; 4383 dest.nonnull = 1;
4353 while (1) { 4384 while (1) {
4354 ch = i_getch(input); 4385 ch = i_getch(input);
4355 if (ch == EOF) { 4386 if (ch == EOF) {
4356 syntax("unterminated '"); 4387 syntax("unterminated '");
4357 debug_printf_parse("parse_stream return 1: unterminated '\n"); 4388 goto parse_error;
4358 return 1;
4359 } 4389 }
4360 if (ch == '\'') 4390 if (ch == '\'')
4361 break; 4391 break;
4362 if (dest->o_assignment == NOT_ASSIGNMENT) 4392 if (dest.o_assignment == NOT_ASSIGNMENT)
4363 o_addqchr(dest, ch); 4393 o_addqchr(&dest, ch);
4364 else 4394 else
4365 o_addchr(dest, ch); 4395 o_addchr(&dest, ch);
4366 } 4396 }
4367 break; 4397 break;
4368 case '"': 4398 case '"':
4369 dest->nonnull = 1; 4399 dest.nonnull = 1;
4370 is_in_dquote ^= 1; /* invert */ 4400 is_in_dquote ^= 1; /* invert */
4371 if (dest->o_assignment == NOT_ASSIGNMENT) 4401 if (dest.o_assignment == NOT_ASSIGNMENT)
4372 dest->o_escape ^= 1; 4402 dest.o_escape ^= 1;
4373 break; 4403 break;
4374#if ENABLE_HUSH_TICK 4404#if ENABLE_HUSH_TICK
4375 case '`': { 4405 case '`': {
4376 //int pos = dest->length; 4406 //int pos = dest.length;
4377 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4407 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
4378 o_addchr(dest, '`'); 4408 o_addchr(&dest, '`');
4379 add_till_backquote(dest, input); 4409 add_till_backquote(&dest, input);
4380 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4410 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
4381 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); 4411 //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos);
4382 break; 4412 break;
4383 } 4413 }
4384#endif 4414#endif
4385 case '>': 4415 case '>':
4386 redir_fd = redirect_opt_num(dest); 4416 redir_fd = redirect_opt_num(&dest);
4387 done_word(dest, ctx); 4417 if (done_word(&dest, &ctx)) {
4418 goto parse_error;
4419 }
4388 redir_style = REDIRECT_OVERWRITE; 4420 redir_style = REDIRECT_OVERWRITE;
4389 if (next == '>') { 4421 if (next == '>') {
4390 redir_style = REDIRECT_APPEND; 4422 redir_style = REDIRECT_APPEND;
@@ -4393,15 +4425,16 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4393#if 0 4425#if 0
4394 else if (next == '(') { 4426 else if (next == '(') {
4395 syntax(">(process) not supported"); 4427 syntax(">(process) not supported");
4396 debug_printf_parse("parse_stream return 1: >(process) not supported\n"); 4428 goto parse_error;
4397 return 1;
4398 } 4429 }
4399#endif 4430#endif
4400 setup_redirect(ctx, redir_fd, redir_style, input); 4431 setup_redirect(&ctx, redir_fd, redir_style, input);
4401 break; 4432 break;
4402 case '<': 4433 case '<':
4403 redir_fd = redirect_opt_num(dest); 4434 redir_fd = redirect_opt_num(&dest);
4404 done_word(dest, ctx); 4435 if (done_word(&dest, &ctx)) {
4436 goto parse_error;
4437 }
4405 redir_style = REDIRECT_INPUT; 4438 redir_style = REDIRECT_INPUT;
4406 if (next == '<') { 4439 if (next == '<') {
4407 redir_style = REDIRECT_HEREIS; 4440 redir_style = REDIRECT_HEREIS;
@@ -4413,18 +4446,19 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4413#if 0 4446#if 0
4414 else if (next == '(') { 4447 else if (next == '(') {
4415 syntax("<(process) not supported"); 4448 syntax("<(process) not supported");
4416 debug_printf_parse("parse_stream return 1: <(process) not supported\n"); 4449 goto parse_error;
4417 return 1;
4418 } 4450 }
4419#endif 4451#endif
4420 setup_redirect(ctx, redir_fd, redir_style, input); 4452 setup_redirect(&ctx, redir_fd, redir_style, input);
4421 break; 4453 break;
4422 case ';': 4454 case ';':
4423#if ENABLE_HUSH_CASE 4455#if ENABLE_HUSH_CASE
4424 case_semi: 4456 case_semi:
4425#endif 4457#endif
4426 done_word(dest, ctx); 4458 if (done_word(&dest, &ctx)) {
4427 done_pipe(ctx, PIPE_SEQ); 4459 goto parse_error;
4460 }
4461 done_pipe(&ctx, PIPE_SEQ);
4428#if ENABLE_HUSH_CASE 4462#if ENABLE_HUSH_CASE
4429 /* Eat multiple semicolons, detect 4463 /* Eat multiple semicolons, detect
4430 * whether it means something special */ 4464 * whether it means something special */
@@ -4433,9 +4467,9 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4433 if (ch != ';') 4467 if (ch != ';')
4434 break; 4468 break;
4435 i_getch(input); 4469 i_getch(input);
4436 if (ctx->ctx_res_w == RES_CASEI) { 4470 if (ctx.ctx_res_w == RES_CASEI) {
4437 ctx->ctx_dsemicolon = 1; 4471 ctx.ctx_dsemicolon = 1;
4438 ctx->ctx_res_w = RES_MATCH; 4472 ctx.ctx_res_w = RES_MATCH;
4439 break; 4473 break;
4440 } 4474 }
4441 } 4475 }
@@ -4443,51 +4477,55 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4443 new_cmd: 4477 new_cmd:
4444 /* We just finished a cmd. New one may start 4478 /* We just finished a cmd. New one may start
4445 * with an assignment */ 4479 * with an assignment */
4446 dest->o_assignment = MAYBE_ASSIGNMENT; 4480 dest.o_assignment = MAYBE_ASSIGNMENT;
4447 break; 4481 break;
4448 case '&': 4482 case '&':
4449 done_word(dest, ctx); 4483 if (done_word(&dest, &ctx)) {
4484 goto parse_error;
4485 }
4450 if (next == '&') { 4486 if (next == '&') {
4451 i_getch(input); 4487 i_getch(input);
4452 done_pipe(ctx, PIPE_AND); 4488 done_pipe(&ctx, PIPE_AND);
4453 } else { 4489 } else {
4454 done_pipe(ctx, PIPE_BG); 4490 done_pipe(&ctx, PIPE_BG);
4455 } 4491 }
4456 goto new_cmd; 4492 goto new_cmd;
4457 case '|': 4493 case '|':
4458 done_word(dest, ctx); 4494 if (done_word(&dest, &ctx)) {
4495 goto parse_error;
4496 }
4459#if ENABLE_HUSH_CASE 4497#if ENABLE_HUSH_CASE
4460 if (ctx->ctx_res_w == RES_MATCH) 4498 if (ctx.ctx_res_w == RES_MATCH)
4461 break; /* we are in case's "word | word)" */ 4499 break; /* we are in case's "word | word)" */
4462#endif 4500#endif
4463 if (next == '|') { /* || */ 4501 if (next == '|') { /* || */
4464 i_getch(input); 4502 i_getch(input);
4465 done_pipe(ctx, PIPE_OR); 4503 done_pipe(&ctx, PIPE_OR);
4466 } else { 4504 } else {
4467 /* we could pick up a file descriptor choice here 4505 /* we could pick up a file descriptor choice here
4468 * with redirect_opt_num(), but bash doesn't do it. 4506 * with redirect_opt_num(), but bash doesn't do it.
4469 * "echo foo 2| cat" yields "foo 2". */ 4507 * "echo foo 2| cat" yields "foo 2". */
4470 done_command(ctx); 4508 done_command(&ctx);
4471 } 4509 }
4472 goto new_cmd; 4510 goto new_cmd;
4473 case '(': 4511 case '(':
4474#if ENABLE_HUSH_CASE 4512#if ENABLE_HUSH_CASE
4475 /* "case... in [(]word)..." - skip '(' */ 4513 /* "case... in [(]word)..." - skip '(' */
4476 if (ctx->ctx_res_w == RES_MATCH 4514 if (ctx.ctx_res_w == RES_MATCH
4477 && ctx->command->argv == NULL /* not (word|(... */ 4515 && ctx.command->argv == NULL /* not (word|(... */
4478 && dest->length == 0 /* not word(... */ 4516 && dest.length == 0 /* not word(... */
4479 && dest->nonnull == 0 /* not ""(... */ 4517 && dest.nonnull == 0 /* not ""(... */
4480 ) { 4518 ) {
4481 continue; 4519 continue;
4482 } 4520 }
4483#endif 4521#endif
4484#if ENABLE_HUSH_FUNCTIONS 4522#if ENABLE_HUSH_FUNCTIONS
4485 if (dest->length != 0 /* not just () but word() */ 4523 if (dest.length != 0 /* not just () but word() */
4486 && dest->nonnull == 0 /* not a"b"c() */ 4524 && dest.nonnull == 0 /* not a"b"c() */
4487 && ctx->command->argv == NULL /* it's the first word */ 4525 && ctx.command->argv == NULL /* it's the first word */
4488//TODO: "func ( ) {...}" - note spaces - is valid format too in bash 4526//TODO: "func ( ) {...}" - note spaces - is valid format too in bash
4489 && i_peek(input) == ')' 4527 && i_peek(input) == ')'
4490 && !match_reserved_word(dest) 4528 && !match_reserved_word(&dest)
4491 ) { 4529 ) {
4492 bb_error_msg("seems like a function definition"); 4530 bb_error_msg("seems like a function definition");
4493 i_getch(input); 4531 i_getch(input);
@@ -4497,21 +4535,19 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4497 } while (ch == ' ' || ch == '\n'); 4535 } while (ch == ' ' || ch == '\n');
4498 if (ch != '{') { 4536 if (ch != '{') {
4499 syntax("was expecting {"); 4537 syntax("was expecting {");
4500 debug_printf_parse("parse_stream return 1\n"); 4538 goto parse_error;
4501 return 1;
4502 } 4539 }
4503 ch = 'F'; /* magic value */ 4540 ch = 'F'; /* magic value */
4504 } 4541 }
4505#endif 4542#endif
4506 case '{': 4543 case '{':
4507 if (parse_group(dest, ctx, input, ch) != 0) { 4544 if (parse_group(&dest, &ctx, input, ch) != 0) {
4508 debug_printf_parse("parse_stream return 1: parse_group returned non-0\n"); 4545 goto parse_error;
4509 return 1;
4510 } 4546 }
4511 goto new_cmd; 4547 goto new_cmd;
4512 case ')': 4548 case ')':
4513#if ENABLE_HUSH_CASE 4549#if ENABLE_HUSH_CASE
4514 if (ctx->ctx_res_w == RES_MATCH) 4550 if (ctx.ctx_res_w == RES_MATCH)
4515 goto case_semi; 4551 goto case_semi;
4516#endif 4552#endif
4517 case '}': 4553 case '}':
@@ -4519,23 +4555,51 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
4519 * if we see {, we call parse_group(..., end_trigger='}') 4555 * if we see {, we call parse_group(..., end_trigger='}')
4520 * and it will match } earlier (not here). */ 4556 * and it will match } earlier (not here). */
4521 syntax("unexpected } or )"); 4557 syntax("unexpected } or )");
4522 debug_printf_parse("parse_stream return 1: unexpected '}'\n"); 4558 goto parse_error;
4523 return 1;
4524 default: 4559 default:
4525 if (HUSH_DEBUG) 4560 if (HUSH_DEBUG)
4526 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 4561 bb_error_msg_and_die("BUG: unexpected %c\n", ch);
4527 } 4562 }
4528 } /* while (1) */ 4563 } /* while (1) */
4529 4564
4530 /* Non-error returns */ 4565 parse_error:
4531 ret_EOF: 4566 {
4532 debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); 4567 struct parse_context *pctx, *p2;
4533 done_word(dest, ctx); 4568
4534 done_pipe(ctx, PIPE_SEQ); 4569 /* Clean up allocated tree.
4535 if (end_trigger) { 4570 * Samples for finding leaks on syntax error recovery path.
4536 return -1; /* EOF found while expecting end_trigger */ 4571 * Execute them from interactive shell and watch pmap `pidof hush`.
4572 * while if false; then false; fi do break; done (bash accepts it)
4573 * while if false; then false; fi; do break; fi
4574 */
4575 pctx = &ctx;
4576 do {
4577 /* Update pipe/command counts,
4578 * otherwise freeing may miss some */
4579 done_pipe(pctx, PIPE_SEQ);
4580 debug_printf_clean("freeing list %p from ctx %p\n",
4581 pctx->list_head, pctx);
4582 debug_print_tree(pctx->list_head, 0);
4583 free_pipe_list(pctx->list_head, 0);
4584 debug_printf_clean("freed list %p\n", pctx->list_head);
4585 p2 = pctx->stack;
4586 if (pctx != &ctx) {
4587 free(pctx);
4588 }
4589 pctx = p2;
4590 } while (pctx);
4591 /* Free text, clear all dest fields */
4592 o_free(&dest);
4593 /* If we are not in top-level parse, we return,
4594 * our caller will propagate error.
4595 */
4596 if (end_trigger != ';')
4597 return ERR_PTR;
4598 /* Discard cached input, force prompt */
4599 input->p = NULL;
4600 input->promptme = 1;
4601 goto reset;
4537 } 4602 }
4538 return 0;
4539} 4603}
4540 4604
4541static void set_in_charmap(const char *set, int code) 4605static void set_in_charmap(const char *set, int code)
@@ -4565,71 +4629,41 @@ static void update_charmap(void)
4565 set_in_charmap(G.ifs, CHAR_IFS); /* are ordinary if quoted */ 4629 set_in_charmap(G.ifs, CHAR_IFS); /* are ordinary if quoted */
4566} 4630}
4567 4631
4568/* Most recursion does not come through here, the exception is 4632/* Execiting from string: eval, sh -c '...'
4569 * from builtin_source() and builtin_eval() */ 4633 * or from file: /etc/profile, . file, sh <script>, sh (intereactive)
4570static int parse_and_run_stream(struct in_str *inp, int parse_flag) 4634 * end_trigger controls how often we stop parsing
4635 * NUL: parse all, execute, return
4636 * ';': parse till ';' or newline, execute, repeat till EOF
4637 */
4638static void parse_and_run_stream(struct in_str *inp, int end_trigger)
4571{ 4639{
4572 struct parse_context ctx; 4640 while (1) {
4573 o_string temp = NULL_O_STRING; 4641 struct pipe *pipe_list;
4574 int rcode;
4575 4642
4576 do {
4577 update_charmap(); 4643 update_charmap();
4578#if ENABLE_HUSH_INTERACTIVE 4644
4579 inp->promptmode = 0; /* PS1 */ 4645 pipe_list = parse_stream(inp, end_trigger);
4580#endif 4646 if (!pipe_list) /* EOF */
4581 /* We will stop & execute after each ';' or '\n'. 4647 break;
4582 * Example: "sleep 9999; echo TEST" + ctrl-C: 4648 debug_print_tree(pipe_list, 0);
4583 * TEST should be printed */ 4649 debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
4584 temp.o_assignment = MAYBE_ASSIGNMENT; 4650 run_and_free_list(pipe_list);
4585 rcode = parse_stream(&temp, &ctx, inp, ';'); 4651 /* Loop on syntax errors, return on EOF: */
4586 debug_printf_parse("rcode %d ctx.old_flag %x\n", rcode, ctx.old_flag); 4652 }
4587#if HAS_KEYWORDS
4588 if (rcode != 1 && ctx.old_flag != 0) {
4589 syntax(NULL);
4590 }
4591#endif
4592 if (rcode != 1 IF_HAS_KEYWORDS(&& ctx.old_flag == 0)) {
4593 debug_print_tree(ctx.list_head, 0);
4594 debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
4595 run_and_free_list(ctx.list_head);
4596 } else {
4597 /* We arrive here also if rcode == 1 (error in parse_stream) */
4598#if HAS_KEYWORDS
4599 if (ctx.old_flag != 0) {
4600 free(ctx.stack);
4601 o_reset(&temp);
4602 }
4603#endif
4604 /*temp.nonnull = 0; - o_free does it below */
4605 /*temp.o_escape = 0; - o_free does it below */
4606 free_pipe_list(ctx.list_head, /* indent: */ 0);
4607 /* Discard all unprocessed line input, force prompt on */
4608 inp->p = NULL;
4609#if ENABLE_HUSH_INTERACTIVE
4610 inp->promptme = 1;
4611#endif
4612 }
4613 o_free(&temp);
4614 /* loop on syntax errors, return on EOF: */
4615 } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP));
4616 return 0;
4617} 4653}
4618 4654
4619static int parse_and_run_string(const char *s, int parse_flag) 4655static void parse_and_run_string(const char *s)
4620{ 4656{
4621 struct in_str input; 4657 struct in_str input;
4622 setup_string_in_str(&input, s); 4658 setup_string_in_str(&input, s);
4623 return parse_and_run_stream(&input, parse_flag); 4659 parse_and_run_stream(&input, '\0');
4624} 4660}
4625 4661
4626static int parse_and_run_file(FILE *f) 4662static void parse_and_run_file(FILE *f)
4627{ 4663{
4628 int rcode;
4629 struct in_str input; 4664 struct in_str input;
4630 setup_file_in_str(&input, f); 4665 setup_file_in_str(&input, f);
4631 rcode = parse_and_run_stream(&input, 0 /* parse_flag */); 4666 parse_and_run_stream(&input, ';');
4632 return rcode;
4633} 4667}
4634 4668
4635#if ENABLE_HUSH_JOB 4669#if ENABLE_HUSH_JOB
@@ -4753,7 +4787,7 @@ int hush_main(int argc, char **argv)
4753 optind--; 4787 optind--;
4754 } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */ 4788 } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */
4755 G.global_argc = argc - optind; 4789 G.global_argc = argc - optind;
4756 opt = parse_and_run_string(optarg, 0 /* parse_flag */); 4790 parse_and_run_string(optarg);
4757 goto final_return; 4791 goto final_return;
4758 case 'i': 4792 case 'i':
4759 /* Well, we cannot just declare interactiveness, 4793 /* Well, we cannot just declare interactiveness,
@@ -4851,14 +4885,14 @@ int hush_main(int argc, char **argv)
4851#endif 4885#endif
4852 4886
4853 if (argv[optind] == NULL) { 4887 if (argv[optind] == NULL) {
4854 opt = parse_and_run_file(stdin); 4888 parse_and_run_file(stdin);
4855 } else { 4889 } else {
4856 debug_printf("\nrunning script '%s'\n", argv[optind]); 4890 debug_printf("\nrunning script '%s'\n", argv[optind]);
4857 G.global_argv = argv + optind; 4891 G.global_argv = argv + optind;
4858 G.global_argc = argc - optind; 4892 G.global_argc = argc - optind;
4859 input = xfopen_for_read(argv[optind]); 4893 input = xfopen_for_read(argv[optind]);
4860 fcntl(fileno(input), F_SETFD, FD_CLOEXEC); 4894 fcntl(fileno(input), F_SETFD, FD_CLOEXEC);
4861 opt = parse_and_run_file(input); 4895 parse_and_run_file(input);
4862 } 4896 }
4863 4897
4864 final_return: 4898 final_return:
@@ -4876,7 +4910,7 @@ int hush_main(int argc, char **argv)
4876 free(tmp); 4910 free(tmp);
4877 } 4911 }
4878#endif 4912#endif
4879 hush_exit(opt ? opt : G.last_return_code); 4913 hush_exit(G.last_return_code);
4880} 4914}
4881 4915
4882 4916
@@ -5000,7 +5034,11 @@ static int builtin_eval(char **argv)
5000 5034
5001 if (argv[1]) { 5035 if (argv[1]) {
5002 char *str = expand_strvec_to_string(argv + 1); 5036 char *str = expand_strvec_to_string(argv + 1);
5003 parse_and_run_string(str, PARSEFLAG_EXIT_FROM_LOOP); 5037 /* bash:
5038 * eval "echo Hi; done" ("done" is syntax error):
5039 * "echo Hi" will not execute too.
5040 */
5041 parse_and_run_string(str);
5004 free(str); 5042 free(str);
5005 rcode = G.last_return_code; 5043 rcode = G.last_return_code;
5006 } 5044 }
@@ -5011,8 +5049,9 @@ static int builtin_cd(char **argv)
5011{ 5049{
5012 const char *newdir; 5050 const char *newdir;
5013 if (argv[1] == NULL) { 5051 if (argv[1] == NULL) {
5014 // bash does nothing (exitcode 0) if HOME is ""; if it's unset, 5052 /* bash does nothing (exitcode 0) if HOME is ""; if it's unset,
5015 // bash says "bash: cd: HOME not set" and does nothing (exitcode 1) 5053 * bash says "bash: cd: HOME not set" and does nothing (exitcode 1)
5054 */
5016 newdir = getenv("HOME") ? : "/"; 5055 newdir = getenv("HOME") ? : "/";
5017 } else 5056 } else
5018 newdir = argv[1]; 5057 newdir = argv[1];
@@ -5309,7 +5348,6 @@ static int builtin_shift(char **argv)
5309static int builtin_source(char **argv) 5348static int builtin_source(char **argv)
5310{ 5349{
5311 FILE *input; 5350 FILE *input;
5312 int status;
5313 5351
5314 if (argv[1] == NULL) 5352 if (argv[1] == NULL)
5315 return EXIT_FAILURE; 5353 return EXIT_FAILURE;
@@ -5326,9 +5364,9 @@ static int builtin_source(char **argv)
5326 /* XXX argv and argc are broken; need to save old G.global_argv 5364 /* XXX argv and argc are broken; need to save old G.global_argv
5327 * (pointer only is OK!) on this stack frame, 5365 * (pointer only is OK!) on this stack frame,
5328 * set G.global_argv=argv+1, recurse, and restore. */ 5366 * set G.global_argv=argv+1, recurse, and restore. */
5329 status = parse_and_run_file(input); 5367 parse_and_run_file(input);
5330 fclose(input); 5368 fclose(input);
5331 return status; 5369 return G.last_return_code;
5332} 5370}
5333 5371
5334static int builtin_umask(char **argv) 5372static int builtin_umask(char **argv)
diff --git a/shell/hush_test/hush-misc/syntax_err_negate.right b/shell/hush_test/hush-misc/syntax_err_negate.right
index d1e7654f5..8c7010629 100644
--- a/shell/hush_test/hush-misc/syntax_err_negate.right
+++ b/shell/hush_test/hush-misc/syntax_err_negate.right
@@ -1,2 +1,2 @@
1bash 3.2 fails this 1bash 3.2 fails this
2hush: syntax error 2hush: syntax error: ! ! command