summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-17 14:38:17 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-17 14:38:17 +0000
commitb6a741ffa7be0926049c663e218864288e9161c1 (patch)
tree9da4bfbdb39cd7f6ba3df9f62e7358312952992b /shell/hush.c
parent96f67dc69d251168ea1c0adfaf6ff126d5dcbd36 (diff)
downloadbusybox-w32-b6a741ffa7be0926049c663e218864288e9161c1.tar.gz
busybox-w32-b6a741ffa7be0926049c663e218864288e9161c1.tar.bz2
busybox-w32-b6a741ffa7be0926049c663e218864288e9161c1.zip
hush: consolidated variable expansion for assignments and "normal" one.
-435 bytes. Tested against testsuite.
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c126
1 files changed, 39 insertions, 87 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 0a035cad4..9f0cc641e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -444,8 +444,9 @@ static void delete_finished_bg_job(struct pipe *pi);
444int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */ 444int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
445#endif 445#endif
446/* local variable support */ 446/* local variable support */
447static char **do_variable_expansion(char **argv); 447static char **expand_variables_to_list(char **argv);
448static char *insert_var_value(char *inp); 448/* used for expansion of right hand of assignments */
449static char *expand_variables_to_string(const char *str);
449static const char *get_local_var(const char *var); 450static const char *get_local_var(const char *var);
450static int set_local_var(const char *s, int flg_export); 451static int set_local_var(const char *s, int flg_export);
451static void unset_local_var(const char *name); 452static void unset_local_var(const char *name);
@@ -1271,7 +1272,7 @@ static void pseudo_exec_argv(char **argv)
1271 debug_printf_exec("pid %d environment modification: %s\n", 1272 debug_printf_exec("pid %d environment modification: %s\n",
1272 getpid(), argv[i]); 1273 getpid(), argv[i]);
1273// FIXME: vfork case?? 1274// FIXME: vfork case??
1274 p = insert_var_value(argv[i]); 1275 p = expand_variables_to_string(argv[i]);
1275 putenv(p == argv[i] ? xstrdup(p) : p); 1276 putenv(p == argv[i] ? xstrdup(p) : p);
1276 } 1277 }
1277 argv += i; 1278 argv += i;
@@ -1282,7 +1283,7 @@ static void pseudo_exec_argv(char **argv)
1282 _exit(EXIT_SUCCESS); 1283 _exit(EXIT_SUCCESS);
1283 } 1284 }
1284 1285
1285 argv = do_variable_expansion(argv); 1286 argv = expand_variables_to_list(argv);
1286 1287
1287 /* 1288 /*
1288 * Check if the command matches any of the builtins. 1289 * Check if the command matches any of the builtins.
@@ -1667,7 +1668,7 @@ static int run_pipe_real(struct pipe *pi)
1667 export_me = 1; 1668 export_me = 1;
1668 } 1669 }
1669 free(name); 1670 free(name);
1670 p = insert_var_value(argv[i]); 1671 p = expand_variables_to_string(argv[i]);
1671 set_local_var(p, export_me); 1672 set_local_var(p, export_me);
1672 if (p != argv[i]) 1673 if (p != argv[i])
1673 free(p); 1674 free(p);
@@ -1675,7 +1676,7 @@ static int run_pipe_real(struct pipe *pi)
1675 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1676 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1676 } 1677 }
1677 for (i = 0; is_assignment(argv[i]); i++) { 1678 for (i = 0; is_assignment(argv[i]); i++) {
1678 p = insert_var_value(argv[i]); 1679 p = expand_variables_to_string(argv[i]);
1679 if (p != argv[i]) { 1680 if (p != argv[i]) {
1680 //sp: child->sp--; 1681 //sp: child->sp--;
1681 putenv(p); 1682 putenv(p);
@@ -1698,7 +1699,7 @@ static int run_pipe_real(struct pipe *pi)
1698 setup_redirects(child, squirrel); 1699 setup_redirects(child, squirrel);
1699 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); 1700 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
1700 //sp: if (child->sp) /* btw we can do it unconditionally... */ 1701 //sp: if (child->sp) /* btw we can do it unconditionally... */
1701 argv_expanded = do_variable_expansion(argv + i); 1702 argv_expanded = expand_variables_to_list(argv + i);
1702 rcode = x->function(argv_expanded); 1703 rcode = x->function(argv_expanded);
1703 free(argv_expanded); 1704 free(argv_expanded);
1704 restore_redirects(squirrel); 1705 restore_redirects(squirrel);
@@ -1714,7 +1715,7 @@ static int run_pipe_real(struct pipe *pi)
1714 save_nofork_data(&nofork_save); 1715 save_nofork_data(&nofork_save);
1715 argv_expanded = argv + i; 1716 argv_expanded = argv + i;
1716 //sp: if (child->sp) 1717 //sp: if (child->sp)
1717 argv_expanded = do_variable_expansion(argv + i); 1718 argv_expanded = expand_variables_to_list(argv + i);
1718 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); 1719 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
1719 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); 1720 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
1720 free(argv_expanded); 1721 free(argv_expanded);
@@ -1991,7 +1992,7 @@ static int run_list_real(struct pipe *pi)
1991 if (!pi->next->progs->argv) 1992 if (!pi->next->progs->argv)
1992 continue; 1993 continue;
1993 /* create list of variable values */ 1994 /* create list of variable values */
1994 for_list = do_variable_expansion(pi->next->progs->argv); 1995 for_list = expand_variables_to_list(pi->next->progs->argv);
1995 for_lcur = for_list; 1996 for_lcur = for_list;
1996 for_varname = pi->progs->argv[0]; 1997 for_varname = pi->progs->argv[0];
1997 pi->progs->argv[0] = NULL; 1998 pi->progs->argv[0] = NULL;
@@ -2251,8 +2252,7 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
2251 return gr; 2252 return gr;
2252} 2253}
2253 2254
2254 2255/* expand_variables_to_list() takes a list of strings, expands
2255/* do_variable_expansion() takes a list of strings, expands
2256 * all variable references within and returns a pointer to 2256 * all variable references within and returns a pointer to
2257 * a list of expanded strings, possibly with larger number 2257 * a list of expanded strings, possibly with larger number
2258 * of strings. (Think VAR="a b"; echo $VAR). 2258 * of strings. (Think VAR="a b"; echo $VAR).
@@ -2371,8 +2371,11 @@ static int expand_on_ifs(char **list, int n, char **posp, const char *str)
2371 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ 2371 * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
2372/* NB: another bug is that we cannot detect empty strings yet: 2372/* NB: another bug is that we cannot detect empty strings yet:
2373 * "" or $empty"" expands to zero words, has to expand to empty word */ 2373 * "" or $empty"" expands to zero words, has to expand to empty word */
2374static int expand_vars_to_list(char **list, int n, char **posp, char *arg) 2374static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask)
2375{ 2375{
2376 /* or_mask is either 0 (normal case) or 0x80
2377 * (expansion of right-hand side of assignment == 1-element expand) */
2378
2376 char first_ch, ored_ch; 2379 char first_ch, ored_ch;
2377 int i; 2380 int i;
2378 const char *val; 2381 const char *val;
@@ -2392,7 +2395,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
2392 arg = ++p; 2395 arg = ++p;
2393 p = strchr(p, SPECIAL_VAR_SYMBOL); 2396 p = strchr(p, SPECIAL_VAR_SYMBOL);
2394 2397
2395 first_ch = arg[0]; 2398 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
2396 ored_ch |= first_ch; 2399 ored_ch |= first_ch;
2397 val = NULL; 2400 val = NULL;
2398 switch (first_ch & 0x7f) { 2401 switch (first_ch & 0x7f) {
@@ -2427,7 +2430,10 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
2427 list[n++] = pos; 2430 list[n++] = pos;
2428 } 2431 }
2429 } 2432 }
2430 } else if (first_ch == ('@'|0x80)) { /* quoted $@ */ 2433 } else
2434 /* If or_mask is nonzero, we handle assignment 'a=....$@.....'
2435 * and in this case should theat it like '$*' */
2436 if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
2431 while (1) { 2437 while (1) {
2432 strcpy(pos, global_argv[i]); 2438 strcpy(pos, global_argv[i]);
2433 pos += strlen(global_argv[i]); 2439 pos += strlen(global_argv[i]);
@@ -2490,7 +2496,7 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
2490 return n; 2496 return n;
2491} 2497}
2492 2498
2493static char **do_variable_expansion(char **argv) 2499static char **expand_variables(char **argv, char or_mask)
2494{ 2500{
2495 int n; 2501 int n;
2496 int count = 1; 2502 int count = 1;
@@ -2515,9 +2521,9 @@ static char **do_variable_expansion(char **argv)
2515 n = 0; 2521 n = 0;
2516 v = argv; 2522 v = argv;
2517 while (*v) 2523 while (*v)
2518 n = expand_vars_to_list(list, n, &pos, *v++); 2524 n = expand_vars_to_list(list, n, &pos, *v++, or_mask);
2519 2525
2520 if(n) debug_printf_expand("finalized list[%d]=%p '%s' " 2526 if (n) debug_printf_expand("finalized list[%d]=%p '%s' "
2521 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1], 2527 "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
2522 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos); 2528 strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
2523 list[n] = NULL; 2529 list[n] = NULL;
@@ -2538,80 +2544,26 @@ static char **do_variable_expansion(char **argv)
2538 return list; 2544 return list;
2539} 2545}
2540 2546
2547static char **expand_variables_to_list(char **argv)
2548{
2549 return expand_variables(argv, 0);
2550}
2541 2551
2542static char *insert_var_value(char *inp) 2552static char *expand_variables_to_string(const char *str)
2543{ 2553{
2544 int res_str_len = 0; 2554 char *argv[2], **list;
2545 int len;
2546 int done = 0;
2547 int i;
2548 const char *p1;
2549 char *p, *p2;
2550 char *res_str = NULL;
2551
2552 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
2553 if (p != inp) {
2554 len = p - inp;
2555 res_str = xrealloc(res_str, (res_str_len + len));
2556 strncpy((res_str + res_str_len), inp, len);
2557 res_str_len += len;
2558 }
2559 inp = ++p;
2560 p = strchr(inp, SPECIAL_VAR_SYMBOL);
2561 *p = '\0';
2562
2563 switch (inp[0]) {
2564 case '$':
2565 /* FIXME: (echo $$) should still print pid of main shell */
2566 p1 = utoa(getpid());
2567 break;
2568 case '!':
2569 p1 = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
2570 break;
2571 case '?':
2572 p1 = utoa(last_return_code);
2573 break;
2574 case '#':
2575 p1 = utoa(global_argc ? global_argc-1 : 0);
2576 break;
2577 case '*':
2578 case '@': /* FIXME: we treat $@ as $* for now */
2579 len = 1;
2580 for (i = 1; i < global_argc; i++)
2581 len += strlen(global_argv[i]) + 1;
2582 p1 = p2 = alloca(--len);
2583 for (i = 1; i < global_argc; i++) {
2584 strcpy(p2, global_argv[i]);
2585 p2 += strlen(global_argv[i]);
2586 *p2++ = ifs[0];
2587 }
2588 *--p2 = '\0';
2589 break;
2590 default:
2591 p1 = lookup_param(inp);
2592 }
2593 2555
2594 if (p1) { 2556 argv[0] = (char*)str;
2595 len = res_str_len + strlen(p1); 2557 argv[1] = NULL;
2596 res_str = xrealloc(res_str, 1 + len); 2558 list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
2597 strcpy(res_str + res_str_len, p1); 2559 /* To be removed / made conditional later. */
2598 res_str_len = len; 2560 if (!list[0] || list[1])
2599 } 2561 bb_error_msg_and_die("BUG in varexp");
2600 *p = SPECIAL_VAR_SYMBOL; 2562 /* actually, just move string 2*sizeof(char*) bytes back */
2601 inp = ++p; 2563 strcpy((char*)list, list[0]);
2602 done = 1; 2564 return (char*)list;
2603 }
2604 if (done) {
2605 res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
2606 strcpy((res_str + res_str_len), inp);
2607 while ((p = strchr(res_str, '\n'))) {
2608 *p = ' ';
2609 }
2610 }
2611 return (res_str == NULL) ? inp : res_str;
2612} 2565}
2613 2566
2614
2615/* This is used to get/check local shell variables */ 2567/* This is used to get/check local shell variables */
2616static const char *get_local_var(const char *s) 2568static const char *get_local_var(const char *s)
2617{ 2569{
@@ -3195,7 +3147,7 @@ static char* make_string(char **inp)
3195 int len = 0; 3147 int len = 0;
3196 3148
3197 for (n = 0; inp[n]; n++) { 3149 for (n = 0; inp[n]; n++) {
3198 p = insert_var_value(inp[n]); 3150 p = expand_variables_to_string(inp[n]);
3199 val_len = strlen(p); 3151 val_len = strlen(p);
3200 str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/ 3152 str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/
3201 str[len++] = ' '; 3153 str[len++] = ' ';