This patch covers one big part of variable handling.

$ a=b foo
should be handled correctly.
$ a=b
is parsed OK, but the actual variable setting is not
yet written.  Except for some weird exceptions related
to quoting rules, this code passes (matches ash behavior)
all the tests I threw at it.

If someone now writes set_local_var(), and updates lookup_param()
to match, we can claim success!

       - Larry
This commit is contained in:
Eric Andersen 2001-05-15 16:30:25 +00:00
parent be9f44a7df
commit 78a7c99f7f
2 changed files with 98 additions and 10 deletions

54
hush.c
View File

@ -43,6 +43,7 @@
* Brace Expansion
* Tilde Expansion
* fancy forms of Parameter Expansion
* aliases
* Arithmetic Expansion
* <(list) and >(list) Process Substitution
* reserved words: case, esac, select, function
@ -54,15 +55,14 @@
* to-do:
* port selected bugfixes from post-0.49 busybox lash - done?
* finish implementing reserved words: for, while, until, do, done
* finish implementing local variable assignment
* change { and } from special chars to reserved words
* builtins: break, continue, eval, return, set, trap, ulimit
* test magic exec
* handle children going into background
* clean up recognition of null pipes
* have builtin_exec set flag to avoid restore_redirects
* check setting of global_argc and global_argv
* control-C handling, probably with longjmp
* VAR=value prefix for simple commands
* follow IFS rules more precisely, including update semantics
* figure out what to do with backslash-newline
* explain why we use signal instead of sigaction
@ -70,6 +70,7 @@
* continuation lines, both explicit and implicit - done?
* memory leak finding and plugging - done?
* more testing, especially quoting rules and redirection
* document how quoting rules not precisely followed for variable assignments
* maybe change map[] to use 2-bit entries
* (eventually) remove all the printf's
*
@ -359,6 +360,9 @@ static int run_pipe_real(struct pipe *pi);
static int globhack(const char *src, int flags, glob_t *pglob);
static int glob_needed(const char *s);
static int xglob(o_string *dest, int flags, glob_t *pglob);
/* variable assignment: */
static int set_local_var(const char *s);
static int is_assignment(const char *s);
/* data structure manipulation: */
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);
@ -1001,9 +1005,20 @@ static int pipe_wait(struct pipe *pi)
/* very simple version for testing */
static void pseudo_exec(struct child_prog *child)
{
int rcode;
int i, rcode;
struct built_in_command *x;
if (child->argv) {
for (i=0; is_assignment(child->argv[i]); i++) {
putenv(strdup(child->argv[i]));
}
child->argv+=i; /* XXX this hack isn't so horrible, since we are about
to exit, and therefore don't need to keep data
structures consistent for free() use. */
/* If a variable is assigned in a forest, and nobody listens,
* was it ever really set?
*/
if (child->argv[0] == NULL) exit(EXIT_SUCCESS);
/*
* Check if the command matches any of the builtins.
* Depending on context, this might be redundant. But it's
@ -1253,11 +1268,19 @@ static int run_pipe_real(struct pipe *pi)
restore_redirects(squirrel);
return rcode;
}
for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
if (i!=0 && child->argv[i]==NULL) {
/* assignments, but no command: set the local environment */
for (i=0; child->argv[i]!=NULL; i++) {
set_local_var(child->argv[i]);
}
return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
}
for (x = bltins; x->cmd; x++) {
if (strcmp(child->argv[0], x->cmd) == 0 ) {
if (strcmp(child->argv[i], x->cmd) == 0 ) {
int squirrel[] = {-1, -1, -1};
int rcode;
if (x->function == builtin_exec && child->argv[1]==NULL) {
if (x->function == builtin_exec && child->argv[i+1]==NULL) {
debug_printf("magic exec\n");
setup_redirects(child,NULL);
return EXIT_SUCCESS;
@ -1268,7 +1291,12 @@ static int run_pipe_real(struct pipe *pi)
* Is it really safe for inline use? Experimentally,
* things seem to work with glibc. */
setup_redirects(child, squirrel);
for (i=0; is_assignment(child->argv[i]); i++) {
putenv(strdup(child->argv[i]));
}
child->argv+=i; /* XXX horrible hack */
rcode = x->function(child);
child->argv-=i; /* XXX restore hack so free() can work right */
restore_redirects(squirrel);
return rcode;
}
@ -1581,6 +1609,22 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
return gr;
}
static int set_local_var(const char *s)
{
/* when you write this, also need to update lookup_param() */
printf("assignment %s not handled: write me!\n",s);
return 0;
}
static int is_assignment(const char *s)
{
if (s==NULL || !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
* for file descriptor duplication, e.g., "2>&1".
* Return code is 0 normally, 1 if a syntax error is detected in src.

View File

@ -43,6 +43,7 @@
* Brace Expansion
* Tilde Expansion
* fancy forms of Parameter Expansion
* aliases
* Arithmetic Expansion
* <(list) and >(list) Process Substitution
* reserved words: case, esac, select, function
@ -54,15 +55,14 @@
* to-do:
* port selected bugfixes from post-0.49 busybox lash - done?
* finish implementing reserved words: for, while, until, do, done
* finish implementing local variable assignment
* change { and } from special chars to reserved words
* builtins: break, continue, eval, return, set, trap, ulimit
* test magic exec
* handle children going into background
* clean up recognition of null pipes
* have builtin_exec set flag to avoid restore_redirects
* check setting of global_argc and global_argv
* control-C handling, probably with longjmp
* VAR=value prefix for simple commands
* follow IFS rules more precisely, including update semantics
* figure out what to do with backslash-newline
* explain why we use signal instead of sigaction
@ -70,6 +70,7 @@
* continuation lines, both explicit and implicit - done?
* memory leak finding and plugging - done?
* more testing, especially quoting rules and redirection
* document how quoting rules not precisely followed for variable assignments
* maybe change map[] to use 2-bit entries
* (eventually) remove all the printf's
*
@ -359,6 +360,9 @@ static int run_pipe_real(struct pipe *pi);
static int globhack(const char *src, int flags, glob_t *pglob);
static int glob_needed(const char *s);
static int xglob(o_string *dest, int flags, glob_t *pglob);
/* variable assignment: */
static int set_local_var(const char *s);
static int is_assignment(const char *s);
/* data structure manipulation: */
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);
@ -1001,9 +1005,20 @@ static int pipe_wait(struct pipe *pi)
/* very simple version for testing */
static void pseudo_exec(struct child_prog *child)
{
int rcode;
int i, rcode;
struct built_in_command *x;
if (child->argv) {
for (i=0; is_assignment(child->argv[i]); i++) {
putenv(strdup(child->argv[i]));
}
child->argv+=i; /* XXX this hack isn't so horrible, since we are about
to exit, and therefore don't need to keep data
structures consistent for free() use. */
/* If a variable is assigned in a forest, and nobody listens,
* was it ever really set?
*/
if (child->argv[0] == NULL) exit(EXIT_SUCCESS);
/*
* Check if the command matches any of the builtins.
* Depending on context, this might be redundant. But it's
@ -1253,11 +1268,19 @@ static int run_pipe_real(struct pipe *pi)
restore_redirects(squirrel);
return rcode;
}
for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
if (i!=0 && child->argv[i]==NULL) {
/* assignments, but no command: set the local environment */
for (i=0; child->argv[i]!=NULL; i++) {
set_local_var(child->argv[i]);
}
return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
}
for (x = bltins; x->cmd; x++) {
if (strcmp(child->argv[0], x->cmd) == 0 ) {
if (strcmp(child->argv[i], x->cmd) == 0 ) {
int squirrel[] = {-1, -1, -1};
int rcode;
if (x->function == builtin_exec && child->argv[1]==NULL) {
if (x->function == builtin_exec && child->argv[i+1]==NULL) {
debug_printf("magic exec\n");
setup_redirects(child,NULL);
return EXIT_SUCCESS;
@ -1268,7 +1291,12 @@ static int run_pipe_real(struct pipe *pi)
* Is it really safe for inline use? Experimentally,
* things seem to work with glibc. */
setup_redirects(child, squirrel);
for (i=0; is_assignment(child->argv[i]); i++) {
putenv(strdup(child->argv[i]));
}
child->argv+=i; /* XXX horrible hack */
rcode = x->function(child);
child->argv-=i; /* XXX restore hack so free() can work right */
restore_redirects(squirrel);
return rcode;
}
@ -1581,6 +1609,22 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
return gr;
}
static int set_local_var(const char *s)
{
/* when you write this, also need to update lookup_param() */
printf("assignment %s not handled: write me!\n",s);
return 0;
}
static int is_assignment(const char *s)
{
if (s==NULL || !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
* for file descriptor duplication, e.g., "2>&1".
* Return code is 0 normally, 1 if a syntax error is detected in src.