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
{
/*
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 );
reader_push_current_filename( 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 );
parser_pop_block();

67
event.c
View file

@ -74,6 +74,7 @@ static array_list_t *killme;
*/
static array_list_t *blocked;
static string_buffer_t *get_desc_buff=0;
/**
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;
}
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 )
{
@ -404,7 +462,10 @@ static void event_fire_internal( event_t *event )
they are marked as non-interactive and as a subshell
*/
is_subshell=1;
parser_push_block( EVENT );
current_block->param1.event = event;
eval( (wchar_t *)b->buff, 0, TOP );
parser_pop_block();
}
@ -578,6 +639,12 @@ void event_destroy()
free( killme );
killme=0;
}
if( get_desc_buff )
{
sb_destroy( get_desc_buff );
free( get_desc_buff );
}
}
void event_free( event_t *e )

View file

@ -130,4 +130,10 @@ void event_destroy();
*/
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

15
exec.c
View file

@ -797,25 +797,17 @@ void exec( job_t *j )
string_buffer_t sb;
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 )
{
debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] );
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 );
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->param3.call_lineno = lineno;
current_block->param4.call_filename = file;
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++ )
{
al_push( &current_block->param2.function_vars,
escape(*arg, 1) );
if( i != 1 )
sb_append( &sb, ARRAY_SEP_STR );
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" )
/**
Source block description
*/
#define EVENT_BLOCK _( L"event handler block" )
/**
Unknown block description
@ -333,6 +338,9 @@ void parser_push_block( int type )
{
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 );
new->outer = current_block;
@ -407,16 +415,11 @@ void parser_pop_block()
case FUNCTION_CALL:
{
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;
}
case SOURCE:
{
free( current_block->param4.call_filename );
free( current_block->param1.source_dest );
break;
}
@ -429,6 +432,8 @@ void parser_pop_block()
free(eb);
}
free( current_block->src_filename );
block_t *old = current_block;
current_block = current_block->outer;
free( old );
@ -471,6 +476,9 @@ const wchar_t *parser_get_block_desc( int block )
case SOURCE:
return SOURCE_BLOCK;
case EVENT:
return EVENT_BLOCK;
default:
return UNKNOWN_BLOCK;
}
@ -1036,39 +1044,59 @@ void parser_stack_trace( block_t *b, string_buffer_t *buff)
if( !b )
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;
if( b->type==SOURCE)
sb_printf( buff, _(L"in . (source) call of file '%ls',\n"), b->param1.source_dest );
else
sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_name );
switch( b->type)
{
case SOURCE:
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 )
sb_printf( buff,
_(L"\tcalled on line %d of file '%ls',\n"),
b->param3.call_lineno,
b->src_lineno,
file );
else
sb_printf( buff,
_(L"\tcalled on standard input,\n") );
if( al_get_count( &b->param2.function_vars ) )
if( b->type == FUNCTION_CALL )
{
string_buffer_t tmp;
sb_init( &tmp );
for( i=0; i<al_get_count( &b->param2.function_vars ); i++ )
if( b->param2.function_call_process->argv[1] )
{
sb_append2( &tmp, i?L" ":L"", (wchar_t *)al_get( &b->param2.function_vars, i ), (void *)0 );
}
sb_printf( buff, _(L"\twith parameter list '%ls'\n"), (wchar_t *)tmp.buff );
string_buffer_t tmp;
sb_init( &tmp );
sb_destroy( &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"\n" );
}
@ -1096,11 +1124,19 @@ static const wchar_t *is_function()
int parser_get_lineno()
{
int i;
const wchar_t *whole_str = tok_string( current_tokenizer );
const wchar_t *whole_str;
const wchar_t *function_name;
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++ )
{
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;
}
if( (block_type!=TOP) &&
(block_type != FUNCTION_CALL) &&
if( (block_type != TOP) &&
(block_type != SUBST))
{
debug( 1,
@ -2392,12 +2427,12 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
}
eval_level++;
current_tokenizer = malloc( sizeof(tokenizer));
parser_push_block( block_type );
current_tokenizer = malloc( sizeof(tokenizer));
tok_init( current_tokenizer, cmd, 0 );
error_code = 0;
event_fire( 0 );

View file

@ -10,6 +10,7 @@
#include "proc.h"
#include "util.h"
#include "parser.h"
#include "event.h"
/**
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 *function_name; /**< The name of the function to define or the function called*/
wchar_t *source_dest; /**< The name of the file to source*/
event_t *event; /**<The event that triggered this block */
} param1;
/**
@ -75,7 +77,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 */
process_t *function_call_process; /**< The process representing this function call */
} param2;
/**
@ -84,7 +86,6 @@ typedef struct block
union
{
int function_is_binding; /**< Whether a function is a keybinding */
int call_lineno; /**< Function invocation line number */
} param3;
/**
@ -93,9 +94,18 @@ typedef struct block
union
{
array_list_t *function_events;
wchar_t *call_filename;
} 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.
*/
@ -123,6 +133,7 @@ enum block_type
TOP, /**< Outermost block */
BEGIN, /**< Unconditional block */
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->command,
sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) );
signal_get_desc( WTERMSIG(p->status) ) );
else
fwprintf( stdout,
_( 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->command,
sig2wcs(WTERMSIG(p->status)),
sig_description( WTERMSIG(p->status) ) );
signal_get_desc( WTERMSIG(p->status) ) );
tputs(clr_eol,1,&writeb);
fwprintf (stdout, L"\n" );
found=1;

View file

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

View file

@ -342,7 +342,7 @@ const wchar_t *sig2wcs( int sig )
return L"Unknown";
}
const wchar_t *sig_description( int sig )
const wchar_t *signal_get_desc( int sig )
{
int 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.
*/
const wchar_t *sig_description( int sig );
const wchar_t *signal_get_desc( int sig );
/**
Set all signal handlers to SIG_DFL