From 6748f690f5d0e40044fbe440303154b133dd6619 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Thu, 9 Nov 2017 00:42:10 -0500 Subject: CLI: Create ast_cli_completion_add function. Some completion generators are very inefficent due to the way CLI requests matches one at a time. ast_cli_completion_add can be called multiple times during one invokation of a CLI generator to add all results without having to reinitialize the search state for each match. Change-Id: I73d26d270bbbe1e3e6390799cfc1b639e39cceec --- main/cli.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'main/cli.c') diff --git a/main/cli.c b/main/cli.c index 1653838ea..0f023b29f 100644 --- a/main/cli.c +++ b/main/cli.c @@ -2512,6 +2512,44 @@ char **ast_cli_completion_matches(const char *text, const char *word) return match_list; } +AST_THREADSTORAGE_RAW(completion_storage); + +/*! + * \internal + * \brief Add a value to the vector. + * + * \param vec Vector to add \a value to. Must be from threadstorage. + * \param value The value to add. + * + * \retval 0 Success + * \retval -1 Failure + */ +static int cli_completion_vector_add(struct ast_vector_string *vec, char *value) +{ + if (!value) { + return 0; + } + + if (!vec || AST_VECTOR_ADD_SORTED(vec, value, strcasecmp)) { + if (vec) { + ast_threadstorage_set_ptr(&completion_storage, NULL); + + AST_VECTOR_CALLBACK_VOID(vec, ast_free); + AST_VECTOR_FREE(vec); + } + ast_free(value); + + return -1; + } + + return 0; +} + +int ast_cli_completion_add(char *value) +{ + return cli_completion_vector_add(ast_threadstorage_get_ptr(&completion_storage), value); +} + struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word) { char *retstr, *prevstr; @@ -2519,13 +2557,23 @@ struct ast_vector_string *ast_cli_completion_vector(const char *text, const char size_t which = 0; struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec)); + /* Recursion into this function is a coding error. */ + ast_assert(!ast_threadstorage_get_ptr(&completion_storage)); + if (!vec) { return NULL; } + if (ast_threadstorage_set_ptr(&completion_storage, vec)) { + ast_log(LOG_ERROR, "Failed to initialize threadstorage for completion.\n"); + ast_free(vec); + + return NULL; + } + while ((retstr = ast_cli_generator(text, word, which)) != NULL) { - if (AST_VECTOR_ADD_SORTED(vec, retstr, strcasecmp)) { - ast_free(retstr); + if (cli_completion_vector_add(vec, retstr)) { + ast_threadstorage_set_ptr(&completion_storage, NULL); goto vector_cleanup; } @@ -2533,6 +2581,8 @@ struct ast_vector_string *ast_cli_completion_vector(const char *text, const char ++which; } + ast_threadstorage_set_ptr(&completion_storage, NULL); + if (!AST_VECTOR_SIZE(vec)) { AST_VECTOR_PTR_FREE(vec); @@ -2571,6 +2621,7 @@ struct ast_vector_string *ast_cli_completion_vector(const char *text, const char 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; } -- cgit v1.2.3