From 9ebdc16be6bf347dbd0b892f73f4e8329e970916 Mon Sep 17 00:00:00 2001 From: axel Date: Sun, 14 May 2006 20:16:23 +1000 Subject: [PATCH] Fix the longstanding hang-on-exit bug in eterm, as well as making sure the history is saved when the terminal emulator exits darcs-hash:20060514101623-ac50b-f8ce693ec111e3c158640ef8de309bf7e5484c5b.gz --- builtin.c | 2 +- event.c | 22 ++++++++++++++++ event.h | 5 ++++ input.c | 9 ++++--- input.h | 2 +- input_common.c | 25 ++++++++++-------- input_common.h | 3 ++- main.c | 7 ++--- reader.c | 70 ++++++++++++++++++++++++++++++++++++-------------- reader.h | 7 ++++- signal.c | 28 +++++++++++++++++++- util.c | 1 + 12 files changed, 141 insertions(+), 40 deletions(-) diff --git a/builtin.c b/builtin.c index 592a12c39..ed4ecc67f 100644 --- a/builtin.c +++ b/builtin.c @@ -1857,7 +1857,7 @@ static int builtin_exit( wchar_t **argv ) return 1; } - reader_exit( 1 ); + reader_exit( 1, 0 ); return ec; } diff --git a/event.c b/event.c index f45c95f4b..6c42414e7 100644 --- a/event.c +++ b/event.c @@ -653,3 +653,25 @@ void event_free( event_t *e ) free( (void *)e->param1.variable ); free( e ); } + +int event_signal_listen( int signal ) +{ + int i; + + if( !events ) + return 0; + + for( i=0; itype == EVENT_SIGNAL && + (e->param1.signal == signal || e->param1.signal == EVENT_ANY_SIGNAL) ) + { + return 1; + } + } + return 0; + + +} diff --git a/event.h b/event.h index 9bd3f81bd..9b09938e4 100644 --- a/event.h +++ b/event.h @@ -136,4 +136,9 @@ void event_free( event_t *e ); */ const wchar_t *event_get_desc( event_t *e ); +/** + Returns a non-zero status if there are event listeners that fire on the specified signal +*/ +int event_signal_listen( int signal ); + #endif diff --git a/input.c b/input.c index 27b7b98ef..4226cacbe 100644 --- a/input.c +++ b/input.c @@ -119,7 +119,8 @@ const wchar_t *name_arr[] = L"history-token-search-backward", L"history-token-search-forward", L"self-insert", - L"null" + L"null", + L"eof" } ; @@ -155,7 +156,8 @@ const wchar_t *desc_arr[] = L"Search backward through list of previous commands for matching token", L"Search forward through list of previous commands for matching token", L"Insert the pressed key", - L"Do nothing" + L"Do nothing", + L"End of file" } ; @@ -191,7 +193,8 @@ const wchar_t code_arr[] = R_HISTORY_TOKEN_SEARCH_BACKWARD, R_HISTORY_TOKEN_SEARCH_FORWARD, R_SELF_INSERT, - R_NULL + R_NULL, + R_EOF } ; diff --git a/input.h b/input.h index e5a375bbd..8b3a3175e 100644 --- a/input.h +++ b/input.h @@ -17,7 +17,7 @@ inputrc information for key bindings. */ enum { - R_BEGINNING_OF_LINE = R_NULL+1, + R_BEGINNING_OF_LINE = R_NULL+10, /* This give input_common ten slots for lowlevel keycodes */ R_END_OF_LINE, R_FORWARD_CHAR, R_BACKWARD_CHAR, diff --git a/input_common.c b/input_common.c index b271b6a51..dcb8bac00 100644 --- a/input_common.c +++ b/input_common.c @@ -64,7 +64,7 @@ static wint_t readb() { unsigned char arr[1]; int do_loop = 0; - + do { fd_set fd; @@ -93,17 +93,21 @@ static wint_t readb() { int res = interrupt_handler(); if( res ) + { return res; + } } + do_loop = 1; break; } default: { - debug( 0, L"Error while reading input from keyboard, shutting down" ); - wperror(L"read"); - exit(1); + /* + The teminal has been closed. Save and exit. + */ + return R_EOF; } } } @@ -120,11 +124,12 @@ static wint_t readb() } if( FD_ISSET( 0, &fd ) ) { - if( read_blocked( 0, arr, 1 ) == -1 ) + if( read_blocked( 0, arr, 1 ) != 1 ) { - debug( 0, L"Error while reading input from keyboard, shutting down" ); - wperror(L"read"); - exit(1); + /* + The teminal has been closed. Save and exit. + */ + return R_EOF; } do_loop = 0; } @@ -179,8 +184,8 @@ wchar_t input_common_readch( int timed ) int sz; - if( b == R_NULL ) - return R_NULL; + if( (b == R_NULL) || (b == R_EOF) ) + return b; bb=b; diff --git a/input_common.h b/input_common.h index bf8182ddc..a2b361f79 100644 --- a/input_common.h +++ b/input_common.h @@ -20,7 +20,8 @@ enum requested but none could be delivered, or when an exception happened. */ - R_NULL = INPUT_COMMON_RESERVED + R_NULL = INPUT_COMMON_RESERVED, + R_EOF } ; diff --git a/main.c b/main.c index c2d9de391..f3324ebf0 100644 --- a/main.c +++ b/main.c @@ -276,7 +276,7 @@ int main( int argc, char **argv ) wchar_t *cmd_wcs = str2wcs( cmd ); res = eval( cmd_wcs, 0, TOP ); free(cmd_wcs); - reader_exit(0); + reader_exit(0, 0); } else { @@ -336,9 +336,9 @@ int main( int argc, char **argv ) } } } - - proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res ); + proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res ); + history_destroy(); complete_destroy(); proc_destroy(); @@ -355,5 +355,6 @@ int main( int argc, char **argv ) halloc_util_destroy(); intern_free_all(); + return res; } diff --git a/reader.c b/reader.c index 212a7c528..dd59a87d8 100644 --- a/reader.c +++ b/reader.c @@ -232,6 +232,11 @@ typedef struct reader_data When this is true, the reader will exit */ int end_loop; + /** + If this is true, exit reader even if there are running + jobs. This happens if we press e.g. ^D twice. + */ + int prev_end_loop; /** Pointer to previous reader_data @@ -299,6 +304,11 @@ 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 ); +/** + Variable to keep track of forced exits - see \c reader_exit_forced(); +*/ +static int exit_forced; + /** Give up control of terminal @@ -370,6 +380,12 @@ static int room_for_usec(struct stat *st) return res; } +int reader_exit_forced() +{ + return exit_forced; +} + + /** string_buffer used as temporary storage for the reader_readline function */ @@ -869,11 +885,14 @@ void reader_destroy() } -void reader_exit( int do_exit ) +void reader_exit( int do_exit, int forced ) { if( data ) data->end_loop=do_exit; end_loop=do_exit; + if( forced ) + exit_forced = 1; + } void repaint() @@ -2230,7 +2249,6 @@ int exit_status() */ static int read_i() { - int prev_end_loop=0; reader_push(L"fish"); reader_set_complete_function( &complete ); @@ -2238,6 +2256,7 @@ static int read_i() reader_set_test_function( &shell_test ); data->prompt_width=60; + data->prev_end_loop=0; while( (!data->end_loop) && (!sanity_check()) ) { @@ -2254,12 +2273,7 @@ static int read_i() during evaluation. */ - tmp = wcsdup( reader_readline() ); - - data->buff_pos=data->buff_len=0; - data->buff[data->buff_len]=L'\0'; - reader_run_command( tmp ); - free( tmp ); + tmp = reader_readline(); if( data->end_loop) { @@ -2275,17 +2289,24 @@ static int read_i() } } - if( !prev_end_loop && has_job ) + if( !reader_exit_forced() && !data->prev_end_loop && has_job ) { writestr(_( L"There are stopped jobs\n" )); write_prompt(); data->end_loop = 0; - prev_end_loop=1; + data->prev_end_loop=1; } } else { - prev_end_loop=0; + tmp = wcsdup( tmp ); + + data->buff_pos=data->buff_len=0; + data->buff[data->buff_len]=L'\0'; + reader_run_command( tmp ); + free( tmp ); + + data->prev_end_loop=0; } } @@ -2442,6 +2463,14 @@ wchar_t *reader_readline() break; } + case R_EOF: + { + exit_forced = 1; + data->end_loop=1; + debug( 1, L"got R_EOF" ); + break; + } + /* complete */ case R_COMPLETE: { @@ -2833,14 +2862,17 @@ wchar_t *reader_readline() } al_destroy( &comp ); - if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */ - { - wperror(L"tcsetattr"); - exit(1); - } - - set_color( FISH_COLOR_RESET, FISH_COLOR_RESET ); - + if( !reader_exit_forced() ) + { + if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */ + { + wperror(L"tcsetattr"); + exit(1); + } + + set_color( FISH_COLOR_RESET, FISH_COLOR_RESET ); + } + return data->buff; } diff --git a/reader.h b/reader.h index 89c35af90..ec67266d6 100644 --- a/reader.h +++ b/reader.h @@ -21,7 +21,7 @@ int reader_read( int fd); /** Tell the shell that it should exit after the currently running command finishes. */ -void reader_exit( int do_exit ); +void reader_exit( int do_exit, int force ); /** Check that the reader is in a sane state @@ -162,5 +162,10 @@ void reader_replace_current_token( wchar_t *new_token ); */ void reader_handle_int( int signal ); +/** + This function returns true if fish is exiting by force, i.e. because stdin died +*/ +int reader_exit_forced(); + #endif diff --git a/signal.c b/signal.c index 71ba0360a..a679ae30c 100644 --- a/signal.c +++ b/signal.c @@ -367,6 +367,7 @@ const wchar_t *signal_get_desc( int sig ) static void default_handler(int signal, siginfo_t *info, void *context) { event_t e; + e.type=EVENT_SIGNAL; e.param1.signal = signal; e.function_name=0; @@ -383,6 +384,22 @@ static void handle_winch( int sig, siginfo_t *info, void *context ) default_handler( sig, 0, 0 ); } +/** + Respond to a winch signal by checking the terminal size +*/ +static void handle_hup( int sig, siginfo_t *info, void *context ) +{ + if( event_signal_listen( SIGHUP ) ) + { + default_handler( sig, 0, 0 ); + } + else + { + reader_exit( 1, 1 ); + } + +} + /** Interactive mode ^C handler. Respond to int signal by setting interrupted-flag and stopping all loops and conditionals. @@ -479,7 +496,7 @@ void signal_set_handlers() wperror( L"sigaction" ); exit(1); } - + act.sa_flags = SA_SIGINFO; act.sa_sigaction= &handle_winch; if( sigaction( SIGWINCH, &act, 0 ) ) @@ -488,6 +505,14 @@ void signal_set_handlers() exit(1); } + act.sa_flags = SA_SIGINFO; + act.sa_sigaction= &handle_hup; + if( sigaction( SIGHUP, &act, 0 ) ) + { + wperror( L"sigaction" ); + exit(1); + } + } else { @@ -510,6 +535,7 @@ void signal_set_handlers() exit(1); } } + } void signal_handle( int sig, int do_handle ) diff --git a/util.c b/util.c index 608b9a3f1..342440a3c 100644 --- a/util.c +++ b/util.c @@ -809,6 +809,7 @@ int wcsfilecmp( const wchar_t *a, const wchar_t *b ) { return 1; } + int secondary_diff=0; if( iswdigit( *a ) && iswdigit( *b ) ) {