Add function stack trace to error output

darcs-hash:20060126144810-ac50b-3426191f596674504ce49dd61fcfa3c2c0c0f2bb.gz
This commit is contained in:
axel 2006-01-27 00:48:10 +10:00
parent 2e35e1ea60
commit 312c7ab7b2
7 changed files with 263 additions and 33 deletions

17
exec.c
View file

@ -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( &current_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( &current_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 )

View file

@ -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; i<len; i++ )
{
if( str[i] == L'\n' )
res++;
}
return res;
}
void function_add( const wchar_t *name,
const wchar_t *val,
const wchar_t *desc,
@ -75,18 +91,22 @@ void function_add( const wchar_t *name,
if( function_exists( name ) )
function_remove( name );
function_data_t *d = malloc( sizeof( function_data_t ) );
d->definition_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; i<al_get_count( events ); i++ )
{
event_add_handler( (event_t *)al_get( events, i ) );
@ -172,3 +192,26 @@ void function_get_names( array_list_t *list, int get_hidden )
}
const wchar_t *function_get_definition_file( const wchar_t *argv )
{
function_data_t *data =
(function_data_t *)hash_get( &function, argv );
if( data == 0 )
return 0;
return data->definition_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;
}

View file

@ -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

14
main.c
View file

@ -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();

203
parser.c
View file

@ -398,6 +398,15 @@ void parser_pop_block()
break;
}
case FUNCTION_CALL:
{
free( current_block->param1.function_name );
al_foreach( &current_block->param2.function_vars,
(void (*)(const void *))&free );
al_destroy( &current_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; i<al_get_count( &b->param2.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; i<current_tokenizer_pos; i++ )
{
if( whole_str[i] == L'\n' )
{
lineno++;
}
}
if( (function_name = is_function()) )
{
lineno += function_get_definition_offset( function_name );
}
return lineno;
}
static const wchar_t *parser_current_filename()
{
block_t *b = current_block;
while( 1 )
{
if( !b )
{
return reader_current_filename();
}
if( b->type == 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; i<len; i++ )
{
if( str[i] == L'\t' )
{
res=(res+8)&~7;
}
else
{
res += wcwidth( str[i] );
}
}
return res;
}
wchar_t *parser_current_line()
{
int lineno=1;
wchar_t *file = reader_current_filename();
const wchar_t *file = parser_current_filename();
wchar_t *whole_str = tok_string( current_tokenizer );
wchar_t *line = whole_str;
wchar_t *line_end;
int i;
int offset;
int current_line_pos=current_tokenizer_pos;
int current_line_width;
const wchar_t *function_name=0;
int current_line_start=0;
if( !line )
return L"";
@ -1015,7 +1154,7 @@ wchar_t *parser_current_line()
lineinfo = malloc( sizeof(string_buffer_t) );
sb_init( lineinfo );
}
sb_clear( lineinfo );
sb_clear( lineinfo );
/*
Calculate line number, line offset, etc.
@ -1025,11 +1164,18 @@ wchar_t *parser_current_line()
if( whole_str[i] == L'\n' )
{
lineno++;
current_line_pos = current_tokenizer_pos-i-1;
current_line_start=i+1;
line = &whole_str[i+1];
}
}
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
*/
@ -1039,34 +1185,55 @@ wchar_t *parser_current_line()
line = wcsndup( line, line_end-line );
debug( 4, L"Current pos %d, line pos %d, file_length %d, is_interactive %d\n", current_tokenizer_pos, current_line_pos, wcslen(whole_str), is_interactive);
/**
If we are not going to print a stack trace, at least print the line number and filename
*/
if( !is_interactive )
{
sb_printf( lineinfo,
_(L"%ls (line %d): "),
file,
lineno );
offset = my_wcswidth( (wchar_t *)lineinfo->buff );
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;
}

View file

@ -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.
*/

View file

@ -385,7 +385,7 @@ void reader_handle_int( int sig )
wchar_t *reader_current_filename()
{
return (wchar_t *)al_peek( &current_filename );
return al_get_count( &current_filename )?(wchar_t *)al_peek( &current_filename ):0;
}