From 312c7ab7b205e5d6792c8d9f0d1bd04c43341501 Mon Sep 17 00:00:00 2001 From: axel Date: Fri, 27 Jan 2006 00:48:10 +1000 Subject: [PATCH] Add function stack trace to error output darcs-hash:20060126144810-ac50b-3426191f596674504ce49dd61fcfa3c2c0c0f2bb.gz --- exec.c | 17 ++++- function.c | 47 ++++++++++++- function.h | 4 ++ main.c | 14 ++-- parser.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++----- parser.h | 9 ++- reader.c | 2 +- 7 files changed, 263 insertions(+), 33 deletions(-) diff --git a/exec.c b/exec.c index 73811e9c4..14553e92a 100644 --- a/exec.c +++ b/exec.c @@ -806,7 +806,7 @@ void exec( job_t *j ) wchar_t **arg; int i; string_buffer_t sb; - + const wchar_t * def = function_get_definition( p->argv[0] ); // fwprintf( stderr, L"run function %ls\n", argv[0] ); if( def == 0 ) @@ -814,14 +814,24 @@ void exec( job_t *j ) debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] ); break; } + + int lineno = parser_get_lineno(); + parser_push_block( FUNCTION_CALL ); + al_init( ¤t_block->param2.function_vars ); + current_block->param1.function_name = wcsdup( p->argv[0] ); + current_block->param3.function_lineno = lineno; + if( builtin_count_args(p->argv)>1 ) { sb_init( &sb ); for( i=1, arg=p->argv+1; *arg; i++, arg++ ) { + al_push( ¤t_block->param2.function_vars, + escape(*arg, 1) ); + if( i != 1 ) sb_append( &sb, ARRAY_SEP_STR ); sb_append( &sb, *arg ); @@ -830,6 +840,11 @@ void exec( job_t *j ) env_set( L"argv", (wchar_t *)sb.buff, ENV_LOCAL ); sb_destroy( &sb ); } + else + { + env_set( L"argv", 0, ENV_LOCAL ); + } + parser_forbid_function( p->argv[0] ); if( p->next ) diff --git a/function.c b/function.c index c18da3b8c..c9787cecc 100644 --- a/function.c +++ b/function.c @@ -17,6 +17,7 @@ #include "common.h" #include "intern.h" #include "event.h" +#include "reader.h" /** @@ -28,6 +29,8 @@ typedef struct wchar_t *cmd; /** Function description */ wchar_t *desc; + const wchar_t *definition_file; + int definition_offset; int is_binding; } function_data_t; @@ -62,6 +65,19 @@ void function_destroy() hash_destroy( &function ); } +static int count_lineno( const wchar_t *str, int len ) +{ + int res = 0; + int i; + for( i=0; idefinition_offset = count_lineno( parser_get_buffer(), current_block->tok_pos ); d->cmd = wcsdup( val ); cmd_end = d->cmd + wcslen(d->cmd)-1; while( (cmd_end>d->cmd) && wcschr( L"\n\r\t ", *cmd_end ) ) { - *cmd_end--=0; + *cmd_end-- = 0; } d->desc = desc?wcsdup( desc ):0; d->is_binding = is_binding; + d->definition_file = reader_current_filename()?intern(reader_current_filename()):0; hash_put( &function, intern(name), d ); - + for( i=0; idefinition_file; +} + + +int function_get_definition_offset( const wchar_t *argv ) +{ + function_data_t *data = + (function_data_t *)hash_get( &function, argv ); + if( data == 0 ) + return -1; + + return data->definition_offset; +} + + + diff --git a/function.h b/function.h index cb4930dd8..e130bcef9 100644 --- a/function.h +++ b/function.h @@ -69,4 +69,8 @@ int function_exists( const wchar_t *name ); void function_get_names( array_list_t *list, int get_hidden ); +const wchar_t *function_get_definition_file( const wchar_t *name ); + +int function_get_definition_offset( const wchar_t *name ); + #endif diff --git a/main.c b/main.c index b60999730..2594dda1d 100644 --- a/main.c +++ b/main.c @@ -184,7 +184,7 @@ int main( int argc, char **argv ) case 'v': fwprintf( stderr, - L"%s, version %s\n", + _(L"%s, version %s\n"), PACKAGE_NAME, PACKAGE_VERSION ); exit( 0 ); @@ -222,8 +222,6 @@ int main( int argc, char **argv ) complete_init(); reader_init(); - reader_push_current_filename( L"(internal)" ); - if( read_init() ) { if( cmd != 0 ) @@ -237,9 +235,7 @@ int main( int argc, char **argv ) { if( my_optind == argc ) { - reader_push_current_filename( L"(stdin)" ); res = reader_read( 0 ); - reader_pop_current_filename(); } else { @@ -278,8 +274,8 @@ int main( int argc, char **argv ) if( res ) { debug( 1, - L"Error while reading file %ls\n", - reader_current_filename() ); + _(L"Error while reading file %ls\n"), + reader_current_filename()?reader_current_filename(): _(L"Standard input") ); } free(reader_pop_current_filename()); } @@ -287,9 +283,7 @@ int main( int argc, char **argv ) } proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res ); - - reader_pop_current_filename(); - + proc_destroy(); env_destroy(); builtin_destroy(); diff --git a/parser.c b/parser.c index b29b97792..42e31a3fc 100644 --- a/parser.c +++ b/parser.c @@ -398,6 +398,15 @@ void parser_pop_block() break; } + case FUNCTION_CALL: + { + free( current_block->param1.function_name ); + al_foreach( ¤t_block->param2.function_vars, + (void (*)(const void *))&free ); + al_destroy( ¤t_block->param2.function_vars ); + break; + } + } for( eb=current_block->first_event_block; eb; eb=eb_next ) @@ -899,6 +908,14 @@ void parser_destroy() } al_destroy( &forbidden_function ); + + if( lineinfo ) + { + sb_destroy( lineinfo ); + free(lineinfo ); + lineinfo = 0; + } + } /** @@ -995,17 +1012,139 @@ int eval_args( const wchar_t *line, array_list_t *args ) return 1; } +static void parser_stack_trace( block_t *b, string_buffer_t *buff) +{ + if( !b ) + return; + + if( b->type == FUNCTION_CALL ) + { + int i; + + sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_name ); + + const wchar_t *file = function_get_definition_file( b->param1.function_name ); + if( file ) + sb_printf( buff, + _(L"\tcalled on line %d of file '%ls'\n"), + b->param3.function_lineno, + file ); + else + sb_printf( buff, + _(L"\tcalled on standard input\n") ); + + if( al_get_count( &b->param2.function_vars ) ) + { + string_buffer_t tmp; + sb_init( &tmp ); + + for( i=0; iparam2.function_vars ); i++ ) + { + sb_append2( &tmp, i?L" ":L"", (wchar_t *)al_get( &b->param2.function_vars, i ), (void *)0 ); + } + sb_printf( buff, _(L"\twith parameters '%ls',\n"), (wchar_t *)tmp.buff ); + + sb_destroy( &tmp ); + } + sb_printf( buff, + L"\n" ); + } + parser_stack_trace( b->outer, buff ); +} + +static const wchar_t *is_function() +{ + block_t *b = current_block; + while( 1 ) + { + if( !b ) + { + return 0; + } + if( b->type == FUNCTION_CALL ) + { + return b->param1.function_name; + } + b=b->outer; + } +} + + +int parser_get_lineno() +{ + int i; + const wchar_t *whole_str = tok_string( current_tokenizer ); + const wchar_t *function_name; + + int lineno = 1; + + for( i=0; itype == FUNCTION_CALL ) + { + return function_get_definition_file(b->param1.function_name ); + } + b=b->outer; + } +} + +static int printed_width( const wchar_t *str, int len ) +{ + int res=0; + int i; + for( i=0; ibuff ); + int prev_width = my_wcswidth( (wchar_t *)lineinfo->buff ); + if( file ) + sb_printf( lineinfo, + _(L"%ls (line %d): "), + file, + lineno ); + else + sb_printf( lineinfo, + L"%ls: ", + _(L"Standard input"), + lineno ); + offset = my_wcswidth( (wchar_t *)lineinfo->buff ) - 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 + and the error was on the first character of the line. */ - if( !is_interactive || (current_line_pos!=0) ) + if( !is_interactive || is_function() || (current_line_width!=0) ) { - sb_printf( lineinfo, - L"%ls\n%*c^\n", - line, - offset+current_line_pos, - L' ' ); + // Workaround since it seems impossible to print 0 copies of a character using printf + if( offset+current_line_width ) + { + sb_printf( lineinfo, + L"%ls\n%*lc^\n", + line, + offset+current_line_width, + L' ' ); + } + else + { + sb_printf( lineinfo, + L"%ls\n^\n", + line ); + } } + free( line ); + parser_stack_trace( current_block, lineinfo ); return (wchar_t *)lineinfo->buff; } diff --git a/parser.h b/parser.h index 2ae523b17..5087cc6cf 100644 --- a/parser.h +++ b/parser.h @@ -63,7 +63,7 @@ typedef struct block wchar_t *for_variable; /**< Name of the variable to loop over */ int if_state; /**< The state of the if block */ wchar_t *switch_value; /**< The value to test in a switch block */ - wchar_t *function_name; /**< The name of the function to define */ + wchar_t *function_name; /**< The name of the function to define or the function called*/ } param1; /** @@ -74,6 +74,7 @@ typedef struct block array_list_t for_vars; /**< List of values for a for block */ int switch_taken; /**< Whether a switch match has already been found */ wchar_t *function_description; /**< The description of the function to define */ + array_list_t function_vars; /**< List of arguments for a function call */ } param2; /** @@ -82,6 +83,7 @@ typedef struct block union { int function_is_binding; /**< Whether a function is a keybinding */ + int function_lineno; /**< Function invocation line number */ } param3; /** @@ -251,6 +253,11 @@ int parser_is_reserved( wchar_t *word ); */ wchar_t *parser_current_line(); +/** + Returns the current line number +*/ +int parser_get_lineno(); + /** Returns the current position in the latest string of the tokenizer. */ diff --git a/reader.c b/reader.c index 3d1598324..b79005d09 100644 --- a/reader.c +++ b/reader.c @@ -385,7 +385,7 @@ void reader_handle_int( int sig ) wchar_t *reader_current_filename() { - return (wchar_t *)al_peek( ¤t_filename ); + return al_get_count( ¤t_filename )?(wchar_t *)al_peek( ¤t_filename ):0; }