aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-04 15:24:40 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-04 15:24:40 +0000
commita24c8caeb29a11fafc748399ab6b30e6b8e638f0 (patch)
tree6405a35e0da6b9946f1c50ece8fae2ad1aa4ed20 /shell
parent7c9861214b2d81603902d344cfdef3342d8d4b5b (diff)
downloadbusybox-w32-a24c8caeb29a11fafc748399ab6b30e6b8e638f0.tar.gz
busybox-w32-a24c8caeb29a11fafc748399ab6b30e6b8e638f0.tar.bz2
busybox-w32-a24c8caeb29a11fafc748399ab6b30e6b8e638f0.zip
hush: remove code which errors out on $- and $_, it's useless;
wrap some longish lines function old new delta handle_dollar 667 626 -41
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c287
1 files changed, 152 insertions, 135 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 6ae42c8b5..0ac42c90b 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1517,13 +1517,16 @@ static int o_save_ptr_helper(o_string *o, int n)
1517 list = (char**)o->data; 1517 list = (char**)o->data;
1518 memmove(list + n + 0x10, list + n, string_len); 1518 memmove(list + n + 0x10, list + n, string_len);
1519 o->length += 0x10 * sizeof(list[0]); 1519 o->length += 0x10 * sizeof(list[0]);
1520 } else 1520 } else {
1521 debug_printf_list("list[%d]=%d string_start=%d\n", n, string_len, string_start); 1521 debug_printf_list("list[%d]=%d string_start=%d\n",
1522 n, string_len, string_start);
1523 }
1522 } else { 1524 } else {
1523 /* We have empty slot at list[n], reuse without growth */ 1525 /* We have empty slot at list[n], reuse without growth */
1524 string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */ 1526 string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */
1525 string_len = o->length - string_start; 1527 string_len = o->length - string_start;
1526 debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n", n, string_len, string_start); 1528 debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n",
1529 n, string_len, string_start);
1527 o->has_empty_slot = 0; 1530 o->has_empty_slot = 0;
1528 } 1531 }
1529 list[n] = (char*)(ptrdiff_t)string_len; 1532 list[n] = (char*)(ptrdiff_t)string_len;
@@ -1917,7 +1920,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
1917 } 1920 }
1918 1921
1919 arg[0] = first_ch; 1922 arg[0] = first_ch;
1920
1921#if ENABLE_HUSH_TICK 1923#if ENABLE_HUSH_TICK
1922 store_val: 1924 store_val:
1923#endif 1925#endif
@@ -2203,8 +2205,12 @@ typedef struct nommu_save_t {
2203 * XXX no exit() here. If you don't exec, use _exit instead. 2205 * XXX no exit() here. If you don't exec, use _exit instead.
2204 * The at_exit handlers apparently confuse the calling process, 2206 * The at_exit handlers apparently confuse the calling process,
2205 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 2207 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */
2206static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; 2208static void pseudo_exec_argv(nommu_save_t *nommu_save,
2207static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) 2209 char **argv, int assignment_cnt,
2210 char **argv_expanded) NORETURN;
2211static void pseudo_exec_argv(nommu_save_t *nommu_save,
2212 char **argv, int assignment_cnt,
2213 char **argv_expanded)
2208{ 2214{
2209 int rcode; 2215 int rcode;
2210 char **new_env; 2216 char **new_env;
@@ -2279,8 +2285,12 @@ static int run_list(struct pipe *pi);
2279 2285
2280/* Called after [v]fork() in run_pipe() 2286/* Called after [v]fork() in run_pipe()
2281 */ 2287 */
2282static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) NORETURN; 2288static void pseudo_exec(nommu_save_t *nommu_save,
2283static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) 2289 struct command *command,
2290 char **argv_expanded) NORETURN;
2291static void pseudo_exec(nommu_save_t *nommu_save,
2292 struct command *command,
2293 char **argv_expanded)
2284{ 2294{
2285 if (command->argv) 2295 if (command->argv)
2286 pseudo_exec_argv(nommu_save, command->argv, command->assignment_cnt, argv_expanded); 2296 pseudo_exec_argv(nommu_save, command->argv, command->assignment_cnt, argv_expanded);
@@ -2655,7 +2665,8 @@ static int run_pipe(struct pipe *pi)
2655 setup_redirects(command, squirrel); 2665 setup_redirects(command, squirrel);
2656 new_env = expand_assignments(argv, command->assignment_cnt); 2666 new_env = expand_assignments(argv, command->assignment_cnt);
2657 old_env = putenv_all_and_save_old(new_env); 2667 old_env = putenv_all_and_save_old(new_env);
2658 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); 2668 debug_printf_exec(": builtin '%s' '%s'...\n",
2669 x->cmd, argv_expanded[1]);
2659 rcode = x->function(argv_expanded) & 0xff; 2670 rcode = x->function(argv_expanded) & 0xff;
2660#if ENABLE_FEATURE_SH_STANDALONE 2671#if ENABLE_FEATURE_SH_STANDALONE
2661 clean_up_and_ret: 2672 clean_up_and_ret:
@@ -2677,7 +2688,8 @@ static int run_pipe(struct pipe *pi)
2677 save_nofork_data(&G.nofork_save); 2688 save_nofork_data(&G.nofork_save);
2678 new_env = expand_assignments(argv, command->assignment_cnt); 2689 new_env = expand_assignments(argv, command->assignment_cnt);
2679 old_env = putenv_all_and_save_old(new_env); 2690 old_env = putenv_all_and_save_old(new_env);
2680 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); 2691 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
2692 argv_expanded[0], argv_expanded[1]);
2681 rcode = run_nofork_applet_prime(&G.nofork_save, i, argv_expanded); 2693 rcode = run_nofork_applet_prime(&G.nofork_save, i, argv_expanded);
2682 goto clean_up_and_ret; 2694 goto clean_up_and_ret;
2683 } 2695 }
@@ -2701,7 +2713,8 @@ static int run_pipe(struct pipe *pi)
2701#endif 2713#endif
2702 command = &(pi->cmds[i]); 2714 command = &(pi->cmds[i]);
2703 if (command->argv) { 2715 if (command->argv) {
2704 debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); 2716 debug_printf_exec(": pipe member '%s' '%s'...\n",
2717 command->argv[0], command->argv[1]);
2705 } else 2718 } else
2706 debug_printf_exec(": pipe member with no argv\n"); 2719 debug_printf_exec(": pipe member with no argv\n");
2707 2720
@@ -2841,7 +2854,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
2841 struct command *command = &pi->cmds[prn]; 2854 struct command *command = &pi->cmds[prn];
2842 char **argv = command->argv; 2855 char **argv = command->argv;
2843 2856
2844 fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt); 2857 fprintf(stderr, "%*s prog %d assignment_cnt:%d",
2858 lvl*2, "", prn,
2859 command->assignment_cnt);
2845 if (command->group) { 2860 if (command->group) {
2846 fprintf(stderr, " group %s: (argv=%p)\n", 2861 fprintf(stderr, " group %s: (argv=%p)\n",
2847 GRPTYPE[command->grp_type], 2862 GRPTYPE[command->grp_type],
@@ -3046,8 +3061,9 @@ static int run_list(struct pipe *pi)
3046 pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); 3061 pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
3047 pi->cmds[0].assignment_cnt = 1; 3062 pi->cmds[0].assignment_cnt = 1;
3048 } 3063 }
3049 if (rword == RES_IN) /* "for v IN list;..." - "in" has no cmds anyway */ 3064 if (rword == RES_IN) {
3050 continue; 3065 continue; /* "for v IN list;..." - "in" has no cmds anyway */
3066 }
3051 if (rword == RES_DONE) { 3067 if (rword == RES_DONE) {
3052 continue; /* "done" has no cmds too */ 3068 continue; /* "done" has no cmds too */
3053 } 3069 }
@@ -3603,7 +3619,8 @@ static int done_word(o_string *word, struct parse_context *ctx)
3603 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); 3619 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
3604 if (reserved_word(word, ctx)) { 3620 if (reserved_word(word, ctx)) {
3605 o_reset(word); 3621 o_reset(word);
3606 debug_printf_parse("done_word return %d\n", (ctx->ctx_res_w == RES_SNTX)); 3622 debug_printf_parse("done_word return %d\n",
3623 (ctx->ctx_res_w == RES_SNTX));
3607 return (ctx->ctx_res_w == RES_SNTX); 3624 return (ctx->ctx_res_w == RES_SNTX);
3608 } 3625 }
3609 } 3626 }
@@ -3800,7 +3817,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
3800 || dest->nonnull /* ""(... */ 3817 || dest->nonnull /* ""(... */
3801 ) { 3818 ) {
3802 syntax(NULL); 3819 syntax(NULL);
3803 debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n"); 3820 debug_printf_parse("parse_group return 1: "
3821 "syntax error, groups and arglists don't mix\n");
3804 return 1; 3822 return 1;
3805 } 3823 }
3806 endch = '}'; 3824 endch = '}';
@@ -3812,7 +3830,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
3812 /* empty ()/{} or parse error? */ 3830 /* empty ()/{} or parse error? */
3813 if (!pipe_list || pipe_list == ERR_PTR) { 3831 if (!pipe_list || pipe_list == ERR_PTR) {
3814 syntax(NULL); 3832 syntax(NULL);
3815 debug_printf_parse("parse_group return 1: parse_stream returned %p\n", pipe_list); 3833 debug_printf_parse("parse_group return 1: "
3834 "parse_stream returned %p\n", pipe_list);
3816 return 1; 3835 return 1;
3817 } 3836 }
3818 command->group = pipe_list; 3837 command->group = pipe_list;
@@ -3910,7 +3929,7 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db
3910 break; 3929 break;
3911 if (ch == '(') 3930 if (ch == '(')
3912 count++; 3931 count++;
3913 if (ch == ')') 3932 if (ch == ')') {
3914 if (--count < 0) { 3933 if (--count < 0) {
3915 if (!dbl) 3934 if (!dbl)
3916 break; 3935 break;
@@ -3919,6 +3938,7 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db
3919 break; 3938 break;
3920 } 3939 }
3921 } 3940 }
3941 }
3922 o_addchr(dest, ch); 3942 o_addchr(dest, ch);
3923 if (ch == '\'') { 3943 if (ch == '\'') {
3924 add_till_single_quote(dest, input); 3944 add_till_single_quote(dest, input);
@@ -3971,136 +3991,130 @@ static int handle_dollar(o_string *dest, struct in_str *input)
3971 o_addchr(dest, ch | quote_mask); 3991 o_addchr(dest, ch | quote_mask);
3972 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3992 o_addchr(dest, SPECIAL_VAR_SYMBOL);
3973 } else switch (ch) { 3993 } else switch (ch) {
3974 case '$': /* pid */ 3994 case '$': /* pid */
3975 case '!': /* last bg pid */ 3995 case '!': /* last bg pid */
3976 case '?': /* last exit code */ 3996 case '?': /* last exit code */
3977 case '#': /* number of args */ 3997 case '#': /* number of args */
3978 case '*': /* args */ 3998 case '*': /* args */
3979 case '@': /* args */ 3999 case '@': /* args */
3980 goto make_one_char_var; 4000 goto make_one_char_var;
3981 case '{': { 4001 case '{': {
3982 bool first_char, all_digits; 4002 bool first_char, all_digits;
3983 4003
3984 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4004 o_addchr(dest, SPECIAL_VAR_SYMBOL);
3985 i_getch(input); 4005 i_getch(input);
3986 /* XXX maybe someone will try to escape the '}' */ 4006 /* XXX maybe someone will try to escape the '}' */
3987 expansion = 0; 4007 expansion = 0;
3988 first_char = true; 4008 first_char = true;
3989 all_digits = false; 4009 all_digits = false;
3990 while (1) { 4010 while (1) {
3991 ch = i_getch(input); 4011 ch = i_getch(input);
3992 if (ch == '}') 4012 if (ch == '}')
3993 break; 4013 break;
3994 4014
3995 if (first_char) { 4015 if (first_char) {
3996 if (ch == '#') 4016 if (ch == '#')
3997 /* ${#var}: length of var contents */ 4017 /* ${#var}: length of var contents */
3998 goto char_ok; 4018 goto char_ok;
3999 else if (isdigit(ch)) { 4019 else if (isdigit(ch)) {
4000 all_digits = true; 4020 all_digits = true;
4001 goto char_ok; 4021 goto char_ok;
4002 }
4003 } 4022 }
4023 }
4004 4024
4005 if (expansion < 2 && 4025 if (expansion < 2
4006 ((all_digits && !isdigit(ch)) || 4026 && ( (all_digits && !isdigit(ch))
4007 (!all_digits && !isalnum(ch) && ch != '_'))) 4027 || (!all_digits && !isalnum(ch) && ch != '_')
4008 { 4028 )
4009 /* handle parameter expansions 4029 ) {
4010 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 4030 /* handle parameter expansions
4011 */ 4031 * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
4012 if (first_char) 4032 */
4013 goto case_default; 4033 if (first_char)
4014 switch (ch) { 4034 goto case_default;
4015 case ':': /* null modifier */ 4035 switch (ch) {
4016 if (expansion == 0) { 4036 case ':': /* null modifier */
4017 debug_printf_parse(": null modifier\n"); 4037 if (expansion == 0) {
4018 ++expansion; 4038 debug_printf_parse(": null modifier\n");
4019 break; 4039 ++expansion;
4020 } 4040 break;
4021 goto case_default; 4041 }
4022 4042 goto case_default;
4023#if 0 /* not implemented yet :( */ 4043#if 0 /* not implemented yet :( */
4024 case '#': /* remove prefix */ 4044 case '#': /* remove prefix */
4025 case '%': /* remove suffix */ 4045 case '%': /* remove suffix */
4026 if (expansion == 0) { 4046 if (expansion == 0) {
4027 debug_printf_parse(": remove suffix/prefix\n"); 4047 debug_printf_parse(": remove suffix/prefix\n");
4028 expansion = 2; 4048 expansion = 2;
4029 break; 4049 break;
4030 } 4050 }
4031 goto case_default; 4051 goto case_default;
4032#endif 4052#endif
4033 4053 case '-': /* default value */
4034 case '-': /* default value */ 4054 case '=': /* assign default */
4035 case '=': /* assign default */ 4055 case '+': /* alternative */
4036 case '+': /* alternative */ 4056 case '?': /* error indicate */
4037 case '?': /* error indicate */ 4057 debug_printf_parse(": parameter expansion\n");
4038 debug_printf_parse(": parameter expansion\n"); 4058 expansion = 2;
4039 expansion = 2; 4059 break;
4040 break; 4060 default:
4041 4061 case_default:
4042 default: 4062 syntax("unterminated ${name}");
4043 case_default: 4063 debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
4044 syntax("unterminated ${name}"); 4064 return 1;
4045 debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
4046 return 1;
4047 }
4048 } 4065 }
4049
4050 char_ok:
4051 debug_printf_parse(": '%c'\n", ch);
4052 o_addchr(dest, ch | quote_mask);
4053 quote_mask = 0;
4054 first_char = false;
4055 } 4066 }
4067 char_ok:
4068 debug_printf_parse(": '%c'\n", ch);
4069 o_addchr(dest, ch | quote_mask);
4070 quote_mask = 0;
4071 first_char = false;
4072 }
4073 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4074 break;
4075 }
4076 case '(': {
4077 i_getch(input);
4078#if ENABLE_SH_MATH_SUPPORT
4079 if (i_peek(input) == '(') {
4080 i_getch(input);
4081 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4082 o_addchr(dest, /*quote_mask |*/ '+');
4083 add_till_closing_paren(dest, input, true);
4056 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4084 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4057 break; 4085 break;
4058 } 4086 }
4059 case '(': {
4060 i_getch(input);
4061
4062#if ENABLE_SH_MATH_SUPPORT
4063 if (i_peek(input) == '(') {
4064 i_getch(input);
4065 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4066 o_addchr(dest, /*quote_mask |*/ '+');
4067 add_till_closing_paren(dest, input, true);
4068 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4069 break;
4070 }
4071#endif 4087#endif
4072
4073#if ENABLE_HUSH_TICK 4088#if ENABLE_HUSH_TICK
4074 //int pos = dest->length; 4089 //int pos = dest->length;
4075 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4090 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4076 o_addchr(dest, quote_mask | '`'); 4091 o_addchr(dest, quote_mask | '`');
4077 add_till_closing_paren(dest, input, false); 4092 add_till_closing_paren(dest, input, false);
4078 //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); 4093 //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
4079 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4094 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4080#endif 4095#endif
4081 break; 4096 break;
4097 }
4098 case '_':
4099 i_getch(input);
4100 ch = i_peek(input);
4101 if (isalnum(ch)) { /* it's $_name or $_123 */
4102 ch = '_';
4103 goto make_var;
4082 } 4104 }
4083 case '_': 4105 /* else: it's $_ */
4084 i_getch(input); 4106 /* TODO: */
4085 ch = i_peek(input); 4107 /* $_ Shell or shell script name; or last cmd name */
4086 if (isalnum(ch)) { /* it's $_name or $_123 */ 4108 /* $- Option flags set by set builtin or shell options (-i etc) */
4087 ch = '_'; 4109 default:
4088 goto make_var; 4110 o_addQchr(dest, '$');
4089 }
4090 /* else: it's $_ */
4091 case '-':
4092 /* still unhandled, but should be eventually */
4093 bb_error_msg("unhandled syntax: $%c", ch);
4094 return 1;
4095 break;
4096 default:
4097 o_addQchr(dest, '$');
4098 } 4111 }
4099 debug_printf_parse("handle_dollar return 0\n"); 4112 debug_printf_parse("handle_dollar return 0\n");
4100 return 0; 4113 return 0;
4101} 4114}
4102 4115
4103static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end) 4116static int parse_stream_dquoted(o_string *dest,
4117 struct in_str *input, int dquote_end)
4104{ 4118{
4105 int ch; 4119 int ch;
4106 int next; 4120 int next;
@@ -4149,7 +4163,8 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote
4149 } 4163 }
4150 if (ch == '$') { 4164 if (ch == '$') {
4151 if (handle_dollar(dest, input) != 0) { 4165 if (handle_dollar(dest, input) != 0) {
4152 debug_printf_parse("parse_stream_dquoted return 1: handle_dollar returned non-0\n"); 4166 debug_printf_parse("parse_stream_dquoted return 1: "
4167 "handle_dollar returned non-0\n");
4153 return 1; 4168 return 1;
4154 } 4169 }
4155 goto again; 4170 goto again;
@@ -4196,8 +4211,8 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
4196 4211
4197 /* Double-quote state is handled in the state variable is_in_dquote. 4212 /* Double-quote state is handled in the state variable is_in_dquote.
4198 * A single-quote triggers a bypass of the main loop until its mate is 4213 * A single-quote triggers a bypass of the main loop until its mate is
4199 * found. When recursing, quote state is passed in via dest->o_escape. */ 4214 * found. When recursing, quote state is passed in via dest->o_escape.
4200 4215 */
4201 debug_printf_parse("parse_stream entered, end_trigger='%c'\n", 4216 debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
4202 end_trigger ? : 'X'); 4217 end_trigger ? : 'X');
4203 4218
@@ -4338,7 +4353,8 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
4338 break; 4353 break;
4339 case '$': 4354 case '$':
4340 if (handle_dollar(&dest, input) != 0) { 4355 if (handle_dollar(&dest, input) != 0) {
4341 debug_printf_parse("parse_stream parse error: handle_dollar returned non-0\n"); 4356 debug_printf_parse("parse_stream parse error: "
4357 "handle_dollar returned non-0\n");
4342 goto parse_error; 4358 goto parse_error;
4343 } 4359 }
4344 break; 4360 break;
@@ -4532,8 +4548,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
4532 4548
4533 /* Clean up allocated tree. 4549 /* Clean up allocated tree.
4534 * Samples for finding leaks on syntax error recovery path. 4550 * Samples for finding leaks on syntax error recovery path.
4535 * Execute them from interactive shell and watch pmap `pidof hush`. 4551 * Run them from interactive shell, watch pmap `pidof hush`.
4536 * while if false; then false; fi do break; done (bash accepts it) 4552 * while if false; then false; fi do break; done
4553 * (bash accepts it)
4537 * while if false; then false; fi; do break; fi 4554 * while if false; then false; fi; do break; fi
4538 */ 4555 */
4539 pctx = &ctx; 4556 pctx = &ctx;