2006-01-31 00:51:50 +08:00
/** \file parse_util.c
2006-02-19 09:54:38 +08:00
Various mostly unrelated utility functions related to parsing ,
loading and evaluating fish code .
2006-01-31 00:51:50 +08:00
*/
# include "config.h"
2006-02-28 21:17:16 +08:00
2006-01-31 00:51:50 +08:00
# include <stdlib.h>
# include <stdio.h>
# include <sys/types.h>
# include <unistd.h>
# include <wctype.h>
# include <wchar.h>
2006-02-08 17:20:05 +08:00
# include <time.h>
2006-01-31 00:51:50 +08:00
# include <assert.h>
2006-02-28 21:17:16 +08:00
# include "fallback.h"
2006-01-31 00:51:50 +08:00
# include "util.h"
2006-02-28 21:17:16 +08:00
2006-01-31 00:51:50 +08:00
# include "wutil.h"
# include "common.h"
# include "tokenizer.h"
# include "parse_util.h"
2006-02-08 17:20:05 +08:00
# include "expand.h"
# include "intern.h"
# include "exec.h"
2006-02-15 03:56:36 +08:00
# include "env.h"
2006-07-20 06:55:49 +08:00
2006-02-19 09:14:32 +08:00
# include "wildcard.h"
2006-02-09 23:50:20 +08:00
# include "halloc_util.h"
2006-02-08 17:20:05 +08:00
2006-07-12 22:22:42 +08:00
/**
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 ;
2006-02-08 17:20:05 +08:00
/**
Set of files which have been autoloaded
*/
2006-02-09 02:44:37 +08:00
static hash_table_t * all_loaded = 0 ;
2006-01-31 00:51:50 +08:00
2006-02-05 21:10:35 +08:00
int parse_util_lineno ( const wchar_t * str , int len )
{
2006-02-20 02:19:32 +08:00
/**
First cached state
*/
2006-06-14 21:22:40 +08:00
static wchar_t * prev_str = 0 ;
2006-02-20 02:19:32 +08:00
static int i = 0 ;
static int res = 1 ;
2006-02-05 21:10:35 +08:00
2006-02-20 02:19:32 +08:00
/**
Second cached state
*/
2006-06-14 21:22:40 +08:00
static wchar_t * prev_str2 = 0 ;
2006-02-05 21:10:35 +08:00
static int i2 = 0 ;
static int res2 = 1 ;
2006-06-21 08:48:36 +08:00
CHECK ( str , 0 ) ;
2006-02-05 21:10:35 +08:00
2006-06-21 08:48:36 +08:00
2006-02-05 21:10:35 +08:00
if ( str ! = prev_str | | i > len )
{
if ( prev_str2 = = str & & i2 < = len )
{
2006-06-14 21:22:40 +08:00
wchar_t * tmp_str = prev_str ;
2006-02-05 21:10:35 +08:00
int tmp_i = i ;
int tmp_res = res ;
prev_str = prev_str2 ;
i = i2 ;
res = res2 ;
prev_str2 = tmp_str ;
i2 = tmp_i ;
res2 = tmp_res ;
}
else
{
prev_str2 = prev_str ;
i2 = i ;
res2 = res ;
2006-06-14 21:22:40 +08:00
prev_str = ( wchar_t * ) str ;
2006-02-05 21:10:35 +08:00
i = 0 ;
res = 1 ;
}
}
2006-02-06 21:47:57 +08:00
for ( ; str [ i ] & & i < len ; i + + )
2006-02-05 21:10:35 +08:00
{
if ( str [ i ] = = L ' \n ' )
res + + ;
}
return res ;
}
2006-01-31 00:51:50 +08:00
int parse_util_locate_cmdsubst ( const wchar_t * in ,
2006-06-14 21:22:40 +08:00
wchar_t * * begin ,
wchar_t * * end ,
2006-01-31 00:51:50 +08:00
int allow_incomplete )
{
2006-06-14 21:22:40 +08:00
wchar_t * pos ;
2006-01-31 00:51:50 +08:00
wchar_t prev = 0 ;
int syntax_error = 0 ;
int paran_count = 0 ;
2006-06-14 21:22:40 +08:00
wchar_t * paran_begin = 0 , * paran_end = 0 ;
2006-01-31 00:51:50 +08:00
2006-06-21 08:48:36 +08:00
CHECK ( in , 0 ) ;
2006-06-15 08:59:31 +08:00
for ( pos = ( wchar_t * ) in ; * pos ; pos + + )
2006-01-31 00:51:50 +08:00
{
if ( prev ! = ' \\ ' )
{
if ( wcschr ( L " \' \" " , * pos ) )
{
2006-06-14 21:22:40 +08:00
wchar_t * q_end = quote_end ( pos ) ;
if ( q_end & & * q_end )
2006-01-31 00:51:50 +08:00
{
2006-06-14 21:22:40 +08:00
pos = q_end ;
2006-01-31 00:51:50 +08:00
}
else
2006-06-15 08:59:31 +08:00
{
2006-01-31 00:51:50 +08:00
break ;
2006-06-15 08:59:31 +08:00
}
2006-01-31 00:51:50 +08:00
}
else
{
if ( * pos = = ' ( ' )
{
if ( ( paran_count = = 0 ) & & ( paran_begin = = 0 ) )
paran_begin = pos ;
2006-02-20 02:19:32 +08:00
2006-01-31 00:51:50 +08:00
paran_count + + ;
}
else if ( * pos = = ' ) ' )
{
paran_count - - ;
if ( ( paran_count = = 0 ) & & ( paran_end = = 0 ) )
{
paran_end = pos ;
break ;
}
if ( paran_count < 0 )
{
syntax_error = 1 ;
break ;
}
}
}
}
prev = * pos ;
}
syntax_error | = ( paran_count < 0 ) ;
syntax_error | = ( ( paran_count > 0 ) & & ( ! allow_incomplete ) ) ;
if ( syntax_error )
{
return - 1 ;
}
if ( paran_begin = = 0 )
{
return 0 ;
}
2006-02-22 23:41:52 +08:00
if ( begin )
* begin = paran_begin ;
if ( end )
2006-06-14 21:22:40 +08:00
* end = paran_count ? ( wchar_t * ) in + wcslen ( in ) : paran_end ;
2006-01-31 00:51:50 +08:00
return 1 ;
}
void parse_util_cmdsubst_extent ( const wchar_t * buff ,
int cursor_pos ,
2006-06-14 21:22:40 +08:00
wchar_t * * a ,
wchar_t * * b )
2006-01-31 00:51:50 +08:00
{
2006-06-14 21:22:40 +08:00
wchar_t * begin , * end ;
wchar_t * pos ;
2006-07-03 18:46:47 +08:00
const wchar_t * cursor = buff + cursor_pos ;
2006-01-31 00:51:50 +08:00
2006-06-21 08:48:36 +08:00
CHECK ( buff , ) ;
2006-01-31 00:51:50 +08:00
if ( a )
2006-07-03 18:46:47 +08:00
* a = ( wchar_t * ) buff ;
2006-01-31 00:51:50 +08:00
if ( b )
2006-07-03 18:46:47 +08:00
* b = ( wchar_t * ) buff + wcslen ( buff ) ;
2006-06-14 21:22:40 +08:00
pos = ( wchar_t * ) buff ;
2006-01-31 00:51:50 +08:00
while ( 1 )
{
if ( parse_util_locate_cmdsubst ( pos ,
& begin ,
& end ,
1 ) < = 0 )
{
2006-07-03 18:46:47 +08:00
/*
No subshell found
*/
2006-01-31 00:51:50 +08:00
break ;
}
if ( ! end )
{
2006-06-14 21:22:40 +08:00
end = ( wchar_t * ) buff + wcslen ( buff ) ;
2006-01-31 00:51:50 +08:00
}
2006-07-03 18:46:47 +08:00
if ( ( begin < cursor ) & & ( end > = cursor ) )
2006-01-31 00:51:50 +08:00
{
begin + + ;
2006-07-03 18:46:47 +08:00
if ( a )
* a = begin ;
if ( b )
* b = end ;
2006-01-31 00:51:50 +08:00
break ;
}
2006-06-15 08:59:31 +08:00
if ( ! * end )
{
break ;
}
2006-01-31 00:51:50 +08:00
pos = end + 1 ;
}
2006-07-03 18:46:47 +08:00
2006-01-31 00:51:50 +08:00
}
/**
Get the beginning and end of the job or process definition under the cursor
*/
static void job_or_process_extent ( const wchar_t * buff ,
int cursor_pos ,
2006-06-14 21:22:40 +08:00
wchar_t * * a ,
wchar_t * * b ,
2006-01-31 00:51:50 +08:00
int process )
{
2006-06-14 21:22:40 +08:00
wchar_t * begin , * end ;
2006-01-31 00:51:50 +08:00
int pos ;
wchar_t * buffcpy ;
int finished = 0 ;
tokenizer tok ;
2006-06-21 08:48:36 +08:00
CHECK ( buff , ) ;
2006-01-31 00:51:50 +08:00
if ( a )
* a = 0 ;
if ( b )
* b = 0 ;
parse_util_cmdsubst_extent ( buff , cursor_pos , & begin , & end ) ;
if ( ! end | | ! begin )
return ;
pos = cursor_pos - ( begin - buff ) ;
if ( a )
{
* a = begin ;
}
if ( b )
{
* b = end ;
}
buffcpy = wcsndup ( begin , end - begin ) ;
if ( ! buffcpy )
{
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-01-31 00:51:50 +08:00
}
for ( tok_init ( & tok , buffcpy , TOK_ACCEPT_UNFINISHED ) ;
tok_has_next ( & tok ) & & ! finished ;
tok_next ( & tok ) )
{
int tok_begin = tok_get_pos ( & tok ) ;
switch ( tok_last_type ( & tok ) )
{
case TOK_PIPE :
if ( ! process )
break ;
case TOK_END :
case TOK_BACKGROUND :
{
if ( tok_begin > = pos )
{
finished = 1 ;
if ( b )
2006-06-14 21:22:40 +08:00
* b = ( wchar_t * ) buff + tok_begin ;
2006-01-31 00:51:50 +08:00
}
else
{
if ( a )
2006-06-14 21:22:40 +08:00
* a = ( wchar_t * ) buff + tok_begin + 1 ;
2006-01-31 00:51:50 +08:00
}
break ;
}
}
}
free ( buffcpy ) ;
tok_destroy ( & tok ) ;
}
void parse_util_process_extent ( const wchar_t * buff ,
int pos ,
2006-06-14 21:22:40 +08:00
wchar_t * * a ,
wchar_t * * b )
2006-01-31 00:51:50 +08:00
{
job_or_process_extent ( buff , pos , a , b , 1 ) ;
}
void parse_util_job_extent ( const wchar_t * buff ,
int pos ,
2006-06-14 21:22:40 +08:00
wchar_t * * a ,
wchar_t * * b )
2006-01-31 00:51:50 +08:00
{
job_or_process_extent ( buff , pos , a , b , 0 ) ;
}
void parse_util_token_extent ( const wchar_t * buff ,
int cursor_pos ,
2006-06-14 21:22:40 +08:00
wchar_t * * tok_begin ,
wchar_t * * tok_end ,
wchar_t * * prev_begin ,
wchar_t * * prev_end )
2006-01-31 00:51:50 +08:00
{
2006-06-14 21:22:40 +08:00
wchar_t * begin , * end ;
2006-01-31 00:51:50 +08:00
int pos ;
wchar_t * buffcpy ;
tokenizer tok ;
2006-06-14 21:22:40 +08:00
wchar_t * a , * b , * pa , * pb ;
2006-06-21 08:48:36 +08:00
CHECK ( buff , ) ;
2006-06-14 21:22:40 +08:00
assert ( cursor_pos > = 0 ) ;
2006-01-31 00:51:50 +08:00
a = b = pa = pb = 0 ;
parse_util_cmdsubst_extent ( buff , cursor_pos , & begin , & end ) ;
if ( ! end | | ! begin )
return ;
2006-07-03 18:46:47 +08:00
2006-01-31 00:51:50 +08:00
pos = cursor_pos - ( begin - buff ) ;
2006-07-03 18:46:47 +08:00
2006-06-14 21:22:40 +08:00
a = ( wchar_t * ) buff + pos ;
2006-01-31 00:51:50 +08:00
b = a ;
2006-06-14 21:22:40 +08:00
pa = ( wchar_t * ) buff + pos ;
2006-01-31 00:51:50 +08:00
pb = pa ;
2006-07-03 18:46:47 +08:00
2006-01-31 00:51:50 +08:00
assert ( begin > = buff ) ;
assert ( begin < = ( buff + wcslen ( buff ) ) ) ;
assert ( end > = begin ) ;
assert ( end < = ( buff + wcslen ( buff ) ) ) ;
2006-07-03 18:46:47 +08:00
2006-01-31 00:51:50 +08:00
buffcpy = wcsndup ( begin , end - begin ) ;
2006-07-03 18:46:47 +08:00
2006-01-31 00:51:50 +08:00
if ( ! buffcpy )
{
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-01-31 00:51:50 +08:00
}
for ( tok_init ( & tok , buffcpy , TOK_ACCEPT_UNFINISHED ) ;
tok_has_next ( & tok ) ;
tok_next ( & tok ) )
{
int tok_begin = tok_get_pos ( & tok ) ;
int tok_end = tok_begin ;
/*
Calculate end of token
*/
if ( tok_last_type ( & tok ) = = TOK_STRING )
tok_end + = wcslen ( tok_last ( & tok ) ) ;
/*
Cursor was before beginning of this token , means that the
cursor is between two tokens , so we set it to a zero element
string and break
*/
if ( tok_begin > pos )
{
2006-06-14 21:22:40 +08:00
a = b = ( wchar_t * ) buff + pos ;
2006-01-31 00:51:50 +08:00
break ;
}
/*
If cursor is inside the token , this is the token we are
looking for . If so , set a and b and break
*/
if ( tok_end > = pos )
{
a = begin + tok_get_pos ( & tok ) ;
b = a + wcslen ( tok_last ( & tok ) ) ;
// fwprintf( stderr, L"Whee %ls\n", *a );
break ;
}
/*
Remember previous string token
*/
if ( tok_last_type ( & tok ) = = TOK_STRING )
{
pa = begin + tok_get_pos ( & tok ) ;
pb = pa + wcslen ( tok_last ( & tok ) ) ;
}
}
free ( buffcpy ) ;
tok_destroy ( & tok ) ;
if ( tok_begin )
* tok_begin = a ;
if ( tok_end )
* tok_end = b ;
if ( prev_begin )
* prev_begin = pa ;
if ( prev_end )
* prev_end = pb ;
assert ( pa > = buff ) ;
assert ( pa < = ( buff + wcslen ( buff ) ) ) ;
assert ( pb > = pa ) ;
assert ( pb < = ( buff + wcslen ( buff ) ) ) ;
}
2006-02-09 23:50:20 +08:00
/**
Free hash value , but not hash key
*/
2006-07-12 22:22:42 +08:00
static void clear_hash_value ( void * key , void * data , void * aux )
2006-02-09 23:50:20 +08:00
{
2006-07-12 22:22:42 +08:00
if ( aux )
{
wchar_t * name = ( wchar_t * ) key ;
void ( * handler ) ( const wchar_t * ) = ( void ( * ) ( const wchar_t * ) ) aux ;
handler ( name ) ;
}
2006-02-09 23:50:20 +08:00
free ( ( void * ) data ) ;
}
2006-02-19 09:54:38 +08:00
/**
Part of the autoloader cleanup
*/
2006-07-12 22:22:42 +08:00
static void clear_loaded_entry ( void * key ,
void * data ,
void * handler )
2006-02-09 23:50:20 +08:00
{
2006-07-12 22:22:42 +08:00
autoload_t * loaded = ( autoload_t * ) data ;
hash_foreach2 ( & loaded - > load_time ,
& clear_hash_value ,
handler ) ;
hash_destroy ( & loaded - > load_time ) ;
2006-07-22 18:15:49 +08:00
hash_destroy ( & loaded - > is_loading ) ;
2006-07-12 22:22:42 +08:00
free ( loaded - > old_path ) ;
2006-02-09 23:50:20 +08:00
free ( loaded ) ;
free ( ( void * ) key ) ;
}
2006-02-19 09:54:38 +08:00
/**
The autoloader cleanup function . It is run on shutdown and frees
any memory used by the autoloader code to keep track of loaded
files .
*/
2006-02-09 23:50:20 +08:00
static void parse_util_destroy ( )
{
if ( all_loaded )
{
2006-07-12 22:22:42 +08:00
hash_foreach2 ( all_loaded ,
& clear_loaded_entry ,
0 ) ;
2006-02-09 23:50:20 +08:00
hash_destroy ( all_loaded ) ;
free ( all_loaded ) ;
all_loaded = 0 ;
}
}
2006-01-31 00:51:50 +08:00
2006-07-12 22:22:42 +08:00
void parse_util_load_reset ( const wchar_t * path_var_name ,
void ( * on_load ) ( const wchar_t * cmd ) )
2006-02-15 10:46:44 +08:00
{
2006-07-12 22:22:42 +08:00
wchar_t * path_var ;
CHECK ( path_var_name , ) ;
path_var = env_get ( path_var_name ) ;
if ( ! path_var )
return ;
2006-02-15 10:46:44 +08:00
if ( all_loaded )
{
void * key , * data ;
2006-07-12 22:22:42 +08:00
hash_remove ( all_loaded , path_var_name , & key , & data ) ;
2006-02-15 10:46:44 +08:00
if ( key )
2006-07-12 22:22:42 +08:00
clear_loaded_entry ( key , data , ( void * ) on_load ) ;
2006-02-15 10:46:44 +08:00
}
}
2006-07-12 22:22:42 +08:00
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 ;
}
2006-02-15 10:46:44 +08:00
2006-02-08 17:20:05 +08:00
int parse_util_load ( const wchar_t * cmd ,
2006-02-20 01:01:16 +08:00
const wchar_t * path_var_name ,
2006-02-15 10:46:44 +08:00
void ( * on_load ) ( const wchar_t * cmd ) ,
int reload )
2006-02-08 17:20:05 +08:00
{
2006-02-13 03:03:01 +08:00
static array_list_t * path_list = 0 ;
static string_buffer_t * path = 0 ;
2006-02-08 17:20:05 +08:00
int i ;
time_t * tm ;
int reloaded = 0 ;
2006-07-12 22:22:42 +08:00
autoload_t * loaded ;
2006-02-13 03:03:01 +08:00
2006-07-12 22:22:42 +08:00
wchar_t * path_var ;
2006-02-20 01:01:16 +08:00
2006-07-12 22:22:42 +08:00
CHECK ( path_var_name , 0 ) ;
CHECK ( cmd , 0 ) ;
path_var = env_get ( path_var_name ) ;
2006-02-08 17:20:05 +08:00
/*
Do we know where to look
*/
if ( ! path_var )
2006-07-12 22:22:42 +08:00
{
2006-02-08 17:20:05 +08:00
return 0 ;
2006-07-12 22:22:42 +08:00
}
2006-02-20 01:01:16 +08:00
2006-02-09 02:44:37 +08:00
if ( ! all_loaded )
{
2006-02-17 20:52:05 +08:00
all_loaded = malloc ( sizeof ( hash_table_t ) ) ;
halloc_register_function_void ( global_context , & parse_util_destroy ) ;
2006-02-09 02:44:37 +08:00
if ( ! all_loaded )
{
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-02-09 02:44:37 +08:00
}
hash_init ( all_loaded , & hash_wcs_func , & hash_wcs_cmp ) ;
2006-02-17 20:52:05 +08:00
}
2006-02-09 02:44:37 +08:00
2006-07-12 22:22:42 +08:00
loaded = ( autoload_t * ) hash_get ( all_loaded , path_var_name ) ;
if ( loaded )
{
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
2006-02-08 17:20:05 +08:00
{
2006-07-12 22:22:42 +08:00
/*
We have never tried to autoload using this name before , set up initial data
*/
loaded = malloc ( sizeof ( autoload_t ) ) ;
2006-02-08 17:20:05 +08:00
if ( ! loaded )
{
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-02-08 17:20:05 +08:00
}
2006-07-12 22:22:42 +08:00
hash_init ( & loaded - > load_time , & hash_wcs_func , & hash_wcs_cmp ) ;
2006-02-20 01:01:16 +08:00
hash_put ( all_loaded , wcsdup ( path_var_name ) , loaded ) ;
2006-07-12 22:22:42 +08:00
hash_init ( & loaded - > is_loading , & hash_wcs_func , & hash_wcs_cmp ) ;
loaded - > old_path = wcsdup ( path_var ) ;
2006-02-08 17:20:05 +08:00
}
2006-07-12 22:22:42 +08:00
hash_put ( & loaded - > is_loading , cmd , cmd ) ;
2006-02-08 17:20:05 +08:00
/*
Get modification time of file
*/
2006-07-12 22:22:42 +08:00
tm = ( time_t * ) hash_get ( & loaded - > load_time , cmd ) ;
2006-02-08 17:20:05 +08:00
/*
Did we just check this ?
*/
if ( tm )
2006-02-17 20:52:05 +08:00
{
2006-02-15 03:55:17 +08:00
if ( time ( 0 ) - tm [ 1 ] < = 1 )
2006-02-17 20:52:05 +08:00
{
2006-07-12 22:22:42 +08:00
hash_remove ( & loaded - > is_loading , cmd , 0 , 0 ) ;
2006-02-08 17:20:05 +08:00
return 0 ;
2006-02-17 20:52:05 +08:00
}
}
2006-02-08 17:20:05 +08:00
/*
Return if already loaded and we are skipping reloading
*/
if ( ! reload & & tm )
2006-07-12 22:22:42 +08:00
{
hash_remove ( & loaded - > is_loading , cmd , 0 , 0 ) ;
2006-02-08 17:20:05 +08:00
return 0 ;
2006-07-12 22:22:42 +08:00
}
2006-02-13 03:03:01 +08:00
if ( ! path_list )
path_list = al_halloc ( global_context ) ;
if ( ! path )
path = sb_halloc ( global_context ) ;
else
sb_clear ( path ) ;
2006-05-29 19:13:42 +08:00
tokenize_variable_array ( path_var , path_list ) ;
2006-02-13 03:03:01 +08:00
2006-02-08 17:20:05 +08:00
/*
Iterate over path searching for suitable completion files
*/
2006-02-13 03:03:01 +08:00
for ( i = 0 ; i < al_get_count ( path_list ) ; i + + )
2006-02-08 17:20:05 +08:00
{
struct stat buf ;
2006-02-13 03:03:01 +08:00
wchar_t * next = ( wchar_t * ) al_get ( path_list , i ) ;
sb_clear ( path ) ;
sb_append2 ( path , next , L " / " , cmd , L " .fish " , ( void * ) 0 ) ;
if ( ( wstat ( ( wchar_t * ) path - > buff , & buf ) = = 0 ) & &
( waccess ( ( wchar_t * ) path - > buff , R_OK ) = = 0 ) )
2006-02-08 17:20:05 +08:00
{
2006-02-17 20:52:05 +08:00
if ( ! tm | | ( tm [ 0 ] ! = buf . st_mtime ) )
2006-02-08 17:20:05 +08:00
{
2006-02-13 03:03:01 +08:00
wchar_t * esc = escape ( ( wchar_t * ) path - > buff , 1 ) ;
2006-02-08 17:20:05 +08:00
wchar_t * src_cmd = wcsdupcat ( L " . " , esc ) ;
2006-02-13 03:03:01 +08:00
2006-02-08 17:20:05 +08:00
if ( ! tm )
{
tm = malloc ( sizeof ( time_t ) * 2 ) ;
if ( ! tm )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-02-08 17:20:05 +08:00
}
tm [ 0 ] = buf . st_mtime ;
tm [ 1 ] = time ( 0 ) ;
2006-07-12 22:22:42 +08:00
hash_put ( & loaded - > load_time ,
2006-02-08 17:20:05 +08:00
intern ( cmd ) ,
tm ) ;
free ( esc ) ;
2006-02-20 02:19:32 +08:00
if ( on_load )
on_load ( cmd ) ;
2006-02-09 02:44:37 +08:00
2006-02-08 17:20:05 +08:00
/*
Source the completion file for the specified completion
*/
exec_subshell ( src_cmd , 0 ) ;
free ( src_cmd ) ;
reloaded = 1 ;
break ;
}
}
}
/*
If no file was found we insert the current time . Later we only
research if the current time is at least five seconds later .
This way , the files won ' t be searched over and over again .
*/
if ( ! tm )
{
tm = malloc ( sizeof ( time_t ) * 2 ) ;
if ( ! tm )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-02-08 17:20:05 +08:00
tm [ 0 ] = 0 ;
tm [ 1 ] = time ( 0 ) ;
2006-07-12 22:22:42 +08:00
hash_put ( & loaded - > load_time , intern ( cmd ) , tm ) ;
2006-02-08 17:20:05 +08:00
}
2006-06-13 05:47:42 +08:00
al_foreach ( path_list , & free ) ;
2006-02-13 03:03:01 +08:00
al_truncate ( path_list , 0 ) ;
2006-07-12 22:22:42 +08:00
hash_remove ( & loaded - > is_loading , cmd , 0 , 0 ) ;
2006-02-08 17:20:05 +08:00
return reloaded ;
}
2006-02-15 03:56:36 +08:00
void parse_util_set_argv ( wchar_t * * argv )
{
if ( * argv )
{
wchar_t * * arg ;
string_buffer_t sb ;
sb_init ( & sb ) ;
for ( arg = argv ; * arg ; arg + + )
{
if ( arg ! = argv )
sb_append ( & sb , ARRAY_SEP_STR ) ;
sb_append ( & sb , * arg ) ;
}
env_set ( L " argv " , ( wchar_t * ) sb . buff , ENV_LOCAL ) ;
sb_destroy ( & sb ) ;
}
else
{
env_set ( L " argv " , 0 , ENV_LOCAL ) ;
}
}
2006-02-19 09:14:32 +08:00
wchar_t * parse_util_unescape_wildcards ( const wchar_t * str )
{
wchar_t * in , * out ;
2006-07-12 22:22:42 +08:00
wchar_t * unescaped ;
CHECK ( str , 0 ) ;
unescaped = wcsdup ( str ) ;
2006-02-19 09:14:32 +08:00
if ( ! unescaped )
2006-07-03 18:39:57 +08:00
DIE_MEM ( ) ;
2006-02-19 09:14:32 +08:00
for ( in = out = unescaped ; * in ; in + + )
{
switch ( * in )
{
case L ' \\ ' :
if ( * ( in + 1 ) )
{
in + + ;
* ( out + + ) = * in ;
}
* ( out + + ) = * in ;
break ;
case L ' * ' :
* ( out + + ) = ANY_STRING ;
break ;
case L ' ? ' :
* ( out + + ) = ANY_CHAR ;
break ;
default :
* ( out + + ) = * in ;
break ;
}
}
return unescaped ;
}
2006-02-15 03:56:36 +08:00