Optionally add type of block to the end builtin to verify block nesting correctness

darcs-hash:20060905204347-ac50b-d0f87a700e38cdff9787be827b0df90b7f7baba5.gz
This commit is contained in:
axel 2006-09-06 06:43:47 +10:00
parent 697d524687
commit e356bdaa8e
4 changed files with 134 additions and 22 deletions

View file

@ -2519,6 +2519,37 @@ static int builtin_end( wchar_t **argv )
variables in the current loop scope won't die between laps.
*/
int kill_block = 1;
wchar_t *type = argv[1];
if( type )
{
int t = parser_get_block_type( type );
if( t != current_block->type )
{
if( t == -1 )
{
sb_printf( sb_err,
BUILTIN_END_BLOCK_UNKNOWN,
argv[0],
type,
parser_get_block_command( current_block->type ) );
}
else
{
sb_printf( sb_err,
BUILTIN_END_BLOCK_MISMATCH,
argv[0],
type,
parser_get_block_command( current_block->type ) );
}
builtin_print_help( argv[0], sb_err );
return 1;
}
}
switch( current_block->type )
{

View file

@ -67,6 +67,16 @@ enum
*/
#define BUILTIN_ERR_TOO_MANY_ARGUMENTS _( L"%ls: Too many arguments\n" )
/**
Error message when block types mismatch in the end builtin, e.g. 'begin; end for'
*/
#define BUILTIN_END_BLOCK_MISMATCH _( L"%ls: Block mismatch: '%ls' vs. '%ls'\n" )
/**
Error message for unknown block type in the end builtin, e.g. 'begin; end beggin'
*/
#define BUILTIN_END_BLOCK_UNKNOWN _( L"%ls: Unknown block type '%ls'\n" )
/**
Stringbuffer used to represent standard output
*/

112
parser.c
View file

@ -2260,30 +2260,45 @@ static int parse_job( process_t *p,
if( !make_sub_block )
{
tok_init( &subtok, end, 0 );
switch( tok_last_type( &subtok ) )
int done=0;
for( tok_init( &subtok, end, 0 );
!done && tok_has_next( &subtok );
tok_next( &subtok ) )
{
case TOK_END:
break;
case TOK_REDIRECT_OUT:
case TOK_REDIRECT_APPEND:
case TOK_REDIRECT_IN:
case TOK_REDIRECT_FD:
case TOK_PIPE:
switch( tok_last_type( &subtok ) )
{
make_sub_block = 1;
break;
}
default:
{
error( SYNTAX_ERROR,
current_tokenizer_pos,
BLOCK_END_ERR_MSG );
case TOK_END:
done = 1;
break;
case TOK_REDIRECT_OUT:
case TOK_REDIRECT_APPEND:
case TOK_REDIRECT_IN:
case TOK_REDIRECT_FD:
case TOK_PIPE:
{
done = 1;
make_sub_block = 1;
break;
}
case TOK_STRING:
{
break;
}
default:
{
done = 1;
error( SYNTAX_ERROR,
current_tokenizer_pos,
BLOCK_END_ERR_MSG );
}
}
}
tok_destroy( &subtok );
}
@ -2733,7 +2748,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
/**
\return the block type created by the specified builtin, or -1 on error.
*/
static int parser_get_block_type( const wchar_t *cmd )
int parser_get_block_type( const wchar_t *cmd )
{
int i;
@ -2750,7 +2765,7 @@ static int parser_get_block_type( const wchar_t *cmd )
/**
\return the block command that createa the specified block type, or null on error.
*/
static const wchar_t *parser_get_block_command( int type )
const wchar_t *parser_get_block_command( int type )
{
int i;
@ -3302,6 +3317,59 @@ int parser_test( const wchar_t * buff,
}
}
}
/*
Try to make sure that arguments passed to 'end' is always the type of block to close
*/
if( wcscmp( cmd, L"end" ) == 0 )
{
if( (arg_count == 1) /*&& (count > 0)*/ )
{
int t = parser_get_block_type( tok_last( &tok ) );
/*
This is ugly. We peek at the element
past the current element on the
block_type stack. It will always contain
the type of the block that just went out
of scope, which is what we need, but it
is not nice coding practice to search
through the 'junk pile' like that...
*/
if( t != block_type[count] )
{
err=1;
if( out )
{
if( t == -1 )
{
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
BUILTIN_END_BLOCK_UNKNOWN,
L"end",
tok_last( &tok ) );
}
else
{
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
BUILTIN_END_BLOCK_MISMATCH,
L"end",
tok_last( &tok ),
parser_get_block_command( block_type[count-1] ) );
}
print_errors( out, prefix );
}
}
}
}
}
break;

View file

@ -377,5 +377,8 @@ const wchar_t *parser_current_filename();
*/
void parser_stack_trace( block_t *b, string_buffer_t *buff);
int parser_get_block_type( const wchar_t *cmd );
const wchar_t *parser_get_block_command( int type );
#endif