summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-13 18:34:53 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-13 18:34:53 +0000
commit602d13cba552fadb8481283aa7872a4b9f206c48 (patch)
tree224cc9027daa059db593e561526a8bb13f95de25 /shell/hush.c
parent119b995437c52a164b2c5e51ef918c3f46b8a130 (diff)
downloadbusybox-w32-602d13cba552fadb8481283aa7872a4b9f206c48.tar.gz
busybox-w32-602d13cba552fadb8481283aa7872a4b9f206c48.tar.bz2
busybox-w32-602d13cba552fadb8481283aa7872a4b9f206c48.zip
hush: fix '{ false; echo $?; }' bug.
hush: expand testsuite. variable expansion is still very broken
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c204
1 files changed, 108 insertions, 96 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 04fb00dc7..dfb819122 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -371,7 +371,7 @@ static int b_check_space(o_string *o, int len);
371static int b_addchr(o_string *o, int ch); 371static int b_addchr(o_string *o, int ch);
372static void b_reset(o_string *o); 372static void b_reset(o_string *o);
373static int b_addqchr(o_string *o, int ch, int quote); 373static int b_addqchr(o_string *o, int ch, int quote);
374static int b_adduint(o_string *o, unsigned i); 374//static int b_adduint(o_string *o, unsigned i);
375/* in_str manipulations: */ 375/* in_str manipulations: */
376static int static_get(struct in_str *i); 376static int static_get(struct in_str *i);
377static int static_peek(struct in_str *i); 377static int static_peek(struct in_str *i);
@@ -413,7 +413,7 @@ static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *inp
413static const char *lookup_param(const char *src); 413static const char *lookup_param(const char *src);
414static char *make_string(char **inp); 414static char *make_string(char **inp);
415static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 415static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
416static int parse_string(o_string *dest, struct p_context *ctx, const char *src); 416//static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
417static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); 417static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
418/* setup: */ 418/* setup: */
419static int parse_stream_outer(struct in_str *inp, int parse_flag); 419static int parse_stream_outer(struct in_str *inp, int parse_flag);
@@ -1015,17 +1015,17 @@ static int b_addqchr(o_string *o, int ch, int quote)
1015 return b_addchr(o, ch); 1015 return b_addchr(o, ch);
1016} 1016}
1017 1017
1018static int b_adduint(o_string *o, unsigned i) 1018//static int b_adduint(o_string *o, unsigned i)
1019{ 1019//{
1020 int r; 1020// int r;
1021 char buf[sizeof(unsigned)*3 + 1]; 1021// char buf[sizeof(unsigned)*3 + 1];
1022 char *p = buf; 1022// char *p = buf;
1023 *(utoa_to_buf(i, buf, sizeof(buf))) = '\0'; 1023// *(utoa_to_buf(i, buf, sizeof(buf))) = '\0';
1024 /* no escape checking necessary */ 1024// /* no escape checking necessary */
1025 do r = b_addchr(o, *p++); while (r == 0 && *p); 1025// do r = b_addchr(o, *p++); while (r == 0 && *p);
1026 return r; 1026// return r;
1027} 1027//}
1028 1028//
1029static int static_get(struct in_str *i) 1029static int static_get(struct in_str *i)
1030{ 1030{
1031 int ch = *i->p++; 1031 int ch = *i->p++;
@@ -1288,9 +1288,7 @@ static void pseudo_exec_argv(char **argv)
1288 getpid(), argv[i]); 1288 getpid(), argv[i]);
1289// FIXME: vfork case?? 1289// FIXME: vfork case??
1290 p = insert_var_value(argv[i]); 1290 p = insert_var_value(argv[i]);
1291 putenv(strdup(p)); 1291 putenv(p == argv[i] ? xstrdup(p) : p);
1292 if (p != argv[i])
1293 free(p);
1294 } 1292 }
1295 argv += i; 1293 argv += i;
1296 /* If a variable is assigned in a forest, and nobody listens, 1294 /* If a variable is assigned in a forest, and nobody listens,
@@ -1699,10 +1697,11 @@ static int run_pipe_real(struct pipe *pi)
1699 } 1697 }
1700 for (i = 0; is_assignment(argv[i]); i++) { 1698 for (i = 0; is_assignment(argv[i]); i++) {
1701 p = insert_var_value(argv[i]); 1699 p = insert_var_value(argv[i]);
1702 putenv(strdup(p));
1703 if (p != argv[i]) { 1700 if (p != argv[i]) {
1704 child->sp--; 1701 child->sp--;
1705 free(p); 1702 putenv(p);
1703 } else {
1704 putenv(xstrdup(p));
1706 } 1705 }
1707 } 1706 }
1708 if (child->sp) { 1707 if (child->sp) {
@@ -2292,39 +2291,42 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
2292static char **make_list_in(char **inp, char *name) 2291static char **make_list_in(char **inp, char *name)
2293{ 2292{
2294 int len, i; 2293 int len, i;
2294#if 0
2295 int name_len = strlen(name); 2295 int name_len = strlen(name);
2296 int n = 0; 2296#endif
2297 int n;
2297 char **list; 2298 char **list;
2298 char *p1, *p2, *p3; 2299 char *p1, *p2, *p3;
2299 2300
2300 /* create list of variable values */ 2301 /* create list of variable values */
2301 list = xmalloc(sizeof(*list)); 2302 list = xmalloc(sizeof(*list));
2303 n = 0;
2302 for (i = 0; inp[i]; i++) { 2304 for (i = 0; inp[i]; i++) {
2303 p3 = insert_var_value(inp[i]); 2305 p3 = insert_var_value(inp[i]);
2304 p1 = p3; 2306 p1 = p3;
2305 while (*p1) { 2307 while (*p1) {
2306 if ((*p1 == ' ')) { 2308 if (*p1 == ' ') {
2307 p1++; 2309 p1++;
2308 continue; 2310 continue;
2309 } 2311 }
2310 p2 = strchr(p1, ' '); 2312 p2 = strchrnul(p1, ' ');
2311 if (p2) { 2313 len = p2 - p1;
2312 len = p2 - p1;
2313 } else {
2314 len = strlen(p1);
2315 p2 = p1 + len;
2316 }
2317 /* we use n + 2 in realloc for list, because we add 2314 /* we use n + 2 in realloc for list, because we add
2318 * new element and then we will add NULL element */ 2315 * new element and then we will add NULL element */
2319 list = xrealloc(list, sizeof(*list) * (n + 2)); 2316 list = xrealloc(list, sizeof(*list) * (n + 2));
2317 list[n] = xasprintf("%s=%.*s", name, len, p1);
2318#if 0 /* faster, but more code */
2320 list[n] = xmalloc(2 + name_len + len); 2319 list[n] = xmalloc(2 + name_len + len);
2321 strcpy(list[n], name); 2320 strcpy(list[n], name);
2322 strcat(list[n], "="); 2321 list[n][name_len] = '=';
2323 strncat(list[n], p1, len); 2322 strncat(&(list[n][name_len + 1]), p1, len);
2324 list[n++][name_len + len + 1] = '\0'; 2323 list[n][name_len + len + 1] = '\0';
2324#endif
2325 n++;
2325 p1 = p2; 2326 p1 = p2;
2326 } 2327 }
2327 if (p3 != inp[i]) free(p3); 2328 if (p3 != inp[i])
2329 free(p3);
2328 } 2330 }
2329 list[n] = NULL; 2331 list[n] = NULL;
2330 return list; 2332 return list;
@@ -2335,8 +2337,10 @@ static char *insert_var_value(char *inp)
2335 int res_str_len = 0; 2337 int res_str_len = 0;
2336 int len; 2338 int len;
2337 int done = 0; 2339 int done = 0;
2338 char *p, *res_str = NULL; 2340 int i;
2339 const char *p1; 2341 const char *p1;
2342 char *p, *p2;
2343 char *res_str = NULL;
2340 2344
2341 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { 2345 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
2342 if (p != inp) { 2346 if (p != inp) {
@@ -2348,11 +2352,42 @@ static char *insert_var_value(char *inp)
2348 inp = ++p; 2352 inp = ++p;
2349 p = strchr(inp, SPECIAL_VAR_SYMBOL); 2353 p = strchr(inp, SPECIAL_VAR_SYMBOL);
2350 *p = '\0'; 2354 *p = '\0';
2351 p1 = lookup_param(inp); 2355
2356 switch (inp[0]) {
2357 case '$':
2358 /* FIXME: (echo $$) should still print pid of main shell */
2359 p1 = utoa(getpid());
2360 break;
2361 case '!':
2362 p1 = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
2363 break;
2364 case '?':
2365 p1 = utoa(last_return_code);
2366 break;
2367 case '#':
2368 p1 = utoa(global_argc ? global_argc-1 : 0);
2369 break;
2370 case '*':
2371 case '@': /* FIXME: we treat $@ as $* for now */
2372 len = 1;
2373 for (i = 1; i < global_argc; i++)
2374 len += strlen(global_argv[i]) + 1;
2375 p1 = p2 = alloca(--len);
2376 for (i = 1; i < global_argc; i++) {
2377 strcpy(p2, global_argv[i]);
2378 p2 += strlen(global_argv[i]);
2379 *p2++ = ifs[0];
2380 }
2381 *--p2 = '\0';
2382 break;
2383 default:
2384 p1 = lookup_param(inp);
2385 }
2386
2352 if (p1) { 2387 if (p1) {
2353 len = res_str_len + strlen(p1); 2388 len = res_str_len + strlen(p1);
2354 res_str = xrealloc(res_str, (1 + len)); 2389 res_str = xrealloc(res_str, 1 + len);
2355 strcpy((res_str + res_str_len), p1); 2390 strcpy(res_str + res_str_len, p1);
2356 res_str_len = len; 2391 res_str_len = len;
2357 } 2392 }
2358 *p = SPECIAL_VAR_SYMBOL; 2393 *p = SPECIAL_VAR_SYMBOL;
@@ -2956,21 +2991,20 @@ static char* make_string(char ** inp)
2956 char *p; 2991 char *p;
2957 char *str = NULL; 2992 char *str = NULL;
2958 int n; 2993 int n;
2959 int len = 2; 2994 int val_len;
2995 int len = 0;
2960 2996
2961 for (n = 0; inp[n]; n++) { 2997 for (n = 0; inp[n]; n++) {
2962 p = insert_var_value(inp[n]); 2998 p = insert_var_value(inp[n]);
2963 str = xrealloc(str, (len + strlen(p))); 2999 val_len = strlen(p);
2964 if (n) { 3000 str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/
2965 strcat(str, " "); 3001 str[len++] = ' ';
2966 } else { 3002 strcpy(str + len, p);
2967 *str = '\0'; 3003 len += val_len;
2968 }
2969 strcat(str, p);
2970 len = strlen(str) + 3;
2971 if (p != inp[n]) free(p); 3004 if (p != inp[n]) free(p);
2972 } 3005 }
2973 len = strlen(str); 3006 /* We do not check for case where loop had no iterations at all
3007 * - cannot happen? */
2974 str[len] = '\n'; 3008 str[len] = '\n';
2975 str[len+1] = '\0'; 3009 str[len+1] = '\0';
2976 return str; 3010 return str;
@@ -2979,46 +3013,39 @@ static char* make_string(char ** inp)
2979/* return code: 0 for OK, 1 for syntax error */ 3013/* return code: 0 for OK, 1 for syntax error */
2980static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) 3014static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
2981{ 3015{
2982 int i, advance = 0; 3016// int i;
2983 char sep[] = " "; 3017// char sep[] = " ";
2984 int ch = input->peek(input); /* first character after the $ */ 3018 int ch = b_peek(input); /* first character after the $ */
2985 3019
2986 debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); 3020 debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
2987 if (isalpha(ch)) { 3021 if (isalpha(ch) || ch == '?') {
2988 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3022 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2989 ctx->child->sp++; 3023 ctx->child->sp++;
2990 while (1) { 3024 while (1) {
2991 ch = b_peek(input);
2992 if (!isalnum(ch) && ch != '_')
2993 break;
2994 debug_printf_parse(": '%c'\n", ch); 3025 debug_printf_parse(": '%c'\n", ch);
2995 b_getch(input); 3026 b_getch(input);
2996 b_addchr(dest, ch); 3027 b_addchr(dest, ch);
3028 ch = b_peek(input);
3029 if (!isalnum(ch) && ch != '_')
3030 break;
2997 } 3031 }
2998 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3032 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2999 } else if (isdigit(ch)) { 3033 } else if (isdigit(ch)) {
3000 i = ch - '0'; /* XXX is $0 special? */ 3034 make_one_char_var:
3001 if (i < global_argc) { 3035 b_addchr(dest, SPECIAL_VAR_SYMBOL);
3002 parse_string(dest, ctx, global_argv[i]); /* recursion */ 3036 ctx->child->sp++;
3003 } 3037 debug_printf_parse(": '%c'\n", ch);
3004 advance = 1; 3038 b_getch(input);
3039 b_addchr(dest, ch);
3040 b_addchr(dest, SPECIAL_VAR_SYMBOL);
3005 } else switch (ch) { 3041 } else switch (ch) {
3006 case '$': 3042 case '$': /* pid */
3007 b_adduint(dest, getpid()); 3043 case '!': /* last bg pid */
3008 advance = 1; 3044 case '?': /* last exit code */
3009 break; 3045 case '#': /* number of args */
3010 case '!': 3046 case '*': /* args */
3011 if (last_bg_pid > 0) b_adduint(dest, last_bg_pid); 3047 case '@': /* args */
3012 advance = 1; 3048 goto make_one_char_var;
3013 break;
3014 case '?':
3015 b_adduint(dest, last_return_code);
3016 advance = 1;
3017 break;
3018 case '#':
3019 b_adduint(dest, global_argc ? global_argc-1 : 0);
3020 advance = 1;
3021 break;
3022 case '{': 3049 case '{':
3023 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3050 b_addchr(dest, SPECIAL_VAR_SYMBOL);
3024 ctx->child->sp++; 3051 ctx->child->sp++;
@@ -3042,15 +3069,6 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
3042 b_getch(input); 3069 b_getch(input);
3043 process_command_subs(dest, ctx, input, ")"); 3070 process_command_subs(dest, ctx, input, ")");
3044 break; 3071 break;
3045 case '*':
3046 sep[0] = ifs[0];
3047 for (i = 1; i < global_argc; i++) {
3048 parse_string(dest, ctx, global_argv[i]);
3049 if (i+1 < global_argc)
3050 parse_string(dest, ctx, sep);
3051 }
3052 break;
3053 case '@':
3054 case '-': 3072 case '-':
3055 case '_': 3073 case '_':
3056 /* still unhandled, but should be eventually */ 3074 /* still unhandled, but should be eventually */
@@ -3058,25 +3076,19 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
3058 return 1; 3076 return 1;
3059 break; 3077 break;
3060 default: 3078 default:
3061 b_addqchr(dest,'$', dest->quote); 3079 b_addqchr(dest, '$', dest->quote);
3062 } 3080 }
3063 /* Eat the character if the flag was set. If the compiler
3064 * is smart enough, we could substitute "b_getch(input);"
3065 * for all the "advance = 1;" above, and also end up with
3066 * a nice size-optimized program. Hah! That'll be the day.
3067 */
3068 if (advance) b_getch(input);
3069 debug_printf_parse("handle_dollar return 0\n"); 3081 debug_printf_parse("handle_dollar return 0\n");
3070 return 0; 3082 return 0;
3071} 3083}
3072 3084
3073static int parse_string(o_string *dest, struct p_context *ctx, const char *src) 3085//static int parse_string(o_string *dest, struct p_context *ctx, const char *src)
3074{ 3086//{
3075 struct in_str foo; 3087// struct in_str foo;
3076 setup_string_in_str(&foo, src); 3088// setup_string_in_str(&foo, src);
3077 return parse_stream(dest, ctx, &foo, NULL); 3089// return parse_stream(dest, ctx, &foo, NULL);
3078} 3090//}
3079 3091//
3080/* return code is 0 for normal exit, 1 for syntax error */ 3092/* return code is 0 for normal exit, 1 for syntax error */
3081static int parse_stream(o_string *dest, struct p_context *ctx, 3093static int parse_stream(o_string *dest, struct p_context *ctx,
3082 struct in_str *input, const char *end_trigger) 3094 struct in_str *input, const char *end_trigger)