diff --git a/builtin.c b/builtin.c index d9990411c..f02dce055 100644 --- a/builtin.c +++ b/builtin.c @@ -1252,6 +1252,7 @@ static int builtin_functions( wchar_t **argv ) int show_hidden=0; int res = STATUS_BUILTIN_OK; int query = 0; + int copy = 0; woptind=0; @@ -1282,6 +1283,10 @@ static int builtin_functions( wchar_t **argv ) L"query", no_argument, 0, 'q' } , + { + L"copy", no_argument, 0, 'c' + } + , { 0, 0, 0, 0 } @@ -1294,7 +1299,7 @@ static int builtin_functions( wchar_t **argv ) int opt = wgetopt_long( argc, argv, - L"ed:nahq", + L"ed:nahqc", long_options, &opt_index ); if( opt == -1 ) @@ -1305,10 +1310,10 @@ static int builtin_functions( wchar_t **argv ) case 0: if(long_options[opt_index].flag != 0) break; - sb_printf( sb_err, - BUILTIN_ERR_UNKNOWN, - argv[0], - long_options[opt_index].name ); + sb_printf( sb_err, + BUILTIN_ERR_UNKNOWN, + argv[0], + long_options[opt_index].name ); builtin_print_help( argv[0], sb_err ); @@ -1338,6 +1343,10 @@ static int builtin_functions( wchar_t **argv ) query = 1; break; + case 'c': + copy = 1; + break; + case '?': builtin_unknown_option( argv[0], argv[woptind-1] ); return STATUS_BUILTIN_ERROR; @@ -1347,9 +1356,9 @@ static int builtin_functions( wchar_t **argv ) } /* - Erase, desc, query and list are mutually exclusive + Erase, desc, query, copy and list are mutually exclusive */ - if( (erase + (!!desc) + list + query) > 1 ) + if( (erase + (!!desc) + list + query + copy) > 1 ) { sb_printf( sb_err, _( L"%ls: Invalid combination of options\n" ), @@ -1434,6 +1443,61 @@ static int builtin_functions( wchar_t **argv ) al_destroy( &names ); return STATUS_BUILTIN_OK; } + else if( copy ) + { + wchar_t *current_func; + wchar_t *new_func; + + if( argc-woptind != 2 ) + { + sb_printf( sb_err, + _( L"%ls: Expected exactly two names (current function name, and new function name)\n" ), + argv[0] ); + builtin_print_help ( argv[0], sb_err ); + + return STATUS_BUILTIN_ERROR; + } + current_func = argv[woptind]; + new_func = argv[woptind+1]; + + if( !function_exists( current_func ) ) + { + sb_printf( sb_err, + _( L"%ls: Function '%ls' does not exist\n" ), + argv[0], + current_func ); + builtin_print_help( argv[0], sb_err ); + + return STATUS_BUILTIN_ERROR; + } + + if( (wcsfuncname( new_func ) != 0) || parser_keywords_is_reserved( new_func ) ) + { + sb_printf( sb_err, + _( L"%ls: Illegal function name '%ls'\n"), + argv[0], + new_func ); + builtin_print_help( argv[0], sb_err ); + return STATUS_BUILTIN_ERROR; + } + + // keep things simple: don't allow existing names to be copy targets. + if( function_exists( new_func ) ) + { + sb_printf( sb_err, + _( L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n" ), + argv[0], + new_func, + current_func ); + builtin_print_help( argv[0], sb_err ); + + return STATUS_BUILTIN_ERROR; + } + + if( function_copy( current_func, new_func ) ) + return STATUS_BUILTIN_OK; + return STATUS_BUILTIN_ERROR; + } for( i=woptind; i-a or --all list all functions, even those whose name start with an underscore. +- -c OLDNAME NEWNAME or --copy OLDNAME NEWNAME creates a new function named NEWNAME, using the definition of the OLDNAME function. - -d DESCRIPTION or --description=DESCRIPTION change the description of this function - -e or --erase causes the specified functions to be erased. - -h or --help display a help message and exit @@ -23,5 +24,8 @@ Automatically loaded functions can not be removed using functions -e. Either remove the definition file or change the $fish_function_path variable to remove autoloaded functions. +Function copies, created with -c, will not have any event/signal/on-exit +notifications that the original may have had. + The exit status of the functions builtin is the number functions specified in the argument list that do not exist. diff --git a/function.c b/function.c index e88da9b6a..576465a5d 100644 --- a/function.c +++ b/function.c @@ -218,6 +218,43 @@ void function_add( function_data_t *data ) } +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; inamed_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 ) { diff --git a/function.h b/function.h index 9e5643fc4..15c35afe7 100644 --- a/function.h +++ b/function.h @@ -131,4 +131,10 @@ array_list_t *function_get_named_arguments( const wchar_t *name ); */ int function_get_shadows( const wchar_t *name ); +/** + Creates a new function using the same definition as the specified function. + Returns non-zero if copy is successful. +*/ +int function_copy( const wchar_t *name, const wchar_t *new_name ); + #endif