Cleanup of builtins. No more hashes.

This commit is contained in:
ridiculousfish 2012-01-31 19:47:56 -08:00
parent beece6a828
commit 3adf6d25f6
3 changed files with 103 additions and 244 deletions

View file

@ -9,7 +9,7 @@
where NAME is the name of the builtin, and args is a zero-terminated list of arguments. where NAME is the name of the builtin, and args is a zero-terminated list of arguments.
2). Add a line like { L"NAME", &builtin_NAME, N_(L"Bla bla bla") }, to the builtin_data variable. The description is used by the completion system. 2). Add a line like { L"NAME", &builtin_NAME, N_(L"Bla bla bla") }, to the builtin_data_t variable. The description is used by the completion system. Note that this array is sorted!
3). Create a file doc_src/NAME.txt, containing the manual for the builtin in Doxygen-format. Check the other builtin manuals for proper syntax. 3). Create a file doc_src/NAME.txt, containing the manual for the builtin in Doxygen-format. Check the other builtin manuals for proper syntax.
@ -85,7 +85,7 @@
/** /**
Datastructure to describe a builtin. Datastructure to describe a builtin.
*/ */
typedef struct builtin_data struct builtin_data_t
{ {
/** /**
Name of the builtin Name of the builtin
@ -99,14 +99,20 @@ typedef struct builtin_data
Description of what the builtin does Description of what the builtin does
*/ */
const wchar_t *desc; const wchar_t *desc;
bool operator<(const wchar_t *) const;
bool operator<(const builtin_data_t *) const;
};
bool builtin_data_t::operator<(const wchar_t *other) const
{
return wcscmp(this->name, other) < 0;
} }
builtin_data_t;
bool builtin_data_t::operator<(const builtin_data_t *other) const
/** {
Table of all builtins return wcscmp(this->name, other->name) < 0;
*/ }
static hash_table_t builtin;
int builtin_out_redirect; int builtin_out_redirect;
int builtin_err_redirect; int builtin_err_redirect;
@ -127,11 +133,6 @@ static array_list_t io_stack;
*/ */
static int builtin_stdin; static int builtin_stdin;
/**
Table containing descriptions for all builtins
*/
static hash_table_t *desc=0;
/** /**
The underlying IO redirections behind the current builtin. This The underlying IO redirections behind the current builtin. This
should normally not be used - sb_out and friends are already should normally not be used - sb_out and friends are already
@ -963,23 +964,18 @@ static int builtin_builtin( parser_t &parser, wchar_t **argv )
if( list ) if( list )
{ {
array_list_t names; wcstring_list_t names = builtin_get_names();
int i; sort(names.begin(), names.end());
al_init( &names );
builtin_get_names( &names );
sort_list( &names );
for( i=0; i<al_get_count( &names ); i++ ) for( size_t i=0; i<names.size(); i++ )
{ {
wchar_t *el = (wchar_t *)al_get( &names, i ); const wchar_t *el = names.at(i).c_str();
sb_append( sb_out, sb_append( sb_out,
el, el,
L"\n", L"\n",
NULL ); NULL );
} }
al_destroy( &names );
} }
return STATUS_BUILTIN_OK; return STATUS_BUILTIN_OK;
} }
@ -1057,7 +1053,7 @@ static int builtin_emit( parser_t &parser, wchar_t **argv )
/** /**
A generic bultin that only supports showing a help message. This is A generic bultin that only supports showing a help message. This is
only a placeholder that prints the help message. Useful for only a placeholder that prints the help message. Useful for
commands that live in hte parser. commands that live in the parser.
*/ */
static int builtin_generic( parser_t &parser, wchar_t **argv ) static int builtin_generic( parser_t &parser, wchar_t **argv )
{ {
@ -3606,214 +3602,90 @@ static int builtin_case( parser_t &parser, wchar_t **argv )
/* /*
END OF BUILTIN COMMANDS END OF BUILTIN COMMANDS
Below are functions for handling the builtin commands Below are functions for handling the builtin commands.
THESE MUST BE SORTED BY NAME! Completion lookup uses binary search.
*/ */
/** /**
Data about all the builtin commands in fish Data about all the builtin commands in fish.
Functions that are bound to builtin_generic are handled directly by the parser.
*/ */
static const builtin_data_t builtin_data[]= static const builtin_data_t builtin_datas[]=
{ {
{ { L".", &builtin_source, N_( L"Evaluate contents of file" ) },
L"block", &builtin_block, N_( L"Temporarily block delivery of events" ) { L"and", &builtin_generic, N_( L"Execute command if previous command suceeded" ) },
} { L"begin", &builtin_begin, N_( L"Create a block of code" ) },
, { L"bg", &builtin_bg, N_( L"Send job to background" ) },
{ { L"bind", &builtin_bind, N_( L"Handle fish key bindings" ) },
L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" ) { L"block", &builtin_block, N_( L"Temporarily block delivery of events" ) },
} { L"break", &builtin_break_continue, N_( L"Stop the innermost loop" ) },
, { L"breakpoint", &builtin_breakpoint, N_( L"Temporarily halt execution of a script and launch an interactive debug prompt" ) },
{ { L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" ) },
L"cd", &builtin_cd, N_( L"Change working directory" ) { L"case", &builtin_case, N_( L"Conditionally execute a block of commands" ) },
} { L"cd", &builtin_cd, N_( L"Change working directory" ) },
, { L"command", &builtin_generic, N_( L"Run a program instead of a function or builtin" ) },
{ { L"commandline", &builtin_commandline, N_( L"Set or get the commandline" ) },
L"count", &builtin_count, N_( L"Count the number of arguments" ) { L"complete", &builtin_complete, N_( L"Edit command specific completions" ) },
} { L"contains", &builtin_contains, N_( L"Search for a specified string in a list" ) },
, { L"continue", &builtin_break_continue, N_( L"Skip the rest of the current lap of the innermost loop" ) },
{ { L"count", &builtin_count, N_( L"Count the number of arguments" ) },
L"contains", &builtin_contains, N_( L"Search for a specified string in a list" ) { L"else", &builtin_else, N_( L"Evaluate block if condition is false" ) },
} { L"emit", &builtin_emit, N_( L"Emit an event" ) },
, { L"end", &builtin_end, N_( L"End a block of commands" ) },
{ { L"exec", &builtin_generic, N_( L"Run command in current process" ) },
L"emit", &builtin_emit, N_( L"Emit an event" ) { L"exit", &builtin_exit, N_( L"Exit the shell" ) },
} { L"fg", &builtin_fg, N_( L"Send job to foreground" ) },
, { L"for", &builtin_for, N_( L"Perform a set of commands multiple times" ) },
{ { L"function", &builtin_function, N_( L"Define a new function" ) },
L"exit", &builtin_exit, N_( L"Exit the shell" ) { L"functions", &builtin_functions, N_( L"List or remove functions" ) },
} { L"if", &builtin_generic, N_( L"Evaluate block if condition is true" ) },
, { L"jobs", &builtin_jobs, N_( L"Print currently running jobs" ) },
{ { L"not", &builtin_generic, N_( L"Negate exit status of job" ) },
L"function", &builtin_function, N_( L"Define a new function" ) { L"or", &builtin_generic, N_( L"Execute command if previous command failed" ) },
} { L"random", &builtin_random, N_( L"Generate random number" ) },
, { L"read", &builtin_read, N_( L"Read a line of input into variables" ) },
{ { L"return", &builtin_return, N_( L"Stop the currently evaluated function" ) },
L"functions", &builtin_functions, N_( L"List or remove functions" ) { L"set", &builtin_set, N_( L"Handle environment variables" ) },
} { L"status", &builtin_status, N_( L"Return status information about fish" ) },
, { L"switch", &builtin_switch, N_( L"Conditionally execute a block of commands" ) },
{ { L"ulimit", &builtin_ulimit, N_( L"Set or get the shells resource usage limits" ) },
L"complete", &builtin_complete, N_( L"Edit command specific completions" ) { L"while", &builtin_generic, N_( L"Perform a command multiple times" ) }
} };
,
{
L"end", &builtin_end, N_( L"End a block of commands" )
}
,
{
L"else", &builtin_else, N_( L"Evaluate block if condition is false" )
}
,
{
L"for", &builtin_for, N_( L"Perform a set of commands multiple times" )
}
,
{
L".", &builtin_source, N_( L"Evaluate contents of file" )
}
,
{
L"set", &builtin_set, N_( L"Handle environment variables" )
}
,
{
L"fg", &builtin_fg, N_( L"Send job to foreground" )
}
,
{
L"bg", &builtin_bg, N_( L"Send job to background" )
}
,
{
L"jobs", &builtin_jobs, N_( L"Print currently running jobs" )
}
,
{
L"read", &builtin_read, N_( L"Read a line of input into variables" )
}
,
{
L"break", &builtin_break_continue, N_( L"Stop the innermost loop" )
}
,
{
L"continue", &builtin_break_continue, N_( L"Skip the rest of the current lap of the innermost loop" )
}
,
{
L"return", &builtin_return, N_( L"Stop the currently evaluated function" )
}
,
{
L"commandline", &builtin_commandline, N_( L"Set or get the commandline" )
}
,
{
L"switch", &builtin_switch, N_( L"Conditionally execute a block of commands" )
}
,
{
L"case", &builtin_case, N_( L"Conditionally execute a block of commands" )
}
,
{
L"bind", &builtin_bind, N_( L"Handle fish key bindings" )
}
,
{
L"random", &builtin_random, N_( L"Generate random number" )
}
,
{
L"status", &builtin_status, N_( L"Return status information about fish" )
}
,
{
L"ulimit", &builtin_ulimit, N_( L"Set or get the shells resource usage limits" )
}
,
{
L"begin", &builtin_begin, N_( L"Create a block of code" )
}
,
{
L"breakpoint", &builtin_breakpoint, N_( L"Temporarily halt execution of a script and launch an interactive debug prompt" )
}
,
/* #define BUILTIN_COUNT (sizeof builtin_datas / sizeof *builtin_datas)
Builtins that are handled directly by the parser. They are
bound to a noop function only so that they show up in the static const builtin_data_t *builtin_lookup(const wchar_t *name) {
listings of builtin commands, etc.. const builtin_data_t *array_end = builtin_datas + BUILTIN_COUNT;
*/ const builtin_data_t *found = std::lower_bound(builtin_datas, array_end, name);
{ if (found != array_end && ! wcscmp(found->name, name)) {
L"command", &builtin_generic, N_( L"Run a program instead of a function or builtin" ) return found;
} } else {
, return NULL;
{ }
L"if", &builtin_generic, N_( L"Evaluate block if condition is true" )
}
,
{
L"while", &builtin_generic, N_( L"Perform a command multiple times" )
}
,
{
L"not", &builtin_generic, N_( L"Negate exit status of job" )
}
,
{
L"and", &builtin_generic, N_( L"Execute command if previous command suceeded" )
}
,
{
L"or", &builtin_generic, N_( L"Execute command if previous command failed" )
}
,
{
L"exec", &builtin_generic, N_( L"Run command in current process" )
}
,
{
0, 0, 0
}
} }
;
void builtin_init() void builtin_init()
{ {
int i;
wopterr = 0; wopterr = 0;
al_init( &io_stack ); al_init( &io_stack );
hash_init( &builtin, &hash_wcs_func, &hash_wcs_cmp );
for( i=0; builtin_data[i].name; i++ ) for( size_t i=0; i < BUILTIN_COUNT; i++ )
{ {
hash_put( &builtin, builtin_data[i].name, (void *)builtin_data[i].func ); intern_static( builtin_datas[i].name );
intern_static( builtin_data[i].name );
} }
} }
void builtin_destroy() void builtin_destroy()
{ {
if( desc )
{
hash_destroy( desc );
free( desc );
desc=0;
}
al_destroy( &io_stack ); al_destroy( &io_stack );
hash_destroy( &builtin );
} }
int builtin_exists( const wchar_t *cmd ) int builtin_exists( const wchar_t *cmd )
{ {
CHECK( cmd, 0 ); CHECK( cmd, 0 );
return !!hash_get(&builtin, cmd); return !!builtin_lookup(cmd);
} }
/** /**
@ -3835,8 +3707,9 @@ int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io )
CHECK( argv, STATUS_BUILTIN_ERROR ); CHECK( argv, STATUS_BUILTIN_ERROR );
CHECK( argv[0], STATUS_BUILTIN_ERROR ); CHECK( argv[0], STATUS_BUILTIN_ERROR );
cmd = (int (*)(parser_t &parser, const wchar_t * const*))hash_get( &builtin, argv[0] ); const builtin_data_t *data = builtin_lookup(argv[0]);
cmd = (int (*)(parser_t &parser, const wchar_t * const*))(data ? data->func : NULL);
if( argv[1] != 0 && !internal_help(argv[0]) ) if( argv[1] != 0 && !internal_help(argv[0]) )
{ {
@ -3847,7 +3720,7 @@ int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io )
} }
} }
if( cmd != 0 ) if( data != NULL )
{ {
int status; int status;
@ -3863,44 +3736,29 @@ int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io )
} }
void builtin_get_names( array_list_t *list ) wcstring_list_t builtin_get_names(void)
{ {
CHECK( list, ); wcstring_list_t result;
hash_get_keys( &builtin, list ); result.reserve(BUILTIN_COUNT);
for (size_t i=0; i < BUILTIN_COUNT; i++) {
result.push_back(builtin_datas[i].name);
}
return result;
} }
void builtin_get_names2(std::vector<completion_t> &list) { void builtin_get_names(std::vector<completion_t> &list) {
for (int i=0;i<builtin.size ; ++i) { for (size_t i=0; i < BUILTIN_COUNT; i++) {
completion_t data_to_push; completion_t data_to_push;
data_to_push.completion = builtin_datas[i].name;
if (builtin.arr[i].key == 0)
continue;
data_to_push.completion = (wchar_t*)builtin.arr[i].key;
list.push_back( data_to_push ); list.push_back( data_to_push );
} }
} }
const wchar_t *builtin_get_desc( const wchar_t *b ) const wchar_t *builtin_get_desc( const wchar_t *name )
{ {
CHECK( b, 0 ); CHECK( name, 0 );
const builtin_data_t *builtin = builtin_lookup(name);
if( !desc ) return builtin ? _(builtin->desc) : NULL;
{
int i;
desc = (hash_table_t *)malloc( sizeof( hash_table_t ) );
if( !desc)
return 0;
hash_init( desc, &hash_wcs_func, &hash_wcs_cmp );
for( i=0; builtin_data[i].name; i++ )
{
hash_put( desc, builtin_data[i].name, builtin_data[i].desc );
}
}
return _( hash_get( desc, b ));
} }
void builtin_push_io( parser_t &parser, int in ) void builtin_push_io( parser_t &parser, int in )

View file

@ -139,12 +139,13 @@ int builtin_exists( const wchar_t *cmd );
*/ */
int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io ); int builtin_run( parser_t &parser, const wchar_t * const *argv, io_data_t *io );
/** /** Returns a list of all builtin names */
Insert all builtin names into l. These are not copies of the strings and should not be freed after use. wcstring_list_t builtin_get_names(void);
*/
void builtin_get_names( array_list_t *list );
void builtin_get_names2 (std::vector<completion_t>&); /**
Insert all builtin names into list.
*/
void builtin_get_names(std::vector<completion_t> &list);
/** /**
Pushes a new set of input/output to the stack. The new stdin is supplied, a new set of output string_buffer_ts is created. Pushes a new set of input/output to the stack. The new stdin is supplied, a new set of output string_buffer_ts is created.

View file

@ -1201,7 +1201,7 @@ static void complete_cmd( const wchar_t *cmd,
if( use_builtin ) if( use_builtin )
{ {
builtin_get_names2( possible_comp ); builtin_get_names( possible_comp );
complete_strings( comp, cmd, 0, &builtin_get_desc, possible_comp, 0 ); complete_strings( comp, cmd, 0, &builtin_get_desc, possible_comp, 0 );
} }
// al_destroy( &possible_comp ); // al_destroy( &possible_comp );