Initial update for new event subsystem

darcs-hash:20051005223708-ac50b-8a8d7e003e1c24747f3f154cb66b6c1a1015c35b.gz
This commit is contained in:
axel 2005-10-06 08:37:08 +10:00
parent b065bd6282
commit b9b841f603
23 changed files with 842 additions and 425 deletions

View file

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

147
builtin.c
View file

@ -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; i<al_get_count( events ); i++ )
{
event_t *e = (event_t *)al_get( events, i );
e->function_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;

187
env.c
View file

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

428
event.c Normal file
View file

@ -0,0 +1,428 @@
/** \file function.c
Functions for storing and retrieving function information.
*/
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <unistd.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
#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; i<al_get_count( events); i++ )
{
event_t *n = (event_t *)al_get( events, i );
if( event_match( criterion, n ) )
{
if( !killme )
killme = al_new();
al_push( killme, n );
}
else
{
al_push( new_list, n );
}
}
al_destroy( events );
events = new_list;
}
void event_get( event_t *criterion, array_list_t *out )
{
int i;
if( !events )
return;
for( i=0; i<al_get_count( events); i++ )
{
event_t *n = (event_t *)al_get( events, i );
if( event_match(criterion, n ) )
al_push( out, n );
}
}
/**
Free all events in the kill list
*/
static void event_free_kills()
{
int i;
if( !killme )
return;
for( i=0; i<al_get_count( killme ); i++ )
{
event_t *roadkill = (event_t *)al_get( events, i );
event_free( roadkill );
}
al_truncate( killme, 0 );
}
/**
Test if the specified event is waiting to be killed
*/
static int event_is_killed( event_t *e )
{
int i;
if( !killme )
return 0;
for( i=0; i<al_get_count( killme ); i++ )
{
event_t *roadkill = (event_t *)al_get( events, i );
if( roadkill ==e )
return 1;
}
return 0;
}
/**
Perform the specified event. Since almost all event firings will
not match a single event handler, we make sureto optimize the 'no
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 )
{
int i, j;
string_buffer_t *b=0;
array_list_t *fire=0;
if( !events )
return;
/*
First we free all events that have been removed
*/
event_free_kills();
/*
Then we iterate over all events, adding events that should be
fired to a second list. We need to do this in a separate step
since an event handler might call event_remove or
event_add_handler, which will change the contents of the \c
events list.
*/
for( i=0; i<al_get_count( events ); i++ )
{
event_t *criterion = (event_t *)al_get( events, i );
/*
Check if this event is a match
*/
if(event_match( criterion, event ) )
{
if( !fire )
fire = al_new();
al_push( fire, criterion );
}
}
/*
No matches. Time to return.
*/
if( !fire )
return;
/*
Iterate over our list of matching events
*/
for( i=0; i<al_get_count( fire ); i++ )
{
event_t *criterion = (event_t *)al_get( fire, i );
/*
Check if this event has been removed, if so, dont fire it
*/
if( event_is_killed( criterion ) )
continue;
/*
Fire event
*/
if( !b )
b = sb_new();
else
sb_clear( b );
sb_append( b, criterion->function_name );
for( j=0; j<al_get_count(arguments); j++ )
{
wchar_t *arg_esc = escape( wcsdup( (wchar_t *)al_get( arguments, j)), 0 );
sb_append( b, L" " );
sb_append( b, arg_esc );
free( arg_esc );
}
eval( (wchar_t *)b->buff, 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; i<lst->count; 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 );
}

107
event.h Normal file
View file

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

3
exec.c
View file

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

View file

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

View file

@ -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<al_get_count( events ); i++ )
{
event_add_handler( (event_t *)al_get( events, i ) );
}
}
int function_exists( const wchar_t *cmd )
@ -84,6 +95,11 @@ void function_remove( const wchar_t *name )
void *key;
function_data_t *d;
event_t ev;
ev.type=EVENT_ANY;
ev.function_name=name;
event_remove( &ev );
hash_remove( &function,
name,
(const void **) &key,
@ -146,3 +162,4 @@ void function_get_names( array_list_t *list, int get_hidden )
hash_foreach2( &function, &get_names_internal, list );
}

View file

@ -27,6 +27,7 @@ void function_destroy();
void function_add( const wchar_t *name,
const wchar_t *val,
const wchar_t *desc,
array_list_t *events,
int is_binding );
/**

View file

@ -3,17 +3,11 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <wchar.h>
#include <wctype.h>
#include <sys/types.h>
#include <termios.h>
#include <signal.h>

View file

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

6
main.c
View file

@ -31,7 +31,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <fcntl.h>
#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();

View file

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

View file

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

152
proc.c
View file

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

2
proc.h
View file

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

154
reader.c
View file

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

View file

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

View file

@ -13,10 +13,6 @@
#include <wchar.h>
#include <wctype.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "util.h"

10
util.c
View file

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

2
util.h
View file

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

View file

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

View file

@ -11,6 +11,7 @@
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
/**