diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-04 12:12:58 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-04 12:12:58 +0000 |
commit | 6da69cddc022773a062a039e354d1ad0ed3e32c8 (patch) | |
tree | 83874ddaf0f8d3726fea433e2fa3c405a63092bc /shell | |
parent | dfa9de71769f2ce9449b43f389962cc977663179 (diff) | |
download | busybox-w32-6da69cddc022773a062a039e354d1ad0ed3e32c8.tar.gz busybox-w32-6da69cddc022773a062a039e354d1ad0ed3e32c8.tar.bz2 busybox-w32-6da69cddc022773a062a039e354d1ad0ed3e32c8.zip |
hush: get rid of charmap[]
function old new delta
parse_stream 1447 1508 +61
get_local_var_value - 31 +31
run_list 2018 2020 +2
pseudo_exec_argv 151 149 -2
maybe_set_sighandler 50 47 -3
hush_exit 93 90 -3
builtin_wait 275 272 -3
check_and_run_traps 169 164 -5
hush_main 985 977 -8
file_get 260 240 -20
builtin_trap 438 414 -24
set_in_charmap 30 - -30
lookup_param 31 - -31
parse_and_run_stream 153 54 -99
------------------------------------------------------------------------------
(add/remove: 1/2 grow/shrink: 2/9 up/down: 94/-228) Total: -134 bytes
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 145 |
1 files changed, 55 insertions, 90 deletions
diff --git a/shell/hush.c b/shell/hush.c index efb20d91e..a57d5d811 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -61,7 +61,6 @@ | |||
61 | * figure out what to do with backslash-newline | 61 | * figure out what to do with backslash-newline |
62 | * propagate syntax errors, die on resource errors? | 62 | * propagate syntax errors, die on resource errors? |
63 | * continuation lines, both explicit and implicit - done? | 63 | * continuation lines, both explicit and implicit - done? |
64 | * maybe change charmap[] to use 2-bit entries | ||
65 | * | 64 | * |
66 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. | 65 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
67 | */ | 66 | */ |
@@ -201,30 +200,25 @@ static void debug_print_strings(const char *prefix, char **vv) | |||
201 | * Leak hunting. Use hush_leaktool.sh for post-processing. | 200 | * Leak hunting. Use hush_leaktool.sh for post-processing. |
202 | */ | 201 | */ |
203 | #ifdef FOR_HUSH_LEAKTOOL | 202 | #ifdef FOR_HUSH_LEAKTOOL |
204 | /* suppress "warning: no previous prototype..." */ | 203 | static void *xxmalloc(int lineno, size_t size) |
205 | void *xxmalloc(int lineno, size_t size); | ||
206 | void *xxrealloc(int lineno, void *ptr, size_t size); | ||
207 | char *xxstrdup(int lineno, const char *str); | ||
208 | void xxfree(void *ptr); | ||
209 | void *xxmalloc(int lineno, size_t size) | ||
210 | { | 204 | { |
211 | void *ptr = xmalloc((size + 0xff) & ~0xff); | 205 | void *ptr = xmalloc((size + 0xff) & ~0xff); |
212 | fdprintf(2, "line %d: malloc %p\n", lineno, ptr); | 206 | fdprintf(2, "line %d: malloc %p\n", lineno, ptr); |
213 | return ptr; | 207 | return ptr; |
214 | } | 208 | } |
215 | void *xxrealloc(int lineno, void *ptr, size_t size) | 209 | static void *xxrealloc(int lineno, void *ptr, size_t size) |
216 | { | 210 | { |
217 | ptr = xrealloc(ptr, (size + 0xff) & ~0xff); | 211 | ptr = xrealloc(ptr, (size + 0xff) & ~0xff); |
218 | fdprintf(2, "line %d: realloc %p\n", lineno, ptr); | 212 | fdprintf(2, "line %d: realloc %p\n", lineno, ptr); |
219 | return ptr; | 213 | return ptr; |
220 | } | 214 | } |
221 | char *xxstrdup(int lineno, const char *str) | 215 | static char *xxstrdup(int lineno, const char *str) |
222 | { | 216 | { |
223 | char *ptr = xstrdup(str); | 217 | char *ptr = xstrdup(str); |
224 | fdprintf(2, "line %d: strdup %p\n", lineno, ptr); | 218 | fdprintf(2, "line %d: strdup %p\n", lineno, ptr); |
225 | return ptr; | 219 | return ptr; |
226 | } | 220 | } |
227 | void xxfree(void *ptr) | 221 | static void xxfree(void *ptr) |
228 | { | 222 | { |
229 | fdprintf(2, "free %p\n", ptr); | 223 | fdprintf(2, "free %p\n", ptr); |
230 | free(ptr); | 224 | free(ptr); |
@@ -491,14 +485,6 @@ struct globals { | |||
491 | const char *cwd; | 485 | const char *cwd; |
492 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ | 486 | struct variable *top_var; /* = &G.shell_ver (set in main()) */ |
493 | struct variable shell_ver; | 487 | struct variable shell_ver; |
494 | #if ENABLE_FEATURE_SH_STANDALONE | ||
495 | struct nofork_save_area nofork_save; | ||
496 | #endif | ||
497 | #if ENABLE_HUSH_JOB | ||
498 | sigjmp_buf toplevel_jb; | ||
499 | #endif | ||
500 | unsigned char charmap[256]; | ||
501 | char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; | ||
502 | /* Signal and trap handling */ | 488 | /* Signal and trap handling */ |
503 | // unsigned count_SIGCHLD; | 489 | // unsigned count_SIGCHLD; |
504 | // unsigned handled_SIGCHLD; | 490 | // unsigned handled_SIGCHLD; |
@@ -507,6 +493,13 @@ struct globals { | |||
507 | char **traps; /* char *traps[NSIG] */ | 493 | char **traps; /* char *traps[NSIG] */ |
508 | sigset_t blocked_set; | 494 | sigset_t blocked_set; |
509 | sigset_t inherited_set; | 495 | sigset_t inherited_set; |
496 | char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; | ||
497 | #if ENABLE_FEATURE_SH_STANDALONE | ||
498 | struct nofork_save_area nofork_save; | ||
499 | #endif | ||
500 | #if ENABLE_HUSH_JOB | ||
501 | sigjmp_buf toplevel_jb; | ||
502 | #endif | ||
510 | }; | 503 | }; |
511 | #define G (*ptr_to_globals) | 504 | #define G (*ptr_to_globals) |
512 | /* Not #defining name to G.name - this quickly gets unwieldy | 505 | /* Not #defining name to G.name - this quickly gets unwieldy |
@@ -1042,9 +1035,7 @@ static struct variable *get_local_var(const char *name) | |||
1042 | return NULL; | 1035 | return NULL; |
1043 | } | 1036 | } |
1044 | 1037 | ||
1045 | /* Basically useful version until someone wants to get fancier, | 1038 | static const char *get_local_var_value(const char *src) |
1046 | * see the bash man page under "Parameter Expansion" */ | ||
1047 | static const char *lookup_param(const char *src) | ||
1048 | { | 1039 | { |
1049 | struct variable *var = get_local_var(src); | 1040 | struct variable *var = get_local_var(src); |
1050 | if (var) | 1041 | if (var) |
@@ -1842,7 +1833,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1842 | o_free(&dest); | 1833 | o_free(&dest); |
1843 | } | 1834 | } |
1844 | skip_expand: | 1835 | skip_expand: |
1845 | hooks.lookupvar = lookup_param; | 1836 | hooks.lookupvar = get_local_var_value; |
1846 | hooks.setvar = arith_set_local_var; | 1837 | hooks.setvar = arith_set_local_var; |
1847 | hooks.endofname = endofname; | 1838 | hooks.endofname = endofname; |
1848 | res = arith(exp_str ? exp_str : arg, &errcode, &hooks); | 1839 | res = arith(exp_str ? exp_str : arg, &errcode, &hooks); |
@@ -1898,7 +1889,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1898 | val = G.global_argv[i]; | 1889 | val = G.global_argv[i]; |
1899 | /* else val remains NULL: $N with too big N */ | 1890 | /* else val remains NULL: $N with too big N */ |
1900 | } else | 1891 | } else |
1901 | val = lookup_param(var); | 1892 | val = get_local_var_value(var); |
1902 | 1893 | ||
1903 | /* handle any expansions */ | 1894 | /* handle any expansions */ |
1904 | if (exp_len) { | 1895 | if (exp_len) { |
@@ -4118,7 +4109,7 @@ static int handle_dollar(o_string *dest, struct in_str *input) | |||
4118 | 4109 | ||
4119 | static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end) | 4110 | static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end) |
4120 | { | 4111 | { |
4121 | int ch, m; | 4112 | int ch; |
4122 | int next; | 4113 | int next; |
4123 | 4114 | ||
4124 | again: | 4115 | again: |
@@ -4136,7 +4127,6 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote | |||
4136 | return 1; | 4127 | return 1; |
4137 | } | 4128 | } |
4138 | next = '\0'; | 4129 | next = '\0'; |
4139 | m = G.charmap[ch]; | ||
4140 | if (ch != '\n') { | 4130 | if (ch != '\n') { |
4141 | next = i_peek(input); | 4131 | next = i_peek(input); |
4142 | } | 4132 | } |
@@ -4206,11 +4196,11 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4206 | { | 4196 | { |
4207 | struct parse_context ctx; | 4197 | struct parse_context ctx; |
4208 | o_string dest = NULL_O_STRING; | 4198 | o_string dest = NULL_O_STRING; |
4209 | int ch, m; | ||
4210 | int redir_fd; | 4199 | int redir_fd; |
4211 | redir_type redir_style; | ||
4212 | int is_in_dquote; | ||
4213 | int next; | 4200 | int next; |
4201 | int is_in_dquote; | ||
4202 | int ch; | ||
4203 | redir_type redir_style; | ||
4214 | 4204 | ||
4215 | /* Double-quote state is handled in the state variable is_in_dquote. | 4205 | /* Double-quote state is handled in the state variable is_in_dquote. |
4216 | * A single-quote triggers a bypass of the main loop until its mate is | 4206 | * A single-quote triggers a bypass of the main loop until its mate is |
@@ -4219,6 +4209,10 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4219 | debug_printf_parse("parse_stream entered, end_trigger='%c'\n", | 4209 | debug_printf_parse("parse_stream entered, end_trigger='%c'\n", |
4220 | end_trigger ? : 'X'); | 4210 | end_trigger ? : 'X'); |
4221 | 4211 | ||
4212 | G.ifs = get_local_var_value("IFS"); | ||
4213 | if (G.ifs == NULL) | ||
4214 | G.ifs = " \t\n"; | ||
4215 | |||
4222 | reset: | 4216 | reset: |
4223 | #if ENABLE_HUSH_INTERACTIVE | 4217 | #if ENABLE_HUSH_INTERACTIVE |
4224 | input->promptmode = 0; /* PS1 */ | 4218 | input->promptmode = 0; /* PS1 */ |
@@ -4227,6 +4221,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4227 | initialize_context(&ctx); | 4221 | initialize_context(&ctx); |
4228 | is_in_dquote = 0; | 4222 | is_in_dquote = 0; |
4229 | while (1) { | 4223 | while (1) { |
4224 | const char *is_ifs; | ||
4225 | const char *is_special; | ||
4226 | |||
4230 | if (is_in_dquote) { | 4227 | if (is_in_dquote) { |
4231 | if (parse_stream_dquoted(&dest, input, '"')) { | 4228 | if (parse_stream_dquoted(&dest, input, '"')) { |
4232 | goto parse_error; | 4229 | goto parse_error; |
@@ -4234,18 +4231,38 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4234 | /* We reached closing '"' */ | 4231 | /* We reached closing '"' */ |
4235 | is_in_dquote = 0; | 4232 | is_in_dquote = 0; |
4236 | } | 4233 | } |
4237 | m = CHAR_IFS; | ||
4238 | next = '\0'; | 4234 | next = '\0'; |
4239 | ch = i_getch(input); | 4235 | ch = i_getch(input); |
4240 | if (ch != EOF) { | 4236 | debug_printf_parse(": ch=%c (%d) escape=%d\n", |
4241 | m = G.charmap[ch]; | 4237 | ch, ch, dest.o_escape); |
4242 | if (ch != '\n') { | 4238 | if (ch == EOF) { |
4243 | next = i_peek(input); | 4239 | struct pipe *pi; |
4240 | if (done_word(&dest, &ctx)) { | ||
4241 | goto parse_error; | ||
4242 | } | ||
4243 | o_free(&dest); | ||
4244 | done_pipe(&ctx, PIPE_SEQ); | ||
4245 | /* If we got nothing... */ | ||
4246 | pi = ctx.list_head; | ||
4247 | if (pi->num_cmds == 0 | ||
4248 | IF_HAS_KEYWORDS( && pi->res_word == RES_NONE) | ||
4249 | ) { | ||
4250 | free_pipe_list(pi, 0); | ||
4251 | pi = NULL; | ||
4244 | } | 4252 | } |
4253 | debug_printf_parse("parse_stream return %p\n", pi); | ||
4254 | return pi; | ||
4245 | } | 4255 | } |
4246 | debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", | 4256 | if (ch != '\n') { |
4247 | ch, ch, m, dest.o_escape); | 4257 | next = i_peek(input); |
4248 | if (m == CHAR_ORDINARY) { | 4258 | } |
4259 | |||
4260 | is_ifs = strchr(G.ifs, ch); | ||
4261 | is_special = strchr("<>;&|(){}#'" /* special outside of "str" */ | ||
4262 | "\\$\"" USE_HUSH_TICK("`") /* always special */ | ||
4263 | , ch); | ||
4264 | |||
4265 | if (!is_special && !is_ifs) { /* ordinary char */ | ||
4249 | o_addQchr(&dest, ch); | 4266 | o_addQchr(&dest, ch); |
4250 | if ((dest.o_assignment == MAYBE_ASSIGNMENT | 4267 | if ((dest.o_assignment == MAYBE_ASSIGNMENT |
4251 | || dest.o_assignment == WORD_IS_KEYWORD) | 4268 | || dest.o_assignment == WORD_IS_KEYWORD) |
@@ -4257,27 +4274,7 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4257 | continue; | 4274 | continue; |
4258 | } | 4275 | } |
4259 | 4276 | ||
4260 | /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */ | 4277 | if (is_ifs) { |
4261 | |||
4262 | if (m == CHAR_IFS) { | ||
4263 | if (ch == EOF) { | ||
4264 | struct pipe *pi; | ||
4265 | if (done_word(&dest, &ctx)) { | ||
4266 | goto parse_error; | ||
4267 | } | ||
4268 | o_free(&dest); | ||
4269 | done_pipe(&ctx, PIPE_SEQ); | ||
4270 | /* If we got nothing... */ | ||
4271 | pi = ctx.list_head; | ||
4272 | if (pi->num_cmds == 0 | ||
4273 | IF_HAS_KEYWORDS( && pi->res_word == RES_NONE) | ||
4274 | ) { | ||
4275 | free_pipe_list(pi, 0); | ||
4276 | pi = NULL; | ||
4277 | } | ||
4278 | debug_printf_parse("parse_stream return %p\n", pi); | ||
4279 | return pi; | ||
4280 | } | ||
4281 | if (done_word(&dest, &ctx)) { | 4278 | if (done_word(&dest, &ctx)) { |
4282 | goto parse_error; | 4279 | goto parse_error; |
4283 | } | 4280 | } |
@@ -4317,11 +4314,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4317 | return ctx.list_head; | 4314 | return ctx.list_head; |
4318 | } | 4315 | } |
4319 | } | 4316 | } |
4320 | if (m == CHAR_IFS) | 4317 | if (is_ifs) |
4321 | continue; | 4318 | continue; |
4322 | 4319 | ||
4323 | /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */ | ||
4324 | |||
4325 | if (dest.o_assignment == MAYBE_ASSIGNMENT) { | 4320 | if (dest.o_assignment == MAYBE_ASSIGNMENT) { |
4326 | /* ch is a special char and thus this word | 4321 | /* ch is a special char and thus this word |
4327 | * cannot be an assignment */ | 4322 | * cannot be an assignment */ |
@@ -4579,33 +4574,6 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4579 | } | 4574 | } |
4580 | } | 4575 | } |
4581 | 4576 | ||
4582 | static void set_in_charmap(const char *set, int code) | ||
4583 | { | ||
4584 | while (*set) | ||
4585 | G.charmap[(unsigned char)*set++] = code; | ||
4586 | } | ||
4587 | |||
4588 | static void update_charmap(void) | ||
4589 | { | ||
4590 | G.ifs = getenv("IFS"); | ||
4591 | if (G.ifs == NULL) | ||
4592 | G.ifs = " \t\n"; | ||
4593 | /* Precompute a list of 'flow through' behavior so it can be treated | ||
4594 | * quickly up front. Computation is necessary because of IFS. | ||
4595 | * Special case handling of IFS == " \t\n" is not implemented. | ||
4596 | * The charmap[] array only really needs two bits each, | ||
4597 | * and on most machines that would be faster (reduced L1 cache use). | ||
4598 | */ | ||
4599 | memset(G.charmap, CHAR_ORDINARY, sizeof(G.charmap)); | ||
4600 | #if ENABLE_HUSH_TICK | ||
4601 | set_in_charmap("\\$\"`", CHAR_SPECIAL); | ||
4602 | #else | ||
4603 | set_in_charmap("\\$\"", CHAR_SPECIAL); | ||
4604 | #endif | ||
4605 | set_in_charmap("<>;&|(){}#'", CHAR_ORDINARY_IF_QUOTED); | ||
4606 | set_in_charmap(G.ifs, CHAR_IFS); /* are ordinary if quoted */ | ||
4607 | } | ||
4608 | |||
4609 | /* Execiting from string: eval, sh -c '...' | 4577 | /* Execiting from string: eval, sh -c '...' |
4610 | * or from file: /etc/profile, . file, sh <script>, sh (intereactive) | 4578 | * or from file: /etc/profile, . file, sh <script>, sh (intereactive) |
4611 | * end_trigger controls how often we stop parsing | 4579 | * end_trigger controls how often we stop parsing |
@@ -4617,15 +4585,12 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) | |||
4617 | while (1) { | 4585 | while (1) { |
4618 | struct pipe *pipe_list; | 4586 | struct pipe *pipe_list; |
4619 | 4587 | ||
4620 | update_charmap(); | ||
4621 | |||
4622 | pipe_list = parse_stream(inp, end_trigger); | 4588 | pipe_list = parse_stream(inp, end_trigger); |
4623 | if (!pipe_list) /* EOF */ | 4589 | if (!pipe_list) /* EOF */ |
4624 | break; | 4590 | break; |
4625 | debug_print_tree(pipe_list, 0); | 4591 | debug_print_tree(pipe_list, 0); |
4626 | debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); | 4592 | debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); |
4627 | run_and_free_list(pipe_list); | 4593 | run_and_free_list(pipe_list); |
4628 | /* Loop on syntax errors, return on EOF: */ | ||
4629 | } | 4594 | } |
4630 | } | 4595 | } |
4631 | 4596 | ||