diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-23 15:22:50 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-23 15:22:50 +0000 |
commit | 90e485ce79b8a0cd345bc5be76100291ec589579 (patch) | |
tree | b994e960b598f802820ddd5cf712678903c404de /shell/hush.c | |
parent | 1744cb18610aece474ba080f43aa5dc89177388e (diff) | |
download | busybox-w32-90e485ce79b8a0cd345bc5be76100291ec589579.tar.gz busybox-w32-90e485ce79b8a0cd345bc5be76100291ec589579.tar.bz2 busybox-w32-90e485ce79b8a0cd345bc5be76100291ec589579.zip |
hush: make syntax error messages a bit more useful
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/shell/hush.c b/shell/hush.c index 1545b041f..579950ff9 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -423,11 +423,20 @@ enum { run_list_level = 0 }; | |||
423 | #define B_NOSPAC 1 | 423 | #define B_NOSPAC 1 |
424 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" | 424 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" |
425 | 425 | ||
426 | static void __syntax(int line) | 426 | #if 1 |
427 | /* Normal */ | ||
428 | static void syntax(const char *msg) | ||
429 | { | ||
430 | bb_error_msg(msg ? "%s: %s" : "syntax error", "syntax error", msg); | ||
431 | } | ||
432 | #else | ||
433 | /* Debug */ | ||
434 | static void syntax_lineno(int line) | ||
427 | { | 435 | { |
428 | bb_error_msg("syntax error hush.c:%d", line); | 436 | bb_error_msg("syntax error hush.c:%d", line); |
429 | } | 437 | } |
430 | #define syntax() __syntax(__LINE__) | 438 | #define syntax(str) syntax_lineno(__LINE__) |
439 | #endif | ||
431 | 440 | ||
432 | /* Index of subroutines: */ | 441 | /* Index of subroutines: */ |
433 | /* function prototypes for builtins */ | 442 | /* function prototypes for builtins */ |
@@ -1981,7 +1990,7 @@ static int run_list_real(struct pipe *pi) | |||
1981 | if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR) | 1990 | if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR) |
1982 | && (rpipe->next == NULL) | 1991 | && (rpipe->next == NULL) |
1983 | ) { | 1992 | ) { |
1984 | syntax(); /* unterminated FOR (no IN or no commands after IN) */ | 1993 | syntax("malformed for"); /* no IN or no commands after IN */ |
1985 | debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); | 1994 | debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); |
1986 | return 1; | 1995 | return 1; |
1987 | } | 1996 | } |
@@ -1989,7 +1998,7 @@ static int run_list_real(struct pipe *pi) | |||
1989 | || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN) | 1998 | || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN) |
1990 | ) { | 1999 | ) { |
1991 | /* TODO: what is tested in the first condition? */ | 2000 | /* TODO: what is tested in the first condition? */ |
1992 | syntax(); /* 2nd: malformed FOR (not followed by IN) */ | 2001 | syntax("malformed for"); /* 2nd condition: not followed by IN */ |
1993 | debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); | 2002 | debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); |
1994 | return 1; | 2003 | return 1; |
1995 | } | 2004 | } |
@@ -2914,7 +2923,7 @@ static int reserved_word(o_string *dest, struct p_context *ctx) | |||
2914 | debug_printf("push stack\n"); | 2923 | debug_printf("push stack\n"); |
2915 | #if ENABLE_HUSH_LOOPS | 2924 | #if ENABLE_HUSH_LOOPS |
2916 | if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) { | 2925 | if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) { |
2917 | syntax(); | 2926 | syntax("malformed for"); /* example: 'for if' */ |
2918 | ctx->res_w = RES_SNTX; | 2927 | ctx->res_w = RES_SNTX; |
2919 | b_reset(dest); | 2928 | b_reset(dest); |
2920 | return 1; | 2929 | return 1; |
@@ -2925,7 +2934,7 @@ static int reserved_word(o_string *dest, struct p_context *ctx) | |||
2925 | initialize_context(ctx); | 2934 | initialize_context(ctx); |
2926 | ctx->stack = new; | 2935 | ctx->stack = new; |
2927 | } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) { | 2936 | } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) { |
2928 | syntax(); | 2937 | syntax(NULL); |
2929 | ctx->res_w = RES_SNTX; | 2938 | ctx->res_w = RES_SNTX; |
2930 | b_reset(dest); | 2939 | b_reset(dest); |
2931 | return 1; | 2940 | return 1; |
@@ -2968,7 +2977,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
2968 | glob_target = &ctx->pending_redirect->word; | 2977 | glob_target = &ctx->pending_redirect->word; |
2969 | } else { | 2978 | } else { |
2970 | if (child->group) { | 2979 | if (child->group) { |
2971 | syntax(); | 2980 | syntax(NULL); |
2972 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); | 2981 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); |
2973 | return 1; | 2982 | return 1; |
2974 | } | 2983 | } |
@@ -3224,21 +3233,15 @@ static int parse_group(o_string *dest, struct p_context *ctx, | |||
3224 | 3233 | ||
3225 | debug_printf_parse("parse_group entered\n"); | 3234 | debug_printf_parse("parse_group entered\n"); |
3226 | if (child->argv) { | 3235 | if (child->argv) { |
3227 | syntax(); | 3236 | syntax(NULL); |
3228 | debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); | 3237 | debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); |
3229 | return 1; | 3238 | return 1; |
3230 | } | 3239 | } |
3231 | initialize_context(&sub); | 3240 | initialize_context(&sub); |
3232 | switch (ch) { | 3241 | endch = "}"; |
3233 | case '(': | 3242 | if (ch == '(') { |
3234 | endch = ")"; | 3243 | endch = ")"; |
3235 | child->subshell = 1; | 3244 | child->subshell = 1; |
3236 | break; | ||
3237 | case '{': | ||
3238 | endch = "}"; | ||
3239 | break; | ||
3240 | default: | ||
3241 | syntax(); /* really logic error */ | ||
3242 | } | 3245 | } |
3243 | rcode = parse_stream(dest, &sub, input, endch); | 3246 | rcode = parse_stream(dest, &sub, input, endch); |
3244 | done_word(dest, &sub); /* finish off the final word in the subcontext */ | 3247 | done_word(dest, &sub); /* finish off the final word in the subcontext */ |
@@ -3307,7 +3310,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
3307 | while (1) { | 3310 | while (1) { |
3308 | ch = b_getch(input); | 3311 | ch = b_getch(input); |
3309 | if (ch == EOF) { | 3312 | if (ch == EOF) { |
3310 | syntax(); | 3313 | syntax("unterminated ${name}"); |
3311 | debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); | 3314 | debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); |
3312 | return 1; | 3315 | return 1; |
3313 | } | 3316 | } |
@@ -3368,7 +3371,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3368 | || (m != CHAR_SPECIAL && dest->quote) | 3371 | || (m != CHAR_SPECIAL && dest->quote) |
3369 | ) { | 3372 | ) { |
3370 | if (ch == EOF) { | 3373 | if (ch == EOF) { |
3371 | syntax(); | 3374 | syntax("unterminated \""); |
3372 | debug_printf_parse("parse_stream return 1: unterminated \"\n"); | 3375 | debug_printf_parse("parse_stream return 1: unterminated \"\n"); |
3373 | return 1; | 3376 | return 1; |
3374 | } | 3377 | } |
@@ -3412,7 +3415,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3412 | break; | 3415 | break; |
3413 | case '\\': | 3416 | case '\\': |
3414 | if (next == EOF) { | 3417 | if (next == EOF) { |
3415 | syntax(); | 3418 | syntax("\\<eof>"); |
3416 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); | 3419 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); |
3417 | return 1; | 3420 | return 1; |
3418 | } | 3421 | } |
@@ -3434,7 +3437,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3434 | b_addchr(dest, ch); | 3437 | b_addchr(dest, ch); |
3435 | } | 3438 | } |
3436 | if (ch == EOF) { | 3439 | if (ch == EOF) { |
3437 | syntax(); | 3440 | syntax("unterminated '"); |
3438 | debug_printf_parse("parse_stream return 1: unterminated '\n"); | 3441 | debug_printf_parse("parse_stream return 1: unterminated '\n"); |
3439 | return 1; | 3442 | return 1; |
3440 | } | 3443 | } |
@@ -3455,11 +3458,14 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3455 | if (next == '>') { | 3458 | if (next == '>') { |
3456 | redir_style = REDIRECT_APPEND; | 3459 | redir_style = REDIRECT_APPEND; |
3457 | b_getch(input); | 3460 | b_getch(input); |
3458 | } else if (next == '(') { | 3461 | } |
3459 | syntax(); /* until we support >(list) Process Substitution */ | 3462 | #if 0 |
3463 | else if (next == '(') { | ||
3464 | syntax(">(process) not supported"); | ||
3460 | debug_printf_parse("parse_stream return 1: >(process) not supported\n"); | 3465 | debug_printf_parse("parse_stream return 1: >(process) not supported\n"); |
3461 | return 1; | 3466 | return 1; |
3462 | } | 3467 | } |
3468 | #endif | ||
3463 | setup_redirect(ctx, redir_fd, redir_style, input); | 3469 | setup_redirect(ctx, redir_fd, redir_style, input); |
3464 | break; | 3470 | break; |
3465 | case '<': | 3471 | case '<': |
@@ -3472,11 +3478,14 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3472 | } else if (next == '>') { | 3478 | } else if (next == '>') { |
3473 | redir_style = REDIRECT_IO; | 3479 | redir_style = REDIRECT_IO; |
3474 | b_getch(input); | 3480 | b_getch(input); |
3475 | } else if (next == '(') { | 3481 | } |
3476 | syntax(); /* until we support <(list) Process Substitution */ | 3482 | #if 0 |
3483 | else if (next == '(') { | ||
3484 | syntax("<(process) not supported"); | ||
3477 | debug_printf_parse("parse_stream return 1: <(process) not supported\n"); | 3485 | debug_printf_parse("parse_stream return 1: <(process) not supported\n"); |
3478 | return 1; | 3486 | return 1; |
3479 | } | 3487 | } |
3488 | #endif | ||
3480 | setup_redirect(ctx, redir_fd, redir_style, input); | 3489 | setup_redirect(ctx, redir_fd, redir_style, input); |
3481 | break; | 3490 | break; |
3482 | case ';': | 3491 | case ';': |
@@ -3513,13 +3522,12 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
3513 | break; | 3522 | break; |
3514 | case ')': | 3523 | case ')': |
3515 | case '}': | 3524 | case '}': |
3516 | syntax(); /* Proper use of this character is caught by end_trigger */ | 3525 | syntax("unexpected }"); /* Proper use of this character is caught by end_trigger */ |
3517 | debug_printf_parse("parse_stream return 1: unexpected '}'\n"); | 3526 | debug_printf_parse("parse_stream return 1: unexpected '}'\n"); |
3518 | return 1; | 3527 | return 1; |
3519 | default: | 3528 | default: |
3520 | syntax(); /* this is really an internal logic error */ | 3529 | if (ENABLE_HUSH_DEBUG) |
3521 | debug_printf_parse("parse_stream return 1: internal logic error\n"); | 3530 | bb_error_msg_and_die("BUG: unexpected %c\n", ch); |
3522 | return 1; | ||
3523 | } | 3531 | } |
3524 | } | 3532 | } |
3525 | /* Complain if quote? No, maybe we just finished a command substitution | 3533 | /* Complain if quote? No, maybe we just finished a command substitution |
@@ -3585,7 +3593,7 @@ static int parse_and_run_stream(struct in_str *inp, int parse_flag) | |||
3585 | * TEST should be printed */ | 3593 | * TEST should be printed */ |
3586 | rcode = parse_stream(&temp, &ctx, inp, ";\n"); | 3594 | rcode = parse_stream(&temp, &ctx, inp, ";\n"); |
3587 | if (rcode != 1 && ctx.old_flag != 0) { | 3595 | if (rcode != 1 && ctx.old_flag != 0) { |
3588 | syntax(); | 3596 | syntax(NULL); |
3589 | } | 3597 | } |
3590 | if (rcode != 1 && ctx.old_flag == 0) { | 3598 | if (rcode != 1 && ctx.old_flag == 0) { |
3591 | done_word(&temp, &ctx); | 3599 | done_word(&temp, &ctx); |