diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-18 01:05:24 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-18 01:05:24 +0200 |
commit | 3bab36b18baa0dc254445828f492051450a38d41 (patch) | |
tree | cc264de1f0ae093cfde9e3470756bf1dcc5d21fc | |
parent | 6b0695bb66dd38af4d4671fb2381fa3e1dbfe90c (diff) | |
download | busybox-w32-3bab36b18baa0dc254445828f492051450a38d41.tar.gz busybox-w32-3bab36b18baa0dc254445828f492051450a38d41.tar.bz2 busybox-w32-3bab36b18baa0dc254445828f492051450a38d41.zip |
hush: convert exp/ro/local parameters to bitfields in one flag param
function old new delta
helper_export_local 174 185 +11
set_local_var 424 420 -4
run_list 1048 1044 -4
set_vars_and_save_old 88 83 -5
set_local_var_from_halves 27 22 -5
run_pipe 1554 1549 -5
builtin_export 173 168 -5
set_pwd_var 40 34 -6
builtin_readonly 70 64 -6
expand_one_var 1625 1618 -7
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/9 up/down: 11/-47) Total: -36 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 81 |
1 files changed, 35 insertions, 46 deletions
diff --git a/shell/hush.c b/shell/hush.c index 4b71344da..7771172b6 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2057,25 +2057,20 @@ static const char* FAST_FUNC get_local_var_value(const char *name) | |||
2057 | 2057 | ||
2058 | /* str holds "NAME=VAL" and is expected to be malloced. | 2058 | /* str holds "NAME=VAL" and is expected to be malloced. |
2059 | * We take ownership of it. | 2059 | * We take ownership of it. |
2060 | * flg_export: | ||
2061 | * 0: do not change export flag | ||
2062 | * (if creating new variable, flag will be 0) | ||
2063 | * 1: set export flag and putenv the variable | ||
2064 | * -1: clear export flag and unsetenv the variable | ||
2065 | * flg_read_only is set only when we handle -R var=val | ||
2066 | */ | 2060 | */ |
2067 | static int set_local_var(char *str, | 2061 | #define SETFLAG_EXPORT (1 << 0) |
2068 | int flg_export UNUSED_PARAM, | 2062 | #define SETFLAG_UNEXPORT (1 << 1) |
2069 | int local_lvl UNUSED_PARAM, | 2063 | #define SETFLAG_MAKE_RO (1 << 2) |
2070 | int flg_read_only UNUSED_PARAM) | 2064 | #define SETFLAG_LOCAL_SHIFT 3 |
2065 | static int set_local_var(char *str, unsigned flags) | ||
2071 | { | 2066 | { |
2072 | struct variable **var_pp; | 2067 | struct variable **var_pp; |
2073 | struct variable *cur; | 2068 | struct variable *cur; |
2074 | char *free_me = NULL; | 2069 | char *free_me = NULL; |
2075 | char *eq_sign; | 2070 | char *eq_sign; |
2076 | int name_len; | 2071 | int name_len; |
2072 | IF_HUSH_LOCAL(unsigned local_lvl = (flags >> SETFLAG_LOCAL_SHIFT);) | ||
2077 | 2073 | ||
2078 | //bb_error_msg("set_local_var('%s',%d,%d,%d)", str, flg_export, local_lvl, flg_read_only); | ||
2079 | eq_sign = strchr(str, '='); | 2074 | eq_sign = strchr(str, '='); |
2080 | if (!eq_sign) { /* not expected to ever happen? */ | 2075 | if (!eq_sign) { /* not expected to ever happen? */ |
2081 | free(str); | 2076 | free(str); |
@@ -2096,7 +2091,7 @@ static int set_local_var(char *str, | |||
2096 | free(str); | 2091 | free(str); |
2097 | return -1; | 2092 | return -1; |
2098 | } | 2093 | } |
2099 | if (flg_export == -1) { // "&& cur->flg_export" ? | 2094 | if (flags & SETFLAG_UNEXPORT) { // && cur->flg_export ? |
2100 | debug_printf_env("%s: unsetenv '%s'\n", __func__, str); | 2095 | debug_printf_env("%s: unsetenv '%s'\n", __func__, str); |
2101 | *eq_sign = '\0'; | 2096 | *eq_sign = '\0'; |
2102 | unsetenv(str); | 2097 | unsetenv(str); |
@@ -2120,7 +2115,7 @@ static int set_local_var(char *str, | |||
2120 | * z=z | 2115 | * z=z |
2121 | */ | 2116 | */ |
2122 | if (cur->flg_export) | 2117 | if (cur->flg_export) |
2123 | flg_export = 1; | 2118 | flags |= SETFLAG_EXPORT; |
2124 | break; | 2119 | break; |
2125 | } | 2120 | } |
2126 | #endif | 2121 | #endif |
@@ -2151,9 +2146,7 @@ static int set_local_var(char *str, | |||
2151 | 2146 | ||
2152 | /* Not found - create new variable struct */ | 2147 | /* Not found - create new variable struct */ |
2153 | cur = xzalloc(sizeof(*cur)); | 2148 | cur = xzalloc(sizeof(*cur)); |
2154 | #if ENABLE_HUSH_LOCAL | 2149 | IF_HUSH_LOCAL(cur->func_nest_level = local_lvl;) |
2155 | cur->func_nest_level = local_lvl; | ||
2156 | #endif | ||
2157 | cur->next = *var_pp; | 2150 | cur->next = *var_pp; |
2158 | *var_pp = cur; | 2151 | *var_pp = cur; |
2159 | 2152 | ||
@@ -2161,16 +2154,16 @@ static int set_local_var(char *str, | |||
2161 | cur->varstr = str; | 2154 | cur->varstr = str; |
2162 | exp: | 2155 | exp: |
2163 | #if !BB_MMU || ENABLE_HUSH_READONLY | 2156 | #if !BB_MMU || ENABLE_HUSH_READONLY |
2164 | if (flg_read_only != 0) { | 2157 | if (flags & SETFLAG_MAKE_RO) { |
2165 | cur->flg_read_only = flg_read_only; | 2158 | cur->flg_read_only = 1; |
2166 | } | 2159 | } |
2167 | #endif | 2160 | #endif |
2168 | if (flg_export == 1) | 2161 | if (flags & SETFLAG_EXPORT) |
2169 | cur->flg_export = 1; | 2162 | cur->flg_export = 1; |
2170 | if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') | 2163 | if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') |
2171 | cmdedit_update_prompt(); | 2164 | cmdedit_update_prompt(); |
2172 | if (cur->flg_export) { | 2165 | if (cur->flg_export) { |
2173 | if (flg_export == -1) { | 2166 | if (flags & SETFLAG_UNEXPORT) { |
2174 | cur->flg_export = 0; | 2167 | cur->flg_export = 0; |
2175 | /* unsetenv was already done */ | 2168 | /* unsetenv was already done */ |
2176 | } else { | 2169 | } else { |
@@ -2187,10 +2180,9 @@ static int set_local_var(char *str, | |||
2187 | } | 2180 | } |
2188 | 2181 | ||
2189 | /* Used at startup and after each cd */ | 2182 | /* Used at startup and after each cd */ |
2190 | static void set_pwd_var(int exp) | 2183 | static void set_pwd_var(unsigned flag) |
2191 | { | 2184 | { |
2192 | set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), | 2185 | set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), flag); |
2193 | /*exp:*/ exp, /*lvl:*/ 0, /*ro:*/ 0); | ||
2194 | } | 2186 | } |
2195 | 2187 | ||
2196 | static int unset_local_var_len(const char *name, int name_len) | 2188 | static int unset_local_var_len(const char *name, int name_len) |
@@ -2248,7 +2240,7 @@ static void unset_vars(char **strings) | |||
2248 | static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) | 2240 | static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) |
2249 | { | 2241 | { |
2250 | char *var = xasprintf("%s=%s", name, val); | 2242 | char *var = xasprintf("%s=%s", name, val); |
2251 | set_local_var(var, /*flags:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | 2243 | set_local_var(var, /*flag:*/ 0); |
2252 | } | 2244 | } |
2253 | #endif | 2245 | #endif |
2254 | 2246 | ||
@@ -2299,7 +2291,7 @@ static struct variable *set_vars_and_save_old(char **strings) | |||
2299 | var_p->next = old; | 2291 | var_p->next = old; |
2300 | old = var_p; | 2292 | old = var_p; |
2301 | } | 2293 | } |
2302 | set_local_var(*s, /*exp:*/ 1, /*lvl:*/ 0, /*ro:*/ 0); | 2294 | set_local_var(*s, SETFLAG_EXPORT); |
2303 | } | 2295 | } |
2304 | s++; | 2296 | s++; |
2305 | } | 2297 | } |
@@ -5805,7 +5797,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5805 | val = NULL; | 5797 | val = NULL; |
5806 | } else { | 5798 | } else { |
5807 | char *new_var = xasprintf("%s=%s", var, val); | 5799 | char *new_var = xasprintf("%s=%s", var, val); |
5808 | set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | 5800 | set_local_var(new_var, /*flag:*/ 0); |
5809 | } | 5801 | } |
5810 | } | 5802 | } |
5811 | } | 5803 | } |
@@ -7775,7 +7767,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7775 | if (new_env) { | 7767 | if (new_env) { |
7776 | argv = new_env; | 7768 | argv = new_env; |
7777 | while (*argv) { | 7769 | while (*argv) { |
7778 | set_local_var(*argv, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | 7770 | set_local_var(*argv, /*flag:*/ 0); |
7779 | /* Do we need to flag set_local_var() errors? | 7771 | /* Do we need to flag set_local_var() errors? |
7780 | * "assignment to readonly var" and "putenv error" | 7772 | * "assignment to readonly var" and "putenv error" |
7781 | */ | 7773 | */ |
@@ -7803,7 +7795,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7803 | fprintf(stderr, " %s", p); | 7795 | fprintf(stderr, " %s", p); |
7804 | debug_printf_exec("set shell var:'%s'->'%s'\n", | 7796 | debug_printf_exec("set shell var:'%s'->'%s'\n", |
7805 | *argv, p); | 7797 | *argv, p); |
7806 | set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | 7798 | set_local_var(p, /*flag:*/ 0); |
7807 | /* Do we need to flag set_local_var() errors? | 7799 | /* Do we need to flag set_local_var() errors? |
7808 | * "assignment to readonly var" and "putenv error" | 7800 | * "assignment to readonly var" and "putenv error" |
7809 | */ | 7801 | */ |
@@ -8215,7 +8207,7 @@ static int run_list(struct pipe *pi) | |||
8215 | } | 8207 | } |
8216 | /* Insert next value from for_lcur */ | 8208 | /* Insert next value from for_lcur */ |
8217 | /* note: *for_lcur already has quotes removed, $var expanded, etc */ | 8209 | /* note: *for_lcur already has quotes removed, $var expanded, etc */ |
8218 | set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); | 8210 | set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*flag:*/ 0); |
8219 | continue; | 8211 | continue; |
8220 | } | 8212 | } |
8221 | if (rword == RES_IN) { | 8213 | if (rword == RES_IN) { |
@@ -8600,7 +8592,7 @@ int hush_main(int argc, char **argv) | |||
8600 | putenv(shell_ver->varstr); | 8592 | putenv(shell_ver->varstr); |
8601 | 8593 | ||
8602 | /* Export PWD */ | 8594 | /* Export PWD */ |
8603 | set_pwd_var(/*exp:*/ 1); | 8595 | set_pwd_var(SETFLAG_EXPORT); |
8604 | 8596 | ||
8605 | #if BASH_HOSTNAME_VAR | 8597 | #if BASH_HOSTNAME_VAR |
8606 | /* Set (but not export) HOSTNAME unless already set */ | 8598 | /* Set (but not export) HOSTNAME unless already set */ |
@@ -8770,7 +8762,7 @@ int hush_main(int argc, char **argv) | |||
8770 | } | 8762 | } |
8771 | case 'R': | 8763 | case 'R': |
8772 | case 'V': | 8764 | case 'V': |
8773 | set_local_var(xstrdup(optarg), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ opt == 'R'); | 8765 | set_local_var(xstrdup(optarg), opt == 'R' ? SETFLAG_MAKE_RO : 0); |
8774 | break; | 8766 | break; |
8775 | # if ENABLE_HUSH_FUNCTIONS | 8767 | # if ENABLE_HUSH_FUNCTIONS |
8776 | case 'F': { | 8768 | case 'F': { |
@@ -9073,7 +9065,7 @@ static int FAST_FUNC builtin_cd(char **argv) | |||
9073 | * Note: do not enforce exporting. If PWD was unset or unexported, | 9065 | * Note: do not enforce exporting. If PWD was unset or unexported, |
9074 | * set it again, but do not export. bash does the same. | 9066 | * set it again, but do not export. bash does the same. |
9075 | */ | 9067 | */ |
9076 | set_pwd_var(/*exp:*/ 0); | 9068 | set_pwd_var(/*flag:*/ 0); |
9077 | return EXIT_SUCCESS; | 9069 | return EXIT_SUCCESS; |
9078 | } | 9070 | } |
9079 | 9071 | ||
@@ -9312,10 +9304,7 @@ static void print_escaped(const char *s) | |||
9312 | #endif | 9304 | #endif |
9313 | 9305 | ||
9314 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY | 9306 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY |
9315 | static int helper_export_local(char **argv, | 9307 | static int helper_export_local(char **argv, unsigned flags) |
9316 | int exp UNUSED_PARAM, | ||
9317 | int ro UNUSED_PARAM, | ||
9318 | int lvl UNUSED_PARAM) | ||
9319 | { | 9308 | { |
9320 | do { | 9309 | do { |
9321 | char *name = *argv; | 9310 | char *name = *argv; |
@@ -9329,7 +9318,7 @@ static int helper_export_local(char **argv, | |||
9329 | vpp = get_ptr_to_local_var(name, name_end - name); | 9318 | vpp = get_ptr_to_local_var(name, name_end - name); |
9330 | var = vpp ? *vpp : NULL; | 9319 | var = vpp ? *vpp : NULL; |
9331 | 9320 | ||
9332 | if (exp == -1) { /* unexporting? */ | 9321 | if (flags & SETFLAG_UNEXPORT) { |
9333 | /* export -n NAME (without =VALUE) */ | 9322 | /* export -n NAME (without =VALUE) */ |
9334 | if (var) { | 9323 | if (var) { |
9335 | var->flg_export = 0; | 9324 | var->flg_export = 0; |
@@ -9338,7 +9327,7 @@ static int helper_export_local(char **argv, | |||
9338 | } /* else: export -n NOT_EXISTING_VAR: no-op */ | 9327 | } /* else: export -n NOT_EXISTING_VAR: no-op */ |
9339 | continue; | 9328 | continue; |
9340 | } | 9329 | } |
9341 | if (exp == 1) { /* exporting? */ | 9330 | if (flags & SETFLAG_EXPORT) { |
9342 | /* export NAME (without =VALUE) */ | 9331 | /* export NAME (without =VALUE) */ |
9343 | if (var) { | 9332 | if (var) { |
9344 | var->flg_export = 1; | 9333 | var->flg_export = 1; |
@@ -9349,9 +9338,8 @@ static int helper_export_local(char **argv, | |||
9349 | } | 9338 | } |
9350 | # if ENABLE_HUSH_LOCAL | 9339 | # if ENABLE_HUSH_LOCAL |
9351 | /* Is this "local" bltin? */ | 9340 | /* Is this "local" bltin? */ |
9352 | if (exp == 0 | 9341 | if (!(flags & (SETFLAG_EXPORT|SETFLAG_UNEXPORT|SETFLAG_MAKE_RO))) { |
9353 | IF_HUSH_READONLY(&& ro == 0) /* in !READONLY config, always true */ | 9342 | unsigned lvl = flags >> SETFLAG_LOCAL_SHIFT; |
9354 | ) { | ||
9355 | if (var && var->func_nest_level == lvl) { | 9343 | if (var && var->func_nest_level == lvl) { |
9356 | /* "local x=abc; ...; local x" - ignore second local decl */ | 9344 | /* "local x=abc; ...; local x" - ignore second local decl */ |
9357 | continue; | 9345 | continue; |
@@ -9376,7 +9364,7 @@ static int helper_export_local(char **argv, | |||
9376 | /* (Un)exporting/making local NAME=VALUE */ | 9364 | /* (Un)exporting/making local NAME=VALUE */ |
9377 | name = xstrdup(name); | 9365 | name = xstrdup(name); |
9378 | } | 9366 | } |
9379 | set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ ro); | 9367 | set_local_var(name, flags); |
9380 | } while (*++argv); | 9368 | } while (*++argv); |
9381 | return EXIT_SUCCESS; | 9369 | return EXIT_SUCCESS; |
9382 | } | 9370 | } |
@@ -9424,7 +9412,7 @@ static int FAST_FUNC builtin_export(char **argv) | |||
9424 | return EXIT_SUCCESS; | 9412 | return EXIT_SUCCESS; |
9425 | } | 9413 | } |
9426 | 9414 | ||
9427 | return helper_export_local(argv, /*exp:*/ (opt_unexport ? -1 : 1), /*ro:*/ 0, /*lvl:*/ 0); | 9415 | return helper_export_local(argv, opt_unexport ? SETFLAG_UNEXPORT : SETFLAG_EXPORT); |
9428 | } | 9416 | } |
9429 | #endif | 9417 | #endif |
9430 | 9418 | ||
@@ -9436,14 +9424,15 @@ static int FAST_FUNC builtin_local(char **argv) | |||
9436 | return EXIT_FAILURE; /* bash compat */ | 9424 | return EXIT_FAILURE; /* bash compat */ |
9437 | } | 9425 | } |
9438 | argv++; | 9426 | argv++; |
9439 | return helper_export_local(argv, /*exp:*/ 0, /*ro:*/ 0, /*lvl:*/ G.func_nest_level); | 9427 | return helper_export_local(argv, G.func_nest_level << SETFLAG_LOCAL_SHIFT); |
9440 | } | 9428 | } |
9441 | #endif | 9429 | #endif |
9442 | 9430 | ||
9443 | #if ENABLE_HUSH_READONLY | 9431 | #if ENABLE_HUSH_READONLY |
9444 | static int FAST_FUNC builtin_readonly(char **argv) | 9432 | static int FAST_FUNC builtin_readonly(char **argv) |
9445 | { | 9433 | { |
9446 | if (*++argv == NULL) { | 9434 | argv++; |
9435 | if (*argv == NULL) { | ||
9447 | /* bash: readonly [-p]: list all readonly VARs | 9436 | /* bash: readonly [-p]: list all readonly VARs |
9448 | * (-p has no effect in bash) | 9437 | * (-p has no effect in bash) |
9449 | */ | 9438 | */ |
@@ -9456,7 +9445,7 @@ static int FAST_FUNC builtin_readonly(char **argv) | |||
9456 | } | 9445 | } |
9457 | return EXIT_SUCCESS; | 9446 | return EXIT_SUCCESS; |
9458 | } | 9447 | } |
9459 | return helper_export_local(argv, /*exp:*/ 0, /*ro:*/ 1, /*lvl:*/ 0); | 9448 | return helper_export_local(argv, SETFLAG_MAKE_RO); |
9460 | } | 9449 | } |
9461 | #endif | 9450 | #endif |
9462 | 9451 | ||