mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Rewrote parse_util.cpp data structures to use STL types and classes
This commit is contained in:
parent
04c7d87261
commit
fec0415d4e
1 changed files with 205 additions and 289 deletions
494
parse_util.cpp
494
parse_util.cpp
|
@ -18,6 +18,8 @@
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -50,36 +52,123 @@
|
||||||
*/
|
*/
|
||||||
#define AUTOLOAD_MIN_AGE 60
|
#define AUTOLOAD_MIN_AGE 60
|
||||||
|
|
||||||
|
struct autoload_function_t
|
||||||
|
{
|
||||||
|
bool is_placeholder; //whether we are a placeholder that stands in for "no such function"
|
||||||
|
wcstring name; //function name
|
||||||
|
time_t modification_time; // st_mtime
|
||||||
|
time_t load_time; // when function was loaded
|
||||||
|
|
||||||
|
struct compare_names
|
||||||
|
{
|
||||||
|
bool operator()(const autoload_function_t &a, const autoload_function_t &b) const {
|
||||||
|
return a.name < b.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
autoload_function_t(const wcstring &the_name) : is_placeholder(false), name(the_name), modification_time(0), load_time(0) { }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A structure representing the autoload state for a specific variable, e.g. fish_complete_path
|
A structure representing the autoload state for a specific variable, e.g. fish_complete_path
|
||||||
*/
|
*/
|
||||||
typedef struct
|
struct autoload_t
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
typedef std::set<autoload_function_t, autoload_function_t::compare_names> autoload_function_set_t;
|
||||||
|
autoload_function_set_t functions_set;
|
||||||
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A table containing the modification times of all loaded
|
A table containing all the files that are currently being
|
||||||
files. Failed loads (non-existing files) have modification time
|
loaded. This is here to help prevent recursion.
|
||||||
0.
|
|
||||||
*/
|
*/
|
||||||
hash_table_t load_time;
|
std::set<wcstring> is_loading_set;
|
||||||
|
|
||||||
|
bool is_loading(const wcstring &name) {
|
||||||
|
return is_loading_set.find(name) != is_loading_set.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
autoload_function_t *create_function_with_name(const wcstring &name)
|
||||||
|
{
|
||||||
|
const autoload_function_t func(name);
|
||||||
|
autoload_function_set_t::iterator iter = functions_set.insert(func).first;
|
||||||
|
return const_cast<autoload_function_t *>(&*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove_function_with_name(const wcstring &name)
|
||||||
|
{
|
||||||
|
const autoload_function_t func(name);
|
||||||
|
size_t numErased = functions_set.erase(func);
|
||||||
|
return numErased > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
autoload_function_t *get_function_with_name(const wcstring &name)
|
||||||
|
{
|
||||||
|
autoload_function_t *result = NULL;
|
||||||
|
const autoload_function_t func(name);
|
||||||
|
autoload_function_set_t::iterator iter = functions_set.find(func);
|
||||||
|
if (iter != functions_set.end())
|
||||||
|
result = const_cast<autoload_function_t *>(&*iter);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_all_functions(void)
|
||||||
|
{
|
||||||
|
functions_set.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t function_count(void) const
|
||||||
|
{
|
||||||
|
return functions_set.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the function least recently loaded, or NULL */
|
||||||
|
autoload_function_t *get_lru_function(const wcstring &skip)
|
||||||
|
{
|
||||||
|
autoload_function_t *result = NULL;
|
||||||
|
autoload_function_set_t::iterator iter;
|
||||||
|
for (iter = functions_set.begin(); iter != functions_set.end(); iter++)
|
||||||
|
{
|
||||||
|
/* Skip the skip */
|
||||||
|
if (iter->name == skip) continue;
|
||||||
|
|
||||||
|
/* Skip items that aren't real */
|
||||||
|
if (iter->is_placeholder) continue;
|
||||||
|
|
||||||
|
/* Skip items that are still loading */
|
||||||
|
if (is_loading(iter->name)) continue;
|
||||||
|
|
||||||
|
/* C++ makes all std::set iterators const because it wants to annoy us. */
|
||||||
|
if (result == NULL || iter->load_time < result->load_time)
|
||||||
|
result = const_cast<autoload_function_t *>(&*iter);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_handler_to_nonplaceholder_function_names(void (*handler)(const wchar_t *cmd)) const
|
||||||
|
{
|
||||||
|
autoload_function_set_t::iterator iter;
|
||||||
|
for (iter = functions_set.begin(); iter != functions_set.end(); iter++)
|
||||||
|
handler(iter->name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A string containg the path used to find any files to load. If
|
A string containg the path used to find any files to load. If
|
||||||
this differs from the current environment variable, the
|
this differs from the current environment variable, the
|
||||||
autoloader needs to drop all loaded files and reload them.
|
autoloader needs to drop all loaded files and reload them.
|
||||||
*/
|
*/
|
||||||
wchar_t *old_path;
|
wcstring 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
|
Set of files which have been autoloaded
|
||||||
*/
|
*/
|
||||||
static hash_table_t *all_loaded=0;
|
|
||||||
|
typedef std::map<wcstring, autoload_t> autoload_map_t;
|
||||||
|
static autoload_map_t all_loaded_map;
|
||||||
|
|
||||||
int parse_util_lineno( const wchar_t *str, int len )
|
int parse_util_lineno( const wchar_t *str, int len )
|
||||||
{
|
{
|
||||||
|
@ -628,83 +717,23 @@ 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, void *aux )
|
|
||||||
{
|
|
||||||
if( aux )
|
|
||||||
{
|
|
||||||
wchar_t *name = (wchar_t *)key;
|
|
||||||
time_t *time = (time_t *)data;
|
|
||||||
void (*handler)(const wchar_t *)= (void (*)(const wchar_t *))aux;
|
|
||||||
|
|
||||||
/*
|
|
||||||
If time[0] is 0, that means the file really doesn't exist,
|
|
||||||
it's simply been checked before. We should not unload it.
|
|
||||||
*/
|
|
||||||
if( time[0] && handler )
|
|
||||||
{
|
|
||||||
// debug( 0, L"Unloading function %ls", name );
|
|
||||||
handler( name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free( (void *)data );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Part of the autoloader cleanup
|
|
||||||
*/
|
|
||||||
static void clear_loaded_entry( void *key,
|
|
||||||
void *data,
|
|
||||||
void *handler )
|
|
||||||
{
|
|
||||||
autoload_t *loaded = (autoload_t *)data;
|
|
||||||
hash_foreach2( &loaded->load_time,
|
|
||||||
&clear_hash_value,
|
|
||||||
handler );
|
|
||||||
hash_destroy( &loaded->load_time );
|
|
||||||
hash_destroy( &loaded->is_loading );
|
|
||||||
|
|
||||||
free( loaded->old_path );
|
|
||||||
free( loaded );
|
|
||||||
free( (void *)key );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The autoloader cleanup function. It is run on shutdown and frees
|
|
||||||
any memory used by the autoloader code to keep track of loaded
|
|
||||||
files.
|
|
||||||
*/
|
|
||||||
static void parse_util_destroy()
|
|
||||||
{
|
|
||||||
if( all_loaded )
|
|
||||||
{
|
|
||||||
hash_foreach2( all_loaded,
|
|
||||||
&clear_loaded_entry,
|
|
||||||
0 );
|
|
||||||
|
|
||||||
hash_destroy( all_loaded );
|
|
||||||
free( all_loaded );
|
|
||||||
all_loaded = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_util_load_reset( const wchar_t *path_var_name,
|
void parse_util_load_reset( const wchar_t *path_var_name,
|
||||||
void (*on_load)(const wchar_t *cmd) )
|
void (*on_load)(const wchar_t *cmd) )
|
||||||
{
|
{
|
||||||
CHECK( path_var_name, );
|
CHECK( path_var_name, );
|
||||||
|
|
||||||
if( all_loaded )
|
autoload_map_t::iterator condemned = all_loaded_map.find(path_var_name);
|
||||||
{
|
if (condemned != all_loaded_map.end())
|
||||||
void *key, *data;
|
{
|
||||||
hash_remove( all_loaded, path_var_name, &key, &data );
|
autoload_t &loaded = condemned->second;
|
||||||
if( key )
|
if (on_load) {
|
||||||
{
|
/* Call the on_load handler on each real function name. */
|
||||||
clear_loaded_entry( key, data, (void *)on_load );
|
loaded.apply_handler_to_nonplaceholder_function_names(on_load);
|
||||||
}
|
}
|
||||||
}
|
/* Empty the functino set */
|
||||||
|
loaded.remove_all_functions();
|
||||||
|
all_loaded_map.erase(condemned);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,35 +741,25 @@ int parse_util_unload( const wchar_t *cmd,
|
||||||
const wchar_t *path_var_name,
|
const wchar_t *path_var_name,
|
||||||
void (*on_load)(const wchar_t *cmd) )
|
void (*on_load)(const wchar_t *cmd) )
|
||||||
{
|
{
|
||||||
autoload_t *loaded;
|
int result = 0;
|
||||||
void *val;
|
|
||||||
|
|
||||||
CHECK( path_var_name, 0 );
|
CHECK( path_var_name, 0 );
|
||||||
CHECK( cmd, 0 );
|
CHECK( cmd, 0 );
|
||||||
|
|
||||||
if( !all_loaded )
|
autoload_map_t::iterator iter = all_loaded_map.find(path_var_name);
|
||||||
{
|
if (iter == all_loaded_map.end())
|
||||||
return 0;
|
{
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
|
|
||||||
|
autoload_t &loaded = iter->second;
|
||||||
if( !loaded )
|
if (loaded.remove_function_with_name(cmd))
|
||||||
{
|
{
|
||||||
return 0;
|
if (on_load)
|
||||||
}
|
on_load(cmd);
|
||||||
|
result = 1;
|
||||||
hash_remove( &loaded->load_time, cmd, 0, &val );
|
}
|
||||||
if( val )
|
return result;
|
||||||
{
|
|
||||||
if( on_load )
|
|
||||||
{
|
|
||||||
on_load( cmd );
|
|
||||||
}
|
|
||||||
free( val );
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -757,71 +776,30 @@ static void parse_util_autounload( const wchar_t *path_var_name,
|
||||||
const wchar_t *skip,
|
const wchar_t *skip,
|
||||||
void (*on_load)(const wchar_t *cmd) )
|
void (*on_load)(const wchar_t *cmd) )
|
||||||
{
|
{
|
||||||
autoload_t *loaded;
|
autoload_map_t::iterator iter = all_loaded_map.find(path_var_name);
|
||||||
int loaded_count=0;
|
if (iter == all_loaded_map.end())
|
||||||
|
{
|
||||||
if( !all_loaded )
|
return;
|
||||||
{
|
}
|
||||||
return;
|
autoload_t &loaded = iter->second;
|
||||||
}
|
|
||||||
|
|
||||||
loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
|
if( loaded.function_count() >= AUTOLOAD_MAX )
|
||||||
if( !loaded )
|
|
||||||
{
|
{
|
||||||
return;
|
autoload_function_t *lru = loaded.get_lru_function(skip);
|
||||||
}
|
time_t cutoff_access = time(0) - AUTOLOAD_MIN_AGE;
|
||||||
|
if (lru && lru->load_time < cutoff_access)
|
||||||
if( hash_get_count( &loaded->load_time ) >= AUTOLOAD_MAX )
|
{
|
||||||
{
|
parse_util_unload( lru->name.c_str(), path_var_name, on_load );
|
||||||
time_t oldest_access = time(0) - AUTOLOAD_MIN_AGE;
|
}
|
||||||
wchar_t *oldest_item=0;
|
}
|
||||||
int i;
|
|
||||||
array_list_t key;
|
|
||||||
al_init( &key );
|
|
||||||
hash_get_keys( &loaded->load_time, &key );
|
|
||||||
for( i=0; i<al_get_count( &key ); i++ )
|
|
||||||
{
|
|
||||||
wchar_t *item = (wchar_t *)al_get( &key, i );
|
|
||||||
time_t *tm = (time_t *)hash_get( &loaded->load_time, item );
|
|
||||||
|
|
||||||
if( wcscmp( item, skip ) == 0 )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !tm[0] )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( hash_get( &loaded->is_loading, item ) )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded_count++;
|
|
||||||
|
|
||||||
if( tm[1] < oldest_access )
|
|
||||||
{
|
|
||||||
oldest_access = tm[1];
|
|
||||||
oldest_item = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
al_destroy( &key );
|
|
||||||
|
|
||||||
if( oldest_item && loaded_count > AUTOLOAD_MAX)
|
|
||||||
{
|
|
||||||
parse_util_unload( oldest_item, path_var_name, on_load );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_util_load_internal( const wchar_t *cmd,
|
static int parse_util_load_internal( const wcstring &cmd,
|
||||||
const struct builtin_script_t *builtin_scripts,
|
const struct builtin_script_t *builtin_scripts,
|
||||||
size_t builtin_script_count,
|
size_t builtin_script_count,
|
||||||
void (*on_load)(const wchar_t *cmd),
|
void (*on_load)(const wchar_t *cmd),
|
||||||
int reload,
|
int reload,
|
||||||
autoload_t *loaded,
|
autoload_t &loaded,
|
||||||
const std::vector<wcstring> &path_list );
|
const std::vector<wcstring> &path_list );
|
||||||
|
|
||||||
|
|
||||||
|
@ -830,12 +808,11 @@ int parse_util_load( const wcstring &cmd,
|
||||||
void (*on_load)(const wchar_t *cmd),
|
void (*on_load)(const wchar_t *cmd),
|
||||||
int reload )
|
int reload )
|
||||||
{
|
{
|
||||||
autoload_t *loaded;
|
|
||||||
|
|
||||||
wchar_t *path_var;
|
wchar_t *path_var;
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
int c, c2;
|
int c, c2;
|
||||||
|
autoload_t *loaded;
|
||||||
|
|
||||||
CHECK_BLOCK( 0 );
|
CHECK_BLOCK( 0 );
|
||||||
|
|
||||||
|
@ -852,29 +829,16 @@ int parse_util_load( const wcstring &cmd,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
autoload_map_t::iterator iter = all_loaded_map.find(path_var_name);
|
||||||
Init if this is the first time we try to autoload anything
|
if (iter != all_loaded_map.end())
|
||||||
*/
|
{
|
||||||
if( !all_loaded )
|
loaded = &iter->second;
|
||||||
{
|
|
||||||
all_loaded = (hash_table_t *)malloc( sizeof( hash_table_t ) );
|
|
||||||
halloc_register_function_void( global_context, &parse_util_destroy );
|
|
||||||
if( !all_loaded )
|
|
||||||
{
|
|
||||||
DIE_MEM();
|
|
||||||
}
|
|
||||||
hash_init( all_loaded, &hash_wcs_func, &hash_wcs_cmp );
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded = (autoload_t *)hash_get( all_loaded, path_var_name.c_str() );
|
|
||||||
|
|
||||||
if( loaded )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
Check if the lookup path has changed. If so, drop all loaded
|
Check if the lookup path has changed. If so, drop all loaded
|
||||||
files and start from scratch.
|
files and start from scratch.
|
||||||
*/
|
*/
|
||||||
if( wcscmp( path_var, loaded->old_path ) != 0 )
|
if( path_var != loaded->old_path )
|
||||||
{
|
{
|
||||||
parse_util_load_reset( path_var_name.c_str(), on_load);
|
parse_util_load_reset( path_var_name.c_str(), on_load);
|
||||||
reload = parse_util_load( cmd, path_var_name, on_load, reload );
|
reload = parse_util_load( cmd, path_var_name, on_load, reload );
|
||||||
|
@ -884,7 +848,7 @@ int parse_util_load( const wcstring &cmd,
|
||||||
/**
|
/**
|
||||||
Warn and fail on infinite recursion
|
Warn and fail on infinite recursion
|
||||||
*/
|
*/
|
||||||
if( hash_get( &loaded->is_loading, cmd.c_str() ) )
|
if (loaded->is_loading(cmd))
|
||||||
{
|
{
|
||||||
debug( 0,
|
debug( 0,
|
||||||
_( L"Could not autoload item '%ls', it is already being autoloaded. "
|
_( L"Could not autoload item '%ls', it is already being autoloaded. "
|
||||||
|
@ -892,7 +856,6 @@ int parse_util_load( const wcstring &cmd,
|
||||||
cmd.c_str() );
|
cmd.c_str() );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -902,17 +865,8 @@ int parse_util_load( const wcstring &cmd,
|
||||||
set up initial data
|
set up initial data
|
||||||
*/
|
*/
|
||||||
// debug( 0, L"Create brand new autoload_t for %ls->%ls", path_var_name, path_var );
|
// debug( 0, L"Create brand new autoload_t for %ls->%ls", path_var_name, path_var );
|
||||||
loaded = (autoload_t *)malloc( sizeof( autoload_t ) );
|
loaded = &all_loaded_map[path_var_name];
|
||||||
if( !loaded )
|
loaded->old_path = path_var;
|
||||||
{
|
|
||||||
DIE_MEM();
|
|
||||||
}
|
|
||||||
hash_init( &loaded->load_time, &hash_wcs_func, &hash_wcs_cmp );
|
|
||||||
hash_put( all_loaded, wcsdup(path_var_name.c_str()), loaded );
|
|
||||||
|
|
||||||
hash_init( &loaded->is_loading, &hash_wcs_func, &hash_wcs_cmp );
|
|
||||||
|
|
||||||
loaded->old_path = wcsdup( path_var );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<wcstring> path_list;
|
std::vector<wcstring> path_list;
|
||||||
|
@ -920,7 +874,7 @@ int parse_util_load( const wcstring &cmd,
|
||||||
|
|
||||||
c = path_list.size();
|
c = path_list.size();
|
||||||
|
|
||||||
hash_put( &loaded->is_loading, cmd.c_str(), cmd.c_str() );
|
loaded->is_loading_set.insert(cmd);
|
||||||
|
|
||||||
/* Figure out which builtin-scripts array to search (if any) */
|
/* Figure out which builtin-scripts array to search (if any) */
|
||||||
const builtin_script_t *builtins = NULL;
|
const builtin_script_t *builtins = NULL;
|
||||||
|
@ -935,16 +889,21 @@ int parse_util_load( const wcstring &cmd,
|
||||||
Do the actual work in the internal helper function
|
Do the actual work in the internal helper function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res = parse_util_load_internal( cmd.c_str(), builtins, builtin_count, on_load, reload, loaded, path_list );
|
res = parse_util_load_internal( cmd, builtins, builtin_count, on_load, reload, *loaded, path_list );
|
||||||
|
|
||||||
autoload_t *loaded2 = (autoload_t *)hash_get( all_loaded, path_var_name.c_str() );
|
autoload_map_t::iterator iter2 = all_loaded_map.find(path_var_name);
|
||||||
if( loaded2 == loaded )
|
if (iter2 != all_loaded_map.end()) {
|
||||||
{
|
autoload_t *loaded2 = &iter2->second;
|
||||||
/**
|
if( loaded2 == loaded )
|
||||||
Cleanup
|
{
|
||||||
*/
|
/**
|
||||||
hash_remove( &loaded->is_loading, cmd.c_str(), 0, 0 );
|
Cleanup
|
||||||
}
|
*/
|
||||||
|
std::set<wcstring>::iterator condemned = loaded->is_loading_set.find(cmd);
|
||||||
|
assert(condemned != loaded->is_loading_set.end());
|
||||||
|
loaded->is_loading_set.erase(condemned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c2 = path_list.size();
|
c2 = path_list.size();
|
||||||
|
|
||||||
|
@ -963,57 +922,34 @@ int parse_util_load( const wcstring &cmd,
|
||||||
the code, and the caller can take care of various cleanup work.
|
the code, and the caller can take care of various cleanup work.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int parse_util_load_internal( const wchar_t *cmd,
|
static int parse_util_load_internal( const wcstring &cmd,
|
||||||
const struct builtin_script_t *builtin_scripts,
|
const struct builtin_script_t *builtin_scripts,
|
||||||
size_t builtin_script_count,
|
size_t builtin_script_count,
|
||||||
void (*on_load)(const wchar_t *cmd),
|
void (*on_load)(const wchar_t *cmd),
|
||||||
int reload,
|
int reload,
|
||||||
autoload_t *loaded,
|
autoload_t &loaded,
|
||||||
const std::vector<wcstring> &path_list )
|
const std::vector<wcstring> &path_list )
|
||||||
{
|
{
|
||||||
static string_buffer_t *path=0;
|
|
||||||
time_t *tm;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
int reloaded = 0;
|
int reloaded = 0;
|
||||||
|
|
||||||
/*
|
/* Get the function */
|
||||||
Get modification time of file
|
autoload_function_t * func = loaded.get_function_with_name(cmd);
|
||||||
*/
|
|
||||||
tm = (time_t *)hash_get( &loaded->load_time, cmd );
|
|
||||||
|
/* Return if already loaded and we are skipping reloading */
|
||||||
/*
|
if( !reload && func )
|
||||||
Did we just check this?
|
|
||||||
*/
|
|
||||||
if( tm )
|
|
||||||
{
|
|
||||||
if(time(0)-tm[1]<=1)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Return if already loaded and we are skipping reloading
|
|
||||||
*/
|
|
||||||
if( !reload && tm )
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
/* Nothing to do if we just checked it */
|
||||||
if( !path )
|
if (func && time(NULL) - func->load_time <= 1)
|
||||||
{
|
return 0;
|
||||||
path = sb_halloc( global_context );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb_clear( path );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Look for built-in scripts.
|
Look for built-in scripts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Iterate over path searching for suitable completion files
|
Iterate over path searching for suitable completion files
|
||||||
*/
|
*/
|
||||||
|
@ -1021,58 +957,44 @@ static int parse_util_load_internal( const wchar_t *cmd,
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
wcstring next = path_list.at(i);
|
wcstring next = path_list.at(i);
|
||||||
sb_clear( path );
|
wcstring path = next + L"/" + cmd + L".fish";
|
||||||
sb_append( path, next.c_str(), L"/", cmd, L".fish", NULL );
|
|
||||||
|
|
||||||
if( (wstat( (wchar_t *)path->buff, &buf )== 0) &&
|
if( (wstat( path.c_str(), &buf )== 0) &&
|
||||||
(waccess( (wchar_t *)path->buff, R_OK ) == 0) )
|
(waccess( path.c_str(), R_OK ) == 0) )
|
||||||
{
|
{
|
||||||
if( !tm || (tm[0] != buf.st_mtime ) )
|
if( !func || (func->modification_time != buf.st_mtime ) )
|
||||||
{
|
{
|
||||||
wchar_t *esc = escape( (wchar_t *)path->buff, 1 );
|
wcstring esc = escape_string(path, 1);
|
||||||
wchar_t *src_cmd = wcsdupcat( L". ", esc );
|
wcstring src_cmd = L". " + esc;
|
||||||
free( esc );
|
|
||||||
|
|
||||||
if( !tm )
|
if( !func )
|
||||||
{
|
func = loaded.create_function_with_name(cmd);
|
||||||
tm = (time_t *)malloc(sizeof(time_t)*2);
|
|
||||||
if( !tm )
|
|
||||||
{
|
|
||||||
DIE_MEM();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tm[0] = buf.st_mtime;
|
|
||||||
tm[1] = time(0);
|
|
||||||
hash_put( &loaded->load_time,
|
|
||||||
intern( cmd ),
|
|
||||||
tm );
|
|
||||||
|
|
||||||
|
func->modification_time = buf.st_mtime;
|
||||||
|
func->load_time = time(NULL);
|
||||||
|
|
||||||
if( on_load )
|
if( on_load )
|
||||||
{
|
on_load(cmd.c_str());
|
||||||
on_load(cmd );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Source the completion file for the specified completion
|
Source the completion file for the specified completion
|
||||||
*/
|
*/
|
||||||
if( exec_subshell( src_cmd, 0 ) == -1 )
|
if( exec_subshell( src_cmd.c_str(), 0 ) == -1 )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Do nothing on failiure
|
Do nothing on failiure
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
free(src_cmd);
|
|
||||||
reloaded = 1;
|
reloaded = 1;
|
||||||
}
|
}
|
||||||
else if( tm )
|
else if( func )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
If we are rechecking an autoload file, and it hasn't
|
If we are rechecking an autoload file, and it hasn't
|
||||||
changed, update the 'last check' timestamp.
|
changed, update the 'last check' timestamp.
|
||||||
*/
|
*/
|
||||||
tm[1] = time(0);
|
func->load_time = time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1080,21 +1002,15 @@ static int parse_util_load_internal( const wchar_t *cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If no file was found we insert the current time. Later we only
|
If no file was found we insert a placeholder function. Later we only
|
||||||
research if the current time is at least five seconds later.
|
research if the current time is at least five seconds later.
|
||||||
This way, the files won't be searched over and over again.
|
This way, the files won't be searched over and over again.
|
||||||
*/
|
*/
|
||||||
if( !tm )
|
if( !func )
|
||||||
{
|
{
|
||||||
tm = (time_t *)malloc(sizeof(time_t)*2);
|
func = loaded.create_function_with_name(cmd);
|
||||||
if( !tm )
|
func->load_time = time(NULL);
|
||||||
{
|
func->is_placeholder = true;
|
||||||
DIE_MEM();
|
|
||||||
}
|
|
||||||
|
|
||||||
tm[0] = 0;
|
|
||||||
tm[1] = time(0);
|
|
||||||
hash_put( &loaded->load_time, intern( cmd ), tm );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return reloaded;
|
return reloaded;
|
||||||
|
|
Loading…
Reference in a new issue