diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-14 12:43:13 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-14 12:43:13 +0000 |
commit | 371de4acf7eb345bf8c92f257f9a14342603e59a (patch) | |
tree | d6286600ded22783a7b08801f52b024178c39f61 | |
parent | ded6ad34edaa03dcd4b899787c2bbdc2ee3e7988 (diff) | |
download | busybox-w32-371de4acf7eb345bf8c92f257f9a14342603e59a.tar.gz busybox-w32-371de4acf7eb345bf8c92f257f9a14342603e59a.tar.bz2 busybox-w32-371de4acf7eb345bf8c92f257f9a14342603e59a.zip |
hush: next small step towards functions
-rw-r--r-- | shell/hush.c | 72 |
1 files changed, 53 insertions, 19 deletions
diff --git a/shell/hush.c b/shell/hush.c index 377f13aa4..6efc3073b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -96,6 +96,12 @@ | |||
96 | #endif | 96 | #endif |
97 | 97 | ||
98 | 98 | ||
99 | /* Keep unconditionally on for now */ | ||
100 | #define HUSH_DEBUG 1 | ||
101 | /* In progress... */ | ||
102 | #define ENABLE_HUSH_FUNCTIONS 0 | ||
103 | |||
104 | |||
99 | /* If you comment out one of these below, it will be #defined later | 105 | /* If you comment out one of these below, it will be #defined later |
100 | * to perform debug printfs to stderr: */ | 106 | * to perform debug printfs to stderr: */ |
101 | #define debug_printf(...) do {} while (0) | 107 | #define debug_printf(...) do {} while (0) |
@@ -218,8 +224,6 @@ void xxfree(void *ptr) | |||
218 | #endif | 224 | #endif |
219 | 225 | ||
220 | 226 | ||
221 | /* Keep unconditionally on for now */ | ||
222 | #define HUSH_DEBUG 1 | ||
223 | /* Do we support ANY keywords? */ | 227 | /* Do we support ANY keywords? */ |
224 | #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE | 228 | #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE |
225 | #define HAS_KEYWORDS 1 | 229 | #define HAS_KEYWORDS 1 |
@@ -307,7 +311,7 @@ struct command { | |||
307 | pid_t pid; /* 0 if exited */ | 311 | pid_t pid; /* 0 if exited */ |
308 | int assignment_cnt; /* how many argv[i] are assignments? */ | 312 | int assignment_cnt; /* how many argv[i] are assignments? */ |
309 | smallint is_stopped; /* is the command currently running? */ | 313 | smallint is_stopped; /* is the command currently running? */ |
310 | smallint subshell; /* flag, non-zero if group must be forked */ | 314 | smallint grp_type; |
311 | struct pipe *group; /* if non-NULL, this "prog" is {} group, | 315 | struct pipe *group; /* if non-NULL, this "prog" is {} group, |
312 | * subshell, or a compound statement */ | 316 | * subshell, or a compound statement */ |
313 | char **argv; /* command name and arguments */ | 317 | char **argv; /* command name and arguments */ |
@@ -319,6 +323,11 @@ struct command { | |||
319 | * Example: argv[0]=='.^C*^C.' here: echo .$*. | 323 | * Example: argv[0]=='.^C*^C.' here: echo .$*. |
320 | * References of the form ^C`cmd arg^C are `cmd arg` substitutions. | 324 | * References of the form ^C`cmd arg^C are `cmd arg` substitutions. |
321 | */ | 325 | */ |
326 | #define GRP_NORMAL 0 | ||
327 | #define GRP_SUBSHELL 1 | ||
328 | #if ENABLE_HUSH_FUNCTIONS | ||
329 | #define GRP_FUNCTION 2 | ||
330 | #endif | ||
322 | 331 | ||
323 | struct pipe { | 332 | struct pipe { |
324 | struct pipe *next; | 333 | struct pipe *next; |
@@ -1016,12 +1025,14 @@ static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len) | |||
1016 | static void o_addqchr(o_string *o, int ch) | 1025 | static void o_addqchr(o_string *o, int ch) |
1017 | { | 1026 | { |
1018 | int sz = 1; | 1027 | int sz = 1; |
1019 | if (strchr("*?[\\", ch)) { | 1028 | char *found = strchr("*?[\\", ch); |
1029 | if (found) | ||
1020 | sz++; | 1030 | sz++; |
1031 | o_grow_by(o, sz); | ||
1032 | if (found) { | ||
1021 | o->data[o->length] = '\\'; | 1033 | o->data[o->length] = '\\'; |
1022 | o->length++; | 1034 | o->length++; |
1023 | } | 1035 | } |
1024 | o_grow_by(o, sz); | ||
1025 | o->data[o->length] = ch; | 1036 | o->data[o->length] = ch; |
1026 | o->length++; | 1037 | o->length++; |
1027 | o->data[o->length] = '\0'; | 1038 | o->data[o->length] = '\0'; |
@@ -1834,7 +1845,15 @@ static int run_pipe(struct pipe *pi) | |||
1834 | */ | 1845 | */ |
1835 | command = &(pi->cmds[0]); | 1846 | command = &(pi->cmds[0]); |
1836 | 1847 | ||
1837 | if (single_and_fg && command->group && command->subshell == 0) { | 1848 | #if ENABLE_HUSH_FUNCTIONS |
1849 | if (single_and_fg && command->group && command->grp_type == GRP_FUNCTION) { | ||
1850 | /* We "execute" function definition */ | ||
1851 | bb_error_msg("here we ought to remember function definition, and go on"); | ||
1852 | return EXIT_SUCCESS; | ||
1853 | } | ||
1854 | #endif | ||
1855 | |||
1856 | if (single_and_fg && command->group && command->grp_type == GRP_NORMAL) { | ||
1838 | debug_printf("non-subshell grouping\n"); | 1857 | debug_printf("non-subshell grouping\n"); |
1839 | setup_redirects(command, squirrel); | 1858 | setup_redirects(command, squirrel); |
1840 | debug_printf_exec(": run_list\n"); | 1859 | debug_printf_exec(": run_list\n"); |
@@ -2023,7 +2042,7 @@ static int run_pipe(struct pipe *pi) | |||
2023 | #ifndef debug_print_tree | 2042 | #ifndef debug_print_tree |
2024 | static void debug_print_tree(struct pipe *pi, int lvl) | 2043 | static void debug_print_tree(struct pipe *pi, int lvl) |
2025 | { | 2044 | { |
2026 | static const char *PIPE[] = { | 2045 | static const char *const PIPE[] = { |
2027 | [PIPE_SEQ] = "SEQ", | 2046 | [PIPE_SEQ] = "SEQ", |
2028 | [PIPE_AND] = "AND", | 2047 | [PIPE_AND] = "AND", |
2029 | [PIPE_OR ] = "OR" , | 2048 | [PIPE_OR ] = "OR" , |
@@ -2057,6 +2076,13 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
2057 | [RES_XXXX ] = "XXXX" , | 2076 | [RES_XXXX ] = "XXXX" , |
2058 | [RES_SNTX ] = "SNTX" , | 2077 | [RES_SNTX ] = "SNTX" , |
2059 | }; | 2078 | }; |
2079 | static const char *const GRPTYPE[] = { | ||
2080 | "()", | ||
2081 | "{}", | ||
2082 | #if ENABLE_HUSH_FUNCTIONS | ||
2083 | "func()", | ||
2084 | #endif | ||
2085 | }; | ||
2060 | 2086 | ||
2061 | int pin, prn; | 2087 | int pin, prn; |
2062 | 2088 | ||
@@ -2072,7 +2098,7 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
2072 | fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); | 2098 | fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); |
2073 | if (command->group) { | 2099 | if (command->group) { |
2074 | fprintf(stderr, " group %s: (argv=%p)\n", | 2100 | fprintf(stderr, " group %s: (argv=%p)\n", |
2075 | (command->subshell ? "()" : "{}"), | 2101 | GRPTYPE[command->grp_type], |
2076 | argv); | 2102 | argv); |
2077 | debug_print_tree(command->group, lvl+1); | 2103 | debug_print_tree(command->group, lvl+1); |
2078 | prn++; | 2104 | prn++; |
@@ -2443,7 +2469,7 @@ static int free_pipe(struct pipe *pi, int indent) | |||
2443 | free_strings(command->argv); | 2469 | free_strings(command->argv); |
2444 | command->argv = NULL; | 2470 | command->argv = NULL; |
2445 | } else if (command->group) { | 2471 | } else if (command->group) { |
2446 | debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), command->subshell); | 2472 | debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type); |
2447 | ret_code = free_pipe_list(command->group, indent+3); | 2473 | ret_code = free_pipe_list(command->group, indent+3); |
2448 | debug_printf_clean("%s end group\n", indenter(indent)); | 2474 | debug_printf_clean("%s end group\n", indenter(indent)); |
2449 | } else { | 2475 | } else { |
@@ -2572,7 +2598,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2572 | #if ENABLE_HUSH_TICK | 2598 | #if ENABLE_HUSH_TICK |
2573 | o_string subst_result = NULL_O_STRING; | 2599 | o_string subst_result = NULL_O_STRING; |
2574 | #endif | 2600 | #endif |
2575 | |||
2576 | o_addstr(output, arg, p - arg); | 2601 | o_addstr(output, arg, p - arg); |
2577 | debug_print_list("expand_vars_to_list[1]", output, n); | 2602 | debug_print_list("expand_vars_to_list[1]", output, n); |
2578 | arg = ++p; | 2603 | arg = ++p; |
@@ -3100,7 +3125,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
3100 | done_pipe(ctx, PIPE_SEQ); | 3125 | done_pipe(ctx, PIPE_SEQ); |
3101 | old = ctx->stack; | 3126 | old = ctx->stack; |
3102 | old->command->group = ctx->list_head; | 3127 | old->command->group = ctx->list_head; |
3103 | old->command->subshell = 0; | 3128 | old->command->grp_type = GRP_NORMAL; |
3104 | *ctx = *old; /* physical copy */ | 3129 | *ctx = *old; /* physical copy */ |
3105 | free(old); | 3130 | free(old); |
3106 | } | 3131 | } |
@@ -3461,15 +3486,24 @@ static int process_command_subs(o_string *dest, | |||
3461 | static int parse_group(o_string *dest, struct parse_context *ctx, | 3486 | static int parse_group(o_string *dest, struct parse_context *ctx, |
3462 | struct in_str *input, int ch) | 3487 | struct in_str *input, int ch) |
3463 | { | 3488 | { |
3464 | /* NB: parse_group may create and use its own o_string, | 3489 | /* dest contains characters seen prior to ( or {. |
3465 | * without any code changes. It just so happens that code is smaller | 3490 | * Typically it's empty, but for functions defs, |
3466 | * if we (ab)use caller's one. */ | 3491 | * it contains function name (without '()'). */ |
3467 | int rcode; | 3492 | int rcode; |
3468 | const char *endch = NULL; | 3493 | const char *endch = NULL; |
3469 | struct parse_context sub; | 3494 | struct parse_context sub; |
3470 | struct command *command = ctx->command; | 3495 | struct command *command = ctx->command; |
3471 | 3496 | ||
3472 | debug_printf_parse("parse_group entered\n"); | 3497 | debug_printf_parse("parse_group entered\n"); |
3498 | #if ENABLE_HUSH_FUNCTIONS | ||
3499 | if (ch == 'F') { /* function definition? */ | ||
3500 | bb_error_msg("aha '%s' is a function, parsing it...", dest->data); | ||
3501 | //command->fname = dest->data; | ||
3502 | command->grp_type = GRP_FUNCTION; | ||
3503 | //TODO: review every o_reset() location... do they handle all o_string fields correctly? | ||
3504 | memset(dest, 0, sizeof(*dest)); | ||
3505 | } | ||
3506 | #endif | ||
3473 | if (command->argv /* word [word](... */ | 3507 | if (command->argv /* word [word](... */ |
3474 | || dest->length /* word(... */ | 3508 | || dest->length /* word(... */ |
3475 | || dest->nonnull /* ""(... */ | 3509 | || dest->nonnull /* ""(... */ |
@@ -3482,11 +3516,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3482 | endch = "}"; | 3516 | endch = "}"; |
3483 | if (ch == '(') { | 3517 | if (ch == '(') { |
3484 | endch = ")"; | 3518 | endch = ")"; |
3485 | command->subshell = 1; | 3519 | command->grp_type = GRP_SUBSHELL; |
3486 | } | 3520 | } |
3487 | //TODO if (ch == 'F') { /* function definition */ | ||
3488 | // command->subshell = 2; | ||
3489 | // } | ||
3490 | rcode = parse_stream(dest, &sub, input, endch); | 3521 | rcode = parse_stream(dest, &sub, input, endch); |
3491 | if (rcode == 0) { | 3522 | if (rcode == 0) { |
3492 | done_word(dest, &sub); /* finish off the final word in the subcontext */ | 3523 | done_word(dest, &sub); /* finish off the final word in the subcontext */ |
@@ -3988,16 +4019,18 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
3988 | continue; | 4019 | continue; |
3989 | } | 4020 | } |
3990 | #endif | 4021 | #endif |
3991 | #if 0 /* TODO: implement functions */ | 4022 | #if ENABLE_HUSH_FUNCTIONS |
3992 | if (dest->length != 0 /* not just () but word() */ | 4023 | if (dest->length != 0 /* not just () but word() */ |
3993 | && dest->nonnull == 0 /* not a"b"c() */ | 4024 | && dest->nonnull == 0 /* not a"b"c() */ |
3994 | && ctx->command->argv == NULL /* it's the first word */ | 4025 | && ctx->command->argv == NULL /* it's the first word */ |
4026 | //TODO: "func ( ) {...}" - note spaces - is valid format too in bash | ||
3995 | && i_peek(input) == ')' | 4027 | && i_peek(input) == ')' |
3996 | && !match_reserved_word(dest) | 4028 | && !match_reserved_word(dest) |
3997 | ) { | 4029 | ) { |
3998 | bb_error_msg("seems like a function definition"); | 4030 | bb_error_msg("seems like a function definition"); |
3999 | i_getch(input); | 4031 | i_getch(input); |
4000 | do { | 4032 | do { |
4033 | //TODO: do it properly. | ||
4001 | ch = i_getch(input); | 4034 | ch = i_getch(input); |
4002 | } while (ch == ' ' || ch == '\n'); | 4035 | } while (ch == ' ' || ch == '\n'); |
4003 | if (ch != '{') { | 4036 | if (ch != '{') { |
@@ -4005,6 +4038,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4005 | debug_printf_parse("parse_stream return 1\n"); | 4038 | debug_printf_parse("parse_stream return 1\n"); |
4006 | return 1; | 4039 | return 1; |
4007 | } | 4040 | } |
4041 | ch = 'F'; /* magic value */ | ||
4008 | } | 4042 | } |
4009 | #endif | 4043 | #endif |
4010 | case '{': | 4044 | case '{': |