diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2011-12-26 19:11:54 -0800 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2011-12-26 19:11:54 -0800 |
commit | 3f16ace6784caab54fb054836ee93902e9701913 (patch) | |
tree | 6ae6170f86bd45ce7fd0dae4a4242bb8dc67c505 /function.cpp | |
parent | 834ea94eb97d37c65fcbf2fcc3b69303f6fb7e24 (diff) |
Initial C++ conversion
Diffstat (limited to 'function.cpp')
-rw-r--r-- | function.cpp | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/function.cpp b/function.cpp new file mode 100644 index 00000000..576465a5 --- /dev/null +++ b/function.cpp @@ -0,0 +1,467 @@ +/** \file function.c + + 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. +*/ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <wchar.h> +#include <unistd.h> +#include <termios.h> +#include <signal.h> + +#include "wutil.h" +#include "fallback.h" +#include "util.h" + +#include "function.h" +#include "proc.h" +#include "parser.h" +#include "common.h" +#include "intern.h" +#include "event.h" +#include "reader.h" +#include "parse_util.h" +#include "parser_keywords.h" +#include "env.h" +#include "expand.h" +#include "halloc.h" +#include "halloc_util.h" + + +/** + Struct describing a function +*/ +typedef struct +{ + /** Function definition */ + wchar_t *definition; + /** Function description */ + wchar_t *description; + /** + File where this function was defined + */ + const wchar_t *definition_file; + /** + Line where definition started + */ + int definition_offset; + + /** + List of all named arguments for this function + */ + array_list_t *named_arguments; + + + /** + Flag for specifying that this function was automatically loaded + */ + int is_autoload; + + /** + Set to non-zero if invoking this function shadows the variables + of the underlying function. + */ + int shadows; +} + function_internal_data_t; + +/** + Table containing all functions +*/ +static hash_table_t function; + +/** + 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... +*/ +static int is_autoload = 0; + +/** + Make sure that if the specified function is a dynamically loaded + function, it has been fully loaded. +*/ +static int load( const wchar_t *name ) +{ + int was_autoload = is_autoload; + int res; + function_internal_data_t *data; + data = (function_internal_data_t *)hash_get( &function, name ); + if( data && !data->is_autoload ) + return 0; + + is_autoload = 1; + res = parse_util_load( name, + L"fish_function_path", + &function_remove, + 1 ); + is_autoload = was_autoload; + return res; +} + +/** + 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 ); + + tokenize_variable_array( path_var, &path_list ); + for( i=0; i<al_get_count( &path_list ); i++ ) + { + wchar_t *ndir = (wchar_t *)al_get( &path_list, i ); + DIR *dir = wopendir( ndir ); + if( !dir ) + continue; + + 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 ) ) + { + const wchar_t *dup; + *suffix = 0; + dup = intern( fn ); + if( !dup ) + DIE_MEM(); + al_push( out, dup ); + } + } + closedir(dir); + } + al_foreach( &path_list, &free ); + al_destroy( &path_list ); +} + +void function_init() +{ + hash_init( &function, + &hash_wcs_func, + &hash_wcs_cmp ); +} + +/** + Clear specified value, but not key + */ +static void clear_entry( void *key, void *value ) +{ + halloc_free( value ); +} + +void function_destroy() +{ + hash_foreach( &function, &clear_entry ); + hash_destroy( &function ); +} + + +void function_add( function_data_t *data ) +{ + int i; + wchar_t *cmd_end; + function_internal_data_t *d; + + CHECK( data->name, ); + CHECK( data->definition, ); + + function_remove( data->name ); + + d = halloc( 0, sizeof( function_internal_data_t ) ); + d->definition_offset = parse_util_lineno( parser_get_buffer(), current_block->tok_pos )-1; + d->definition = halloc_wcsdup( d, data->definition ); + + if( data->named_arguments ) + { + d->named_arguments = al_halloc( d ); + + for( i=0; i<al_get_count( data->named_arguments ); i++ ) + { + al_push( d->named_arguments, halloc_wcsdup( d, (wchar_t *)al_get( data->named_arguments, i ) ) ); + } + } + + cmd_end = d->definition + wcslen(d->definition)-1; + + d->description = data->description?halloc_wcsdup( d, data->description ):0; + d->definition_file = intern(reader_current_filename()); + d->is_autoload = is_autoload; + d->shadows = data->shadows; + + hash_put( &function, intern(data->name), d ); + + for( i=0; i<al_get_count( data->events ); i++ ) + { + event_add_handler( (event_t *)al_get( data->events, i ) ); + } + +} + +int function_copy( const wchar_t *name, const wchar_t *new_name ) +{ + int i; + function_internal_data_t *d, *orig_d; + + CHECK( name, 0 ); + CHECK( new_name, 0 ); + + orig_d = (function_internal_data_t *)hash_get(&function, name); + if( !orig_d ) + return 0; + + d = halloc(0, sizeof( function_internal_data_t ) ); + d->definition_offset = orig_d->definition_offset; + d->definition = halloc_wcsdup( d, orig_d->definition ); + if( orig_d->named_arguments ) + { + d->named_arguments = al_halloc( d ); + for( i=0; i<al_get_count( orig_d->named_arguments ); i++ ) + { + al_push( d->named_arguments, halloc_wcsdup( d, (wchar_t *)al_get( orig_d->named_arguments, i ) ) ); + } + d->description = orig_d->description?halloc_wcsdup(d, orig_d->description):0; + d->shadows = orig_d->shadows; + + // This new instance of the function shouldn't be tied to the def + // file of the original. + d->definition_file = 0; + d->is_autoload = 0; + } + + hash_put( &function, intern(new_name), d ); + + return 1; +} + + +int function_exists( const wchar_t *cmd ) +{ + + CHECK( cmd, 0 ); + + if( parser_keywords_is_reserved(cmd) ) + return 0; + + load( cmd ); + return (hash_get(&function, cmd) != 0 ); +} + +void function_remove( const wchar_t *name ) +{ + void *key; + void *dv; + function_internal_data_t *d; + event_t ev; + + CHECK( name, ); + + hash_remove( &function, + name, + &key, + &dv ); + + d=(function_internal_data_t *)dv; + + if( !key ) + return; + + ev.type=EVENT_ANY; + ev.function_name=name; + event_remove( &ev ); + + halloc_free( d ); + + /* + 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 ); + } +} + +const wchar_t *function_get_definition( const wchar_t *name ) +{ + function_internal_data_t *data; + + CHECK( name, 0 ); + + load( name ); + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return 0; + return data->definition; +} + +array_list_t *function_get_named_arguments( const wchar_t *name ) +{ + function_internal_data_t *data; + + CHECK( name, 0 ); + + load( name ); + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return 0; + return data->named_arguments; +} + +int function_get_shadows( const wchar_t *name ) +{ + function_internal_data_t *data; + + CHECK( name, 0 ); + + load( name ); + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return 0; + return data->shadows; +} + + +const wchar_t *function_get_desc( const wchar_t *name ) +{ + function_internal_data_t *data; + + CHECK( name, 0 ); + + load( name ); + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return 0; + + return _(data->description); +} + +void function_set_desc( const wchar_t *name, const wchar_t *desc ) +{ + function_internal_data_t *data; + + CHECK( name, ); + CHECK( desc, ); + + load( name ); + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return; + + data->description = halloc_wcsdup( data, desc ); +} + +/** + Search arraylist of strings for specified string +*/ +static int al_contains_str( array_list_t *list, const wchar_t * str ) +{ + int i; + + CHECK( list, 0 ); + CHECK( str, 0 ); + + for( i=0; i<al_get_count( list ); i++ ) + { + if( wcscmp( al_get( list, i ), str) == 0 ) + { + return 1; + } + } + return 0; +} + +/** + Helper function for removing hidden functions +*/ +static void get_names_internal( void *key, + void *val, + void *aux ) +{ + wchar_t *name = (wchar_t *)key; + if( name[0] != L'_' && !al_contains_str( (array_list_t *)aux, name ) ) + { + al_push( (array_list_t *)aux, name ); + } +} + +/** + Helper function for removing hidden functions +*/ +static void get_names_internal_all( void *key, + void *val, + void *aux ) +{ + wchar_t *name = (wchar_t *)key; + + if( !al_contains_str( (array_list_t *)aux, name ) ) + { + al_push( (array_list_t *)aux, name ); + } +} + +void function_get_names( array_list_t *list, int get_hidden ) +{ + CHECK( list, ); + + autoload_names( list, get_hidden ); + + if( get_hidden ) + { + hash_foreach2( &function, &get_names_internal_all, list ); + } + else + { + hash_foreach2( &function, &get_names_internal, list ); + } + +} + +const wchar_t *function_get_definition_file( const wchar_t *name ) +{ + function_internal_data_t *data; + + CHECK( name, 0 ); + + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return 0; + + return data->definition_file; +} + + +int function_get_definition_offset( const wchar_t *name ) +{ + function_internal_data_t *data; + + CHECK( name, -1 ); + + data = (function_internal_data_t *)hash_get( &function, name ); + if( data == 0 ) + return -1; + + return data->definition_offset; +} + |