CLI: Refactor cli_complete.
authorCorey Farrell <git@cfware.com>
Tue, 7 Nov 2017 21:34:40 +0000 (16:34 -0500)
committerCorey Farrell <git@cfware.com>
Tue, 21 Nov 2017 14:48:36 +0000 (09:48 -0500)
* Stop using "_COMMAND NUMMATCHES" on remote consoles.  Using this
  command had doubled the amount of work needed from the Asterisk
  daemon for each completion request.
* Fix code formatting.
* Remove static buffer used to send the command, use the same buffer
  that will receive the results.
* Move sort from ast_cli_display_match_list.

Change-Id: Ie2211b519a3d4bec45bf46e0095bdd01d384cb69

main/asterisk.c

index 46dc9a7..ec8ead1 100644 (file)
@@ -3054,7 +3054,7 @@ static int ast_el_sort_compare(const void *i1, const void *i2)
        return strcasecmp(s1, s2);
 }
 
-static void ast_cli_display_match_list(char **matches, int len, int max)
+static void ast_cli_display_match_list(char **matches, int max)
 {
        int idx = 1;
        /* find out how many entries can be put on one line, with two spaces between strings */
@@ -3064,8 +3064,6 @@ static void ast_cli_display_match_list(char **matches, int len, int max)
                limit = 1;
        }
 
-       qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
-
        for (;;) {
                int numoutputline;
 
@@ -3095,7 +3093,7 @@ static char *cli_complete(EditLine *editline, int ch)
        int nummatches = 0;
        char **matches;
        int retval = CC_ERROR;
-       char buf[2048], savechr;
+       char savechr;
        int res;
 
        LineInfo *lf = (LineInfo *)el_line(editline);
@@ -3116,65 +3114,80 @@ static char *cli_complete(EditLine *editline, int ch)
        len = lf->cursor - ptr;
 
        if (ast_opt_remote) {
-               snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
-               fdsend(ast_consock, buf);
-               if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
-                       return (char*)(CC_ERROR);
+#define CMD_MATCHESARRAY "_COMMAND MATCHESARRAY \"%s\" \"%s\""
+               char *mbuf;
+               char *new_mbuf;
+               int mlen = 0, maxmbuf = 2048;
+
+               /* Start with a 2048 byte buffer */
+               mbuf = ast_malloc(maxmbuf);
+
+               /* This will run snprintf twice at most. */
+               while (mbuf && (mlen = snprintf(mbuf, maxmbuf, CMD_MATCHESARRAY, lf->buffer, ptr)) > maxmbuf) {
+                       /* Return value does not include space for NULL terminator. */
+                       maxmbuf = mlen + 1;
+                       ast_free(mbuf);
+                       mbuf = ast_malloc(maxmbuf);
                }
-               buf[res] = '\0';
-               nummatches = atoi(buf);
-
-               if (nummatches > 0) {
-                       char *mbuf;
-                       char *new_mbuf;
-                       int mlen = 0, maxmbuf = 2048;
-
-                       /* Start with a 2048 byte buffer */
-                       if (!(mbuf = ast_malloc(maxmbuf))) {
-                               *((char *) lf->cursor) = savechr;
-                               return (char *)(CC_ERROR);
-                       }
-                       snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
-                       fdsend(ast_consock, buf);
-                       res = 0;
-                       mbuf[0] = '\0';
-                       while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
-                               if (mlen + 1024 > maxmbuf) {
-                                       /* Every step increment buffer 1024 bytes */
-                                       maxmbuf += 1024;
-                                       new_mbuf = ast_realloc(mbuf, maxmbuf);
-                                       if (!new_mbuf) {
-                                               ast_free(mbuf);
-                                               *((char *) lf->cursor) = savechr;
-                                               return (char *)(CC_ERROR);
-                                       }
-                                       mbuf = new_mbuf;
+
+               if (!mbuf) {
+                       *((char *) lf->cursor) = savechr;
+
+                       return (char *)(CC_ERROR);
+               }
+
+               fdsend(ast_consock, mbuf);
+               res = 0;
+               mlen = 0;
+               mbuf[0] = '\0';
+
+               while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
+                       if (mlen + 1024 > maxmbuf) {
+                               /* Expand buffer to the next 1024 byte increment. */
+                               maxmbuf = mlen + 1024;
+                               new_mbuf = ast_realloc(mbuf, maxmbuf);
+                               if (!new_mbuf) {
+                                       ast_free(mbuf);
+                                       *((char *) lf->cursor) = savechr;
+
+                                       return (char *)(CC_ERROR);
                                }
-                               /* Only read 1024 bytes at a time */
-                               res = read(ast_consock, mbuf + mlen, 1024);
-                               if (res > 0)
-                                       mlen += res;
+                               mbuf = new_mbuf;
+                       }
+                       /* Only read 1024 bytes at a time */
+                       res = read(ast_consock, mbuf + mlen, 1024);
+                       if (res > 0) {
+                               mlen += res;
                        }
-                       mbuf[mlen] = '\0';
+               }
+               mbuf[mlen] = '\0';
 
-                       matches = ast_el_strtoarr(mbuf);
-                       ast_free(mbuf);
-               } else
-                       matches = (char **) NULL;
+               matches = ast_el_strtoarr(mbuf);
+               ast_free(mbuf);
        } else {
-               char **p, *oldbuf=NULL;
-               nummatches = 0;
                matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
-               for (p = matches; p && *p; p++) {
-                       if (!oldbuf || strcmp(*p,oldbuf))
-                               nummatches++;
-                       oldbuf = *p;
-               }
        }
 
        if (matches) {
                int i;
-               int matches_num, maxlen, match_len;
+               int maxlen, match_len;
+
+               while (matches[nummatches + 1]) {
+                       nummatches++;
+               }
+
+               if (ast_opt_remote && nummatches > 1) {
+                       qsort(&matches[0], (size_t)(nummatches), sizeof(char *), ast_el_sort_compare);
+                       nummatches = 1;
+                       i = 1;
+                       while (matches[i + 1]) {
+                               if (strcasecmp(matches[i], matches[i + 1])) {
+                                       /* don't count duplicates. */
+                                       nummatches++;
+                               }
+                               i++;
+                       }
+               }
 
                if (matches[0][0] != '\0') {
                        el_deletestr(editline, (int) len);
@@ -3190,21 +3203,18 @@ static char *cli_complete(EditLine *editline, int ch)
                        /* Must be more than one match */
                        for (i = 1, maxlen = 0; matches[i]; i++) {
                                match_len = strlen(matches[i]);
-                               if (match_len > maxlen)
+                               if (match_len > maxlen) {
                                        maxlen = match_len;
+                               }
                        }
-                       matches_num = i - 1;
-                       if (matches_num >1) {
-                               fprintf(stdout, "\n");
-                               ast_cli_display_match_list(matches, nummatches, maxlen);
-                               retval = CC_REDISPLAY;
-                       } else {
-                               el_insertstr(editline," ");
-                               retval = CC_REFRESH;
-                       }
+
+                       fprintf(stdout, "\n");
+                       ast_cli_display_match_list(matches, maxlen);
+                       retval = CC_REDISPLAY;
                }
-               for (i = 0; matches[i]; i++)
+               for (i = 0; matches[i]; i++) {
                        ast_free(matches[i]);
+               }
                ast_free(matches);
        }