aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2015-04-18 19:36:38 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2015-04-18 19:36:38 +0200
commit0a0acb55db8d7c4dec445573f1b0528d126b9e1f (patch)
tree6947e42871e5360c8ff07e57127e1f65cfc08e6e /shell
parent63f4d32c9859c1ed341debefddad4b9c0ae944cc (diff)
downloadbusybox-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.c51
-rw-r--r--shell/ash_test/ash-heredoc/heredoc1.right2
-rw-r--r--shell/ash_test/ash-vars/var3.right5
-rwxr-xr-xshell/ash_test/ash-vars/var3.tests1
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
2249static void FAST_FUNC 2249static void FAST_FUNC
2250setvar2(const char *name, const char *val) 2250setvar0(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 @@
11
21
3
4
50
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