diff --git a/Makefile.in b/Makefile.in index 004265881..f3530a64f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -79,13 +79,13 @@ MIME_OBJS := mimedb.o xdgmimealias.o xdgmime.o xdgmimeglob.o \ BUILTIN_DOC_SRC := doc_src/source.txt doc_src/and.txt \ doc_src/begin.txt doc_src/bg.txt doc_src/bind.txt \ - doc_src/break.txt doc_src/builtin.txt doc_src/case.txt \ - doc_src/cd.txt doc_src/command.txt doc_src/commandline.txt \ - doc_src/complete.txt doc_src/continue.txt doc_src/else.txt \ - doc_src/end.txt doc_src/eval.txt doc_src/exec.txt doc_src/exit.txt \ - doc_src/fg.txt doc_src/for.txt doc_src/function.txt \ - doc_src/functions.txt doc_src/if.txt doc_src/jobs.txt \ - doc_src/not.txt doc_src/or.txt doc_src/random.txt \ + doc_src/block.txt doc_src/break.txt doc_src/builtin.txt \ + doc_src/case.txt doc_src/cd.txt doc_src/command.txt \ + doc_src/commandline.txt doc_src/complete.txt doc_src/continue.txt \ + doc_src/else.txt doc_src/end.txt doc_src/eval.txt doc_src/exec.txt \ + doc_src/exit.txt doc_src/fg.txt doc_src/for.txt \ + doc_src/function.txt doc_src/functions.txt doc_src/if.txt \ + doc_src/jobs.txt doc_src/not.txt doc_src/or.txt doc_src/random.txt \ doc_src/return.txt doc_src/read.txt doc_src/set.txt \ doc_src/status.txt doc_src/switch.txt doc_src/ulimit.txt \ doc_src/while.txt diff --git a/builtin.c b/builtin.c index eac987b95..f5ebb5b7b 100644 --- a/builtin.c +++ b/builtin.c @@ -244,6 +244,173 @@ static int builtin_bind( wchar_t **argv ) return 0; } +/** + The block builtin, used for temporarily blocking events + */ +static int builtin_block( wchar_t **argv ) +{ + enum + { + UNSET, + GLOBAL, + LOCAL, + } + ; + + + + int scope=UNSET; + + int erase = 0; + + int argc=builtin_count_args( argv ); + + int type = (1<next; + free( eb ); + } + else + { + block_t *block=current_block; + + event_block_t *eb = malloc( sizeof( event_block_t ) ); + + if( !eb ) + die_mem(); + + eb->type = type; + + switch( scope ) + { + case LOCAL: + { + if( !block->outer ) + block=0; + break; + } + case GLOBAL: + { + block=0; + } + case UNSET: + { + while( block && block->type != FUNCTION_CALL ) + block = block->outer; + } + } + if( block ) + { + eb->next = block->first_event_block; + block->first_event_block = eb; + } + else + { + eb->next = global_event_block; + global_event_block=eb; + } + } + + return 0; + +} + + /** The builtin builtin, used for given builtins precedence over functions. Mostly handled by the parser. All this code does is some additional operational modes, such as printing a list of all builtins. @@ -838,7 +1005,7 @@ static int builtin_function( wchar_t **argv ) break; } - e = malloc( sizeof(event_t)); + e = calloc( 1, sizeof(event_t)); if( !e ) die_mem(); e->type = EVENT_SIGNAL; @@ -862,7 +1029,7 @@ static int builtin_function( wchar_t **argv ) break; } - e = malloc( sizeof(event_t)); + e = calloc( 1, sizeof(event_t)); if( !e ) die_mem(); e->type = EVENT_VARIABLE; @@ -879,7 +1046,7 @@ static int builtin_function( wchar_t **argv ) wchar_t *end; event_t *e; - e = malloc( sizeof(event_t)); + e = calloc( 1, sizeof(event_t)); if( !e ) die_mem(); @@ -2850,6 +3017,7 @@ void builtin_init() hash_init( &builtin, &hash_wcs_func, &hash_wcs_cmp ); hash_put( &builtin, L"exit", (void*) &builtin_exit ); + hash_put( &builtin, L"block", (void*) &builtin_block ); hash_put( &builtin, L"builtin", (void*) &builtin_builtin ); hash_put( &builtin, L"cd", (void*) &builtin_cd ); hash_put( &builtin, L"function", (void*) &builtin_function ); @@ -2899,6 +3067,7 @@ void builtin_init() intern_static( L"exit" ); intern_static( L"builtin" ); + intern_static( L"block" ); intern_static( L"cd" ); intern_static( L"function" ); intern_static( L"functions" ); @@ -3026,11 +3195,13 @@ const wchar_t *builtin_get_desc( const wchar_t *b ) hash_init( desc, &hash_wcs_func, &hash_wcs_cmp ); - hash_put( desc, L"exit", L"Exit the shell" ); + hash_put( desc, L"block", L"Temporarily block delivery of events" ); + hash_put( desc, L"builtin", L"Run a builtin command" ); + hash_put( desc, L"complete", L"Edit command specific completions" ); hash_put( desc, L"cd", L"Change working directory" ); + hash_put( desc, L"exit", L"Exit the shell" ); hash_put( desc, L"function", L"Define a new function" ); hash_put( desc, L"functions", L"List or remove functions" ); - hash_put( desc, L"complete", L"Edit command specific completions" ); hash_put( desc, L"end", L"End a block of commands" ); hash_put( desc, L"else", L"Evaluate block if condition is false" ); hash_put( desc, L"eval", L"Evaluate parameters as a command" ); @@ -3047,7 +3218,6 @@ const wchar_t *builtin_get_desc( const wchar_t *b ) hash_put( desc, L"commandline", L"Set the commandline" ); hash_put( desc, L"switch", L"Conditionally execute a block of commands" ); hash_put( desc, L"case", L"Conditionally execute a block of commands" ); - hash_put( desc, L"builtin", L"Run a builtin command" ); hash_put( desc, L"command", L"Run a program" ); hash_put( desc, L"if", L"Conditionally execute a command" ); hash_put( desc, L"while", L"Perform a command multiple times" ); diff --git a/doc_src/doc.hdr b/doc_src/doc.hdr index 644e85ba5..b8bf38566 100644 --- a/doc_src/doc.hdr +++ b/doc_src/doc.hdr @@ -682,6 +682,7 @@ builtins or shellscript functions, and can only be used inside fish. - begin, execute a block of commands - bind, change keyboard bindings - break, stop the execution of a loop +- block, Temporarily block delivery of events - builtin, execute a builtin command - case, conditionally execute a block of commands - cd, change the current directory @@ -995,7 +996,10 @@ g++, javac, java, gcj, lpr, doxygen, whois, find) - Check keybinding commands for output - if non has happened, don't repaint to reduce flicker - The jobs builtin should be able to give information on a specific job, such as the pids of the processes in the job - Syntax highlighting should mark cd to non-existing directories as an error - +- the code for printing the prompt should know about the most common escape sequences +- block builtin +- redo the jobs command +- wait shellscript \subsection todo-possible Possible features diff --git a/env.c b/env.c index 3429e3c7d..13a0dc82d 100644 --- a/env.c +++ b/env.c @@ -236,7 +236,6 @@ static void universal_callback( int type, if( str ) { - array_list_t arg; event_t ev; has_changed=1; @@ -245,12 +244,12 @@ static void universal_callback( int type, ev.param1.variable=name; ev.function_name=0; - al_init( &arg ); - al_push( &arg, L"VARIABLE" ); - al_push( &arg, str ); - al_push( &arg, name ); - event_fire( &ev, &arg ); - al_destroy( &arg ); + al_init( &ev.arguments ); + al_push( &ev.arguments, L"VARIABLE" ); + al_push( &ev.arguments, str ); + al_push( &ev.arguments, name ); + event_fire( &ev ); + al_destroy( &ev.arguments ); } } @@ -489,7 +488,6 @@ void env_set( const wchar_t *key, int done=0; event_t ev; - array_list_t ev_list; int is_universal = 0; if( (var_mode & ENV_USER ) && @@ -669,14 +667,14 @@ void env_set( const wchar_t *key, ev.param1.variable = key; ev.function_name = 0; - al_init( &ev_list ); - al_push( &ev_list, L"VARIABLE" ); - al_push( &ev_list, key ); + al_init( &ev.arguments ); + al_push( &ev.arguments, L"VARIABLE" ); + al_push( &ev.arguments, key ); // debug( 1, L"env_set: fire events on variable %ls", key ); - event_fire( &ev, &ev_list ); + event_fire( &ev ); // debug( 1, L"env_set: return from event firing" ); - al_destroy( &ev_list ); + al_destroy( &ev.arguments ); } } diff --git a/event.c b/event.c index 7685585b1..9c2633ed9 100644 --- a/event.c +++ b/event.c @@ -67,6 +67,12 @@ static array_list_t *events; */ static array_list_t *killme; +/** + List of events that have been sent but have not yet been delivered because they are blocked. +*/ +static array_list_t *blocked; + + /** Tests if one event instance matches the definition of a event class. If the class defines a function name, that will also be a @@ -120,7 +126,7 @@ static int event_match( event_t *class, event_t *instance ) 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 ) +static event_t *event_copy( event_t *event, int copy_arguments ) { event_t *e = malloc( sizeof( event_t ) ); if( !e ) @@ -133,12 +139,55 @@ static event_t *event_copy( event_t *event ) if( e->type == EVENT_VARIABLE ) e->param1.variable = wcsdup( e->param1.variable ); + al_init( &e->arguments ); + if( copy_arguments ) + { + int i; + for( i=0; iarguments ); i++ ) + { + al_push( &e->arguments, wcsdup( (wchar_t *)al_get( &event->arguments, i ) ) ); + } + + } + return e; } + +static int event_is_blocked( event_t *e ) +{ + block_t *block; + event_block_t *eb; + + for( block = current_block; block; block = block->outer ) + { + for( eb = block->first_event_block; eb; eb=eb->next ) + { + if( eb->type & (1<type & (1<type) ) + return 1; + } + } + for( eb = global_event_block; eb; eb=eb->next ) + { + if( eb->type & (1<type & (1<type) ) + return 1; + return 1; + + } + + return 0; +} + + void event_add_handler( event_t *event ) { - event_t *e = event_copy( event ); + event_t *e; + + e = event_copy( event, 0 ); if( !events ) events = al_new(); @@ -268,7 +317,7 @@ static int event_is_killed( event_t *e ) matches' path. This means that nothing is allocated/initialized unless that is needed. */ -static void event_fire_internal( event_t *event, array_list_t *arguments ) +static void event_fire_internal( event_t *event ) { int i, j; string_buffer_t *b=0; @@ -337,9 +386,9 @@ static void event_fire_internal( event_t *event, array_list_t *arguments ) sb_append( b, criterion->function_name ); - for( j=0; jarguments); j++ ) { - wchar_t *arg_esc = escape( (wchar_t *)al_get( arguments, j), 0 ); + wchar_t *arg_esc = escape( (wchar_t *)al_get( &event->arguments, j), 0 ); sb_append( b, L" " ); sb_append( b, arg_esc ); free( arg_esc ); @@ -385,15 +434,42 @@ static void event_fire_internal( event_t *event, array_list_t *arguments ) /** Handle all pending signal events */ -static void event_fire_signal_events() +static void event_fire_delayed() { + + int i; + + if( blocked && is_event==1) + { + array_list_t *new_blocked = 0; + + for( i=0; i 0 ) { - int i; signal_list_t *lst; event_t e; - array_list_t a; - al_init( &a ); + al_init( &e.arguments ); /* Switch signal lists @@ -421,17 +497,26 @@ static void event_fire_signal_events() 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_set( &e.arguments, 0, sig2wcs( e.param1.signal ) ); + if( event_is_blocked( &e ) ) + { + if( !blocked ) + blocked = al_new(); + al_push( blocked, event_copy(&e, 1) ); + } + else + { + event_fire_internal( &e ); + } } - al_destroy( &a ); + al_destroy( &e.arguments ); } } -void event_fire( event_t *event, array_list_t *arguments ) +void event_fire( event_t *event ) { //int is_event_old = is_event; is_event++; @@ -452,10 +537,23 @@ void event_fire( event_t *event, array_list_t *arguments ) } else { - event_fire_signal_events(); + event_fire_delayed(); + if( event ) - event_fire_internal( event, arguments ); + { + if( event_is_blocked( event ) ) + { + if( !blocked ) + blocked = al_new(); + + al_push( blocked, event_copy(event, 1) ); + } + else + { + event_fire_internal( event ); + } + } } is_event--;// = is_event_old; @@ -487,9 +585,14 @@ void event_destroy() void event_free( event_t *e ) { + /* + When apropriate, we clear the argument vector + */ + al_foreach( &e->arguments, (void (*)(const void *))&free ); + al_destroy( &e->arguments ); + free( (void *)e->function_name ); if( e->type == EVENT_VARIABLE ) free( (void *)e->param1.variable ); free( e ); } - diff --git a/event.h b/event.h index 43d81a8d1..742e9df78 100644 --- a/event.h +++ b/event.h @@ -43,15 +43,17 @@ typedef struct union { /** - Signal number for signal-type events.Use EVENT_ANY_SIGNAL to match any signal + Signal number for signal-type events.Use EVENT_ANY_SIGNAL + to match any signal */ int signal; /** - Variable name for variable-type events. + Variable name for variable-type events. */ const wchar_t *variable; /** - Process id for process-type events. Use EVENT_ANY_PID to match any pid. + Process id for process-type events. Use EVENT_ANY_PID to + match any pid. */ pid_t pid; /** @@ -65,6 +67,13 @@ typedef struct The name of the event handler function */ const wchar_t *function_name; + + /** + The argument list. Only used when sending a new event using + event_fire. In all other situations, the value of this variable + is ignored. + */ + array_list_t arguments; } event_t; @@ -98,7 +107,7 @@ int event_get( event_t *criterion, array_list_t *out ); \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 ); +void event_fire( event_t *event ); /** Initialize the event-handling library diff --git a/input.c b/input.c index f9bbb99da..78fec9a29 100644 --- a/input.c +++ b/input.c @@ -1270,7 +1270,7 @@ static int interrupt_handler() /* Fire any pending events */ - event_fire( 0, 0 ); + event_fire( 0 ); if( job_reap( 1 ) ) repaint(); if( reader_interupted() ) diff --git a/parser.c b/parser.c index 27caabba0..ef4e6b3a5 100644 --- a/parser.c +++ b/parser.c @@ -111,6 +111,8 @@ The fish parser. Contains functions for parsing code. /** Last error code */ int error_code; +event_block_t *global_event_block=0; + /** Position of last error */ static int err_pos; @@ -194,7 +196,7 @@ int block_count( block_t *b ) void parser_push_block( int type ) { - block_t *new = malloc( sizeof( block_t )); + block_t *new = calloc( 1, sizeof( block_t )); // debug( 2, L"Block push %ls %d\n", bl[type], block_count( current_block)+1 ); new->outer = current_block; @@ -230,6 +232,7 @@ void parser_push_block( int type ) void parser_pop_block() { // debug( 2, L"Block pop %ls %d\n", bl[current_block->type], block_count(current_block)-1 ); + event_block_t *eb, *eb_next; if( (current_block->type != FUNCTION_DEF ) && (current_block->type != FAKE) && @@ -270,6 +273,12 @@ void parser_pop_block() } + for( eb=current_block->first_event_block; eb; eb=eb_next ) + { + eb_next = eb->next; + free(eb); + } + block_t *old = current_block; current_block = current_block->outer; free( old ); @@ -1996,7 +2005,7 @@ 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 ); + event_fire( 0 ); while( tok_has_next( current_tokenizer ) && !error_code && @@ -2004,7 +2013,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type ) !exit_status() ) { eval_job( current_tokenizer ); - event_fire( 0, 0 ); + event_fire( 0 ); } int prev_block_type = current_block->type; diff --git a/parser.h b/parser.h index 2a597a1e0..57fac016d 100644 --- a/parser.h +++ b/parser.h @@ -11,6 +11,27 @@ #include "util.h" #include "parser.h" +typedef struct event_block +{ + /** + The types of events to block. This is interpreted as a bitset + whete the value is 1 for every bit corresponding to a blocked + event type. For example, if EVENT_VARIABLE type events should + be blocked, (type & 1<