Overhaul of the script autoloader. This should make sure that old scripts are unloaded and new scripts are loaded when the fish_function_path and fish_complete_path variables change

darcs-hash:20060712142242-ac50b-3966a0e96a32facc8bc1164d6d0837fc551e4733.gz
This commit is contained in:
axel 2006-07-13 00:22:42 +10:00
parent 6d9631d0d0
commit 9e304fa734
7 changed files with 207 additions and 44 deletions

View file

@ -233,7 +233,6 @@ static hash_table_t *condition_cache=0;
*/
static string_buffer_t *get_desc_buff=0;
/**
This command clears the cache of condition tests created by \c condition_test().
*/
@ -354,7 +353,7 @@ void complete_destroy()
suffix_hash=0;
}
parse_util_load_reset(L"fish_complete_path");
parse_util_load_reset( L"fish_complete_path", 0 );
}
@ -1551,7 +1550,10 @@ static void complete_load_handler( const wchar_t *cmd )
void complete_load( const wchar_t *name, int reload )
{
parse_util_load( name, L"fish_complete_path", &complete_load_handler, reload );
parse_util_load( name,
L"fish_complete_path",
&complete_load_handler,
reload );
}
/**
@ -1955,20 +1957,18 @@ void complete( const wchar_t *cmd,
wchar_t *buff;
tokenizer tok;
wchar_t *current_token=0, *current_command=0, *prev_token=0;
int on_command=0;
int pos;
int done=0;
int cursor_pos = wcslen(cmd );
int cursor_pos;
CHECK( cmd, );
CHECK( comp, );
// debug( 1, L"Complete '%ls'", cmd );
cursor_pos = wcslen(cmd );
/**
If we are completing a variable name or a tilde expansion user
name, we do that and return. No need for any other competions.

3
env.c
View file

@ -317,9 +317,6 @@ static void handle_locale()
if( is_interactive )
{
complete_destroy();
complete_init();
debug( 0, _(L"Changing language to English") );
}
}

View file

@ -225,7 +225,7 @@ void function_remove( const wchar_t *name )
event_t ev;
CHECK( name, );
hash_remove( &function,
name,
&key,
@ -241,6 +241,16 @@ void function_remove( const wchar_t *name )
event_remove( &ev );
clear_function_entry( key, d );
/*
Notify the autoloader that the specified function is erased, but
only if this call to fish_remove is not made by the autoloader
itself.
*/
if( !is_autoload )
{
parse_util_unload( name, L"fish_function_path", 0 );
}
}
const wchar_t *function_get_definition( const wchar_t *argv )

View file

@ -29,9 +29,36 @@
#include "intern.h"
#include "exec.h"
#include "env.h"
#include "translate.h"
#include "wildcard.h"
#include "halloc_util.h"
/**
A structure representing the autoload state for a specific variable, e.g. fish_complete_path
*/
typedef struct
{
/**
A table containing the modification times of all loaded
files. Failed loads (non-existing files) have modification time
0.
*/
hash_table_t load_time;
/**
A string containg the path used to find any files to load. If
this differs from the current environment variable, the
autoloader needs to drop all loaded files and reload them.
*/
wchar_t *old_path;
/**
A table containing all the files that are currently being
loaded. This is here to help prevent recursion.
*/
hash_table_t is_loading;
}
autoload_t;
/**
Set of files which have been autoloaded
*/
@ -448,20 +475,32 @@ void parse_util_token_extent( const wchar_t *buff,
/**
Free hash value, but not hash key
*/
static void clear_hash_value( void *key, void *data )
static void clear_hash_value( void *key, void *data, void *aux )
{
if( aux )
{
wchar_t *name = (wchar_t *)key;
void (*handler)(const wchar_t *)= (void (*)(const wchar_t *))aux;
handler( name );
}
free( (void *)data );
}
/**
Part of the autoloader cleanup
*/
static void clear_loaded_entry( void *key, void *data )
static void clear_loaded_entry( void *key,
void *data,
void *handler )
{
hash_table_t *loaded = (hash_table_t *)data;
hash_foreach( loaded,
&clear_hash_value );
hash_destroy( loaded );
autoload_t *loaded = (autoload_t *)data;
hash_foreach2( &loaded->load_time,
&clear_hash_value,
handler );
hash_destroy( &loaded->load_time );
free( loaded->old_path );
free( loaded );
free( (void *)key );
}
@ -475,8 +514,9 @@ static void parse_util_destroy()
{
if( all_loaded )
{
hash_foreach( all_loaded,
&clear_loaded_entry );
hash_foreach2( all_loaded,
&clear_loaded_entry,
0 );
hash_destroy( all_loaded );
free( all_loaded );
@ -484,18 +524,61 @@ static void parse_util_destroy()
}
}
void parse_util_load_reset( const wchar_t *path_var )
void parse_util_load_reset( const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) )
{
wchar_t *path_var;
CHECK( path_var_name, );
path_var = env_get( path_var_name );
if( !path_var )
return;
if( all_loaded )
{
void *key, *data;
hash_remove( all_loaded, path_var, &key, &data );
hash_remove( all_loaded, path_var_name, &key, &data );
if( key )
clear_loaded_entry( key, data );
clear_loaded_entry( key, data, (void *)on_load );
}
}
int parse_util_unload( const wchar_t *cmd,
const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) )
{
autoload_t *loaded;
void *val;
CHECK( path_var_name, 0 );
CHECK( cmd, 0 );
if( !all_loaded )
{
return 0;
}
loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
if( !loaded )
{
return 0;
}
hash_remove( &loaded->load_time, cmd, 0, &val );
if( val )
{
if( on_load )
{
on_load( (wchar_t *)val );
}
free( val );
}
return !!val;
}
int parse_util_load( const wchar_t *cmd,
const wchar_t *path_var_name,
@ -508,16 +591,22 @@ int parse_util_load( const wchar_t *cmd,
int i;
time_t *tm;
int reloaded = 0;
hash_table_t *loaded;
autoload_t *loaded;
wchar_t *path_var = env_get( path_var_name );
wchar_t *path_var;
CHECK( path_var_name, 0 );
CHECK( cmd, 0 );
path_var = env_get( path_var_name );
/*
Do we know where to look
*/
if( !path_var )
{
return 0;
}
if( !all_loaded )
{
@ -530,23 +619,52 @@ int parse_util_load( const wchar_t *cmd,
hash_init( all_loaded, &hash_wcs_func, &hash_wcs_cmp );
}
loaded = (hash_table_t *)hash_get( all_loaded, path_var_name );
if( !loaded )
loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
if( loaded )
{
loaded = malloc( sizeof( hash_table_t ) );
if( hash_get( &loaded->is_loading, cmd ) )
{
debug( 0, _(L"Could not autoload item %ls, it is already being autoloaded. This is a circular dependency in the autoloading scripts, please remove it."), cmd );
return 1;
}
/*
Check if the lookup path has changed. If so, drop all loaded
files and start from scratch.
*/
if( wcscmp( path_var, loaded->old_path ) != 0 )
{
parse_util_load_reset( path_var_name, on_load);
reload = parse_util_load( cmd, path_var_name, on_load, reload );
return reload;
}
}
else
{
/*
We have never tried to autoload using this name before, set up initial data
*/
loaded = malloc( sizeof( autoload_t ) );
if( !loaded )
{
DIE_MEM();
}
hash_init( loaded, &hash_wcs_func, &hash_wcs_cmp );
hash_init( &loaded->load_time, &hash_wcs_func, &hash_wcs_cmp );
hash_put( all_loaded, wcsdup(path_var_name), loaded );
hash_init( &loaded->is_loading, &hash_wcs_func, &hash_wcs_cmp );
loaded->old_path = wcsdup( path_var );
}
hash_put( &loaded->is_loading, cmd, cmd );
/*
Get modification time of file
*/
tm = (time_t *)hash_get( loaded, cmd );
tm = (time_t *)hash_get( &loaded->load_time, cmd );
/*
Did we just check this?
@ -555,6 +673,7 @@ int parse_util_load( const wchar_t *cmd,
{
if(time(0)-tm[1]<=1)
{
hash_remove( &loaded->is_loading, cmd, 0, 0 );
return 0;
}
}
@ -563,7 +682,10 @@ int parse_util_load( const wchar_t *cmd,
Return if already loaded and we are skipping reloading
*/
if( !reload && tm )
{
hash_remove( &loaded->is_loading, cmd, 0, 0 );
return 0;
}
if( !path_list )
path_list = al_halloc( global_context);
@ -601,7 +723,7 @@ int parse_util_load( const wchar_t *cmd,
tm[0] = buf.st_mtime;
tm[1] = time(0);
hash_put( loaded,
hash_put( &loaded->load_time,
intern( cmd ),
tm );
@ -634,12 +756,13 @@ int parse_util_load( const wchar_t *cmd,
tm[0] = 0;
tm[1] = time(0);
hash_put( loaded, intern( cmd ), tm );
hash_put( &loaded->load_time, intern( cmd ), tm );
}
al_foreach( path_list, &free );
al_truncate( path_list, 0 );
hash_remove( &loaded->is_loading, cmd, 0, 0 );
return reloaded;
}
@ -670,7 +793,11 @@ void parse_util_set_argv( wchar_t **argv )
wchar_t *parse_util_unescape_wildcards( const wchar_t *str )
{
wchar_t *in, *out;
wchar_t *unescaped = wcsdup(str);
wchar_t *unescaped;
CHECK( str, 0 );
unescaped = wcsdup(str);
if( !unescaped )
DIE_MEM();

View file

@ -95,10 +95,11 @@ int parse_util_lineno( const wchar_t *str, int len );
/**
Autoload the specified file, if it exists in the specified path. Do
not load it multiple times unless it's timestamp changes.
not load it multiple times unless it's timestamp changes or
parse_util_unload is called.
\param cmd the filename to search for. The suffix '.fish' is always added to this name
\param path_var_name the name of an environment variable containing a search path
\param path_var_name the environment variable giving the search path
\param on_load a callback function to run if a suitable file is found, which has not already been run
\param reload wheter to recheck file timestamps on already loaded files
*/
@ -108,9 +109,28 @@ int parse_util_load( const wchar_t *cmd,
int reload );
/**
Reset the loader for the specified path variable
Reset the loader for the specified path variable. This will cause
all information on loaded files in the specified directory to be
reset.
\param path_var_name the environment variable giving the search path
\param on_load the callback function to use when a file is reloaded
\param on_load the callback function to call if the file has been previously loaded
*/
void parse_util_load_reset( const wchar_t *path_var );
void parse_util_load_reset( const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) );
/**
Tell the autoloader that the specified file, in the specified path,
is no longer loaded.
\param cmd the filename to search for. The suffix '.fish' is always added to this name
\param path_var_name the environment variable giving the search path
\return non-zero if the file was removed, zero if the file had not yet been loaded
*/
int parse_util_unload( const wchar_t *cmd,
const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) );
/**
Set the argv environment variable to the specified null-terminated

View file

@ -443,11 +443,19 @@ void parser_push_block( int type )
blocks should always be skipped. Rather complicated... :-(
*/
new->skip=current_block?current_block->skip:0;
/*
Type TOP and SUBST are never skipped
*/
if( type == TOP || type == SUBST )
{
new->skip = 0;
}
if( type == FAKE )
/*
Fake blocks and function definition blocks are never executed
*/
if( type == FAKE || type == FUNCTION_DEF )
{
new->skip = 1;
}
@ -2065,11 +2073,12 @@ static int parse_job( process_t *p,
forbid = (wchar_t *)(al_get_count( forbidden_function)?al_peek( forbidden_function ):0);
nxt_forbidden = forbid && (wcscmp( forbid, nxt) == 0 );
/*
Make feeble attempt to avoid infinite recursion. Will at
least catch some accidental infinite recursion calls.
*/
if( function_exists( nxt ) && !nxt_forbidden)
{
/*

View file

@ -2,7 +2,7 @@
# Match colors for grep, if supported
#
if grep --color=auto --help 1>/dev/null 2>/dev/null
if command grep --color=auto --help 1>/dev/null 2>/dev/null
if not set -q GREP_COLOR
set -gx GREP_COLOR '97;45'
end