Merged revisions 97350 via svnmerge from
authorTilghman Lesher <tilghman@meg.abyt.es>
Wed, 9 Jan 2008 00:51:59 +0000 (00:51 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Wed, 9 Jan 2008 00:51:59 +0000 (00:51 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r97350 | tilghman | 2008-01-08 18:44:14 -0600 (Tue, 08 Jan 2008) | 5 lines

Allow filename completion on zero-length modules, remove a memory leak, remove
a file descriptor leak, and make filename completion thread-safe.
Patched and tested by tilghman.
(Closes issue #11681)

........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@97364 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/cli.c
main/editline/readline.c

index 94ed6b5..c412d63 100644 (file)
@@ -121,7 +121,7 @@ static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry);
 
 static char *complete_fn(const char *word, int state)
 {
-       char *c;
+       char *c, *d;
        char filename[256];
 
        if (word[0] == '/')
@@ -129,13 +129,15 @@ static char *complete_fn(const char *word, int state)
        else
                snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
 
-       /* XXX the following function is not reentrant, so we better not use it */
-       c = filename_completion_function(filename, state);
+       c = d = filename_completion_function(filename, state);
        
        if (c && word[0] != '/')
                c += (strlen(ast_config_AST_MODULE_DIR) + 1);
+       if (c)
+               c = ast_strdup(c);
+       free(d);
        
-       return c ? ast_strdup(c) : c;
+       return c;
 }
 
 static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
index 442118b..3fbbb79 100644 (file)
@@ -1189,68 +1189,63 @@ tilde_expand(char *txt)
 
 /*
  * return first found file name starting by the ``text'' or NULL if no
- * such file can be found
- * value of ``state'' is ignored
+ * such file can be found.
+ * The first ``state'' matches are ignored.
  *
  * it's caller's responsibility to free returned string
  */
 char *
 filename_completion_function(const char *text, int state)
 {
-       static DIR *dir = NULL;
-       static char *filename = NULL, *dirname = NULL;
-       static size_t filename_len = 0;
+       DIR *dir = NULL;
+       char *filename = NULL, *dirname = NULL;
+       size_t filename_len = 0;
        struct dirent *entry;
        char *temp;
        size_t len;
+       int count = 0;
+
+       temp = strrchr(text, '/');
+       if (temp) {
+               temp++;
+               filename = realloc(filename, strlen(temp) + 1);
+               (void) strcpy(filename, temp);
+               len = temp - text;      /* including last slash */
+               dirname = realloc(dirname, len + 1);
+               (void) strncpy(dirname, text, len);
+               dirname[len] = '\0';
+       } else {
+               filename = strdup(text);
+               dirname = NULL;
+       }
 
-       if (state == 0 || dir == NULL) {
-               if (dir != NULL) {
-                       closedir(dir);
-                       dir = NULL;
-               }
-               temp = strrchr(text, '/');
-               if (temp) {
-                       temp++;
-                       filename = realloc(filename, strlen(temp) + 1);
-                       (void) strcpy(filename, temp);
-                       len = temp - text;      /* including last slash */
-                       dirname = realloc(dirname, len + 1);
-                       (void) strncpy(dirname, text, len);
-                       dirname[len] = '\0';
-               } else {
-                       filename = strdup(text);
-                       dirname = NULL;
-               }
-
-               /* support for ``~user'' syntax */
-               if (dirname && *dirname == '~') {
-                       temp = tilde_expand(dirname);
-                       dirname = realloc(dirname, strlen(temp) + 1);
-                       (void) strcpy(dirname, temp);   /* safe */
-                       free(temp);     /* no longer needed */
-               }
-               /* will be used in cycle */
-               filename_len = strlen(filename);
-               if (filename_len == 0)
-                       return (NULL);  /* no expansion possible */
-
-               dir = opendir(dirname ? dirname : ".");
-               if (!dir)
-                       return (NULL);  /* cannot open the directory */
+       /* support for ``~user'' syntax */
+       if (dirname && *dirname == '~') {
+               temp = tilde_expand(dirname);
+               dirname = realloc(dirname, strlen(temp) + 1);
+               (void) strcpy(dirname, temp);   /* safe */
+               free(temp);     /* no longer needed */
        }
+       /* will be used in cycle */
+       filename_len = strlen(filename);
+
+       dir = opendir(dirname ? dirname : ".");
+       if (!dir)
+               return (NULL);  /* cannot open the directory */
+
        /* find the match */
        while ((entry = readdir(dir)) != NULL) {
                /* otherwise, get first entry where first */
                /* filename_len characters are equal      */
-               if (entry->d_name[0] == filename[0]
+               if (
 #if defined(__SVR4) || defined(__linux__)
-                   && strlen(entry->d_name) >= filename_len
+                   strlen(entry->d_name) >= filename_len
 #else
-                   && entry->d_namlen >= filename_len
+                   entry->d_namlen >= filename_len
 #endif
                    && strncmp(entry->d_name, filename,
-                       filename_len) == 0)
+                       filename_len) == 0
+                       && (state-- == 0))
                        break;
        }
 
@@ -1272,6 +1267,7 @@ filename_completion_function(const char *text, int state)
                        strcat(temp, "/");      /* safe */
        } else
                temp = NULL;
+       closedir(dir);
 
        return (temp);
 }