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 | |
| 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')
| -rw-r--r-- | shell/hush.c | 66 | ||||
| -rw-r--r-- | shell/hush_test/hush-parsing/noeol3.right (renamed from shell/hush_test/hush-bugs/noeol3.right) | 0 | ||||
| -rwxr-xr-x | shell/hush_test/hush-parsing/noeol3.tests (renamed from shell/hush_test/hush-bugs/noeol3.tests) | 0 |
3 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); |
diff --git a/shell/hush_test/hush-bugs/noeol3.right b/shell/hush_test/hush-parsing/noeol3.right index 56f8515b7..56f8515b7 100644 --- a/shell/hush_test/hush-bugs/noeol3.right +++ b/shell/hush_test/hush-parsing/noeol3.right | |||
diff --git a/shell/hush_test/hush-bugs/noeol3.tests b/shell/hush_test/hush-parsing/noeol3.tests index ec958ed7a..ec958ed7a 100755 --- a/shell/hush_test/hush-bugs/noeol3.tests +++ b/shell/hush_test/hush-parsing/noeol3.tests | |||
