<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/8051">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Sean Bright: Looks good to me, but someone else must approve
Joshua Colp: Looks good to me, approved
Jenkins2: Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">loader: Use ast_cli_completion_add for 'module load' completion.<br><br>This addresses all performance issues with 'module load' completion. In<br>addition to using ast_cli_completion_add we stop using libedit's<br>filename_completion_function, instead using ast_file_read_dir. This<br>ensures all results are produced from a single call to opendir.<br><br>Change-Id: I8bf51ffaa7ef1606f3bd1b5bb13f1905d72c6134<br>---<br>M include/asterisk/file.h<br>M main/Makefile<br>M main/loader.c<br>3 files changed, 54 insertions(+), 50 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/file.h b/include/asterisk/file.h<br>index 453dc07..c17cb32 100644<br>--- a/include/asterisk/file.h<br>+++ b/include/asterisk/file.h<br>@@ -143,6 +143,11 @@<br> * \param filename the name of the file<br> * \param obj user data object<br> * \return non-zero to stop reading, otherwise zero to continue<br>+ *<br>+ * \note dir_name is not processed by realpath or other functions,<br>+ * symbolic links are not resolved. This ensures dir_name<br>+ * always starts with the exact string originally passed to<br>+ * \ref ast_file_read_dir or \ref ast_file_read_dirs.<br> */<br> typedef int (*ast_file_on_file)(const char *dir_name, const char *filename, void *obj);<br> <br>diff --git a/main/Makefile b/main/Makefile<br>index c724e20..63b65af 100644<br>--- a/main/Makefile<br>+++ b/main/Makefile<br>@@ -149,7 +149,6 @@<br> <br> db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE)<br> asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)<br>-loader.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)<br> json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE)<br> bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE)<br> crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE)<br>diff --git a/main/loader.c b/main/loader.c<br>index afb4054..c495d76 100644<br>--- a/main/loader.c<br>+++ b/main/loader.c<br>@@ -36,7 +36,6 @@<br> #include "asterisk/_private.h"<br> #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */<br> #include <dirent.h><br>-#include <editline/readline.h><br> <br> #include "asterisk/dlinkedlists.h"<br> #include "asterisk/module.h"<br>@@ -56,6 +55,7 @@<br> #include "asterisk/app.h"<br> #include "asterisk/test.h"<br> #include "asterisk/sounds_index.h"<br>+#include "asterisk/cli.h"<br> <br> #include <dlfcn.h><br> <br>@@ -765,57 +765,55 @@<br> }<br> }<br> <br>-static char *module_load_helper(const char *word, int state)<br>-{<br>- struct ast_module *mod;<br>- int which = 0;<br>- char *name;<br>- char *ret = NULL;<br>- char *editline_ret;<br>- char fullpath[PATH_MAX];<br>- int idx = 0;<br>- /* This is needed to avoid listing modules that are already running. */<br>- AST_VECTOR(, char *) running_modules;<br>+struct module_load_word {<br>+ const char *word;<br>+ size_t len;<br>+ size_t moddir_len;<br>+};<br> <br>- AST_VECTOR_INIT(&running_modules, 200);<br>+static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)<br>+{<br>+ struct module_load_word *word = obj;<br>+ struct ast_module *mod;<br>+ char *filename_merged = NULL;<br>+<br>+ /* dir_name will never be shorter than word->moddir_len. */<br>+ dir_name += word->moddir_len;<br>+ if (!ast_strlen_zero(dir_name)) {<br>+ ast_assert(dir_name[0] == '/');<br>+<br>+ dir_name += 1;<br>+ if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {<br>+ /* If we can't allocate the string just give up! */<br>+ return -1;<br>+ }<br>+ filename = filename_merged;<br>+ }<br>+<br>+ if (!strncasecmp(filename, word->word, word->len)) {<br>+ /* Don't list files that are already loaded! */<br>+ mod = find_resource(filename, 0);<br>+ if (!mod || !mod->flags.running) {<br>+ ast_cli_completion_add(ast_strdup(filename));<br>+ }<br>+ }<br>+<br>+ ast_free(filename_merged);<br>+<br>+ return 0;<br>+}<br>+<br>+static void module_load_helper(const char *word)<br>+{<br>+ struct module_load_word word_l = {<br>+ .word = word,<br>+ .len = strlen(word),<br>+ .moddir_len = strlen(ast_config_AST_MODULE_DIR),<br>+ };<br> <br> AST_DLLIST_LOCK(&module_list);<br>- AST_DLLIST_TRAVERSE(&module_list, mod, entry) {<br>- if (mod->flags.running) {<br>- AST_VECTOR_APPEND(&running_modules, mod->resource);<br>- }<br>- }<br>-<br>- if (word[0] == '/') {<br>- /* BUGBUG: we should not support this. */<br>- ast_copy_string(fullpath, word, sizeof(fullpath));<br>- } else {<br>- snprintf(fullpath, sizeof(fullpath), "%s/%s", ast_config_AST_MODULE_DIR, word);<br>- }<br>-<br>- /*<br>- * This is ugly that we keep calling filename_completion_function.<br>- * The only way to avoid this would be to make a copy of the function<br>- * that skips matches found in the running_modules vector.<br>- */<br>- while (!ret && (name = editline_ret = filename_completion_function(fullpath, idx++))) {<br>- if (word[0] != '/') {<br>- name += (strlen(ast_config_AST_MODULE_DIR) + 1);<br>- }<br>-<br>- /* Don't list files that are already loaded! */<br>- if (!AST_VECTOR_GET_CMP(&running_modules, name, !strcasecmp) && ++which > state) {<br>- ret = ast_strdup(name);<br>- }<br>-<br>- ast_std_free(editline_ret);<br>- }<br>-<br>- /* Do not clean-up the elements, they belong to module_list. */<br>- AST_VECTOR_FREE(&running_modules);<br>+ ast_file_read_dirs(ast_config_AST_MODULE_DIR, module_load_helper_on_file, &word_l, -1);<br> AST_DLLIST_UNLOCK(&module_list);<br>-<br>- return ret;<br> }<br> <br> char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int _type)<br>@@ -831,7 +829,9 @@<br> }<br> <br> if (type == AST_MODULE_HELPER_LOAD) {<br>- return module_load_helper(word, state);<br>+ module_load_helper(word);<br>+<br>+ return NULL;<br> }<br> <br> if (type == AST_MODULE_HELPER_RELOAD) {<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/8051">change 8051</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/8051"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I8bf51ffaa7ef1606f3bd1b5bb13f1905d72c6134 </div>
<div style="display:none"> Gerrit-Change-Number: 8051 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>