mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 12:23:09 +00:00
Initial update for new event subsystem
darcs-hash:20051005223708-ac50b-8a8d7e003e1c24747f3f154cb66b6c1a1015c35b.gz
This commit is contained in:
parent
b065bd6282
commit
b9b841f603
23 changed files with 842 additions and 425 deletions
|
@ -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
147
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; 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
187
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;
|
||||
|
|
428
event.c
Normal file
428
event.c
Normal 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
107
event.h
Normal 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
3
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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
29
function.c
29
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<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 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
1
input.c
1
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;
|
||||
|
||||
|
|
6
main.c
6
main.c
|
@ -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();
|
||||
|
||||
|
|
6
parser.c
6
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" );
|
||||
}
|
||||
|
|
11
parser.h
11
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
|
||||
*/
|
||||
|
|
152
proc.c
152
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.
|
||||
|
|
2
proc.h
2
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;
|
||||
|
||||
|
|
154
reader.c
154
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;
|
||||
}
|
||||
|
|
4
reader.h
4
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
|
||||
|
|
|
@ -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
10
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 );
|
||||
|
|
2
util.h
2
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
|
||||
*/
|
||||
|
|
|
@ -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,
|
||||
|
|
1
wutil.h
1
wutil.h
|
@ -11,6 +11,7 @@
|
|||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue