From 0ebf6db4b972648ff5a2bed41120bff7b681ea37 Mon Sep 17 00:00:00 2001 From: axel Date: Fri, 14 Oct 2005 21:40:33 +1000 Subject: [PATCH] Increase fish robustness by improving signal handling when forking jobs and minor signal handling improvements darcs-hash:20051014114033-ac50b-8d0f6274ac590f1b6dbe82c55366f44ed7debf20.gz --- builtin.c | 2 +- common.c | 57 ++++++++++++++++++--- common.h | 43 ++++++++++++++-- env.c | 38 ++++++++++++-- env.h | 8 +-- event.c | 19 +++++-- exec.c | 112 ++++++++++++++++++----------------------- fish_tests.c | 2 + main.c | 2 +- parser.c | 26 +++++----- proc.c | 140 +++++++++++++++++++++------------------------------ proc.h | 15 ++++-- reader.c | 59 ++-------------------- reader.h | 17 ++----- signal.c | 48 ++++++++++++++++-- signal.h | 15 +++++- wutil.c | 44 ++++++---------- 17 files changed, 355 insertions(+), 292 deletions(-) diff --git a/builtin.c b/builtin.c index be14bdb13..2908e19b7 100644 --- a/builtin.c +++ b/builtin.c @@ -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" ); diff --git a/common.c b/common.c index 14ea33569..a819845f8 100644 --- a/common.c +++ b/common.c @@ -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; @@ -817,35 +822,51 @@ void debug( int level, wchar_t *msg, ... ) int overflow = 0; 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; - + 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 ); + putwc( L'\n', stderr ); fwprintf( stderr, L"%ls-\n", token ); free( token ); line_width=0; } 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; +} + diff --git a/common.h b/common.h index d23d3a076..c554f52ef 100644 --- a/common.h +++ b/common.h @@ -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: + + debug( 1, L"Pi = %.3f", M_PI ); + + 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 ); diff --git a/env.c b/env.c index 0971840f3..8fda3a7df 100644 --- a/env.c +++ b/env.c @@ -251,7 +251,7 @@ void env_init() hash_put( &env_read_only, L"LINES", L"" ); hash_put( &env_read_only, L"COLUMNS", L"" ); hash_put( &env_read_only, L"PWD", L"" ); - + /* HOME should be writeable by root, since this is often a convenient way to install software. @@ -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,10 +676,10 @@ int env_exist( const wchar_t *key ) env_node_t *env = top; wchar_t *item; - if( wcscmp( key, L"history" ) == 0 ) - { - return 1; - } + if( hash_get( &env_read_only, key ) ) + { + return 1; + } while( env != 0 ) { @@ -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 ) diff --git a/env.h b/env.h index b982fa36a..bd43e3caa 100644 --- a/env.h +++ b/env.h @@ -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 ); diff --git a/event.c b/event.c index 3c2ff486f..669f6beb8 100644 --- a/event.c +++ b/event.c @@ -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,16 +391,19 @@ 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; icount; i++ ) { e.param1.signal = lst->signal[i]; al_set( &a, 0, sig2wcs( e.param1.signal ) ); event_fire_internal( &e, &a ); - } - + } + al_destroy( &a ); } diff --git a/exec.c b/exec.c index 08ec35a4d..ec5b35d90 100644 --- a/exec.c +++ b/exec.c @@ -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 ) { @@ -400,13 +390,12 @@ 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(); + } @@ -539,8 +528,13 @@ static int internal_exec_helper( const wchar_t *def, io_data_t *io_internal = io_transmogrify( io ); 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,56 +577,37 @@ 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( tcsetpgrp (0, j->pgid) ) - { - if( errno != EINTR ) - { - debug( 1, L"Could not send job %d ('%ls')to foreground", - j->job_id, - j->command ); - wperror( L"tcsetpgrp" ); - return -1; - } - } - else - break; + debug( 1, L"Could not send job %d ('%ls')to foreground", + j->job_id, + j->command ); + wperror( L"tcsetpgrp" ); + return -1; } } if( j->fg && new_pgid) { - while( 1 ) + if( tcsetpgrp (0, j->pgid) ) { - if( tcsetpgrp (0, j->pgid) ) - { - if( errno != EINTR ) - { - debug( 1, L"Could not send job %d ('%ls')to foreground", - j->job_id, - j->command ); - wperror( L"tcsetpgrp" ); - return -1; - } - } - else - break; + debug( 1, L"Could not send job %d ('%ls')to foreground", + j->job_id, + j->command ); + wperror( L"tcsetpgrp" ); + return -1; } - } - + } } 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 ); @@ -1179,7 +1167,7 @@ int exec_subshell( const wchar_t *cmd, PACKAGE_BUGREPORT ); return 0; } - + is_subshell=1; io_buffer= io_buffer_create(); diff --git a/fish_tests.c b/fish_tests.c index ad37c4c8f..6eaae62b6 100644 --- a/fish_tests.c +++ b/fish_tests.c @@ -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(); } diff --git a/main.c b/main.c index 8fecbdef5..98737f358 100644 --- a/main.c +++ b/main.c @@ -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; diff --git a/parser.c b/parser.c index f0ca2f27a..b3d063dde 100644 --- a/parser.c +++ b/parser.c @@ -477,7 +477,7 @@ wchar_t *parser_cdpath_get( wchar_t *dir ) { die_mem(); } - + for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state ); nxt_path != 0; nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) ) @@ -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 ); @@ -2300,8 +2302,8 @@ int parser_test( wchar_t * buff, print_errors(); } } - - + + if( babble && count>0 ) { error( SYNTAX_ERROR, @@ -2309,9 +2311,9 @@ int parser_test( wchar_t * buff, block_pos[count-1] ); print_errors(); } - + tok_destroy( &tok ); - + current_tokenizer=previous_tokenizer; current_tokenizer_pos = previous_pos; diff --git a/proc.c b/proc.c index c23da4fb5..3f188ad85 100644 --- a/proc.c +++ b/proc.c @@ -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; @@ -832,49 +842,34 @@ void job_continue (job_t *j, int cont) { if( !is_subshell && is_interactive && !is_block) { - + /* Put the job into the foreground. */ if( j->fg ) { - while( 1 ) + signal_block(); + if( tcsetpgrp (0, j->pgid) ) { - if( tcsetpgrp (0, j->pgid) ) - { - if( errno != EINTR ) - { - debug( 1, - L"Could not send job %d ('%ls') to foreground", - j->job_id, - j->command ); - wperror( L"tcsetpgrp" ); - return; - } - } - else - break; + debug( 1, + L"Could not send job %d ('%ls') to foreground", + j->job_id, + j->command ); + wperror( L"tcsetpgrp" ); + return; } if( cont ) { - while( 1 ) + if( tcsetattr (0, TCSADRAIN, &j->tmodes)) { - if( tcsetattr (0, TCSADRAIN, &j->tmodes)) - { - if( errno != EINTR ) - { - debug( 1, - L"Could not send job %d ('%ls') to foreground", - j->job_id, - j->command ); - wperror( L"tcsetattr" ); - return; - } - } - else - break; - } - + debug( 1, + L"Could not send job %d ('%ls') to foreground", + j->job_id, + j->command ); + wperror( L"tcsetattr" ); + return; + } } + 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( tcsetpgrp (0, getpid()) ) - { - if( errno != EINTR ) - { - debug( 1, L"Could not return shell to foreground" ); - wperror( L"tcsetpgrp" ); - return; - } - } - else break; + debug( 1, L"Could not return shell to foreground" ); + wperror( L"tcsetpgrp" ); + return; } /* Save jobs terminal modes. */ - while( 1 ) + if( tcgetattr (0, &j->tmodes) ) { - if( tcgetattr (0, &j->tmodes) ) - { - if( errno != EINTR ) - { - debug( 1, L"Could not return shell to foreground" ); - wperror( L"tcgetattr" ); - return; - } - } - else - break; + debug( 1, L"Could not return shell to foreground" ); + wperror( L"tcgetattr" ); + return; } /* Restore the shell's terminal modes. */ - while( 1 ) + if( tcsetattr (0, TCSADRAIN, &shell_modes)) { - if( tcsetattr (0, TCSADRAIN, &shell_modes)) - { - if( errno != EINTR ) - { - debug( 1, L"Could not return shell to foreground" ); - wperror( L"tcsetattr" ); - return; - } - } - else - break; + debug( 1, L"Could not return shell to foreground" ); + wperror( L"tcsetattr" ); + return; } + signal_unblock(); } } } diff --git a/proc.h b/proc.h index 9c11a3860..67539f719 100644 --- a/proc.h +++ b/proc.h @@ -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 diff --git a/reader.c b/reader.c index 5586c2704..b74805e6d 100644 --- a/reader.c +++ b/reader.c @@ -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( ¤t_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 ) { @@ -1405,7 +1384,7 @@ static int handle_completions( array_list_t *comp ) len = &data->buff[data->buff_pos]-prefix_start; - + if( len <= PREFIX_MAX_LEN ) { prefix = malloc( sizeof(wchar_t)*(len+1) ); @@ -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) ) diff --git a/reader.h b/reader.h index ac61098d9..c152bd9a3 100644 --- a/reader.h +++ b/reader.h @@ -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 ); diff --git a/signal.c b/signal.c index b31a1390d..115e38374 100644 --- a/signal.c +++ b/signal.c @@ -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 ); - act.sa_flags=SA_SIGINFO; - act.sa_sigaction = (do_handle?&default_handler:SIG_DFL); + if( do_handle ) + { + act.sa_flags=SA_SIGINFO; + 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); +} + + diff --git a/signal.h b/signal.h index ef491a143..d7878ae1d 100644 --- a/signal.h +++ b/signal.h @@ -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(); diff --git a/wutil.c b/wutil.c index 09b26d768..7f8b09846 100644 --- a/wutil.c +++ b/wutil.c @@ -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 */