From b9b841f60319fb5838060cb724a4882ef3be9a74 Mon Sep 17 00:00:00 2001 From: axel Date: Thu, 6 Oct 2005 08:37:08 +1000 Subject: [PATCH] Initial update for new event subsystem darcs-hash:20051005223708-ac50b-8a8d7e003e1c24747f3f154cb66b6c1a1015c35b.gz --- Makefile.in | 3 +- builtin.c | 147 +++++++++++++----- env.c | 187 ++++++++++++---------- event.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++ event.h | 107 +++++++++++++ exec.c | 3 +- fish_tests.c | 2 + function.c | 29 +++- function.h | 1 + highlight.c | 6 - input.c | 1 - main.c | 6 +- parser.c | 6 +- parser.h | 11 ++ proc.c | 152 +----------------- proc.h | 2 + reader.c | 154 +++--------------- reader.h | 4 + tokenizer.c | 4 - util.c | 10 ++ util.h | 2 + wildcard.h | 1 - wutil.h | 1 + 23 files changed, 842 insertions(+), 425 deletions(-) create mode 100644 event.c create mode 100644 event.h diff --git a/Makefile.in b/Makefile.in index e763cbb1e..e3c242cd1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,7 +51,8 @@ docdir = @docdir@ COMMON_OBJS := function.o builtin.o common.o complete.o env.o exec.o \ expand.o highlight.o history.o kill.o parser.o proc.o reader.o \ sanity.o tokenizer.o util.o wildcard.o wgetopt.o wutil.o input.o \ - output.o intern.o env_universal.o env_universal_common.o input_common.o + output.o intern.o env_universal.o env_universal_common.o \ + input_common.o event.o signal.o # builtin_help.h exists, but builtin_help.c is autogenerated COMMON_OBJS_WITH_HEADER := builtin_help.o diff --git a/builtin.c b/builtin.c index 3eb679c94..152bb670f 100644 --- a/builtin.c +++ b/builtin.c @@ -57,6 +57,7 @@ #include "input_common.h" #include "input.h" #include "intern.h" +#include "event.h" /** The default prompt for the read command @@ -726,7 +727,8 @@ static int builtin_function( wchar_t **argv ) int res=0; wchar_t *desc=0; int is_binding=0; - + array_list_t *events = al_new(); + woptind=0; const static struct woption @@ -740,19 +742,31 @@ static int builtin_function( wchar_t **argv ) L"key-binding", no_argument, 0, 'b' } , + { + L"on-signal", required_argument, 0, 's' + } + , + { + L"on-exit", required_argument, 0, 'x' + } + , + { + L"on-variable", required_argument, 0, 'v' + } + , { 0, 0, 0, 0 } } ; - while( 1 ) + while( 1 && (!res ) ) { int opt_index = 0; int opt = wgetopt_long( argc, argv, - L"d:b", + L"bd:s:x:v:", long_options, &opt_index ); if( opt == -1 ) @@ -772,7 +786,9 @@ static int builtin_function( wchar_t **argv ) (void *)0); builtin_print_help( argv[0], sb_err ); - return 1; + res = 1; + break; + case 'd': desc=woptarg; @@ -782,46 +798,84 @@ static int builtin_function( wchar_t **argv ) is_binding=1; break; - + case 's': + { + event_t *e = malloc( sizeof(event_t)); + if( !e ) + die_mem(); + e->type = EVENT_SIGNAL; + e->signal = wcs2sig( woptarg ); + e->function_name=0; + al_push( events, e ); + break; + } + + case 'v': + { + event_t *e = malloc( sizeof(event_t)); + if( !e ) + die_mem(); + e->type = EVENT_VARIABLE; + e->variable = wcsdup( woptarg ); + e->function_name=0; + al_push( events, e ); + break; + } + + case 'x': + { + event_t *e = malloc( sizeof(event_t)); + if( !e ) + die_mem(); + e->type = EVENT_EXIT; + e->pid = wcstol( woptarg, 0, 10 ); + e->function_name=0; + al_push( events, e ); + break; + } + case '?': builtin_print_help( argv[0], sb_err ); - - return 1; + res = 1; + break; } } - - if( argc-woptind != 1 ) - { - sb_printf( sb_err, - L"%ls: Expected one argument, got %d\n", - argv[0], - argc-woptind ); - res=1; + + if( !res ) + { + if( argc-woptind != 1 ) + { + sb_printf( sb_err, + L"%ls: Expected one argument, got %d\n", + argv[0], + argc-woptind ); + res=1; + } + else if( !(is_binding?wcsbindingname( argv[woptind] ) : wcsvarname( argv[woptind] ) )) + { + sb_append2( sb_err, + argv[0], + L": illegal function name \'", + argv[woptind], + L"\'\n", + (void *)0 ); + + res=1; + } + else if( parser_is_reserved(argv[woptind] ) ) + { + + sb_append2( sb_err, + argv[0], + L": the name \'", + argv[woptind], + L"\' is reserved,\nand can not be used as a function name\n", + (void *)0 ); + res=1; + } } - else if( !(is_binding?wcsbindingname( argv[woptind] ) : wcsvarname( argv[woptind] ) )) - { - sb_append2( sb_err, - argv[0], - L": illegal function name \'", - argv[woptind], - L"\'\n", - (void *)0 ); - - res=1; - } - else if( parser_is_reserved(argv[woptind] ) ) - { - - sb_append2( sb_err, - argv[0], - L": the name \'", - argv[woptind], - L"\' is reserved,\nand can not be used as a function name\n", - (void *)0 ); - res=1; - } if( res ) { @@ -859,13 +913,26 @@ static int builtin_function( wchar_t **argv ) sb_append( sb_err, L"\n" ); parser_push_block( FAKE ); + + al_foreach( events, (void (*)(const void *))&event_free ); + al_destroy( events ); + } else { + int i; + parser_push_block( FUNCTION_DEF ); current_block->function_name=wcsdup(argv[woptind]); current_block->function_description=desc?wcsdup(desc):0; current_block->function_is_binding = is_binding; + current_block->function_events = events; + for( i=0; ifunction_name = wcsdup( current_block->function_name ); + } + } current_block->tok_pos = parser_get_pos(); @@ -2388,6 +2455,8 @@ static int builtin_end( wchar_t **argv ) case FUNCTION_DEF: { + int i; + /** Copy the text from the beginning of the function until the end command and use as the new definition @@ -2402,8 +2471,10 @@ static int builtin_end( wchar_t **argv ) function_add( current_block->function_name, def, current_block->function_description, + current_block->function_events, current_block->function_is_binding ); - } + } + free(def); } break; diff --git a/env.c b/env.c index 10d232a4f..e5a38dd3f 100644 --- a/env.c +++ b/env.c @@ -40,6 +40,7 @@ #include "parser.h" #include "env_universal.h" #include "input_common.h" +#include "event.h" /** Command used to start fishd @@ -80,7 +81,7 @@ typedef struct env_node */ struct env_node *next; } -env_node_t; + env_node_t; /** A variable entry. Stores the value of a variable and whether it @@ -92,7 +93,7 @@ typedef struct var_entry int export; /**< Whether the variable should be exported */ wchar_t val[0]; /**< The value of the variable */ } -var_entry_t; + var_entry_t; /** Top node on the function stack @@ -328,7 +329,11 @@ void env_set( const wchar_t *key, env_node_t *node; int has_changed_old = has_changed; int has_changed_new = 0; - var_entry_t *e=0; + var_entry_t *e=0; + int done=0; + + event_t ev; + array_list_t ev_list; if( (var_mode & ENV_USER ) && hash_get( &env_read_only, key ) ) @@ -363,112 +368,124 @@ void env_set( const wchar_t *key, env_universal_set( key, val, export ); - return; - } - - if( val == 0 ) - { - wchar_t *prev_val; - free_val = 1; - prev_val = env_get( key ); - val = wcsdup( prev_val?prev_val:L"" ); - } - - node = env_get_node( key ); - if( node && &node->env != 0 ) - { - e = (var_entry_t *) hash_get( &node->env, - key ); - - if( e->export ) - has_changed_new = 1; - - } - - if( (var_mode & ENV_LOCAL) || - (var_mode & ENV_GLOBAL) ) - { - node = ( var_mode & ENV_GLOBAL )?global_env:top; } else { - if( node ) + + if( val == 0 ) { - if( !(var_mode & ENV_EXPORT ) && - !(var_mode & ENV_UNEXPORT ) ) - { - var_mode = e->export?ENV_EXPORT:0; - } + wchar_t *prev_val; + free_val = 1; + prev_val = env_get( key ); + val = wcsdup( prev_val?prev_val:L"" ); + } + + node = env_get_node( key ); + if( node && &node->env != 0 ) + { + e = (var_entry_t *) hash_get( &node->env, + key ); + + if( e->export ) + has_changed_new = 1; + + } + + if( (var_mode & ENV_LOCAL) || + (var_mode & ENV_GLOBAL) ) + { + node = ( var_mode & ENV_GLOBAL )?global_env:top; } else { - if( !proc_had_barrier) - env_universal_barrier(); - - if( env_universal_get( key ) ) + if( node ) { - int export = 0; - if( !(var_mode & ENV_EXPORT ) && !(var_mode & ENV_UNEXPORT ) ) - { - env_universal_get_export( key ); + { + var_mode = e->export?ENV_EXPORT:0; } - else - export = (var_mode & ENV_EXPORT ); - - env_universal_set( key, val, export ); - - return; } else { - /* - New variable with unspecified scope. The default scope is the innermost scope that is shadowing - */ - node = top; - while( node->next && !node->new_scope ) - node = node->next; + if( !proc_had_barrier) + env_universal_barrier(); + + if( env_universal_get( key ) ) + { + int export = 0; + if( !(var_mode & ENV_EXPORT ) && + !(var_mode & ENV_UNEXPORT ) ) + { + env_universal_get_export( key ); + } + else + export = (var_mode & ENV_EXPORT ); + + env_universal_set( key, val, export ); + + done = 1; + + } + else + { + /* + New variable with unspecified scope. The default scope is the innermost scope that is shadowing + */ + node = top; + while( node->next && !node->new_scope ) + node = node->next; + + } } } - } -// env_remove( key, 0 ); - void *k, *v; - hash_remove( &node->env, key, (const void **)&k, (const void **)&v ); - free( k ); - free( v ); + if( !done ) + { + void *k, *v; + hash_remove( &node->env, key, (const void **)&k, (const void **)&v ); + free( k ); + free( v ); - entry = malloc( sizeof( var_entry_t ) + - sizeof(wchar_t )*(wcslen(val)+1)); + entry = malloc( sizeof( var_entry_t ) + + sizeof(wchar_t )*(wcslen(val)+1)); - if( var_mode & ENV_EXPORT) - { - entry->export = 1; - has_changed_new = 1; - } - else - entry->export = 0; + if( var_mode & ENV_EXPORT) + { + entry->export = 1; + has_changed_new = 1; + } + else + entry->export = 0; - wcscpy( entry->val, val ); + wcscpy( entry->val, val ); - hash_put( &node->env, wcsdup(key), entry ); + hash_put( &node->env, wcsdup(key), entry ); - if( entry->export ) - { - node->export=1; - } - - if( free_val ) - free((void *)val); + if( entry->export ) + { + node->export=1; + } + if( free_val ) + free((void *)val); - has_changed = has_changed_old || has_changed_new; + has_changed = has_changed_old || has_changed_new; + } + + } -/* if( has_changed_new && !has_changed_old ) - fwprintf( stderr, L"Reexport after setting %ls to %ls, %d %d %d\n", key, val, has_changed_old, has_changed_new, has_changed ); -*/ + ev.type=EVENT_VARIABLE; + ev.variable = key; + ev.function_name = 0; + + al_init( &ev_list ); + al_push( &ev_list, L"VARIABLE" ); + al_push( &ev_list, key ); + + event_fire( &ev, &ev_list ); + al_destroy( &ev_list ); } /** @@ -560,7 +577,7 @@ wchar_t *env_get( const wchar_t *key ) while( env != 0 ) { res = (var_entry_t *) hash_get( &env->env, - key ); + key ); if( res != 0 ) { if( wcscmp( res->val, ENV_NULL )==0) @@ -602,7 +619,7 @@ int env_exist( const wchar_t *key ) while( env != 0 ) { res = (var_entry_t *) hash_get( &env->env, - key ); + key ); if( res != 0 ) { return 1; diff --git a/event.c b/event.c new file mode 100644 index 000000000..acc8d873c --- /dev/null +++ b/event.c @@ -0,0 +1,428 @@ +/** \file function.c + + Functions for storing and retrieving function information. + +*/ +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "util.h" +#include "function.h" +#include "proc.h" +#include "parser.h" +#include "common.h" +#include "intern.h" +#include "event.h" +#include "signal.h" + +/** + Number of signals that can be queued before an overflow occurs +*/ +#define SIG_UNHANDLED_MAX 64 + +/** + This struct contains a list of generated signals waiting to be + dispatched +*/ +typedef struct +{ + int count; + int overflow; + int signal[SIG_UNHANDLED_MAX]; +} + signal_list_t; + +/* + The signal event list. Actually two separate lists. One which is + active, which is the one that new events is written to. The inactive + one contains the events that are currently beeing performed. +*/ +static signal_list_t sig_list[2]; + +/** + The index of sig_list that is the list of signals currently written to +*/ +static int active_list=0; + +/** + List of event handlers +*/ +static array_list_t *events; +/** + List of event handlers that should be removed +*/ +static array_list_t *killme; + +/** + Tests if one event instance matches the definition of a event + class. If the class defines a function name, that will also be a + match criterion. + +*/ +static int event_match( event_t *class, event_t *instance ) +{ + if( class->function_name && instance->function_name ) + { + if( wcscmp( class->function_name, instance->function_name ) != 0 ) + return 0; + } + + if( class->type == EVENT_ANY ) + return 1; + + if( class->type != instance->type ) + return 0; + + + switch( class->type ) + { + + case EVENT_SIGNAL: + if( class->signal == EVENT_ANY_SIGNAL ) + return 1; + return class->signal == instance->signal; + + case EVENT_VARIABLE: + return wcscmp( instance->variable, class->variable )==0; + + case EVENT_EXIT: + if( class->pid == EVENT_ANY_PID ) + return 1; + return class->pid == instance->pid; + } + + /** + This should never be reached + */ + return 0; +} + + +/** + Create an identical copy of an event. Use deep copying, i.e. make + duplicates of any strings used as well. +*/ +static event_t *event_copy( event_t *event ) +{ + event_t *e = malloc( sizeof( event_t ) ); + if( !e ) + die_mem(); + memcpy( e, event, sizeof(event_t)); + + if( e->function_name ) + e->function_name = wcsdup( e->function_name ); + + if( e->type == EVENT_VARIABLE ) + e->variable = wcsdup( e->variable ); + + return e; +} + +void event_add_handler( event_t *event ) +{ + event_t *e = event_copy( event ); + + if( !events ) + events = al_new(); + + debug( 1, L"add event of type %d", e->type ); + + al_push( events, e ); +} + +void event_remove( event_t *criterion ) +{ + int i; + array_list_t *new_list = al_new(); + + /* + Because of concurrency issues, env_remove does not actually free + anything - instead it simply moves all events that should be + removed to the killme list. + */ + + if( !events ) + return; + + for( i=0; ifunction_name ); + + for( j=0; jbuff, 0, TOP ); + } + + if( b ) + { + sb_destroy( b ); + free( b ); + } + + if( fire ) + { + al_destroy( fire ); + free( fire ); + } + + /* + Free killed events + */ + event_free_kills(); + +} + +/** + Perform all pending signal events +*/ +static void event_fire_signal_events() +{ + while( sig_list[active_list].count > 0 ) + { + int i; + signal_list_t *lst; + event_t e; + array_list_t a; + al_init( &a ); + + sig_list[1-active_list].count=0; + sig_list[1-active_list].overflow=0; + active_list=1-active_list; + + e.type=EVENT_SIGNAL; + e.function_name=0; + + lst = &sig_list[1-active_list]; + + if( lst->overflow ) + { + debug( 0, L"Signal overflow. Signals have been ignored" ); + } + + for( i=0; icount; i++ ) + { + e.signal = lst->signal[i]; + al_set( &a, 0, sig2wcs( e.signal ) ); + event_fire_internal( &e, &a ); + } + + al_destroy( &a ); + + } +} + + +void event_fire( event_t *event, array_list_t *arguments ) +{ + + int is_event_old = is_event; + is_event=1; + + if( event && (event->type == EVENT_SIGNAL) ) + { + /* + This means we are in a signal handler. We must be very + careful not do do anything that could cause a memory + allocation or something else that might be illegal in a + signal handler. + */ + if( sig_list[active_list].count < SIG_UNHANDLED_MAX ) + sig_list[active_list].signal[sig_list[active_list].count++]=event->signal; + else + sig_list[active_list].overflow=1; + + return; + } + else + { + event_fire_signal_events(); + + if( event ) + event_fire_internal( event, arguments ); + + } + is_event = is_event_old; + +} + + +void event_init() +{ + sig_list[active_list].count=0; +} + +void event_destroy() +{ + if( events ) + { + al_foreach( events, (void (*)(const void *))&event_free ); + al_destroy( events ); + events=0; + } + if( killme ) + { + al_foreach( killme, (void (*)(const void *))&event_free ); + al_destroy( killme ); + killme=0; + } +} + +void event_free( event_t *e ) +{ + free( e->function_name ); + if( e->type == EVENT_VARIABLE ) + free( e->variable ); + free( e ); +} + diff --git a/event.h b/event.h new file mode 100644 index 000000000..7e032cdce --- /dev/null +++ b/event.h @@ -0,0 +1,107 @@ +/** \file event.h + +Event handling library + +*/ +#ifndef FISH_EVENT_H +#define FISH_EVENT_H + + +/** + The signal number that is used to match any signal +*/ +#define EVENT_ANY_SIGNAL -1 + +/** + The process id that is used to match any process id +*/ +#define EVENT_ANY_PID 0 + +enum +{ + EVENT_ANY, /**< Matches any event type (Not always any event, as the function name may limit the choice as well */ + EVENT_SIGNAL, /**< An event triggered by a signal */ + EVENT_VARIABLE, /**< An event triggered by a variable update */ + EVENT_EXIT, /**< An event triggered by a job or process exit */ +} + ; + +/** + The structure which represents an event. The event_t struct has + several event-related use-cases: + + - When used as a parameter to event_add, it represents a class of events, and function_name is the name of the function which will be called whenever an event matching the specified class occurs. This is also how events are stored internally. + - When used as a parameter to event_get, event_remove and event_fire, it represents a class of events, and if the function_name field is non-zero, only events which call the specified function will be returned. +*/ +typedef struct +{ + /** + Type of event + */ + int type; + union + { + /** + Signal number for signal-type events.Use EVENT_ANY_SIGNAL to match any signal + */ + int signal; + /** + Variable name for variable-type events. + */ + const wchar_t *variable; + /** + Process id for process-type events. Use EVENT_ANY_PID to match any pid. + */ + pid_t pid; + } + ; + + const wchar_t *function_name; +} + event_t; + +/** + Add an event handler +*/ +void event_add_handler( event_t *event ); + +/** + Remove all events matching the specified criterion. +*/ +void event_remove( event_t *event ); + +/** + Return all events which match the specified event class + + \param criterion Is the class of events to return. If the criterion has a non-null function_name, only events which trigger the specified function will return. +*/ +void event_get( event_t *criterion, array_list_t *out ); + +/** + Fire the specified event. The function_name field of the event must + be set to 0. If the event is of type EVENT_SIGNAL, no the event is + queued, and will be dispatched the next time event_fire is + called. If event is a null-pointer, all pending events are + dispatched. + + \param event the specific event whose handlers should fire + \param arguments the argument string to send to the event handler function +*/ +void event_fire( event_t *event, array_list_t *arguments ); + +/** + Initialize the event-handling library +*/ +void event_init(); + +/** + Destroy the event-handling library +*/ +void event_destroy(); + +/** + Free all memory used by event +*/ +void event_free( event_t *e ); + +#endif diff --git a/exec.c b/exec.c index ae41c225e..b3d34a730 100644 --- a/exec.c +++ b/exec.c @@ -649,7 +649,8 @@ static int internal_exec_helper( const wchar_t *def, buff->out_buffer->used ); */ io_untransmogrify( io, io_internal ); - job_do_notification(); + if( !is_event ) + job_do_notification(); is_block=is_block_old; return res; } diff --git a/fish_tests.c b/fish_tests.c index 7cf8066a9..4a29ddefd 100644 --- a/fish_tests.c +++ b/fish_tests.c @@ -615,6 +615,7 @@ int main( int argc, char **argv ) say( L"Testing low-level functionality"); say( L"Lines beginning with 'fish:' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All errors begin with 'Error:'." ); + event_init(); exec_init(); parser_init(); function_init(); @@ -644,5 +645,6 @@ int main( int argc, char **argv ) complete_destroy(); wutil_destroy(); exec_destroy(); + event_destroy(); } diff --git a/function.c b/function.c index b71eab883..c57760e4c 100644 --- a/function.c +++ b/function.c @@ -15,11 +15,8 @@ #include "parser.h" #include "common.h" #include "intern.h" +#include "event.h" -/** - Table containing all functions -*/ -static hash_table_t function; /** Struct describing a function @@ -32,7 +29,12 @@ typedef struct wchar_t *desc; int is_binding; } -function_data_t; + function_data_t; + +/** + Table containing all functions +*/ +static hash_table_t function; /** Free all contents of an entry to the function hash table @@ -62,8 +64,11 @@ void function_destroy() void function_add( const wchar_t *name, const wchar_t *val, const wchar_t *desc, - int is_binding) + array_list_t *events, + int is_binding ) { + int i; + if( function_exists( name ) ) function_remove( name ); @@ -72,6 +77,12 @@ void function_add( const wchar_t *name, d->desc = desc?wcsdup( desc ):0; d->is_binding = is_binding; hash_put( &function, intern(name), d ); + + for( i=0; i #include -#include -#include -#include -#include -#include #include #include #include #include #include -#include #include #include diff --git a/input.c b/input.c index 8176c783c..d609b8631 100644 --- a/input.c +++ b/input.c @@ -999,7 +999,6 @@ void input_parse_inputrc_line( wchar_t *cmd ) wchar_t *key; wchar_t *val; wchar_t *sequence; - wchar_t prev=0; key=cmd; diff --git a/main.c b/main.c index b54d7e0f0..88f671db2 100644 --- a/main.c +++ b/main.c @@ -31,7 +31,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include -#include #include #ifdef HAVE_GETOPT_H @@ -54,6 +53,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "parser.h" #include "expand.h" #include "intern.h" +#include "exec.h" +#include "event.h" /** Parse init files @@ -206,6 +207,7 @@ int main( int argc, char **argv ) if( force_interactive ) is_interactive_session=1; + event_init(); exec_init(); parser_init(); builtin_init(); @@ -301,6 +303,8 @@ int main( int argc, char **argv ) wutil_destroy(); common_destroy(); exec_destroy(); + event_destroy(); + intern_free_all(); diff --git a/parser.c b/parser.c index 009198229..a50dfe81f 100644 --- a/parser.c +++ b/parser.c @@ -34,6 +34,7 @@ The fish parser. Contains functions for parsing code. #include "reader.h" #include "sanity.h" #include "env_universal.h" +#include "event.h" /** Length of the lineinfo string used for describing the current tokenizer position */ #define LINEINFO_SIZE 128 @@ -209,6 +210,9 @@ void parser_pop_block() { free( current_block->function_name ); free( current_block->function_description ); + al_foreach( current_block->function_events, + (void (*)(const void *))&event_free ); + free( current_block->function_events ); break; } @@ -1799,7 +1803,7 @@ static void eval_job( tokenizer *tok ) } } - if( is_subshell || is_block ) + if(( is_subshell || is_block ) && (!is_event)) job_do_notification(); // debug( 2, L"end eval_job()\n" ); } diff --git a/parser.h b/parser.h index 04b091e04..a6101eff4 100644 --- a/parser.h +++ b/parser.h @@ -55,6 +55,17 @@ typedef struct block int function_is_binding; /**< Whether a function is a keybinding */ }; + /** + Fourth block type specific variable + */ + union + { + array_list_t *function_events; + } + ; + + + /** Next outer block */ diff --git a/proc.c b/proc.c index a2245e682..a892eae20 100644 --- a/proc.c +++ b/proc.c @@ -46,6 +46,7 @@ Some of the code in this file is based on code from the Glibc manual. #include "sanity.h" #include "env.h" #include "parser.h" +#include "signal.h" /** Size of message buffer @@ -69,6 +70,7 @@ int is_interactive_session=0; int is_subshell=0; int is_block=0; int is_login=0; +int is_event=0; int proc_had_barrier; pid_t proc_last_bg_pid = 0; @@ -349,156 +351,6 @@ static int job_last_is_completed( const job_t *j ) return p->completed; } -/** - Get string representation of a signal -*/ -static wchar_t *sig2wcs( int sig ) -{ - switch( sig ) - { - case SIGHUP: - return L"SIGHUP"; - case SIGINT: - return L"SIGINT"; - case SIGQUIT: - return L"SIGQUIT"; - case SIGILL: - return L"SIGILL"; - case SIGTRAP: - return L"SIGTRAP"; - case SIGABRT: - return L"SIGABRT"; - case SIGBUS: - return L"SIGBUS"; - case SIGFPE: - return L"SIGFPE"; - case SIGKILL: - return L"SIGKILL"; - case SIGUSR1: - return L"SIGUSR1"; - case SIGSEGV: - return L"SIGSEGV"; - case SIGUSR2: - return L"SIGUSR2"; - case SIGPIPE: - return L"SIGPIPE"; - case SIGALRM: - return L"SIGALRM"; - case SIGTERM: - return L"SIGTERM"; - case SIGCHLD: - return L"SIGCHLD"; - case SIGCONT: - return L"SIGCONT"; - case SIGSTOP: - return L"SIGSTOP"; - case SIGTSTP: - return L"SIGTSTP"; - case SIGTTIN: - return L"SIGTTIN"; - case SIGTTOU: - return L"SIGTTOU"; - case SIGURG: - return L"SIGURG"; - case SIGXCPU: - return L"SIGXCPU"; - case SIGXFSZ: - return L"SIGFXSZ"; - case SIGVTALRM: - return L"SIGVTALRM"; - case SIGPROF: - return L"SIGPROF"; - case SIGWINCH: - return L"SIGWINCH"; - case SIGIO: - return L"SIGIO"; -#ifdef SIGPWR - case SIGPWR: - return L"SIGPWR"; -#endif - case SIGSYS: - return L"SIGSYS"; - default: - return L"Unknown"; - } - -} - -/** - Returns a description of the specified signal. -*/ -static wchar_t *sig_description( int sig ) -{ - switch( sig ) - { - case SIGHUP: - return L"Terminal hung up"; - case SIGINT: - return L"Quit request from job control (^C)"; - case SIGQUIT: - return L"Quit request from job control with core dump (^\\)"; - case SIGILL: - return L"Illegal instruction"; - case SIGTRAP: - return L"Trace or breakpoint trap"; - case SIGABRT: - return L"Abort"; - case SIGBUS: - return L"Misaligned address error"; - case SIGFPE: - return L"Floating point exception"; - case SIGKILL: - return L"Forced quit"; - case SIGUSR1: - return L"User defined signal 1"; - case SIGUSR2: - return L"User defined signal 2"; - case SIGSEGV: - return L"Address boundary error"; - case SIGPIPE: - return L"Broken pipe"; - case SIGALRM: - return L"Timer expired"; - case SIGTERM: - return L"Polite quit request"; - case SIGCHLD: - return L"Child process status changed"; - case SIGCONT: - return L"Continue previously stopped process"; - case SIGSTOP: - return L"Forced stop"; - case SIGTSTP: - return L"Stop request from job control (^Z)"; - case SIGTTIN: - return L"Stop from terminal input"; - case SIGTTOU: - return L"Stop from terminal output"; - case SIGURG: - return L"Urgent socket condition"; - case SIGXCPU: - return L"CPU time limit exceeded"; - case SIGXFSZ: - return L"File size limit exceeded"; - case SIGVTALRM: - return L"Virtual timer expired"; - case SIGPROF: - return L"Profiling timer expired"; - case SIGWINCH: - return L"Window size change"; - case SIGIO: - return L"Asynchronous IO event"; -#ifdef SIGPWR - case SIGPWR: - return L"Power failure"; -#endif - case SIGSYS: - return L"Bad system call"; - default: - return L"Unknown"; - } - -} - /** Store the status of the process pid that was returned by waitpid. diff --git a/proc.h b/proc.h index c92a6d10e..3bdf1db74 100644 --- a/proc.h +++ b/proc.h @@ -156,6 +156,8 @@ extern int is_interactive; extern int is_interactive_session; /** Whether we are a login shell*/ extern int is_login; +/** Whether we are a event handler*/ +extern int is_event; /** Linked list of all jobs */ extern job_t *first_job; diff --git a/reader.c b/reader.c index a8a2672e3..78e14993b 100644 --- a/reader.c +++ b/reader.c @@ -236,12 +236,8 @@ static int end_loop = 0; */ static struct winsize termsize; -/** - This flag is set when a WINCH signal was recieved. -*/ static int new_size=0; - /** The list containing names of files that are being parsed */ @@ -272,10 +268,7 @@ static struct termios saved_modes; */ static pid_t original_pid; -/** - Interrupted flag. Set to 1 when the user presses \^C. -*/ -static int interupted; +static int interupted=0; /* Prototypes for a bunch of functions defined later on. @@ -284,9 +277,7 @@ static int interupted; 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 handle_winch( int sig ); - - +static void check_winch(); static struct termios old_modes; @@ -333,7 +324,8 @@ static void term_steal() break; } - handle_winch( 0 ); + reader_handle_winch(0 ); + check_winch(); if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */ { @@ -360,6 +352,19 @@ static int room_for_usec(struct stat *st) */ static string_buffer_t *readline_buffer=0; +void reader_handle_int( int sig ) +{ + block_t *c = current_block; + while( c ) + { + c->skip=1; + c=c->outer; + } + interupted = 1; + +} + + int reader_get_width() { return termsize.ws_col; @@ -1410,11 +1415,9 @@ static int handle_completions( array_list_t *comp ) } } -/** - Respond to a winch signal by checking the terminal size -*/ -static void handle_winch( int sig ) +void reader_handle_winch( int signal ) { + if (ioctl(1,TIOCGWINSZ,&termsize)!=0) { return; @@ -1422,8 +1425,7 @@ static void handle_winch( int sig ) new_size=1; } - -void check_winch() +static void check_winch() { if( new_size ) { @@ -1436,22 +1438,6 @@ void check_winch() } } -/** - Interactive mode ^C handler. Respond to int signal by setting - interrupted-flag and stopping all loops and conditionals. -*/ -static void handle_int( int sig ) -{ - interupted=1; - - block_t *c = current_block; - while( c ) - { - c->skip=1; - c=c->outer; - } - -} /** Reset the terminal. This function is placed in the list of @@ -1466,98 +1452,6 @@ static void exit_func() tcsetattr(0, TCSANOW, &saved_modes); } -/** - Sets appropriate signal handlers. -*/ -static void set_signal_handlers() -{ - struct sigaction act; - sigemptyset( & act.sa_mask ); - act.sa_flags=0; - act.sa_handler=SIG_DFL; - - /* - First reset everything - */ - sigaction( SIGINT, &act, 0); - sigaction( SIGQUIT, &act, 0); - sigaction( SIGTSTP, &act, 0); - sigaction( SIGTTIN, &act, 0); - sigaction( SIGTTOU, &act, 0); - sigaction( SIGCHLD, &act, 0); - - /* - Ignore sigpipe, it is generated if fishd dies, but we can - recover. - */ - act.sa_handler=SIG_IGN; - sigaction( SIGPIPE, &act, 0); - - if( is_interactive ) - { - - /* - Interactive mode. Ignore interactive signals. We are a - shell, we know whats best for the user. ;-) - */ - - act.sa_handler=SIG_IGN; - - sigaction( SIGINT, &act, 0); - sigaction( SIGQUIT, &act, 0); - sigaction( SIGTSTP, &act, 0); - sigaction( SIGTTIN, &act, 0); - sigaction( SIGTTOU, &act, 0); - - act.sa_handler = &handle_int; - act.sa_flags = 0; - if( sigaction( SIGINT, &act, 0) ) - { - wperror( L"sigaction" ); - exit(1); - } - - act.sa_sigaction = &job_handle_signal; - act.sa_flags = SA_SIGINFO; - if( sigaction( SIGCHLD, &act, 0) ) - { - wperror( L"sigaction" ); - exit(1); - } - - act.sa_flags = 0; - act.sa_handler= &handle_winch; - if( sigaction( SIGWINCH, &act, 0 ) ) - { - wperror( L"sigaction" ); - exit(1); - } - - } - else - { - /* - Non-interactive. Ignore interrupt, check exit status of - processes to determine result instead. - */ - act.sa_handler=SIG_IGN; - - sigaction( SIGINT, &act, 0); - sigaction( SIGQUIT, &act, 0); - - act.sa_handler=SIG_DFL; - - act.sa_sigaction = &job_handle_signal; - act.sa_flags = SA_SIGINFO; - if( sigaction( SIGCHLD, &act, 0) ) - { - wperror( L"sigaction" ); - exit(1); - } - } -} - - /** Initialize data for interactive use */ @@ -1603,7 +1497,7 @@ static void reader_interactive_init() history_init(); - handle_winch( 0 ); /* Set handler for window change events */ + reader_handle_winch(0); check_winch(); tcgetattr(0,&shell_modes); /* get the current terminal modes */ @@ -3034,8 +2928,8 @@ int reader_read() */ int shell_was_interactive = is_interactive; is_interactive = isatty(STDIN_FILENO); - set_signal_handlers(); - + signal_set_handlers(); + res= is_interactive?read_i():read_ni(); /* @@ -3045,6 +2939,6 @@ int reader_read() end_loop = 0; is_interactive = shell_was_interactive; - set_signal_handlers(); + signal_set_handlers(); return res; } diff --git a/reader.h b/reader.h index 167fdbabe..ac61098d9 100644 --- a/reader.h +++ b/reader.h @@ -191,4 +191,8 @@ 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 ); +void reader_handle_int( int signal ); + + #endif diff --git a/tokenizer.c b/tokenizer.c index a5bb97903..f105e96e1 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -13,10 +13,6 @@ #include #include #include -#include -#include -#include -#include #include #include "util.h" diff --git a/util.c b/util.c index fe41033c2..31ccf7b4e 100644 --- a/util.c +++ b/util.c @@ -810,6 +810,16 @@ void sb_init( string_buffer_t * b) b->used -= sizeof(wchar_t); } +string_buffer_t *sb_new() +{ + string_buffer_t *res = malloc( sizeof( string_buffer_t ) ); + if( !res ) + die_mem(); + sb_init( res ); + return res; +} + + void sb_append( string_buffer_t *b, const wchar_t * s) { // fwprintf( stderr, L"Append string \'%ls\'\n", s ); diff --git a/util.h b/util.h index 88d828bf1..04c76bac0 100644 --- a/util.h +++ b/util.h @@ -409,6 +409,8 @@ int wcsfilecmp( const wchar_t *a, const wchar_t *b ); */ void sb_init( string_buffer_t * ); +string_buffer_t *sb_new(); + /** Append a string to the buffer */ diff --git a/wildcard.h b/wildcard.h index c7478b0b4..5db4e38c1 100644 --- a/wildcard.h +++ b/wildcard.h @@ -64,7 +64,6 @@ int wildcard_expand( const wchar_t *wc, \param str The string to test \param wc The wildcard to test against - \param wc_unescaped if wc_unescaped is true, \c wildcard_match uses the ANY_CHAR and ANY_STRING characters for globbing, otherwise, the '?' and '*' characters are used \return true if the wildcard matched */ int wildcard_match( const wchar_t *str, diff --git a/wutil.h b/wutil.h index c0f57ef92..8ce2ac6a1 100644 --- a/wutil.h +++ b/wutil.h @@ -11,6 +11,7 @@ #include #include #include +#include /**