9
0
Fork 0

hush: remove quotes at end of processing

hush removes the quotes from strings too early. This leads to some bugs.
When hush executes

echo "hello sascha"

it correctly results in:

argv[0] = "echo"
argv[1] = "hello sascha"

However, the following behaves incorrect:

a="hello sascha"
echo "$a"

results in:

argv[0] = "echo"
argv[1] = "hello"
argv[2] = "sascha"

This is because hush removes the quotes and inserts variable values in a
single loop, so

echo "$a"

becomes:

echo hello sascha

after the loop.

Instead, keep the quotes until all variables are inserted and remove them
at the end.

This also fixes that echo \" resulted in \" instead of ".

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2012-04-29 14:11:38 +02:00
parent 37e77d3cfe
commit 1aad6d033a
1 changed files with 66 additions and 23 deletions

View File

@ -270,7 +270,6 @@ static void syntax_err(void) {
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);
/* in_str manipulations: */
static int static_get(struct in_str *i);
static int static_peek(struct in_str *i);
@ -356,22 +355,6 @@ static void b_free(o_string *o)
o->maxlen = 0;
}
/* My analysis of quoting semantics tells me that state information
* is associated with a destination, not a source.
*/
static int b_addqchr(o_string *o, int ch, int quote)
{
if (quote && strchr("*?[",ch)) {
int rc;
rc = b_addchr(o, '\\');
if (rc)
return rc;
}
return b_addchr(o, ch);
}
static int b_adduint(o_string *o, unsigned int i)
{
int r;
@ -565,6 +548,59 @@ out:
BAREBOX_MAGICVAR(OPTARG, "optarg for hush builtin getopt");
#endif
static void remove_quotes_in_str(char *src)
{
char *trg = src;
while (*src) {
if (*src == '\'') {
src++;
while (*src != '\'')
*trg++ = *src++;
src++;
continue;
}
/* drop quotes */
if (*src == '"') {
src++;
continue;
}
/* replace \" with " */
if (*src == '\\' && *(src + 1) == '"') {
*trg++ = '"';
src += 2;
continue;
}
/* replace \' with ' */
if (*src == '\\' && *(src + 1) == '\'') {
*trg++ = '\'';
src += 2;
continue;
}
/* replace \\ with \ */
if (*src == '\\' && *(src + 1) == '\\') {
*trg++ = '\\';
src += 2;
continue;
}
*trg++ = *src++;
}
*trg = 0;
}
static void remove_quotes(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
remove_quotes_in_str(argv[i]);
}
/* run_pipe_real() starts all the jobs, but doesn't wait for anything
* to finish. See checkjobs().
*
@ -670,6 +706,8 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
return last_return_code;
}
remove_quotes(child->argc - i, &child->argv[i]);
#ifdef CONFIG_HUSH_GETOPT
if (!strcmp(child->argv[i], "getopt"))
return builtin_getopt(ctx, child);
@ -1007,6 +1045,8 @@ static int set_local_var(const char *s, int flg_export)
}
*value++ = 0;
remove_quotes_in_str(value);
ret = setenv(name, value);
free(name);
@ -1347,7 +1387,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
b_addchr(dest, SPECIAL_VAR_SYMBOL);
break;
default:
b_addqchr(dest,'$',dest->quote);
b_addchr(dest, '$');
}
}
/* Eat the character if the flag was set. If the compiler
@ -1387,7 +1427,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
dest->quote, ctx->stack == NULL ? '*' : '.');
if (m == 0 || ((m == 1 || m == 2) && dest->quote)) {
b_addqchr(dest, ch, dest->quote);
b_addchr(dest, ch);
continue;
}
@ -1416,7 +1456,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
b_getch(input);
}
} else {
b_addqchr(dest, ch, dest->quote);
b_addchr(dest, ch);
}
break;
case '\\':
@ -1424,8 +1464,8 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
syntax();
return 1;
}
b_addqchr(dest, '\\', dest->quote);
b_addqchr(dest, b_getch(input), dest->quote);
b_addchr(dest, '\\');
b_addchr(dest, b_getch(input));
break;
case '$':
if (handle_dollar(dest, ctx, input)!=0)
@ -1433,11 +1473,13 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
break;
case '\'':
dest->nonnull = 1;
while (ch = b_getch(input), ch!=EOF && ch != '\'') {
b_addchr(dest, '\'');
while (ch = b_getch(input), ch != EOF && ch != '\'') {
if (input->__promptme == 0)
return 1;
b_addchr(dest,ch);
}
b_addchr(dest, '\'');
if (ch == EOF) {
syntax();
return 1;
@ -1445,6 +1487,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
break;
case '"':
dest->nonnull = 1;
b_addchr(dest, '"');
dest->quote = !dest->quote;
break;
case ';':