diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-13 18:34:53 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-13 18:34:53 +0000 |
commit | 602d13cba552fadb8481283aa7872a4b9f206c48 (patch) | |
tree | 224cc9027daa059db593e561526a8bb13f95de25 /shell/hush.c | |
parent | 119b995437c52a164b2c5e51ef918c3f46b8a130 (diff) | |
download | busybox-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.c | 204 |
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); | |||
371 | static int b_addchr(o_string *o, int ch); | 371 | static int b_addchr(o_string *o, int ch); |
372 | static void b_reset(o_string *o); | 372 | static void b_reset(o_string *o); |
373 | static int b_addqchr(o_string *o, int ch, int quote); | 373 | static int b_addqchr(o_string *o, int ch, int quote); |
374 | static 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: */ |
376 | static int static_get(struct in_str *i); | 376 | static int static_get(struct in_str *i); |
377 | static int static_peek(struct in_str *i); | 377 | static 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 | |||
413 | static const char *lookup_param(const char *src); | 413 | static const char *lookup_param(const char *src); |
414 | static char *make_string(char **inp); | 414 | static char *make_string(char **inp); |
415 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); | 415 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); |
416 | static 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); |
417 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); | 417 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); |
418 | /* setup: */ | 418 | /* setup: */ |
419 | static int parse_stream_outer(struct in_str *inp, int parse_flag); | 419 | static 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 | ||
1018 | static 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 | // | |
1029 | static int static_get(struct in_str *i) | 1029 | static 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) | |||
2292 | static char **make_list_in(char **inp, char *name) | 2291 | static 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 */ |
2980 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) | 3014 | static 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 | ||
3073 | static 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 */ |
3081 | static int parse_stream(o_string *dest, struct p_context *ctx, | 3093 | static 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) |