diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2015-04-18 19:36:38 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-04-18 19:36:38 +0200 |
commit | 0a0acb55db8d7c4dec445573f1b0528d126b9e1f (patch) | |
tree | 6947e42871e5360c8ff07e57127e1f65cfc08e6e /shell | |
parent | 63f4d32c9859c1ed341debefddad4b9c0ae944cc (diff) | |
download | busybox-w32-0a0acb55db8d7c4dec445573f1b0528d126b9e1f.tar.gz busybox-w32-0a0acb55db8d7c4dec445573f1b0528d126b9e1f.tar.bz2 busybox-w32-0a0acb55db8d7c4dec445573f1b0528d126b9e1f.zip |
ash: fix handling of duplicate "local"
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 51 | ||||
-rw-r--r-- | shell/ash_test/ash-heredoc/heredoc1.right | 2 | ||||
-rw-r--r-- | shell/ash_test/ash-vars/var3.right | 5 | ||||
-rwxr-xr-x | shell/ash_test/ash-vars/var3.tests | 1 |
4 files changed, 42 insertions, 17 deletions
diff --git a/shell/ash.c b/shell/ash.c index b568013b4..697a64fea 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -2030,7 +2030,7 @@ varcmp(const char *p, const char *q) | |||
2030 | int c, d; | 2030 | int c, d; |
2031 | 2031 | ||
2032 | while ((c = *p) == (d = *q)) { | 2032 | while ((c = *p) == (d = *q)) { |
2033 | if (!c || c == '=') | 2033 | if (c == '\0' || c == '=') |
2034 | goto out; | 2034 | goto out; |
2035 | p++; | 2035 | p++; |
2036 | q++; | 2036 | q++; |
@@ -2247,7 +2247,7 @@ setvar(const char *name, const char *val, int flags) | |||
2247 | } | 2247 | } |
2248 | 2248 | ||
2249 | static void FAST_FUNC | 2249 | static void FAST_FUNC |
2250 | setvar2(const char *name, const char *val) | 2250 | setvar0(const char *name, const char *val) |
2251 | { | 2251 | { |
2252 | setvar(name, val, 0); | 2252 | setvar(name, val, 0); |
2253 | } | 2253 | } |
@@ -2310,7 +2310,7 @@ unsetvar(const char *s) | |||
2310 | free(vp); | 2310 | free(vp); |
2311 | INT_ON; | 2311 | INT_ON; |
2312 | } else { | 2312 | } else { |
2313 | setvar2(s, 0); | 2313 | setvar0(s, NULL); |
2314 | vp->flags &= ~VEXPORT; | 2314 | vp->flags &= ~VEXPORT; |
2315 | } | 2315 | } |
2316 | ok: | 2316 | ok: |
@@ -5505,7 +5505,7 @@ ash_arith(const char *s) | |||
5505 | arith_t result; | 5505 | arith_t result; |
5506 | 5506 | ||
5507 | math_state.lookupvar = lookupvar; | 5507 | math_state.lookupvar = lookupvar; |
5508 | math_state.setvar = setvar2; | 5508 | math_state.setvar = setvar0; |
5509 | //math_state.endofname = endofname; | 5509 | //math_state.endofname = endofname; |
5510 | 5510 | ||
5511 | INT_OFF; | 5511 | INT_OFF; |
@@ -6360,7 +6360,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6360 | 6360 | ||
6361 | switch (subtype) { | 6361 | switch (subtype) { |
6362 | case VSASSIGN: | 6362 | case VSASSIGN: |
6363 | setvar2(varname, startp); | 6363 | setvar0(varname, startp); |
6364 | amount = startp - expdest; | 6364 | amount = startp - expdest; |
6365 | STADJUST(amount, expdest); | 6365 | STADJUST(amount, expdest); |
6366 | return startp; | 6366 | return startp; |
@@ -8591,7 +8591,7 @@ evalfor(union node *n, int flags) | |||
8591 | loopnest++; | 8591 | loopnest++; |
8592 | flags &= EV_TESTED; | 8592 | flags &= EV_TESTED; |
8593 | for (sp = arglist.list; sp; sp = sp->next) { | 8593 | for (sp = arglist.list; sp; sp = sp->next) { |
8594 | setvar2(n->nfor.var, sp->text); | 8594 | setvar0(n->nfor.var, sp->text); |
8595 | evaltree(n->nfor.body, flags); | 8595 | evaltree(n->nfor.body, flags); |
8596 | if (evalskip) { | 8596 | if (evalskip) { |
8597 | if (evalskip == SKIPCONT && --skipcount <= 0) { | 8597 | if (evalskip == SKIPCONT && --skipcount <= 0) { |
@@ -8970,21 +8970,37 @@ mklocal(char *name) | |||
8970 | struct localvar *lvp; | 8970 | struct localvar *lvp; |
8971 | struct var **vpp; | 8971 | struct var **vpp; |
8972 | struct var *vp; | 8972 | struct var *vp; |
8973 | char *eq = strchr(name, '='); | ||
8973 | 8974 | ||
8974 | INT_OFF; | 8975 | INT_OFF; |
8975 | lvp = ckzalloc(sizeof(struct localvar)); | 8976 | /* Cater for duplicate "local". Examples: |
8977 | * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x | ||
8978 | * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x | ||
8979 | */ | ||
8980 | lvp = localvars; | ||
8981 | while (lvp) { | ||
8982 | if (varcmp(lvp->vp->var_text, name) == 0) { | ||
8983 | if (eq) | ||
8984 | setvareq(name, 0); | ||
8985 | /* else: | ||
8986 | * it's a duplicate "local VAR" declaration, do nothing | ||
8987 | */ | ||
8988 | return; | ||
8989 | } | ||
8990 | lvp = lvp->next; | ||
8991 | } | ||
8992 | |||
8993 | lvp = ckzalloc(sizeof(*lvp)); | ||
8976 | if (LONE_DASH(name)) { | 8994 | if (LONE_DASH(name)) { |
8977 | char *p; | 8995 | char *p; |
8978 | p = ckmalloc(sizeof(optlist)); | 8996 | p = ckmalloc(sizeof(optlist)); |
8979 | lvp->text = memcpy(p, optlist, sizeof(optlist)); | 8997 | lvp->text = memcpy(p, optlist, sizeof(optlist)); |
8980 | vp = NULL; | 8998 | vp = NULL; |
8981 | } else { | 8999 | } else { |
8982 | char *eq; | ||
8983 | |||
8984 | vpp = hashvar(name); | 9000 | vpp = hashvar(name); |
8985 | vp = *findvar(vpp, name); | 9001 | vp = *findvar(vpp, name); |
8986 | eq = strchr(name, '='); | ||
8987 | if (vp == NULL) { | 9002 | if (vp == NULL) { |
9003 | /* variable did not exist yet */ | ||
8988 | if (eq) | 9004 | if (eq) |
8989 | setvareq(name, VSTRFIXED); | 9005 | setvareq(name, VSTRFIXED); |
8990 | else | 9006 | else |
@@ -8994,12 +9010,15 @@ mklocal(char *name) | |||
8994 | } else { | 9010 | } else { |
8995 | lvp->text = vp->var_text; | 9011 | lvp->text = vp->var_text; |
8996 | lvp->flags = vp->flags; | 9012 | lvp->flags = vp->flags; |
9013 | /* make sure neither "struct var" nor string gets freed | ||
9014 | * during (un)setting: | ||
9015 | */ | ||
8997 | vp->flags |= VSTRFIXED|VTEXTFIXED; | 9016 | vp->flags |= VSTRFIXED|VTEXTFIXED; |
8998 | if (eq) | 9017 | if (eq) |
8999 | setvareq(name, 0); | 9018 | setvareq(name, 0); |
9000 | else | 9019 | else |
9001 | /* "local VAR" unsets VAR: */ | 9020 | /* "local VAR" unsets VAR: */ |
9002 | setvar(name, NULL, 0); | 9021 | setvar0(name, NULL); |
9003 | } | 9022 | } |
9004 | } | 9023 | } |
9005 | lvp->vp = vp; | 9024 | lvp->vp = vp; |
@@ -9491,7 +9510,7 @@ evalcommand(union node *cmd, int flags) | |||
9491 | * '_' in 'vi' command mode during line editing... | 9510 | * '_' in 'vi' command mode during line editing... |
9492 | * However I implemented that within libedit itself. | 9511 | * However I implemented that within libedit itself. |
9493 | */ | 9512 | */ |
9494 | setvar2("_", lastarg); | 9513 | setvar0("_", lastarg); |
9495 | } | 9514 | } |
9496 | popstackmark(&smark); | 9515 | popstackmark(&smark); |
9497 | } | 9516 | } |
@@ -12885,7 +12904,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12885 | * to jump out of it. | 12904 | * to jump out of it. |
12886 | */ | 12905 | */ |
12887 | INT_OFF; | 12906 | INT_OFF; |
12888 | r = shell_builtin_read(setvar2, | 12907 | r = shell_builtin_read(setvar0, |
12889 | argptr, | 12908 | argptr, |
12890 | bltinlookup("IFS"), /* can be NULL */ | 12909 | bltinlookup("IFS"), /* can be NULL */ |
12891 | read_flags, | 12910 | read_flags, |
@@ -13046,14 +13065,14 @@ init(void) | |||
13046 | } | 13065 | } |
13047 | } | 13066 | } |
13048 | 13067 | ||
13049 | setvar2("PPID", utoa(getppid())); | 13068 | setvar0("PPID", utoa(getppid())); |
13050 | #if ENABLE_ASH_BASH_COMPAT | 13069 | #if ENABLE_ASH_BASH_COMPAT |
13051 | p = lookupvar("SHLVL"); | 13070 | p = lookupvar("SHLVL"); |
13052 | setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); | 13071 | setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); |
13053 | if (!lookupvar("HOSTNAME")) { | 13072 | if (!lookupvar("HOSTNAME")) { |
13054 | struct utsname uts; | 13073 | struct utsname uts; |
13055 | uname(&uts); | 13074 | uname(&uts); |
13056 | setvar2("HOSTNAME", uts.nodename); | 13075 | setvar0("HOSTNAME", uts.nodename); |
13057 | } | 13076 | } |
13058 | #endif | 13077 | #endif |
13059 | p = lookupvar("PWD"); | 13078 | p = lookupvar("PWD"); |
@@ -13309,7 +13328,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13309 | hp = lookupvar("HOME"); | 13328 | hp = lookupvar("HOME"); |
13310 | if (hp) { | 13329 | if (hp) { |
13311 | hp = concat_path_file(hp, ".ash_history"); | 13330 | hp = concat_path_file(hp, ".ash_history"); |
13312 | setvar2("HISTFILE", hp); | 13331 | setvar0("HISTFILE", hp); |
13313 | free((char*)hp); | 13332 | free((char*)hp); |
13314 | hp = lookupvar("HISTFILE"); | 13333 | hp = lookupvar("HISTFILE"); |
13315 | } | 13334 | } |
diff --git a/shell/ash_test/ash-heredoc/heredoc1.right b/shell/ash_test/ash-heredoc/heredoc1.right index 895f5ee80..40aa5a5fe 100644 --- a/shell/ash_test/ash-heredoc/heredoc1.right +++ b/shell/ash_test/ash-heredoc/heredoc1.right | |||
@@ -1 +1 @@ | |||
heredoc1.tests: line 3: syntax error: unexpected "then" | ./heredoc1.tests: line 3: syntax error: unexpected "then" | ||
diff --git a/shell/ash_test/ash-vars/var3.right b/shell/ash_test/ash-vars/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/ash_test/ash-vars/var3.right | |||
@@ -0,0 +1,5 @@ | |||
1 | 1 | ||
2 | 1 | ||
3 | |||
4 | |||
5 | 0 | ||
diff --git a/shell/ash_test/ash-vars/var3.tests b/shell/ash_test/ash-vars/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/ash_test/ash-vars/var3.tests | |||
@@ -0,0 +1 @@ | |||
x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x | |||