[Asterisk-code-review] CLI: Create ast cli completion add function. (asterisk[15])

George Joseph asteriskteam at digium.com
Mon Nov 27 12:29:10 CST 2017


George Joseph has submitted this change and it was merged. ( https://gerrit.asterisk.org/7256 )

Change subject: CLI: Create ast_cli_completion_add function.
......................................................................

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
---
M include/asterisk/cli.h
M main/cli.c
2 files changed, 76 insertions(+), 2 deletions(-)

Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved
  Jenkins2: Approved for Submit



diff --git a/include/asterisk/cli.h b/include/asterisk/cli.h
index 51f077f..c75fc29 100644
--- a/include/asterisk/cli.h
+++ b/include/asterisk/cli.h
@@ -305,6 +305,9 @@
  * Subsequent entries are all possible values, followed by a NULL.
  * All strings and the array itself are malloc'ed and must be freed
  * by the caller.
+ *
+ * \warning This function cannot be called recursively so it will always
+ *          fail if called from a CLI_GENERATE callback.
  */
 char **ast_cli_completion_matches(const char *, const char *);
 
@@ -326,10 +329,30 @@
  *       by the caller.
  *
  * \note The vector is sorted and does not contain any duplicates.
+ *
+ * \warning This function cannot be called recursively so it will always
+ *          fail if called from a CLI_GENERATE callback.
  */
 struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word);
 
 /*!
+ * \brief Add a result to a request for completion options.
+ *
+ * \param value A completion option text.
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ *
+ * This is an alternative to returning individual values from CLI_GENERATE.  Instead
+ * of repeatedly being asked for the next match and having to start over, you can
+ * call this function repeatedly from your own stateful loop.  When all matches have
+ * been added you can return NULL from the CLI_GENERATE function.
+ *
+ * \note This function always eventually results in calling ast_free on \a value.
+ */
+int ast_cli_completion_add(char *value);
+
+/*!
  * \brief Command completion for the list of active channels.
  *
  * This can be called from a CLI command completion function that wants to
diff --git a/main/cli.c b/main/cli.c
index 1653838..0f023b2 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -2512,6 +2512,44 @@
 	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,19 +2557,31 @@
 	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;
 		}
 
 		++which;
 	}
+
+	ast_threadstorage_set_ptr(&completion_storage, NULL);
 
 	if (!AST_VECTOR_SIZE(vec)) {
 		AST_VECTOR_PTR_FREE(vec);
@@ -2571,6 +2621,7 @@
 	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;
 	}
 

-- 
To view, visit https://gerrit.asterisk.org/7256
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 15
Gerrit-MessageType: merged
Gerrit-Change-Id: I73d26d270bbbe1e3e6390799cfc1b639e39cceec
Gerrit-Change-Number: 7256
Gerrit-PatchSet: 3
Gerrit-Owner: Corey Farrell <git at cfware.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Jenkins2
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171127/613f5573/attachment-0001.html>


More information about the asterisk-code-review mailing list