Add validator check to make sure the second argument to 'for' is 'in'

darcs-hash:20060521221604-ac50b-5bc4ce217a08304f68b97b20e908ea1279fe26e9.gz
This commit is contained in:
axel 2006-05-22 08:16:04 +10:00
parent 07e14ed7a8
commit b746a803a9
5 changed files with 70 additions and 27 deletions

View file

@ -2590,7 +2590,7 @@ static int builtin_for( wchar_t **argv )
else if (wcscmp( argv[2], L"in") != 0 ) else if (wcscmp( argv[2], L"in") != 0 )
{ {
sb_printf( sb_err, sb_printf( sb_err,
_( L"%ls: Second argument must be 'in'\n" ), BUILTIN_FOR_ERR_IN,
argv[0] ); argv[0] );
builtin_print_help( argv[0], sb_err ); builtin_print_help( argv[0], sb_err );
} }

View file

@ -57,6 +57,11 @@ enum
*/ */
#define BUILTIN_ERR_VARNAME_ZERO _( L"%ls: Variable name can not be the empty string\n" ) #define BUILTIN_ERR_VARNAME_ZERO _( L"%ls: Variable name can not be the empty string\n" )
/**
Error message when second argument to for isn't 'in'
*/
#define BUILTIN_FOR_ERR_IN _( L"%ls: Second argument must be 'in'\n" )
/** /**
Stringbuffer used to represent standard output Stringbuffer used to represent standard output
*/ */

View file

@ -96,15 +96,7 @@ parameter expansion.
*/ */
#define UNCLEAN L"$*?\\\"'({})" #define UNCLEAN L"$*?\\\"'({})"
/** int expand_is_clean( const wchar_t *in )
Test if the specified argument is clean, i.e. it does not contain
any tokens which need to be expanded or otherwise altered. Clean
strings can be passed through expand_string and expand_one without
changing them. About 90% of all strings are clean, so skipping
expansion on them actually does save a small amount of time, since
it avoids multiple memory allocations during the expansion process.
*/
static int is_clean( const wchar_t *in )
{ {
const wchar_t * str = in; const wchar_t * str = in;
@ -1372,7 +1364,6 @@ static void remove_internal_separator( const void *s, int conv )
*out=0; *out=0;
} }
/** /**
The real expansion function. expand_one is just a wrapper around this one. The real expansion function. expand_one is just a wrapper around this one.
*/ */
@ -1389,9 +1380,7 @@ int expand_string( void *context,
int res = EXPAND_OK; int res = EXPAND_OK;
int start_count = al_get_count( end_out ); int start_count = al_get_count( end_out );
// debug( 1, L"Expand %ls", str ); if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( str ) )
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( str ) )
{ {
halloc_register( context, str ); halloc_register( context, str );
al_push( end_out, str ); al_push( end_out, str );
@ -1637,7 +1626,7 @@ wchar_t *expand_one( void *context, wchar_t *string, int flags )
int res; int res;
wchar_t *one; wchar_t *one;
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( string ) ) if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( string ) )
{ {
halloc_register( context, string ); halloc_register( context, string );
return string; return string;

View file

@ -188,4 +188,15 @@ wchar_t *expand_tilde(wchar_t *in);
*/ */
void expand_variable_array( const wchar_t *val, array_list_t *out ); void expand_variable_array( const wchar_t *val, array_list_t *out );
/**
Test if the specified argument is clean, i.e. it does not contain
any tokens which need to be expanded or otherwise altered. Clean
strings can be passed through expand_string and expand_one without
changing them. About two thirds of all strings are clean, so
skipping expansion on them actually does save a small amount of
time, since it avoids multiple memory allocations during the
expansion process.
*/
int expand_is_clean( const wchar_t *in );
#endif #endif

View file

@ -2790,6 +2790,8 @@ int parser_test( const wchar_t * buff,
*/ */
int needs_cmd=0; int needs_cmd=0;
void *context = halloc( 0, 0 ); void *context = halloc( 0, 0 );
int arg_count=0;
wchar_t *cmd;
current_tokenizer = &tok; current_tokenizer = &tok;
@ -2808,10 +2810,11 @@ int parser_test( const wchar_t * buff,
{ {
int mark = tok_get_pos( &tok ); int mark = tok_get_pos( &tok );
had_cmd = 1; had_cmd = 1;
arg_count=0;
if( !expand_one( context, if( !(cmd = expand_one( context,
wcsdup( tok_last( &tok ) ), wcsdup( tok_last( &tok ) ),
EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES ) ) EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES ) ) )
{ {
err=1; err=1;
if( babble ) if( babble )
@ -2827,7 +2830,7 @@ int parser_test( const wchar_t * buff,
if( needs_cmd ) if( needs_cmd )
{ {
if( contains_str( tok_last(&tok), if( contains_str( cmd,
L"end", L"end",
0 ) ) 0 ) )
{ {
@ -2848,7 +2851,7 @@ int parser_test( const wchar_t * buff,
/* /*
Decrement block count on end command Decrement block count on end command
*/ */
if( wcscmp(tok_last(&tok), L"end")==0) if( wcscmp(cmd, L"end")==0)
{ {
tok_next( &tok ); tok_next( &tok );
count--; count--;
@ -2858,7 +2861,7 @@ int parser_test( const wchar_t * buff,
/* /*
Handle block commands Handle block commands
*/ */
if( parser_is_block( tok_last(&tok) ) ) if( parser_is_block( cmd ) )
{ {
if( count >= BLOCK_MAX_COUNT ) if( count >= BLOCK_MAX_COUNT )
{ {
@ -3041,7 +3044,42 @@ int parser_test( const wchar_t * buff,
} }
else else
{ {
err = parser_test_argument( tok_last( &tok ), babble ); err |= parser_test_argument( tok_last( &tok ), babble );
if( arg_count >= 0 && expand_is_clean( tok_last( &tok ) ) )
{
arg_count++;
}
else
{
arg_count = -1;
}
/*
Try to make sure the second argument to 'for' is 'in'
*/
if( wcscmp( cmd, L"for" ) == 0 )
{
if( arg_count == 2 )
{
if( wcscmp( tok_last( &tok ), L"in" ) != 0 )
{
err = 1;
if( babble )
{
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
BUILTIN_FOR_ERR_IN,
L"for" );
print_errors();
}
}
}
}
} }
break; break;