diff --git a/builtin.c b/builtin.c index 2f2005bd6..6952dce7c 100644 --- a/builtin.c +++ b/builtin.c @@ -678,10 +678,10 @@ static int builtin_generic( wchar_t **argv ) } /** - Output a definition of the specified function to the sb_out + Output a definition of the specified function to the specified stringbuffer. Used by the functions builtin. */ -static void functions_def( wchar_t *name ) +static void functions_def( wchar_t *name, string_buffer_t *out ) { const wchar_t *desc = function_get_desc( name ); const wchar_t *def = function_get_definition(name); @@ -697,7 +697,7 @@ static void functions_def( wchar_t *name ) al_init( &ev ); event_get( &search, &ev ); - sb_append2( sb_out, + sb_append2( out, L"function ", name, (void *)0); @@ -706,7 +706,7 @@ static void functions_def( wchar_t *name ) { wchar_t *esc_desc = escape( desc, 1 ); - sb_append2( sb_out, L" --description ", esc_desc, (void *)0 ); + sb_append2( out, L" --description ", esc_desc, (void *)0 ); free( esc_desc ); } @@ -717,22 +717,22 @@ static void functions_def( wchar_t *name ) { case EVENT_SIGNAL: { - sb_printf( sb_out, L" --on-signal %ls", sig2wcs( next->param1.signal ) ); + sb_printf( out, L" --on-signal %ls", sig2wcs( next->param1.signal ) ); break; } case EVENT_VARIABLE: { - sb_printf( sb_out, L" --on-variable %ls", next->param1.variable ); + sb_printf( out, L" --on-variable %ls", next->param1.variable ); break; } case EVENT_EXIT: { if( next->param1.pid > 0 ) - sb_printf( sb_out, L" --on-process-exit %d", next->param1.pid ); + sb_printf( out, L" --on-process-exit %d", next->param1.pid ); else - sb_printf( sb_out, L" --on-job-exit %d", -next->param1.pid ); + sb_printf( out, L" --on-job-exit %d", -next->param1.pid ); break; } @@ -740,7 +740,7 @@ static void functions_def( wchar_t *name ) { job_t *j = job_get( next->param1.job_id ); if( j ) - sb_printf( sb_out, L" --on-job-exit %d", j->pgid ); + sb_printf( out, L" --on-job-exit %d", j->pgid ); break; } @@ -750,7 +750,7 @@ static void functions_def( wchar_t *name ) al_destroy( &ev ); - sb_append2( sb_out, + sb_append2( out, L"\n\t", def, L"\nend\n\n", @@ -973,7 +973,7 @@ static int builtin_functions( wchar_t **argv ) for( i=0; iparam1.function_name=halloc_wcsdup( current_block, argv[woptind]); - current_block->param2.function_description=desc?halloc_wcsdup( current_block, desc):0; - current_block->param3.function_is_binding = is_binding; - current_block->param4.function_events = events; + function_data_t * d = halloc( current_block, sizeof( function_data_t )); + + d->name=halloc_wcsdup( current_block, argv[woptind]); + d->description=desc?halloc_wcsdup( current_block, desc):0; + d->is_binding = is_binding; + d->events = events; + d->do_save = do_save; for( i=0; ifunction_name = current_block->param1.function_name; + e->function_name = d->name; } + + current_block->data = d; + } current_block->tok_pos = parser_get_pos(); @@ -2494,6 +2521,201 @@ static int builtin_begin( wchar_t **argv ) return proc_get_last_status(); } +static void builtin_end_add_function_def( function_data_t *d ) +{ + /** + Copy the text from the beginning of the function + until the end command and use as the new definition + for the specified function + */ + void *context = halloc( 0, 0 ); + + wchar_t *def = halloc_wcsndup( context, + parser_get_buffer()+current_block->tok_pos, + parser_get_job_pos()-current_block->tok_pos ); + + function_add( d->name, + def, + d->description, + d->events, + d->is_binding ); + + if( d->do_save ) + { + wchar_t *func_path; + array_list_t func_path_list; + + func_path = env_get( L"fish_function_path" ); + + if( !func_path ) + { + sb_printf( sb_err, + _(L"%ls: Can't save the function '%ls' because the function path is undefined. Define the variable $fish_function_path to a suitable directory and retry"), + L"function", + d->name ); + + } + else + { + wchar_t *target_dir=0; + int i; + struct stat buf; + + al_init( &func_path_list ); + + tokenize_variable_array( func_path, &func_path_list ); + + for( i=0; i= 0; j-- ) + { + wchar_t *cre = (wchar_t *)al_get( subdirs, j); + if( wmkdir( cre, 0700 ) ) + { + create_err = 1; + break; + } + + } + + if( !create_err ) + target_dir = dir; + + + break; + } + else + { + break; + } + + } + else + { + if( errno != ENOENT ) + { + break; + } + } + + if( wcslen( dir_copy ) <= 1 ) + break; + + } + + if( target_dir ) + break; + } + + } + + + } + + //debug( 0, L"target directory is %ls", target_dir ); + + if( target_dir ) + { + int err=0; + string_buffer_t filename; + FILE *out; + wchar_t *efunc = L"unknown"; + + + sb_init( &filename ); + + sb_printf( &filename, + L"%ls/%ls.fish", + target_dir, + d->name ); + + if( (out = wfopen( (wchar_t *)filename.buff, "w" ))) + { + string_buffer_t *tmp = sb_halloc( context ); + functions_def( d->name, tmp ); + + fwprintf( out, L"%ls", (wchar_t *)tmp->buff ); + if( fclose( out ) ) + { + efunc = L"fclose"; + err = 1; + } + } + else + { + efunc = L"wfopen"; + err=1; + } + + sb_destroy( &filename ); + + if( err ) + { + sb_printf( sb_err, + _(L"%ls: Unexpected error while saving function %ls\n"), + L"function", + d->name ); + builtin_wperror( efunc ); + + } + + } + + + al_foreach( &func_path_list, &free ); + al_destroy( &func_path_list ); + } + + } + + halloc_free( context ); + +} + + /** Builtin for ending a block of code, such as a for-loop or an if statement. @@ -2605,21 +2827,21 @@ static int builtin_end( wchar_t **argv ) case FUNCTION_DEF: { - /** - Copy the text from the beginning of the function - until the end command and use as the new definition - for the specified function - */ - wchar_t *def = wcsndup( parser_get_buffer()+current_block->tok_pos, - parser_get_job_pos()-current_block->tok_pos ); - function_add( current_block->param1.function_name, - def, - current_block->param2.function_description, - current_block->param4.function_events, - current_block->param3.function_is_binding ); + function_data_t *d = (function_data_t *)current_block->data; + + if( d ) + { + builtin_end_add_function_def( d ); + } + else + { + debug(0, + _(L"%ls: Missing function definition information. This is a fish bug. If you can reproduce it, please file a bug report to %s."), + argv[0], + PACKAGE_BUGREPORT); + } - free(def); } break; diff --git a/exec.c b/exec.c index d500aecc6..842722d1f 100644 --- a/exec.c +++ b/exec.c @@ -869,18 +869,17 @@ void exec( job_t *j ) { case INTERNAL_FUNCTION: { - wchar_t * def = halloc_register( j, wcsdup( function_get_definition( p->argv[0] ))); if( def == 0 ) { debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] ); break; } - + parser_push_block( FUNCTION_CALL ); current_block->param2.function_call_process = p; - current_block->param1.function_name = halloc_register( current_block, wcsdup( p->argv[0] ) ); + current_block->param1.function_call_name = halloc_register( current_block, wcsdup( p->argv[0] ) ); parse_util_set_argv( p->argv+1 ); diff --git a/expand.c b/expand.c index e31532e80..87a6b2064 100644 --- a/expand.c +++ b/expand.c @@ -1307,22 +1307,21 @@ static int expand_cmdsubst( wchar_t *in, array_list_t *out ) } al_foreach( sub_res, &free ); sub_res = sub_res2; - } - + } } tail_expand = al_halloc( context ); /* Recursively call ourselves to expand any remaining command - substitutions. The result of this recusrive call usiung the tail + substitutions. The result of this recursive call usiung the tail of the string is inserted into the tail_expand array list */ expand_cmdsubst( wcsdup(tail_begin), tail_expand ); /* Combine the result of the current command substitution with the - result of the recusrive tail expansion + result of the recursive tail expansion */ for( i=0; iparam1.function_name ); + sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_call_name ); break; } case SUBST: @@ -1245,7 +1245,7 @@ static const wchar_t *is_function() } if( b->type == FUNCTION_CALL ) { - return b->param1.function_name; + return b->param1.function_call_name; } b=b->outer; } @@ -1293,7 +1293,7 @@ const wchar_t *parser_current_filename() } if( b->type == FUNCTION_CALL ) { - return function_get_definition_file(b->param1.function_name ); + return function_get_definition_file(b->param1.function_call_name ); } b=b->outer; } @@ -3323,7 +3323,8 @@ int parser_test( const wchar_t * buff, } /* - Try to make sure that arguments passed to 'end' is always the type of block to close + Try to make sure that arguments passed to 'end' + is always the type of block to close */ if( wcscmp( cmd, L"end" ) == 0 ) { diff --git a/parser.h b/parser.h index 9a4df4612..d563b0fba 100644 --- a/parser.h +++ b/parser.h @@ -54,6 +54,11 @@ typedef struct block The job that is currently evaluated in the specified block. */ job_t *job; + + /** + Block type-specific data + */ + void *data; /** First block type specific variable @@ -62,11 +67,11 @@ typedef struct block { int while_state; /**< True if the loop condition has not yet been evaluated*/ wchar_t *for_variable; /**< Name of the variable to loop over */ - int if_state; /**< The state of the if block */ + int if_state; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */ wchar_t *switch_value; /**< The value to test in a switch block */ - wchar_t *function_name; /**< The name of the function to define or the function called*/ const wchar_t *source_dest; /**< The name of the file to source*/ event_t *event; /**