hush: continue fixing quoting and subst: fix glob_and_assign.tests.
This commit is contained in:
parent
c7985b76c5
commit
30c9cc5b17
73
shell/hush.c
73
shell/hush.c
@ -106,6 +106,7 @@
|
|||||||
#define debug_printf_expand(...) do {} while (0)
|
#define debug_printf_expand(...) do {} while (0)
|
||||||
#define debug_printf_glob(...) do {} while (0)
|
#define debug_printf_glob(...) do {} while (0)
|
||||||
#define debug_printf_list(...) do {} while (0)
|
#define debug_printf_list(...) do {} while (0)
|
||||||
|
#define debug_printf_subst(...) do {} while (0)
|
||||||
#define debug_printf_clean(...) do {} while (0)
|
#define debug_printf_clean(...) do {} while (0)
|
||||||
|
|
||||||
#ifndef debug_printf
|
#ifndef debug_printf
|
||||||
@ -145,6 +146,10 @@
|
|||||||
#define debug_printf_list(...) fprintf(stderr, __VA_ARGS__)
|
#define debug_printf_list(...) fprintf(stderr, __VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef debug_printf_subst
|
||||||
|
#define debug_printf_subst(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Keep unconditionally on for now */
|
/* Keep unconditionally on for now */
|
||||||
#define ENABLE_HUSH_DEBUG 1
|
#define ENABLE_HUSH_DEBUG 1
|
||||||
|
|
||||||
@ -516,8 +521,6 @@ static int run_list(struct pipe *pi);
|
|||||||
static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN;
|
static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN;
|
||||||
static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN;
|
static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN;
|
||||||
static int run_pipe(struct pipe *pi);
|
static int run_pipe(struct pipe *pi);
|
||||||
/* variable assignment: */
|
|
||||||
static int is_assignment(const char *s);
|
|
||||||
/* data structure manipulation: */
|
/* data structure manipulation: */
|
||||||
static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
|
static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
|
||||||
static void initialize_context(struct p_context *ctx);
|
static void initialize_context(struct p_context *ctx);
|
||||||
@ -573,6 +576,16 @@ static int glob_needed(const char *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_assignment(const char *s)
|
||||||
|
{
|
||||||
|
if (!s || !isalpha(*s))
|
||||||
|
return 0;
|
||||||
|
s++;
|
||||||
|
while (isalnum(*s) || *s == '_')
|
||||||
|
s++;
|
||||||
|
return *s == '=';
|
||||||
|
}
|
||||||
|
|
||||||
static char **add_malloced_strings_to_strings(char **strings, char **add)
|
static char **add_malloced_strings_to_strings(char **strings, char **add)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -938,7 +951,7 @@ static void o_addQstr(o_string *o, const char *str, int len)
|
|||||||
if (ordinary_cnt == len)
|
if (ordinary_cnt == len)
|
||||||
return;
|
return;
|
||||||
str += ordinary_cnt;
|
str += ordinary_cnt;
|
||||||
len -= ordinary_cnt - 1; /* we are processing + 1 char below */
|
len -= ordinary_cnt + 1; /* we are processing + 1 char below */
|
||||||
|
|
||||||
ch = *str++;
|
ch = *str++;
|
||||||
sz = 1;
|
sz = 1;
|
||||||
@ -1000,7 +1013,7 @@ static int o_save_ptr_helper(o_string *o, int n)
|
|||||||
string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
|
string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
|
||||||
string_len = o->length - string_start;
|
string_len = o->length - string_start;
|
||||||
if (!(n & 0xf)) { /* 0, 0x10, 0x20...? */
|
if (!(n & 0xf)) { /* 0, 0x10, 0x20...? */
|
||||||
debug_printf_list("list[%d]=%d string_start=%d (growing)", n, string_len, string_start);
|
debug_printf_list("list[%d]=%d string_start=%d (growing)\n", n, string_len, string_start);
|
||||||
/* list[n] points to string_start, make space for 16 more pointers */
|
/* list[n] points to string_start, make space for 16 more pointers */
|
||||||
o->maxlen += 0x10 * sizeof(list[0]);
|
o->maxlen += 0x10 * sizeof(list[0]);
|
||||||
o->data = xrealloc(o->data, o->maxlen + 1);
|
o->data = xrealloc(o->data, o->maxlen + 1);
|
||||||
@ -1008,12 +1021,12 @@ static int o_save_ptr_helper(o_string *o, int n)
|
|||||||
memmove(list + n + 0x10, list + n, string_len);
|
memmove(list + n + 0x10, list + n, string_len);
|
||||||
o->length += 0x10 * sizeof(list[0]);
|
o->length += 0x10 * sizeof(list[0]);
|
||||||
} else
|
} else
|
||||||
debug_printf_list("list[%d]=%d string_start=%d", n, string_len, string_start);
|
debug_printf_list("list[%d]=%d string_start=%d\n", n, string_len, string_start);
|
||||||
} else {
|
} else {
|
||||||
/* We have empty slot at list[n], reuse without growth */
|
/* We have empty slot at list[n], reuse without growth */
|
||||||
string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */
|
string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */
|
||||||
string_len = o->length - string_start;
|
string_len = o->length - string_start;
|
||||||
debug_printf_list("list[%d]=%d string_start=%d (empty slot)", n, string_len, string_start);
|
debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n", n, string_len, string_start);
|
||||||
o->has_empty_slot = 0;
|
o->has_empty_slot = 0;
|
||||||
}
|
}
|
||||||
list[n] = (char*)string_len;
|
list[n] = (char*)string_len;
|
||||||
@ -1048,15 +1061,15 @@ static int o_glob(o_string *o, int n)
|
|||||||
int gr;
|
int gr;
|
||||||
char *pattern;
|
char *pattern;
|
||||||
|
|
||||||
debug_printf_glob("start o_glob: n:%d o->data:%p", n, o->data);
|
debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data);
|
||||||
if (!o->data)
|
if (!o->data)
|
||||||
return o_save_ptr_helper(o, n);
|
return o_save_ptr_helper(o, n);
|
||||||
pattern = o->data + o_get_last_ptr(o, n);
|
pattern = o->data + o_get_last_ptr(o, n);
|
||||||
debug_printf_glob("glob pattern '%s'", pattern);
|
debug_printf_glob("glob pattern '%s'\n", pattern);
|
||||||
if (!glob_needed(pattern)) {
|
if (!glob_needed(pattern)) {
|
||||||
literal:
|
literal:
|
||||||
o->length = unbackslash(pattern) - o->data;
|
o->length = unbackslash(pattern) - o->data;
|
||||||
debug_printf_glob("glob pattern '%s' is literal", pattern);
|
debug_printf_glob("glob pattern '%s' is literal\n", pattern);
|
||||||
return o_save_ptr_helper(o, n);
|
return o_save_ptr_helper(o, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,7 +1121,7 @@ static char **o_finalize_list(o_string *o, int n)
|
|||||||
n = o_save_ptr(o, n); /* force growth for list[n] if necessary */
|
n = o_save_ptr(o, n); /* force growth for list[n] if necessary */
|
||||||
if (DEBUG_EXPAND)
|
if (DEBUG_EXPAND)
|
||||||
debug_print_list("finalized", o, n);
|
debug_print_list("finalized", o, n);
|
||||||
debug_printf_expand("finalized n:%d", n);
|
debug_printf_expand("finalized n:%d\n", n);
|
||||||
list = (char**)o->data;
|
list = (char**)o->data;
|
||||||
string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
|
string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]);
|
||||||
list[--n] = NULL;
|
list[--n] = NULL;
|
||||||
@ -2285,7 +2298,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
|
|||||||
while (1) {
|
while (1) {
|
||||||
int word_len = strcspn(str, ifs);
|
int word_len = strcspn(str, ifs);
|
||||||
if (word_len) {
|
if (word_len) {
|
||||||
o_addQstr(output, str, word_len);
|
o_addstr(output, str, word_len);
|
||||||
str += word_len;
|
str += word_len;
|
||||||
}
|
}
|
||||||
if (!*str) /* EOL - do not finalize word */
|
if (!*str) /* EOL - do not finalize word */
|
||||||
@ -2328,7 +2341,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
o_string subst_result = NULL_O_STRING;
|
o_string subst_result = NULL_O_STRING;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
o_addQstr(output, arg, p - arg);
|
o_addstr(output, arg, p - arg);
|
||||||
debug_print_list("expand_vars_to_list[1]", output, n);
|
debug_print_list("expand_vars_to_list[1]", output, n);
|
||||||
arg = ++p;
|
arg = ++p;
|
||||||
p = strchr(p, SPECIAL_VAR_SYMBOL);
|
p = strchr(p, SPECIAL_VAR_SYMBOL);
|
||||||
@ -2374,7 +2387,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
* and in this case should treat it like '$*' - see 'else...' below */
|
* and in this case should treat it like '$*' - see 'else...' below */
|
||||||
if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
|
if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
|
||||||
while (1) {
|
while (1) {
|
||||||
o_addQstr(output, global_argv[i], strlen(global_argv[i]));
|
o_addQstr(output, global_argv[i], strlen(global_argv[i])); ///really Q?
|
||||||
if (++i >= global_argc)
|
if (++i >= global_argc)
|
||||||
break;
|
break;
|
||||||
o_addchr(output, '\0');
|
o_addchr(output, '\0');
|
||||||
@ -2383,7 +2396,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
}
|
}
|
||||||
} else { /* quoted $*: add as one word */
|
} else { /* quoted $*: add as one word */
|
||||||
while (1) {
|
while (1) {
|
||||||
o_addQstr(output, global_argv[i], strlen(global_argv[i]));
|
o_addQstr(output, global_argv[i], strlen(global_argv[i])); ///really Q?
|
||||||
if (!global_argv[++i])
|
if (!global_argv[++i])
|
||||||
break;
|
break;
|
||||||
if (ifs[0])
|
if (ifs[0])
|
||||||
@ -2397,10 +2410,10 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
*p = '\0';
|
*p = '\0';
|
||||||
arg++;
|
arg++;
|
||||||
//TODO: can we just stuff it into "output" directly?
|
//TODO: can we just stuff it into "output" directly?
|
||||||
//bb_error_msg("SUBST '%s' first_ch %x", arg, first_ch);
|
debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch);
|
||||||
setup_string_in_str(&input, arg);
|
setup_string_in_str(&input, arg);
|
||||||
process_command_subs(&subst_result, &input, NULL);
|
process_command_subs(&subst_result, &input, NULL);
|
||||||
//bb_error_msg("RES '%s'", subst_result.data);
|
debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
|
||||||
val = subst_result.data;
|
val = subst_result.data;
|
||||||
goto store_val;
|
goto store_val;
|
||||||
}
|
}
|
||||||
@ -2421,14 +2434,16 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
#endif
|
#endif
|
||||||
*p = SPECIAL_VAR_SYMBOL;
|
*p = SPECIAL_VAR_SYMBOL;
|
||||||
if (!(first_ch & 0x80)) { /* unquoted $VAR */
|
if (!(first_ch & 0x80)) { /* unquoted $VAR */
|
||||||
|
debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote);
|
||||||
if (val) {
|
if (val) {
|
||||||
n = expand_on_ifs(output, n, val);
|
n = expand_on_ifs(output, n, val);
|
||||||
val = NULL;
|
val = NULL;
|
||||||
}
|
}
|
||||||
} /* else: quoted $VAR, val will be appended below */
|
} else /* quoted $VAR, val will be appended below */
|
||||||
|
debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote);
|
||||||
}
|
}
|
||||||
if (val) {
|
if (val) {
|
||||||
o_addQstr(output, val, strlen(val));
|
o_addQstr(output, val, strlen(val)); ///maybe q?
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_HUSH_TICK
|
#if ENABLE_HUSH_TICK
|
||||||
@ -2439,7 +2454,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
|
|
||||||
if (arg[0]) {
|
if (arg[0]) {
|
||||||
debug_print_list("expand_vars_to_list[a]", output, n);
|
debug_print_list("expand_vars_to_list[a]", output, n);
|
||||||
o_addQstr(output, arg, strlen(arg) + 1);
|
/* this part is literal, and it was already pre-quoted
|
||||||
|
* if needed (much earlier), do not use o_addQstr here! */
|
||||||
|
o_addstr(output, arg, strlen(arg) + 1);
|
||||||
debug_print_list("expand_vars_to_list[b]", output, n);
|
debug_print_list("expand_vars_to_list[b]", output, n);
|
||||||
} else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
|
} else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
|
||||||
&& !(ored_ch & 0x80) /* and all vars were not quoted. */
|
&& !(ored_ch & 0x80) /* and all vars were not quoted. */
|
||||||
@ -2460,8 +2477,10 @@ static char **expand_variables(char **argv, int or_mask)
|
|||||||
char **v;
|
char **v;
|
||||||
o_string output = NULL_O_STRING;
|
o_string output = NULL_O_STRING;
|
||||||
|
|
||||||
if (or_mask & 0x100)
|
if (or_mask & 0x100) {
|
||||||
|
output.o_quote = 1;
|
||||||
output.o_glob = 1;
|
output.o_glob = 1;
|
||||||
|
}
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
v = argv;
|
v = argv;
|
||||||
@ -2637,16 +2656,6 @@ static void unset_local_var(const char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_assignment(const char *s)
|
|
||||||
{
|
|
||||||
if (!s || !isalpha(*s))
|
|
||||||
return 0;
|
|
||||||
s++;
|
|
||||||
while (isalnum(*s) || *s == '_')
|
|
||||||
s++;
|
|
||||||
return *s == '=';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the src parameter allows us to peek forward to a possible &n syntax
|
/* the src parameter allows us to peek forward to a possible &n syntax
|
||||||
* for file descriptor duplication, e.g., "2>&1".
|
* for file descriptor duplication, e.g., "2>&1".
|
||||||
* Return code is 0 normally, 1 if a syntax error is detected in src.
|
* Return code is 0 normally, 1 if a syntax error is detected in src.
|
||||||
@ -3341,7 +3350,7 @@ static int handle_dollar(o_string *dest, struct in_str *input)
|
|||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(dest, quote_mask | '`');
|
o_addchr(dest, quote_mask | '`');
|
||||||
add_till_closing_curly_brace(dest, input);
|
add_till_closing_curly_brace(dest, input);
|
||||||
//bb_error_msg("RES '%s'", dest->data + pos);
|
//debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3496,7 +3505,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
|
|||||||
o_addchr(dest, dest->o_quote ? 0x80 | '`' : '`');
|
o_addchr(dest, dest->o_quote ? 0x80 | '`' : '`');
|
||||||
add_till_backquote(dest, input);
|
add_till_backquote(dest, input);
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
//bb_error_msg("RES '%s'", dest->data + pos);
|
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,2 +1,6 @@
|
|||||||
ZVAR=z.map
|
ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
|
||||||
*.map
|
ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
|
||||||
|
*.tmp
|
||||||
|
ZVAR=z.tmp z.tmp
|
||||||
|
ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
|
||||||
|
ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
## # bash zbad2
|
>ZVAR=z.tmp
|
||||||
## ZVAR=z.map
|
>z.tmp
|
||||||
## *.map
|
ZVAR=*.tmp echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
|
||||||
## # hush zbad2
|
ZVAR=*.tmp /bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
|
||||||
## ZVAR=z.map
|
ZVAR=*.tmp
|
||||||
## z.map <====== !!!
|
|
||||||
|
|
||||||
## hush does globbing for "VAR=val" too!
|
|
||||||
## it should do it only for non-assignments.
|
|
||||||
## even if word looks like assignment, it can be non-assignment:
|
|
||||||
## ZVAR=*.map /bin/echo ZVAR=*.map
|
|
||||||
## ^dont_glob ^glob
|
|
||||||
|
|
||||||
>ZVAR=z.map
|
|
||||||
ZVAR=*.map /bin/echo ZVAR=*.map
|
|
||||||
ZVAR=*.map
|
|
||||||
echo "$ZVAR"
|
echo "$ZVAR"
|
||||||
rm ZVAR=z.map
|
echo $ZVAR
|
||||||
|
echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
|
||||||
|
/bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
|
||||||
|
rm ZVAR=z.tmp z.tmp
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
unset LANG LANGUAGE
|
||||||
|
unset LC_COLLATE
|
||||||
|
unset LC_CTYPE
|
||||||
|
unset LC_MONETARY
|
||||||
|
unset LC_MESSAGES
|
||||||
|
unset LC_NUMERIC
|
||||||
|
unset LC_TIME
|
||||||
|
unset LC_ALL
|
||||||
|
|
||||||
test -x hush || {
|
test -x hush || {
|
||||||
echo "No ./hush - creating a link to ../../busybox"
|
echo "No ./hush - creating a link to ../../busybox"
|
||||||
ln -s ../../busybox hush
|
ln -s ../../busybox hush
|
||||||
|
Loading…
x
Reference in New Issue
Block a user