]> granicus.if.org Git - neomutt/commitdiff
tags: Don't duplicate tags allocation
authorMehdi Abaakouk <sileht@sileht.net>
Wed, 20 Sep 2017 09:05:35 +0000 (11:05 +0200)
committerRichard Russon <rich@flatcap.org>
Tue, 3 Oct 2017 12:47:31 +0000 (13:47 +0100)
The HeaderTags and TagList structure can be replaced
by a simple linked list.

13 files changed:
copy.c
curs_main.c
hcache/hcache.c
hdrline.c
header.h
imap/imap.c
imap/message.c
mutt.h
mutt_notmuch.c
mutt_tags.c
mutt_tags.h
muttlib.c
pattern.c

diff --git a/copy.c b/copy.c
index f3ceaa70a571f75774b72d12146742d0dd6d97ce..71014bd7d06661067816d573607fc9115bcc08d2 100644 (file)
--- a/copy.c
+++ b/copy.c
@@ -465,13 +465,14 @@ int mutt_copy_header(FILE *in, struct Header *h, FILE *out, int flags, const cha
       fputs(buf, out);
       fputc('\n', out);
     }
-    const char *tags = driver_tags_get(h->tags);
+    char *tags = driver_tags_get(&h->tags);
     if (tags && !(option(OPT_WEED) && mutt_matches_ignore("tags")))
     {
       fputs("Tags: ", out);
       fputs(tags, out);
       fputc('\n', out);
     }
+    FREE(&tags);
   }
 #endif
 
index 85fdcc2a5278d6920cd233edfd24ebe30f7598da..f480403c8a7fc0dd22220bc9c075197d0210f0d7 100644 (file)
@@ -1865,8 +1865,11 @@ int mutt_index_menu(void)
         CHECK_MSGCOUNT;
         CHECK_VISIBLE;
         CHECK_READONLY;
-
-        rc = mx_tags_editor(Context, tag ? NULL : driver_tags_get_with_hidden(CURHDR->tags), buf, sizeof(buf));
+        char *tags = NULL;
+        if (!tag)
+          tags = driver_tags_get_with_hidden(&CURHDR->tags);
+        rc = mx_tags_editor(Context, tags, buf, sizeof(buf));
+        FREE(&tags);
         if (rc < 0)
           break;
         else if (rc == 0)
index 2e6c0c96c467f1453c684c544dc82814267bb783..6f210d306d0bfe48c230ee0ee98f15959e2daa02 100644 (file)
@@ -60,6 +60,7 @@
 #include "list.h"
 #include "mbyte.h"
 #include "mutt_regex.h"
+#include "mutt_tags.h"
 #include "parameter.h"
 #include "protos.h"
 #include "rfc822.h"
@@ -685,7 +686,7 @@ static void *hcache_dump(header_cache_t *h, struct Header *header, int *off,
   nh.path = NULL;
   nh.tree = NULL;
   nh.thread = NULL;
-  nh.tags = NULL;
+  STAILQ_INIT(&nh.tags);
 #ifdef MIXMASTER
   STAILQ_INIT(&nh.chain);
 #endif
index 7b96913bf272fb89371580ff51dd6137a024d3e2..b7c1bea69d0fcc17aec03bcd9c6c3210a3e557bb 100644 (file)
--- a/hdrline.c
+++ b/hdrline.c
@@ -510,7 +510,7 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
   struct HdrFormatInfo *hfi = (struct HdrFormatInfo *) data;
   struct Header *hdr = NULL, *htmp = NULL;
   struct Context *ctx = NULL;
-  char fmt[SHORT_STRING], buf2[LONG_STRING], *p = NULL;
+  char fmt[SHORT_STRING], buf2[LONG_STRING], *p, *tags = NULL;
   char *wch = NULL;
   int do_locales, i;
   int optional = (flags & MUTT_FORMAT_OPTIONAL);
@@ -840,20 +840,20 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
         optional = 0;
       break;
 
-    case 'g':
+    case 'g':;
+      tags = driver_tags_get_transformed(&hdr->tags);
       if (!optional)
       {
         colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAGS);
-        mutt_format_s(dest + colorlen, destlen - colorlen, prefix,
-                      driver_tags_get_transformed(hdr->tags));
+        mutt_format_s(dest + colorlen, destlen - colorlen, prefix, NONULL(tags));
         add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
       }
-      else if (!driver_tags_get_transformed(hdr->tags))
+      else if (!tags)
         optional = 0;
+      FREE(&tags);
       break;
 
     case 'G':;
-      const char *tag_transformed = NULL;
       char format[3];
       char *tag = NULL;
 
@@ -866,11 +866,11 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
         tag = hash_find(TagFormats, format);
         if (tag)
         {
-          tag_transformed = driver_tags_get_transformed_for(tag, hdr->tags);
+          tags = driver_tags_get_transformed_for(tag, &hdr->tags);
           colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAG);
-          mutt_format_s(dest + colorlen, destlen - colorlen, prefix,
-                        (tag_transformed) ? tag_transformed : "");
+          mutt_format_s(dest + colorlen, destlen - colorlen, prefix, NONULL(tags));
           add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+          FREE(&tags);
         }
         src++;
       }
@@ -881,9 +881,12 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
         format[2] = 0;
 
         tag = hash_find(TagFormats, format);
-        if (tag)
-          if (driver_tags_get_transformed_for(tag, hdr->tags) == NULL)
+        if (tag) {
+          tags = driver_tags_get_transformed_for(tag, &hdr->tags);
+          if (!tags)
             optional = 0;
+          FREE(&tags);
+        }
       }
       break;
 
@@ -904,22 +907,20 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
       break;
 
     case 'J':;
-      const char *tags = driver_tags_get_transformed(hdr->tags);
+      tags = driver_tags_get_transformed(&hdr->tags);
       if (tags)
       {
         i = 1; /* reduce reuse recycle */
-        htmp = NULL;
-
-        if (flags & MUTT_FORMAT_TREE &&
-            (hdr->thread->prev && hdr->thread->prev->message &&
-             driver_tags_get_transformed(hdr->thread->prev->message->tags)))
-          htmp = hdr->thread->prev->message;
-        else if (flags & MUTT_FORMAT_TREE &&
-                 (hdr->thread->parent && hdr->thread->parent->message &&
-                  driver_tags_get_transformed(hdr->thread->parent->message->tags)))
-          htmp = hdr->thread->parent->message;
-        if (htmp && mutt_strcasecmp(tags, driver_tags_get_transformed(htmp->tags)) == 0)
-          i = 0;
+        if (flags & MUTT_FORMAT_TREE){
+          char *parent_tags = NULL;
+          if (hdr->thread->prev && hdr->thread->prev->message)
+            parent_tags = driver_tags_get_transformed(&hdr->thread->prev->message->tags);
+          if (!parent_tags && hdr->thread->parent && hdr->thread->parent->message)
+            parent_tags = driver_tags_get_transformed(&hdr->thread->parent->message->tags);
+          if (parent_tags && mutt_strcasecmp(tags, parent_tags) == 0)
+            i = 0;
+          FREE(&parent_tags);
+        }
       }
       else
         i = 0;
@@ -933,6 +934,7 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
       else
         mutt_format_s(dest + colorlen, destlen - colorlen, prefix, "");
       add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+      FREE(&tags);
       break;
 
     case 'l':
index 278ff3e6fdb2c238fa5f64a525dcb894b4c4fc4e..75c2df138e96e1ba5b1767d488abf81fd3f4fdf7 100644 (file)
--- a/header.h
+++ b/header.h
@@ -109,7 +109,8 @@ struct Header
   int refno; /**< message number on server */
 #endif
 
-  struct TagHead *tags; /**< for drivers that support server tagging */
+  struct TagHead tags; /**< for drivers that support server tagging */
+
 #if defined(USE_POP) || defined(USE_IMAP) || defined(USE_NNTP) || defined(USE_NOTMUCH)
   void *data;                       /**< driver-specific data */
   void (*free_cb)(struct Header *); /**< driver-specific data free function */
@@ -124,6 +125,7 @@ static inline struct Header *mutt_new_header(void)
 #ifdef MIXMASTER
   STAILQ_INIT(&h->chain);
 #endif
+  STAILQ_INIT(&h->tags);
   return h;
 }
 
index cb06916e4855e0d9c85e9a028a8619d690294bc3..86595db460f1ec7d776f15a95d282febe44251e8 100644 (file)
@@ -1143,6 +1143,7 @@ int imap_sync_message_for_copy(struct ImapData *idata, struct Header *hdr,
                                struct Buffer *cmd, int *err_continue)
 {
   char flags[LONG_STRING];
+  char *tags;
   char uid[11];
 
   if (!compare_flags_for_copy(hdr))
@@ -1172,8 +1173,11 @@ int imap_sync_message_for_copy(struct ImapData *idata, struct Header *hdr,
     if (HEADER_DATA(hdr)->flags_system)
       safe_strcat(flags, sizeof(flags), HEADER_DATA(hdr)->flags_system);
     /* set custom flags */
-    if (driver_tags_get_with_hidden(hdr->tags))
-      safe_strcat(flags, sizeof(flags), driver_tags_get_with_hidden(hdr->tags));
+    tags = driver_tags_get_with_hidden(&hdr->tags);
+    if (tags) {
+      safe_strcat(flags, sizeof(flags), tags);
+      FREE(&tags);
+    }
   }
 
   mutt_remove_trailing_ws(flags);
@@ -1221,7 +1225,7 @@ int imap_sync_message_for_copy(struct ImapData *idata, struct Header *hdr,
 
   /* server have now the updated flags */
   FREE(&HEADER_DATA(hdr)->flags_remote);
-  HEADER_DATA(hdr)->flags_remote = safe_strdup(driver_tags_get_with_hidden(hdr->tags));
+  HEADER_DATA(hdr)->flags_remote = driver_tags_get_with_hidden(&hdr->tags);
 
   hdr->active = true;
   if (hdr->deleted == HEADER_DATA(hdr)->deleted)
@@ -1427,9 +1431,9 @@ static int imap_commit_message_tags(struct Context *ctx, struct Header *h, char
 
   /* We are good sync them */
   mutt_debug(1, "NEW TAGS: %d\n", tags);
-  driver_tags_replace(h->tags, tags);
+  driver_tags_replace(&h->tags, tags);
   FREE(&HEADER_DATA(h)->flags_remote);
-  HEADER_DATA(h)->flags_remote = safe_strdup(driver_tags_get_with_hidden(h->tags));
+  HEADER_DATA(h)->flags_remote = driver_tags_get_with_hidden(&h->tags);
   return 0;
 }
 
index 319129b8e71ed1d6595044a3903a50cc47febb7c..c54d6a9efd261f427803e550ef72eb0e889b1c17 100644 (file)
@@ -636,8 +636,8 @@ int imap_read_headers(struct ImapData *idata, unsigned int msn_begin, unsigned i
           ctx->hdrs[idx]->changed = h.data->changed;
           /*  ctx->hdrs[msgno]->received is restored from mutt_hcache_restore */
           ctx->hdrs[idx]->data = (void *) (h.data);
-          driver_tags_init(ctx->hdrs[idx]->tags);
-          driver_tags_replace(ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
+          STAILQ_INIT(&ctx->hdrs[idx]->tags);
+          driver_tags_replace(&ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
 
           ctx->msgcount++;
           ctx->size += ctx->hdrs[idx]->content->length;
@@ -756,8 +756,8 @@ int imap_read_headers(struct ImapData *idata, unsigned int msn_begin, unsigned i
         ctx->hdrs[idx]->changed = h.data->changed;
         ctx->hdrs[idx]->received = h.received;
         ctx->hdrs[idx]->data = (void *) (h.data);
-        driver_tags_init(ctx->hdrs[idx]->tags);
-        driver_tags_replace(ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
+        STAILQ_INIT(&ctx->hdrs[idx]->tags);
+        driver_tags_replace(&ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
 
         if (maxuid < h.data->uid)
           maxuid = h.data->uid;
@@ -1480,7 +1480,7 @@ char *imap_set_flags(struct ImapData *idata, struct Header *h, char *s, int *ser
     return NULL;
 
   /* Update tags system */
-  driver_tags_replace(h->tags, safe_strdup(hd->flags_remote));
+  driver_tags_replace(&h->tags, safe_strdup(hd->flags_remote));
 
   /* YAUH (yet another ugly hack): temporarily set context to
    * read-write even if it's read-only, so *server* updates of
diff --git a/mutt.h b/mutt.h
index c97a1cb049449623a232541206fbc15d53533f43..35da5ef250fb0ae8db420aad231b3c52b9acc42b 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -34,6 +34,7 @@ struct ReplaceList;
 struct RegexList;
 struct State;
 struct ListHead;
+struct TagHead;
 struct Mapping;
 
 /* On OS X 10.5.x, wide char functions are inlined by default breaking
index a8015603c0fcee64924cb4e138f013ca713b7a10..484a890e2068febe9dcdcd93813574a5187c258d 100644 (file)
@@ -842,6 +842,7 @@ static int update_header_tags(struct Header *h, notmuch_message_t *msg)
 #endif
   notmuch_tags_t *tags = NULL;
   char *new_tags = NULL;
+  char *old_tags = NULL;
 
   mutt_debug(2, "nm: tags update requested (%s)\n", data->virtual_id);
 
@@ -856,17 +857,28 @@ static int update_header_tags(struct Header *h, notmuch_message_t *msg)
     mutt_str_append_item(&new_tags, t, ' ');
   }
 
-  if (driver_tags_get(h->tags) && new_tags && (strcmp(driver_tags_get(h->tags), new_tags) == 0))
+
+  old_tags = driver_tags_get(&h->tags);
+
+  if (new_tags && old_tags && (strcmp(old_tags, new_tags) == 0))
   {
+    FREE(&old_tags);
     FREE(&new_tags);
     mutt_debug(2, "nm: tags unchanged\n");
     return 1;
   }
 
   /* new version */
-  driver_tags_replace(h->tags, new_tags);
-  mutt_debug(2, "nm: new tags: '%s'\n", driver_tags_get(h->tags));
-  mutt_debug(2, "nm: new tag transforms: '%s'\n", driver_tags_get_transformed(h->tags));
+  driver_tags_replace(&h->tags, new_tags);
+  FREE(&new_tags);
+
+  new_tags = driver_tags_get_transformed(&h->tags);
+  mutt_debug(2, "nm: new tags: '%s'\n", new_tags);
+  FREE(&new_tags);
+
+  new_tags = driver_tags_get(&h->tags);
+  mutt_debug(2, "nm: new tag transforms: '%s'\n", new_tags);
+  FREE(&new_tags);
 
   return 0;
 }
@@ -962,7 +974,6 @@ static int init_header(struct Header *h, const char *path, notmuch_message_t *ms
 
   h->data = safe_calloc(1, sizeof(struct NmHdrData));
   h->free_cb = deinit_header;
-  driver_tags_init(h->tags);
 
   /*
    * Notmuch ensures that message Id exists (if not notmuch Notmuch will
@@ -1597,7 +1608,10 @@ static int rename_filename(struct NmCtxData *data, const char *old,
   {
     notmuch_message_maildir_flags_to_tags(msg);
     update_header_tags(h, msg);
-    update_tags(msg, driver_tags_get(h->tags));
+
+    char *tags = driver_tags_get(&h->tags);
+    update_tags(msg, tags);
+    FREE(&tags);
   }
 
   rc = 0;
@@ -2116,8 +2130,11 @@ int nm_record_message(struct Context *ctx, char *path, struct Header *h)
   if (st == NOTMUCH_STATUS_SUCCESS && msg)
   {
     notmuch_message_maildir_flags_to_tags(msg);
-    if (h)
-      update_tags(msg, driver_tags_get(h->tags));
+    if (h) {
+      char *tags = driver_tags_get(&h->tags);
+      update_tags(msg, tags);
+      FREE(&tags);
+    }
     if (NmRecordTags)
       update_tags(msg, NmRecordTags);
   }
index 0ead620481428322601cd022704bdd97b0aa2b36..30f15326168ee35b821b146a657da385db8af19b 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <stddef.h>
+
 #include "config.h"
 #include "mutt_tags.h"
 #include "globals.h"
 #include "lib/hash.h"
 #include "lib/string2.h"
-#include "mx.h"
+#include "queue.h"
+
 
 /**
- * driver_tags_free_tag_list - free tag
- * @param[in] h: pointer to a Header struct
+ * driver_tags_free - Free tags from a header
+ * @param[in] head: pointer to the tags head
  *
- * Free tag
+ * Free the whole tags structure
  */
-static void driver_tags_free_tag_list(struct TagNode **kw_list)
+void driver_tags_free(struct TagHead *head)
 {
-  struct TagNode *tmp = NULL;
+  if (!head)
+    return;
 
-  while ((tmp = *kw_list) != NULL)
+  struct TagNode *np = STAILQ_FIRST(head), *next = NULL;
+  while (np)
   {
-    *kw_list = tmp->next;
-    FREE(&tmp->name);
-    FREE(&tmp->transformed);
-    FREE(&tmp);
+      next = STAILQ_NEXT(np, entries);
+      FREE(&np->name);
+      FREE(&np->transformed);
+      FREE(&np);
+      np = next;
   }
-
-  *kw_list = 0;
+  STAILQ_INIT(head);
 }
 
 /**
- * driver_tags_free - Free tags from a header
- * @param[in] h: pointer to a header struct
+ * driver_tags_get_transformed - Get transformed tags
+ * @param[in] head: pointer to the tags head
  *
- * Free the whole tags structure
+ * Return a new allocated string containing tags separated by space
  */
-void driver_tags_free(struct TagHead *head)
+static char *driver_tags_getter(struct TagHead *head, bool show_hidden, bool show_tranformed, char *filter)
 {
   if (!head)
-    return;
-  FREE(&head->tags);
-  FREE(&head->tags_transformed);
-  FREE(&head->tags_with_hidden);
-  driver_tags_free_tag_list(&head->tag_list);
-  FREE(head);
+    return NULL;
+
+  char *tags = NULL;
+  struct TagNode *np;
+  STAILQ_FOREACH(np, head, entries)
+  {
+    if(filter && mutt_strcmp(np->name, filter) != 0)
+      continue;
+    if (show_hidden || !np->hidden)
+    {
+      if (show_tranformed && np->transformed)
+        mutt_str_append_item(&tags, np->transformed, ' ');
+      else
+        mutt_str_append_item(&tags, np->name, ' ');
+    }
+  }
+  return tags;
 }
 
+
 /**
- * driver_tags_get_transformed - Get transformed tags from a header
- * @param[in] h: pointer to a header struct
- *
- * @return string transformed tags
+ * driver_tags_get_transformed - Get transformed tags
+ * @param[in] head: pointer to the tags head
  *
- * Return a string containing all transformed tags separated by space
- * without hidden tags
+ * Return a new allocated string containing all tags separated by space with
+ * transformation
  */
-const char *driver_tags_get_transformed(struct TagHead *head)
+char *driver_tags_get_transformed(struct TagHead *head)
 {
-  if (!head)
-    return NULL;
-  if(!head->tags_transformed)
-    return head->tags;
-  return head->tags_transformed;
+  return driver_tags_getter(head, false, true, NULL);
 }
 
 /**
- * driver_tags_get - Get tags from a header
- * @param[in] h: pointer to a header struct
- *
- * @return string tags
+ * driver_tags_get - Get tags
+ * @param[in] head: pointer to the tags head
  *
- * Return a string containing all tags separated by space with
- * hidden tags
+ * Return a new allocated string containing all tags separated by space
  */
-const char *driver_tags_get(struct TagHead *head)
+char *driver_tags_get(struct TagHead *head)
 {
-  if (!head || !head->tags)
-    return NULL;
-  return head->tags;
+  return driver_tags_getter(head, false, false, NULL);
 }
 
 /**
- * driver_tags_get_with_hidden - Get tags with hiddens from a header
- * @param[in] h: pointer to a header struct
- *
- * @return string tags
+ * driver_tags_get_with_hidden - Get tags with hiddens
+ * @param[in] head: pointer to the tags head
  *
- * Return a string containing all tags separated by space
- * even the hiddens.
+ * Return a new allocated string containing all tags separated by space even
+ * the hiddens.
  */
-const char *driver_tags_get_with_hidden(struct TagHead *head)
+char *driver_tags_get_with_hidden(struct TagHead *head)
 {
-  if (!head || !head->tags_with_hidden)
-    return NULL;
-  return head->tags_with_hidden;
+  return driver_tags_getter(head, true, false, NULL);
 }
 
 /**
  * driver_tags_get_transformed_for - Get tranformed tag for a tag name from a header
  * @param[in] tag: char* to the tag to get the transformed version
- * @param[in] h: pointer to a header struct
+ * @param[in] head: pointer to the tags head
  *
  * @return string tag
  *
- * Return a string containing transformed tag that match the tag
- * even if this is a hidden tags
+ * Return a new allocated string containing all tags separated by space even
+ * the hiddens.
  */
-const char *driver_tags_get_transformed_for(char *name, struct TagHead *head)
-{
-  if (!head || !head->tag_list)
-    return NULL;
-
-  struct TagNode *tag = head->tag_list;
-  while (tag)
-  {
-    if (strcmp(tag->name, name) == 0) {
-      if (!tag->transformed)
-        return tag->name;
-      else
-        return tag->transformed;
-    }
-    tag = tag->next;
-  }
-  return NULL;
-}
-
-void driver_tags_init(struct TagHead *head)
+char *driver_tags_get_transformed_for(char *name, struct TagHead *head)
 {
-  head = safe_calloc(1, sizeof(struct TagHead));
-  head->tags = NULL;
-  head->tags_transformed = NULL;
-  head->tags_with_hidden = NULL;
-  head->tag_list = NULL;
+  return driver_tags_getter(head, true, true, name);
 }
 
 /**
  * driver_tags_add - Add a tag to header
- * @param[in] h: pointer to a header struct
+ * @param[in] head: pointer to the tags head
  * @param[in] new_tag: string representing the new tag
  *
  * Add a tag to the header tags
  */
 static void driver_tags_add(struct TagHead *head, char *new_tag)
 {
-  struct TagNode *ttmp = NULL;
-  char *new_tag_transformed = NULL;
+  char *new_tag_transformed = hash_find(TagTransforms, new_tag);
 
-  new_tag_transformed = hash_find(TagTransforms, new_tag);
-
-  ttmp = safe_calloc(1, sizeof(*ttmp));
-  ttmp->name = safe_strdup(new_tag);
+  struct TagNode *np = safe_calloc(1, sizeof(struct TagNode));
+  np->name = safe_strdup(new_tag);;
+  np->hidden = false;
   if (new_tag_transformed)
-    ttmp->transformed = safe_strdup(new_tag_transformed);
-  ttmp->next = head->tag_list;
-  head->tag_list = ttmp;
-
-  /* expand the all un-transformed tag string */
-  mutt_str_append_item(&head->tags_with_hidden, new_tag, ' ');
+    np->transformed = safe_strdup(new_tag_transformed);
 
   /* filter out hidden tags */
   if (HiddenTags)
@@ -185,22 +157,15 @@ static void driver_tags_add(struct TagHead *head, char *new_tag)
 
     if (p && ((p == HiddenTags) || (*(p - 1) == ',') || (*(p - 1) == ' ')) &&
         ((*(p + xsz) == '\0') || (*(p + xsz) == ',') || (*(p + xsz) == ' ')))
-      return;
+      np->hidden = true;
   }
 
-  /* expand the visible un-transformed tag string */
-  mutt_str_append_item(&head->tags, new_tag, ' ');
-
-  /* expand the transformed tag string */
-  if (new_tag_transformed)
-    mutt_str_append_item(&head->tags_transformed, new_tag_transformed, ' ');
-  else
-    mutt_str_append_item(&head->tags_transformed, new_tag, ' ');
+  STAILQ_INSERT_TAIL(head, np, entries);
 }
 
 /**
  * driver_tags_replace - Replace all tags
- * @param[in] h: pointer to a header struct
+ * @param[in] head: pointer to the tags head
  * @param[in] tags: string of all tags separated by space
  *
  * @retval  0 If no change are made
@@ -211,12 +176,10 @@ static void driver_tags_add(struct TagHead *head, char *new_tag)
  */
 int driver_tags_replace(struct TagHead *head, char *tags)
 {
-  if (tags && head && head->tags &&
-      mutt_strcmp(head->tags, tags) == 0)
+  if (!head)
     return 0;
 
   driver_tags_free(head);
-  driver_tags_init(head);
 
   if (tags)
   {
index 38006fdc0d599ad37a47c75fd0ad084557c43bd0..ac19fcbd367a3b42406ffcdd4fbef69292e330ce 100644 (file)
 #ifndef _MUTT_TAG_H
 #define _MUTT_TAG_H
 
+#include <stdbool.h>
+#include <stddef.h>
+#include "queue.h"
+
 /**
- * struct TagNode - Tag element
+ * struct TagNode - LinkedList Tag Element
  *
  * Keep a linked list of header tags and their transformed values.
  * Textual tags can be transformed to symbols to save space.
  *
- * @sa TagNodes
+ * @sa TagNode
  */
-struct TagNode
-{
-  char *name;
-  char *transformed;
-  struct TagNode *next;
-};
 
-/**
- * struct TagHead - tags data attached to an email
- *
- * This stores all tags data associated with an email.
- */
-struct TagHead
+STAILQ_HEAD(TagHead, TagNode);
+struct TagNode
 {
-  /* Without hidden tags */
-  char *tags;
-  char *tags_transformed;
-
-  /* With hidden tags */
-  char *tags_with_hidden;
-  struct TagNode *tag_list;
+    char *name;
+    char *transformed;
+    bool hidden;
+    STAILQ_ENTRY(TagNode) entries;
 };
 
 void driver_tags_free(struct TagHead *head);
-const char *driver_tags_get(struct TagHead *head);
-const char *driver_tags_get_with_hidden(struct TagHead *head);
-const char *driver_tags_get_transformed(struct TagHead *head);
-const char *driver_tags_get_transformed_for(char *name, struct TagHead *head);
-void driver_tags_init(struct TagHead *head);
+char *driver_tags_get(struct TagHead *head);
+char *driver_tags_get_with_hidden(struct TagHead *head);
+char *driver_tags_get_transformed(struct TagHead *head);
+char *driver_tags_get_transformed_for(char *name, struct TagHead *head);
 int driver_tags_replace(struct TagHead *head, char *tags);
 
 #endif /* _MUTT_TAG_H */
index f6acfb1a8ce14d7d9beb8791507a3816beb731fe..1643a41298a3e0f64d015925cc99326e29814378 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -167,7 +167,7 @@ void mutt_free_header(struct Header **h)
 #ifdef MIXMASTER
   mutt_list_free(&(*h)->chain);
 #endif
-  driver_tags_free((*h)->tags);
+  driver_tags_free(&(*h)->tags);
 #if defined(USE_POP) || defined(USE_IMAP) || defined(USE_NNTP) || defined(USE_NOTMUCH)
   if ((*h)->free_cb)
     (*h)->free_cb(*h);
index 4ada30d872b9774de1234dca5fcc25d951e75c0d..3a1532bcf5a01d47d021410b5f0beb7f0c5002ef 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -1714,8 +1714,10 @@ int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags,
       return (pat->not ^ (h->env->x_label && patmatch(pat, h->env->x_label) == 0));
     case MUTT_DRIVER_LABEL:
     {
-      const char *tags = driver_tags_get(h->tags);
-      return (pat->not ^ (tags && patmatch(pat, tags) == 0));
+      char *tags = driver_tags_get(&h->tags);
+      bool ret = (pat->not ^ (tags && patmatch(pat, tags) == 0));
+      FREE(&tags);
+      return ret;
     }
     case MUTT_HORMEL:
       return (pat->not ^ (h->env->spam && h->env->spam->data &&