Factor out final completion match string building

We have several places doing essentially the same thing; factor them
out to a central place.  Some of the places overallocate for no good
reason, or use strcat unnecessarily.  The centralized version is more
precise and to the point.

(I considered making the gdb::unique_xmalloc_ptr overload version of
make_completer_match_str try to realloc (not xrealloc) probably
avoiding an allocation in most cases, but that'd be probably overdoing
it, and also, now that I'm writing this I thought I'd try to see how
could we ever get to filename_completer with "text != word", but I
couldn't figure it out.  Running the testsuite with 'gdb_assert (text
== word);' never tripped on the assertion either.  So post gdb 8.1,
I'll probably propose a patch to simplify filename_completer a bit,
and the gdb::unique_xmalloc_str overload can be removed then.)

gdb/ChangeLog:
2017-12-13  Pedro Alves  <palves@redhat.com>

	* cli/cli-decode.c (complete_on_cmdlist, complete_on_enum): Use
	make_completion_match_str.
	* completer.c: Use gdb::unique_xmalloc_ptr and
	make_completion_match_str.
	(make_completion_match_str_1): New.
	(make_completion_match_str(const char *, const char *,
	const char *)): New.
	(make_completion_match_str(gdb::unique_xmalloc_ptr<char> &&,
	const char *, const char *)): New.
	* completer.h (make_completion_match_str(const char *,
	const char *, const char *)): New.
	(make_completion_match_str(gdb::unique_xmalloc_ptr<char> &&,
	const char *, const char *)): New.
	* interps.c (interpreter_completer): Use make_completion_match_str.
	* symtab.c (completion_list_add_name, add_filename_to_list): Use
	make_completion_match_str.
This commit is contained in:
Pedro Alves
2017-12-13 16:38:49 +00:00
parent 0b982d685e
commit 60a20c1907
6 changed files with 106 additions and 131 deletions

View File

@@ -158,10 +158,9 @@ filename_completer (struct cmd_list_element *ignore,
subsequent_name = 0;
while (1)
{
char *p, *q;
p = rl_filename_completion_function (text, subsequent_name);
if (p == NULL)
gdb::unique_xmalloc_ptr<char> p_rl
(rl_filename_completion_function (text, subsequent_name));
if (p_rl == NULL)
break;
/* We need to set subsequent_name to a non-zero value before the
continue line below, because otherwise, if the first file
@@ -170,32 +169,12 @@ filename_completer (struct cmd_list_element *ignore,
subsequent_name = 1;
/* Like emacs, don't complete on old versions. Especially
useful in the "source" command. */
const char *p = p_rl.get ();
if (p[strlen (p) - 1] == '~')
{
xfree (p);
continue;
}
continue;
if (word == text)
/* Return exactly p. */
q = p;
else if (word > text)
{
/* Return some portion of p. */
q = (char *) xmalloc (strlen (p) + 5);
strcpy (q, p + (word - text));
xfree (p);
}
else
{
/* Return some of TEXT plus p. */
q = (char *) xmalloc (strlen (p) + (text - word) + 5);
strncpy (q, word, text - word);
q[text - word] = '\0';
strcat (q, p);
xfree (p);
}
tracker.add_completion (gdb::unique_xmalloc_ptr<char> (q));
tracker.add_completion
(make_completion_match_str (std::move (p_rl), text, word));
}
#if 0
/* There is no way to do this just long enough to affect quote
@@ -1580,6 +1559,63 @@ completion_tracker::add_completions (completion_list &&list)
add_completion (std::move (candidate));
}
/* Helper for the make_completion_match_str overloads. Returns NULL
as an indication that we want MATCH_NAME exactly. It is up to the
caller to xstrdup that string if desired. */
static char *
make_completion_match_str_1 (const char *match_name,
const char *text, const char *word)
{
char *newobj;
if (word == text)
{
/* Return NULL as an indication that we want MATCH_NAME
exactly. */
return NULL;
}
else if (word > text)
{
/* Return some portion of MATCH_NAME. */
newobj = xstrdup (match_name + (word - text));
}
else
{
/* Return some of WORD plus MATCH_NAME. */
size_t len = strlen (match_name);
newobj = (char *) xmalloc (text - word + len + 1);
memcpy (newobj, word, text - word);
memcpy (newobj + (text - word), match_name, len + 1);
}
return newobj;
}
/* See completer.h. */
gdb::unique_xmalloc_ptr<char>
make_completion_match_str (const char *match_name,
const char *text, const char *word)
{
char *newobj = make_completion_match_str_1 (match_name, text, word);
if (newobj == NULL)
newobj = xstrdup (match_name);
return gdb::unique_xmalloc_ptr<char> (newobj);
}
/* See completer.h. */
gdb::unique_xmalloc_ptr<char>
make_completion_match_str (gdb::unique_xmalloc_ptr<char> &&match_name,
const char *text, const char *word)
{
char *newobj = make_completion_match_str_1 (match_name.get (), text, word);
if (newobj == NULL)
return std::move (match_name);
return gdb::unique_xmalloc_ptr<char> (newobj);
}
/* Generate completions all at once. Does nothing if max_completions
is 0. If max_completions is non-negative, this will collect at
most max_completions strings.