mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -305,6 +305,9 @@ int ast_cli_generatornummatches(const char *, const char *); | ||||
|  * 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,9 +329,29 @@ char **ast_cli_completion_matches(const char *, const char *); | ||||
|  *       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. | ||||
|  * | ||||
|   | ||||
							
								
								
									
										55
									
								
								main/cli.c
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								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; | ||||
| 	} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user