Cleanup of completion_entry in complete.cpp

This commit is contained in:
ridiculousfish
2012-02-08 14:47:50 -08:00
parent bc8a288386
commit 4f8b4379f5
2 changed files with 81 additions and 170 deletions

View File

@@ -154,26 +154,24 @@ typedef struct complete_entry_opt
/** /**
Struct describing a command completion Struct describing a command completion
*/ */
typedef struct complete_entry struct completion_entry_t
{ {
/** True if command is a path */ /** True if command is a path */
int cmd_type; int cmd_type;
/** Command string */ /** Command string */
const wchar_t *cmd; wcstring cmd;
/** String containing all short option characters */ /** String containing all short option characters */
wchar_t *short_opt_str; wcstring short_opt_str;
/** Linked list of all options */ /** Linked list of all options */
complete_entry_opt_t *first_option; complete_entry_opt_t *first_option;
/** Next command completion in the linked list */
struct complete_entry *next;
/** True if no other options than the ones supplied are possible */ /** True if no other options than the ones supplied are possible */
int authoritative; int authoritative;
} };
complete_entry_t;
/** First node in the linked list of all completion entries */ /** Linked list of all completion entries */
static complete_entry_t *first_entry=0; typedef std::list<completion_entry_t *> completion_entry_list_t;
static completion_entry_list_t completion_entries;
/** /**
Table of completions conditions that have already been tested and Table of completions conditions that have already been tested and
@@ -301,47 +299,38 @@ static void complete_free_opt_recursive( complete_entry_opt_t *o )
/** /**
Search for an exactly matching completion entry Search for an exactly matching completion entry
*/ */
static complete_entry_t *complete_find_exact_entry( const wchar_t *cmd, static completion_entry_t *complete_find_exact_entry( const wchar_t *cmd,
const int cmd_type ) const int cmd_type )
{ {
complete_entry_t *i; for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
for( i=first_entry; i; i=i->next )
{ {
if( ( wcscmp(cmd, i->cmd)==0) && ( cmd_type == i->cmd_type )) completion_entry_t *entry = *iter;
{ if (entry->cmd == cmd && cmd_type == entry->cmd_type)
return i; return entry;
}
} }
return 0; return NULL;
} }
/** /**
Locate the specified entry. Create it if it doesn't exist. Locate the specified entry. Create it if it doesn't exist.
*/ */
static complete_entry_t *complete_get_exact_entry( const wchar_t *cmd, static completion_entry_t *complete_get_exact_entry( const wchar_t *cmd,
int cmd_type ) int cmd_type )
{ {
complete_entry_t *c; completion_entry_t *c;
complete_init(); complete_init();
c = complete_find_exact_entry( cmd, cmd_type ); c = complete_find_exact_entry( cmd, cmd_type );
if( c == 0 ) if( c == NULL )
{ {
if( !(c = (complete_entry_t *)malloc( sizeof(complete_entry_t) ))) c = new completion_entry_t();
{ completion_entries.push_front(c);
DIE_MEM();
}
c->next = first_entry;
first_entry = c;
c->first_option = 0; c->first_option = 0;
c->cmd = cmd;
c->cmd = intern( cmd );
c->cmd_type = cmd_type; c->cmd_type = cmd_type;
c->short_opt_str = wcsdup(L""); c->short_opt_str = L"";
c->authoritative = 1; c->authoritative = 1;
} }
@@ -353,7 +342,7 @@ void complete_set_authoritative( const wchar_t *cmd,
int cmd_type, int cmd_type,
int authoritative ) int authoritative )
{ {
complete_entry_t *c; completion_entry_t *c;
CHECK( cmd, ); CHECK( cmd, );
c = complete_get_exact_entry( cmd, cmd_type ); c = complete_get_exact_entry( cmd, cmd_type );
@@ -372,7 +361,7 @@ void complete_add( const wchar_t *cmd,
const wchar_t *desc, const wchar_t *desc,
int flags ) int flags )
{ {
complete_entry_t *c; completion_entry_t *c;
complete_entry_opt_t *opt; complete_entry_opt_t *opt;
CHECK( cmd, ); CHECK( cmd, );
@@ -386,14 +375,11 @@ void complete_add( const wchar_t *cmd,
if( short_opt != L'\0' ) if( short_opt != L'\0' )
{ {
int len = 1 + ((result_mode & NO_COMMON) != 0); int len = 1 + ((result_mode & NO_COMMON) != 0);
c->short_opt_str =
(wchar_t *)realloc( c->short_opt_str, c->short_opt_str.push_back(short_opt);
sizeof(wchar_t)*(wcslen( c->short_opt_str ) + 1 + len) );
wcsncat( c->short_opt_str,
&short_opt, 1 );
if( len == 2 ) if( len == 2 )
{ {
wcscat( c->short_opt_str, L":" ); c->short_opt_str.push_back(L':');
} }
} }
@@ -419,11 +405,10 @@ void complete_add( const wchar_t *cmd,
/** /**
Remove all completion options in the specified entry that match the Remove all completion options in the specified entry that match the
specified short / long option strings. specified short / long option strings. Returns true if it is now
empty and should be deleted, false if it's not empty.
*/ */
static complete_entry_t *complete_remove_entry( complete_entry_t *e, static bool complete_remove_entry( completion_entry_t *e, wchar_t short_opt, const wchar_t *long_opt )
wchar_t short_opt,
const wchar_t *long_opt )
{ {
complete_entry_opt_t *o, *oprev=0, *onext=0; complete_entry_opt_t *o, *oprev=0, *onext=0;
@@ -443,7 +428,6 @@ static complete_entry_t *complete_remove_entry( complete_entry_t *e,
if( ( short_opt==o->short_opt ) || if( ( short_opt==o->short_opt ) ||
( wcscmp( long_opt, o->long_opt ) == 0 ) ) ( wcscmp( long_opt, o->long_opt ) == 0 ) )
{ {
wchar_t *pos;
/* fwprintf( stderr, /* fwprintf( stderr,
L"remove option -%lc --%ls\n", L"remove option -%lc --%ls\n",
o->short_opt?o->short_opt:L' ', o->short_opt?o->short_opt:L' ',
@@ -451,20 +435,15 @@ static complete_entry_t *complete_remove_entry( complete_entry_t *e,
*/ */
if( o->short_opt ) if( o->short_opt )
{ {
pos = wcschr( e->short_opt_str, size_t idx = e->short_opt_str.find(o->short_opt);
o->short_opt ); if (idx != wcstring::npos)
if( pos ) {
{ /* Consume all colons */
wchar_t *pos2 = pos+1; size_t first_non_colon = idx + 1;
while( *pos2 == L':' ) while (first_non_colon < e->short_opt_str.size() && e->short_opt_str.at(first_non_colon) == L':')
{ first_non_colon++;
pos2++; e->short_opt_str.erase(idx, first_non_colon - idx);
} }
memmove( pos,
pos2,
sizeof(wchar_t)*wcslen(pos2) );
}
} }
if( oprev == 0 ) if( oprev == 0 )
@@ -483,16 +462,8 @@ static complete_entry_t *complete_remove_entry( complete_entry_t *e,
} }
} }
} }
if( e && (e->first_option == 0) ) return e->first_option == 0;
{
free( e->short_opt_str );
free( e );
e=0;
}
return e;
} }
@@ -501,77 +472,25 @@ void complete_remove( const wchar_t *cmd,
wchar_t short_opt, wchar_t short_opt,
const wchar_t *long_opt ) const wchar_t *long_opt )
{ {
complete_entry_t *e, *eprev=0, *enext=0;
CHECK( cmd, ); CHECK( cmd, );
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); ) {
for( e = first_entry; e; e=enext ) completion_entry_t *e = *iter;
{ bool delete_it = false;
enext=e->next; if(cmd_type == e->cmd_type && cmd == e->cmd) {
delete_it = complete_remove_entry( e, short_opt, long_opt );
if( (cmd_type == e->cmd_type ) && }
( wcscmp( cmd, e->cmd) == 0 ) )
{ if (delete_it) {
e = complete_remove_entry( e, short_opt, long_opt ); /* Delete this entry */
} iter = completion_entries.erase(iter);
delete e;
if( e ) } else {
{ /* Don't delete it */
eprev = e; iter++;
} }
else
{
if( eprev )
{
eprev->next = enext;
}
else
{
first_entry = enext;
}
}
} }
} }
/**
Find the full path and commandname from a command string. Both
pointers are allocated using halloc and will be free'd when\c
context is halloc_free'd.
*/
static void parse_cmd_string( void *context,
const wchar_t *str,
wchar_t **pathp,
wchar_t **cmdp )
{
wchar_t *cmd, *path;
/* Get the path of the command */
path = (wchar_t *)halloc_register(context, path_get_path( str ));
if( path == 0 )
{
/**
Use the empty string as the 'path' for commands that can
not be found.
*/
path = halloc_wcsdup( context, L"");
}
/* Make sure the path is not included in the command */
cmd = const_cast<wchar_t*>(wcsrchr( str, L'/' ));
if( cmd != 0 )
{
cmd++;
}
else
{
cmd = (wchar_t *)str;
}
*pathp=path;
*cmdp=cmd;
}
/** /**
Find the full path and commandname from a command string 'str'. Find the full path and commandname from a command string 'str'.
*/ */
@@ -595,7 +514,6 @@ int complete_is_valid_option( const wchar_t *str,
array_list_t *errors, array_list_t *errors,
bool allow_autoload ) bool allow_autoload )
{ {
complete_entry_t *i;
complete_entry_opt_t *o; complete_entry_opt_t *o;
wcstring cmd, path; wcstring cmd, path;
int found_match = 0; int found_match = 0;
@@ -673,8 +591,9 @@ int complete_is_valid_option( const wchar_t *str,
*/ */
if (allow_autoload) complete_load( cmd, false ); if (allow_autoload) complete_load( cmd, false );
for( i=first_entry; i; i=i->next ) for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
{ {
const completion_entry_t *i = *iter;
const wcstring &match = i->cmd_type?path:cmd; const wcstring &match = i->cmd_type?path:cmd;
const wchar_t *a; const wchar_t *a;
@@ -739,7 +658,8 @@ int complete_is_valid_option( const wchar_t *str,
for( a = &opt[1]; *a; a++ ) for( a = &opt[1]; *a; a++ )
{ {
wchar_t *str_pos = wcschr(i->short_opt_str, *a); //PCA Rewrite this
wchar_t *str_pos = wcschr(i->short_opt_str.c_str(), *a);
if (str_pos ) if (str_pos )
{ {
@@ -1248,10 +1168,10 @@ static wchar_t *param_match2( const complete_entry_opt_t *e,
/** /**
Tests whether a short option is a viable completion Tests whether a short option is a viable completion
*/ */
static int short_ok( const wchar_t *arg, static int short_ok( const wcstring &arg_str, wchar_t nextopt, const wcstring &allopt_str )
wchar_t nextopt,
const wchar_t *allopt )
{ {
const wchar_t *arg = arg_str.c_str();
const wchar_t *allopt = allopt_str.c_str();
const wchar_t *ptr; const wchar_t *ptr;
if( arg[0] != L'-') if( arg[0] != L'-')
@@ -1300,21 +1220,19 @@ static int complete_param( const wchar_t *cmd_orig,
int use_switches, int use_switches,
std::vector<completion_t> &comp_out ) std::vector<completion_t> &comp_out )
{ {
complete_entry_t *i;
complete_entry_opt_t *o; complete_entry_opt_t *o;
wchar_t *cmd, *path;
int use_common=1, use_files=1; int use_common=1, use_files=1;
void *context = halloc( 0, 0 ); wcstring cmd, path;
parse_cmd_string(cmd_orig, path, cmd);
parse_cmd_string( context, cmd_orig, &path, &cmd );
complete_load( cmd, true ); complete_load( cmd, true );
for( i=first_entry; i; i=i->next ) for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
{ {
wchar_t *match = i->cmd_type?path:cmd; completion_entry_t *i = *iter;
const wcstring &match = i->cmd_type?path:cmd;
if( ( (!wildcard_match( match, i->cmd ) ) ) ) if( ( (!wildcard_match( match, i->cmd ) ) ) )
{ {
@@ -1437,14 +1355,15 @@ static int complete_param( const wchar_t *cmd_orig,
{ {
int match=0, match_no_case=0; int match=0, match_no_case=0;
string_buffer_t *whole_opt = sb_halloc( context ); wcstring whole_opt;
sb_append( whole_opt, o->old_mode?L"-":L"--", o->long_opt, NULL ); whole_opt.append(o->old_mode?L"-":L"--");
whole_opt.append(o->long_opt);
match = wcsncmp( str, (wchar_t *)whole_opt->buff, wcslen(str) )==0; match = string_prefixes_string(str, whole_opt);
if( !match ) if( !match )
{ {
match_no_case = wcsncasecmp( str, (wchar_t *)whole_opt->buff, wcslen(str) )==0; match_no_case = wcsncasecmp( str, whole_opt.c_str(), wcslen(str) )==0;
} }
if( match || match_no_case ) if( match || match_no_case )
@@ -1481,7 +1400,7 @@ static int complete_param( const wchar_t *cmd_orig,
sb_printf( &completion, sb_printf( &completion,
L"%ls=", L"%ls=",
((wchar_t *)whole_opt->buff)+offset ); whole_opt.c_str()+offset );
completion_allocate( comp_out, completion_allocate( comp_out,
(wchar_t *)completion.buff, (wchar_t *)completion.buff,
@@ -1493,7 +1412,7 @@ static int complete_param( const wchar_t *cmd_orig,
} }
completion_allocate( comp_out, completion_allocate( comp_out,
((wchar_t *)whole_opt->buff) + offset, whole_opt.c_str() + offset,
C_(o->desc), C_(o->desc),
flags ); flags );
} }
@@ -1503,8 +1422,6 @@ static int complete_param( const wchar_t *cmd_orig,
} }
} }
halloc_free( context );
return use_files; return use_files;
} }
@@ -1995,27 +1912,23 @@ void complete( const wchar_t *cmd,
non-null and longer than 0 characters. non-null and longer than 0 characters.
*/ */
static void append_switch( string_buffer_t *out, static void append_switch( string_buffer_t *out,
const wchar_t *opt, const wcstring &opt,
const wchar_t *argument ) const wcstring &argument )
{ {
wchar_t *esc; if( argument.empty() )
if( !argument || wcscmp( argument, L"") == 0 )
return; return;
esc = escape( argument, 1 ); wcstring esc = escape_string( argument, 1 );
sb_printf( out, L" --%ls %ls", opt, esc ); sb_printf( out, L" --%ls %ls", opt.c_str(), esc.c_str() );
free(esc);
} }
void complete_print( string_buffer_t *out ) void complete_print( string_buffer_t *out )
{ {
complete_entry_t *e;
CHECK( out, ); CHECK( out, );
for( e = first_entry; e; e=e->next ) for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
{ {
completion_entry_t *e = *iter;
complete_entry_opt_t *o; complete_entry_opt_t *o;
for( o= e->first_option; o; o=o->next ) for( o= e->first_option; o; o=o->next )
{ {

View File

@@ -24,8 +24,6 @@
#include "wutil.h" #include "wutil.h"
#include "history.h" #include "history.h"
#include "common.h" #include "common.h"
#include "halloc.h"
#include "halloc_util.h"
#include "intern.h" #include "intern.h"
#include "path.h" #include "path.h"
#include "signal.h" #include "signal.h"