hush: add testsuite for "no globbing in redirection" rule.
simplify redirection habdling
This commit is contained in:
parent
985de15bf3
commit
ab876cd107
63
shell/hush.c
63
shell/hush.c
@ -287,7 +287,7 @@ struct redir_struct {
|
|||||||
redir_type type; /* type of redirection */
|
redir_type type; /* type of redirection */
|
||||||
int fd; /* file descriptor being redirected */
|
int fd; /* file descriptor being redirected */
|
||||||
int dup; /* -1, or file descriptor being duplicated */
|
int dup; /* -1, or file descriptor being duplicated */
|
||||||
char **glob_word; /* *word.gl_pathv is the filename */
|
char *rd_filename; /* filename */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct child_prog {
|
struct child_prog {
|
||||||
@ -1304,14 +1304,14 @@ static int setup_redirects(struct child_prog *prog, int squirrel[])
|
|||||||
struct redir_struct *redir;
|
struct redir_struct *redir;
|
||||||
|
|
||||||
for (redir = prog->redirects; redir; redir = redir->next) {
|
for (redir = prog->redirects; redir; redir = redir->next) {
|
||||||
if (redir->dup == -1 && redir->glob_word == NULL) {
|
if (redir->dup == -1 && redir->rd_filename == NULL) {
|
||||||
/* something went wrong in the parse. Pretend it didn't happen */
|
/* something went wrong in the parse. Pretend it didn't happen */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (redir->dup == -1) {
|
if (redir->dup == -1) {
|
||||||
char *p;
|
char *p;
|
||||||
mode = redir_table[redir->type].mode;
|
mode = redir_table[redir->type].mode;
|
||||||
p = expand_string_to_string(redir->glob_word[0]);
|
p = expand_string_to_string(redir->rd_filename);
|
||||||
openfd = open_or_warn(p, mode);
|
openfd = open_or_warn(p, mode);
|
||||||
free(p);
|
free(p);
|
||||||
if (openfd < 0) {
|
if (openfd < 0) {
|
||||||
@ -2227,10 +2227,10 @@ static int free_pipe(struct pipe *pi, int indent)
|
|||||||
debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip);
|
debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip);
|
||||||
if (r->dup == -1) {
|
if (r->dup == -1) {
|
||||||
/* guard against the case >$FOO, where foo is unset or blank */
|
/* guard against the case >$FOO, where foo is unset or blank */
|
||||||
if (r->glob_word) {
|
if (r->rd_filename) {
|
||||||
debug_printf_clean(" %s\n", r->glob_word[0]);
|
debug_printf_clean(" %s\n", r->rd_filename);
|
||||||
free_strings(r->glob_word);
|
free(r->rd_filename);
|
||||||
r->glob_word = NULL;
|
r->rd_filename = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug_printf_clean("&%d\n", r->dup);
|
debug_printf_clean("&%d\n", r->dup);
|
||||||
@ -2680,7 +2680,7 @@ static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
|
|||||||
}
|
}
|
||||||
redir = xzalloc(sizeof(struct redir_struct));
|
redir = xzalloc(sizeof(struct redir_struct));
|
||||||
/* redir->next = NULL; */
|
/* redir->next = NULL; */
|
||||||
/* redir->glob_word = NULL; */
|
/* redir->rd_filename = NULL; */
|
||||||
if (last_redir) {
|
if (last_redir) {
|
||||||
last_redir->next = redir;
|
last_redir->next = redir;
|
||||||
} else {
|
} else {
|
||||||
@ -2857,17 +2857,17 @@ static int reserved_word(const o_string *word, struct p_context *ctx)
|
|||||||
static int done_word(o_string *word, struct p_context *ctx)
|
static int done_word(o_string *word, struct p_context *ctx)
|
||||||
{
|
{
|
||||||
struct child_prog *child = ctx->child;
|
struct child_prog *child = ctx->child;
|
||||||
char ***glob_target;
|
|
||||||
|
|
||||||
debug_printf_parse("done_word entered: '%s' %p\n", word->data, child);
|
debug_printf_parse("done_word entered: '%s' %p\n", word->data, child);
|
||||||
if (word->length == 0) {
|
if (word->length == 0 && word->nonnull == 0) {
|
||||||
if (!word->nonnull) {
|
|
||||||
debug_printf_parse("done_word return 0: true null, ignored\n");
|
debug_printf_parse("done_word return 0: true null, ignored\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (ctx->pending_redirect) {
|
if (ctx->pending_redirect) {
|
||||||
glob_target = &ctx->pending_redirect->glob_word;
|
/* We do not glob in e.g. >*.tmp case. bash seems to glob here
|
||||||
|
* only if run as "bash", not "sh" */
|
||||||
|
ctx->pending_redirect->rd_filename = xstrdup(word->data);
|
||||||
|
debug_printf("word stored in rd_filename: '%s'\n", word->data);
|
||||||
} else {
|
} else {
|
||||||
if (child->group) { /* TODO: example how to trigger? */
|
if (child->group) { /* TODO: example how to trigger? */
|
||||||
syntax(NULL);
|
syntax(NULL);
|
||||||
@ -2882,46 +2882,25 @@ static int done_word(o_string *word, struct p_context *ctx)
|
|||||||
return (ctx->res_w == RES_SNTX);
|
return (ctx->res_w == RES_SNTX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (word->nonnull) {
|
if (word->nonnull
|
||||||
|
/* && word->data[0] != */
|
||||||
|
) {
|
||||||
/* Insert "empty variable" reference, this makes e.g. "", '',
|
/* Insert "empty variable" reference, this makes e.g. "", '',
|
||||||
* $empty"" etc to not disappear */
|
* $empty"" etc to not disappear */
|
||||||
o_addchr(word, SPECIAL_VAR_SYMBOL);
|
o_addchr(word, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(word, SPECIAL_VAR_SYMBOL);
|
o_addchr(word, SPECIAL_VAR_SYMBOL);
|
||||||
}
|
}
|
||||||
glob_target = &child->argv;
|
child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data));
|
||||||
}
|
debug_print_strings("word appended to argv", child->argv);
|
||||||
|
|
||||||
//FIXME: we had globbing here, but now it's moved! Do we glob in e.g. ">*.tmp" now!?
|
|
||||||
|
|
||||||
/*if (word->length || word->nonnull) - true */ {
|
|
||||||
*glob_target = add_malloced_string_to_strings(*glob_target, xstrdup(word->data));
|
|
||||||
debug_print_strings("glob_target appended", *glob_target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o_reset(word);
|
o_reset(word);
|
||||||
if (ctx->pending_redirect) {
|
|
||||||
/* NB: don't free_strings(ctx->pending_redirect->glob_word) here */
|
|
||||||
if (ctx->pending_redirect->glob_word
|
|
||||||
&& ctx->pending_redirect->glob_word[0]
|
|
||||||
&& ctx->pending_redirect->glob_word[1]
|
|
||||||
) {
|
|
||||||
/* more than one word resulted from globbing redir */
|
|
||||||
ctx->pending_redirect = NULL;
|
ctx->pending_redirect = NULL;
|
||||||
bb_error_msg("ambiguous redirect");
|
|
||||||
debug_printf_parse("done_word return 1: ambiguous redirect\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
ctx->pending_redirect = NULL;
|
|
||||||
}
|
|
||||||
#if ENABLE_HUSH_LOOPS
|
#if ENABLE_HUSH_LOOPS
|
||||||
/* comment? is it forcing "for" to have just one word (variable name)? */
|
/* Force FOR to have just one word (variable name) */
|
||||||
if (ctx->res_w == RES_FOR) {
|
if (ctx->res_w == RES_FOR)
|
||||||
//TESTING
|
|
||||||
//looks like (word->length == 0 && !word->nonnull) is true here, always
|
|
||||||
//(due to o_reset). done_word would return at once. Why then?
|
|
||||||
// done_word(word, ctx);
|
|
||||||
done_pipe(ctx, PIPE_SEQ);
|
done_pipe(ctx, PIPE_SEQ);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
debug_printf_parse("done_word return 0\n");
|
debug_printf_parse("done_word return 0\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
2
shell/hush_test/hush-glob/glob_redir.right
Normal file
2
shell/hush_test/hush-glob/glob_redir.right
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
z.tmp:
|
||||||
|
?.tmp: TEST
|
9
shell/hush_test/hush-glob/glob_redir.tests
Executable file
9
shell/hush_test/hush-glob/glob_redir.tests
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
# Redirections are not globbed.
|
||||||
|
# bash:
|
||||||
|
# if run as "sh", they are not globbed, but
|
||||||
|
# if run as "bash", they are!
|
||||||
|
>z.tmp
|
||||||
|
echo TEST >?.tmp
|
||||||
|
echo 'z.tmp:' `cat 'z.tmp'`
|
||||||
|
echo '?.tmp:' `cat '?.tmp'`
|
||||||
|
rm 'z.tmp' '?.tmp'
|
23
shell/hush_test/hush-parsing/escape3.right
Normal file
23
shell/hush_test/hush-parsing/escape3.right
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
v: a \ b \\ c \\\ d \\\\ e
|
||||||
|
v: a \ b \\ c \\\ d \\\\ e
|
||||||
|
Unquoted:
|
||||||
|
.a.
|
||||||
|
.\.
|
||||||
|
.b.
|
||||||
|
.\\.
|
||||||
|
.c.
|
||||||
|
.\\\.
|
||||||
|
.d.
|
||||||
|
.\\\\.
|
||||||
|
.e.
|
||||||
|
Quoted:
|
||||||
|
.a.
|
||||||
|
.\.
|
||||||
|
.b.
|
||||||
|
.\\.
|
||||||
|
.c.
|
||||||
|
.\\\.
|
||||||
|
.d.
|
||||||
|
.\\\\.
|
||||||
|
.e.
|
||||||
|
done
|
8
shell/hush_test/hush-parsing/escape3.tests
Executable file
8
shell/hush_test/hush-parsing/escape3.tests
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
v='a \ b \\ c \\\ d \\\\ e'
|
||||||
|
echo v: $v
|
||||||
|
echo v: "$v"
|
||||||
|
echo Unquoted:
|
||||||
|
for a in $v; do echo .$a.; done
|
||||||
|
echo Quoted:
|
||||||
|
for a in $v; do echo ".$a."; done
|
||||||
|
echo done
|
3
shell/hush_test/hush-parsing/redir_space.right
Normal file
3
shell/hush_test/hush-parsing/redir_space.right
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
z1.tmp: 1
|
||||||
|
z2.tmp: 1
|
||||||
|
"z1.tmp z2.tmp": TEST 0
|
6
shell/hush_test/hush-parsing/redir_space.tests
Executable file
6
shell/hush_test/hush-parsing/redir_space.tests
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
v='z1.tmp z2.tmp'
|
||||||
|
echo TEST >$v
|
||||||
|
echo 'z1.tmp:' `cat 'z1.tmp' 2>/dev/null; echo $?`
|
||||||
|
echo 'z2.tmp:' `cat 'z2.tmp' 2>/dev/null; echo $?`
|
||||||
|
echo '"z1.tmp z2.tmp":' `cat 'z1.tmp z2.tmp' 2>/dev/null; echo $?`
|
||||||
|
rm z*.tmp
|
Loading…
x
Reference in New Issue
Block a user