Generalize the stack tracing code, add support for showing events and command substitutions in stack traces

darcs-hash:20060201154911-ac50b-707358ea50231661c05a92b40ca109ec801081e6.gz
This commit is contained in:
axel 2006-02-02 01:49:11 +10:00
parent 9f9f7bf95a
commit feabc032f6
10 changed files with 158 additions and 61 deletions

View file

@ -2029,20 +2029,10 @@ static int builtin_source( wchar_t ** argv )
} }
else else
{ {
/*
Push a new non-shadowwing variable scope to the stack. That
way one can use explicitly local variables in sourced files
that will die on return to the calling file.
*/
int lineno = parser_get_lineno();
wchar_t *file = parser_current_filename()?wcsdup(parser_current_filename()):0;
reader_push_current_filename( argv[1] );
parser_push_block( SOURCE ); parser_push_block( SOURCE );
reader_push_current_filename( argv[1] );
current_block->param1.source_dest = wcsdup( argv[1] ); current_block->param1.source_dest = wcsdup( argv[1] );
current_block->param3.call_lineno = lineno;
current_block->param4.call_filename = file;
res = reader_read( fd ); res = reader_read( fd );
parser_pop_block(); parser_pop_block();

69
event.c
View file

@ -74,6 +74,7 @@ static array_list_t *killme;
*/ */
static array_list_t *blocked; static array_list_t *blocked;
static string_buffer_t *get_desc_buff=0;
/** /**
Tests if one event instance matches the definition of a event Tests if one event instance matches the definition of a event
@ -186,6 +187,63 @@ static int event_is_blocked( event_t *e )
return 0; return 0;
} }
const wchar_t *event_get_desc( event_t *e )
{
if( !get_desc_buff )
{
get_desc_buff=malloc(sizeof(string_buffer_t) );
if( !get_desc_buff )
die_mem();
sb_init( get_desc_buff );
}
else
{
sb_clear( get_desc_buff );
}
switch( e->type )
{
case EVENT_SIGNAL:
sb_printf( get_desc_buff, _(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal ), signal_get_desc( e->param1.signal ) );
break;
case EVENT_VARIABLE:
sb_printf( get_desc_buff, _(L"handler for variable '%ls'"), e->param1.variable );
break;
case EVENT_EXIT:
if( e->param1.pid > 0 )
{
sb_printf( get_desc_buff, _(L"exit handler for process %d"), e->param1.pid );
}
else
{
job_t *j = job_get_from_pid( -e->param1.pid );
if( j )
sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command );
else
sb_printf( get_desc_buff, _(L"exit handler for job with process group %d"), -e->param1.pid );
}
break;
case EVENT_JOB_ID:
{
job_t *j = job_get( e->param1.job_id );
if( j )
sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command );
else
sb_printf( get_desc_buff, _(L"exit handler for job with job id %d"), j->job_id );
break;
}
}
return (const wchar_t *)get_desc_buff->buff;
}
void event_add_handler( event_t *event ) void event_add_handler( event_t *event )
{ {
@ -404,8 +462,11 @@ static void event_fire_internal( event_t *event )
they are marked as non-interactive and as a subshell they are marked as non-interactive and as a subshell
*/ */
is_subshell=1; is_subshell=1;
parser_push_block( EVENT );
current_block->param1.event = event;
eval( (wchar_t *)b->buff, 0, TOP ); eval( (wchar_t *)b->buff, 0, TOP );
parser_pop_block();
} }
/* /*
@ -578,6 +639,12 @@ void event_destroy()
free( killme ); free( killme );
killme=0; killme=0;
} }
if( get_desc_buff )
{
sb_destroy( get_desc_buff );
free( get_desc_buff );
}
} }
void event_free( event_t *e ) void event_free( event_t *e )

View file

@ -130,4 +130,10 @@ void event_destroy();
*/ */
void event_free( event_t *e ); void event_free( event_t *e );
/**
Returns a string describing the specified event. The string should
not be freed.
*/
const wchar_t *event_get_desc( event_t *e );
#endif #endif

15
exec.c
View file

@ -797,25 +797,17 @@ void exec( job_t *j )
string_buffer_t sb; string_buffer_t sb;
const wchar_t * def = function_get_definition( p->argv[0] ); const wchar_t * def = function_get_definition( p->argv[0] );
// fwprintf( stderr, L"run function %ls\n", argv[0] ); //fwprintf( stderr, L"run function %ls\n", argv[0] );
if( def == 0 ) if( def == 0 )
{ {
debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] ); debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] );
break; break;
} }
/*
These two lines must be called before the new block is pushed
*/
int lineno = parser_get_lineno();
wchar_t *file = parser_current_filename()?wcsdup(parser_current_filename()):0;
parser_push_block( FUNCTION_CALL ); parser_push_block( FUNCTION_CALL );
al_init( &current_block->param2.function_vars ); current_block->param2.function_call_process = p;
current_block->param1.function_name = wcsdup( p->argv[0] ); current_block->param1.function_name = wcsdup( p->argv[0] );
current_block->param3.call_lineno = lineno;
current_block->param4.call_filename = file;
if( builtin_count_args(p->argv)>1 ) if( builtin_count_args(p->argv)>1 )
{ {
@ -823,9 +815,6 @@ void exec( job_t *j )
for( i=1, arg=p->argv+1; *arg; i++, arg++ ) for( i=1, arg=p->argv+1; *arg; i++, arg++ )
{ {
al_push( &current_block->param2.function_vars,
escape(*arg, 1) );
if( i != 1 ) if( i != 1 )
sb_append( &sb, ARRAY_SEP_STR ); sb_append( &sb, ARRAY_SEP_STR );
sb_append( &sb, *arg ); sb_append( &sb, *arg );

View file

@ -233,6 +233,11 @@ The fish parser. Contains functions for parsing code.
*/ */
#define SOURCE_BLOCK _( L"Block created by the . builtin" ) #define SOURCE_BLOCK _( L"Block created by the . builtin" )
/**
Source block description
*/
#define EVENT_BLOCK _( L"event handler block" )
/** /**
Unknown block description Unknown block description
@ -333,6 +338,9 @@ void parser_push_block( int type )
{ {
block_t *new = calloc( 1, sizeof( block_t )); block_t *new = calloc( 1, sizeof( block_t ));
new->src_lineno = parser_get_lineno();
new->src_filename = parser_current_filename()?wcsdup(parser_current_filename()):0;
debug( 3, L"Block push %ls %d\n", parser_get_block_desc(type), block_count( current_block)+1 ); debug( 3, L"Block push %ls %d\n", parser_get_block_desc(type), block_count( current_block)+1 );
new->outer = current_block; new->outer = current_block;
@ -407,16 +415,11 @@ void parser_pop_block()
case FUNCTION_CALL: case FUNCTION_CALL:
{ {
free( current_block->param1.function_name ); free( current_block->param1.function_name );
free( current_block->param4.call_filename );
al_foreach( &current_block->param2.function_vars,
(void (*)(const void *))&free );
al_destroy( &current_block->param2.function_vars );
break; break;
} }
case SOURCE: case SOURCE:
{ {
free( current_block->param4.call_filename );
free( current_block->param1.source_dest ); free( current_block->param1.source_dest );
break; break;
} }
@ -429,6 +432,8 @@ void parser_pop_block()
free(eb); free(eb);
} }
free( current_block->src_filename );
block_t *old = current_block; block_t *old = current_block;
current_block = current_block->outer; current_block = current_block->outer;
free( old ); free( old );
@ -471,6 +476,9 @@ const wchar_t *parser_get_block_desc( int block )
case SOURCE: case SOURCE:
return SOURCE_BLOCK; return SOURCE_BLOCK;
case EVENT:
return EVENT_BLOCK;
default: default:
return UNKNOWN_BLOCK; return UNKNOWN_BLOCK;
} }
@ -1035,40 +1043,60 @@ void parser_stack_trace( block_t *b, string_buffer_t *buff)
{ {
if( !b ) if( !b )
return; return;
if( b->type == FUNCTION_CALL || b->type==SOURCE) if( b->type==EVENT )
{
sb_printf( buff, _(L"in event handler: %ls\n"), event_get_desc( b->param1.event ));
sb_printf( buff,
L"\n" );
return;
}
if( b->type == FUNCTION_CALL || b->type==SOURCE || b->type==SUBST)
{ {
int i; int i;
if( b->type==SOURCE) switch( b->type)
sb_printf( buff, _(L"in . (source) call of file '%ls',\n"), b->param1.source_dest ); {
else case SOURCE:
sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_name ); sb_printf( buff, _(L"in . (source) call of file '%ls',\n"), b->param1.source_dest );
break;
case FUNCTION_CALL:
sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_name );
break;
case SUBST:
sb_printf( buff, _(L"in command substitution\n") );
break;
}
const wchar_t *file = b->param4.call_filename; const wchar_t *file = b->src_filename;
if( file ) if( file )
sb_printf( buff, sb_printf( buff,
_(L"\tcalled on line %d of file '%ls',\n"), _(L"\tcalled on line %d of file '%ls',\n"),
b->param3.call_lineno, b->src_lineno,
file ); file );
else else
sb_printf( buff, sb_printf( buff,
_(L"\tcalled on standard input,\n") ); _(L"\tcalled on standard input,\n") );
if( al_get_count( &b->param2.function_vars ) ) if( b->type == FUNCTION_CALL )
{ {
string_buffer_t tmp; if( b->param2.function_call_process->argv[1] )
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 ); string_buffer_t tmp;
sb_init( &tmp );
for( i=1; b->param2.function_call_process->argv[i]; i++ )
{
sb_append2( &tmp, i>1?L" ":L"", b->param2.function_call_process->argv[i], (void *)0 );
}
sb_printf( buff, _(L"\twith parameter list '%ls'\n"), (wchar_t *)tmp.buff );
sb_destroy( &tmp );
} }
sb_printf( buff, _(L"\twith parameter list '%ls'\n"), (wchar_t *)tmp.buff );
sb_destroy( &tmp );
} }
sb_printf( buff, sb_printf( buff,
L"\n" ); L"\n" );
} }
@ -1096,11 +1124,19 @@ static const wchar_t *is_function()
int parser_get_lineno() int parser_get_lineno()
{ {
int i; int i;
const wchar_t *whole_str = tok_string( current_tokenizer ); const wchar_t *whole_str;
const wchar_t *function_name; const wchar_t *function_name;
int lineno = 1; int lineno = 1;
if( !current_tokenizer )
return -1;
whole_str = tok_string( current_tokenizer );
if( !whole_str )
return -1;
for( i=0; i<current_tokenizer_pos; i++ ) for( i=0; i<current_tokenizer_pos; i++ )
{ {
if( whole_str[i] == L'\n' ) if( whole_str[i] == L'\n' )
@ -2377,8 +2413,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
return 1; return 1;
} }
if( (block_type!=TOP) && if( (block_type != TOP) &&
(block_type != FUNCTION_CALL) &&
(block_type != SUBST)) (block_type != SUBST))
{ {
debug( 1, debug( 1,
@ -2392,12 +2427,12 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
} }
eval_level++; eval_level++;
current_tokenizer = malloc( sizeof(tokenizer));
parser_push_block( block_type ); parser_push_block( block_type );
current_tokenizer = malloc( sizeof(tokenizer));
tok_init( current_tokenizer, cmd, 0 ); tok_init( current_tokenizer, cmd, 0 );
error_code = 0; error_code = 0;
event_fire( 0 ); event_fire( 0 );

View file

@ -10,6 +10,7 @@
#include "proc.h" #include "proc.h"
#include "util.h" #include "util.h"
#include "parser.h" #include "parser.h"
#include "event.h"
/** /**
event_block_t represents a block on events of the specified type event_block_t represents a block on events of the specified type
@ -65,6 +66,7 @@ typedef struct block
wchar_t *switch_value; /**< The value to test in a switch block */ wchar_t *switch_value; /**< The value to test in a switch block */
wchar_t *function_name; /**< The name of the function to define or the function called*/ wchar_t *function_name; /**< The name of the function to define or the function called*/
wchar_t *source_dest; /**< The name of the file to source*/ wchar_t *source_dest; /**< The name of the file to source*/
event_t *event; /**<The event that triggered this block */
} param1; } param1;
/** /**
@ -75,7 +77,7 @@ typedef struct block
array_list_t for_vars; /**< List of values for a for block */ array_list_t for_vars; /**< List of values for a for block */
int switch_taken; /**< Whether a switch match has already been found */ int switch_taken; /**< Whether a switch match has already been found */
wchar_t *function_description; /**< The description of the function to define */ wchar_t *function_description; /**< The description of the function to define */
array_list_t function_vars; /**< List of arguments for a function call */ process_t *function_call_process; /**< The process representing this function call */
} param2; } param2;
/** /**
@ -84,7 +86,6 @@ typedef struct block
union union
{ {
int function_is_binding; /**< Whether a function is a keybinding */ int function_is_binding; /**< Whether a function is a keybinding */
int call_lineno; /**< Function invocation line number */
} param3; } param3;
/** /**
@ -93,8 +94,17 @@ typedef struct block
union union
{ {
array_list_t *function_events; array_list_t *function_events;
wchar_t *call_filename;
} param4; } param4;
/**
Name of file that created this block
*/
wchar_t *src_filename;
/**
Line number where this block was created
*/
int src_lineno;
/** /**
Some naming confusion. This is a pointer to the first element in the list of all event blocks. Some naming confusion. This is a pointer to the first element in the list of all event blocks.
@ -123,6 +133,7 @@ enum block_type
TOP, /**< Outermost block */ TOP, /**< Outermost block */
BEGIN, /**< Unconditional block */ BEGIN, /**< Unconditional block */
SOURCE, /**< Block created by the . (source) builtin */ SOURCE, /**< Block created by the . (source) builtin */
EVENT, /**< Block created on event notifier invocation */
} }
; ;

4
proc.c
View file

@ -588,7 +588,7 @@ int job_reap( int interactive )
j->job_id, j->job_id,
j->command, j->command,
sig2wcs(WTERMSIG(p->status)), sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) ); signal_get_desc( WTERMSIG(p->status) ) );
else else
fwprintf( stdout, fwprintf( stdout,
_( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ), _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ),
@ -598,7 +598,7 @@ int job_reap( int interactive )
j->job_id, j->job_id,
j->command, j->command,
sig2wcs(WTERMSIG(p->status)), sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) ); signal_get_desc( WTERMSIG(p->status) ) );
tputs(clr_eol,1,&writeb); tputs(clr_eol,1,&writeb);
fwprintf (stdout, L"\n" ); fwprintf (stdout, L"\n" );
found=1; found=1;

View file

@ -2813,7 +2813,6 @@ wchar_t *reader_readline()
data->search_buff[0]=0; data->search_buff[0]=0;
history_reset(); history_reset();
data->token_history_pos=-1; data->token_history_pos=-1;
} }

View file

@ -342,7 +342,7 @@ const wchar_t *sig2wcs( int sig )
return L"Unknown"; return L"Unknown";
} }
const wchar_t *sig_description( int sig ) const wchar_t *signal_get_desc( int sig )
{ {
int i; int i;
for( i=0; lookup[i].desc ; i++ ) for( i=0; lookup[i].desc ; i++ )

View file

@ -18,7 +18,7 @@ const wchar_t *sig2wcs( int sig );
/** /**
Returns a description of the specified signal. Returns a description of the specified signal.
*/ */
const wchar_t *sig_description( int sig ); const wchar_t *signal_get_desc( int sig );
/** /**
Set all signal handlers to SIG_DFL Set all signal handlers to SIG_DFL