Initial blocking implementation

darcs-hash:20051211222101-ac50b-6e11220bd608187fbb32a0313b5b73dbdc8354fc.gz
This commit is contained in:
axel 2005-12-12 08:21:01 +10:00
parent 2cac04850b
commit 1d69e70b7a
11 changed files with 390 additions and 68 deletions

View file

@ -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

182
builtin.c
View file

@ -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<<EVENT_ANY);
woptind=0;
const static struct woption
long_options[] =
{
{
L"erase", no_argument, 0, 'e'
}
,
{
L"local", no_argument, 0, 'l'
}
,
{
L"global", no_argument, 0, 'g'
}
,
{
L"help", no_argument, 0, 'h'
}
,
{
0, 0, 0, 0
}
}
;
while( 1 )
{
int opt_index = 0;
int opt = wgetopt_long( argc,
argv,
L"elgh",
long_options,
&opt_index );
if( opt == -1 )
break;
switch( opt )
{
case 0:
if(long_options[opt_index].flag != 0)
break;
sb_append2( sb_err,
argv[0],
BUILTIN_ERR_UNKNOWN,
L" ",
long_options[opt_index].name,
L"\n",
(void *)0);
builtin_print_help( argv[0], sb_err );
return 1;
case 'h':
builtin_print_help( argv[0], sb_err );
return 0;
case 'g':
scope = GLOBAL;
break;
case 'l':
scope = LOCAL;
break;
case 'e':
erase = 1;
break;
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
}
}
if( erase )
{
if( scope != UNSET )
{
sb_printf( sb_err, L"%ls: Can not specify scope when removing block\n", argv[0] );
return 1;
}
if( !global_event_block )
{
sb_printf( sb_err, L"%ls: No blocks defined\n", argv[0] );
return 1;
}
event_block_t *eb = global_event_block;
global_event_block = eb->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" );

View file

@ -682,6 +682,7 @@ builtins or shellscript functions, and can only be used inside fish.
- <a href="builtins.html#begin">begin</a>, execute a block of commands
- <a href="builtins.html#bind">bind</a>, change keyboard bindings
- <a href="builtins.html#break">break</a>, stop the execution of a loop
- <a href="builtins.html#block">block</a>, Temporarily block delivery of events
- <a href="builtins.html#builtin">builtin</a>, execute a builtin command
- <a href="builtins.html#case">case</a>, conditionally execute a block of commands
- <a href="builtins.html#cd">cd</a>, 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

24
env.c
View file

@ -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 );
}
}

135
event.c
View file

@ -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; i<al_get_count( &event->arguments ); 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<<EVENT_ANY ) )
return 1;
if( eb->type & (1<<e->type) )
return 1;
}
}
for( eb = global_event_block; eb; eb=eb->next )
{
if( eb->type & (1<<EVENT_ANY ) )
return 1;
if( eb->type & (1<<e->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; j<al_get_count(arguments); j++ )
for( j=0; j<al_get_count(&event->arguments); 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<al_get_count( blocked ); i++ )
{
event_t *e = (event_t *)al_get( blocked, i );
if( event_is_blocked( e ) )
{
if( !new_blocked )
new_blocked = al_new();
al_push( new_blocked, e );
}
else
{
event_fire_internal( e );
event_free( e );
}
}
al_destroy( blocked );
free( blocked );
blocked = new_blocked;
}
while( sig_list[active_list].count > 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; i<lst->count; 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 );
}

17
event.h
View file

@ -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

View file

@ -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() )

View file

@ -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;

View file

@ -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<<EVENT_BLOCKED) should be set.
Note that EVENT_ANY can be used to specify any event.
*/
int type;
/**
The next event_block struct
*/
struct event_block *next;
}
event_block_t;
/**
block_t represents a block of commands.
*/
@ -21,12 +42,12 @@ typedef struct block
int tok_pos; /**< The start index of the block */
/**
Status for the current loop block. Can be anu of the values from the loop_status enum.
Status for the current loop block. Can be any of the values from the loop_status enum.
*/
int loop_status;
/**
The log that is currently evaluated in the specified block.
The job that is currently evaluated in the specified block.
*/
job_t *job;
@ -68,8 +89,11 @@ typedef struct block
array_list_t *function_events;
} param4;
/**
Some naming confusion. This is a pointer to the first element in the list of all event blocks.
*/
event_block_t *first_event_block;
/**
Next outer block
*/
@ -159,6 +183,10 @@ enum parser_error
/** The current innermost block */
extern block_t *current_block;
/** Global event blocks */
extern event_block_t *global_event_block;
/** The current error code */
extern int error_code;

25
proc.c
View file

@ -76,9 +76,10 @@ int proc_had_barrier;
pid_t proc_last_bg_pid = 0;
/**
List used to store arguments when firing events
The event variable used to send all process event
*/
static array_list_t event_arg;
static event_t event;
/**
Stringbuffer used to create arguments when firing events
*/
@ -91,7 +92,7 @@ static string_buffer_t event_status;
void proc_init()
{
al_init( &event_arg );
al_init( &event.arguments );
sb_init( &event_pid );
sb_init( &event_status );
}
@ -185,7 +186,7 @@ void job_free( job_t * j )
void proc_destroy()
{
al_destroy( &event_arg );
al_destroy( &event.arguments );
sb_destroy( &event_pid );
sb_destroy( &event_status );
while( first_job )
@ -484,21 +485,21 @@ static void format_job_info( const job_t *j, const wchar_t *status )
void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status )
{
static event_t ev;
ev.type=type;
ev.param1.pid = pid;
event.type=type;
event.param1.pid = pid;
al_push( &event_arg, msg );
al_push( &event.arguments, msg );
sb_printf( &event_pid, L"%d", pid );
al_push( &event_arg, event_pid.buff );
al_push( &event.arguments, event_pid.buff );
sb_printf( &event_status, L"%d", status );
al_push( &event_arg, event_status.buff );
al_push( &event.arguments, event_status.buff );
event_fire( &ev, &event_arg );
al_truncate( &event_arg, 0 );
event_fire( &event );
al_truncate( &event.arguments, 0 );
sb_clear( &event_pid );
sb_clear( &event_status );
}

View file

@ -305,7 +305,7 @@ static void default_handler(int signal, siginfo_t *info, void *context)
e.param1.signal = signal;
e.function_name=0;
event_fire( &e, 0 );
event_fire( &e );
}
/**