diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-06-07 16:42:05 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-06-07 16:42:05 +0000 |
commit | 04407e522b43c37198c8a821723950470d0919f5 (patch) | |
tree | 26d6ed9beac36d72c4423ae6eddfdd7bf31a43c4 | |
parent | 4f3e24979bfa8f6a954d5222c7508545c42867e0 (diff) | |
download | busybox-w32-04407e522b43c37198c8a821723950470d0919f5.tar.gz busybox-w32-04407e522b43c37198c8a821723950470d0919f5.tar.bz2 busybox-w32-04407e522b43c37198c8a821723950470d0919f5.zip |
Another hush update from Larry:
Fixes the interaction between if/then/else/fi syntax and variables.
I planned to do it right from the beginning, but my implementation
was buggy. Also adds the relevant test cases. Also adds some old
Matt Kraai variable test cases that got left out somehow.
-rw-r--r-- | hush.c | 30 | ||||
-rw-r--r-- | shell/hush.c | 30 | ||||
-rw-r--r-- | tests/sh.testcases | 29 |
3 files changed, 61 insertions, 28 deletions
@@ -1326,19 +1326,18 @@ static int run_pipe_real(struct pipe *pi) | |||
1326 | * Builtins within pipes have to fork anyway, and are handled in | 1326 | * Builtins within pipes have to fork anyway, and are handled in |
1327 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. | 1327 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. |
1328 | */ | 1328 | */ |
1329 | if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { | 1329 | if (pi->num_progs == 1) child = & (pi->progs[0]); |
1330 | child = & (pi->progs[0]); | 1330 | if (pi->num_progs == 1 && child->group && child->subshell == 0) { |
1331 | if (child->group && ! child->subshell) { | 1331 | int squirrel[] = {-1, -1, -1}; |
1332 | int squirrel[] = {-1, -1, -1}; | 1332 | int rcode; |
1333 | int rcode; | 1333 | debug_printf("non-subshell grouping\n"); |
1334 | debug_printf("non-subshell grouping\n"); | 1334 | setup_redirects(child, squirrel); |
1335 | setup_redirects(child, squirrel); | 1335 | /* XXX could we merge code with following builtin case, |
1336 | /* XXX could we merge code with following builtin case, | 1336 | * by creating a pseudo builtin that calls run_list_real? */ |
1337 | * by creating a pseudo builtin that calls run_list_real? */ | 1337 | rcode = run_list_real(child->group); |
1338 | rcode = run_list_real(child->group); | 1338 | restore_redirects(squirrel); |
1339 | restore_redirects(squirrel); | 1339 | return rcode; |
1340 | return rcode; | 1340 | } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { |
1341 | } | ||
1342 | for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } | 1341 | for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } |
1343 | if (i!=0 && child->argv[i]==NULL) { | 1342 | if (i!=0 && child->argv[i]==NULL) { |
1344 | /* assignments, but no command: set the local environment */ | 1343 | /* assignments, but no command: set the local environment */ |
@@ -1352,7 +1351,8 @@ static int run_pipe_real(struct pipe *pi) | |||
1352 | * variable. */ | 1351 | * variable. */ |
1353 | int export_me=0; | 1352 | int export_me=0; |
1354 | char *name, *value; | 1353 | char *name, *value; |
1355 | name = strdup(child->argv[i]); | 1354 | name = xstrdup(child->argv[i]); |
1355 | debug_printf("Local environment set: %s\n", name); | ||
1356 | value = strchr(name, '='); | 1356 | value = strchr(name, '='); |
1357 | if (value) | 1357 | if (value) |
1358 | *value=0; | 1358 | *value=0; |
@@ -1478,6 +1478,7 @@ static int run_list_real(struct pipe *pi) | |||
1478 | if (rmode == RES_ELIF && !if_code) continue; | 1478 | if (rmode == RES_ELIF && !if_code) continue; |
1479 | if (pi->num_progs == 0) continue; | 1479 | if (pi->num_progs == 0) continue; |
1480 | rcode = run_pipe_real(pi); | 1480 | rcode = run_pipe_real(pi); |
1481 | debug_printf("run_pipe_real returned %d\n",rcode); | ||
1481 | if (rcode!=-1) { | 1482 | if (rcode!=-1) { |
1482 | /* We only ran a builtin: rcode was set by the return value | 1483 | /* We only ran a builtin: rcode was set by the return value |
1483 | * of run_pipe_real(), and we don't need to wait for anything. */ | 1484 | * of run_pipe_real(), and we don't need to wait for anything. */ |
@@ -1943,6 +1944,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
1943 | debug_printf("pop stack\n"); | 1944 | debug_printf("pop stack\n"); |
1944 | old = ctx->stack; | 1945 | old = ctx->stack; |
1945 | old->child->group = ctx->list_head; | 1946 | old->child->group = ctx->list_head; |
1947 | old->child->subshell = 0; | ||
1946 | *ctx = *old; /* physical copy */ | 1948 | *ctx = *old; /* physical copy */ |
1947 | free(old); | 1949 | free(old); |
1948 | } | 1950 | } |
diff --git a/shell/hush.c b/shell/hush.c index 126f9da89..3b1e53c82 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1326,19 +1326,18 @@ static int run_pipe_real(struct pipe *pi) | |||
1326 | * Builtins within pipes have to fork anyway, and are handled in | 1326 | * Builtins within pipes have to fork anyway, and are handled in |
1327 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. | 1327 | * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. |
1328 | */ | 1328 | */ |
1329 | if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { | 1329 | if (pi->num_progs == 1) child = & (pi->progs[0]); |
1330 | child = & (pi->progs[0]); | 1330 | if (pi->num_progs == 1 && child->group && child->subshell == 0) { |
1331 | if (child->group && ! child->subshell) { | 1331 | int squirrel[] = {-1, -1, -1}; |
1332 | int squirrel[] = {-1, -1, -1}; | 1332 | int rcode; |
1333 | int rcode; | 1333 | debug_printf("non-subshell grouping\n"); |
1334 | debug_printf("non-subshell grouping\n"); | 1334 | setup_redirects(child, squirrel); |
1335 | setup_redirects(child, squirrel); | 1335 | /* XXX could we merge code with following builtin case, |
1336 | /* XXX could we merge code with following builtin case, | 1336 | * by creating a pseudo builtin that calls run_list_real? */ |
1337 | * by creating a pseudo builtin that calls run_list_real? */ | 1337 | rcode = run_list_real(child->group); |
1338 | rcode = run_list_real(child->group); | 1338 | restore_redirects(squirrel); |
1339 | restore_redirects(squirrel); | 1339 | return rcode; |
1340 | return rcode; | 1340 | } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { |
1341 | } | ||
1342 | for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } | 1341 | for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } |
1343 | if (i!=0 && child->argv[i]==NULL) { | 1342 | if (i!=0 && child->argv[i]==NULL) { |
1344 | /* assignments, but no command: set the local environment */ | 1343 | /* assignments, but no command: set the local environment */ |
@@ -1352,7 +1351,8 @@ static int run_pipe_real(struct pipe *pi) | |||
1352 | * variable. */ | 1351 | * variable. */ |
1353 | int export_me=0; | 1352 | int export_me=0; |
1354 | char *name, *value; | 1353 | char *name, *value; |
1355 | name = strdup(child->argv[i]); | 1354 | name = xstrdup(child->argv[i]); |
1355 | debug_printf("Local environment set: %s\n", name); | ||
1356 | value = strchr(name, '='); | 1356 | value = strchr(name, '='); |
1357 | if (value) | 1357 | if (value) |
1358 | *value=0; | 1358 | *value=0; |
@@ -1478,6 +1478,7 @@ static int run_list_real(struct pipe *pi) | |||
1478 | if (rmode == RES_ELIF && !if_code) continue; | 1478 | if (rmode == RES_ELIF && !if_code) continue; |
1479 | if (pi->num_progs == 0) continue; | 1479 | if (pi->num_progs == 0) continue; |
1480 | rcode = run_pipe_real(pi); | 1480 | rcode = run_pipe_real(pi); |
1481 | debug_printf("run_pipe_real returned %d\n",rcode); | ||
1481 | if (rcode!=-1) { | 1482 | if (rcode!=-1) { |
1482 | /* We only ran a builtin: rcode was set by the return value | 1483 | /* We only ran a builtin: rcode was set by the return value |
1483 | * of run_pipe_real(), and we don't need to wait for anything. */ | 1484 | * of run_pipe_real(), and we don't need to wait for anything. */ |
@@ -1943,6 +1944,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |||
1943 | debug_printf("pop stack\n"); | 1944 | debug_printf("pop stack\n"); |
1944 | old = ctx->stack; | 1945 | old = ctx->stack; |
1945 | old->child->group = ctx->list_head; | 1946 | old->child->group = ctx->list_head; |
1947 | old->child->subshell = 0; | ||
1946 | *ctx = *old; /* physical copy */ | 1948 | *ctx = *old; /* physical copy */ |
1947 | free(old); | 1949 | free(old); |
1948 | } | 1950 | } |
diff --git a/tests/sh.testcases b/tests/sh.testcases index 88e709f87..e2a75873e 100644 --- a/tests/sh.testcases +++ b/tests/sh.testcases | |||
@@ -28,6 +28,35 @@ if false; then tr 'A-Z' 'a-z'; else echo bar4; fi <foo | |||
28 | if true || false; then echo foo; else echo bar5; fi | 28 | if true || false; then echo foo; else echo bar5; fi |
29 | if true && false; then echo bar6; else echo foo; fi | 29 | if true && false; then echo bar6; else echo foo; fi |
30 | 30 | ||
31 | # basic distinction between local and env variables | ||
32 | unset FOO | ||
33 | FOO=bar env | grep FOO | ||
34 | echo "but not here: $FOO" | ||
35 | FOO=bar | ||
36 | env | grep FOO | ||
37 | echo "yes, here: $FOO" | ||
38 | FOO= | ||
39 | echo a $FOO b | ||
40 | echo "a $FOO b" | ||
41 | |||
42 | # not quite so basic variables. Credit to Matt Kraai. | ||
43 | unset FOO | ||
44 | FOO=bar | ||
45 | export FOO | ||
46 | env | grep FOO | ||
47 | unset FOO | ||
48 | export FOO=bar | ||
49 | FOO=baz | ||
50 | env | grep FOO | ||
51 | |||
52 | # interaction between environment variables and if/then and subshells | ||
53 | FOO=default | ||
54 | if true; then FOO=new; fi | ||
55 | echo $FOO | ||
56 | FOO=default | ||
57 | (FOO=bogus) | ||
58 | echo $FOO | ||
59 | |||
31 | # make sure we can duplicate file descriptors properly | 60 | # make sure we can duplicate file descriptors properly |
32 | echo replacement >foo 2>&1 | 61 | echo replacement >foo 2>&1 |
33 | cat foo | 62 | cat foo |