diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-14 16:19:34 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-14 16:19:34 +0000 |
commit | 03eb8bf6ce2cef8f30402b7c2b18e8479f9da1ea (patch) | |
tree | 2ca7e7d1fba638187467c1597f2746b0163c9e76 /shell/hush.c | |
parent | 602d13cba552fadb8481283aa7872a4b9f206c48 (diff) | |
download | busybox-w32-03eb8bf6ce2cef8f30402b7c2b18e8479f9da1ea.tar.gz busybox-w32-03eb8bf6ce2cef8f30402b7c2b18e8479f9da1ea.tar.bz2 busybox-w32-03eb8bf6ce2cef8f30402b7c2b18e8479f9da1ea.zip |
hush: move towards more correct variable expansion
hush: fix a few cases in FOR v IN ... construct
unfortunately, code growth is big - ~600 bytes
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 367 |
1 files changed, 304 insertions, 63 deletions
diff --git a/shell/hush.c b/shell/hush.c index dfb819122..803970b57 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -85,13 +85,14 @@ | |||
85 | 85 | ||
86 | /* If you comment out one of these below, it will be #defined later | 86 | /* If you comment out one of these below, it will be #defined later |
87 | * to perform debug printfs to stderr: */ | 87 | * to perform debug printfs to stderr: */ |
88 | #define debug_printf(...) do {} while (0) | 88 | #define debug_printf(...) do {} while (0) |
89 | /* Finer-grained debug switches */ | 89 | /* Finer-grained debug switches */ |
90 | #define debug_printf_parse(...) do {} while (0) | 90 | #define debug_printf_parse(...) do {} while (0) |
91 | #define debug_print_tree(a, b) do {} while (0) | 91 | #define debug_print_tree(a, b) do {} while (0) |
92 | #define debug_printf_exec(...) do {} while (0) | 92 | #define debug_printf_exec(...) do {} while (0) |
93 | #define debug_printf_jobs(...) do {} while (0) | 93 | #define debug_printf_jobs(...) do {} while (0) |
94 | #define debug_printf_clean(...) do {} while (0) | 94 | #define debug_printf_expand(...) do {} while (0) |
95 | #define debug_printf_clean(...) do {} while (0) | ||
95 | 96 | ||
96 | #ifndef debug_printf | 97 | #ifndef debug_printf |
97 | #define debug_printf(...) fprintf(stderr, __VA_ARGS__) | 98 | #define debug_printf(...) fprintf(stderr, __VA_ARGS__) |
@@ -110,6 +111,11 @@ | |||
110 | #define DEBUG_SHELL_JOBS 1 | 111 | #define DEBUG_SHELL_JOBS 1 |
111 | #endif | 112 | #endif |
112 | 113 | ||
114 | #ifndef debug_printf_expand | ||
115 | #define debug_printf_expand(...) fprintf(stderr, __VA_ARGS__) | ||
116 | #define DEBUG_EXPAND 1 | ||
117 | #endif | ||
118 | |||
113 | #ifndef debug_printf_clean | 119 | #ifndef debug_printf_clean |
114 | /* broken, of course, but OK for testing */ | 120 | /* broken, of course, but OK for testing */ |
115 | static const char *indenter(int i) | 121 | static const char *indenter(int i) |
@@ -229,6 +235,12 @@ struct child_prog { | |||
229 | int sp; /* number of SPECIAL_VAR_SYMBOL */ | 235 | int sp; /* number of SPECIAL_VAR_SYMBOL */ |
230 | int type; | 236 | int type; |
231 | }; | 237 | }; |
238 | // sp counting seems to be broken... | ||
239 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) | ||
240 | * and on execution these are substituted with their values. | ||
241 | * Substitution can make _several_ words out of one argv[n]! | ||
242 | * Example: argv[0]=='.^C*^C.' here: echo .$*. | ||
243 | */ | ||
232 | 244 | ||
233 | struct pipe { | 245 | struct pipe { |
234 | struct pipe *next; | 246 | struct pipe *next; |
@@ -430,7 +442,7 @@ static void delete_finished_bg_job(struct pipe *pi); | |||
430 | int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ | 442 | int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ |
431 | #endif | 443 | #endif |
432 | /* local variable support */ | 444 | /* local variable support */ |
433 | static char **make_list_in(char **inp, char *name); | 445 | static char **do_variable_expansion(char **argv); |
434 | static char *insert_var_value(char *inp); | 446 | static char *insert_var_value(char *inp); |
435 | static const char *get_local_var(const char *var); | 447 | static const char *get_local_var(const char *var); |
436 | static int set_local_var(const char *s, int flg_export); | 448 | static int set_local_var(const char *s, int flg_export); |
@@ -1265,10 +1277,8 @@ static void restore_redirects(int squirrel[]) | |||
1265 | for (i = 0; i < 3; i++) { | 1277 | for (i = 0; i < 3; i++) { |
1266 | fd = squirrel[i]; | 1278 | fd = squirrel[i]; |
1267 | if (fd != -1) { | 1279 | if (fd != -1) { |
1268 | /* No error checking. I sure wouldn't know what | 1280 | /* We simply die on error */ |
1269 | * to do with an error if I found one! */ | 1281 | xmove_fd(fd, i); |
1270 | dup2(fd, i); | ||
1271 | close(fd); | ||
1272 | } | 1282 | } |
1273 | } | 1283 | } |
1274 | } | 1284 | } |
@@ -1916,9 +1926,9 @@ static int run_list_real(struct pipe *pi) | |||
1916 | enum { level = 0 }; | 1926 | enum { level = 0 }; |
1917 | #endif | 1927 | #endif |
1918 | 1928 | ||
1919 | char *save_name = NULL; | 1929 | char *for_varname = NULL; |
1920 | char **list = NULL; | 1930 | char **for_lcur = NULL; |
1921 | char **save_list = NULL; | 1931 | char **for_list = NULL; |
1922 | struct pipe *rpipe; | 1932 | struct pipe *rpipe; |
1923 | int flag_rep = 0; | 1933 | int flag_rep = 0; |
1924 | int save_num_progs; | 1934 | int save_num_progs; |
@@ -2018,30 +2028,29 @@ static int run_list_real(struct pipe *pi) | |||
2018 | if (rmode == RES_ELIF && !if_code) | 2028 | if (rmode == RES_ELIF && !if_code) |
2019 | break; | 2029 | break; |
2020 | if (rmode == RES_FOR && pi->num_progs) { | 2030 | if (rmode == RES_FOR && pi->num_progs) { |
2021 | if (!list) { | 2031 | if (!for_lcur) { |
2022 | /* if no variable values after "in" we skip "for" */ | 2032 | /* if no variable values after "in" we skip "for" */ |
2023 | if (!pi->next->progs->argv) | 2033 | if (!pi->next->progs->argv) |
2024 | continue; | 2034 | continue; |
2025 | /* create list of variable values */ | 2035 | /* create list of variable values */ |
2026 | list = make_list_in(pi->next->progs->argv, | 2036 | for_list = do_variable_expansion(pi->next->progs->argv); |
2027 | pi->progs->argv[0]); | 2037 | for_lcur = for_list; |
2028 | save_list = list; | 2038 | for_varname = pi->progs->argv[0]; |
2029 | save_name = pi->progs->argv[0]; | ||
2030 | pi->progs->argv[0] = NULL; | 2039 | pi->progs->argv[0] = NULL; |
2031 | flag_rep = 1; | 2040 | flag_rep = 1; |
2032 | } | 2041 | } |
2033 | if (!*list) { | 2042 | free(pi->progs->argv[0]); |
2034 | free(pi->progs->argv[0]); | 2043 | if (!*for_lcur) { |
2035 | free(save_list); | 2044 | free(for_list); |
2036 | list = NULL; | 2045 | for_lcur = NULL; |
2037 | flag_rep = 0; | 2046 | flag_rep = 0; |
2038 | pi->progs->argv[0] = save_name; | 2047 | pi->progs->argv[0] = for_varname; |
2039 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; | 2048 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; |
2040 | continue; | 2049 | continue; |
2041 | } | 2050 | } |
2042 | /* insert new value from list for variable */ | 2051 | /* insert next value from for_lcur */ |
2043 | free(pi->progs->argv[0]); | 2052 | //vda: does it need escaping? |
2044 | pi->progs->argv[0] = *list++; | 2053 | pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); |
2045 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; | 2054 | pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; |
2046 | } | 2055 | } |
2047 | if (rmode == RES_IN) | 2056 | if (rmode == RES_IN) |
@@ -2288,50 +2297,267 @@ static int xglob(o_string *dest, int flags, glob_t *pglob) | |||
2288 | return gr; | 2297 | return gr; |
2289 | } | 2298 | } |
2290 | 2299 | ||
2291 | static char **make_list_in(char **inp, char *name) | 2300 | |
2301 | /* do_variable_expansion() takes a list of strings, expands | ||
2302 | * all variable references within and returns a pointer to | ||
2303 | * a list of expanded strings, possibly with larger number | ||
2304 | * of strings. (Think VAR="a b"; echo $VAR). | ||
2305 | * This new list is allocated as a single malloc block. | ||
2306 | * NULL-terminated list of char* pointers is at the beginning of it, | ||
2307 | * followed by strings themself. | ||
2308 | * Caller can deallocate entire list by single free(list). */ | ||
2309 | |||
2310 | /* Helpers first: | ||
2311 | * count_XXX estimates, how large block do we need. It's okay | ||
2312 | * to over-estimate sizes a bit, if it makes code simpler */ | ||
2313 | static int count_ifs(const char *str) | ||
2292 | { | 2314 | { |
2293 | int len, i; | 2315 | int cnt = 0; |
2294 | #if 0 | 2316 | debug_printf_expand("count_ifs('%s') ifs='%s'", str, ifs); |
2295 | int name_len = strlen(name); | 2317 | while (1) { |
2296 | #endif | 2318 | str += strcspn(str, ifs); |
2297 | int n; | 2319 | if (!*str) break; |
2298 | char **list; | 2320 | str++; // str += strspn(str, ifs); ? |
2299 | char *p1, *p2, *p3; | 2321 | cnt++; // cnt += strspn(str, ifs); ? |
2322 | } | ||
2323 | debug_printf_expand(" return %d\n", cnt); | ||
2324 | return cnt; | ||
2325 | } | ||
2300 | 2326 | ||
2301 | /* create list of variable values */ | 2327 | static void count_var_expansion_space(int *countp, int *lenp, char *arg) |
2302 | list = xmalloc(sizeof(*list)); | 2328 | { |
2303 | n = 0; | 2329 | char first_ch; |
2304 | for (i = 0; inp[i]; i++) { | 2330 | int i; |
2305 | p3 = insert_var_value(inp[i]); | 2331 | int len = *lenp; |
2306 | p1 = p3; | 2332 | int count = *countp; |
2307 | while (*p1) { | 2333 | const char *val; |
2308 | if (*p1 == ' ') { | 2334 | char *p; |
2309 | p1++; | 2335 | |
2310 | continue; | 2336 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) { |
2337 | len += p - arg; | ||
2338 | arg = ++p; | ||
2339 | p = strchr(p, SPECIAL_VAR_SYMBOL); | ||
2340 | first_ch = arg[0]; | ||
2341 | |||
2342 | switch (first_ch & 0x7f) { | ||
2343 | /* high bit in 1st_ch indicates that var is double-quoted */ | ||
2344 | case '$': /* pid */ | ||
2345 | case '!': /* bg pid */ | ||
2346 | case '?': /* exitcode */ | ||
2347 | case '#': /* argc */ | ||
2348 | len += sizeof(int)*3 + 1; /* enough for int */ | ||
2349 | break; | ||
2350 | case '*': | ||
2351 | case '@': | ||
2352 | for (i = 1; i < global_argc; i++) { | ||
2353 | len += strlen(global_argv[i]) + 1; | ||
2354 | count++; | ||
2355 | if (!(first_ch & 0x80)) | ||
2356 | count += count_ifs(global_argv[i]); | ||
2357 | } | ||
2358 | break; | ||
2359 | default: | ||
2360 | *p = '\0'; | ||
2361 | arg[0] = first_ch & 0x7f; | ||
2362 | val = lookup_param(arg); | ||
2363 | arg[0] = first_ch; | ||
2364 | *p = SPECIAL_VAR_SYMBOL; | ||
2365 | |||
2366 | if (val) { | ||
2367 | len += strlen(val) + 1; | ||
2368 | if (!(first_ch & 0x80)) | ||
2369 | count += count_ifs(val); | ||
2311 | } | 2370 | } |
2312 | p2 = strchrnul(p1, ' '); | ||
2313 | len = p2 - p1; | ||
2314 | /* we use n + 2 in realloc for list, because we add | ||
2315 | * new element and then we will add NULL element */ | ||
2316 | list = xrealloc(list, sizeof(*list) * (n + 2)); | ||
2317 | list[n] = xasprintf("%s=%.*s", name, len, p1); | ||
2318 | #if 0 /* faster, but more code */ | ||
2319 | list[n] = xmalloc(2 + name_len + len); | ||
2320 | strcpy(list[n], name); | ||
2321 | list[n][name_len] = '='; | ||
2322 | strncat(&(list[n][name_len + 1]), p1, len); | ||
2323 | list[n][name_len + len + 1] = '\0'; | ||
2324 | #endif | ||
2325 | n++; | ||
2326 | p1 = p2; | ||
2327 | } | 2371 | } |
2328 | if (p3 != inp[i]) | 2372 | arg = ++p; |
2329 | free(p3); | ||
2330 | } | 2373 | } |
2374 | |||
2375 | len += strlen(arg) + 1; | ||
2376 | count++; | ||
2377 | *lenp = len; | ||
2378 | *countp = count; | ||
2379 | } | ||
2380 | |||
2381 | /* Store given string, finalizing the word and starting new one whenever | ||
2382 | * we encounter ifs char(s). This is used for expanding variable values. | ||
2383 | * End-of-string does NOT finalize word, because cases like echo -$VAR- */ | ||
2384 | static int expand_on_ifs(char **list, int n, char **posp, const char *str) | ||
2385 | { | ||
2386 | char *pos = *posp; | ||
2387 | while (1) { | ||
2388 | int word_len = strcspn(str, ifs); | ||
2389 | if (word_len) { | ||
2390 | memcpy(pos, str, word_len); /* store non-ifs chars */ | ||
2391 | pos += word_len; | ||
2392 | str += word_len; | ||
2393 | if (!*str) /* EOL - do not finalize word */ | ||
2394 | break; | ||
2395 | *pos++ = '\0'; | ||
2396 | if (n) debug_printf_expand("expand_on_ifs finalized list[%d]=%p '%s' " | ||
2397 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | ||
2398 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | ||
2399 | list[n++] = pos; | ||
2400 | } | ||
2401 | if (!*str) break; /* EOL, not ifs char */ | ||
2402 | str += strspn(str, ifs); /* skip ifs chars */ | ||
2403 | } | ||
2404 | *posp = pos; | ||
2405 | return n; | ||
2406 | } | ||
2407 | |||
2408 | /* Expand all variable references in given string, adding words to list[] | ||
2409 | * at n, n+1,... positions. Return updated n (so that list[n] is next one | ||
2410 | * to be filled). This routine is extremely tricky: has to deal with | ||
2411 | * variables/parameters with whitespace, $* and $@, and constructs like | ||
2412 | * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ | ||
2413 | /* NB: support for double-quoted expansion is not used yet (we never set | ||
2414 | * magic bit 0x80 elsewhere...) */ | ||
2415 | /* NB: another bug is that we cannot detect empty strings yet: | ||
2416 | * "" or $empty"" expands to zero words, has to expand to empty word */ | ||
2417 | static int expand_vars_to_list(char **list, int n, char **posp, char *arg) | ||
2418 | { | ||
2419 | char first_ch, ored_ch; | ||
2420 | const char *val; | ||
2421 | char *p; | ||
2422 | char *pos = *posp; | ||
2423 | |||
2424 | ored_ch = 0; | ||
2425 | |||
2426 | if (n) debug_printf_expand("expand_vars_to_list finalized list[%d]=%p '%s' " | ||
2427 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | ||
2428 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | ||
2429 | list[n++] = pos; | ||
2430 | |||
2431 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL))) { | ||
2432 | memcpy(pos, arg, p - arg); | ||
2433 | pos += (p - arg); | ||
2434 | arg = ++p; | ||
2435 | p = strchr(p, SPECIAL_VAR_SYMBOL); | ||
2436 | |||
2437 | first_ch = arg[0]; | ||
2438 | ored_ch |= first_ch; | ||
2439 | val = NULL; | ||
2440 | switch (first_ch & 0x7f) { | ||
2441 | /* Highest bit in first_ch indicates that var is double-quoted */ | ||
2442 | case '$': /* pid */ | ||
2443 | /* FIXME: (echo $$) should still print pid of main shell */ | ||
2444 | val = utoa(getpid()); | ||
2445 | break; | ||
2446 | case '!': /* bg pid */ | ||
2447 | val = last_bg_pid ? utoa(last_bg_pid) : (char*)""; | ||
2448 | break; | ||
2449 | case '?': /* exitcode */ | ||
2450 | val = utoa(last_return_code); | ||
2451 | break; | ||
2452 | case '#': /* argc */ | ||
2453 | val = utoa(global_argc ? global_argc-1 : 0); | ||
2454 | break; | ||
2455 | case '*': | ||
2456 | case '@': | ||
2457 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ | ||
2458 | int i = 1; | ||
2459 | while (i < global_argc) { | ||
2460 | n = expand_on_ifs(list, n, &pos, global_argv[i]); | ||
2461 | debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1); | ||
2462 | if (global_argv[i++][0] && i < global_argc) { | ||
2463 | /* this argv[] is not empty and not last: | ||
2464 | * put terminating NUL, start new word */ | ||
2465 | *pos++ = '\0'; | ||
2466 | if (n) debug_printf_expand("expand_vars_to_list 2 finalized list[%d]=%p '%s' " | ||
2467 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | ||
2468 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | ||
2469 | list[n++] = pos; | ||
2470 | } | ||
2471 | } | ||
2472 | } else if (first_ch == ('@'|0x80)) { /* quoted $@ */ | ||
2473 | /* TODO */ | ||
2474 | } else { /* quoted $* */ | ||
2475 | /* TODO */ | ||
2476 | } | ||
2477 | break; | ||
2478 | default: | ||
2479 | *p = '\0'; | ||
2480 | arg[0] = first_ch & 0x7f; | ||
2481 | val = lookup_param(arg); | ||
2482 | arg[0] = first_ch; | ||
2483 | *p = SPECIAL_VAR_SYMBOL; | ||
2484 | if (!(first_ch & 0x80)) { /* unquoted var */ | ||
2485 | if (val) { | ||
2486 | n = expand_on_ifs(list, n, &pos, val); | ||
2487 | val = NULL; | ||
2488 | } | ||
2489 | } | ||
2490 | } | ||
2491 | if (val) { | ||
2492 | strcpy(pos, val); | ||
2493 | pos += strlen(val); | ||
2494 | } | ||
2495 | arg = ++p; | ||
2496 | } | ||
2497 | debug_printf_expand("expand_vars_to_list adding tail '%s' at %p\n", arg, pos); | ||
2498 | strcpy(pos, arg); | ||
2499 | pos += strlen(arg) + 1; | ||
2500 | if (pos == list[n-1] + 1) { /* expansion is empty */ | ||
2501 | if (!(ored_ch & 0x80)) { /* all vars were not quoted... */ | ||
2502 | debug_printf_expand("expand_vars_to_list list[%d] empty, going back\n", n); | ||
2503 | pos--; | ||
2504 | n--; | ||
2505 | } | ||
2506 | } | ||
2507 | |||
2508 | *posp = pos; | ||
2509 | return n; | ||
2510 | } | ||
2511 | |||
2512 | static char **do_variable_expansion(char **argv) | ||
2513 | { | ||
2514 | int n; | ||
2515 | int count = 1; | ||
2516 | int len = 0; | ||
2517 | char *pos, **v, **list; | ||
2518 | |||
2519 | v = argv; | ||
2520 | if (!*v) debug_printf_expand("count_var_expansion_space: " | ||
2521 | "argv[0]=NULL count=%d len=%d alloc_space=%d\n", | ||
2522 | count, len, sizeof(char*) * count + len); | ||
2523 | while (*v) { | ||
2524 | count_var_expansion_space(&count, &len, *v); | ||
2525 | debug_printf_expand("count_var_expansion_space: " | ||
2526 | "'%s' count=%d len=%d alloc_space=%d\n", | ||
2527 | *v, count, len, sizeof(char*) * count + len); | ||
2528 | v++; | ||
2529 | } | ||
2530 | len += sizeof(char*) * count; /* total to alloc */ | ||
2531 | list = xmalloc(len); | ||
2532 | pos = (char*)(list + count); | ||
2533 | debug_printf_expand("list=%p, list[0] should be %p\n", list, pos); | ||
2534 | n = 0; | ||
2535 | v = argv; | ||
2536 | while (*v) | ||
2537 | n = expand_vars_to_list(list, n, &pos, *v++); | ||
2538 | |||
2539 | if(n) debug_printf_expand("finalized list[%d]=%p '%s' " | ||
2540 | "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], | ||
2541 | strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); | ||
2331 | list[n] = NULL; | 2542 | list[n] = NULL; |
2543 | |||
2544 | #ifdef DEBUG_EXPAND | ||
2545 | { | ||
2546 | int m = 0; | ||
2547 | while (m <= n) { | ||
2548 | debug_printf_expand("list[%d]=%p '%s'\n", m, list[m], list[m]); | ||
2549 | m++; | ||
2550 | } | ||
2551 | debug_printf_expand("used_space=%d\n", pos - (char*)list); | ||
2552 | } | ||
2553 | #endif | ||
2554 | /* To be removed / made conditional later. */ | ||
2555 | if (pos - (char*)list > len) | ||
2556 | bb_error_msg_and_die("BUG in varexp"); | ||
2332 | return list; | 2557 | return list; |
2333 | } | 2558 | } |
2334 | 2559 | ||
2560 | |||
2335 | static char *insert_var_value(char *inp) | 2561 | static char *insert_var_value(char *inp) |
2336 | { | 2562 | { |
2337 | int res_str_len = 0; | 2563 | int res_str_len = 0; |
@@ -2404,6 +2630,21 @@ static char *insert_var_value(char *inp) | |||
2404 | return (res_str == NULL) ? inp : res_str; | 2630 | return (res_str == NULL) ? inp : res_str; |
2405 | } | 2631 | } |
2406 | 2632 | ||
2633 | |||
2634 | |||
2635 | |||
2636 | |||
2637 | |||
2638 | |||
2639 | |||
2640 | |||
2641 | |||
2642 | |||
2643 | |||
2644 | |||
2645 | |||
2646 | |||
2647 | |||
2407 | /* This is used to get/check local shell variables */ | 2648 | /* This is used to get/check local shell variables */ |
2408 | static const char *get_local_var(const char *s) | 2649 | static const char *get_local_var(const char *s) |
2409 | { | 2650 | { |
@@ -2986,7 +3227,7 @@ static const char *lookup_param(const char *src) | |||
2986 | } | 3227 | } |
2987 | 3228 | ||
2988 | /* Make new string for parser */ | 3229 | /* Make new string for parser */ |
2989 | static char* make_string(char ** inp) | 3230 | static char* make_string(char **inp) |
2990 | { | 3231 | { |
2991 | char *p; | 3232 | char *p; |
2992 | char *str = NULL; | 3233 | char *str = NULL; |