diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-21 10:18:23 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-21 10:18:23 +0000 |
| commit | 219e88d0505f9c06d42772333995887ca694465a (patch) | |
| tree | 6b581bd94ea16537313768a61113fb95ba453485 /shell | |
| parent | 004baba2d6857a3cc0c5d25020ec257169a2d2b7 (diff) | |
| download | busybox-w32-219e88d0505f9c06d42772333995887ca694465a.tar.gz busybox-w32-219e88d0505f9c06d42772333995887ca694465a.tar.bz2 busybox-w32-219e88d0505f9c06d42772333995887ca694465a.zip | |
hush: using smallints where we can. save ~20 bytes in code and
some data storage at runtime.
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 97 |
1 files changed, 50 insertions, 47 deletions
diff --git a/shell/hush.c b/shell/hush.c index 107b821f8..90c89fba2 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -137,9 +137,10 @@ static const char *indenter(int i) | |||
| 137 | #endif | 137 | #endif |
| 138 | 138 | ||
| 139 | #define SPECIAL_VAR_SYMBOL 3 | 139 | #define SPECIAL_VAR_SYMBOL 3 |
| 140 | #define FLAG_EXIT_FROM_LOOP 1 | 140 | |
| 141 | #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ | 141 | #define PARSEFLAG_EXIT_FROM_LOOP 1 |
| 142 | #define FLAG_REPARSING (1 << 2) /* >= 2nd pass */ | 142 | #define PARSEFLAG_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ |
| 143 | #define PARSEFLAG_REPARSING (1 << 2) /* >= 2nd pass */ | ||
| 143 | 144 | ||
| 144 | typedef enum { | 145 | typedef enum { |
| 145 | REDIRECT_INPUT = 1, | 146 | REDIRECT_INPUT = 1, |
| @@ -210,10 +211,10 @@ struct p_context { | |||
| 210 | struct pipe *list_head; | 211 | struct pipe *list_head; |
| 211 | struct pipe *pipe; | 212 | struct pipe *pipe; |
| 212 | struct redir_struct *pending_redirect; | 213 | struct redir_struct *pending_redirect; |
| 213 | reserved_style res_w; | 214 | smallint res_w; |
| 214 | int old_flag; /* for figuring out valid reserved words */ | 215 | smallint parse_type; /* bitmask of PARSEFLAG_xxx, defines type of parser : ";$" common or special symbol */ |
| 216 | int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */ | ||
| 215 | struct p_context *stack; | 217 | struct p_context *stack; |
| 216 | int parse_type; /* define type of parser : ";$" common or special symbol */ | ||
| 217 | /* How about quoting status? */ | 218 | /* How about quoting status? */ |
| 218 | }; | 219 | }; |
| 219 | 220 | ||
| @@ -249,17 +250,17 @@ struct pipe { | |||
| 249 | struct pipe *next; | 250 | struct pipe *next; |
| 250 | int num_progs; /* total number of programs in job */ | 251 | int num_progs; /* total number of programs in job */ |
| 251 | int running_progs; /* number of programs running (not exited) */ | 252 | int running_progs; /* number of programs running (not exited) */ |
| 252 | char *cmdbuf; /* buffer various argv's point into */ | 253 | int stopped_progs; /* number of programs alive, but stopped */ |
| 253 | #if ENABLE_HUSH_JOB | 254 | #if ENABLE_HUSH_JOB |
| 254 | int jobid; /* job number */ | 255 | int jobid; /* job number */ |
| 255 | char *cmdtext; /* name of job */ | ||
| 256 | pid_t pgrp; /* process group ID for the job */ | 256 | pid_t pgrp; /* process group ID for the job */ |
| 257 | char *cmdtext; /* name of job */ | ||
| 257 | #endif | 258 | #endif |
| 259 | char *cmdbuf; /* buffer various argv's point into */ | ||
| 258 | struct child_prog *progs; /* array of commands in pipe */ | 260 | struct child_prog *progs; /* array of commands in pipe */ |
| 259 | int stopped_progs; /* number of programs alive, but stopped */ | ||
| 260 | int job_context; /* bitmask defining current context */ | 261 | int job_context; /* bitmask defining current context */ |
| 261 | pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ | 262 | smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ |
| 262 | reserved_style r_mode; /* supports if, for, while, until */ | 263 | smallint res_word; /* needed for if, for, while, until... */ |
| 263 | }; | 264 | }; |
| 264 | 265 | ||
| 265 | struct close_me { | 266 | struct close_me { |
| @@ -271,8 +272,8 @@ struct variables { | |||
| 271 | struct variables *next; | 272 | struct variables *next; |
| 272 | const char *name; | 273 | const char *name; |
| 273 | const char *value; | 274 | const char *value; |
| 274 | int flg_export; | 275 | smallint flg_export; |
| 275 | int flg_read_only; | 276 | smallint flg_read_only; |
| 276 | }; | 277 | }; |
| 277 | 278 | ||
| 278 | typedef struct { | 279 | typedef struct { |
| @@ -703,8 +704,8 @@ static int builtin_eval(char **argv) | |||
| 703 | 704 | ||
| 704 | if (argv[1]) { | 705 | if (argv[1]) { |
| 705 | str = make_string(argv + 1); | 706 | str = make_string(argv + 1); |
| 706 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | | 707 | parse_string_outer(str, PARSEFLAG_EXIT_FROM_LOOP | |
| 707 | FLAG_PARSE_SEMICOLON); | 708 | PARSEFLAG_SEMICOLON); |
| 708 | free(str); | 709 | free(str); |
| 709 | rcode = last_return_code; | 710 | rcode = last_return_code; |
| 710 | } | 711 | } |
| @@ -1897,10 +1898,11 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
| 1897 | }; | 1898 | }; |
| 1898 | 1899 | ||
| 1899 | int pin, prn; | 1900 | int pin, prn; |
| 1901 | |||
| 1900 | pin = 0; | 1902 | pin = 0; |
| 1901 | while (pi) { | 1903 | while (pi) { |
| 1902 | fprintf(stderr, "%*spipe %d r_mode=%s followup=%d %s\n", lvl*2, "", | 1904 | fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", |
| 1903 | pin, RES[pi->r_mode], pi->followup, PIPE[pi->followup]); | 1905 | pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); |
| 1904 | prn = 0; | 1906 | prn = 0; |
| 1905 | while (prn < pi->num_progs) { | 1907 | while (prn < pi->num_progs) { |
| 1906 | struct child_prog *child = &pi->progs[prn]; | 1908 | struct child_prog *child = &pi->progs[prn]; |
| @@ -1942,21 +1944,22 @@ static int run_list_real(struct pipe *pi) | |||
| 1942 | int rcode = 0; /* probably for gcc only */ | 1944 | int rcode = 0; /* probably for gcc only */ |
| 1943 | int flag_restore = 0; | 1945 | int flag_restore = 0; |
| 1944 | int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ | 1946 | int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */ |
| 1945 | reserved_style rmode, skip_more_in_this_rmode = RES_XXXX; | 1947 | reserved_style rword; |
| 1948 | reserved_style skip_more_for_this_rword = RES_XXXX; | ||
| 1946 | 1949 | ||
| 1947 | debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1); | 1950 | debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1); |
| 1948 | 1951 | ||
| 1949 | /* check syntax for "for" */ | 1952 | /* check syntax for "for" */ |
| 1950 | for (rpipe = pi; rpipe; rpipe = rpipe->next) { | 1953 | for (rpipe = pi; rpipe; rpipe = rpipe->next) { |
| 1951 | if ((rpipe->r_mode == RES_IN || rpipe->r_mode == RES_FOR) | 1954 | if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR) |
| 1952 | && (rpipe->next == NULL) | 1955 | && (rpipe->next == NULL) |
| 1953 | ) { | 1956 | ) { |
| 1954 | syntax(); /* unterminated FOR (no IN or no commands after IN) */ | 1957 | syntax(); /* unterminated FOR (no IN or no commands after IN) */ |
| 1955 | debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); | 1958 | debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level); |
| 1956 | return 1; | 1959 | return 1; |
| 1957 | } | 1960 | } |
| 1958 | if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs[0].argv != NULL) | 1961 | if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL) |
| 1959 | || (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN) | 1962 | || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN) |
| 1960 | ) { | 1963 | ) { |
| 1961 | /* TODO: what is tested in the first condition? */ | 1964 | /* TODO: what is tested in the first condition? */ |
| 1962 | syntax(); /* 2nd: malformed FOR (not followed by IN) */ | 1965 | syntax(); /* 2nd: malformed FOR (not followed by IN) */ |
| @@ -2008,32 +2011,32 @@ static int run_list_real(struct pipe *pi) | |||
| 2008 | #endif | 2011 | #endif |
| 2009 | 2012 | ||
| 2010 | for (; pi; pi = flag_restore ? rpipe : pi->next) { | 2013 | for (; pi; pi = flag_restore ? rpipe : pi->next) { |
| 2011 | rmode = pi->r_mode; | 2014 | rword = pi->res_word; |
| 2012 | if (rmode == RES_WHILE || rmode == RES_UNTIL || rmode == RES_FOR) { | 2015 | if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) { |
| 2013 | flag_restore = 0; | 2016 | flag_restore = 0; |
| 2014 | if (!rpipe) { | 2017 | if (!rpipe) { |
| 2015 | flag_rep = 0; | 2018 | flag_rep = 0; |
| 2016 | rpipe = pi; | 2019 | rpipe = pi; |
| 2017 | } | 2020 | } |
| 2018 | } | 2021 | } |
| 2019 | debug_printf_exec(": rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", | 2022 | debug_printf_exec(": rword=%d if_code=%d next_if_code=%d skip_more=%d\n", |
| 2020 | rmode, if_code, next_if_code, skip_more_in_this_rmode); | 2023 | rword, if_code, next_if_code, skip_more_for_this_rword); |
| 2021 | if (rmode == skip_more_in_this_rmode && flag_skip) { | 2024 | if (rword == skip_more_for_this_rword && flag_skip) { |
| 2022 | if (pi->followup == PIPE_SEQ) | 2025 | if (pi->followup == PIPE_SEQ) |
| 2023 | flag_skip = 0; | 2026 | flag_skip = 0; |
| 2024 | continue; | 2027 | continue; |
| 2025 | } | 2028 | } |
| 2026 | flag_skip = 1; | 2029 | flag_skip = 1; |
| 2027 | skip_more_in_this_rmode = RES_XXXX; | 2030 | skip_more_for_this_rword = RES_XXXX; |
| 2028 | if (rmode == RES_THEN || rmode == RES_ELSE) | 2031 | if (rword == RES_THEN || rword == RES_ELSE) |
| 2029 | if_code = next_if_code; | 2032 | if_code = next_if_code; |
| 2030 | if (rmode == RES_THEN && if_code) | 2033 | if (rword == RES_THEN && if_code) |
| 2031 | continue; | 2034 | continue; |
| 2032 | if (rmode == RES_ELSE && !if_code) | 2035 | if (rword == RES_ELSE && !if_code) |
| 2033 | continue; | 2036 | continue; |
| 2034 | if (rmode == RES_ELIF && !if_code) | 2037 | if (rword == RES_ELIF && !if_code) |
| 2035 | break; | 2038 | break; |
| 2036 | if (rmode == RES_FOR && pi->num_progs) { | 2039 | if (rword == RES_FOR && pi->num_progs) { |
| 2037 | if (!for_lcur) { | 2040 | if (!for_lcur) { |
| 2038 | /* if no variable values after "in" we skip "for" */ | 2041 | /* if no variable values after "in" we skip "for" */ |
| 2039 | if (!pi->next->progs->argv) | 2042 | if (!pi->next->progs->argv) |
| @@ -2059,13 +2062,13 @@ static int run_list_real(struct pipe *pi) | |||
| 2059 | pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); | 2062 | pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); |
| 2060 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; | 2063 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; |
| 2061 | } | 2064 | } |
| 2062 | if (rmode == RES_IN) | 2065 | if (rword == RES_IN) |
| 2063 | continue; | 2066 | continue; |
| 2064 | if (rmode == RES_DO) { | 2067 | if (rword == RES_DO) { |
| 2065 | if (!flag_rep) | 2068 | if (!flag_rep) |
| 2066 | continue; | 2069 | continue; |
| 2067 | } | 2070 | } |
| 2068 | if (rmode == RES_DONE) { | 2071 | if (rword == RES_DONE) { |
| 2069 | if (flag_rep) { | 2072 | if (flag_rep) { |
| 2070 | flag_restore = 1; | 2073 | flag_restore = 1; |
| 2071 | } else { | 2074 | } else { |
| @@ -2107,16 +2110,16 @@ static int run_list_real(struct pipe *pi) | |||
| 2107 | debug_printf_exec(": setting last_return_code=%d\n", rcode); | 2110 | debug_printf_exec(": setting last_return_code=%d\n", rcode); |
| 2108 | last_return_code = rcode; | 2111 | last_return_code = rcode; |
| 2109 | pi->num_progs = save_num_progs; /* restore number of programs */ | 2112 | pi->num_progs = save_num_progs; /* restore number of programs */ |
| 2110 | if (rmode == RES_IF || rmode == RES_ELIF) | 2113 | if (rword == RES_IF || rword == RES_ELIF) |
| 2111 | next_if_code = rcode; /* can be overwritten a number of times */ | 2114 | next_if_code = rcode; /* can be overwritten a number of times */ |
| 2112 | if (rmode == RES_WHILE) | 2115 | if (rword == RES_WHILE) |
| 2113 | flag_rep = !last_return_code; | 2116 | flag_rep = !last_return_code; |
| 2114 | if (rmode == RES_UNTIL) | 2117 | if (rword == RES_UNTIL) |
| 2115 | flag_rep = last_return_code; | 2118 | flag_rep = last_return_code; |
| 2116 | if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR) | 2119 | if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR) |
| 2117 | || (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND) | 2120 | || (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND) |
| 2118 | ) { | 2121 | ) { |
| 2119 | skip_more_in_this_rmode = rmode; | 2122 | skip_more_for_this_rword = rword; |
| 2120 | } | 2123 | } |
| 2121 | checkjobs(NULL); | 2124 | checkjobs(NULL); |
| 2122 | } | 2125 | } |
| @@ -2192,7 +2195,7 @@ static int free_pipe_list(struct pipe *head, int indent) | |||
| 2192 | struct pipe *pi, *next; | 2195 | struct pipe *pi, *next; |
| 2193 | 2196 | ||
| 2194 | for (pi = head; pi; pi = next) { | 2197 | for (pi = head; pi; pi = next) { |
| 2195 | debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->r_mode); | 2198 | debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); |
| 2196 | rcode = free_pipe(pi, indent); | 2199 | rcode = free_pipe(pi, indent); |
| 2197 | debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); | 2200 | debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); |
| 2198 | next = pi->next; | 2201 | next = pi->next; |
| @@ -2786,7 +2789,7 @@ static struct pipe *new_pipe(void) | |||
| 2786 | /*pi->next = NULL;*/ | 2789 | /*pi->next = NULL;*/ |
| 2787 | /*pi->followup = 0; invalid */ | 2790 | /*pi->followup = 0; invalid */ |
| 2788 | if (RES_NONE) | 2791 | if (RES_NONE) |
| 2789 | pi->r_mode = RES_NONE; | 2792 | pi->res_word = RES_NONE; |
| 2790 | return pi; | 2793 | return pi; |
| 2791 | } | 2794 | } |
| 2792 | 2795 | ||
| @@ -2898,7 +2901,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |||
| 2898 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); | 2901 | debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n"); |
| 2899 | return 1; | 2902 | return 1; |
| 2900 | } | 2903 | } |
| 2901 | if (!child->argv && (ctx->parse_type & FLAG_PARSE_SEMICOLON)) { | 2904 | if (!child->argv && (ctx->parse_type & PARSEFLAG_SEMICOLON)) { |
| 2902 | debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data); | 2905 | debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data); |
| 2903 | if (reserved_word(dest, ctx)) { | 2906 | if (reserved_word(dest, ctx)) { |
| 2904 | debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX)); | 2907 | debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX)); |
| @@ -2986,7 +2989,7 @@ static int done_pipe(struct p_context *ctx, pipe_style type) | |||
| 2986 | debug_printf_parse("done_pipe entered, followup %d\n", type); | 2989 | debug_printf_parse("done_pipe entered, followup %d\n", type); |
| 2987 | not_null = done_command(ctx); /* implicit closure of previous command */ | 2990 | not_null = done_command(ctx); /* implicit closure of previous command */ |
| 2988 | ctx->pipe->followup = type; | 2991 | ctx->pipe->followup = type; |
| 2989 | ctx->pipe->r_mode = ctx->res_w; | 2992 | ctx->pipe->res_word = ctx->res_w; |
| 2990 | /* Without this check, even just <enter> on command line generates | 2993 | /* Without this check, even just <enter> on command line generates |
| 2991 | * tree of three NOPs (!). Which is harmless but annoying. | 2994 | * tree of three NOPs (!). Which is harmless but annoying. |
| 2992 | * IOW: it is safe to do it unconditionally. */ | 2995 | * IOW: it is safe to do it unconditionally. */ |
| @@ -3510,7 +3513,7 @@ static int parse_stream_outer(struct in_str *inp, int parse_flag) | |||
| 3510 | ctx.parse_type = parse_flag; | 3513 | ctx.parse_type = parse_flag; |
| 3511 | initialize_context(&ctx); | 3514 | initialize_context(&ctx); |
| 3512 | update_charmap(); | 3515 | update_charmap(); |
| 3513 | if (!(parse_flag & FLAG_PARSE_SEMICOLON) || (parse_flag & FLAG_REPARSING)) | 3516 | if (!(parse_flag & PARSEFLAG_SEMICOLON) || (parse_flag & PARSEFLAG_REPARSING)) |
| 3514 | set_in_charmap(";$&|", CHAR_ORDINARY); | 3517 | set_in_charmap(";$&|", CHAR_ORDINARY); |
| 3515 | #if ENABLE_HUSH_INTERACTIVE | 3518 | #if ENABLE_HUSH_INTERACTIVE |
| 3516 | inp->promptmode = 1; | 3519 | inp->promptmode = 1; |
| @@ -3539,7 +3542,7 @@ static int parse_stream_outer(struct in_str *inp, int parse_flag) | |||
| 3539 | free_pipe_list(ctx.list_head, 0); | 3542 | free_pipe_list(ctx.list_head, 0); |
| 3540 | } | 3543 | } |
| 3541 | b_free(&temp); | 3544 | b_free(&temp); |
| 3542 | } while (rcode != -1 && !(parse_flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ | 3545 | } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ |
| 3543 | return 0; | 3546 | return 0; |
| 3544 | } | 3547 | } |
| 3545 | 3548 | ||
| @@ -3555,7 +3558,7 @@ static int parse_file_outer(FILE *f) | |||
| 3555 | int rcode; | 3558 | int rcode; |
| 3556 | struct in_str input; | 3559 | struct in_str input; |
| 3557 | setup_file_in_str(&input, f); | 3560 | setup_file_in_str(&input, f); |
| 3558 | rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); | 3561 | rcode = parse_stream_outer(&input, PARSEFLAG_SEMICOLON); |
| 3559 | return rcode; | 3562 | return rcode; |
| 3560 | } | 3563 | } |
| 3561 | 3564 | ||
| @@ -3646,7 +3649,7 @@ int hush_main(int argc, char **argv) | |||
| 3646 | case 'c': | 3649 | case 'c': |
| 3647 | global_argv = argv + optind; | 3650 | global_argv = argv + optind; |
| 3648 | global_argc = argc - optind; | 3651 | global_argc = argc - optind; |
| 3649 | opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); | 3652 | opt = parse_string_outer(optarg, PARSEFLAG_SEMICOLON); |
| 3650 | goto final_return; | 3653 | goto final_return; |
| 3651 | case 'i': | 3654 | case 'i': |
| 3652 | /* Well, we cannot just declare interactiveness, | 3655 | /* Well, we cannot just declare interactiveness, |
