From b746a803a947c1d130aa1f76125ee7d91dced9d5 Mon Sep 17 00:00:00 2001 From: axel Date: Mon, 22 May 2006 08:16:04 +1000 Subject: [PATCH] Add validator check to make sure the second argument to 'for' is 'in' darcs-hash:20060521221604-ac50b-5bc4ce217a08304f68b97b20e908ea1279fe26e9.gz --- builtin.c | 2 +- builtin.h | 5 +++++ expand.c | 21 +++++--------------- expand.h | 11 +++++++++++ parser.c | 58 +++++++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/builtin.c b/builtin.c index f4eb7db40..e5b3b4b10 100644 --- a/builtin.c +++ b/builtin.c @@ -2590,7 +2590,7 @@ static int builtin_for( wchar_t **argv ) else if (wcscmp( argv[2], L"in") != 0 ) { sb_printf( sb_err, - _( L"%ls: Second argument must be 'in'\n" ), + BUILTIN_FOR_ERR_IN, argv[0] ); builtin_print_help( argv[0], sb_err ); } diff --git a/builtin.h b/builtin.h index 02a0ddead..f00eecef5 100644 --- a/builtin.h +++ b/builtin.h @@ -57,6 +57,11 @@ enum */ #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 */ diff --git a/expand.c b/expand.c index a98a648a0..b6dcff827 100644 --- a/expand.c +++ b/expand.c @@ -96,15 +96,7 @@ parameter expansion. */ #define UNCLEAN L"$*?\\\"'({})" -/** - 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 ) +int expand_is_clean( const wchar_t *in ) { const wchar_t * str = in; @@ -204,7 +196,7 @@ wchar_t *expand_escape_variable( const wchar_t *in ) case 0: sb_append( &buff, L"''"); break; - + case 1: { wchar_t *el = (wchar_t *)al_get( &l, 0 ); @@ -1372,7 +1364,6 @@ static void remove_internal_separator( const void *s, int conv ) *out=0; } - /** 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 start_count = al_get_count( end_out ); -// debug( 1, L"Expand %ls", str ); - - if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( str ) ) + if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( str ) ) { halloc_register( context, str ); al_push( end_out, str ); @@ -1636,8 +1625,8 @@ wchar_t *expand_one( void *context, wchar_t *string, int flags ) array_list_t l; int res; wchar_t *one; - - if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( string ) ) + + if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( string ) ) { halloc_register( context, string ); return string; diff --git a/expand.h b/expand.h index b1df1c233..b6ebfc65b 100644 --- a/expand.h +++ b/expand.h @@ -188,4 +188,15 @@ wchar_t *expand_tilde(wchar_t *in); */ 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 diff --git a/parser.c b/parser.c index 337b0cde9..348e8bc57 100644 --- a/parser.c +++ b/parser.c @@ -2790,7 +2790,9 @@ int parser_test( const wchar_t * buff, */ int needs_cmd=0; void *context = halloc( 0, 0 ); - + int arg_count=0; + wchar_t *cmd; + current_tokenizer = &tok; for( tok_init( &tok, buff, 0 ); @@ -2808,10 +2810,11 @@ int parser_test( const wchar_t * buff, { int mark = tok_get_pos( &tok ); had_cmd = 1; - - if( !expand_one( context, - wcsdup( tok_last( &tok ) ), - EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES ) ) + arg_count=0; + + if( !(cmd = expand_one( context, + wcsdup( tok_last( &tok ) ), + EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES ) ) ) { err=1; if( babble ) @@ -2827,7 +2830,7 @@ int parser_test( const wchar_t * buff, if( needs_cmd ) { - if( contains_str( tok_last(&tok), + if( contains_str( cmd, L"end", 0 ) ) { @@ -2848,7 +2851,7 @@ int parser_test( const wchar_t * buff, /* Decrement block count on end command */ - if( wcscmp(tok_last(&tok), L"end")==0) + if( wcscmp(cmd, L"end")==0) { tok_next( &tok ); count--; @@ -2858,7 +2861,7 @@ int parser_test( const wchar_t * buff, /* Handle block commands */ - if( parser_is_block( tok_last(&tok) ) ) + if( parser_is_block( cmd ) ) { if( count >= BLOCK_MAX_COUNT ) { @@ -3041,7 +3044,42 @@ int parser_test( const wchar_t * buff, } 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; @@ -3217,7 +3255,7 @@ int parser_test( const wchar_t * buff, error_code=0; halloc_free( context ); - + return err | ((count!=0)<<1); }