Increase fish robustness by improving signal handling when forking jobs and minor signal handling improvements

darcs-hash:20051014114033-ac50b-8d0f6274ac590f1b6dbe82c55366f44ed7debf20.gz
This commit is contained in:
axel 2005-10-14 21:40:33 +10:00
parent f321855c02
commit 0ebf6db4b9
17 changed files with 355 additions and 292 deletions

View file

@ -946,7 +946,7 @@ static int builtin_function( wchar_t **argv )
{
wchar_t *nxt = names_arr[i];
int l = wcslen( nxt + 2 );
if( chars+l > reader_get_width() )
if( chars+l > common_get_width() )
{
chars = 0;
sb_append(sb_err, L"\n" );

View file

@ -87,6 +87,11 @@ wchar_t *program_name;
int debug_level=1;
/**
This struct should be continually updated by signals as the term resizes, and as such always contain the correct current size.
*/
static struct winsize termsize;
static int block_count=0;
@ -799,7 +804,7 @@ void debug( int level, wchar_t *msg, ... )
wchar_t *start, *pos;
int line_width = 0;
int tok_width = 0;
int screen_width = 80;
int screen_width = common_get_width();
if( level > debug_level )
return;
@ -818,25 +823,38 @@ void debug( int level, wchar_t *msg, ... )
tok_width=0;
/*
Tokenize on whitespace, and also calculate the width of the token
*/
while( *pos && ( !wcschr( L" \n\r\t", *pos ) ) )
{
if((tok_width + wcwidth(*pos)) >= (screen_width-1))
/*
Check is token is wider than one line.
If so we mark it as an overflow and break the token.
*/
if((tok_width + wcwidth(*pos)) > (screen_width-1))
{
overflow = 1;
break;
}
tok_width += wcwidth( *pos );
pos++;
}
/*
If token is zero character long, we don't do anything
*/
if( pos == start )
{
start = pos = pos+1;
}
else if( overflow )
{
/*
In case of overflow, we print a newline, except if we alreade are at position 0
*/
wchar_t *token = wcsndup( start, pos-start );
if( line_width != 0 )
putwc( L'\n', stderr );
@ -846,6 +864,9 @@ void debug( int level, wchar_t *msg, ... )
}
else
{
/*
Print the token
*/
wchar_t *token = wcsndup( start, pos-start );
if( (line_width + (line_width!=0?1:0) + tok_width) > screen_width )
{
@ -856,7 +877,9 @@ void debug( int level, wchar_t *msg, ... )
free( token );
line_width += (line_width!=0?1:0) + tok_width;
}
/*
Break on end of string
*/
if( !*pos )
break;
@ -1383,3 +1406,23 @@ int acquire_lock_file( const char *lockfile, const int timeout, int force )
free( linkfile );
return ret;
}
void common_handle_winch( int signal )
{
if (ioctl(1,TIOCGWINSZ,&termsize)!=0)
{
return;
}
}
int common_get_width()
{
return termsize.ws_col;
}
int common_get_height()
{
return termsize.ws_row;
}

View file

@ -231,15 +231,23 @@ void die_mem();
void common_destroy();
/**
Issue a debug message
Issue a debug message with printf-style string formating and
automatic line breaking. The string will begin with the string \c
program_name, followed by a colon and a whitespace.
\param level the priority of the message. Lower number means higher priority. Messages with too high priority number will be discarded.
\param the message.
\param level the priority of the message. Lower number means higher priority. Messages with a priority_number higher than \c debug_level will be ignored..
\param the message format string.
Example:
<code>debug( 1, L"Pi = %.3f", M_PI );</code>
will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that program_name is 'fish'.
*/
void debug( int level, wchar_t *msg, ... );
/**
Replace special characters with escape sequences. Newline is
Replace special characters with backslash escape sequences. Newline is
replaced with \n, etc.
\param in The string to be escaped
@ -255,6 +263,31 @@ wchar_t *unescape( const wchar_t * in, int escape_special );
void block();
void unblock();
int acquire_lock_file( const char *lockfile, const int timeout, int force );
/**
Returns the width of the terminal window, so that not all
functions that use these values continually have to keep track of
it.
Only works if common_handle_winch is registered to handle winch signals.
*/
int common_get_width();
/**
Returns the height of the terminal window, so that not all
functions that use these values continually have to keep track of
it.
Only works if common_handle_winch is registered to handle winch signals.
*/
int common_get_height();
/*
Handle a window change event by looking up the new window size and
saving it in an internal variable used by common_get_wisth and
common_get_height().
*/
void common_handle_winch( int signal );
#endif
int acquire_lock_file( const char *lockfile, const int timeout, int force );

30
env.c
View file

@ -620,6 +620,24 @@ wchar_t *env_get( const wchar_t *key )
}
return (wchar_t *)dyn_var.buff;
}
else if( wcscmp( key, L"COLUMNS" )==0 )
{
sb_clear( &dyn_var );
sb_printf( &dyn_var, L"%d", common_get_width() );
return (wchar_t *)dyn_var.buff;
}
else if( wcscmp( key, L"LINES" )==0 )
{
sb_clear( &dyn_var );
sb_printf( &dyn_var, L"%d", common_get_height() );
return (wchar_t *)dyn_var.buff;
}
else if( wcscmp( key, L"status" )==0 )
{
sb_clear( &dyn_var );
sb_printf( &dyn_var, L"%d", proc_get_last_status() );
return (wchar_t *)dyn_var.buff;
}
while( env != 0 )
{
@ -658,7 +676,7 @@ int env_exist( const wchar_t *key )
env_node_t *env = top;
wchar_t *item;
if( wcscmp( key, L"history" ) == 0 )
if( hash_get( &env_read_only, key ) )
{
return 1;
}
@ -809,7 +827,17 @@ void env_get_names( array_list_t *l, int flags )
add_key_to_hash,
&names );
if( get_names_show_unexported )
{
al_push( l, L"history" );
al_push( l, L"status" );
}
if( get_names_show_exported )
{
al_push( l, L"COLUMNS" );
al_push( l, L"LINES" );
}
}
if( show_universal )

8
env.h
View file

@ -69,9 +69,11 @@ void env_set( const wchar_t *key,
/**
Return the value of the variable with the specified name.
Returns 0 if the key does not exist.
The returned string should not be modified or freed.
Return the value of the variable with the specified name. Returns 0
if the key does not exist. The returned string should not be
modified or freed. The returned string is only guaranteed to be
valid until the next call to env_get(), env_set(), env_push() or
env_pop() takes place.
*/
wchar_t *env_get( const wchar_t *key );

11
event.c
View file

@ -374,10 +374,16 @@ static void event_fire_signal_events()
array_list_t a;
al_init( &a );
/*
Switch signal lists
*/
sig_list[1-active_list].count=0;
sig_list[1-active_list].overflow=0;
active_list=1-active_list;
/*
Set up
*/
e.type=EVENT_SIGNAL;
e.function_name=0;
@ -385,9 +391,12 @@ static void event_fire_signal_events()
if( lst->overflow )
{
debug( 0, L"Signal overflow. Signals have been ignored" );
debug( 0, L"Signal list overflow. Signals have been ignored" );
}
/*
Send all signals in our private list
*/
for( i=0; i<lst->count; i++ )
{
e.param1.signal = lst->signal[i];

80
exec.c
View file

@ -259,17 +259,7 @@ static void handle_child_io( io_data_t *io )
We don't mind if this fails, it is just a speculative close
to make sure no unexpected untracked fd causes us to fail
*/
while( close(io->fd) == -1 )
{
if( errno != EINTR )
break;
/* debug( 1,
FD_ERROR,
io->fd );
wperror( L"close" );
exit(1);*/
}
close(io->fd);
switch( io->io_mode )
{
@ -401,12 +391,11 @@ static void setup_child_process( job_t *j )
/* Set the handling for job control signals back to the default. */
signal_reset_handlers();
sigset_t chldset;
sigemptyset( &chldset );
sigaddset( &chldset, SIGCHLD );
sigprocmask(SIG_UNBLOCK, &chldset, 0);
handle_child_io( j->io );
/* Remove all signal blocks */
signal_unblock();
}
@ -540,7 +529,12 @@ static int internal_exec_helper( const wchar_t *def,
int is_block_old=is_block;
is_block=1;
signal_unblock();
eval( def, io_internal, block_type );
signal_block();
/*
io_data_t *buff = io_get( io, 1 );
if( buff && buff->io_mode == IO_BUFFER )
@ -583,16 +577,11 @@ static int handle_new_child( job_t *j, process_t *p )
j->pgid );
wperror( L"setpgid" );
}
}
if( j->fg )
{
while( 1)
{
if( tcsetpgrp (0, j->pgid) )
{
if( errno != EINTR )
{
debug( 1, L"Could not send job %d ('%ls')to foreground",
j->job_id,
@ -601,18 +590,10 @@ static int handle_new_child( job_t *j, process_t *p )
return -1;
}
}
else
break;
}
}
if( j->fg && new_pgid)
{
while( 1 )
{
if( tcsetpgrp (0, j->pgid) )
{
if( errno != EINTR )
{
debug( 1, L"Could not send job %d ('%ls')to foreground",
j->job_id,
@ -621,18 +602,12 @@ static int handle_new_child( job_t *j, process_t *p )
return -1;
}
}
else
break;
}
}
}
else
{
j->pgid = getpid();
}
return 0;
}
@ -659,6 +634,11 @@ void exec( job_t *j )
/*
Do a regular launch - but without forking first...
*/
signal_block();
/*
setup_child_process make sure signals are propelry set up
*/
setup_child_process( j );
launch_process( j->first_process );
/*
@ -689,6 +669,8 @@ void exec( job_t *j )
j->io = io_add( j->io, &pipe_write );
signal_block();
for (p = j->first_process; p; p = p->next)
{
mypipe[1]=-1;
@ -890,8 +872,13 @@ void exec( job_t *j )
builtin_err_redirect = has_fd( j->io, 2 );
fg = j->fg;
j->fg = 0;
signal_unblock();
p->status = builtin_run( p->argv );
signal_block();
/*
Restore the fg flag, which is temporarily set to
false during builtin execution so as not to confuse
@ -939,8 +926,7 @@ void exec( job_t *j )
if( io_buffer->param2.out_buffer->used != 0 )
{
/*Temporary signal block for SIGCHLD */
sigprocmask(SIG_BLOCK, &chldset, 0);
pid = fork ();
if (pid == 0)
{
@ -965,12 +951,13 @@ void exec( job_t *j )
{
/*
This is the parent process. Store away
information on the child, and possibly fice
information on the child, and possibly give
it control over the terminal.
*/
p->pid = pid;
if( handle_new_child( j, p ) )
return;
exit(1);
}
}
@ -1029,8 +1016,7 @@ void exec( job_t *j )
}
/*Temporary signal block for SIGCHLD */
sigprocmask(SIG_BLOCK, &chldset, 0);
pid = fork ();
if (pid == 0)
{
@ -1064,7 +1050,8 @@ void exec( job_t *j )
p->pid = pid;
if( handle_new_child( j, p ) )
return;
exit( 1 );
}
break;
@ -1072,8 +1059,6 @@ void exec( job_t *j )
case EXTERNAL:
{
/*Temporary signal block for SIGCHLD */
sigprocmask(SIG_BLOCK, &chldset, 0);
// fwprintf( stderr,
// L"fork on %ls\n", j->command );
@ -1108,7 +1093,8 @@ void exec( job_t *j )
p->pid = pid;
if( handle_new_child( j, p ) )
return;
exit( 1 );
}
break;
@ -1120,7 +1106,7 @@ void exec( job_t *j )
if(p->type == INTERNAL_BUILTIN)
builtin_pop_io();
sigprocmask(SIG_UNBLOCK, &chldset, 0);
/*
Close the pipe the current process uses to read from the previous process_t
@ -1143,6 +1129,8 @@ void exec( job_t *j )
}
}
signal_unblock();
debug( 3, L"Job is constructed" );
j->io = io_remove( j->io, &pipe_read );

View file

@ -616,6 +616,7 @@ int main( int argc, char **argv )
say( L"Testing low-level functionality");
say( L"Lines beginning with '(ignore):' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All actual errors begin with 'Error:'." );
proc_init();
output_init();
event_init();
exec_init();
@ -649,5 +650,6 @@ int main( int argc, char **argv )
exec_destroy();
event_destroy();
output_destroy();
proc_destroy();
}

2
main.c
View file

@ -207,6 +207,7 @@ int main( int argc, char **argv )
if( force_interactive )
is_interactive_session=1;
proc_init();
output_init();
event_init();
exec_init();
@ -306,7 +307,6 @@ int main( int argc, char **argv )
event_destroy();
output_destroy();
intern_free_all();
return res;

View file

@ -1658,7 +1658,7 @@ static void eval_job( tokenizer *tok )
job_t *j;
int start_pos = job_start_pos = tok_get_pos( tok );
debug( 2, L"begin eval_job()\n" );
debug( 2, L"begin eval_job()" );
long long t1=0, t2=0, t3=0;
profile_element_t *p=0;
int skip = 0;
@ -1755,7 +1755,6 @@ static void eval_job( tokenizer *tok )
if( current_block->type == WHILE )
{
// debug( 2, L"We are at begining of a while block\n" );
switch( current_block->param1.while_state )
{
@ -1773,8 +1772,6 @@ static void eval_job( tokenizer *tok )
if( (!current_block->param1.if_state) &&
(!current_block->skip) )
{
// debug( 2, L"Result of if block is %d\n", proc_get_last_status() );
current_block->skip = proc_get_last_status()!= 0;
current_block->param1.if_state++;
}
@ -1840,7 +1837,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
if( !cmd )
{
debug( 1,
L"Tried to evaluate null pointer\n" BUGREPORT_MSG,
L"Tried to evaluate null pointer. " BUGREPORT_MSG,
PACKAGE_BUGREPORT );
return 1;
}
@ -1850,7 +1847,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
(block_type != SUBST))
{
debug( 1,
L"Tried to evaluate buffer using invalid block scope of type '%ls'\n" BUGREPORT_MSG,
L"Tried to evaluate buffer using invalid block scope of type '%ls'. " BUGREPORT_MSG,
parser_get_block_desc( block_type ),
PACKAGE_BUGREPORT );
return 1;
@ -1866,11 +1863,16 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
tok_init( current_tokenizer, cmd, 0 );
error_code = 0;
event_fire( 0, 0 );
while( tok_has_next( current_tokenizer ) &&
!error_code &&
!sanity_check() &&
!exit_status() )
{
eval_job( current_tokenizer );
event_fire( 0, 0 );
}
int prev_block_type = current_block->type;
parser_pop_block();
@ -1880,7 +1882,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
if( current_block == 0 )
{
debug( 0,
L"End of block mismatch\n"
L"End of block mismatch. "
L"Program terminating. "
BUGREPORT_MSG,
PACKAGE_BUGREPORT );

84
proc.c
View file

@ -75,6 +75,27 @@ int is_event=0;
int proc_had_barrier;
pid_t proc_last_bg_pid = 0;
/**
List used to store arguments when firing events
*/
static array_list_t event_arg;
/**
Stringbuffer used to create arguments when firing events
*/
static string_buffer_t event_pid;
/**
Stringbuffer used to create arguments when firing events
*/
static string_buffer_t event_status;
void proc_init()
{
al_init( &event_arg );
sb_init( &event_pid );
sb_init( &event_status );
}
/**
Recursively free a process and those following it
@ -164,6 +185,9 @@ void job_free( job_t * j )
void proc_destroy()
{
al_destroy( &event_arg );
sb_destroy( &event_pid );
sb_destroy( &event_status );
while( first_job )
{
debug( 2, L"freeing leaked job %ls", first_job->command );
@ -174,9 +198,6 @@ void proc_destroy()
void proc_set_last_status( int s )
{
last_status = s;
wchar_t stat[16];
swprintf( stat, 16, L"%d", s );
env_set( L"status", stat, ENV_GLOBAL );
// fwprintf( stderr, L"Set last status to %d\n", s );
}
@ -464,19 +485,8 @@ static void format_job_info( const job_t *j, const wchar_t *status )
static void fire_process_event( const wchar_t *msg, pid_t pid, int status )
{
static event_t ev;
static array_list_t event_arg;
static string_buffer_t event_pid, event_status;
static int init=0;
event_t e;
if( !init )
{
al_init( &event_arg );
sb_init( &event_pid );
sb_init( &event_status );
init=1;
}
e.function_name=0;
@ -836,11 +846,8 @@ void job_continue (job_t *j, int cont)
/* Put the job into the foreground. */
if( j->fg )
{
while( 1 )
{
signal_block();
if( tcsetpgrp (0, j->pgid) )
{
if( errno != EINTR )
{
debug( 1,
L"Could not send job %d ('%ls') to foreground",
@ -849,18 +856,10 @@ void job_continue (job_t *j, int cont)
wperror( L"tcsetpgrp" );
return;
}
}
else
break;
}
if( cont )
{
while( 1 )
{
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
{
if( errno != EINTR )
{
debug( 1,
L"Could not send job %d ('%ls') to foreground",
@ -870,11 +869,7 @@ void job_continue (job_t *j, int cont)
return;
}
}
else
break;
}
}
signal_unblock();
}
}
@ -976,57 +971,34 @@ void job_continue (job_t *j, int cont)
*/
if( !is_subshell && is_interactive && !is_block)
{
while( 1 )
{
signal_block();
if( tcsetpgrp (0, getpid()) )
{
if( errno != EINTR )
{
debug( 1, L"Could not return shell to foreground" );
wperror( L"tcsetpgrp" );
return;
}
}
else break;
}
/*
Save jobs terminal modes.
*/
while( 1 )
{
if( tcgetattr (0, &j->tmodes) )
{
if( errno != EINTR )
{
debug( 1, L"Could not return shell to foreground" );
wperror( L"tcgetattr" );
return;
}
}
else
break;
}
/*
Restore the shell's terminal modes.
*/
while( 1 )
{
if( tcsetattr (0, TCSADRAIN, &shell_modes))
{
if( errno != EINTR )
{
debug( 1, L"Could not return shell to foreground" );
wperror( L"tcsetattr" );
return;
}
}
else
break;
}
signal_unblock();
}
}
}

15
proc.h
View file

@ -196,11 +196,6 @@ int job_reap( int interactive );
*/
void job_handle_signal( int signal, siginfo_t *info, void *con );
/**
Clean up before exiting
*/
void proc_destroy();
#ifdef HAVE__PROC_SELF_STAT
/**
@ -225,4 +220,14 @@ void proc_update_jiffies();
*/
void proc_sanity_check();
/*
Initializations
*/
void proc_init();
/**
Clean up before exiting
*/
void proc_destroy();
#endif

View file

@ -239,11 +239,6 @@ static reader_data_t *data=0;
static int end_loop = 0;
/**
This struct should be continually updated by signals as the term resizes, and as such always contain the correct current size.
*/
static struct winsize termsize;
static int new_size=0;
/**
@ -285,8 +280,6 @@ static int interupted=0;
static void reader_save_status();
static void reader_check_status();
static void reader_super_highlight_me_plenty( wchar_t * buff, int *color, int pos, array_list_t *error );
static void check_winch();
static struct termios old_modes;
@ -332,8 +325,7 @@ static void term_steal()
break;
}
reader_handle_winch(0 );
check_winch();
common_handle_winch(0 );
if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */
{
@ -372,19 +364,6 @@ void reader_handle_int( int sig )
}
int reader_get_width()
{
return termsize.ws_col;
}
int reader_get_height()
{
return termsize.ws_row;
}
wchar_t *reader_current_filename()
{
return (wchar_t *)al_peek( &current_filename );
@ -444,7 +423,7 @@ static int check_size()
*/
static int force_repaint()
{
int max_width = reader_get_width() - data->prompt_width;
int max_width = common_get_width() - data->prompt_width;
int pref_width = my_wcswidth( data->buff ) + (data->buff_pos==data->buff_len);
return pref_width >= max_width;
}
@ -457,7 +436,7 @@ static int force_repaint()
*/
static int calc_output()
{
int max_width = reader_get_width() - data->prompt_width;
int max_width = common_get_width() - data->prompt_width;
int pref_width = my_wcswidth( data->buff ) + (data->buff_pos==data->buff_len);
if( pref_width <= max_width )
{
@ -1457,30 +1436,6 @@ static int handle_completions( array_list_t *comp )
}
}
void reader_handle_winch( int signal )
{
if (ioctl(1,TIOCGWINSZ,&termsize)!=0)
{
return;
}
new_size=1;
}
static void check_winch()
{
if( new_size )
{
wchar_t tmp[64];
new_size=0;
swprintf(tmp, 64, L"%d", termsize.ws_row );
env_set( L"LINES", tmp, ENV_GLOBAL );
swprintf(tmp, 64, L"%d", termsize.ws_col );
env_set( L"COLUMNS", tmp, ENV_GLOBAL );
}
}
/**
Reset the terminal. This function is placed in the list of
functions to call when exiting by using the atexit function. It
@ -1539,8 +1494,7 @@ static void reader_interactive_init()
history_init();
reader_handle_winch(0);
check_winch();
common_handle_winch(0);
tcgetattr(0,&shell_modes); /* get the current terminal modes */
memcpy( &saved_modes,
@ -2487,7 +2441,6 @@ wchar_t *reader_readline()
but it should be ignored. (Example: Trying to add a tilde
(~) to digit)
*/
check_winch();
while( 1 )
{
c=input_readch();
@ -2529,8 +2482,6 @@ wchar_t *reader_readline()
break;
}
check_winch();
reader_check_status();
if( (last_char == R_COMPLETE) && (c != R_COMPLETE) && (!comp_empty) )

View file

@ -54,19 +54,6 @@ void reader_push_current_filename( wchar_t *fn );
*/
wchar_t *reader_pop_current_filename();
/**
Returns the width of the terminal window, so that not all
functions that use these values continually have to keep track of
it.
*/
int reader_get_width();
/**
Returns the height of the terminal window, so that not all
functions that use these values continually have to keep track of
it.
*/
int reader_get_height();
/**
Write the title to the titlebar. This function is called just
before a new application starts executing and just after it
@ -191,7 +178,9 @@ void reader_current_token_extent( wchar_t **a, wchar_t **b, wchar_t **pa, wchar_
*/
void reader_replace_current_token( wchar_t *new_token );
void reader_handle_winch( int signal );
/**
The readers interupt signal handler. Cancels all currently running blocks.
*/
void reader_handle_int( int signal );

View file

@ -313,7 +313,7 @@ static void default_handler(int signal, siginfo_t *info, void *context)
*/
static void handle_winch( int sig, siginfo_t *info, void *context )
{
reader_handle_winch( sig );
common_handle_winch( sig );
default_handler( sig, 0, 0 );
}
@ -395,7 +395,7 @@ void signal_set_handlers()
sigaction( SIGTTIN, &act, 0);
sigaction( SIGTTOU, &act, 0);
act.sa_handler = &handle_int;
act.sa_sigaction = &handle_int;
act.sa_flags = SA_SIGINFO;
if( sigaction( SIGINT, &act, 0) )
{
@ -412,7 +412,7 @@ void signal_set_handlers()
}
act.sa_flags = SA_SIGINFO;
act.sa_handler= &handle_winch;
act.sa_sigaction= &handle_winch;
if( sigaction( SIGWINCH, &act, 0 ) )
{
wperror( L"sigaction" );
@ -459,8 +459,46 @@ void signal_handle( int sig, int do_handle )
return;
sigemptyset( & act.sa_mask );
if( do_handle )
{
act.sa_flags=SA_SIGINFO;
act.sa_sigaction = (do_handle?&default_handler:SIG_DFL);
act.sa_sigaction = &default_handler;
}
else
{
act.sa_flags=0;
act.sa_handler = SIG_DFL;
}
sigaction( sig, &act, 0);
}
void signal_block()
{
int i;
sigset_t chldset;
sigemptyset( &chldset );
for( i=0; lookup[i].desc ; i++ )
{
sigaddset( &chldset, lookup[i].signal );
}
sigprocmask(SIG_BLOCK, &chldset, 0);
}
void signal_unblock()
{
int i;
sigset_t chldset;
sigemptyset( &chldset );
for( i=0; lookup[i].desc ; i++ )
{
sigaddset( &chldset, lookup[i].signal );
}
sigprocmask(SIG_UNBLOCK, &chldset, 0);
}

View file

@ -31,6 +31,19 @@ void signal_reset_handlers();
void signal_set_handlers();
/**
Tell fish to catch the specified signal and fire an event, instead of performing the default action
Tell fish what to do on the specified signal.
\param sig The signal to specify the action of
\param do_handle If true fish will catch the specified signal and fire an event, otherwise the default action (SIG_DFL) will be set
*/
void signal_handle( int sig, int do_handle );
/*
Block all signals
*/
void signal_block();
/**
Unblock all signals
*/
void signal_unblock();

44
wutil.c
View file

@ -194,23 +194,26 @@ void wperror(const wchar_t *s)
#if !HAVE_WPRINTF
/*
Here is my own implementation of *wprintf, included since NetBSD does
not provide one of it's own.
*/
/**
This function is defined to help vgwprintf when it wants to call
itself recursively
*/
static int gwprintf( void (*writer)(wchar_t),
const wchar_t *filter,
... );
Generic formatting function. All other string formatting functions
are secretly a wrapper around this function. vgprintf does not
implement all the filters supported by printf, only those that are
currently used by fish. vgprintf internally uses snprintf to
implement the %f %d and %u filters.
Currently supported functionality:
/**
Generic formatting function. All other formatting functions are
secretly a wrapper around this function.
- precision specification, both through .* and .N
- width specification through *
- long versions of all filters thorugh l and ll prefix
- Character outout using %c
- String output through %s
- Floating point number output through %f
- Integer output through %d or %i
- Unsigned integer output through %u
For a full description on the usage of *printf, see use 'man 3 printf'.
*/
static int vgwprintf( void (*writer)(wchar_t),
const wchar_t *filter,
@ -530,21 +533,6 @@ static int vgwprintf( void (*writer)(wchar_t),
return count;
}
static int gwprintf( void (*writer)(wchar_t),
const wchar_t *filter,
... )
{
va_list va;
int written;
va_start( va, filter );
written=vgwprintf( writer,
filter,
va );
va_end( va );
return written;
}
/**
Holds data for swprintf writer
*/