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

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