david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[cmdline] Expand settings within each command-line token individually

Perform settings expansion after tokenisation, and only at the point
of executing each command.  This allows statements such as

   dhcp && echo ${net0/ip}

to work correctly.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2011-03-28 17:35:23 +01:00
parent 1f4c5f90c3
commit b5f5f735c1
1 changed files with 80 additions and 36 deletions

View File

@ -216,6 +216,45 @@ int shell_stopped ( int stop ) {
return stopped; return stopped;
} }
/**
* Expand settings within a token list
*
* @v argc Argument count
* @v tokens Token list
* @v argv Argument list to fill in
* @ret rc Return status code
*/
static int expand_tokens ( int argc, char **tokens, char **argv ) {
int i;
/* Expand each token in turn */
for ( i = 0 ; i < argc ; i++ ) {
argv[i] = expand_settings ( tokens[i] );
if ( ! argv[i] )
goto err_expand_settings;
}
return 0;
err_expand_settings:
assert ( argv[i] == NULL );
for ( ; i >= 0 ; i-- )
free ( argv[i] );
return -ENOMEM;
}
/**
* Free an expanded token list
*
* @v argv Argument list
*/
static void free_tokens ( char **argv ) {
/* Free each expanded argument */
while ( *argv )
free ( *(argv++) );
}
/** /**
* Execute command line * Execute command line
* *
@ -225,58 +264,63 @@ int shell_stopped ( int stop ) {
* Execute the named command and arguments. * Execute the named command and arguments.
*/ */
int system ( const char *command ) { int system ( const char *command ) {
int count = split_command ( ( char * ) command, NULL );
char *all_tokens[ count + 1 ];
int ( * process_next ) ( int rc ); int ( * process_next ) ( int rc );
char *expcmd; char *command_copy;
char **argv; char **tokens;
int argc; int argc;
int count;
int process; int process;
int rc = 0; int rc = 0;
/* Perform variable expansion */ /* Create modifiable copy of command */
expcmd = expand_settings ( command ); command_copy = strdup ( command );
if ( ! expcmd ) if ( ! command_copy )
return -ENOMEM; return -ENOMEM;
/* Count tokens */ /* Split command into tokens */
count = split_command ( expcmd, NULL ); split_command ( command_copy, all_tokens );
all_tokens[count] = NULL;
/* Create token array */ /* Process individual commands */
if ( count ) { process = 1;
char * tokens[count + 1]; for ( tokens = all_tokens ; ; tokens += ( argc + 1 ) ) {
split_command ( expcmd, tokens );
tokens[count] = NULL;
process = 1;
for ( argv = tokens ; ; argv += ( argc + 1 ) ) { /* Find command terminator */
argc = command_terminator ( tokens, &process_next );
/* Find command terminator */ /* Expand tokens and execute command */
argc = command_terminator ( argv, &process_next ); if ( process ) {
char *argv[ argc + 1 ];
/* Expand tokens */
if ( ( rc = expand_tokens ( argc, tokens, argv ) ) != 0)
break;
argv[argc] = NULL;
/* Execute command */ /* Execute command */
if ( process ) { rc = execv ( argv[0], argv );
argv[argc] = NULL;
rc = execv ( argv[0], argv );
}
/* Stop processing, if applicable */ /* Free tokens */
if ( shell_stopped ( SHELL_STOP_COMMAND ) ) free_tokens ( argv );
break;
/* Stop processing if we have reached the end
* of the command.
*/
if ( ! process_next )
break;
/* Determine whether or not to process next command */
process = process_next ( rc );
} }
/* Stop processing, if applicable */
if ( shell_stopped ( SHELL_STOP_COMMAND ) )
break;
/* Stop processing if we have reached the end of the
* command.
*/
if ( ! process_next )
break;
/* Determine whether or not to process next command */
process = process_next ( rc );
} }
/* Free expanded command */ /* Free modified copy of command */
free ( expcmd ); free ( command_copy );
return rc; return rc;
} }