hush: fix a bit different instance of "No EOL" bug,

add testsuite for that. Expand another testsuite.
This commit is contained in:
Denis Vlasenko 2007-05-23 00:32:25 +00:00
parent 94dace3016
commit 1a7358612f
5 changed files with 57 additions and 40 deletions

View File

@ -2836,14 +2836,13 @@ static struct pipe *new_pipe(void)
static void initialize_context(struct p_context *ctx) static void initialize_context(struct p_context *ctx)
{ {
ctx->pipe = NULL;
ctx->pending_redirect = NULL;
ctx->child = NULL; ctx->child = NULL;
ctx->list_head = new_pipe(); ctx->pipe = ctx->list_head = new_pipe();
ctx->pipe = ctx->list_head; ctx->pending_redirect = NULL;
ctx->res_w = RES_NONE; ctx->res_w = RES_NONE;
ctx->stack = NULL; //only ctx->parse_type is not touched... is this intentional?
ctx->old_flag = 0; ctx->old_flag = 0;
ctx->stack = NULL;
done_command(ctx); /* creates the memory for working child */ done_command(ctx); /* creates the memory for working child */
} }
@ -2886,44 +2885,44 @@ static int reserved_word(o_string *dest, struct p_context *ctx)
const struct reserved_combo *r; const struct reserved_combo *r;
for (r = reserved_list; r < reserved_list + NRES; r++) { for (r = reserved_list; r < reserved_list + NRES; r++) {
if (strcmp(dest->data, r->literal) == 0) { if (strcmp(dest->data, r->literal) != 0)
debug_printf("found reserved word %s, code %d\n", r->literal, r->code); continue;
if (r->flag & FLAG_START) { debug_printf("found reserved word %s, code %d\n", r->literal, r->code);
struct p_context *new = xmalloc(sizeof(struct p_context)); if (r->flag & FLAG_START) {
debug_printf("push stack\n"); struct p_context *new;
debug_printf("push stack\n");
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) { if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) {
syntax();
free(new);
ctx->res_w = RES_SNTX;
b_reset(dest);
return 1;
}
#endif
*new = *ctx; /* physical copy */
initialize_context(ctx);
ctx->stack = new;
} else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) {
syntax(); syntax();
ctx->res_w = RES_SNTX; ctx->res_w = RES_SNTX;
b_reset(dest); b_reset(dest);
return 1; return 1;
} }
ctx->res_w = r->code; #endif
ctx->old_flag = r->flag; new = xmalloc(sizeof(*new));
if (ctx->old_flag & FLAG_END) { *new = *ctx; /* physical copy */
struct p_context *old; initialize_context(ctx);
debug_printf("pop stack\n"); ctx->stack = new;
done_pipe(ctx, PIPE_SEQ); } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) {
old = ctx->stack; syntax();
old->child->group = ctx->list_head; ctx->res_w = RES_SNTX;
old->child->subshell = 0;
*ctx = *old; /* physical copy */
free(old);
}
b_reset(dest); b_reset(dest);
return 1; return 1;
} }
ctx->res_w = r->code;
ctx->old_flag = r->flag;
if (ctx->old_flag & FLAG_END) {
struct p_context *old;
debug_printf("pop stack\n");
done_pipe(ctx, PIPE_SEQ);
old = ctx->stack;
old->child->group = ctx->list_head;
old->child->subshell = 0;
*ctx = *old; /* physical copy */
free(old);
}
b_reset(dest);
return 1;
} }
return 0; return 0;
} }
@ -3155,7 +3154,8 @@ static int process_command_subs(o_string *dest, struct p_context *ctx,
/* recursion to generate command */ /* recursion to generate command */
retcode = parse_stream(&result, &inner, input, subst_end); retcode = parse_stream(&result, &inner, input, subst_end);
if (retcode != 0) return retcode; /* syntax error or EOF */ if (retcode != 0)
return retcode; /* syntax error or EOF */
done_word(&result, &inner); done_word(&result, &inner);
done_pipe(&inner, PIPE_SEQ); done_pipe(&inner, PIPE_SEQ);
b_free(&result); b_free(&result);
@ -3357,9 +3357,15 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger); debug_printf_parse("parse_stream entered, end_trigger='%s'\n", end_trigger);
while ((ch = b_getch(input)) != EOF) { while (1) {
m = charmap[ch]; ch = b_getch(input);
next = (ch == '\n') ? '\0' : b_peek(input); m = CHAR_IFS;
next = '\0';
if (ch != EOF) {
m = charmap[ch];
if (ch != '\n')
next = b_peek(input);
}
debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
ch, ch, m, dest->quote); ch, ch, m, dest->quote);
if (m == CHAR_ORDINARY if (m == CHAR_ORDINARY
@ -3373,6 +3379,8 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
debug_printf_parse("parse_stream return 1: done_word!=0\n"); debug_printf_parse("parse_stream return 1: done_word!=0\n");
return 1; return 1;
} }
if (ch == EOF)
break;
/* If we aren't performing a substitution, treat /* If we aren't performing a substitution, treat
* a newline as a command separator. * a newline as a command separator.
* [why we don't handle it exactly like ';'? --vda] */ * [why we don't handle it exactly like ';'? --vda] */

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,7 @@
# last line has no EOL!
if true
then
echo 1
else
echo 2
fi

View File

@ -3,3 +3,4 @@
.d. .d.
.e. .e.
.f. .f.
.1 abc d e f.

View File

@ -4,5 +4,5 @@ fi
# 'd e f' should be split into 3 separate args: # 'd e f' should be split into 3 separate args:
for a in $*; do echo ".$a."; done for a in $*; do echo ".$a."; done
# must produce .1 abc d e f. Currently does not # must produce .1 abc d e f.
#for a in "$*"; do echo ".$a."; done for a in "$*"; do echo ".$a."; done