aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-13 18:34:53 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-13 18:34:53 +0000
commit602d13cba552fadb8481283aa7872a4b9f206c48 (patch)
tree224cc9027daa059db593e561526a8bb13f95de25
parent119b995437c52a164b2c5e51ef918c3f46b8a130 (diff)
downloadbusybox-602d13cba552fadb8481283aa7872a4b9f206c48.tar.gz
hush: fix '{ false; echo $?; }' bug.
hush: expand testsuite. variable expansion is still very broken
-rw-r--r--shell/hush.c204
-rw-r--r--shell/hush_test/hush-bugs/argv0.right1
-rwxr-xr-xshell/hush_test/hush-bugs/argv0.tests4
-rw-r--r--shell/hush_test/hush-bugs/quote1.right1
-rwxr-xr-xshell/hush_test/hush-bugs/quote1.tests2
-rw-r--r--shell/hush_test/hush-bugs/quote2.right1
-rwxr-xr-xshell/hush_test/hush-bugs/quote2.tests2
-rw-r--r--shell/hush_test/hush-bugs/starquoted.right1
-rwxr-xr-xshell/hush_test/hush-bugs/starquoted.tests4
-rw-r--r--shell/hush_test/hush-vars/star.right5
-rwxr-xr-xshell/hush_test/hush-vars/star.tests8
-rw-r--r--shell/hush_test/hush-vars/var.right2
-rwxr-xr-xshell/hush_test/hush-vars/var.tests1
13 files changed, 138 insertions, 98 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 04fb00dc7..dfb819122 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -371,7 +371,7 @@ static int b_check_space(o_string *o, int len);
static int b_addchr(o_string *o, int ch);
static void b_reset(o_string *o);
static int b_addqchr(o_string *o, int ch, int quote);
-static int b_adduint(o_string *o, unsigned i);
+//static int b_adduint(o_string *o, unsigned i);
/* in_str manipulations: */
static int static_get(struct in_str *i);
static int static_peek(struct in_str *i);
@@ -413,7 +413,7 @@ static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *inp
static const char *lookup_param(const char *src);
static char *make_string(char **inp);
static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
-static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
+//static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
/* setup: */
static int parse_stream_outer(struct in_str *inp, int parse_flag);
@@ -1015,17 +1015,17 @@ static int b_addqchr(o_string *o, int ch, int quote)
return b_addchr(o, ch);
}
-static int b_adduint(o_string *o, unsigned i)
-{
- int r;
- char buf[sizeof(unsigned)*3 + 1];
- char *p = buf;
- *(utoa_to_buf(i, buf, sizeof(buf))) = '\0';
- /* no escape checking necessary */
- do r = b_addchr(o, *p++); while (r == 0 && *p);
- return r;
-}
-
+//static int b_adduint(o_string *o, unsigned i)
+//{
+// int r;
+// char buf[sizeof(unsigned)*3 + 1];
+// char *p = buf;
+// *(utoa_to_buf(i, buf, sizeof(buf))) = '\0';
+// /* no escape checking necessary */
+// do r = b_addchr(o, *p++); while (r == 0 && *p);
+// return r;
+//}
+//
static int static_get(struct in_str *i)
{
int ch = *i->p++;
@@ -1288,9 +1288,7 @@ static void pseudo_exec_argv(char **argv)
getpid(), argv[i]);
// FIXME: vfork case??
p = insert_var_value(argv[i]);
- putenv(strdup(p));
- if (p != argv[i])
- free(p);
+ putenv(p == argv[i] ? xstrdup(p) : p);
}
argv += i;
/* If a variable is assigned in a forest, and nobody listens,
@@ -1699,10 +1697,11 @@ static int run_pipe_real(struct pipe *pi)
}
for (i = 0; is_assignment(argv[i]); i++) {
p = insert_var_value(argv[i]);
- putenv(strdup(p));
if (p != argv[i]) {
child->sp--;
- free(p);
+ putenv(p);
+ } else {
+ putenv(xstrdup(p));
}
}
if (child->sp) {
@@ -2292,39 +2291,42 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
static char **make_list_in(char **inp, char *name)
{
int len, i;
+#if 0
int name_len = strlen(name);
- int n = 0;
+#endif
+ int n;
char **list;
char *p1, *p2, *p3;
/* create list of variable values */
list = xmalloc(sizeof(*list));
+ n = 0;
for (i = 0; inp[i]; i++) {
p3 = insert_var_value(inp[i]);
p1 = p3;
while (*p1) {
- if ((*p1 == ' ')) {
+ if (*p1 == ' ') {
p1++;
continue;
}
- p2 = strchr(p1, ' ');
- if (p2) {
- len = p2 - p1;
- } else {
- len = strlen(p1);
- p2 = p1 + len;
- }
+ p2 = strchrnul(p1, ' ');
+ len = p2 - p1;
/* we use n + 2 in realloc for list, because we add
* new element and then we will add NULL element */
list = xrealloc(list, sizeof(*list) * (n + 2));
+ list[n] = xasprintf("%s=%.*s", name, len, p1);
+#if 0 /* faster, but more code */
list[n] = xmalloc(2 + name_len + len);
strcpy(list[n], name);
- strcat(list[n], "=");
- strncat(list[n], p1, len);
- list[n++][name_len + len + 1] = '\0';
+ list[n][name_len] = '=';
+ strncat(&(list[n][name_len + 1]), p1, len);
+ list[n][name_len + len + 1] = '\0';
+#endif
+ n++;
p1 = p2;
}
- if (p3 != inp[i]) free(p3);
+ if (p3 != inp[i])
+ free(p3);
}
list[n] = NULL;
return list;
@@ -2335,8 +2337,10 @@ static char *insert_var_value(char *inp)
int res_str_len = 0;
int len;
int done = 0;
- char *p, *res_str = NULL;
+ int i;
const char *p1;
+ char *p, *p2;
+ char *res_str = NULL;
while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
if (p != inp) {
@@ -2348,11 +2352,42 @@ static char *insert_var_value(char *inp)
inp = ++p;
p = strchr(inp, SPECIAL_VAR_SYMBOL);
*p = '\0';
- p1 = lookup_param(inp);
+
+ switch (inp[0]) {
+ case '$':
+ /* FIXME: (echo $$) should still print pid of main shell */
+ p1 = utoa(getpid());
+ break;
+ case '!':
+ p1 = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
+ break;
+ case '?':
+ p1 = utoa(last_return_code);
+ break;
+ case '#':
+ p1 = utoa(global_argc ? global_argc-1 : 0);
+ break;
+ case '*':
+ case '@': /* FIXME: we treat $@ as $* for now */
+ len = 1;
+ for (i = 1; i < global_argc; i++)
+ len += strlen(global_argv[i]) + 1;
+ p1 = p2 = alloca(--len);
+ for (i = 1; i < global_argc; i++) {
+ strcpy(p2, global_argv[i]);
+ p2 += strlen(global_argv[i]);
+ *p2++ = ifs[0];
+ }
+ *--p2 = '\0';
+ break;
+ default:
+ p1 = lookup_param(inp);
+ }
+
if (p1) {
len = res_str_len + strlen(p1);
- res_str = xrealloc(res_str, (1 + len));
- strcpy((res_str + res_str_len), p1);
+ res_str = xrealloc(res_str, 1 + len);
+ strcpy(res_str + res_str_len, p1);
res_str_len = len;
}
*p = SPECIAL_VAR_SYMBOL;
@@ -2956,21 +2991,20 @@ static char* make_string(char ** inp)
char *p;
char *str = NULL;
int n;
- int len = 2;
+ int val_len;
+ int len = 0;
for (n = 0; inp[n]; n++) {
p = insert_var_value(inp[n]);
- str = xrealloc(str, (len + strlen(p)));
- if (n) {
- strcat(str, " ");
- } else {
- *str = '\0';
- }
- strcat(str, p);
- len = strlen(str) + 3;
+ val_len = strlen(p);
+ str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/
+ str[len++] = ' ';
+ strcpy(str + len, p);
+ len += val_len;
if (p != inp[n]) free(p);
}
- len = strlen(str);
+ /* We do not check for case where loop had no iterations at all
+ * - cannot happen? */
str[len] = '\n';
str[len+1] = '\0';
return str;
@@ -2979,46 +3013,39 @@ static char* make_string(char ** inp)
/* return code: 0 for OK, 1 for syntax error */
static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
{
- int i, advance = 0;
- char sep[] = " ";
- int ch = input->peek(input); /* first character after the $ */
+// int i;
+// char sep[] = " ";
+ int ch = b_peek(input); /* first character after the $ */
debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
- if (isalpha(ch)) {
+ if (isalpha(ch) || ch == '?') {
b_addchr(dest, SPECIAL_VAR_SYMBOL);
ctx->child->sp++;
while (1) {
- ch = b_peek(input);
- if (!isalnum(ch) && ch != '_')
- break;
debug_printf_parse(": '%c'\n", ch);
b_getch(input);
b_addchr(dest, ch);
+ ch = b_peek(input);
+ if (!isalnum(ch) && ch != '_')
+ break;
}
b_addchr(dest, SPECIAL_VAR_SYMBOL);
} else if (isdigit(ch)) {
- i = ch - '0'; /* XXX is $0 special? */
- if (i < global_argc) {
- parse_string(dest, ctx, global_argv[i]); /* recursion */
- }
- advance = 1;
+ make_one_char_var:
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
+ ctx->child->sp++;
+ debug_printf_parse(": '%c'\n", ch);
+ b_getch(input);
+ b_addchr(dest, ch);
+ b_addchr(dest, SPECIAL_VAR_SYMBOL);
} else switch (ch) {
- case '$':
- b_adduint(dest, getpid());
- advance = 1;
- break;
- case '!':
- if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);
- advance = 1;
- break;
- case '?':
- b_adduint(dest, last_return_code);
- advance = 1;
- break;
- case '#':
- b_adduint(dest, global_argc ? global_argc-1 : 0);
- advance = 1;
- break;
+ case '$': /* pid */
+ case '!': /* last bg pid */
+ case '?': /* last exit code */
+ case '#': /* number of args */
+ case '*': /* args */
+ case '@': /* args */
+ goto make_one_char_var;
case '{':
b_addchr(dest, SPECIAL_VAR_SYMBOL);
ctx->child->sp++;
@@ -3042,15 +3069,6 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
b_getch(input);
process_command_subs(dest, ctx, input, ")");
break;
- case '*':
- sep[0] = ifs[0];
- for (i = 1; i < global_argc; i++) {
- parse_string(dest, ctx, global_argv[i]);
- if (i+1 < global_argc)
- parse_string(dest, ctx, sep);
- }
- break;
- case '@':
case '-':
case '_':
/* still unhandled, but should be eventually */
@@ -3058,25 +3076,19 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
return 1;
break;
default:
- b_addqchr(dest,'$', dest->quote);
+ b_addqchr(dest, '$', dest->quote);
}
- /* Eat the character if the flag was set. If the compiler
- * is smart enough, we could substitute "b_getch(input);"
- * for all the "advance = 1;" above, and also end up with
- * a nice size-optimized program. Hah! That'll be the day.
- */
- if (advance) b_getch(input);
debug_printf_parse("handle_dollar return 0\n");
return 0;
}
-static int parse_string(o_string *dest, struct p_context *ctx, const char *src)
-{
- struct in_str foo;
- setup_string_in_str(&foo, src);
- return parse_stream(dest, ctx, &foo, NULL);
-}
-
+//static int parse_string(o_string *dest, struct p_context *ctx, const char *src)
+//{
+// struct in_str foo;
+// setup_string_in_str(&foo, src);
+// return parse_stream(dest, ctx, &foo, NULL);
+//}
+//
/* return code is 0 for normal exit, 1 for syntax error */
static int parse_stream(o_string *dest, struct p_context *ctx,
struct in_str *input, const char *end_trigger)
diff --git a/shell/hush_test/hush-bugs/argv0.right b/shell/hush_test/hush-bugs/argv0.right
new file mode 100644
index 000000000..d86bac9de
--- /dev/null
+++ b/shell/hush_test/hush-bugs/argv0.right
@@ -0,0 +1 @@
+OK
diff --git a/shell/hush_test/hush-bugs/argv0.tests b/shell/hush_test/hush-bugs/argv0.tests
new file mode 100755
index 000000000..f5c40f6fe
--- /dev/null
+++ b/shell/hush_test/hush-bugs/argv0.tests
@@ -0,0 +1,4 @@
+if test $# = 0; then
+ exec "$THIS_SH" "$0" arg
+fi
+echo OK
diff --git a/shell/hush_test/hush-bugs/quote1.right b/shell/hush_test/hush-bugs/quote1.right
new file mode 100644
index 000000000..cb382054c
--- /dev/null
+++ b/shell/hush_test/hush-bugs/quote1.right
@@ -0,0 +1 @@
+'1'
diff --git a/shell/hush_test/hush-bugs/quote1.tests b/shell/hush_test/hush-bugs/quote1.tests
new file mode 100755
index 000000000..f55895466
--- /dev/null
+++ b/shell/hush_test/hush-bugs/quote1.tests
@@ -0,0 +1,2 @@
+a=1
+echo "'$a'"
diff --git a/shell/hush_test/hush-bugs/quote2.right b/shell/hush_test/hush-bugs/quote2.right
new file mode 100644
index 000000000..3bc9edcd6
--- /dev/null
+++ b/shell/hush_test/hush-bugs/quote2.right
@@ -0,0 +1 @@
+>1
diff --git a/shell/hush_test/hush-bugs/quote2.tests b/shell/hush_test/hush-bugs/quote2.tests
new file mode 100755
index 000000000..bd966f30b
--- /dev/null
+++ b/shell/hush_test/hush-bugs/quote2.tests
@@ -0,0 +1,2 @@
+a=1
+echo ">$a"
diff --git a/shell/hush_test/hush-bugs/starquoted.right b/shell/hush_test/hush-bugs/starquoted.right
new file mode 100644
index 000000000..fedaf4805
--- /dev/null
+++ b/shell/hush_test/hush-bugs/starquoted.right
@@ -0,0 +1 @@
+.1 abc d e f.
diff --git a/shell/hush_test/hush-bugs/starquoted.tests b/shell/hush_test/hush-bugs/starquoted.tests
new file mode 100755
index 000000000..3be2026b7
--- /dev/null
+++ b/shell/hush_test/hush-bugs/starquoted.tests
@@ -0,0 +1,4 @@
+if test $# = 0; then
+ exec "$THIS_SH" starquoted.tests 1 abc 'd e f'
+fi
+for a in "$*"; do echo ".$a."; done
diff --git a/shell/hush_test/hush-vars/star.right b/shell/hush_test/hush-vars/star.right
new file mode 100644
index 000000000..b33b176b2
--- /dev/null
+++ b/shell/hush_test/hush-vars/star.right
@@ -0,0 +1,5 @@
+.1.
+.abc.
+.d.
+.e.
+.f.
diff --git a/shell/hush_test/hush-vars/star.tests b/shell/hush_test/hush-vars/star.tests
new file mode 100755
index 000000000..1914dde44
--- /dev/null
+++ b/shell/hush_test/hush-vars/star.tests
@@ -0,0 +1,8 @@
+if test $# = 0; then
+ exec "$THIS_SH" star.tests 1 abc 'd e f'
+fi
+# 'd e f' should be split into 3 separate args:
+for a in $*; do echo ".$a."; done
+
+# must produce .1 abc d e f. Currently does not
+#for a in "$*"; do echo ".$a."; done
diff --git a/shell/hush_test/hush-vars/var.right b/shell/hush_test/hush-vars/var.right
index c13b98e38..14b2314d9 100644
--- a/shell/hush_test/hush-vars/var.right
+++ b/shell/hush_test/hush-vars/var.right
@@ -1,4 +1,4 @@
http://busybox.net
http://busybox.net_abc
1
-0
+1
diff --git a/shell/hush_test/hush-vars/var.tests b/shell/hush_test/hush-vars/var.tests
index b0637ea6b..0a63696c9 100755
--- a/shell/hush_test/hush-vars/var.tests
+++ b/shell/hush_test/hush-vars/var.tests
@@ -6,5 +6,4 @@ echo ${URL}_abc
true
false; echo $?
true
-# BUG: prints 0, must be 1
{ false; echo $?; }