mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 12:23:09 +00:00
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:
parent
9f9f7bf95a
commit
feabc032f6
10 changed files with 158 additions and 61 deletions
12
builtin.c
12
builtin.c
|
@ -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();
|
||||
|
|
69
event.c
69
event.c
|
@ -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,8 +462,11 @@ 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 )
|
||||
|
|
6
event.h
6
event.h
|
@ -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
15
exec.c
|
@ -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( ¤t_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( ¤t_block->param2.function_vars,
|
||||
escape(*arg, 1) );
|
||||
|
||||
if( i != 1 )
|
||||
sb_append( &sb, ARRAY_SEP_STR );
|
||||
sb_append( &sb, *arg );
|
||||
|
|
91
parser.c
91
parser.c
|
@ -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( ¤t_block->param2.function_vars,
|
||||
(void (*)(const void *))&free );
|
||||
al_destroy( ¤t_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;
|
||||
}
|
||||
|
@ -1035,40 +1043,60 @@ 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 ) )
|
||||
{
|
||||
string_buffer_t tmp;
|
||||
sb_init( &tmp );
|
||||
|
||||
for( i=0; i<al_get_count( &b->param2.function_vars ); i++ )
|
||||
if( b->type == FUNCTION_CALL )
|
||||
{
|
||||
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 );
|
||||
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,
|
||||
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 );
|
||||
|
|
17
parser.h
17
parser.h
|
@ -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,8 +94,17 @@ 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
4
proc.c
|
@ -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;
|
||||
|
|
1
reader.c
1
reader.c
|
@ -2813,7 +2813,6 @@ wchar_t *reader_readline()
|
|||
data->search_buff[0]=0;
|
||||
history_reset();
|
||||
data->token_history_pos=-1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
2
signal.c
2
signal.c
|
@ -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++ )
|
||||
|
|
2
signal.h
2
signal.h
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue