mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
CLI: Create ast_cli_completion_vector.
This is a rewrite of ast_cli_completion_matches using a vector to build the list. The original function calls the vector version, NULL terminates the vector and extracts the elements array. One change in behavior the results are now sorted and deduplicated. This will solve bugs where some duplicate checking was done before the list was sorted. Change-Id: Iede20c5b4d965fa5ec71fda136ce9425eeb69519
This commit is contained in:
134
main/cli.c
134
main/cli.c
@@ -2488,76 +2488,98 @@ int ast_cli_generatornummatches(const char *text, const char *word)
|
||||
return matches;
|
||||
}
|
||||
|
||||
static void destroy_match_list(char **match_list, int matches)
|
||||
{
|
||||
if (match_list) {
|
||||
int idx;
|
||||
|
||||
for (idx = 1; idx < matches; ++idx) {
|
||||
ast_free(match_list[idx]);
|
||||
}
|
||||
ast_free(match_list);
|
||||
}
|
||||
}
|
||||
|
||||
char **ast_cli_completion_matches(const char *text, const char *word)
|
||||
{
|
||||
char **match_list = NULL, *retstr, *prevstr;
|
||||
char **new_list;
|
||||
size_t match_list_len, max_equal, which, i;
|
||||
int matches = 0;
|
||||
struct ast_vector_string *vec = ast_cli_completion_vector(text, word);
|
||||
char **match_list;
|
||||
|
||||
/* leave entry 0 free for the longest common substring */
|
||||
match_list_len = 1;
|
||||
while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
|
||||
if (matches + 1 >= match_list_len) {
|
||||
match_list_len <<= 1;
|
||||
new_list = ast_realloc(match_list, match_list_len * sizeof(*match_list));
|
||||
if (!new_list) {
|
||||
destroy_match_list(match_list, matches);
|
||||
return NULL;
|
||||
}
|
||||
match_list = new_list;
|
||||
if (!vec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AST_VECTOR_APPEND(vec, NULL)) {
|
||||
/* We failed to NULL terminate the elements */
|
||||
AST_VECTOR_CALLBACK_VOID(vec, ast_free);
|
||||
AST_VECTOR_PTR_FREE(vec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
match_list = AST_VECTOR_STEAL_ELEMENTS(vec);
|
||||
AST_VECTOR_PTR_FREE(vec);
|
||||
|
||||
return match_list;
|
||||
}
|
||||
|
||||
struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word)
|
||||
{
|
||||
char *retstr, *prevstr;
|
||||
size_t max_equal;
|
||||
size_t which = 0;
|
||||
struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
|
||||
|
||||
if (!vec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((retstr = ast_cli_generator(text, word, which)) != NULL) {
|
||||
if (AST_VECTOR_ADD_SORTED(vec, retstr, strcasecmp)) {
|
||||
ast_free(retstr);
|
||||
|
||||
goto vector_cleanup;
|
||||
}
|
||||
match_list[++matches] = retstr;
|
||||
|
||||
++which;
|
||||
}
|
||||
|
||||
if (!match_list) {
|
||||
return match_list; /* NULL */
|
||||
if (!AST_VECTOR_SIZE(vec)) {
|
||||
AST_VECTOR_PTR_FREE(vec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prevstr = AST_VECTOR_GET(vec, 0);
|
||||
max_equal = strlen(prevstr);
|
||||
which = 1;
|
||||
|
||||
/* Find the longest substring that is common to all results
|
||||
* (it is a candidate for completion), and store a copy in entry 0.
|
||||
*/
|
||||
prevstr = match_list[1];
|
||||
max_equal = strlen(prevstr);
|
||||
for (which = 2; which <= matches; which++) {
|
||||
for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
|
||||
continue;
|
||||
max_equal = i;
|
||||
}
|
||||
while (which < AST_VECTOR_SIZE(vec)) {
|
||||
size_t i = 0;
|
||||
|
||||
retstr = ast_malloc(max_equal + 1);
|
||||
if (!retstr) {
|
||||
destroy_match_list(match_list, matches);
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(retstr, match_list[1], max_equal + 1);
|
||||
match_list[0] = retstr;
|
||||
|
||||
/* ensure that the array is NULL terminated */
|
||||
if (matches + 1 >= match_list_len) {
|
||||
new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list));
|
||||
if (!new_list) {
|
||||
retstr = AST_VECTOR_GET(vec, which);
|
||||
/* Check for and remove duplicate strings. */
|
||||
if (!strcasecmp(prevstr, retstr)) {
|
||||
AST_VECTOR_REMOVE(vec, which, 1);
|
||||
ast_free(retstr);
|
||||
destroy_match_list(match_list, matches);
|
||||
return NULL;
|
||||
}
|
||||
match_list = new_list;
|
||||
}
|
||||
match_list[matches + 1] = NULL;
|
||||
|
||||
return match_list;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (i < max_equal && toupper(prevstr[i]) == toupper(retstr[i])) {
|
||||
i++;
|
||||
}
|
||||
|
||||
max_equal = i;
|
||||
prevstr = retstr;
|
||||
++which;
|
||||
}
|
||||
|
||||
/* Insert longest match to position 0. */
|
||||
retstr = ast_strndup(AST_VECTOR_GET(vec, 0), max_equal);
|
||||
if (!retstr || AST_VECTOR_INSERT_AT(vec, 0, retstr)) {
|
||||
ast_free(retstr);
|
||||
goto vector_cleanup;
|
||||
}
|
||||
|
||||
return vec;
|
||||
|
||||
vector_cleanup:
|
||||
AST_VECTOR_CALLBACK_VOID(vec, ast_free);
|
||||
AST_VECTOR_PTR_FREE(vec);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! \brief returns true if there are more words to match */
|
||||
|
Reference in New Issue
Block a user