]> granicus.if.org Git - neomutt/commitdiff
Convert query to rxi-vec
authorPietro Cerutti <gahr@gahr.ch>
Wed, 7 Aug 2019 11:45:42 +0000 (11:45 +0000)
committerRichard Russon <rich@flatcap.org>
Mon, 21 Oct 2019 18:58:45 +0000 (19:58 +0100)
query.c

diff --git a/query.c b/query.c
index f9d439cba099899761a1b00a70fee3fb910e5114..82faacd85a88b2d449070ce693d6214bf9b70418 100644 (file)
--- a/query.c
+++ b/query.c
 #include "muttlib.h"
 #include "opcodes.h"
 #include "send.h"
+#include "rxi-vec/vec.h"
 
 /* These Config Variables are only used in query.c */
 char *C_QueryCommand; ///< Config: External command to query and external address book
 char *C_QueryFormat; ///< Config: printf-like format string for the query menu (address book)
 
 /**
- * struct Query - An entry from an external address-book
+ * struct Query - An entry in the menu, populated by an external address-book
  */
 struct Query
 {
+  bool tagged;
   int num;
   struct AddressList addr;
   char *name;
   char *other;
-  struct Query *next;
 };
 
-/**
- * struct QueryEntry - An entry in a selectable list of Query's
- */
-struct QueryEntry
-{
-  bool tagged;
-  struct Query *data;
-};
+typedef vec_t(struct Query*) QueryVector;
+
 
 static const struct Mapping QueryHelp[] = {
   { N_("Exit"), OP_EXIT },
@@ -122,39 +117,45 @@ static struct Query *query_new(void)
 }
 
 /**
- * query_free - Free a Query
- * @param[out] query Query to free
+ * query_free - Free one query
+ * @param[out] qp Query to free
  */
-static void query_free(struct Query **query)
+static void query_free(struct Query **qp)
 {
-  if (!query)
+  if (!qp || !*qp)
     return;
 
-  struct Query *p = NULL;
+  struct Query *q = *qp;
+  mutt_addrlist_clear(&q->addr);
+  FREE(&q->name);
+  FREE(&q->other);
+  FREE(qp);
+}
 
-  while (*query)
+/**
+ * query_free - Free all elements of a QueryVector an reinitialize it
+ * @param[out] vector QueryVector to free
+ */
+static void query_freevector(QueryVector *vector)
+{
+  struct Query *q;
+  int iter;
+  vec_foreach(vector, q, iter)
   {
-    p = *query;
-    *query = (*query)->next;
-
-    mutt_addrlist_clear(&p->addr);
-    FREE(&p->name);
-    FREE(&p->other);
-    FREE(&p);
+    query_free(&q);
   }
+  vec_deinit(vector);
 }
 
 /**
  * run_query - Run an external program to find Addresses
- * @param s     String to match
- * @param quiet If true, don't print progress messages
- * @retval ptr Query List of results
+ * @param queries QueryVector where results are appended
+ * @param s      String to match
+ * @param quiet  If true, don't print progress messages
  */
-static struct Query *run_query(char *s, int quiet)
+static void run_query(QueryVector *queries, char *s, int quiet)
 {
   FILE *fp = NULL;
-  struct Query *first = NULL;
-  struct Query *cur = NULL;
   char *buf = NULL;
   size_t buflen;
   int dummy = 0;
@@ -170,7 +171,7 @@ static struct Query *run_query(char *s, int quiet)
   {
     mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", mutt_b2s(cmd));
     mutt_buffer_pool_release(&cmd);
-    return 0;
+    return;
   }
   mutt_buffer_pool_release(&cmd);
 
@@ -185,26 +186,17 @@ static struct Query *run_query(char *s, int quiet)
     p = strtok(buf, "\t\n");
     if (p)
     {
-      if (!first)
-      {
-        first = query_new();
-        cur = first;
-      }
-      else
-      {
-        cur->next = query_new();
-        cur = cur->next;
-      }
-
-      mutt_addrlist_parse(&cur->addr, p);
+      struct Query *q = query_new();
+      mutt_addrlist_parse(&q->addr, p);
       p = strtok(NULL, "\t\n");
       if (p)
       {
-        cur->name = mutt_str_strdup(p);
+        q->name = mutt_str_strdup(p);
         p = strtok(NULL, "\t\n");
         if (p)
-          cur->other = mutt_str_strdup(p);
+          q->other = mutt_str_strdup(p);
       }
+      vec_push(queries, q);
     }
   }
   FREE(&buf);
@@ -220,8 +212,6 @@ static struct Query *run_query(char *s, int quiet)
     if (!quiet)
       mutt_message("%s", msg);
   }
-
-  return first;
 }
 
 /**
@@ -231,8 +221,7 @@ static struct Query *run_query(char *s, int quiet)
  */
 static int query_search(struct Menu *menu, regex_t *rx, int line)
 {
-  struct QueryEntry *table = menu->data;
-  struct Query *query = table[line].data;
+  struct Query *query = ((QueryVector *)menu->data)->data[line];
 
   if (query->name && !regexec(rx, query->name, 0, NULL, 0))
     return 0;
@@ -270,8 +259,7 @@ static const char *query_format_str(char *buf, size_t buflen, size_t col, int co
                                     const char *if_str, const char *else_str,
                                     unsigned long data, MuttFormatFlags flags)
 {
-  struct QueryEntry *entry = (struct QueryEntry *) data;
-  struct Query *query = entry->data;
+  struct Query *query = (struct Query *) data;
   char fmt[128];
   char tmp[256] = { 0 };
   bool optional = (flags & MUTT_FORMAT_OPTIONAL);
@@ -297,7 +285,7 @@ static const char *query_format_str(char *buf, size_t buflen, size_t col, int co
       break;
     case 't':
       snprintf(fmt, sizeof(fmt), "%%%sc", prec);
-      snprintf(buf, buflen, fmt, entry->tagged ? '*' : ' ');
+      snprintf(buf, buflen, fmt, query->tagged ? '*' : ' ');
       break;
     default:
       snprintf(fmt, sizeof(fmt), "%%%sc", prec);
@@ -320,11 +308,11 @@ static const char *query_format_str(char *buf, size_t buflen, size_t col, int co
  */
 static void query_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
 {
-  struct QueryEntry *entry = &((struct QueryEntry *) menu->data)[line];
+  struct Query *query = ((QueryVector*) menu->data)->data[line];
 
-  entry->data->num = line;
+  query->num = line;
   mutt_expando_format(buf, buflen, 0, menu->indexwin->cols, NONULL(C_QueryFormat),
-                      query_format_str, (unsigned long) entry, MUTT_FORMAT_ARROWCURSOR);
+                      query_format_str, (unsigned long) query, MUTT_FORMAT_ARROWCURSOR);
 }
 
 /**
@@ -332,276 +320,220 @@ static void query_make_entry(char *buf, size_t buflen, struct Menu *menu, int li
  */
 static int query_tag(struct Menu *menu, int sel, int act)
 {
-  struct QueryEntry *cur = &((struct QueryEntry *) menu->data)[sel];
-  bool ot = cur->tagged;
+  struct Query *q = ((QueryVector *) menu->data)->data[sel];
+  bool ot = q->tagged;
 
-  cur->tagged = ((act >= 0) ? act : !cur->tagged);
-  return cur->tagged - ot;
+  q->tagged = ((act >= 0) ? act : !q->tagged);
+  return q->tagged - ot;
 }
 
 /**
  * query_menu - Get the user to enter an Address Query
  * @param buf     Buffer for the query
  * @param buflen  Length of buffer
- * @param results Query List
+ * @param queries QueryVector
  * @param retbuf  If true, populate the results
  */
-static void query_menu(char *buf, size_t buflen, struct Query *results, bool retbuf)
+static void query_menu(char *buf, size_t buflen, QueryVector *queries, bool retbuf)
 {
   struct Menu *menu = NULL;
-  struct QueryEntry *query_table = NULL;
-  struct Query *queryp = NULL;
   char title[256];
 
-  if (!results)
+  if (queries->length == 0)
   {
     /* Prompt for Query */
     if ((mutt_get_field(_("Query: "), buf, buflen, 0) == 0) && (buf[0] != '\0'))
     {
-      results = run_query(buf, 0);
+      run_query(queries, buf, 0);
     }
   }
 
-  if (results)
+  if (queries->length == 0)
+    return;
+
+  snprintf(title, sizeof(title), _("Query '%s'"), buf);
+
+  menu = mutt_menu_new(MENU_QUERY);
+  menu->menu_make_entry = query_make_entry;
+  menu->menu_search = query_search;
+  menu->menu_tag = query_tag;
+  menu->title = title;
+  menu->data = queries;
+  menu->max = queries->length;
+  char helpstr[1024];
+  menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_QUERY, QueryHelp);
+  mutt_menu_push_current(menu);
+
+  int done = 0;
+  while (done == 0)
   {
-    snprintf(title, sizeof(title), _("Query '%s'"), buf);
-
-    menu = mutt_menu_new(MENU_QUERY);
-    menu->menu_make_entry = query_make_entry;
-    menu->menu_search = query_search;
-    menu->menu_tag = query_tag;
-    menu->title = title;
-    char helpstr[1024];
-    menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_QUERY, QueryHelp);
-    mutt_menu_push_current(menu);
-
-    /* count the number of results */
-    for (queryp = results; queryp; queryp = queryp->next)
-      menu->max++;
-
-    query_table = mutt_mem_calloc(menu->max, sizeof(struct QueryEntry));
-    menu->data = query_table;
-
-    queryp = results;
-    for (int i = 0; queryp; queryp = queryp->next, i++)
-      query_table[i].data = queryp;
-
-    int done = 0;
-    while (done == 0)
+    const int op = mutt_menu_loop(menu);
+    switch (op)
     {
-      const int op = mutt_menu_loop(menu);
-      switch (op)
-      {
-        case OP_QUERY_APPEND:
-        case OP_QUERY:
-          if ((mutt_get_field(_("Query: "), buf, buflen, 0) == 0) && (buf[0] != '\0'))
+      case OP_QUERY_APPEND:
+      case OP_QUERY:
+        if ((mutt_get_field(_("Query: "), buf, buflen, 0) == 0) && (buf[0] != '\0'))
+        {
+          int prev_length = queries->length;
+          run_query(queries, buf, 0);
+
+          menu->redraw = REDRAW_FULL;
+          if (queries->length != prev_length)
           {
-            struct Query *newresults = run_query(buf, 0);
+            snprintf(title, sizeof(title), _("Query '%s'"), buf);
 
-            menu->redraw = REDRAW_FULL;
-            if (newresults)
+            if (op == OP_QUERY)
             {
-              snprintf(title, sizeof(title), _("Query '%s'"), buf);
-
-              if (op == OP_QUERY)
-              {
-                query_free(&results);
-                results = newresults;
-                FREE(&query_table);
-              }
-              else
-              {
-                /* append */
-                for (queryp = results; queryp->next; queryp = queryp->next)
-                  ;
-
-                queryp->next = newresults;
-              }
-
-              menu->current = 0;
-              mutt_menu_pop_current(menu);
-              mutt_menu_free(&menu);
-              menu = mutt_menu_new(MENU_QUERY);
-              menu->menu_make_entry = query_make_entry;
-              menu->menu_search = query_search;
-              menu->menu_tag = query_tag;
-              menu->title = title;
-              menu->help = mutt_compile_help(helpstr, sizeof(helpstr), MENU_QUERY, QueryHelp);
-              mutt_menu_push_current(menu);
-
-              /* count the number of results */
-              for (queryp = results; queryp; queryp = queryp->next)
-                menu->max++;
-
-              if (op == OP_QUERY)
-              {
-                menu->data = query_table =
-                    mutt_mem_calloc(menu->max, sizeof(struct QueryEntry));
-
-                queryp = results;
-                for (int i = 0; queryp; queryp = queryp->next, i++)
-                  query_table[i].data = queryp;
-              }
-              else
+              /* remove the old items */
+              for (size_t i = 0; i < prev_length; ++i)
               {
-                bool clear = false;
-
-                /* append */
-                mutt_mem_realloc(&query_table, menu->max * sizeof(struct QueryEntry));
-
-                menu->data = query_table;
-
-                queryp = results;
-                for (int i = 0; queryp; queryp = queryp->next, i++)
-                {
-                  /* once we hit new entries, clear/init the tag */
-                  if (queryp == newresults)
-                    clear = true;
-
-                  query_table[i].data = queryp;
-                  if (clear)
-                    query_table[i].tagged = false;
-                }
+                query_free(&queries->data[i]);
               }
+              vec_splice(queries, 0, prev_length);
             }
-          }
-          break;
-
-        case OP_CREATE_ALIAS:
-          if (menu->tagprefix)
-          {
-            struct AddressList naddr = TAILQ_HEAD_INITIALIZER(naddr);
-
-            for (int i = 0; i < menu->max; i++)
+            else
             {
-              if (query_table[i].tagged)
-              {
-                struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-                if (result_to_addr(&al, query_table[i].data))
-                {
-                  mutt_addrlist_copy(&naddr, &al, false);
-                  mutt_addrlist_clear(&al);
-                }
-              }
+              /* append - run_query appends by default, so nothing to do*/
             }
 
-            mutt_alias_create(NULL, &naddr);
-            mutt_addrlist_clear(&naddr);
+            menu->max = queries->length;
           }
-          else
+        }
+        break;
+
+      case OP_CREATE_ALIAS:
+        if (menu->tagprefix)
+        {
+          struct AddressList naddr = TAILQ_HEAD_INITIALIZER(naddr);
+
+          for (int i = 0; i < menu->max; i++)
           {
-            struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-            if (result_to_addr(&al, query_table[menu->current].data))
+            if (queries->data[i]->tagged)
             {
-              mutt_alias_create(NULL, &al);
-              mutt_addrlist_clear(&al);
+              struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+              if (result_to_addr(&al, queries->data[i]))
+              {
+                mutt_addrlist_copy(&naddr, &al, false);
+                mutt_addrlist_clear(&al);
+              }
             }
           }
-          break;
 
-        case OP_GENERIC_SELECT_ENTRY:
-          if (retbuf)
+          mutt_alias_create(NULL, &naddr);
+          mutt_addrlist_clear(&naddr);
+        }
+        else
+        {
+          struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+          if (result_to_addr(&al, queries->data[menu->current]))
           {
-            done = 2;
-            break;
+            mutt_alias_create(NULL, &al);
+            mutt_addrlist_clear(&al);
           }
-        /* fallthrough */
-        case OP_MAIL:
+        }
+        break;
+
+      case OP_GENERIC_SELECT_ENTRY:
+        if (retbuf)
+        {
+          done = 2;
+          break;
+        }
+      /* fallthrough */
+      case OP_MAIL:
+      {
+        struct Email *e = email_new();
+        e->env = mutt_env_new();
+        if (!menu->tagprefix)
         {
-          struct Email *e = email_new();
-          e->env = mutt_env_new();
-          if (!menu->tagprefix)
+          struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+          if (result_to_addr(&al, queries->data[menu->current]))
           {
-            struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-            if (result_to_addr(&al, query_table[menu->current].data))
-            {
-              mutt_addrlist_copy(&e->env->to, &al, false);
-              mutt_addrlist_clear(&al);
-            }
+            mutt_addrlist_copy(&e->env->to, &al, false);
+            mutt_addrlist_clear(&al);
           }
-          else
+        }
+        else
+        {
+          for (int i = 0; i < menu->max; i++)
           {
-            for (int i = 0; i < menu->max; i++)
+            if (queries->data[i]->tagged)
             {
-              if (query_table[i].tagged)
+              struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+              if (result_to_addr(&al, queries->data[i]))
               {
-                struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-                if (result_to_addr(&al, query_table[i].data))
-                {
-                  mutt_addrlist_copy(&e->env->to, &al, false);
-                  mutt_addrlist_clear(&al);
-                }
+                mutt_addrlist_copy(&e->env->to, &al, false);
+                mutt_addrlist_clear(&al);
               }
             }
           }
-          ci_send_message(SEND_NO_FLAGS, e, NULL, Context, NULL);
-          menu->redraw = REDRAW_FULL;
-          break;
         }
-
-        case OP_EXIT:
-          done = 1;
-          break;
+        ci_send_message(SEND_NO_FLAGS, e, NULL, Context, NULL);
+        menu->redraw = REDRAW_FULL;
+        break;
       }
+
+      case OP_EXIT:
+        done = 1;
+        break;
     }
+  }
 
-    /* if we need to return the selected entries */
-    if (retbuf && (done == 2))
-    {
-      bool tagged = false;
-      size_t curpos = 0;
+  /* if we need to return the selected entries */
+  if (retbuf && (done == 2))
+  {
+    bool tagged = false;
+    size_t curpos = 0;
 
-      memset(buf, 0, buflen);
+    memset(buf, 0, buflen);
 
-      /* check for tagged entries */
-      for (int i = 0; i < menu->max; i++)
+    /* check for tagged entries */
+    for (int i = 0; i < menu->max; i++)
+    {
+      if (queries->data[i]->tagged)
       {
-        if (query_table[i].tagged)
+        if (curpos == 0)
         {
-          if (curpos == 0)
+          struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+          if (result_to_addr(&al, queries->data[i]))
           {
-            struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-            if (result_to_addr(&al, query_table[i].data))
-            {
-              mutt_addrlist_to_local(&al);
-              tagged = true;
-              mutt_addrlist_write(buf, buflen, &al, false);
-              curpos = mutt_str_strlen(buf);
-              mutt_addrlist_clear(&al);
-            }
+            mutt_addrlist_to_local(&al);
+            tagged = true;
+            mutt_addrlist_write(buf, buflen, &al, false);
+            curpos = mutt_str_strlen(buf);
+            mutt_addrlist_clear(&al);
           }
-          else if (curpos + 2 < buflen)
+        }
+        else if (curpos + 2 < buflen)
+        {
+          struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+          if (result_to_addr(&al, queries->data[i]))
           {
-            struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-            if (result_to_addr(&al, query_table[i].data))
-            {
-              mutt_addrlist_to_local(&al);
-              strcat(buf, ", ");
-              mutt_addrlist_write(buf + curpos + 1, buflen - curpos - 1, &al, false);
-              curpos = mutt_str_strlen(buf);
-              mutt_addrlist_clear(&al);
-            }
+            mutt_addrlist_to_local(&al);
+            strcat(buf, ", ");
+            mutt_addrlist_write(buf + curpos + 1, buflen - curpos - 1, &al, false);
+            curpos = mutt_str_strlen(buf);
+            mutt_addrlist_clear(&al);
           }
         }
       }
-      /* then enter current message */
-      if (!tagged)
+    }
+    /* then enter current message */
+    if (!tagged)
+    {
+      struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
+      if (result_to_addr(&al, queries->data[menu->current]))
       {
-        struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-        if (result_to_addr(&al, query_table[menu->current].data))
-        {
-          mutt_addrlist_to_local(&al);
-          mutt_addrlist_write(buf, buflen, &al, false);
-          mutt_addrlist_clear(&al);
-        }
+        mutt_addrlist_to_local(&al);
+        mutt_addrlist_write(buf, buflen, &al, false);
+        mutt_addrlist_clear(&al);
       }
     }
-
-    query_free(&results);
-    FREE(&query_table);
-    mutt_menu_pop_current(menu);
-    mutt_menu_free(&menu);
   }
+
+  query_freevector(queries);
+  mutt_menu_pop_current(menu);
+  mutt_menu_free(&menu);
 }
 
 /**
@@ -618,26 +550,28 @@ int mutt_query_complete(char *buf, size_t buflen)
     return 0;
   }
 
-  struct Query *results = run_query(buf, 1);
-  if (results)
+  QueryVector queries;
+  vec_init(&queries);
+  run_query(&queries, buf, 1);
+  if (queries.length)
   {
     /* only one response? */
-    if (!results->next)
+    if (queries.length == 1)
     {
       struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
-      if (result_to_addr(&al, results))
+      if (result_to_addr(&al, queries.data[0]))
       {
         mutt_addrlist_to_local(&al);
         buf[0] = '\0';
         mutt_addrlist_write(buf, buflen, &al, false);
         mutt_addrlist_clear(&al);
-        query_free(&results);
+        query_freevector(&queries);
         mutt_clear_error();
       }
       return 0;
     }
     /* multiple results, choose from query menu */
-    query_menu(buf, buflen, results, true);
+    query_menu(buf, buflen, &queries, true);
   }
   return 0;
 }
@@ -655,14 +589,14 @@ void mutt_query_menu(char *buf, size_t buflen)
     return;
   }
 
+  char tmp[256] = { 0 };
   if (!buf)
   {
-    char tmp[256] = { 0 };
-
-    query_menu(tmp, sizeof(tmp), NULL, false);
-  }
-  else
-  {
-    query_menu(buf, buflen, NULL, true);
+    buf = tmp;
+    buflen = sizeof(tmp);
   }
+
+  QueryVector queries;
+  vec_init(&queries);
+  query_menu(buf, buflen, &queries, true);
 }