2005-09-20 23:26:39 +10:00
/** \file function.c
Functions for storing and retrieving function information .
*/
2006-08-11 11:18:35 +10:00
# include "config.h"
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <unistd.h>
# include <termios.h>
# include <signal.h>
2006-01-21 00:27:21 +10:00
# include "wutil.h"
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "function.h"
# include "proc.h"
# include "parser.h"
# include "common.h"
# include "intern.h"
2005-10-06 08:37:08 +10:00
# include "event.h"
2006-01-27 00:48:10 +10:00
# include "reader.h"
2006-02-05 23:10:35 +10:00
# include "parse_util.h"
2006-02-08 19:20:05 +10:00
# include "env.h"
2006-02-09 01:29:09 +10:00
# include "expand.h"
2005-09-20 23:26:39 +10:00
/**
Struct describing a function
*/
typedef struct
{
/** Function definition */
wchar_t * cmd ;
/** Function description */
wchar_t * desc ;
2006-06-17 23:07:08 +10:00
/**
File where this function was defined
*/
2006-01-27 00:48:10 +10:00
const wchar_t * definition_file ;
2006-06-17 23:07:08 +10:00
/**
Line where definition started
*/
2006-01-27 00:48:10 +10:00
int definition_offset ;
2006-06-17 23:07:08 +10:00
/**
Flag for specifying that this function was automatically loaded
*/
2006-02-08 19:20:05 +10:00
int is_autoload ;
2005-09-20 23:26:39 +10:00
}
2005-10-06 08:37:08 +10:00
function_data_t ;
/**
Table containing all functions
*/
static hash_table_t function ;
2006-06-17 23:07:08 +10: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 19:20:05 +10:00
static int is_autoload = 0 ;
2006-02-09 03:37:18 +10:00
/**
Make sure that if the specified function is a dynamically loaded
function , it has been fully loaded .
*/
2006-02-08 19:20:05 +10:00
static int load ( const wchar_t * name )
{
int was_autoload = is_autoload ;
int res ;
function_data_t * data ;
data = ( function_data_t * ) hash_get ( & function , name ) ;
if ( data & & ! data - > is_autoload )
return 0 ;
is_autoload = 1 ;
res = parse_util_load ( name ,
2006-02-20 03:01:16 +10:00
L " fish_function_path " ,
2006-02-08 19:20:05 +10:00
& function_remove ,
1 ) ;
is_autoload = was_autoload ;
return res ;
}
2006-02-09 03:37:18 +10:00
/**
Insert a list of all dynamically loaded functions into the
specified list .
*/
static void autoload_names ( array_list_t * out , int get_hidden )
{
int i ;
array_list_t path_list ;
const wchar_t * path_var = env_get ( L " fish_function_path " ) ;
if ( ! path_var )
return ;
al_init ( & path_list ) ;
2006-05-29 21:13:42 +10:00
tokenize_variable_array ( path_var , & path_list ) ;
2006-02-09 03:37:18 +10:00
for ( i = 0 ; i < al_get_count ( & path_list ) ; i + + )
{
wchar_t * ndir = ( wchar_t * ) al_get ( & path_list , i ) ;
DIR * dir = wopendir ( ndir ) ;
2006-02-14 07:44:16 +10:00
if ( ! dir )
continue ;
2006-02-09 03:37:18 +10:00
struct wdirent * next ;
while ( ( next = wreaddir ( dir ) ) ! = 0 )
{
wchar_t * fn = next - > d_name ;
wchar_t * suffix ;
if ( ! get_hidden & & fn [ 0 ] = = L ' _ ' )
continue ;
suffix = wcsrchr ( fn , L ' . ' ) ;
if ( suffix & & ( wcscmp ( suffix , L " .fish " ) = = 0 ) )
{
2006-02-17 20:13:39 +10:00
const wchar_t * dup ;
2006-02-09 03:37:18 +10:00
* suffix = 0 ;
2006-02-14 07:44:16 +10:00
dup = intern ( fn ) ;
2006-02-09 03:37:18 +10:00
if ( ! dup )
2006-07-03 20:39:57 +10:00
DIE_MEM ( ) ;
2006-02-09 03:37:18 +10:00
al_push ( out , dup ) ;
}
}
closedir ( dir ) ;
}
2006-06-13 07:47:42 +10:00
al_foreach ( & path_list , & free ) ;
2006-02-09 03:37:18 +10:00
al_destroy ( & path_list ) ;
2006-02-08 19:20:05 +10:00
}
2005-09-20 23:26:39 +10:00
/**
Free all contents of an entry to the function hash table
*/
2006-06-13 07:47:42 +10:00
static void clear_function_entry ( void * key ,
void * data )
2005-09-20 23:26:39 +10:00
{
function_data_t * d = ( function_data_t * ) data ;
free ( ( void * ) d - > cmd ) ;
free ( ( void * ) d - > desc ) ;
free ( ( void * ) d ) ;
}
void function_init ( )
{
hash_init ( & function ,
& hash_wcs_func ,
& hash_wcs_cmp ) ;
}
void function_destroy ( )
{
hash_foreach ( & function , & clear_function_entry ) ;
hash_destroy ( & function ) ;
}
2006-01-27 00:48:10 +10:00
2005-09-20 23:26:39 +10:00
void function_add ( const wchar_t * name ,
const wchar_t * val ,
2005-09-21 09:42:00 +10:00
const wchar_t * desc ,
2006-10-26 06:28:36 +10:00
array_list_t * events )
2005-09-20 23:26:39 +10:00
{
2005-10-06 08:37:08 +10:00
int i ;
2006-01-14 11:58:01 +10:00
wchar_t * cmd_end ;
2006-01-31 02:51:50 +10:00
function_data_t * d ;
2005-10-06 08:37:08 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( name , ) ;
CHECK ( val , ) ;
2006-06-08 10:01:45 +10:00
2006-02-05 23:10:35 +10:00
function_remove ( name ) ;
2005-09-20 23:26:39 +10:00
2006-01-31 02:51:50 +10:00
d = malloc ( sizeof ( function_data_t ) ) ;
2006-06-08 09:32:06 +10:00
d - > definition_offset = parse_util_lineno ( parser_get_buffer ( ) , current_block - > tok_pos ) - 1 ;
2005-09-20 23:26:39 +10:00
d - > cmd = wcsdup ( val ) ;
2006-02-05 23:10:35 +10:00
2006-01-14 11:58:01 +10:00
cmd_end = d - > cmd + wcslen ( d - > cmd ) - 1 ;
2005-09-20 23:26:39 +10:00
d - > desc = desc ? wcsdup ( desc ) : 0 ;
2006-02-05 23:10:35 +10:00
d - > definition_file = intern ( reader_current_filename ( ) ) ;
2006-02-08 19:20:05 +10:00
d - > is_autoload = is_autoload ;
2005-09-20 23:26:39 +10:00
hash_put ( & function , intern ( name ) , d ) ;
2006-01-27 00:48:10 +10:00
2005-10-06 08:37:08 +10:00
for ( i = 0 ; i < al_get_count ( events ) ; i + + )
{
event_add_handler ( ( event_t * ) al_get ( events , i ) ) ;
}
2005-09-20 23:26:39 +10:00
}
int function_exists ( const wchar_t * cmd )
{
2006-06-08 10:01:45 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( cmd , 0 ) ;
2006-02-08 19:20:05 +10:00
if ( parser_is_reserved ( cmd ) )
return 0 ;
load ( cmd ) ;
2005-09-20 23:26:39 +10:00
return ( hash_get ( & function , cmd ) ! = 0 ) ;
}
void function_remove ( const wchar_t * name )
{
void * key ;
2006-06-13 07:47:42 +10:00
void * dv ;
2005-09-20 23:26:39 +10:00
function_data_t * d ;
2005-10-06 08:37:08 +10:00
event_t ev ;
2006-06-08 10:01:45 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( name , ) ;
2006-07-13 00:22:42 +10:00
2005-09-20 23:26:39 +10:00
hash_remove ( & function ,
name ,
2006-06-13 07:47:42 +10:00
& key ,
2006-03-26 21:23:39 +10:00
& dv ) ;
2005-09-20 23:26:39 +10:00
2006-03-26 21:23:39 +10:00
d = ( function_data_t * ) dv ;
2006-02-05 23:10:35 +10:00
if ( ! key )
2005-09-20 23:26:39 +10:00
return ;
2006-02-05 23:10:35 +10:00
ev . type = EVENT_ANY ;
ev . function_name = name ;
event_remove ( & ev ) ;
2005-09-20 23:26:39 +10:00
clear_function_entry ( key , d ) ;
2006-07-13 00:22:42 +10: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 ) ;
}
2005-09-20 23:26:39 +10:00
}
const wchar_t * function_get_definition ( const wchar_t * argv )
{
2006-02-08 19:20:05 +10:00
function_data_t * data ;
2006-06-08 10:01:45 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( argv , 0 ) ;
2006-02-08 19:20:05 +10:00
load ( argv ) ;
data = ( function_data_t * ) hash_get ( & function , argv ) ;
2005-09-20 23:26:39 +10:00
if ( data = = 0 )
return 0 ;
return data - > cmd ;
}
const wchar_t * function_get_desc ( const wchar_t * argv )
{
2006-02-08 19:20:05 +10:00
function_data_t * data ;
2006-06-08 10:01:45 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( argv , 0 ) ;
2006-02-08 19:20:05 +10:00
load ( argv ) ;
data = ( function_data_t * ) hash_get ( & function , argv ) ;
2005-09-20 23:26:39 +10:00
if ( data = = 0 )
return 0 ;
2006-03-02 02:53:47 +10:00
return _ ( data - > desc ) ;
2005-09-20 23:26:39 +10:00
}
void function_set_desc ( const wchar_t * name , const wchar_t * desc )
{
2006-02-08 19:20:05 +10:00
function_data_t * data ;
2006-06-21 10:48:36 +10:00
CHECK ( name , ) ;
CHECK ( desc , ) ;
2006-06-08 10:01:45 +10:00
2006-02-08 19:20:05 +10:00
load ( name ) ;
data = ( function_data_t * ) hash_get ( & function , name ) ;
2005-09-20 23:26:39 +10:00
if ( data = = 0 )
return ;
data - > desc = wcsdup ( desc ) ;
}
2006-06-20 10:50:10 +10:00
/**
Search arraylist of strings for specified string
*/
2006-05-14 19:46:35 +10:00
static int al_contains_str ( array_list_t * list , const wchar_t * str )
{
int i ;
for ( i = 0 ; i < al_get_count ( list ) ; i + + )
{
if ( wcscmp ( al_get ( list , i ) , str ) = = 0 )
{
return 1 ;
}
}
return 0 ;
}
2005-09-20 23:26:39 +10:00
/**
Helper function for removing hidden functions
*/
2006-06-13 07:47:42 +10:00
static void get_names_internal ( void * key ,
void * val ,
2005-09-20 23:26:39 +10:00
void * aux )
{
wchar_t * name = ( wchar_t * ) key ;
2006-10-26 06:28:36 +10:00
if ( name [ 0 ] ! = L ' _ ' & & ! al_contains_str ( ( array_list_t * ) aux , name ) )
2006-05-14 19:46:35 +10:00
{
al_push ( ( array_list_t * ) aux , name ) ;
}
}
/**
Helper function for removing hidden functions
*/
2006-06-13 07:47:42 +10:00
static void get_names_internal_all ( void * key ,
void * val ,
void * aux )
2006-05-14 19:46:35 +10:00
{
wchar_t * name = ( wchar_t * ) key ;
if ( ! al_contains_str ( ( array_list_t * ) aux , name ) )
{
2005-09-20 23:26:39 +10:00
al_push ( ( array_list_t * ) aux , name ) ;
2006-05-14 19:46:35 +10:00
}
2005-09-20 23:26:39 +10:00
}
void function_get_names ( array_list_t * list , int get_hidden )
{
2006-06-21 10:48:36 +10:00
CHECK ( list , ) ;
2006-02-09 03:37:18 +10:00
autoload_names ( list , get_hidden ) ;
2006-02-08 19:20:05 +10:00
2005-09-20 23:26:39 +10:00
if ( get_hidden )
2006-05-14 19:46:35 +10:00
{
hash_foreach2 ( & function , & get_names_internal_all , list ) ;
}
2005-09-20 23:26:39 +10:00
else
2006-05-14 19:46:35 +10:00
{
2005-09-20 23:26:39 +10:00
hash_foreach2 ( & function , & get_names_internal , list ) ;
2006-05-14 19:46:35 +10:00
}
2005-09-20 23:26:39 +10:00
}
2005-10-06 08:37:08 +10:00
2006-01-27 00:48:10 +10:00
const wchar_t * function_get_definition_file ( const wchar_t * argv )
{
2006-02-08 19:20:05 +10:00
function_data_t * data ;
2006-06-08 10:01:45 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( argv , 0 ) ;
2006-02-08 19:20:05 +10:00
data = ( function_data_t * ) hash_get ( & function , argv ) ;
2006-01-27 00:48:10 +10:00
if ( data = = 0 )
return 0 ;
return data - > definition_file ;
}
int function_get_definition_offset ( const wchar_t * argv )
{
2006-02-08 19:20:05 +10:00
function_data_t * data ;
2006-06-08 10:01:45 +10:00
2006-06-21 10:48:36 +10:00
CHECK ( argv , - 1 ) ;
2006-02-08 19:20:05 +10:00
data = ( function_data_t * ) hash_get ( & function , argv ) ;
2006-01-27 00:48:10 +10:00
if ( data = = 0 )
return - 1 ;
return data - > definition_offset ;
}