static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN;
static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN;
static int run_pipe(struct pipe *pi);
-/* extended glob support: */
-static char **globhack(const char *src, char **strings);
-static int glob_needed(const char *s);
-static int xglob(o_string *dest, char ***pglob);
/* variable assignment: */
static int is_assignment(const char *s);
/* data structure manipulation: */
}
#endif
+#ifdef DEBUG_EXPAND
+static void debug_print_strings(const char *prefix, char **vv)
+{
+ fprintf(stderr, "%s:\n", prefix);
+ while (*vv)
+ fprintf(stderr, " '%s'\n", *vv++);
+}
+#else
+#define debug_print_strings(prefix, vv) ((void)0)
+#endif
+
/* Function prototypes for builtins */
static int builtin_cd(char **argv);
if (!pi->next->progs->argv)
continue;
/* create list of variable values */
+ debug_print_strings("for_list made from", pi->next->progs->argv);
for_list = expand_strvec_to_strvec(pi->next->progs->argv);
+ debug_print_strings("for_list", for_list);
for_lcur = for_list;
for_varname = pi->progs->argv[0];
pi->progs->argv[0] = NULL;
return rcode;
}
-/* The API for glob is arguably broken. This routine pushes a non-matching
- * string into the output structure, removing non-backslashed backslashes.
- * If someone can prove me wrong, by performing this function within the
- * original glob(3) api, feel free to rewrite this routine into oblivion.
+/* Remove non-backslashed backslashes and add to "strings" vector.
* XXX broken if the last character is '\\', check that before calling.
*/
-static char **globhack(const char *src, char **strings)
+static char **add_unq_string_to_strings(char **strings, const char *src)
{
int cnt;
const char *s;
return 0;
}
-static int xglob(o_string *dest, char ***pglob)
+static int xglob(char ***pglob, const char *pattern)
{
- /* short-circuit for null word */
- /* we can code this better when the debug_printf's are gone */
- if (dest->length == 0) {
- if (dest->nonnull) {
- /* bash man page calls this an "explicit" null */
- *pglob = globhack(dest->data, *pglob);
- }
- return 0;
- }
-
- if (glob_needed(dest->data)) {
+ if (glob_needed(pattern)) {
glob_t globdata;
int gr;
memset(&globdata, 0, sizeof(globdata));
- gr = glob(dest->data, 0, NULL, &globdata);
+ gr = glob(pattern, 0, NULL, &globdata);
debug_printf("glob returned %d\n", gr);
if (gr == GLOB_NOSPACE)
bb_error_msg_and_die("out of memory during glob");
if (gr == GLOB_NOMATCH) {
- debug_printf("globhack returned %d\n", gr);
- /* quote removal, or more accurately, backslash removal */
- *pglob = globhack(dest->data, *pglob);
globfree(&globdata);
- return 0;
+ goto literal;
}
if (gr != 0) { /* GLOB_ABORTED ? */
bb_error_msg("glob(3) error %d", gr);
return gr;
}
- *pglob = globhack(dest->data, *pglob);
+ literal:
+ /* quote removal, or more accurately, backslash removal */
+ *pglob = add_unq_string_to_strings(*pglob, pattern);
+ debug_print_strings("after xglob", *pglob);
return 0;
}
n = expand_vars_to_list(&output, n, *v++, or_mask);
o_debug_list("expand_variables", &output, n);
- /* output.data (malloced) gets returned in "list" */
+ /* output.data (malloced in one block) gets returned in "list" */
list = o_finalize_list(&output, n);
#ifdef DEBUG_EXPAND
static char **expand_strvec_to_strvec(char **argv)
{
- return expand_variables(argv, 0);
+ char **exp;
+ char **res = NULL;
+
+ debug_print_strings("expand_strvec_to_strvec: pre expand", argv);
+ exp = argv = expand_variables(argv, 0);
+ debug_print_strings("expand_strvec_to_strvec: post expand", argv);
+ while (*argv) {
+ int r = xglob(&res, *argv);
+ if (r)
+ bb_error_msg("xglob returned %d on '%s'", r, *argv);
+//TODO: testcase for bad glob pattern behavior
+ argv++;
+ }
+ free(exp);
+ debug_print_strings("expand_strvec_to_strvec: res", res);
+ return res;
}
+/* used for expansion of right hand of assignments */
+/* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs
+ * "v=/bin/c*" */
static char *expand_string_to_string(const char *str)
{
char *argv[2], **list;
return (char*)list;
}
+/* used for eval */
static char* expand_strvec_to_string(char **argv)
{
char **list;
{
struct child_prog *child = ctx->child;
char ***glob_target;
- int gr;
debug_printf_parse("done_word entered: '%s' %p\n", word->data, child);
if (word->length == 0 && !word->nonnull) {
}
glob_target = &child->argv;
}
-//BUG! globbing should be done after variable expansion!
-//See glob_and_vars testcase
- gr = xglob(word, glob_target);
- if (gr != 0) {
- debug_printf_parse("done_word return 1: xglob returned %d\n", gr);
- return 1;
+
+ if (word->length || word->nonnull) {
+ *glob_target = add_string_to_strings(*glob_target, xstrdup(word->data));
+ debug_print_strings("glob_target appended", *glob_target);
}
o_reset(word);
o_addQchr(dest, '\n');
eol_cnt--;
}
+ /* Even unquoted `echo '\'` results in two backslashes
+ * (which are converted into one by globbing later) */
+ if (!dest->o_quote && ch == '\\') {
+ o_addchr(dest, ch);
+ }
o_addQchr(dest, ch);
}
break;
if (ch == '\'')
break;
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
}
}
/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
if (ch == '"')
break;
if (ch == '\\') { /* \x. Copy both chars. */
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
ch = i_getch(input);
}
if (ch == EOF)
break;
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
if (ch == '`') {
add_till_backquote(dest, input);
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
continue;
}
//if (ch == '$') ...
if (ch == '\\') { /* \x. Copy both chars unless it is \` */
int ch2 = i_getch(input);
if (ch2 != '`' && ch2 != '$' && ch2 != '\\')
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
ch = ch2;
}
if (ch == EOF)
break;
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
}
}
/* Process $(cmd) - copy contents until ")" is seen. Complicated by
if (ch == ')')
if (--count < 0)
break;
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
if (ch == '\'') {
add_till_single_quote(dest, input);
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
continue;
}
if (ch == '"') {
add_till_double_quote(dest, input);
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
continue;
}
if (ch == '\\') { /* \x. Copy verbatim. Important for \(, \) */
ch = i_getch(input);
if (ch == EOF)
break;
- o_addqchr(dest, ch);
+ o_addchr(dest, ch);
continue;
}
}