diff options
author | Łukasz Niemier <lukasz@niemier.pl> | 2012-11-18 11:23:22 +0100 |
---|---|---|
committer | Łukasz Niemier <lukasz@niemier.pl> | 2012-11-18 11:23:22 +0100 |
commit | 47df1ae40adecd0a02fc7dd06ab0745cb18c3fe0 (patch) | |
tree | 13bf3e8fdcae60fdfb5fa5e26c95818dc7a49790 /parser.cpp | |
parent | b79854ad1aa814d9d35d76a1929b4726fa4bffa5 (diff) |
Remove trailing whitespaces and change tabs to spaces
Diffstat (limited to 'parser.cpp')
-rw-r--r-- | parser.cpp | 5520 |
1 files changed, 2760 insertions, 2760 deletions
@@ -191,7 +191,7 @@ The fish parser. Contains functions for parsing and evaluating code. /** While block description -*/ +*/ #define WHILE_BLOCK N_( L"'while' block" ) /** @@ -199,10 +199,10 @@ The fish parser. Contains functions for parsing and evaluating code. */ #define FOR_BLOCK N_( L"'for' block" ) -/** - Breakpoint block +/** + Breakpoint block */ -#define BREAKPOINT_BLOCK N_( L"Block created by breakpoint" ) +#define BREAKPOINT_BLOCK N_( L"Block created by breakpoint" ) @@ -282,87 +282,87 @@ The fish parser. Contains functions for parsing and evaluating code. struct block_lookup_entry { - /** - The block type id. The legal values are defined in parser.h. - */ - block_type_t type; - - /** - The name of the builtin that creates this type of block, if any. - */ - const wchar_t *name; - - /** - A description of this block type - */ - const wchar_t *desc; + /** + The block type id. The legal values are defined in parser.h. + */ + block_type_t type; + + /** + The name of the builtin that creates this type of block, if any. + */ + const wchar_t *name; + + /** + A description of this block type + */ + const wchar_t *desc; } - ; + ; /** List of all legal block types */ static const struct block_lookup_entry block_lookup[]= { - { - WHILE, L"while", WHILE_BLOCK - } - , - { - FOR, L"for", FOR_BLOCK - } - , - { - IF, L"if", IF_BLOCK - } - , - { - FUNCTION_DEF, L"function", FUNCTION_DEF_BLOCK - } - , - { - FUNCTION_CALL, 0, FUNCTION_CALL_BLOCK - } - , - { - FUNCTION_CALL_NO_SHADOW, 0, FUNCTION_CALL_NO_SHADOW_BLOCK - } - , - { - SWITCH, L"switch", SWITCH_BLOCK - } - , - { - FAKE, 0, FAKE_BLOCK - } - , - { - TOP, 0, TOP_BLOCK - } - , - { - SUBST, 0, SUBST_BLOCK - } - , - { - BEGIN, L"begin", BEGIN_BLOCK - } - , - { - SOURCE, L".", SOURCE_BLOCK - } - , - { - EVENT, 0, EVENT_BLOCK - } - , - { - BREAKPOINT, L"breakpoint", BREAKPOINT_BLOCK - } - , - { - (block_type_t)0, 0, 0 - } + { + WHILE, L"while", WHILE_BLOCK + } + , + { + FOR, L"for", FOR_BLOCK + } + , + { + IF, L"if", IF_BLOCK + } + , + { + FUNCTION_DEF, L"function", FUNCTION_DEF_BLOCK + } + , + { + FUNCTION_CALL, 0, FUNCTION_CALL_BLOCK + } + , + { + FUNCTION_CALL_NO_SHADOW, 0, FUNCTION_CALL_NO_SHADOW_BLOCK + } + , + { + SWITCH, L"switch", SWITCH_BLOCK + } + , + { + FAKE, 0, FAKE_BLOCK + } + , + { + TOP, 0, TOP_BLOCK + } + , + { + SUBST, 0, SUBST_BLOCK + } + , + { + BEGIN, L"begin", BEGIN_BLOCK + } + , + { + SOURCE, L".", SOURCE_BLOCK + } + , + { + EVENT, 0, EVENT_BLOCK + } + , + { + BREAKPOINT, L"breakpoint", BREAKPOINT_BLOCK + } + , + { + (block_type_t)0, 0, 0 + } }; static bool job_should_skip_elseif(const job_t *job, const block_t *current_block); @@ -379,7 +379,7 @@ parser_t::parser_t(enum parser_type_t type, bool errors) : current_block(NULL), block_io(NULL) { - + } /* A pointer to the principal parser (which is a static local) */ @@ -420,91 +420,91 @@ void parser_t::skip_all_blocks(void) static int block_count( block_t *b ) { - if( b==0) - return 0; - return( block_count(b->outer)+1); + if( b==0) + return 0; + return( block_count(b->outer)+1); } */ void parser_t::push_block( block_t *newv ) { const enum block_type_t type = newv->type(); - newv->src_lineno = parser_t::get_lineno(); - newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0; - - newv->outer = current_block; + newv->src_lineno = parser_t::get_lineno(); + newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0; + + newv->outer = current_block; if (current_block && current_block->skip) newv->mark_as_fake(); - - /* - New blocks should be skipped if the outer block is skipped, - except TOP ans SUBST block, which open up new environments. Fake - blocks should always be skipped. Rather complicated... :-( - */ - newv->skip=current_block?current_block->skip:0; - - /* - Type TOP and SUBST are never skipped - */ - if( type == TOP || type == SUBST ) - { - newv->skip = 0; - } - - /* - Fake blocks and function definition blocks are never executed - */ - if( type == FAKE || type == FUNCTION_DEF ) - { - newv->skip = 1; - } - - newv->job = 0; - newv->loop_status=LOOP_NORMAL; - - current_block = newv; - - if( (newv->type() != FUNCTION_DEF) && - (newv->type() != FAKE) && - (newv->type() != TOP) ) - { - env_push( type == FUNCTION_CALL ); + + /* + New blocks should be skipped if the outer block is skipped, + except TOP ans SUBST block, which open up new environments. Fake + blocks should always be skipped. Rather complicated... :-( + */ + newv->skip=current_block?current_block->skip:0; + + /* + Type TOP and SUBST are never skipped + */ + if( type == TOP || type == SUBST ) + { + newv->skip = 0; + } + + /* + Fake blocks and function definition blocks are never executed + */ + if( type == FAKE || type == FUNCTION_DEF ) + { + newv->skip = 1; + } + + newv->job = 0; + newv->loop_status=LOOP_NORMAL; + + current_block = newv; + + if( (newv->type() != FUNCTION_DEF) && + (newv->type() != FAKE) && + (newv->type() != TOP) ) + { + env_push( type == FUNCTION_CALL ); newv->wants_pop_env = true; - } + } } void parser_t::pop_block() { - block_t *old = current_block; - if( !current_block ) - { - debug( 1, - L"function %s called on empty block stack.", - __func__); - bugreport(); - return; - } - - current_block = current_block->outer; - + block_t *old = current_block; + if( !current_block ) + { + debug( 1, + L"function %s called on empty block stack.", + __func__); + bugreport(); + return; + } + + current_block = current_block->outer; + if (old->wants_pop_env) env_pop(); - + delete old; } const wchar_t *parser_t::get_block_desc( int block ) const { - int i; - - for( i=0; block_lookup[i].desc; i++ ) - { - if( block_lookup[i].type == block ) - { - return _( block_lookup[i].desc ); - } - } - return _(UNKNOWN_BLOCK); + int i; + + for( i=0; block_lookup[i].desc; i++ ) + { + if( block_lookup[i].type == block ) + { + return _( block_lookup[i].desc ); + } + } + return _(UNKNOWN_BLOCK); } /** @@ -512,12 +512,12 @@ const wchar_t *parser_t::get_block_desc( int block ) const */ static int parser_is_pipe_forbidden( const wcstring &word ) { - return contains( word, - L"exec", - L"case", - L"break", - L"return", - L"continue" ); + return contains( word, + L"exec", + L"case", + L"break", + L"return", + L"continue" ); } /** @@ -525,87 +525,87 @@ static int parser_is_pipe_forbidden( const wcstring &word ) */ static const wchar_t *parser_find_end( const wchar_t * buff ) { - tokenizer tok; - int had_cmd=0; - int count = 0; - int error=0; - int mark=0; - - CHECK( buff, 0 ); - - for( tok_init( &tok, buff, 0 ); - tok_has_next( &tok ) && !error; - tok_next( &tok ) ) - { - int last_type = tok_last_type( &tok ); - switch( last_type ) - { - case TOK_STRING: - { - if( !had_cmd ) - { - if( wcscmp(tok_last(&tok), L"end")==0) - { - count--; - } - else if( parser_keywords_is_block( tok_last(&tok) ) ) - { - count++; - } - - if( count < 0 ) - { - error = 1; - } - had_cmd = 1; - } - break; - } - - case TOK_END: - { - had_cmd = 0; - break; - } - - case TOK_PIPE: - case TOK_BACKGROUND: - { - if( had_cmd ) - { - had_cmd = 0; - } - else - { - error = 1; - } - break; - - } - - case TOK_ERROR: - error = 1; - break; - - default: - break; - - } - if(!count) - { - tok_next( &tok ); - mark = tok_get_pos( &tok ); - break; - } - - } - - tok_destroy( &tok ); - if(!count && !error){ - - return buff+mark; - } - return 0; + tokenizer tok; + int had_cmd=0; + int count = 0; + int error=0; + int mark=0; + + CHECK( buff, 0 ); + + for( tok_init( &tok, buff, 0 ); + tok_has_next( &tok ) && !error; + tok_next( &tok ) ) + { + int last_type = tok_last_type( &tok ); + switch( last_type ) + { + case TOK_STRING: + { + if( !had_cmd ) + { + if( wcscmp(tok_last(&tok), L"end")==0) + { + count--; + } + else if( parser_keywords_is_block( tok_last(&tok) ) ) + { + count++; + } + + if( count < 0 ) + { + error = 1; + } + had_cmd = 1; + } + break; + } + + case TOK_END: + { + had_cmd = 0; + break; + } + + case TOK_PIPE: + case TOK_BACKGROUND: + { + if( had_cmd ) + { + had_cmd = 0; + } + else + { + error = 1; + } + break; + + } + + case TOK_ERROR: + error = 1; + break; + + default: + break; + + } + if(!count) + { + tok_next( &tok ); + mark = tok_get_pos( &tok ); + break; + } + + } + + tok_destroy( &tok ); + if(!count && !error){ + + return buff+mark; + } + return 0; } @@ -626,16 +626,16 @@ void parser_t::allow_function() void parser_t::error( int ec, int p, const wchar_t *str, ... ) { - va_list va; + va_list va; - CHECK( str, ); - - error_code = ec; - err_pos = p; + CHECK( str, ); - va_start( va, str ); + error_code = ec; + err_pos = p; + + va_start( va, str ); err_buff = vformat_string(str, va); - va_end( va ); + va_end( va ); } @@ -643,108 +643,108 @@ void parser_t::error( int ec, int p, const wchar_t *str, ... ) Print profiling information to the specified stream */ static void print_profile( const std::vector<profile_item_t> &items, - size_t pos, - FILE *out ) + size_t pos, + FILE *out ) { - const profile_item_t *me, *prev; - size_t i; - int my_time; - - if( pos >= items.size() ) - { - return; - } - - me= &items.at(pos); - if( !me->skipped ) - { - my_time=me->parse+me->exec; - - for( i=pos+1; i<items.size(); i++ ) - { - prev = &items.at(i); - if( prev->skipped ) - { - continue; - } - - if( prev->level <= me->level ) - { - break; - } - - if( prev->level > me->level+1 ) - { - continue; - } - - my_time -= prev->parse; - my_time -= prev->exec; - } - - if( me->cmd.size() > 0 ) - { - if( fwprintf( out, L"%d\t%d\t", my_time, me->parse+me->exec ) < 0 ) - { - wperror( L"fwprintf" ); - return; - } - - for( i=0; i<me->level; i++ ) - { - if( fwprintf( out, L"-" ) < 0 ) - { - wperror( L"fwprintf" ); - return; - } - - } - if( fwprintf( out, L"> %ls\n", me->cmd.c_str() ) < 0 ) - { - wperror( L"fwprintf" ); - return; - } - - } - } - print_profile( items, pos+1, out ); + const profile_item_t *me, *prev; + size_t i; + int my_time; + + if( pos >= items.size() ) + { + return; + } + + me= &items.at(pos); + if( !me->skipped ) + { + my_time=me->parse+me->exec; + + for( i=pos+1; i<items.size(); i++ ) + { + prev = &items.at(i); + if( prev->skipped ) + { + continue; + } + + if( prev->level <= me->level ) + { + break; + } + + if( prev->level > me->level+1 ) + { + continue; + } + + my_time -= prev->parse; + my_time -= prev->exec; + } + + if( me->cmd.size() > 0 ) + { + if( fwprintf( out, L"%d\t%d\t", my_time, me->parse+me->exec ) < 0 ) + { + wperror( L"fwprintf" ); + return; + } + + for( i=0; i<me->level; i++ ) + { + if( fwprintf( out, L"-" ) < 0 ) + { + wperror( L"fwprintf" ); + return; + } + + } + if( fwprintf( out, L"> %ls\n", me->cmd.c_str() ) < 0 ) + { + wperror( L"fwprintf" ); + return; + } + + } + } + print_profile( items, pos+1, out ); } void parser_t::destroy() { - if( profile ) - { - /* Save profiling information. OK to not use CLO_EXEC here because this is called while fish is dying (and hence will not fork) */ - FILE *f = fopen( profile, "w" ); - if( !f ) - { - debug( 1, - _(L"Could not write profiling information to file '%s'"), - profile ); - } - else - { - if( fwprintf( f, - _(L"Time\tSum\tCommand\n"), - profile_items.size() ) < 0 ) - { - wperror( L"fwprintf" ); - } - else - { - print_profile( profile_items, 0, f ); - } - - if( fclose( f ) ) - { - wperror( L"fclose" ); - } - } - } + if( profile ) + { + /* Save profiling information. OK to not use CLO_EXEC here because this is called while fish is dying (and hence will not fork) */ + FILE *f = fopen( profile, "w" ); + if( !f ) + { + debug( 1, + _(L"Could not write profiling information to file '%s'"), + profile ); + } + else + { + if( fwprintf( f, + _(L"Time\tSum\tCommand\n"), + profile_items.size() ) < 0 ) + { + wperror( L"fwprintf" ); + } + else + { + print_profile( profile_items, 0, f ); + } + + if( fclose( f ) ) + { + wperror( L"fclose" ); + } + } + } lineinfo.clear(); - forbidden_function.clear(); + forbidden_function.clear(); } @@ -756,21 +756,21 @@ void parser_t::destroy() */ void parser_t::print_errors( wcstring &target, const wchar_t *prefix ) { - CHECK( prefix, ); - - if( error_code && ! err_buff.empty() ) - { - int tmp; + CHECK( prefix, ); + + if( error_code && ! err_buff.empty() ) + { + int tmp; - append_format( target, L"%ls: %ls\n", prefix, err_buff.c_str() ); + append_format( target, L"%ls: %ls\n", prefix, err_buff.c_str() ); - tmp = current_tokenizer_pos; - current_tokenizer_pos = err_pos; + tmp = current_tokenizer_pos; + current_tokenizer_pos = err_pos; - append_format( target, L"%ls", this->current_line() ); + append_format( target, L"%ls", this->current_line() ); - current_tokenizer_pos=tmp; - } + current_tokenizer_pos=tmp; + } } /** @@ -778,215 +778,215 @@ void parser_t::print_errors( wcstring &target, const wchar_t *prefix ) */ void parser_t::print_errors_stderr() { - if( error_code && ! err_buff.empty() ) - { - debug( 0, L"%ls", err_buff.c_str() ); - int tmp; - - tmp = current_tokenizer_pos; - current_tokenizer_pos = err_pos; - - fwprintf( stderr, L"%ls", this->current_line() ); - - current_tokenizer_pos=tmp; - } - + if( error_code && ! err_buff.empty() ) + { + debug( 0, L"%ls", err_buff.c_str() ); + int tmp; + + tmp = current_tokenizer_pos; + current_tokenizer_pos = err_pos; + + fwprintf( stderr, L"%ls", this->current_line() ); + + current_tokenizer_pos=tmp; + } + } int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args ) { - tokenizer tok; - + tokenizer tok; + expand_flags_t eflags = 0; if (! show_errors) eflags |= EXPAND_NO_DESCRIPTIONS; if (this->parser_type != PARSER_TYPE_GENERAL) eflags |= EXPAND_SKIP_CMDSUBST; - - /* - eval_args may be called while evaulating another command, so we - save the previous tokenizer and restore it on exit - */ - tokenizer *previous_tokenizer=current_tokenizer; - int previous_pos=current_tokenizer_pos; - int do_loop=1; - - CHECK( line, 1 ); -// CHECK( args, 1 ); - + + /* + eval_args may be called while evaulating another command, so we + save the previous tokenizer and restore it on exit + */ + tokenizer *previous_tokenizer=current_tokenizer; + int previous_pos=current_tokenizer_pos; + int do_loop=1; + + CHECK( line, 1 ); +// CHECK( args, 1 ); + // PCA we need to suppress calling proc_push_interactive off of the main thread. I'm not sure exactly what it does. if (this->parser_type == PARSER_TYPE_GENERAL) proc_push_interactive(0); - - current_tokenizer = &tok; - current_tokenizer_pos = 0; - - tok_init( &tok, line, (show_errors ? 0 : TOK_SQUASH_ERRORS) ); - error_code=0; - - for(;do_loop && tok_has_next( &tok) ; tok_next( &tok ) ) - { - current_tokenizer_pos = tok_get_pos( &tok ); - switch(tok_last_type( &tok ) ) - { - case TOK_STRING: - { - const wcstring tmp = tok_last(&tok); - if( expand_string(tmp, args, eflags) == EXPAND_ERROR ) - { - err_pos=tok_get_pos( &tok ); - do_loop=0; - } - break; - } - - case TOK_END: - { - break; - } - - case TOK_ERROR: - { - if (show_errors) + + current_tokenizer = &tok; + current_tokenizer_pos = 0; + + tok_init( &tok, line, (show_errors ? 0 : TOK_SQUASH_ERRORS) ); + error_code=0; + + for(;do_loop && tok_has_next( &tok) ; tok_next( &tok ) ) + { + current_tokenizer_pos = tok_get_pos( &tok ); + switch(tok_last_type( &tok ) ) + { + case TOK_STRING: + { + const wcstring tmp = tok_last(&tok); + if( expand_string(tmp, args, eflags) == EXPAND_ERROR ) + { + err_pos=tok_get_pos( &tok ); + do_loop=0; + } + break; + } + + case TOK_END: + { + break; + } + + case TOK_ERROR: + { + if (show_errors) error( SYNTAX_ERROR, tok_get_pos( &tok ), TOK_ERR_MSG, tok_last(&tok) ); - do_loop=0; - break; - } + do_loop=0; + break; + } - default: - { + default: + { if (show_errors) error( SYNTAX_ERROR, tok_get_pos( &tok ), UNEXPECTED_TOKEN_ERR_MSG, tok_get_desc( tok_last_type(&tok)) ); - do_loop=0; - break; - } - } - } + do_loop=0; + break; + } + } + } if (show_errors) this->print_errors_stderr(); - - tok_destroy( &tok ); - - current_tokenizer=previous_tokenizer; - current_tokenizer_pos = previous_pos; - + + tok_destroy( &tok ); + + current_tokenizer=previous_tokenizer; + current_tokenizer_pos = previous_pos; + if (this->parser_type == PARSER_TYPE_GENERAL) proc_pop_interactive(); - return 1; + return 1; } void parser_t::stack_trace( block_t *b, wcstring &buff) -{ - /* - Check if we should end the recursion - */ - if( !b ) - return; - - if( b->type()==EVENT ) - { - /* - This is an event handler - */ +{ + /* + Check if we should end the recursion + */ + if( !b ) + return; + + if( b->type()==EVENT ) + { + /* + This is an event handler + */ const event_block_t *eb = static_cast<const event_block_t *>(b); wcstring description = event_get_desc( eb->event ); - append_format( buff, _(L"in event handler: %ls\n"), description.c_str()); - buff.append( L"\n" ); - - /* - Stop recursing at event handler. No reason to belive that - any other code is relevant. - - It might make sense in the future to continue printing the - stack trace of the code that invoked the event, if this is a - programmatic event, but we can't currently detect that. - */ - return; - } - - if( b->type() == FUNCTION_CALL || b->type()==SOURCE || b->type()==SUBST) - { - /* - These types of blocks should be printed - */ - - int i; - - switch( b->type()) - { - case SOURCE: - { + append_format( buff, _(L"in event handler: %ls\n"), description.c_str()); + buff.append( L"\n" ); + + /* + Stop recursing at event handler. No reason to belive that + any other code is relevant. + + It might make sense in the future to continue printing the + stack trace of the code that invoked the event, if this is a + programmatic event, but we can't currently detect that. + */ + return; + } + + if( b->type() == FUNCTION_CALL || b->type()==SOURCE || b->type()==SUBST) + { + /* + These types of blocks should be printed + */ + + int i; + + switch( b->type()) + { + case SOURCE: + { const source_block_t *sb = static_cast<const source_block_t*>(b); const wchar_t *source_dest = sb->source_file; - append_format( buff, _(L"in . (source) call of file '%ls',\n"), source_dest ); - break; - } - case FUNCTION_CALL: - { + append_format( buff, _(L"in . (source) call of file '%ls',\n"), source_dest ); + break; + } + case FUNCTION_CALL: + { const function_block_t *fb = static_cast<const function_block_t*>(b); - append_format( buff, _(L"in function '%ls',\n"), fb->name.c_str() ); - break; - } - case SUBST: - { - append_format( buff, _(L"in command substitution\n") ); - break; - } - + append_format( buff, _(L"in function '%ls',\n"), fb->name.c_str() ); + break; + } + case SUBST: + { + append_format( buff, _(L"in command substitution\n") ); + break; + } + default: /* Can't get here */ break; - } - - const wchar_t *file = b->src_filename; - - if( file ) - { - append_format( buff, - _(L"\tcalled on line %d of file '%ls',\n"), - b->src_lineno, - file ); - } - else - { - append_format( buff, - _(L"\tcalled on standard input,\n") ); - } - - if( b->type() == FUNCTION_CALL ) + } + + const wchar_t *file = b->src_filename; + + if( file ) + { + append_format( buff, + _(L"\tcalled on line %d of file '%ls',\n"), + b->src_lineno, + file ); + } + else + { + append_format( buff, + _(L"\tcalled on standard input,\n") ); + } + + if( b->type() == FUNCTION_CALL ) { const function_block_t *fb = static_cast<const function_block_t *>(b); const process_t * const process = fb->process; - if( process->argv(1) ) - { - wcstring tmp; - - for( i=1; process->argv(i); i++ ) - { + if( process->argv(1) ) + { + wcstring tmp; + + for( i=1; process->argv(i); i++ ) + { if (i > 1) tmp.push_back(L' '); tmp.append(process->argv(i)); - } - append_format( buff, _(L"\twith parameter list '%ls'\n"), tmp.c_str() ); - } - } - - append_format( buff, L"\n" ); - } - - /* - Recursively print the next block - */ - parser_t::stack_trace( b->outer, buff ); + } + append_format( buff, _(L"\twith parameter list '%ls'\n"), tmp.c_str() ); + } + } + + append_format( buff, L"\n" ); + } + + /* + Recursively print the next block + */ + parser_t::stack_trace( b->outer, buff ); } /** @@ -1000,47 +1000,47 @@ const wchar_t *parser_t::is_function() const // PCA: Have to make this a string somehow ASSERT_IS_MAIN_THREAD(); wcstring result; - - block_t *b = current_block; - while( 1 ) - { - if( !b ) - { - return NULL; - } - if( b->type() == FUNCTION_CALL ) - { + + block_t *b = current_block; + while( 1 ) + { + if( !b ) + { + return NULL; + } + if( b->type() == FUNCTION_CALL ) + { const function_block_t *fb = static_cast<const function_block_t *>(b); - return fb->name.c_str(); - } - b=b->outer; - } + return fb->name.c_str(); + } + b=b->outer; + } } int parser_t::get_lineno() const { - int lineno; - + int lineno; + if( ! current_tokenizer || ! tok_string( current_tokenizer )) - return -1; - + return -1; + lineno = current_tokenizer->line_number_of_character_at_offset(current_tokenizer_pos); - + const wchar_t *function_name; - if( (function_name = is_function()) ) - { - lineno += function_get_definition_offset( function_name ); - } + if( (function_name = is_function()) ) + { + lineno += function_get_definition_offset( function_name ); + } - return lineno; + return lineno; } int parser_t::line_number_of_character_at_offset(size_t idx) const { if( ! current_tokenizer) return -1; - + int result = current_tokenizer->line_number_of_character_at_offset(idx); //assert(result == parse_util_lineno(tok_string( current_tokenizer ), idx)); return result; @@ -1051,22 +1051,22 @@ const wchar_t *parser_t::current_filename() const /* We query a global array for the current file name, so it only makes sense to ask this on the principal parser. */ ASSERT_IS_MAIN_THREAD(); assert(this == &principal_parser()); - - block_t *b = current_block; - - while( 1 ) - { - if( !b ) - { - return reader_current_filename(); - } - if( b->type() == FUNCTION_CALL ) - { + + block_t *b = current_block; + + while( 1 ) + { + if( !b ) + { + return reader_current_filename(); + } + if( b->type() == FUNCTION_CALL ) + { const function_block_t *fb = static_cast<const function_block_t *>(b); - return function_get_definition_file(fb->name); - } - b=b->outer; - } + return function_get_definition_file(fb->name); + } + b=b->outer; + } } /** @@ -1077,184 +1077,184 @@ const wchar_t *parser_t::current_filename() const */ static int printed_width( const wchar_t *str, int len ) { - int res=0; - int i; - - CHECK( str, 0 ); - - for( i=0; str[i] && i<len; i++ ) - { - if( str[i] == L'\t' ) - { - res=(res+8)&~7; - } - else - { - res += fish_wcwidth( str[i] ); - } - } - return res; + int res=0; + int i; + + CHECK( str, 0 ); + + for( i=0; str[i] && i<len; i++ ) + { + if( str[i] == L'\t' ) + { + res=(res+8)&~7; + } + else + { + res += fish_wcwidth( str[i] ); + } + } + return res; } const wchar_t *parser_t::current_line() { - int lineno=1; + int lineno=1; + + const wchar_t *file; + const wchar_t *whole_str; + const wchar_t *line; + const wchar_t *line_end; + int i; + int offset; + int current_line_width; + const wchar_t *function_name=0; + int current_line_start=0; + + if( !current_tokenizer ) + { + return L""; + } - const wchar_t *file; - const wchar_t *whole_str; - const wchar_t *line; - const wchar_t *line_end; - int i; - int offset; - int current_line_width; - const wchar_t *function_name=0; - int current_line_start=0; + file = parser_t::current_filename(); + whole_str = tok_string( current_tokenizer ); + line = whole_str; - if( !current_tokenizer ) - { - return L""; - } + if( !line ) + return L""; - file = parser_t::current_filename(); - whole_str = tok_string( current_tokenizer ); - line = whole_str; - if( !line ) - return L""; + lineinfo.clear(); + /* + Calculate line number, line offset, etc. + */ + for( i=0; i<current_tokenizer_pos && whole_str[i]; i++ ) + { + if( whole_str[i] == L'\n' ) + { + lineno++; + current_line_start=i+1; + line = &whole_str[i+1]; + } + } - lineinfo.clear(); +// lineno = current_tokenizer_pos; + + + current_line_width=printed_width( whole_str+current_line_start, + current_tokenizer_pos-current_line_start ); - /* - Calculate line number, line offset, etc. - */ - for( i=0; i<current_tokenizer_pos && whole_str[i]; i++ ) - { - if( whole_str[i] == L'\n' ) - { - lineno++; - current_line_start=i+1; - line = &whole_str[i+1]; - } - } - -// lineno = current_tokenizer_pos; - - - current_line_width=printed_width( whole_str+current_line_start, - current_tokenizer_pos-current_line_start ); - - if( (function_name = is_function()) ) - { - lineno += function_get_definition_offset( function_name ); - } - - /* - Copy current line from whole string - */ - line_end = wcschr( line, L'\n' ); - if( !line_end ) - line_end = line+wcslen(line); - - line = wcsndup( line, line_end-line ); - - /** - If we are not going to print a stack trace, at least print the line number and filename - */ - if( !get_is_interactive() || is_function() ) - { - int prev_width = my_wcswidth( lineinfo.c_str() ); - if( file ) - append_format( lineinfo, - _(L"%ls (line %d): "), - file, - lineno ); - else - append_format( lineinfo, - L"%ls: ", - _(L"Standard input"), - lineno ); - offset = my_wcswidth( lineinfo.c_str() ) - prev_width; - } - else - { - offset=0; - } - -// debug( 1, L"Current pos %d, line pos %d, file_length %d, is_interactive %d, offset %d\n", current_tokenizer_pos, current_line_pos, wcslen(whole_str), is_interactive, offset); - /* - Skip printing character position if we are in interactive mode - and the error was on the first character of the line. - */ - if( !get_is_interactive() || is_function() || (current_line_width!=0) ) - { - // Workaround since it seems impossible to print 0 copies of a character using %*lc - if( offset+current_line_width ) - { - append_format( lineinfo, - L"%ls\n%*lc^\n", - line, - offset+current_line_width, - L' ' ); - } - else - { - append_format( lineinfo, - L"%ls\n^\n", - line ); - } - } - - free( (void *)line ); - parser_t::stack_trace( current_block, lineinfo ); - - return lineinfo.c_str(); + if( (function_name = is_function()) ) + { + lineno += function_get_definition_offset( function_name ); + } + + /* + Copy current line from whole string + */ + line_end = wcschr( line, L'\n' ); + if( !line_end ) + line_end = line+wcslen(line); + + line = wcsndup( line, line_end-line ); + + /** + If we are not going to print a stack trace, at least print the line number and filename + */ + if( !get_is_interactive() || is_function() ) + { + int prev_width = my_wcswidth( lineinfo.c_str() ); + if( file ) + append_format( lineinfo, + _(L"%ls (line %d): "), + file, + lineno ); + else + append_format( lineinfo, + L"%ls: ", + _(L"Standard input"), + lineno ); + offset = my_wcswidth( lineinfo.c_str() ) - prev_width; + } + else + { + offset=0; + } + +// debug( 1, L"Current pos %d, line pos %d, file_length %d, is_interactive %d, offset %d\n", current_tokenizer_pos, current_line_pos, wcslen(whole_str), is_interactive, offset); + /* + Skip printing character position if we are in interactive mode + and the error was on the first character of the line. + */ + if( !get_is_interactive() || is_function() || (current_line_width!=0) ) + { + // Workaround since it seems impossible to print 0 copies of a character using %*lc + if( offset+current_line_width ) + { + append_format( lineinfo, + L"%ls\n%*lc^\n", + line, + offset+current_line_width, + L' ' ); + } + else + { + append_format( lineinfo, + L"%ls\n^\n", + line ); + } + } + + free( (void *)line ); + parser_t::stack_trace( current_block, lineinfo ); + + return lineinfo.c_str(); } int parser_t::get_pos() const { - return tok_get_pos( current_tokenizer ); + return tok_get_pos( current_tokenizer ); } int parser_t::get_job_pos() const { - return job_start_pos; + return job_start_pos; } void parser_t::set_pos( int p) { - tok_set_pos( current_tokenizer, p ); + tok_set_pos( current_tokenizer, p ); } const wchar_t *parser_t::get_buffer() const { - return tok_string( current_tokenizer ); + return tok_string( current_tokenizer ); } int parser_t::is_help( const wchar_t *s, int min_match ) const { - CHECK( s, 0 ); + CHECK( s, 0 ); + + size_t len = wcslen(s); - size_t len = wcslen(s); + min_match = maxi( min_match, 3 ); - min_match = maxi( min_match, 3 ); - - return ( wcscmp( L"-h", s ) == 0 ) || - ( len >= min_match && (wcsncmp( L"--help", s, len ) == 0) ); + return ( wcscmp( L"-h", s ) == 0 ) || + ( len >= min_match && (wcsncmp( L"--help", s, len ) == 0) ); } job_t *parser_t::job_create(void) { job_t *res = new job_t(acquire_job_id()); this->my_job_list.push_front(res); - - job_set_flag( res, - JOB_CONTROL, - (job_control_mode==JOB_CONTROL_ALL) || - ((job_control_mode == JOB_CONTROL_INTERACTIVE) && (get_is_interactive())) ); + + job_set_flag( res, + JOB_CONTROL, + (job_control_mode==JOB_CONTROL_ALL) || + ((job_control_mode == JOB_CONTROL_INTERACTIVE) && (get_is_interactive())) ); return res; } @@ -1265,8 +1265,8 @@ bool parser_t::job_remove( job_t *j ) my_job_list.erase(iter); return true; } else { - debug( 1, _( L"Job inconsistency" ) ); - sanity_lose(); + debug( 1, _( L"Job inconsistency" ) ); + sanity_lose(); return false; } } @@ -1275,7 +1275,7 @@ void parser_t::job_promote(job_t *job) { job_list_t::iterator loc = std::find(my_job_list.begin(), my_job_list.end(), job); assert(loc != my_job_list.end()); - + /* Move the job to the beginning */ my_job_list.splice(my_job_list.begin(), my_job_list, loc); } @@ -1287,8 +1287,8 @@ job_t *parser_t::job_get(job_id_t id) while ((job = jobs.next())) { if( id <= 0 || job->job_id == id) return job; - } - return NULL; + } + return NULL; } job_t *parser_t::job_get_from_pid( int pid ) @@ -1296,10 +1296,10 @@ job_t *parser_t::job_get_from_pid( int pid ) job_iterator_t jobs; job_t *job; while ((job = jobs.next())) { - if( job->pgid == pid ) - return job; - } - return 0; + if( job->pgid == pid ) + return job; + } + return 0; } /** @@ -1312,115 +1312,115 @@ job_t *parser_t::job_get_from_pid( int pid ) \param args unskip whether we should ignore current_block->skip. Big hack because of our dumb handling of if statements. */ void parser_t::parse_job_argument_list( process_t *p, - job_t *j, - tokenizer *tok, - std::vector<completion_t> &args, + job_t *j, + tokenizer *tok, + std::vector<completion_t> &args, bool unskip ) { - int is_finished=0; - - int proc_is_count=0; - - int matched_wildcard = 0, unmatched_wildcard = 0; - - wcstring unmatched; - int unmatched_pos=0; - - /* - Test if this is the 'count' command. We need to special case - count in the shell, since it should display a help message on - 'count -h', but not on 'set foo -h; count $foo'. This is an ugly - workaround and a huge hack, but as near as I can tell, the - alternatives are worse. - */ - proc_is_count = ( args.at(0).completion == L"count" ); - - while( 1 ) - { - - switch( tok_last_type( tok ) ) - { - case TOK_PIPE: - { - wchar_t *end; - - if (p->type == INTERNAL_EXEC) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - EXEC_ERR_MSG ); - return; - } - - errno = 0; - p->pipe_write_fd = fish_wcstoi( tok_last( tok ), &end, 10 ); - if( p->pipe_write_fd < 0 || errno || *end ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - ILLEGAL_FD_ERR_MSG, - tok_last( tok ) ); - return; - } - + int is_finished=0; + + int proc_is_count=0; + + int matched_wildcard = 0, unmatched_wildcard = 0; + + wcstring unmatched; + int unmatched_pos=0; + + /* + Test if this is the 'count' command. We need to special case + count in the shell, since it should display a help message on + 'count -h', but not on 'set foo -h; count $foo'. This is an ugly + workaround and a huge hack, but as near as I can tell, the + alternatives are worse. + */ + proc_is_count = ( args.at(0).completion == L"count" ); + + while( 1 ) + { + + switch( tok_last_type( tok ) ) + { + case TOK_PIPE: + { + wchar_t *end; + + if (p->type == INTERNAL_EXEC) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + EXEC_ERR_MSG ); + return; + } + + errno = 0; + p->pipe_write_fd = fish_wcstoi( tok_last( tok ), &end, 10 ); + if( p->pipe_write_fd < 0 || errno || *end ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + ILLEGAL_FD_ERR_MSG, + tok_last( tok ) ); + return; + } + p->set_argv(completions_to_wcstring_list(args)); - p->next = new process_t(); - - tok_next( tok ); - - /* - Don't do anything on failiure. parse_job will notice - the error flag and report any errors for us - */ - parse_job( p->next, j, tok ); - - is_finished = 1; - break; - } - - case TOK_BACKGROUND: - { - job_set_flag( j, JOB_FOREGROUND, 0 ); - } - - case TOK_END: - { - if( !p->get_argv() ) - p->set_argv(completions_to_wcstring_list(args)); - if( tok_has_next(tok)) - tok_next(tok); - - is_finished = 1; - - break; - } - - case TOK_STRING: - { - int skip=0; - - if( job_get_flag( j, JOB_SKIP ) ) - { - skip = 1; - } - else if( current_block->skip && ! unskip ) - { - /* - If this command should be skipped, we do not expand the arguments - */ - skip=1; - - /* But if this is in fact a case statement or an elseif statement, then it should be evaluated */ + p->next = new process_t(); + + tok_next( tok ); + + /* + Don't do anything on failiure. parse_job will notice + the error flag and report any errors for us + */ + parse_job( p->next, j, tok ); + + is_finished = 1; + break; + } + + case TOK_BACKGROUND: + { + job_set_flag( j, JOB_FOREGROUND, 0 ); + } + + case TOK_END: + { + if( !p->get_argv() ) + p->set_argv(completions_to_wcstring_list(args)); + if( tok_has_next(tok)) + tok_next(tok); + + is_finished = 1; + + break; + } + + case TOK_STRING: + { + int skip=0; + + if( job_get_flag( j, JOB_SKIP ) ) + { + skip = 1; + } + else if( current_block->skip && ! unskip ) + { + /* + If this command should be skipped, we do not expand the arguments + */ + skip=1; + + /* But if this is in fact a case statement or an elseif statement, then it should be evaluated */ block_type_t type = current_block->type(); - if( type == SWITCH && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN ) - { - skip=0; - } + if( type == SWITCH && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN ) + { + skip=0; + } else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block)) { skip=0; } - } + } else { /* If this is an else if, and we should skip it, then don't expand any arguments */ @@ -1430,264 +1430,264 @@ void parser_t::parse_job_argument_list( process_t *p, } } - if( !skip ) - { - if( ( proc_is_count ) && - ( args.size() == 1) && - ( parser_t::is_help( tok_last(tok), 0) ) && - ( p->type == INTERNAL_BUILTIN ) ) - { - /* - Display help for count - */ - p->count_help_magic = 1; - } - - switch( expand_string( tok_last( tok ), args, 0 ) ) - { - case EXPAND_ERROR: - { - err_pos=tok_get_pos( tok ); - if( error_code == 0 ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - _(L"Could not expand string '%ls'"), - tok_last(tok) ); - - } - break; - } - - case EXPAND_WILDCARD_NO_MATCH: - { - unmatched_wildcard = 1; - if( unmatched.empty() ) - { + if( !skip ) + { + if( ( proc_is_count ) && + ( args.size() == 1) && + ( parser_t::is_help( tok_last(tok), 0) ) && + ( p->type == INTERNAL_BUILTIN ) ) + { + /* + Display help for count + */ + p->count_help_magic = 1; + } + + switch( expand_string( tok_last( tok ), args, 0 ) ) + { + case EXPAND_ERROR: + { + err_pos=tok_get_pos( tok ); + if( error_code == 0 ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + _(L"Could not expand string '%ls'"), + tok_last(tok) ); + + } + break; + } + + case EXPAND_WILDCARD_NO_MATCH: + { + unmatched_wildcard = 1; + if( unmatched.empty() ) + { unmatched = tok_last(tok); - unmatched_pos = tok_get_pos( tok ); - } + unmatched_pos = tok_get_pos( tok ); + } - break; - } + break; + } - case EXPAND_WILDCARD_MATCH: - { - matched_wildcard = 1; - break; - } + case EXPAND_WILDCARD_MATCH: + { + matched_wildcard = 1; + break; + } - case EXPAND_OK: - { - break; - } + case EXPAND_OK: + { + break; + } - } + } - } + } - break; - } + break; + } - case TOK_REDIRECT_OUT: - case TOK_REDIRECT_IN: - case TOK_REDIRECT_APPEND: - case TOK_REDIRECT_FD: - case TOK_REDIRECT_NOCLOB: - { - int type = tok_last_type( tok ); + case TOK_REDIRECT_OUT: + case TOK_REDIRECT_IN: + case TOK_REDIRECT_APPEND: + case TOK_REDIRECT_FD: + case TOK_REDIRECT_NOCLOB: + { + int type = tok_last_type( tok ); std::auto_ptr<io_data_t> new_io; wcstring target; - bool has_target = false; - wchar_t *end; - - /* - Don't check redirections in skipped part - - Otherwise, bogus errors may be the result. (Do check - that token is string, though) - */ - if( current_block->skip && ! unskip ) - { - tok_next( tok ); - if( tok_last_type( tok ) != TOK_STRING ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - REDIRECT_TOKEN_ERR_MSG, - tok_get_desc( tok_last_type(tok)) ); - } - - break; - } - - new_io.reset(new io_data_t); - - errno = 0; - new_io->fd = fish_wcstoi( tok_last( tok ), - &end, - 10 ); - if( new_io->fd < 0 || errno || *end ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - ILLEGAL_FD_ERR_MSG, - tok_last( tok ) ); - } - else - { - - tok_next( tok ); - - switch( tok_last_type( tok ) ) - { - case TOK_STRING: - { + bool has_target = false; + wchar_t *end; + + /* + Don't check redirections in skipped part + + Otherwise, bogus errors may be the result. (Do check + that token is string, though) + */ + if( current_block->skip && ! unskip ) + { + tok_next( tok ); + if( tok_last_type( tok ) != TOK_STRING ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + REDIRECT_TOKEN_ERR_MSG, + tok_get_desc( tok_last_type(tok)) ); + } + + break; + } + + new_io.reset(new io_data_t); + + errno = 0; + new_io->fd = fish_wcstoi( tok_last( tok ), + &end, + 10 ); + if( new_io->fd < 0 || errno || *end ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + ILLEGAL_FD_ERR_MSG, + tok_last( tok ) ); + } + else + { + + tok_next( tok ); + + switch( tok_last_type( tok ) ) + { + case TOK_STRING: + { target = tok_last( tok ); has_target = expand_one(target, no_exec ? EXPAND_SKIP_VARIABLES : 0); - if( ! has_target && error_code == 0 ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - REDIRECT_TOKEN_ERR_MSG, - tok_last( tok ) ); - - } - break; - } - - default: - error( SYNTAX_ERROR, - tok_get_pos( tok ), - REDIRECT_TOKEN_ERR_MSG, - tok_get_desc( tok_last_type(tok)) ); - } - - if( ! has_target || target.empty() ) - { - if( error_code == 0 ) - error( SYNTAX_ERROR, - tok_get_pos( tok ), - _(L"Invalid IO redirection") ); - tok_next(tok); - } - else - { - - switch( type ) - { - case TOK_REDIRECT_APPEND: - new_io->io_mode = IO_FILE; - new_io->param2.flags = O_CREAT | O_APPEND | O_WRONLY; - new_io->set_filename(target); - break; - - case TOK_REDIRECT_OUT: - new_io->io_mode = IO_FILE; - new_io->param2.flags = O_CREAT | O_WRONLY | O_TRUNC; - new_io->set_filename(target); - break; - - case TOK_REDIRECT_NOCLOB: - new_io->io_mode = IO_FILE; - new_io->param2.flags = O_CREAT | O_EXCL | O_WRONLY; - new_io->set_filename(target); - break; - - case TOK_REDIRECT_IN: - new_io->io_mode = IO_FILE; - new_io->param2.flags = O_RDONLY; - new_io->set_filename(target); - break; - - case TOK_REDIRECT_FD: - { - if( target == L"-" ) - { - new_io->io_mode = IO_CLOSE; - } - else - { - wchar_t *end; - - new_io->io_mode = IO_FD; - errno = 0; - - new_io->param1.old_fd = fish_wcstoi( target.c_str(), &end, 10 ); - - if( ( new_io->param1.old_fd < 0 ) || - errno || *end ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - _(L"Requested redirection to something that is not a file descriptor %ls"), - target.c_str() ); - - tok_next(tok); - } - } - break; - } - } - - } - } - - j->io.push_back(new_io.release()); - - } - break; - - case TOK_ERROR: - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - TOK_ERR_MSG, - tok_last(tok) ); - - return; - } - - default: - error( SYNTAX_ERROR, - tok_get_pos( tok ), - UNEXPECTED_TOKEN_ERR_MSG, - tok_get_desc( tok_last_type(tok)) ); - - tok_next(tok); - break; - } - - if( (is_finished) || (error_code != 0) ) - break; - - tok_next( tok ); - } - - if( !error_code ) - { - if( unmatched_wildcard && !matched_wildcard ) - { - job_set_flag( j, JOB_WILDCARD_ERROR, 1 ); - proc_set_last_status( STATUS_UNMATCHED_WILDCARD ); - if( get_is_interactive() && !is_block ) - { - int tmp; - - debug( 1, WILDCARD_ERR_MSG, unmatched.c_str() ); - tmp = current_tokenizer_pos; - current_tokenizer_pos = unmatched_pos; - - fwprintf( stderr, L"%ls", parser_t::current_line() ); - - current_tokenizer_pos=tmp; - } - - } - } - - return; + if( ! has_target && error_code == 0 ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + REDIRECT_TOKEN_ERR_MSG, + tok_last( tok ) ); + + } + break; + } + + default: + error( SYNTAX_ERROR, + tok_get_pos( tok ), + REDIRECT_TOKEN_ERR_MSG, + tok_get_desc( tok_last_type(tok)) ); + } + + if( ! has_target || target.empty() ) + { + if( error_code == 0 ) + error( SYNTAX_ERROR, + tok_get_pos( tok ), + _(L"Invalid IO redirection") ); + tok_next(tok); + } + else + { + + switch( type ) + { + case TOK_REDIRECT_APPEND: + new_io->io_mode = IO_FILE; + new_io->param2.flags = O_CREAT | O_APPEND | O_WRONLY; + new_io->set_filename(target); + break; + + case TOK_REDIRECT_OUT: + new_io->io_mode = IO_FILE; + new_io->param2.flags = O_CREAT | O_WRONLY | O_TRUNC; + new_io->set_filename(target); + break; + + case TOK_REDIRECT_NOCLOB: + new_io->io_mode = IO_FILE; + new_io->param2.flags = O_CREAT | O_EXCL | O_WRONLY; + new_io->set_filename(target); + break; + + case TOK_REDIRECT_IN: + new_io->io_mode = IO_FILE; + new_io->param2.flags = O_RDONLY; + new_io->set_filename(target); + break; + + case TOK_REDIRECT_FD: + { + if( target == L"-" ) + { + new_io->io_mode = IO_CLOSE; + } + else + { + wchar_t *end; + + new_io->io_mode = IO_FD; + errno = 0; + + new_io->param1.old_fd = fish_wcstoi( target.c_str(), &end, 10 ); + + if( ( new_io->param1.old_fd < 0 ) || + errno || *end ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + _(L"Requested redirection to something that is not a file descriptor %ls"), + target.c_str() ); + + tok_next(tok); + } + } + break; + } + } + + } + } + + j->io.push_back(new_io.release()); + + } + break; + + case TOK_ERROR: + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + TOK_ERR_MSG, + tok_last(tok) ); + + return; + } + + default: + error( SYNTAX_ERROR, + tok_get_pos( tok ), + UNEXPECTED_TOKEN_ERR_MSG, + tok_get_desc( tok_last_type(tok)) ); + + tok_next(tok); + break; + } + + if( (is_finished) || (error_code != 0) ) + break; + + tok_next( tok ); + } + + if( !error_code ) + { + if( unmatched_wildcard && !matched_wildcard ) + { + job_set_flag( j, JOB_WILDCARD_ERROR, 1 ); + proc_set_last_status( STATUS_UNMATCHED_WILDCARD ); + if( get_is_interactive() && !is_block ) + { + int tmp; + + debug( 1, WILDCARD_ERR_MSG, unmatched.c_str() ); + tmp = current_tokenizer_pos; + current_tokenizer_pos = unmatched_pos; + + fwprintf( stderr, L"%ls", parser_t::current_line() ); + + current_tokenizer_pos=tmp; + } + + } + } + + return; } /* @@ -1696,11 +1696,11 @@ void parser_t::parse_job_argument_list( process_t *p, if( !b ) return; print_block_stack( b->outer ); - - debug( 0, L"Block type %ls, skip: %d", parser_get_block_desc( b->type ), b->skip ); + + debug( 0, L"Block type %ls, skip: %d", parser_get_block_desc( b->type ), b->skip ); } */ - + /** Fully parse a single job. Does not call exec on it, but any command substitutions in the job will be executed. @@ -1711,213 +1711,213 @@ f \return 1 on success, 0 on error */ int parser_t::parse_job( process_t *p, - job_t *j, - tokenizer *tok ) + job_t *j, + tokenizer *tok ) { std::vector<completion_t> args; // The list that will become the argc array for the program - int use_function = 1; // May functions be considered when checking what action this command represents - int use_builtin = 1; // May builtins be considered when checking what action this command represents - int use_command = 1; // May commands be considered when checking what action this command represents - int is_new_block=0; // Does this command create a new block? - bool unskip = false; // Maybe we are an elseif inside an if block; if so we may want to evaluate this even if the if block is currently set to skip - bool allow_bogus_command = false; // If we are an elseif that will not be executed, or an AND or OR that will have been short circuited, don't complain about non-existent commands + int use_function = 1; // May functions be considered when checking what action this command represents + int use_builtin = 1; // May builtins be considered when checking what action this command represents + int use_command = 1; // May commands be considered when checking what action this command represents + int is_new_block=0; // Does this command create a new block? + bool unskip = false; // Maybe we are an elseif inside an if block; if so we may want to evaluate this even if the if block is currently set to skip + bool allow_bogus_command = false; // If we are an elseif that will not be executed, or an AND or OR that will have been short circuited, don't complain about non-existent commands - block_t *prev_block = current_block; - int prev_tokenizer_pos = current_tokenizer_pos; + block_t *prev_block = current_block; + int prev_tokenizer_pos = current_tokenizer_pos; - current_tokenizer_pos = tok_get_pos( tok ); + current_tokenizer_pos = tok_get_pos( tok ); - while( args.empty() ) - { - wcstring nxt; + while( args.empty() ) + { + wcstring nxt; bool has_nxt = false; - bool consumed = false; // Set to one if the command requires a second command, like e.g. while does - int mark; // Use to save the position of the beginning of the token - - switch( tok_last_type( tok )) - { - case TOK_STRING: - { + bool consumed = false; // Set to one if the command requires a second command, like e.g. while does + int mark; // Use to save the position of the beginning of the token + + switch( tok_last_type( tok )) + { + case TOK_STRING: + { nxt = tok_last( tok ); has_nxt = expand_one(nxt, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES); - - if( ! has_nxt) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - ILLEGAL_CMD_ERR_MSG, - tok_last( tok ) ); - - current_tokenizer_pos = prev_tokenizer_pos; - return 0; - } - break; - } - - case TOK_ERROR: - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - TOK_ERR_MSG, - tok_last(tok) ); - - current_tokenizer_pos = prev_tokenizer_pos; - return 0; - } - - case TOK_PIPE: - { - const wchar_t *str = tok_string( tok ); - if( tok_get_pos(tok)>0 && str[tok_get_pos(tok)-1] == L'|' ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - CMD_OR_ERR_MSG, - tok_get_desc( tok_last_type(tok) ) ); - } - else - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(tok) ) ); - } - - current_tokenizer_pos = prev_tokenizer_pos; - return 0; - } - - default: - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(tok) ) ); - - current_tokenizer_pos = prev_tokenizer_pos; - return 0; - } - } - - mark = tok_get_pos( tok ); - - if( contains( nxt, - L"command", - L"builtin", - L"not", - L"and", - L"or", - L"exec" ) ) - { - int sw; - int is_exec = nxt == L"exec"; - - if( is_exec && (p != j->first_process) ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - EXEC_ERR_MSG ); - current_tokenizer_pos = prev_tokenizer_pos; - return 0; - } - - tok_next( tok ); - sw = parser_keywords_is_switch( tok_last( tok ) ); - - if( sw == ARG_SWITCH ) - { - tok_set_pos( tok, mark); - } - else - { - if( sw == ARG_SKIP ) - { - tok_next( tok ); - } - - consumed = true; - - if( nxt == L"command" || nxt == L"builtin" ) - { - use_function = 0; - if( nxt == L"command" ) - { - use_builtin = 0; - use_command = 1; - } - else - { - use_builtin = 1; - use_command = 0; - } - } - else if( nxt == L"not" ) - { - job_set_flag( j, JOB_NEGATE, !job_get_flag( j, JOB_NEGATE ) ); - } - else if( nxt == L"and" ) - { + + if( ! has_nxt) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + ILLEGAL_CMD_ERR_MSG, + tok_last( tok ) ); + + current_tokenizer_pos = prev_tokenizer_pos; + return 0; + } + break; + } + + case TOK_ERROR: + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + TOK_ERR_MSG, + tok_last(tok) ); + + current_tokenizer_pos = prev_tokenizer_pos; + return 0; + } + + case TOK_PIPE: + { + const wchar_t *str = tok_string( tok ); + if( tok_get_pos(tok)>0 && str[tok_get_pos(tok)-1] == L'|' ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + CMD_OR_ERR_MSG, + tok_get_desc( tok_last_type(tok) ) ); + } + else + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(tok) ) ); + } + + current_tokenizer_pos = prev_tokenizer_pos; + return 0; + } + + default: + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(tok) ) ); + + current_tokenizer_pos = prev_tokenizer_pos; + return 0; + } + } + + mark = tok_get_pos( tok ); + + if( contains( nxt, + L"command", + L"builtin", + L"not", + L"and", + L"or", + L"exec" ) ) + { + int sw; + int is_exec = nxt == L"exec"; + + if( is_exec && (p != j->first_process) ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + EXEC_ERR_MSG ); + current_tokenizer_pos = prev_tokenizer_pos; + return 0; + } + + tok_next( tok ); + sw = parser_keywords_is_switch( tok_last( tok ) ); + + if( sw == ARG_SWITCH ) + { + tok_set_pos( tok, mark); + } + else + { + if( sw == ARG_SKIP ) + { + tok_next( tok ); + } + + consumed = true; + + if( nxt == L"command" || nxt == L"builtin" ) + { + use_function = 0; + if( nxt == L"command" ) + { + use_builtin = 0; + use_command = 1; + } + else + { + use_builtin = 1; + use_command = 0; + } + } + else if( nxt == L"not" ) + { + job_set_flag( j, JOB_NEGATE, !job_get_flag( j, JOB_NEGATE ) ); + } + else if( nxt == L"and" ) + { bool skip = (proc_get_last_status() != 0); - job_set_flag( j, JOB_SKIP, skip); + job_set_flag( j, JOB_SKIP, skip); allow_bogus_command = skip; - } - else if( nxt == L"or" ) - { + } + else if( nxt == L"or" ) + { bool skip = (proc_get_last_status() == 0); - job_set_flag( j, JOB_SKIP, skip); + job_set_flag( j, JOB_SKIP, skip); allow_bogus_command = skip; - } - else if( is_exec ) - { - use_function = 0; - use_builtin=0; - p->type=INTERNAL_EXEC; - current_tokenizer_pos = prev_tokenizer_pos; - } - } - } - else if( nxt == L"while" ) - { - bool new_block = false; - tok_next( tok ); + } + else if( is_exec ) + { + use_function = 0; + use_builtin=0; + p->type=INTERNAL_EXEC; + current_tokenizer_pos = prev_tokenizer_pos; + } + } + } + else if( nxt == L"while" ) + { + bool new_block = false; + tok_next( tok ); while_block_t *wb = NULL; - if( ( current_block->type() != WHILE ) ) - { - new_block = true; - } - else if( (wb = static_cast<while_block_t*>(current_block))->status == WHILE_TEST_AGAIN ) - { - wb->status = WHILE_TEST_FIRST; - } - else - { - new_block = true; - } - - if( new_block ) - { + if( ( current_block->type() != WHILE ) ) + { + new_block = true; + } + else if( (wb = static_cast<while_block_t*>(current_block))->status == WHILE_TEST_AGAIN ) + { + wb->status = WHILE_TEST_FIRST; + } + else + { + new_block = true; + } + + if( new_block ) + { while_block_t *wb = new while_block_t(); - wb->status = WHILE_TEST_FIRST; - wb->tok_pos = mark; - this->push_block( wb ); - } + wb->status = WHILE_TEST_FIRST; + wb->tok_pos = mark; + this->push_block( wb ); + } - consumed = true; - is_new_block=1; + consumed = true; + is_new_block=1; - } - else if( nxt == L"if" ) - { - tok_next( tok ); + } + else if( nxt == L"if" ) + { + tok_next( tok ); if_block_t *ib = new if_block_t(); - this->push_block( ib ); - ib->tok_pos = mark; + this->push_block( ib ); + ib->tok_pos = mark; - is_new_block=1; - consumed = true; - } + is_new_block=1; + consumed = true; + } else if (nxt == L"else") { /* Record where the else is for error reporting */ @@ -1927,7 +1927,7 @@ int parser_t::parse_job( process_t *p, if (tok_last_type(tok) == TOK_STRING && current_block->type() == IF) { const if_block_t *ib = static_cast<const if_block_t *>(current_block); - + /* If we've already encountered an else, complain */ if (ib->else_evaluated) { @@ -1939,16 +1939,16 @@ int parser_t::parse_job( process_t *p, } else { - + job_set_flag( j, JOB_ELSEIF, 1 ); consumed = true; - + /* We're at the IF. Go past it. */ tok_next(tok); - + /* We want to execute this ELSEIF if the IF expression was evaluated, it failed, and so has every other ELSEIF (if any) */ unskip = (ib->if_expr_evaluated && ! ib->any_branch_taken); - + /* But if we're not executing it, don't complain about its command if it doesn't exist */ if (! unskip) allow_bogus_command = true; @@ -1956,44 +1956,44 @@ int parser_t::parse_job( process_t *p, } } - /* - Test if we need another command - */ - if( consumed ) - { - /* - Yes we do, around in the loop for another lap, then! - */ - continue; - } - - if( use_function && ( unskip || ! current_block->skip )) - { - bool nxt_forbidden=false; - wcstring forbid; - - int is_function_call=0; - - /* - This is a bit fragile. It is a test to see if we are - inside of function call, but not inside a block in that - function call. If, in the future, the rules for what - block scopes are pushed on function invocation changes, - then this check will break. - */ - if( ( current_block->type() == TOP ) && - ( current_block->outer ) && - ( current_block->outer->type() == FUNCTION_CALL ) ) - is_function_call = 1; - - /* - If we are directly in a function, and this is the first - command of the block, then the function we are executing - may not be called, since that would mean an infinite - recursion. - */ - if( is_function_call && !current_block->had_command ) - { + /* + Test if we need another command + */ + if( consumed ) + { + /* + Yes we do, around in the loop for another lap, then! + */ + continue; + } + + if( use_function && ( unskip || ! current_block->skip )) + { + bool nxt_forbidden=false; + wcstring forbid; + + int is_function_call=0; + + /* + This is a bit fragile. It is a test to see if we are + inside of function call, but not inside a block in that + function call. If, in the future, the rules for what + block scopes are pushed on function invocation changes, + then this check will break. + */ + if( ( current_block->type() == TOP ) && + ( current_block->outer ) && + ( current_block->outer->type() == FUNCTION_CALL ) ) + is_function_call = 1; + + /* + If we are directly in a function, and this is the first + command of the block, then the function we are executing + may not be called, since that would mean an infinite + recursion. + */ + if( is_function_call && !current_block->had_command ) + { forbid = forbidden_function.empty() ? wcstring(L"") : forbidden_function.back(); if (forbid == nxt) { @@ -2001,57 +2001,57 @@ int parser_t::parse_job( process_t *p, nxt_forbidden = true; error( SYNTAX_ERROR, tok_get_pos( tok ), INFINITE_RECURSION_ERR_MSG ); } - } - - if( !nxt_forbidden && has_nxt && function_exists( nxt ) ) - { - /* - Check if we have reached the maximum recursion depth - */ - if( forbidden_function.size() > MAX_RECURSION_DEPTH ) - { - error( SYNTAX_ERROR, tok_get_pos( tok ), OVERFLOW_RECURSION_ERR_MSG ); - } - else - { - p->type = INTERNAL_FUNCTION; - } - } - } - args.push_back(completion_t(nxt)); - } - - if( error_code == 0 ) - { - if( !p->type ) - { - if( use_builtin && - builtin_exists(args.at(0).completion)) - { - p->type = INTERNAL_BUILTIN; - is_new_block |= parser_keywords_is_block( args.at( 0 ).completion ); - } - } - - if( (!p->type || (p->type == INTERNAL_EXEC) ) ) - { - /* - If we are not executing the current block, allow - non-existent commands. - */ + } + + if( !nxt_forbidden && has_nxt && function_exists( nxt ) ) + { + /* + Check if we have reached the maximum recursion depth + */ + if( forbidden_function.size() > MAX_RECURSION_DEPTH ) + { + error( SYNTAX_ERROR, tok_get_pos( tok ), OVERFLOW_RECURSION_ERR_MSG ); + } + else + { + p->type = INTERNAL_FUNCTION; + } + } + } + args.push_back(completion_t(nxt)); + } + + if( error_code == 0 ) + { + if( !p->type ) + { + if( use_builtin && + builtin_exists(args.at(0).completion)) + { + p->type = INTERNAL_BUILTIN; + is_new_block |= parser_keywords_is_block( args.at( 0 ).completion ); + } + } + + if( (!p->type || (p->type == INTERNAL_EXEC) ) ) + { + /* + If we are not executing the current block, allow + non-existent commands. + */ if (current_block->skip && ! unskip) allow_bogus_command = true; //note this may already be true for other reasons - - if (allow_bogus_command) - { - p->actual_cmd.clear(); - } - else - { - int err; + + if (allow_bogus_command) + { + p->actual_cmd.clear(); + } + else + { + int err; bool has_command = path_get_path(args.at(0).completion, &p->actual_cmd); - err = errno; - + err = errno; + bool use_implicit_cd = false; if (! has_command) { @@ -2063,7 +2063,7 @@ int parser_t::parse_job( process_t *p, args.clear(); args.push_back(completion_t(L"cd")); args.push_back(completion_t(implicit_cd_path)); - + /* If we have defined a wrapper around cd, use it, otherwise use the cd builtin */ if (use_function && function_exists(L"cd")) p->type = INTERNAL_FUNCTION; @@ -2071,17 +2071,17 @@ int parser_t::parse_job( process_t *p, p->type = INTERNAL_BUILTIN; } } - - /* Check if the specified command exists */ - if( ! has_command && ! use_implicit_cd ) - { - - int tmp; + + /* Check if the specified command exists */ + if( ! has_command && ! use_implicit_cd ) + { + + int tmp; const wchar_t *cmd = args.at( 0 ).completion.c_str(); - - /* + + /* We couldn't find the specified command. - + What we want to happen now is that the specified job won't get executed, and an error message is printed on-screen, but @@ -2101,20 +2101,20 @@ int parser_t::parse_job( process_t *p, wchar_t *cpy = wcsdup( cmd ); wchar_t *valpart = wcschr( cpy, L'=' ); *valpart++=0; - + debug( 0, COMMAND_ASSIGN_ERR_MSG, cmd, cpy, valpart); free(cpy); - + } else if(cmd[0]==L'$') { - + const env_var_t val_wstr = env_get_string( cmd+1 ); - const wchar_t *val = val_wstr.missing() ? NULL : val_wstr.c_str(); + const wchar_t *val = val_wstr.missing() ? NULL : val_wstr.c_str(); if( val ) { debug( 0, @@ -2128,7 +2128,7 @@ int parser_t::parse_job( process_t *p, debug( 0, _(L"Variables may not be used as commands. Instead, define a function. See the help section for the function command by typing 'help function'." ), cmd ); - } + } } else if(wcschr( cmd, L'$' )) { @@ -2144,155 +2144,155 @@ int parser_t::parse_job( process_t *p, cmd?cmd:L"UNKNOWN" ); } else - { + { debug( 0, _(L"Unknown command '%ls'"), cmd?cmd:L"UNKNOWN" ); } - + tmp = current_tokenizer_pos; current_tokenizer_pos = tok_get_pos(tok); - + fwprintf( stderr, L"%ls", parser_t::current_line() ); - + current_tokenizer_pos=tmp; - + job_set_flag( j, JOB_SKIP, 1 ); event_fire_generic(L"fish_command_not_found", (wchar_t *)( args.at( 0 ).completion.c_str() ) ); proc_set_last_status( err==ENOENT?STATUS_UNKNOWN_COMMAND:STATUS_NOT_EXECUTABLE ); - } - } - } - - if( (p->type == EXTERNAL) && !use_command ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - UNKNOWN_BUILTIN_ERR_MSG, - args.back().completion.c_str() ); - } - } - - - if( is_new_block ) - { - - const wchar_t *end=parser_find_end( tok_string( tok ) + - current_tokenizer_pos ); - tokenizer subtok; - int make_sub_block = j->first_process != p; - - if( !end ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - BLOCK_END_ERR_MSG ); - - } - else - { - - if( !make_sub_block ) - { - int done=0; - - for( tok_init( &subtok, end, 0 ); - !done && tok_has_next( &subtok ); - tok_next( &subtok ) ) - { - - switch( tok_last_type( &subtok ) ) - { - case TOK_END: - done = 1; - break; - - case TOK_REDIRECT_OUT: - case TOK_REDIRECT_NOCLOB: - 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 ); - } - - if( make_sub_block ) - { - - long end_pos = end-tok_string( tok ); + } + } + } + + if( (p->type == EXTERNAL) && !use_command ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + UNKNOWN_BUILTIN_ERR_MSG, + args.back().completion.c_str() ); + } + } + + + if( is_new_block ) + { + + const wchar_t *end=parser_find_end( tok_string( tok ) + + current_tokenizer_pos ); + tokenizer subtok; + int make_sub_block = j->first_process != p; + + if( !end ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + BLOCK_END_ERR_MSG ); + + } + else + { + + if( !make_sub_block ) + { + int done=0; + + for( tok_init( &subtok, end, 0 ); + !done && tok_has_next( &subtok ); + tok_next( &subtok ) ) + { + + switch( tok_last_type( &subtok ) ) + { + case TOK_END: + done = 1; + break; + + case TOK_REDIRECT_OUT: + case TOK_REDIRECT_NOCLOB: + 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 ); + } + + if( make_sub_block ) + { + + long end_pos = end-tok_string( tok ); const wcstring sub_block(tok_string( tok ) + current_tokenizer_pos, end_pos - current_tokenizer_pos); - - p->type = INTERNAL_BLOCK; - args.at( 0 ) = completion_t(sub_block); - - tok_set_pos( tok, (int)end_pos ); - - while( prev_block != current_block ) - { - parser_t::pop_block(); - } - - } - else tok_next( tok ); - } - - } - else tok_next( tok ); - - if( !error_code ) - { - if( p->type == INTERNAL_BUILTIN && parser_keywords_skip_arguments(args.at(0).completion)) - { - if( !p->get_argv() ) + + p->type = INTERNAL_BLOCK; + args.at( 0 ) = completion_t(sub_block); + + tok_set_pos( tok, (int)end_pos ); + + while( prev_block != current_block ) + { + parser_t::pop_block(); + } + + } + else tok_next( tok ); + } + + } + else tok_next( tok ); + + if( !error_code ) + { + if( p->type == INTERNAL_BUILTIN && parser_keywords_skip_arguments(args.at(0).completion)) + { + if( !p->get_argv() ) p->set_argv(completions_to_wcstring_list(args)); - } - else - { - parse_job_argument_list(p, j, tok, args, unskip); - } - } - - if( !error_code ) - { - if( !is_new_block ) - { - current_block->had_command = true; - } - } - - if( error_code ) - { - /* - Make sure the block stack is consistent - */ - while( prev_block != current_block ) - { - parser_t::pop_block(); - } - } - current_tokenizer_pos = prev_tokenizer_pos; - return !error_code; + } + else + { + parse_job_argument_list(p, j, tok, args, unskip); + } + } + + if( !error_code ) + { + if( !is_new_block ) + { + current_block->had_command = true; + } + } + + if( error_code ) + { + /* + Make sure the block stack is consistent + */ + while( prev_block != current_block ) + { + parser_t::pop_block(); + } + } + current_tokenizer_pos = prev_tokenizer_pos; + return !error_code; } /** @@ -2305,32 +2305,32 @@ int parser_t::parse_job( process_t *p, */ void parser_t::skipped_exec( job_t * j ) { - process_t *p; + process_t *p; /* Handle other skipped guys */ - for( p = j->first_process; p; p=p->next ) - { - if( p->type == INTERNAL_BUILTIN ) - { - if(( wcscmp( p->argv0(), L"for" )==0) || - ( wcscmp( p->argv0(), L"switch" )==0) || - ( wcscmp( p->argv0(), L"begin" )==0) || - ( wcscmp( p->argv0(), L"function" )==0)) - { - this->push_block( new fake_block_t() ); - } - else if( wcscmp( p->argv0(), L"end" )==0) - { - if(!current_block->outer->skip ) - { - exec( *this, j ); - return; - } - parser_t::pop_block(); - } - else if( wcscmp( p->argv0(), L"else" )==0) - { - if (current_block->type() == IF) + for( p = j->first_process; p; p=p->next ) + { + if( p->type == INTERNAL_BUILTIN ) + { + if(( wcscmp( p->argv0(), L"for" )==0) || + ( wcscmp( p->argv0(), L"switch" )==0) || + ( wcscmp( p->argv0(), L"begin" )==0) || + ( wcscmp( p->argv0(), L"function" )==0)) + { + this->push_block( new fake_block_t() ); + } + else if( wcscmp( p->argv0(), L"end" )==0) + { + if(!current_block->outer->skip ) + { + exec( *this, j ); + return; + } + parser_t::pop_block(); + } + else if( wcscmp( p->argv0(), L"else" )==0) + { + if (current_block->type() == IF) { /* Evaluate this ELSE if the IF expression failed, and so has every ELSEIF (if any) expression thus far */ const if_block_t *ib = static_cast<const if_block_t*>(current_block); @@ -2341,17 +2341,17 @@ void parser_t::skipped_exec( job_t * j ) } } } - else if( wcscmp( p->argv0(), L"case" )==0) - { - if(current_block->type() == SWITCH) - { - exec( *this, j ); - return; - } - } - } - } - job_free( j ); + else if( wcscmp( p->argv0(), L"case" )==0) + { + if(current_block->type() == SWITCH) + { + exec( *this, j ); + return; + } + } + } + } + job_free( j ); } /* Return whether we should skip the current block, if it is an elseif. */ @@ -2366,10 +2366,10 @@ static bool job_should_skip_elseif(const job_t *job, const block_t *current_bloc { /* We are an IF block */ const if_block_t *ib = static_cast<const if_block_t *>(current_block); - + /* Execute this ELSEIF if the IF expression has been evaluated, it evaluated to false, and all ELSEIFs so far have evaluated to false. */ bool execute_elseif = (ib->if_expr_evaluated && ! ib->any_branch_taken); - + /* Invert the sense */ return ! execute_elseif; } @@ -2385,83 +2385,83 @@ static bool job_should_skip_elseif(const job_t *job, const block_t *current_bloc void parser_t::eval_job( tokenizer *tok ) { ASSERT_IS_MAIN_THREAD(); - job_t *j; + job_t *j; + + int start_pos = job_start_pos = tok_get_pos( tok ); + long long t1=0, t2=0, t3=0; + - int start_pos = job_start_pos = tok_get_pos( tok ); - long long t1=0, t2=0, t3=0; - - profile_item_t *profile_item = NULL; - bool skip = false; - int job_begin_pos, prev_tokenizer_pos; - const bool do_profile = profile; - - if( do_profile ) - { + bool skip = false; + int job_begin_pos, prev_tokenizer_pos; + const bool do_profile = profile; + + if( do_profile ) + { profile_items.resize(profile_items.size() + 1); profile_item = &profile_items.back(); profile_item->cmd = L""; - profile_item->skipped = 1; - t1 = get_time(); - } - - switch( tok_last_type( tok ) ) - { - case TOK_STRING: - { - j = this->job_create(); - job_set_flag( j, JOB_FOREGROUND, 1 ); - job_set_flag( j, JOB_TERMINAL, job_get_flag( j, JOB_CONTROL ) ); - job_set_flag( j, JOB_TERMINAL, job_get_flag( j, JOB_CONTROL ) \ - && (!is_subshell && !is_event)); - job_set_flag( j, JOB_SKIP_NOTIFICATION, is_subshell \ - || is_block \ - || is_event \ - || (!get_is_interactive())); - - current_block->job = j; - - if( get_is_interactive() ) - { - if( tcgetattr (0, &j->tmodes) ) - { - tok_next( tok ); - wperror( L"tcgetattr" ); - job_free( j ); - break; - } - } - - j->first_process = new process_t(); - job_begin_pos = tok_get_pos( tok ); - - if( parse_job( j->first_process, j, tok ) && - j->first_process->get_argv() ) - { - if( job_start_pos < tok_get_pos( tok ) ) - { - long stop_pos = tok_get_pos( tok ); - const wchar_t *newline = wcschr(tok_string(tok)+start_pos, L'\n'); - if( newline ) - stop_pos = mini<long>( stop_pos, newline - tok_string(tok) ); - - j->set_command(wcstring(tok_string(tok)+start_pos, stop_pos-start_pos)); - } - else - j->set_command(L""); - - if( do_profile ) - { - t2 = get_time(); - profile_item->cmd = wcsdup( j->command_wcstr() ); - profile_item->skipped=current_block->skip; - } - + profile_item->skipped = 1; + t1 = get_time(); + } + + switch( tok_last_type( tok ) ) + { + case TOK_STRING: + { + j = this->job_create(); + job_set_flag( j, JOB_FOREGROUND, 1 ); + job_set_flag( j, JOB_TERMINAL, job_get_flag( j, JOB_CONTROL ) ); + job_set_flag( j, JOB_TERMINAL, job_get_flag( j, JOB_CONTROL ) \ + && (!is_subshell && !is_event)); + job_set_flag( j, JOB_SKIP_NOTIFICATION, is_subshell \ + || is_block \ + || is_event \ + || (!get_is_interactive())); + + current_block->job = j; + + if( get_is_interactive() ) + { + if( tcgetattr (0, &j->tmodes) ) + { + tok_next( tok ); + wperror( L"tcgetattr" ); + job_free( j ); + break; + } + } + + j->first_process = new process_t(); + job_begin_pos = tok_get_pos( tok ); + + if( parse_job( j->first_process, j, tok ) && + j->first_process->get_argv() ) + { + if( job_start_pos < tok_get_pos( tok ) ) + { + long stop_pos = tok_get_pos( tok ); + const wchar_t *newline = wcschr(tok_string(tok)+start_pos, L'\n'); + if( newline ) + stop_pos = mini<long>( stop_pos, newline - tok_string(tok) ); + + j->set_command(wcstring(tok_string(tok)+start_pos, stop_pos-start_pos)); + } + else + j->set_command(L""); + + if( do_profile ) + { + t2 = get_time(); + profile_item->cmd = wcsdup( j->command_wcstr() ); + profile_item->skipped=current_block->skip; + } + /* If we're an ELSEIF, then we may want to unskip, if we're skipping because of an IF */ if (job_get_flag(j, JOB_ELSEIF)) { bool skip_elseif = job_should_skip_elseif(j, current_block); - + /* Record that we're entering an elseif */ if (! skip_elseif) { @@ -2469,62 +2469,62 @@ void parser_t::eval_job( tokenizer *tok ) assert(current_block->type() == IF); static_cast<if_block_t *>(current_block)->is_elseif_entry = true; } - + /* Record that in the block too. This is similar to what builtin_else does. */ current_block->skip = skip_elseif; } - + skip = skip || current_block->skip; - skip = skip || job_get_flag( j, JOB_WILDCARD_ERROR ); - skip = skip || job_get_flag( j, JOB_SKIP ); - - if(!skip ) - { - int was_builtin = 0; - if( j->first_process->type==INTERNAL_BUILTIN && !j->first_process->next) - was_builtin = 1; - prev_tokenizer_pos = current_tokenizer_pos; - current_tokenizer_pos = job_begin_pos; - exec( *this, j ); - current_tokenizer_pos = prev_tokenizer_pos; - - /* Only external commands require a new fishd barrier */ - if( !was_builtin ) - set_proc_had_barrier(false); - } - else - { - this->skipped_exec( j ); - } - - if( do_profile ) - { - t3 = get_time(); - profile_item->level=eval_level; - profile_item->parse = (int)(t2-t1); - profile_item->exec=(int)(t3-t2); - } - - if( current_block->type() == WHILE ) - { + skip = skip || job_get_flag( j, JOB_WILDCARD_ERROR ); + skip = skip || job_get_flag( j, JOB_SKIP ); + + if(!skip ) + { + int was_builtin = 0; + if( j->first_process->type==INTERNAL_BUILTIN && !j->first_process->next) + was_builtin = 1; + prev_tokenizer_pos = current_tokenizer_pos; + current_tokenizer_pos = job_begin_pos; + exec( *this, j ); + current_tokenizer_pos = prev_tokenizer_pos; + + /* Only external commands require a new fishd barrier */ + if( !was_builtin ) + set_proc_had_barrier(false); + } + else + { + this->skipped_exec( j ); + } + + if( do_profile ) + { + t3 = get_time(); + profile_item->level=eval_level; + profile_item->parse = (int)(t2-t1); + profile_item->exec=(int)(t3-t2); + } + + if( current_block->type() == WHILE ) + { while_block_t *wb = static_cast<while_block_t *>(current_block); - switch( wb->status ) - { - case WHILE_TEST_FIRST: - { - // PCA I added the 'wb->skip ||' part because we couldn't reliably - // control-C out of loops like this: while test 1 -eq 1; end - wb->skip = wb->skip || proc_get_last_status()!= 0; - wb->status = WHILE_TESTED; - } - break; - } - } - - if( current_block->type() == IF ) - { - if_block_t *ib = static_cast<if_block_t *>(current_block); - + switch( wb->status ) + { + case WHILE_TEST_FIRST: + { + // PCA I added the 'wb->skip ||' part because we couldn't reliably + // control-C out of loops like this: while test 1 -eq 1; end + wb->skip = wb->skip || proc_get_last_status()!= 0; + wb->status = WHILE_TESTED; + } + break; + } + } + + if( current_block->type() == IF ) + { + if_block_t *ib = static_cast<if_block_t *>(current_block); + if (ib->skip) { /* Nothing */ @@ -2534,10 +2534,10 @@ void parser_t::eval_job( tokenizer *tok ) /* Execute the IF */ bool if_result = (proc_get_last_status() == 0); ib->any_branch_taken = if_result; - + /* Don't execute if the expression failed */ - current_block->skip = ! if_result; - ib->if_expr_evaluated = true; + current_block->skip = ! if_result; + ib->if_expr_evaluated = true; } else if (ib->is_elseif_entry && ! ib->any_branch_taken) { @@ -2547,200 +2547,200 @@ void parser_t::eval_job( tokenizer *tok ) current_block->skip = ! elseif_taken; ib->is_elseif_entry = false; } - } - - } - else - { - /* - This job could not be properly parsed. We free it - instead, and set the status to 1. This should be - rare, since most errors should be detected by the - ahead of time validator. - */ - job_free( j ); - - proc_set_last_status( 1 ); - } - current_block->job = 0; - break; - } - - case TOK_END: - { - if( tok_has_next( tok )) - tok_next( tok ); - break; - } - - case TOK_BACKGROUND: - { - const wchar_t *str = tok_string( tok ); - if( tok_get_pos(tok)>0 && str[tok_get_pos(tok)-1] == L'&' ) - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - CMD_AND_ERR_MSG, - tok_get_desc( tok_last_type(tok) ) ); - } - else - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(tok) ) ); - } - - return; - } - - case TOK_ERROR: - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - TOK_ERR_MSG, - tok_last(tok) ); - - return; - } - - default: - { - error( SYNTAX_ERROR, - tok_get_pos( tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(tok)) ); - - return; - } - } - - job_reap( 0 ); + } + + } + else + { + /* + This job could not be properly parsed. We free it + instead, and set the status to 1. This should be + rare, since most errors should be detected by the + ahead of time validator. + */ + job_free( j ); + + proc_set_last_status( 1 ); + } + current_block->job = 0; + break; + } + + case TOK_END: + { + if( tok_has_next( tok )) + tok_next( tok ); + break; + } + + case TOK_BACKGROUND: + { + const wchar_t *str = tok_string( tok ); + if( tok_get_pos(tok)>0 && str[tok_get_pos(tok)-1] == L'&' ) + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + CMD_AND_ERR_MSG, + tok_get_desc( tok_last_type(tok) ) ); + } + else + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(tok) ) ); + } + + return; + } + + case TOK_ERROR: + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + TOK_ERR_MSG, + tok_last(tok) ); + + return; + } + + default: + { + error( SYNTAX_ERROR, + tok_get_pos( tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(tok)) ); + + return; + } + } + + job_reap( 0 ); } int parser_t::eval( const wcstring &cmdStr, const io_chain_t &io, enum block_type_t block_type ) { const wchar_t * const cmd = cmdStr.c_str(); - size_t forbid_count; - int code; - tokenizer *previous_tokenizer=current_tokenizer; - block_t *start_current_block = current_block; - + size_t forbid_count; + int code; + tokenizer *previous_tokenizer=current_tokenizer; + block_t *start_current_block = current_block; + /* Record the current chain so we can put it back later */ const io_chain_t prev_io = block_io; block_io = io; - + std::vector<wcstring> prev_forbidden = forbidden_function; - if( block_type == SUBST ) - { - forbidden_function.clear(); - } - - CHECK_BLOCK( 1 ); - - forbid_count = forbidden_function.size(); - - block_io = io; - - job_reap( 0 ); - - debug( 4, L"eval: %ls", cmd ); - - if( !cmd ) - { - debug( 1, - EVAL_NULL_ERR_MSG ); - bugreport(); - return 1; - } - - if( (block_type != TOP) && - (block_type != SUBST)) - { - debug( 1, - INVALID_SCOPE_ERR_MSG, - parser_t::get_block_desc( block_type ) ); - bugreport(); - return 1; - } - - eval_level++; - - this->push_block( new scope_block_t(block_type) ); - - current_tokenizer = new tokenizer; - tok_init( current_tokenizer, cmd, 0 ); - - error_code = 0; - - event_fire( NULL ); - - while( tok_has_next( current_tokenizer ) && - !error_code && - !sanity_check() && - !exit_status() ) - { - this->eval_job( current_tokenizer ); - event_fire( NULL ); - } - - parser_t::pop_block(); - - while( start_current_block != current_block ) - { - if( current_block == 0 ) - { - debug( 0, - _(L"End of block mismatch. Program terminating.") ); - bugreport(); - FATAL_EXIT(); - break; - } - - if( (!error_code) && (!exit_status()) && (!proc_get_last_status()) ) - { - - //debug( 2, L"Status %d\n", proc_get_last_status() ); - - debug( 1, - L"%ls", parser_t::get_block_desc( current_block->type() ) ); - debug( 1, - BLOCK_END_ERR_MSG ); - fwprintf( stderr, L"%ls", parser_t::current_line() ); - - const wcstring h = builtin_help_get( *this, L"end" ); - if( h.size() ) - fwprintf( stderr, L"%ls", h.c_str() ); - break; - - } - parser_t::pop_block(); - } - - this->print_errors_stderr(); - - tok_destroy( current_tokenizer ); - delete current_tokenizer; + if( block_type == SUBST ) + { + forbidden_function.clear(); + } + + CHECK_BLOCK( 1 ); + + forbid_count = forbidden_function.size(); + + block_io = io; + + job_reap( 0 ); + + debug( 4, L"eval: %ls", cmd ); + + if( !cmd ) + { + debug( 1, + EVAL_NULL_ERR_MSG ); + bugreport(); + return 1; + } + + if( (block_type != TOP) && + (block_type != SUBST)) + { + debug( 1, + INVALID_SCOPE_ERR_MSG, + parser_t::get_block_desc( block_type ) ); + bugreport(); + return 1; + } + + eval_level++; + + this->push_block( new scope_block_t(block_type) ); + + current_tokenizer = new tokenizer; + tok_init( current_tokenizer, cmd, 0 ); + + error_code = 0; + + event_fire( NULL ); + + while( tok_has_next( current_tokenizer ) && + !error_code && + !sanity_check() && + !exit_status() ) + { + this->eval_job( current_tokenizer ); + event_fire( NULL ); + } + + parser_t::pop_block(); + + while( start_current_block != current_block ) + { + if( current_block == 0 ) + { + debug( 0, + _(L"End of block mismatch. Program terminating.") ); + bugreport(); + FATAL_EXIT(); + break; + } + + if( (!error_code) && (!exit_status()) && (!proc_get_last_status()) ) + { + + //debug( 2, L"Status %d\n", proc_get_last_status() ); + + debug( 1, + L"%ls", parser_t::get_block_desc( current_block->type() ) ); + debug( 1, + BLOCK_END_ERR_MSG ); + fwprintf( stderr, L"%ls", parser_t::current_line() ); + + const wcstring h = builtin_help_get( *this, L"end" ); + if( h.size() ) + fwprintf( stderr, L"%ls", h.c_str() ); + break; + + } + parser_t::pop_block(); + } + + this->print_errors_stderr(); + + tok_destroy( current_tokenizer ); + delete current_tokenizer; while (forbidden_function.size() > forbid_count) - parser_t::allow_function(); + parser_t::allow_function(); - /* - Restore previous eval state - */ - forbidden_function = prev_forbidden; - current_tokenizer=previous_tokenizer; - block_io = prev_io; - eval_level--; + /* + Restore previous eval state + */ + forbidden_function = prev_forbidden; + current_tokenizer=previous_tokenizer; + block_io = prev_io; + eval_level--; - code=error_code; - error_code=0; + code=error_code; + error_code=0; - job_reap( 0 ); + job_reap( 0 ); - return code; + return code; } @@ -2749,16 +2749,16 @@ int parser_t::eval( const wcstring &cmdStr, const io_chain_t &io, enum block_typ */ block_type_t parser_get_block_type( const wcstring &cmd ) { - int i; - - for( i=0; block_lookup[i].desc; i++ ) - { - if( block_lookup[i].name && cmd == block_lookup[i].name ) - { - return block_lookup[i].type; - } - } - return (block_type_t)-1; + int i; + + for( i=0; block_lookup[i].desc; i++ ) + { + if( block_lookup[i].name && cmd == block_lookup[i].name ) + { + return block_lookup[i].type; + } + } + return (block_type_t)-1; } /** @@ -2766,16 +2766,16 @@ block_type_t parser_get_block_type( const wcstring &cmd ) */ const wchar_t *parser_get_block_command( int type ) { - int i; - - for( i=0; block_lookup[i].desc; i++ ) - { - if( block_lookup[i].type == type ) - { - return block_lookup[i].name; - } - } - return 0; + int i; + + for( i=0; block_lookup[i].desc; i++ ) + { + if( block_lookup[i].type == type ) + { + return block_lookup[i].name; + } + } + return 0; } /** @@ -2785,349 +2785,349 @@ const wchar_t *parser_get_block_command( int type ) */ int parser_t::parser_test_argument( const wchar_t *arg, wcstring *out, const wchar_t *prefix, int offset ) { - wchar_t *unesc; - wchar_t *pos; - int err=0; - - wchar_t *paran_begin, *paran_end; - wchar_t *arg_cpy; - int do_loop = 1; - - CHECK( arg, 1 ); - - arg_cpy = wcsdup( arg ); - - while( do_loop ) - { - switch( parse_util_locate_cmdsubst(arg_cpy, - ¶n_begin, - ¶n_end, - 0 ) ) - { - case -1: - err=1; - if( out ) - { - error( SYNTAX_ERROR, - offset, - L"Mismatched parenthesis" ); - this->print_errors( *out, prefix); - } - free( arg_cpy ); - return err; - - case 0: - do_loop = 0; - break; - - case 1: - { - - wchar_t *subst = wcsndup( paran_begin+1, paran_end-paran_begin-1 ); - wcstring tmp; - - tmp.append(arg_cpy, paran_begin - arg_cpy); - tmp.push_back(INTERNAL_SEPARATOR); + wchar_t *unesc; + wchar_t *pos; + int err=0; + + wchar_t *paran_begin, *paran_end; + wchar_t *arg_cpy; + int do_loop = 1; + + CHECK( arg, 1 ); + + arg_cpy = wcsdup( arg ); + + while( do_loop ) + { + switch( parse_util_locate_cmdsubst(arg_cpy, + ¶n_begin, + ¶n_end, + 0 ) ) + { + case -1: + err=1; + if( out ) + { + error( SYNTAX_ERROR, + offset, + L"Mismatched parenthesis" ); + this->print_errors( *out, prefix); + } + free( arg_cpy ); + return err; + + case 0: + do_loop = 0; + break; + + case 1: + { + + wchar_t *subst = wcsndup( paran_begin+1, paran_end-paran_begin-1 ); + wcstring tmp; + + tmp.append(arg_cpy, paran_begin - arg_cpy); + tmp.push_back(INTERNAL_SEPARATOR); tmp.append(paran_end+1); - -// debug( 1, L"%ls -> %ls %ls", arg_cpy, subst, tmp.buff ); - - err |= parser_t::test( subst, 0, out, prefix ); - - free( subst ); - free( arg_cpy ); - arg_cpy = wcsdup(tmp.c_str()); - - /* - Do _not_ call sb_destroy on this stringbuffer - it's - buffer is used as the new 'arg_cpy'. It is free'd at - the end of the loop. - */ - break; - } - } - } - - unesc = unescape( arg_cpy, 1 ); - if( !unesc ) - { - if( out ) - { - error( SYNTAX_ERROR, - offset, - L"Invalid token '%ls'", arg_cpy ); - print_errors( *out, prefix); - } - return 1; - } - else - { - /* - Check for invalid variable expansions - */ - for( pos = unesc; *pos; pos++ ) - { - switch( *pos ) - { - case VARIABLE_EXPAND: - case VARIABLE_EXPAND_SINGLE: - { - wchar_t n = *(pos+1); - - if( n != VARIABLE_EXPAND && - n != VARIABLE_EXPAND_SINGLE && - !wcsvarchr(n) ) - { - err=1; - if( out ) - { - expand_variable_error( *this, unesc, pos-unesc, offset ); - print_errors( *out, prefix); - } - } - - break; - } - } - } - } - - free( arg_cpy ); - - free( unesc ); - return err; - + +// debug( 1, L"%ls -> %ls %ls", arg_cpy, subst, tmp.buff ); + + err |= parser_t::test( subst, 0, out, prefix ); + + free( subst ); + free( arg_cpy ); + arg_cpy = wcsdup(tmp.c_str()); + + /* + Do _not_ call sb_destroy on this stringbuffer - it's + buffer is used as the new 'arg_cpy'. It is free'd at + the end of the loop. + */ + break; + } + } + } + + unesc = unescape( arg_cpy, 1 ); + if( !unesc ) + { + if( out ) + { + error( SYNTAX_ERROR, + offset, + L"Invalid token '%ls'", arg_cpy ); + print_errors( *out, prefix); + } + return 1; + } + else + { + /* + Check for invalid variable expansions + */ + for( pos = unesc; *pos; pos++ ) + { + switch( *pos ) + { + case VARIABLE_EXPAND: + case VARIABLE_EXPAND_SINGLE: + { + wchar_t n = *(pos+1); + + if( n != VARIABLE_EXPAND && + n != VARIABLE_EXPAND_SINGLE && + !wcsvarchr(n) ) + { + err=1; + if( out ) + { + expand_variable_error( *this, unesc, pos-unesc, offset ); + print_errors( *out, prefix); + } + } + + break; + } + } + } + } + + free( arg_cpy ); + + free( unesc ); + return err; + } int parser_t::test_args(const wchar_t * buff, wcstring *out, const wchar_t *prefix ) { - tokenizer tok; - tokenizer *previous_tokenizer = current_tokenizer; - int previous_pos = current_tokenizer_pos; - int do_loop = 1; - int err = 0; - - CHECK( buff, 1 ); - - current_tokenizer = &tok; - - for( tok_init( &tok, buff, 0 ); - do_loop && tok_has_next( &tok ); - tok_next( &tok ) ) - { - current_tokenizer_pos = tok_get_pos( &tok ); - switch( tok_last_type( &tok ) ) - { - - case TOK_STRING: - { - err |= parser_test_argument( tok_last( &tok ), out, prefix, tok_get_pos( &tok ) ); - break; - } - - case TOK_END: - { - break; - } - - case TOK_ERROR: - { - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - TOK_ERR_MSG, - tok_last(&tok) ); - print_errors( *out, prefix ); - } - err=1; - do_loop=0; - break; - } - - default: - { - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - UNEXPECTED_TOKEN_ERR_MSG, - tok_get_desc( tok_last_type(&tok)) ); - print_errors( *out, prefix ); - } - err=1; - do_loop=0; - break; - } - } - } - - tok_destroy( &tok ); - - current_tokenizer=previous_tokenizer; - current_tokenizer_pos = previous_pos; - - error_code=0; - - return err; + tokenizer tok; + tokenizer *previous_tokenizer = current_tokenizer; + int previous_pos = current_tokenizer_pos; + int do_loop = 1; + int err = 0; + + CHECK( buff, 1 ); + + current_tokenizer = &tok; + + for( tok_init( &tok, buff, 0 ); + do_loop && tok_has_next( &tok ); + tok_next( &tok ) ) + { + current_tokenizer_pos = tok_get_pos( &tok ); + switch( tok_last_type( &tok ) ) + { + + case TOK_STRING: + { + err |= parser_test_argument( tok_last( &tok ), out, prefix, tok_get_pos( &tok ) ); + break; + } + + case TOK_END: + { + break; + } + + case TOK_ERROR: + { + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + TOK_ERR_MSG, + tok_last(&tok) ); + print_errors( *out, prefix ); + } + err=1; + do_loop=0; + break; + } + + default: + { + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + UNEXPECTED_TOKEN_ERR_MSG, + tok_get_desc( tok_last_type(&tok)) ); + print_errors( *out, prefix ); + } + err=1; + do_loop=0; + break; + } + } + } + + tok_destroy( &tok ); + + current_tokenizer=previous_tokenizer; + current_tokenizer_pos = previous_pos; + + error_code=0; + + return err; } int parser_t::test( const wchar_t * buff, - int *block_level, - wcstring *out, - const wchar_t *prefix ) + int *block_level, + wcstring *out, + const wchar_t *prefix ) { ASSERT_IS_MAIN_THREAD(); - - tokenizer tok; - /* - Set to one if a command name has been given for the currently - parsed process specification - */ - int had_cmd=0; - int err=0; - int unfinished = 0; - - tokenizer *previous_tokenizer=current_tokenizer; - int previous_pos=current_tokenizer_pos; - - int block_pos[BLOCK_MAX_COUNT] = {}; - block_type_t block_type[BLOCK_MAX_COUNT] = {}; - int count = 0; - int res = 0; - - /* - Set to 1 if the current command is inside a pipeline - */ - int is_pipeline = 0; - - /* - Set to one if the currently specified process can not be used inside a pipeline - */ - int forbid_pipeline = 0; - - /* - Set to one if an additional process specification is needed - */ - bool needs_cmd = false; - - /* - Counter on the number of arguments this function has encountered - so far. Is set to -1 when the count is unknown, i.e. after - encountering an argument that contains substitutions that can - expand to more/less arguemtns then 1. - */ - int arg_count=0; - - /* - The currently validated command. - */ + + tokenizer tok; + /* + Set to one if a command name has been given for the currently + parsed process specification + */ + int had_cmd=0; + int err=0; + int unfinished = 0; + + tokenizer *previous_tokenizer=current_tokenizer; + int previous_pos=current_tokenizer_pos; + + int block_pos[BLOCK_MAX_COUNT] = {}; + block_type_t block_type[BLOCK_MAX_COUNT] = {}; + int count = 0; + int res = 0; + + /* + Set to 1 if the current command is inside a pipeline + */ + int is_pipeline = 0; + + /* + Set to one if the currently specified process can not be used inside a pipeline + */ + int forbid_pipeline = 0; + + /* + Set to one if an additional process specification is needed + */ + bool needs_cmd = false; + + /* + Counter on the number of arguments this function has encountered + so far. Is set to -1 when the count is unknown, i.e. after + encountering an argument that contains substitutions that can + expand to more/less arguemtns then 1. + */ + int arg_count=0; + + /* + The currently validated command. + */ wcstring command; bool has_command = false; - - CHECK( buff, 1 ); - - if( block_level ) - { - size_t len = wcslen(buff); - for( size_t i=0; i<len; i++ ) - { - block_level[i] = -1; - } - - } - - current_tokenizer = &tok; - - for( tok_init( &tok, buff, 0 ); - ; - tok_next( &tok ) ) - { - current_tokenizer_pos = tok_get_pos( &tok ); - - int last_type = tok_last_type( &tok ); - int end_of_cmd = 0; - - switch( last_type ) - { - case TOK_STRING: - { - if( !had_cmd ) - { - int mark = tok_get_pos( &tok ); - had_cmd = 1; - arg_count=0; - + + CHECK( buff, 1 ); + + if( block_level ) + { + size_t len = wcslen(buff); + for( size_t i=0; i<len; i++ ) + { + block_level[i] = -1; + } + + } + + current_tokenizer = &tok; + + for( tok_init( &tok, buff, 0 ); + ; + tok_next( &tok ) ) + { + current_tokenizer_pos = tok_get_pos( &tok ); + + int last_type = tok_last_type( &tok ); + int end_of_cmd = 0; + + switch( last_type ) + { + case TOK_STRING: + { + if( !had_cmd ) + { + int mark = tok_get_pos( &tok ); + had_cmd = 1; + arg_count=0; + command = tok_last(&tok); has_command = expand_one(command, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES); - if( !has_command ) - { + if( !has_command ) + { command = L""; - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - ILLEGAL_CMD_ERR_MSG, - tok_last( &tok ) ); - - print_errors( *out, prefix ); - } - break; - } - - if( needs_cmd ) - { - /* - end is not a valid command when a followup - command is needed, such as after 'and' or - 'while' - */ - if( contains( command, - L"end" ) ) - { - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - COND_ERR_MSG ); - - print_errors( *out, prefix ); - } - } - - needs_cmd = false; - } - - /* - Decrement block count on end command - */ - if( command == L"end") - { - tok_next( &tok ); - count--; - tok_set_pos( &tok, mark ); - } - - /* - Store the block level. This needs to be done - _after_ checking for end commands, but _before_ - checking for block opening commands. - */ - bool is_else_or_elseif = (command == L"else"); - if( block_level ) - { - block_level[tok_get_pos( &tok )] = count + (is_else_or_elseif?-1:0); - } - - /* - Handle block commands - */ - if( parser_keywords_is_block( command ) ) - { - if( count >= BLOCK_MAX_COUNT ) - { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + ILLEGAL_CMD_ERR_MSG, + tok_last( &tok ) ); + + print_errors( *out, prefix ); + } + break; + } + + if( needs_cmd ) + { + /* + end is not a valid command when a followup + command is needed, such as after 'and' or + 'while' + */ + if( contains( command, + L"end" ) ) + { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + COND_ERR_MSG ); + + print_errors( *out, prefix ); + } + } + + needs_cmd = false; + } + + /* + Decrement block count on end command + */ + if( command == L"end") + { + tok_next( &tok ); + count--; + tok_set_pos( &tok, mark ); + } + + /* + Store the block level. This needs to be done + _after_ checking for end commands, but _before_ + checking for block opening commands. + */ + bool is_else_or_elseif = (command == L"else"); + if( block_level ) + { + block_level[tok_get_pos( &tok )] = count + (is_else_or_elseif?-1:0); + } + + /* + Handle block commands + */ + if( parser_keywords_is_block( command ) ) + { + if( count >= BLOCK_MAX_COUNT ) + { if (out) { error( SYNTAX_ERROR, tok_get_pos( &tok ), @@ -3135,325 +3135,325 @@ int parser_t::test( const wchar_t * buff, print_errors( *out, prefix ); } - } - else - { - block_type[count] = parser_get_block_type( command ); - block_pos[count] = current_tokenizer_pos; - tok_next( &tok ); - count++; - tok_set_pos( &tok, mark ); - } - } - - /* - If parser_keywords_is_subcommand is true, the command - accepts a second command as it's first - argument. If parser_skip_arguments is true, the - second argument is optional. - */ - if( parser_keywords_is_subcommand( command ) && !parser_keywords_skip_arguments(command ) ) - { - needs_cmd = true; - had_cmd = 0; - } - - if( contains( command, - L"or", - L"and" ) ) - { - /* - 'or' and 'and' can not be used inside pipelines - */ - if( is_pipeline ) - { - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - EXEC_ERR_MSG ); - - print_errors( *out, prefix ); - - } - } - } - - /* - There are a lot of situations where pipelines - are forbidden, including when using the exec - builtin. - */ - if( parser_is_pipe_forbidden( command ) ) - { - if( is_pipeline ) - { - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - EXEC_ERR_MSG ); - - print_errors( *out, prefix ); - - } - } - forbid_pipeline = 1; - } - - /* - Test that the case builtin is only used directly in a switch block - */ - if( command == L"case" ) - { - if( !count || block_type[count-1]!=SWITCH ) - { - err=1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - INVALID_CASE_ERR_MSG ); - - print_errors( *out, prefix); - const wcstring h = builtin_help_get( *this, L"case" ); - if( h.size() ) - append_format( *out, L"%ls", h.c_str() ); - } - } - } - - /* - Test that the return bultin is only used within function definitions - */ - if( command == L"return" ) - { - int found_func=0; - int i; - for( i=count-1; i>=0; i-- ) - { - if( block_type[i]==FUNCTION_DEF ) - { - found_func=1; - break; - } - } - - if( !found_func ) - { - /* - Peek to see if the next argument is - --help, in which case we'll allow it to - show the help. - */ - - int old_pos = tok_get_pos( &tok ); - int is_help = 0; - - tok_next( &tok ); - if( tok_last_type( &tok ) == TOK_STRING ) - { + } + else + { + block_type[count] = parser_get_block_type( command ); + block_pos[count] = current_tokenizer_pos; + tok_next( &tok ); + count++; + tok_set_pos( &tok, mark ); + } + } + + /* + If parser_keywords_is_subcommand is true, the command + accepts a second command as it's first + argument. If parser_skip_arguments is true, the + second argument is optional. + */ + if( parser_keywords_is_subcommand( command ) && !parser_keywords_skip_arguments(command ) ) + { + needs_cmd = true; + had_cmd = 0; + } + + if( contains( command, + L"or", + L"and" ) ) + { + /* + 'or' and 'and' can not be used inside pipelines + */ + if( is_pipeline ) + { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + EXEC_ERR_MSG ); + + print_errors( *out, prefix ); + + } + } + } + + /* + There are a lot of situations where pipelines + are forbidden, including when using the exec + builtin. + */ + if( parser_is_pipe_forbidden( command ) ) + { + if( is_pipeline ) + { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + EXEC_ERR_MSG ); + + print_errors( *out, prefix ); + + } + } + forbid_pipeline = 1; + } + + /* + Test that the case builtin is only used directly in a switch block + */ + if( command == L"case" ) + { + if( !count || block_type[count-1]!=SWITCH ) + { + err=1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + INVALID_CASE_ERR_MSG ); + + print_errors( *out, prefix); + const wcstring h = builtin_help_get( *this, L"case" ); + if( h.size() ) + append_format( *out, L"%ls", h.c_str() ); + } + } + } + + /* + Test that the return bultin is only used within function definitions + */ + if( command == L"return" ) + { + int found_func=0; + int i; + for( i=count-1; i>=0; i-- ) + { + if( block_type[i]==FUNCTION_DEF ) + { + found_func=1; + break; + } + } + + if( !found_func ) + { + /* + Peek to see if the next argument is + --help, in which case we'll allow it to + show the help. + */ + + int old_pos = tok_get_pos( &tok ); + int is_help = 0; + + tok_next( &tok ); + if( tok_last_type( &tok ) == TOK_STRING ) + { wcstring first_arg = tok_last(&tok); if (expand_one(first_arg, EXPAND_SKIP_CMDSUBST) && parser_t::is_help( first_arg.c_str(), 3)) - { - is_help = 1; - } - } - - tok_set_pos( &tok, old_pos ); - - if( !is_help ) - { - err=1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - INVALID_RETURN_ERR_MSG ); - print_errors( *out, prefix ); - } - } - } - } - - - /* - Test that break and continue are only used within loop blocks - */ - if( contains( command, L"break", L"continue" ) ) - { - int found_loop=0; - int i; - for( i=count-1; i>=0; i-- ) - { - if( (block_type[i]==WHILE) || - (block_type[i]==FOR) ) - { - found_loop=1; - break; - } - } - - if( !found_loop ) - { - /* - Peek to see if the next argument is - --help, in which case we'll allow it to - show the help. - */ - - int old_pos = tok_get_pos( &tok ); - int is_help = 0; - - tok_next( &tok ); - if( tok_last_type( &tok ) == TOK_STRING ) - { + { + is_help = 1; + } + } + + tok_set_pos( &tok, old_pos ); + + if( !is_help ) + { + err=1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + INVALID_RETURN_ERR_MSG ); + print_errors( *out, prefix ); + } + } + } + } + + + /* + Test that break and continue are only used within loop blocks + */ + if( contains( command, L"break", L"continue" ) ) + { + int found_loop=0; + int i; + for( i=count-1; i>=0; i-- ) + { + if( (block_type[i]==WHILE) || + (block_type[i]==FOR) ) + { + found_loop=1; + break; + } + } + + if( !found_loop ) + { + /* + Peek to see if the next argument is + --help, in which case we'll allow it to + show the help. + */ + + int old_pos = tok_get_pos( &tok ); + int is_help = 0; + + tok_next( &tok ); + if( tok_last_type( &tok ) == TOK_STRING ) + { wcstring first_arg = tok_last( &tok ); - if( expand_one(first_arg, EXPAND_SKIP_CMDSUBST) && parser_t::is_help( first_arg.c_str(), 3 ) ) - { - is_help = 1; - } - } - - tok_set_pos( &tok, old_pos ); - - if( !is_help ) - { - err=1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - INVALID_LOOP_ERR_MSG ); - print_errors( *out, prefix ); - } - } - } - } - - /* - Test that else and else-if are only used directly in an if-block - */ - if( command == L"else") - { - if( !count || block_type[count-1]!=IF ) - { - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - INVALID_ELSE_ERR_MSG, + if( expand_one(first_arg, EXPAND_SKIP_CMDSUBST) && parser_t::is_help( first_arg.c_str(), 3 ) ) + { + is_help = 1; + } + } + + tok_set_pos( &tok, old_pos ); + + if( !is_help ) + { + err=1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + INVALID_LOOP_ERR_MSG ); + print_errors( *out, prefix ); + } + } + } + } + + /* + Test that else and else-if are only used directly in an if-block + */ + if( command == L"else") + { + if( !count || block_type[count-1]!=IF ) + { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + INVALID_ELSE_ERR_MSG, command.c_str()); - print_errors( *out, prefix ); - } - } - } - - /* - Test that end is not used when not inside any block - */ - if( count < 0 ) - { - err = 1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - INVALID_END_ERR_MSG ); - print_errors( *out, prefix ); - const wcstring h = builtin_help_get( *this, L"end" ); - if( h.size() ) - append_format( *out, L"%ls", h.c_str() ); - } - } - - } - else - { - err |= parser_test_argument( tok_last( &tok ), out, prefix, tok_get_pos( &tok ) ); - - /* If possible, keep track of number of supplied arguments */ - if( arg_count >= 0 && expand_is_clean( tok_last( &tok ) ) ) - { - arg_count++; - } - else - { - arg_count = -1; - } - - if( has_command ) - { - - /* - Try to make sure the second argument to 'for' is 'in' - */ - if( command == L"for" ) - { - if( arg_count == 1 ) - { - - if( wcsvarname( tok_last( &tok )) ) - { - - err = 1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - BUILTIN_FOR_ERR_NAME, - L"for", - tok_last( &tok ) ); - - print_errors( *out, prefix ); - } - } - - } - else if( arg_count == 2 ) - { - if( wcscmp( tok_last( &tok ), L"in" ) != 0 ) - { - err = 1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - BUILTIN_FOR_ERR_IN, - L"for" ); - - print_errors( *out, prefix ); - } - } - } - } + print_errors( *out, prefix ); + } + } + } + + /* + Test that end is not used when not inside any block + */ + if( count < 0 ) + { + err = 1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + INVALID_END_ERR_MSG ); + print_errors( *out, prefix ); + const wcstring h = builtin_help_get( *this, L"end" ); + if( h.size() ) + append_format( *out, L"%ls", h.c_str() ); + } + } + + } + else + { + err |= parser_test_argument( tok_last( &tok ), out, prefix, tok_get_pos( &tok ) ); + + /* If possible, keep track of number of supplied arguments */ + if( arg_count >= 0 && expand_is_clean( tok_last( &tok ) ) ) + { + arg_count++; + } + else + { + arg_count = -1; + } + + if( has_command ) + { + + /* + Try to make sure the second argument to 'for' is 'in' + */ + if( command == L"for" ) + { + if( arg_count == 1 ) + { + + if( wcsvarname( tok_last( &tok )) ) + { + + err = 1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + BUILTIN_FOR_ERR_NAME, + L"for", + tok_last( &tok ) ); + + print_errors( *out, prefix ); + } + } + + } + else if( arg_count == 2 ) + { + if( wcscmp( tok_last( &tok ), L"in" ) != 0 ) + { + err = 1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + BUILTIN_FOR_ERR_IN, + L"for" ); + + print_errors( *out, prefix ); + } + } + } + } else if (command == L"else") { if (arg_count == 1) { /* Any second argument must be "if" */ - if (wcscmp(tok_last(&tok), L"if") != 0) - { - err = 1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - BUILTIN_ELSEIF_ERR_ARGUMENT, - L"else" ); - print_errors( *out, prefix ); - } - } + if (wcscmp(tok_last(&tok), L"if") != 0) + { + err = 1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + BUILTIN_ELSEIF_ERR_ARGUMENT, + L"else" ); + print_errors( *out, prefix ); + } + } else { /* Successfully detected "else if". Now we need a new command. */ @@ -3462,185 +3462,185 @@ int parser_t::test( const wchar_t * buff, } } } - } - - } - - break; - } - - case TOK_REDIRECT_OUT: - case TOK_REDIRECT_IN: - case TOK_REDIRECT_APPEND: - case TOK_REDIRECT_FD: - case TOK_REDIRECT_NOCLOB: - { - if( !had_cmd ) - { - err = 1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - INVALID_REDIRECTION_ERR_MSG ); - print_errors( *out, prefix ); - } - } - break; - } - - case TOK_END: - { - if( needs_cmd && !had_cmd ) - { - err = 1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(&tok))); - print_errors( *out, prefix ); - } - } - needs_cmd = false; - had_cmd = 0; - is_pipeline=0; - forbid_pipeline=0; - end_of_cmd = 1; - - break; - } - - case TOK_PIPE: - { - if( !had_cmd ) - { - err=1; - if( out ) - { - if( tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'|' ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - CMD_OR_ERR_MSG, - tok_get_desc( tok_last_type(&tok) ) ); - - } - else - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(&tok))); - } - - print_errors( *out, prefix ); - } - } - else if( forbid_pipeline ) - { - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - EXEC_ERR_MSG ); - - print_errors( *out, prefix ); - } - } - else - { - needs_cmd = true; - is_pipeline=1; - had_cmd=0; - end_of_cmd = 1; - - } - break; - } - - case TOK_BACKGROUND: - { - if( !had_cmd ) - { - err = 1; - if( out ) - { - if( tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'&' ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - CMD_AND_ERR_MSG, - tok_get_desc( tok_last_type(&tok) ) ); - - } - else - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - CMD_ERR_MSG, - tok_get_desc( tok_last_type(&tok))); - } - - print_errors( *out, prefix ); - } - } - - had_cmd = 0; - end_of_cmd = 1; - - break; - } - - case TOK_ERROR: - default: - if( tok_get_error( &tok ) == TOK_UNTERMINATED_QUOTE ) - { - unfinished = 1; - } - else - { - err = 1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - TOK_ERR_MSG, - tok_last(&tok) ); - - - print_errors( *out, prefix ); - } - } - - break; - } - - if( end_of_cmd ) - { - if( has_command && command == L"for" ) - { - if( arg_count >= 0 && arg_count < 2 ) - { - /* - Not enough arguments to the for builtin - */ - err = 1; - - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - BUILTIN_FOR_ERR_COUNT, - L"for", - arg_count ); - - print_errors( *out, prefix ); - } - } - } + } + + } + + break; + } + + case TOK_REDIRECT_OUT: + case TOK_REDIRECT_IN: + case TOK_REDIRECT_APPEND: + case TOK_REDIRECT_FD: + case TOK_REDIRECT_NOCLOB: + { + if( !had_cmd ) + { + err = 1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + INVALID_REDIRECTION_ERR_MSG ); + print_errors( *out, prefix ); + } + } + break; + } + + case TOK_END: + { + if( needs_cmd && !had_cmd ) + { + err = 1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(&tok))); + print_errors( *out, prefix ); + } + } + needs_cmd = false; + had_cmd = 0; + is_pipeline=0; + forbid_pipeline=0; + end_of_cmd = 1; + + break; + } + + case TOK_PIPE: + { + if( !had_cmd ) + { + err=1; + if( out ) + { + if( tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'|' ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + CMD_OR_ERR_MSG, + tok_get_desc( tok_last_type(&tok) ) ); + + } + else + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(&tok))); + } + + print_errors( *out, prefix ); + } + } + else if( forbid_pipeline ) + { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + EXEC_ERR_MSG ); + + print_errors( *out, prefix ); + } + } + else + { + needs_cmd = true; + is_pipeline=1; + had_cmd=0; + end_of_cmd = 1; + + } + break; + } + + case TOK_BACKGROUND: + { + if( !had_cmd ) + { + err = 1; + if( out ) + { + if( tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'&' ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + CMD_AND_ERR_MSG, + tok_get_desc( tok_last_type(&tok) ) ); + + } + else + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + CMD_ERR_MSG, + tok_get_desc( tok_last_type(&tok))); + } + + print_errors( *out, prefix ); + } + } + + had_cmd = 0; + end_of_cmd = 1; + + break; + } + + case TOK_ERROR: + default: + if( tok_get_error( &tok ) == TOK_UNTERMINATED_QUOTE ) + { + unfinished = 1; + } + else + { + err = 1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + TOK_ERR_MSG, + tok_last(&tok) ); + + + print_errors( *out, prefix ); + } + } + + break; + } + + if( end_of_cmd ) + { + if( has_command && command == L"for" ) + { + if( arg_count >= 0 && arg_count < 2 ) + { + /* + Not enough arguments to the for builtin + */ + err = 1; + + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + BUILTIN_FOR_ERR_COUNT, + L"for", + arg_count ); + + print_errors( *out, prefix ); + } + } + } else if (has_command && command == L"else") { if (arg_count == 1) @@ -3649,133 +3649,133 @@ int parser_t::test( const wchar_t * buff, err = true; if (out) { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - BUILTIN_ELSEIF_ERR_COUNT, - L"else", - arg_count ); - - print_errors( *out, prefix ); + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + BUILTIN_ELSEIF_ERR_COUNT, + L"else", + arg_count ); + + print_errors( *out, prefix ); } } } - - } - - if( !tok_has_next( &tok ) ) - break; - - } - - if( needs_cmd ) - { - err=1; - if( out ) - { - error( SYNTAX_ERROR, - tok_get_pos( &tok ), - COND_ERR_MSG ); - - print_errors( *out, prefix ); - } - } - - - if( out && count>0 ) - { - const wchar_t *cmd; - - error( SYNTAX_ERROR, - block_pos[count-1], - BLOCK_END_ERR_MSG ); - - print_errors( *out, prefix ); - - cmd = parser_get_block_command( block_type[count -1] ); - if( cmd ) - { - const wcstring h = builtin_help_get( *this, cmd ); - if( h.size() ) - { - append_format( *out, L"%ls", h.c_str() ); - } - } - - - } - - /* - Fill in the unset block_level entries. Until now, only places - where the block level _changed_ have been filled out. This fills - in the rest. - */ - - if( block_level ) - { - int last_level = 0; - size_t i, len = wcslen(buff); - for( i=0; i<len; i++ ) - { - if( block_level[i] >= 0 ) - { - last_level = block_level[i]; - /* - Make all whitespace before a token have the new - level. This avoid using the wrong indentation level - if a new line starts with whitespace. - */ + + } + + if( !tok_has_next( &tok ) ) + break; + + } + + if( needs_cmd ) + { + err=1; + if( out ) + { + error( SYNTAX_ERROR, + tok_get_pos( &tok ), + COND_ERR_MSG ); + + print_errors( *out, prefix ); + } + } + + + if( out && count>0 ) + { + const wchar_t *cmd; + + error( SYNTAX_ERROR, + block_pos[count-1], + BLOCK_END_ERR_MSG ); + + print_errors( *out, prefix ); + + cmd = parser_get_block_command( block_type[count -1] ); + if( cmd ) + { + const wcstring h = builtin_help_get( *this, cmd ); + if( h.size() ) + { + append_format( *out, L"%ls", h.c_str() ); + } + } + + + } + + /* + Fill in the unset block_level entries. Until now, only places + where the block level _changed_ have been filled out. This fills + in the rest. + */ + + if( block_level ) + { + int last_level = 0; + size_t i, len = wcslen(buff); + for( i=0; i<len; i++ ) + { + if( block_level[i] >= 0 ) + { + last_level = block_level[i]; + /* + Make all whitespace before a token have the new + level. This avoid using the wrong indentation level + if a new line starts with whitespace. + */ size_t prev_char_idx = i; while (prev_char_idx--) - { - if( !wcschr( L" \n\t\r", buff[prev_char_idx] ) ) - break; - block_level[prev_char_idx] = last_level; - } - } - block_level[i] = last_level; - } - - /* - Make all trailing whitespace have the block level that the - validator had at exit. This makes sure a new line is - correctly indented even if it is empty. - */ + { + if( !wcschr( L" \n\t\r", buff[prev_char_idx] ) ) + break; + block_level[prev_char_idx] = last_level; + } + } + block_level[i] = last_level; + } + + /* + Make all trailing whitespace have the block level that the + validator had at exit. This makes sure a new line is + correctly indented even if it is empty. + */ size_t suffix_idx = len; while (suffix_idx--) - { - if( !wcschr( L" \n\t\r", buff[suffix_idx] ) ) - break; - block_level[suffix_idx] = count; - } - } - - /* - Calculate exit status - */ - if( count!= 0 ) - unfinished = 1; - - if( err ) - res |= PARSER_TEST_ERROR; - - if( unfinished ) - res |= PARSER_TEST_INCOMPLETE; - - /* - Cleanup - */ - - tok_destroy( &tok ); - - current_tokenizer=previous_tokenizer; - current_tokenizer_pos = previous_pos; - - error_code=0; - - - return res; - + { + if( !wcschr( L" \n\t\r", buff[suffix_idx] ) ) + break; + block_level[suffix_idx] = count; + } + } + + /* + Calculate exit status + */ + if( count!= 0 ) + unfinished = 1; + + if( err ) + res |= PARSER_TEST_ERROR; + + if( unfinished ) + res |= PARSER_TEST_INCOMPLETE; + + /* + Cleanup + */ + + tok_destroy( &tok ); + + current_tokenizer=previous_tokenizer; + current_tokenizer_pos = previous_pos; + + error_code=0; + + + return res; + } block_t::block_t(block_type_t t) : |