2005-09-20 13:26:39 +00:00
/** \file function.c
2006-11-15 14:16:49 +00:00
Prototypes for functions for storing and retrieving function
information . These functions also take care of autoloading
functions in the $ fish_function_path . Actual function evaluation
is taken care of by the parser and to some degree the builtin
handling library .
2005-09-20 13:26:39 +00:00
*/
2006-08-11 01:18:35 +00:00
# include "config.h"
2005-09-20 13:26:39 +00:00
# include <stdlib.h>
# include <stdio.h>
2011-12-27 03:18:46 +00:00
# include <string.h>
2005-09-20 13:26:39 +00:00
# include <wchar.h>
# include <unistd.h>
# include <termios.h>
# include <signal.h>
2011-12-27 03:18:46 +00:00
# include <pthread.h>
# include <errno.h>
2012-01-14 07:44:18 +00:00
# include <map>
# include <set>
2005-09-20 13:26:39 +00:00
2006-01-20 14:27:21 +00:00
# include "wutil.h"
2006-02-28 13:17:16 +00:00
# include "fallback.h"
2005-09-20 13:26:39 +00:00
# include "util.h"
2006-02-28 13:17:16 +00:00
2005-09-20 13:26:39 +00:00
# include "function.h"
# include "proc.h"
# include "parser.h"
# include "common.h"
# include "intern.h"
2005-10-05 22:37:08 +00:00
# include "event.h"
2006-01-26 14:48:10 +00:00
# include "reader.h"
2006-02-05 13:10:35 +00:00
# include "parse_util.h"
2007-04-22 09:50:26 +00:00
# include "parser_keywords.h"
2006-02-08 09:20:05 +00:00
# include "env.h"
2006-02-08 15:29:09 +00:00
# include "expand.h"
2006-11-15 14:16:49 +00:00
# include "halloc.h"
# include "halloc_util.h"
2005-09-20 13:26:39 +00:00
2012-01-14 07:44:18 +00:00
class function_internal_info_t
2005-09-20 13:26:39 +00:00
{
2012-01-14 07:44:18 +00:00
public :
/** Function definition */
wcstring definition ;
/** Function description */
wcstring description ;
2006-06-17 13:07:08 +00:00
/**
File where this function was defined
*/
2012-01-14 07:44:18 +00:00
const wchar_t * definition_file ;
2006-06-17 13:07:08 +00:00
/**
Line where definition started
*/
2012-01-14 07:44:18 +00:00
int definition_offset ;
2008-01-13 16:47:47 +00:00
/**
List of all named arguments for this function
*/
2012-01-14 07:44:18 +00:00
wcstring_list_t named_arguments ;
2006-06-17 13:07:08 +00:00
/**
Flag for specifying that this function was automatically loaded
*/
2012-01-14 07:44:18 +00:00
bool is_autoload ;
2008-01-13 16:47:47 +00:00
/**
Set to non - zero if invoking this function shadows the variables
of the underlying function .
*/
2012-01-14 07:44:18 +00:00
bool shadows ;
} ;
2005-10-05 22:37:08 +00:00
/**
Table containing all functions
*/
2012-01-14 07:44:18 +00:00
typedef std : : map < wcstring , function_internal_info_t > function_map_t ;
static function_map_t loaded_functions ;
2011-12-27 03:18:46 +00:00
/* Lock for functions */
static pthread_mutex_t functions_lock ;
/* Helper macro for vomiting */
# define VOMIT_ON_FAILURE(a) do { if (0 != (a)) { int err = errno; fprintf(stderr, "%s failed on line %d in file %s: %d (%s)\n", #a, __LINE__, __FILE__, err, strerror(err)); abort(); }} while (0)
static int kLockDepth = 0 ;
static char kLockFunction [ 1024 ] ;
/**
Lock and unlock the functions hash
*/
static void lock_functions ( const char * func ) {
VOMIT_ON_FAILURE ( pthread_mutex_lock ( & functions_lock ) ) ;
if ( ! kLockDepth + + ) {
strcat ( kLockFunction , func ) ;
}
}
static void unlock_functions ( void ) {
if ( ! - - kLockDepth ) {
memset ( kLockFunction , 0 , sizeof kLockFunction ) ;
}
VOMIT_ON_FAILURE ( pthread_mutex_unlock ( & functions_lock ) ) ;
}
# define LOCK_FUNCTIONS() lock_functions(__FUNCTION__)
# define UNLOCK_FUNCTIONS() unlock_functions()
2006-06-17 13:07:08 +00:00
/**
Kludgy flag set by the load function in order to tell function_add
that the function being defined is autoloaded . There should be a
better way to do this . . .
*/
2006-02-08 09:20:05 +00:00
static int is_autoload = 0 ;
2006-02-08 17:37:18 +00:00
/**
Make sure that if the specified function is a dynamically loaded
function , it has been fully loaded .
*/
2006-02-08 09:20:05 +00:00
static int load ( const wchar_t * name )
{
2011-12-27 05:56:23 +00:00
ASSERT_IS_MAIN_THREAD ( ) ;
2006-02-08 09:20:05 +00:00
int was_autoload = is_autoload ;
int res ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) & & ! iter - > second . is_autoload ) {
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2006-02-08 09:20:05 +00:00
return 0 ;
2011-12-27 03:18:46 +00:00
}
UNLOCK_FUNCTIONS ( ) ;
is_autoload = 1 ;
2006-02-08 09:20:05 +00:00
res = parse_util_load ( name ,
2006-02-19 17:01:16 +00:00
L " fish_function_path " ,
2006-02-08 09:20:05 +00:00
& function_remove ,
1 ) ;
is_autoload = was_autoload ;
return res ;
}
2006-02-08 17:37:18 +00:00
/**
Insert a list of all dynamically loaded functions into the
specified list .
*/
2012-01-14 07:44:18 +00:00
static void autoload_names ( std : : set < wcstring > & names , int get_hidden )
2006-02-08 17:37:18 +00:00
{
2012-01-10 20:51:09 +00:00
size_t i ;
2011-12-27 03:18:46 +00:00
2012-01-14 10:42:17 +00:00
const env_var_t path_var_wstr = env_get_string ( L " fish_function_path " ) ;
if ( path_var_wstr . missing ( ) )
return ;
const wchar_t * path_var = path_var_wstr . c_str ( ) ;
2011-12-27 03:18:46 +00:00
2012-01-10 20:51:09 +00:00
wcstring_list_t path_list ;
2006-02-08 17:37:18 +00:00
2012-01-10 20:51:09 +00:00
tokenize_variable_array2 ( path_var , path_list ) ;
for ( i = 0 ; i < path_list . size ( ) ; i + + )
2006-02-08 17:37:18 +00:00
{
2012-01-10 20:51:09 +00:00
const wcstring & ndir_str = path_list . at ( i ) ;
const wchar_t * ndir = ( wchar_t * ) ndir_str . c_str ( ) ;
2006-02-08 17:37:18 +00:00
DIR * dir = wopendir ( ndir ) ;
2006-02-13 21:44:16 +00:00
if ( ! dir )
continue ;
2011-12-27 03:18:46 +00:00
wcstring name ;
while ( wreaddir ( dir , name ) )
2006-02-08 17:37:18 +00:00
{
2011-12-27 03:18:46 +00:00
const wchar_t * fn = name . c_str ( ) ;
2012-01-14 07:44:18 +00:00
const wchar_t * suffix ;
2006-02-08 17:37:18 +00:00
if ( ! get_hidden & & fn [ 0 ] = = L ' _ ' )
continue ;
2011-12-27 03:18:46 +00:00
2012-01-14 07:44:18 +00:00
suffix = wcsrchr ( fn , L ' . ' ) ;
2006-02-08 17:37:18 +00:00
if ( suffix & & ( wcscmp ( suffix , L " .fish " ) = = 0 ) )
{
2012-01-14 07:44:18 +00:00
wcstring name ( fn , suffix - fn ) ;
names . insert ( name ) ;
2006-02-08 17:37:18 +00:00
}
2011-12-27 03:18:46 +00:00
}
2006-02-08 17:37:18 +00:00
closedir ( dir ) ;
}
2006-02-08 09:20:05 +00:00
}
2005-09-20 13:26:39 +00:00
void function_init ( )
{
2011-12-27 03:18:46 +00:00
pthread_mutexattr_t a ;
VOMIT_ON_FAILURE ( pthread_mutexattr_init ( & a ) ) ;
VOMIT_ON_FAILURE ( pthread_mutexattr_settype ( & a , PTHREAD_MUTEX_RECURSIVE ) ) ;
VOMIT_ON_FAILURE ( pthread_mutex_init ( & functions_lock , & a ) ) ;
VOMIT_ON_FAILURE ( pthread_mutexattr_destroy ( & a ) ) ;
2005-09-20 13:26:39 +00:00
}
void function_destroy ( )
{
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
loaded_functions . clear ( ) ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2005-09-20 13:26:39 +00:00
}
2006-01-26 14:48:10 +00:00
2007-04-22 22:10:33 +00:00
void function_add ( function_data_t * data )
2005-09-20 13:26:39 +00:00
{
2005-10-05 22:37:08 +00:00
int i ;
2011-12-27 03:18:46 +00:00
2007-04-22 22:10:33 +00:00
CHECK ( data - > name , ) ;
CHECK ( data - > definition , ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2007-04-22 22:10:33 +00:00
function_remove ( data - > name ) ;
2012-01-14 07:44:18 +00:00
function_internal_info_t & info = loaded_functions [ data - > name ] ;
info . definition_offset = parse_util_lineno ( parser_get_buffer ( ) , current_block - > tok_pos ) - 1 ;
info . definition = data - > definition ;
2007-04-16 20:06:11 +00:00
2007-04-22 22:10:33 +00:00
if ( data - > named_arguments )
2007-04-16 20:06:11 +00:00
{
2007-04-22 22:10:33 +00:00
for ( i = 0 ; i < al_get_count ( data - > named_arguments ) ; i + + )
2007-04-16 20:06:11 +00:00
{
2012-01-14 07:44:18 +00:00
info . named_arguments . push_back ( ( wchar_t * ) al_get ( data - > named_arguments , i ) ) ;
2007-04-16 20:06:11 +00:00
}
}
2011-12-27 03:18:46 +00:00
2012-01-14 07:44:18 +00:00
if ( data - > description )
info . description = data - > description ;
info . definition_file = intern ( reader_current_filename ( ) ) ;
info . is_autoload = is_autoload ;
info . shadows = data - > shadows ;
2011-12-27 03:18:46 +00:00
2007-04-22 22:10:33 +00:00
for ( i = 0 ; i < al_get_count ( data - > events ) ; i + + )
2005-10-05 22:37:08 +00:00
{
2007-04-22 22:10:33 +00:00
event_add_handler ( ( event_t * ) al_get ( data - > events , i ) ) ;
2005-10-05 22:37:08 +00:00
}
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2005-09-20 13:26:39 +00:00
}
2011-12-27 05:56:23 +00:00
static int function_exists_internal ( const wchar_t * cmd , bool autoload )
2010-09-07 17:31:05 +00:00
{
2011-12-27 03:18:46 +00:00
int res ;
CHECK ( cmd , 0 ) ;
2010-09-07 17:31:05 +00:00
2011-12-27 03:18:46 +00:00
if ( parser_keywords_is_reserved ( cmd ) )
2010-09-07 17:31:05 +00:00
return 0 ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
if ( autoload ) load ( cmd ) ;
2012-01-14 07:44:18 +00:00
res = loaded_functions . find ( cmd ) ! = loaded_functions . end ( ) ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
return res ;
2010-09-07 17:31:05 +00:00
}
2005-09-20 13:26:39 +00:00
int function_exists ( const wchar_t * cmd )
{
2011-12-27 05:56:23 +00:00
return function_exists_internal ( cmd , true ) ;
2011-12-27 03:18:46 +00:00
}
2010-09-18 01:51:16 +00:00
2011-12-27 03:18:46 +00:00
int function_exists_no_autoload ( const wchar_t * cmd )
{
2011-12-27 05:56:23 +00:00
return function_exists_internal ( cmd , false ) ;
2005-09-20 13:26:39 +00:00
}
void function_remove ( const wchar_t * name )
{
2005-10-05 22:37:08 +00:00
event_t ev ;
2011-12-27 03:18:46 +00:00
2006-06-21 00:48:36 +00:00
CHECK ( name , ) ;
2006-07-12 14:22:42 +00:00
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
bool erased = ( loaded_functions . erase ( name ) > 0 ) ;
2011-12-27 03:18:46 +00:00
2012-01-14 07:44:18 +00:00
if ( ! erased ) {
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2005-09-20 13:26:39 +00:00
return ;
2011-12-27 03:18:46 +00:00
}
2005-09-20 13:26:39 +00:00
2006-02-05 13:10:35 +00:00
ev . type = EVENT_ANY ;
2011-12-27 03:18:46 +00:00
ev . function_name = name ;
2006-02-05 13:10:35 +00:00
event_remove ( & ev ) ;
2006-07-12 14:22:42 +00:00
/*
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 ) ;
}
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
2007-04-16 20:06:11 +00:00
const wchar_t * function_get_definition ( const wchar_t * name )
2005-09-20 13:26:39 +00:00
{
2012-01-14 07:44:18 +00:00
const wchar_t * result = NULL ;
2007-04-16 20:06:11 +00:00
CHECK ( name , 0 ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2007-04-16 20:06:11 +00:00
load ( name ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
result = iter - > second . definition . c_str ( ) ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
return result ;
2005-09-20 13:26:39 +00:00
}
2007-04-16 20:06:11 +00:00
2012-01-14 07:44:18 +00:00
wcstring_list_t function_get_named_arguments ( const wchar_t * name )
2007-04-16 20:06:11 +00:00
{
2012-01-14 07:44:18 +00:00
wcstring_list_t result ;
CHECK ( name , result ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2007-04-16 20:06:11 +00:00
load ( name ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
result = iter - > second . named_arguments ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
return result ;
2007-04-16 20:06:11 +00:00
}
2007-04-22 22:10:33 +00:00
int function_get_shadows ( const wchar_t * name )
{
2012-01-14 07:44:18 +00:00
bool result = false ;
2007-04-22 22:10:33 +00:00
CHECK ( name , 0 ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2007-04-22 22:10:33 +00:00
load ( name ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : const_iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
result = iter - > second . shadows ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
return result ;
2007-04-22 22:10:33 +00:00
}
2011-12-27 03:18:46 +00:00
2007-04-16 20:06:11 +00:00
const wchar_t * function_get_desc ( const wchar_t * name )
2005-09-20 13:26:39 +00:00
{
2012-01-14 07:44:18 +00:00
const wchar_t * result = NULL ;
2007-04-16 20:06:11 +00:00
CHECK ( name , 0 ) ;
load ( name ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : const_iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
result = iter - > second . description . c_str ( ) ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
/* Empty length string goes to NULL */
if ( result & & ! result [ 0 ] )
result = NULL ;
return result ? _ ( result ) : NULL ;
2005-09-20 13:26:39 +00:00
}
void function_set_desc ( const wchar_t * name , const wchar_t * desc )
{
2006-06-21 00:48:36 +00:00
CHECK ( name , ) ;
CHECK ( desc , ) ;
2011-12-27 03:18:46 +00:00
2006-02-08 09:20:05 +00:00
load ( name ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
iter - > second . description = desc ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2005-09-20 13:26:39 +00:00
}
2011-12-27 03:18:46 +00:00
int function_copy ( const wchar_t * name , const wchar_t * new_name )
{
2012-01-14 07:44:18 +00:00
int result = 0 ;
LOCK_FUNCTIONS ( ) ;
function_map_t : : const_iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) ) {
function_internal_info_t & new_info = loaded_functions [ new_name ] ;
new_info = iter - > second ;
2011-12-27 03:18:46 +00:00
// This new instance of the function shouldn't be tied to the def
// file of the original.
2012-01-14 07:44:18 +00:00
new_info . definition_file = 0 ;
new_info . is_autoload = 0 ;
result = 1 ;
}
UNLOCK_FUNCTIONS ( ) ;
return result ;
2005-09-20 13:26:39 +00:00
}
2012-01-14 07:44:18 +00:00
wcstring_list_t function_get_names ( int get_hidden )
2005-09-20 13:26:39 +00:00
{
2012-01-14 07:44:18 +00:00
std : : set < wcstring > names ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
autoload_names ( names , get_hidden ) ;
function_map_t : : const_iterator iter ;
for ( iter = loaded_functions . begin ( ) ; iter ! = loaded_functions . end ( ) ; iter + + ) {
const wcstring & name = iter - > first ;
/* Maybe skip hidden */
if ( ! get_hidden ) {
if ( name . size ( ) = = 0 | | name . at ( 0 ) = = L ' _ ' ) continue ;
}
names . insert ( name ) ;
}
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
return wcstring_list_t ( names . begin ( ) , names . end ( ) ) ;
2005-09-20 13:26:39 +00:00
}
2005-10-05 22:37:08 +00:00
2007-04-16 20:06:11 +00:00
const wchar_t * function_get_definition_file ( const wchar_t * name )
2006-01-26 14:48:10 +00:00
{
2012-01-14 07:44:18 +00:00
const wchar_t * result = NULL ;
2006-06-08 00:01:45 +00:00
2007-04-16 20:06:11 +00:00
CHECK ( name , 0 ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : const_iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
result = iter - > second . definition_file ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
return result ;
2006-01-26 14:48:10 +00:00
}
2007-04-16 20:06:11 +00:00
int function_get_definition_offset ( const wchar_t * name )
2006-01-26 14:48:10 +00:00
{
2012-01-14 07:44:18 +00:00
int result = - 1 ;
2006-06-08 00:01:45 +00:00
2007-04-16 20:06:11 +00:00
CHECK ( name , - 1 ) ;
2011-12-27 03:18:46 +00:00
LOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
function_map_t : : const_iterator iter = loaded_functions . find ( name ) ;
if ( iter ! = loaded_functions . end ( ) )
result = iter - > second . definition_offset ;
2011-12-27 03:18:46 +00:00
UNLOCK_FUNCTIONS ( ) ;
2012-01-14 07:44:18 +00:00
return result ;
2006-01-26 14:48:10 +00:00
}