commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-3.0-21-g15f6dbf


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-3.0-21-g15f6dbf
Date: Fri, 2 Dec 2016 15:19:01 +0000 (UTC)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=15f6dbf66eed6bed5c084d97077e7cc5f8e192a7

The branch, master has been updated
       via  15f6dbf66eed6bed5c084d97077e7cc5f8e192a7 (commit)
      from  ed04bc837e353e61e4c43f6bdbd9a67859c61f61 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 15f6dbf66eed6bed5c084d97077e7cc5f8e192a7
Author: Sergey Poznyakoff <address@hidden>
Date:   Fri Dec 2 17:11:01 2016 +0200

    sieve: change string allocation and argument passing convention
    
    Strings are allocated in a per-machine string space.  String and
    argument lists form contiguous arrays of structures.  Regular ex-
    pressions are compiled when they are needed. Compiled expressions
    are cached for eventual reuse.

-----------------------------------------------------------------------

Summary of changes:
 examples/numaddr.c                                 |    2 +-
 include/mailutils/sieve.h                          |   78 ++--
 libmu_sieve/Makefile.am                            |    1 +
 libmu_sieve/actions.c                              |   17 +-
 libmu_sieve/comparator.c                           |  297 ++++++---------
 libmu_sieve/extensions/editheader.c                |   62 ++--
 libmu_sieve/extensions/list.c                      |    2 +-
 libmu_sieve/extensions/vacation.c                  |   22 +-
 libmu_sieve/mem.c                                  |   41 ++-
 libmu_sieve/prog.c                                 |  366 +++++++++----------
 libmu_sieve/relational.c                           |    5 +-
 libmu_sieve/require.c                              |   24 +-
 libmu_sieve/runtime.c                              |   46 +--
 libmu_sieve/sieve-priv.h                           |   51 ++-
 libmu_sieve/sieve.y                                |  257 ++++++-------
 .../pop/pop3_disconnect.c => libmu_sieve/string.c  |   59 +--
 libmu_sieve/tests.c                                |   84 +++--
 libmu_sieve/util.c                                 |  379 ++++++++++----------
 sieve/tests/delheader.at                           |    2 +-
 sieve/tests/enc-char.at                            |   35 +-
 20 files changed, 880 insertions(+), 950 deletions(-)
 copy libproto/pop/pop3_disconnect.c => libmu_sieve/string.c (50%)

diff --git a/examples/numaddr.c b/examples/numaddr.c
index 7981e0b..584d2b9 100644
--- a/examples/numaddr.c
+++ b/examples/numaddr.c
@@ -95,7 +95,7 @@ numaddr_test (mu_sieve_machine_t mach)
   vc.count = 0;
 
   /* Count the addresses */
-  rc = mu_sieve_vlist_do (h, _count_items, &vc);
+  rc = mu_sieve_vlist_do (mach, h, _count_items, &vc);
 
   /* Here rc >= 1 iff the counted number of addresses is greater or equal
      to vc.limit. If `:under' tag was given we reverse the return value */
diff --git a/include/mailutils/sieve.h b/include/mailutils/sieve.h
index 20ad24e..7227aba 100644
--- a/include/mailutils/sieve.h
+++ b/include/mailutils/sieve.h
@@ -33,6 +33,13 @@ extern "C" {
 
 typedef struct mu_sieve_machine *mu_sieve_machine_t;
 
+typedef struct mu_sieve_string
+{
+  char *orig;
+  char *exp;
+  void *rx;
+} mu_sieve_string_t;
+  
 typedef int (*mu_sieve_handler_t) (mu_sieve_machine_t mach);
 typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t mach,
                                       const char *action,
@@ -40,13 +47,12 @@ typedef void (*mu_sieve_action_log_t) (mu_sieve_machine_t 
mach,
 
 typedef int (*mu_sieve_relcmp_t) (int, int);
 typedef int (*mu_sieve_relcmpn_t) (size_t, size_t);
-typedef int (*mu_sieve_comparator_t) (const char *, const char *);
+typedef int (*mu_sieve_comparator_t) (mu_sieve_machine_t mach,
+                                     mu_sieve_string_t *, const char *);
 typedef int (*mu_sieve_retrieve_t) (void *item, void *data, int idx,
                                    char **pval);
 typedef void (*mu_sieve_destructor_t) (void *data);
-typedef int (*mu_sieve_tag_checker_t) (mu_sieve_machine_t mach,
-                                      const char *name,
-                                      mu_list_t tags, mu_list_t args);
+typedef int (*mu_sieve_tag_checker_t) (mu_sieve_machine_t mach);
 
 typedef enum
 {
@@ -55,24 +61,29 @@ typedef enum
   SVT_STRING,
   SVT_STRING_LIST,
   SVT_TAG,
-  SVT_IDENT,
-  SVT_POINTER
+  SVT_IDENT
 }
 mu_sieve_data_type;
 
-typedef struct mu_sieve_runtime_tag mu_sieve_runtime_tag_t;
+struct mu_sieve_slice
+{
+  size_t first;
+  size_t count;
+};
+
+typedef struct mu_sieve_slice *mu_sieve_slice_t;
 
 union mu_sieve_value_storage
 {
   char *string;
   size_t number;
-  mu_list_t list;
-  void *ptr;
+  struct mu_sieve_slice list;
 };
 
 typedef struct
 {
   mu_sieve_data_type type;
+  char *tag;
   union mu_sieve_value_storage v;
 } mu_sieve_value_t;
 
@@ -88,12 +99,6 @@ typedef struct
   mu_sieve_tag_checker_t checker;
 } mu_sieve_tag_group_t;
 
-struct mu_sieve_runtime_tag
-{
-  char *tag;
-  mu_sieve_value_t *arg;
-};
-
 typedef struct
 {
   const char *name;
@@ -135,11 +140,9 @@ void *mu_sieve_realloc (mu_sieve_machine_t mach, void 
*ptr, size_t size);
 void mu_sieve_reclaim_default (void *p);
 void mu_sieve_reclaim_list (void *p);
 void mu_sieve_reclaim_value (void *p);
-void mu_sieve_reclaim_tag (void *p);
   
-mu_sieve_value_t *mu_sieve_value_create (mu_sieve_machine_t mach,
-                                        mu_sieve_data_type type, void *data);
-void mu_sieve_slist_destroy (mu_list_t *plist);
+size_t mu_sieve_value_create (mu_sieve_machine_t mach,
+                             mu_sieve_data_type type, void *data);
 
 /* Symbol space functions */
 mu_sieve_register_t *mu_sieve_test_lookup (mu_sieve_machine_t mach,
@@ -185,30 +188,41 @@ int mu_sieve_str_to_relcmp (const char *str, 
mu_sieve_relcmp_t *test,
                            mu_sieve_relcmpn_t *stest);
 mu_sieve_relcmp_t mu_sieve_get_relcmp (mu_sieve_machine_t mach);
 
-void mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist);
+void mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list);
 
+void mu_sieve_value_get (mu_sieve_machine_t mach, mu_sieve_value_t *val,
+                        mu_sieve_data_type type, void *ret);
+  
 int mu_sieve_get_tag (mu_sieve_machine_t mach, char *name,
                      mu_sieve_data_type type, void *ret);
-int mu_sieve_get_tag_untyped (mu_sieve_machine_t mach, 
-                             char *name, mu_sieve_value_t **ret);
+mu_sieve_value_t *mu_sieve_get_tag_untyped (mu_sieve_machine_t mach,
+                                           char const *name);
+mu_sieve_value_t *mu_sieve_get_tag_n (mu_sieve_machine_t mach, size_t n);
   
 int mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name);
-int mu_sieve_match_part_checker (mu_sieve_machine_t mach,
-                                const char *name, mu_list_t tags,
-                                mu_list_t args);
-int mu_sieve_match_part_checker (mu_sieve_machine_t mach,
-                                const char *name, mu_list_t tags,
-                                mu_list_t args);
+int mu_sieve_match_part_checker (mu_sieve_machine_t mach);
+
 /* Operations on value lists */
 mu_sieve_value_t *mu_sieve_get_arg_optional (mu_sieve_machine_t mach,
                                             size_t index);
 mu_sieve_value_t *mu_sieve_get_arg_untyped (mu_sieve_machine_t mach,
                                            size_t index);
-int mu_sieve_get_arg (mu_sieve_machine_t mach, size_t index,
-                     mu_sieve_data_type type, void *ret);
-int mu_sieve_vlist_do (mu_sieve_value_t *val, mu_list_action_t ac,
+void mu_sieve_get_arg (mu_sieve_machine_t mach, size_t index,
+                      mu_sieve_data_type type, void *ret);
+
+char *mu_sieve_string (mu_sieve_machine_t mach,
+                      mu_sieve_slice_t slice,
+                      size_t i);
+struct mu_sieve_string *mu_sieve_string_raw (mu_sieve_machine_t mach,
+                                            mu_sieve_slice_t slice,
+                                            size_t i);
+
+  
+int mu_sieve_vlist_do (mu_sieve_machine_t mach,
+                      mu_sieve_value_t *val, mu_list_action_t ac,
                       void *data);
-int mu_sieve_vlist_compare (mu_sieve_value_t *a, mu_sieve_value_t *b,
+int mu_sieve_vlist_compare (mu_sieve_machine_t mach,
+                           mu_sieve_value_t *a, mu_sieve_value_t *b,
                            mu_sieve_comparator_t comp,
                            mu_sieve_relcmp_t test, mu_sieve_retrieve_t ac,
                            void *data, size_t *count);
diff --git a/libmu_sieve/Makefile.am b/libmu_sieve/Makefile.am
index 0b06ffe..b9f3a0a 100644
--- a/libmu_sieve/Makefile.am
+++ b/libmu_sieve/Makefile.am
@@ -42,6 +42,7 @@ libmu_sieve_la_SOURCES = \
  sieve-gram.h\
  sieve-lex.c\
  strexp.c\
+ string.c\
  tests.c\
  util.c
 libmu_sieve_la_LIBADD = ${MU_LIB_MAILUTILS} @LTDL_LIB@
diff --git a/libmu_sieve/actions.c b/libmu_sieve/actions.c
index 077b8cd..f3ef7f4 100644
--- a/libmu_sieve/actions.c
+++ b/libmu_sieve/actions.c
@@ -511,24 +511,22 @@ mu_sieve_data_type fileinto_args[] = {
 };
 
 static int
-perms_tag_checker (mu_sieve_machine_t mach,
-                  const char *name, mu_list_t tags, mu_list_t args)
+perms_tag_checker (mu_sieve_machine_t mach)
 {
-  mu_iterator_t itr;
+  size_t i;
   int err = 0;
   
-  if (!tags || mu_list_get_iterator (tags, &itr))
+  if (mach->tagcount == 0)
     return 0;
-  for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr);
-       mu_iterator_next (itr))
+  for (i = 0; i < mach->tagcount; i++)
     {
       int flag;
       const char *p;
-      mu_sieve_runtime_tag_t *t;
-      mu_iterator_current (itr, (void **)&t);
+      mu_sieve_value_t *t = mu_sieve_get_tag_n (mach, i);
+
       if (strcmp (t->tag, "permissions") == 0)
        {
-         if (mu_parse_stream_perm_string (&flag, t->arg->v.string, &p))
+         if (mu_parse_stream_perm_string (&flag, t->v.string, &p))
            {
              mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
                                _("invalid permissions (near %s)"), p);
@@ -537,7 +535,6 @@ perms_tag_checker (mu_sieve_machine_t mach,
            }
        }
     }
-  mu_iterator_destroy (&itr);
   return err;
 }
 
diff --git a/libmu_sieve/comparator.c b/libmu_sieve/comparator.c
index a2ac34b..a0d5836 100644
--- a/libmu_sieve/comparator.c
+++ b/libmu_sieve/comparator.c
@@ -38,13 +38,13 @@ typedef struct {
 
 int
 mu_sieve_register_comparator (mu_sieve_machine_t mach,
-                          const char *name,
-                          int required,
-                          mu_sieve_comparator_t is,
-                          mu_sieve_comparator_t contains,
-                          mu_sieve_comparator_t matches,
-                          mu_sieve_comparator_t regex,
-                          mu_sieve_comparator_t eq)
+                             const char *name,
+                             int required,
+                             mu_sieve_comparator_t is,
+                             mu_sieve_comparator_t contains,
+                             mu_sieve_comparator_t matches,
+                             mu_sieve_comparator_t regex,
+                             mu_sieve_comparator_t eq)
 {
   sieve_comparator_record_t *rp;
 
@@ -113,56 +113,28 @@ mu_sieve_comparator_lookup (mu_sieve_machine_t mach, 
const char *name,
   return NULL;
 }
 
-static int
-_find_comparator (void *item, void *data)
-{
-  mu_sieve_runtime_tag_t *tag = item;
-
-  if (strcmp (tag->tag, TAG_COMPFUN) == 0)
-    {
-      *(mu_sieve_comparator_t*)data = tag->arg->v.ptr;
-      return 1;
-    }
-  return 0;
-}
+static int i_ascii_casemap_is (mu_sieve_machine_t mach,
+                              mu_sieve_string_t *pattern, const char *text);
 
 mu_sieve_comparator_t
 mu_sieve_get_comparator (mu_sieve_machine_t mach)
 {
-  mu_sieve_comparator_t comp = NULL;
-
-  mu_list_foreach (mach->tag_list, _find_comparator, &comp);
-  return comp ? comp : mu_sieve_comparator_lookup (mach,
-                                                  "i;ascii-casemap",
-                                                  MU_SIEVE_MATCH_IS);
+  if (!mach->comparator)
+    return i_ascii_casemap_is;
+  return mach->comparator;
 }
 
 /* Compile time support */
-
-struct regex_data
-{
-  mu_sieve_machine_t mach;
-  int flags;
-  mu_list_t list;
-};
-
-#ifndef FNM_CASEFOLD
-static int
-_pattern_upcase (void *item, void *data)
-{
-  mu_strupper (item);
-  return 0;
-}
-#endif
-
-static int
-_regex_compile (void *item, void *data)
+static void
+compile_pattern (mu_sieve_machine_t mach, mu_sieve_string_t *pattern, int 
flags)
 {
-  struct regex_data *rd = data;
   int rc;
-  regex_t *preg = mu_sieve_malloc (rd->mach, sizeof (*preg));
-  
-  rc = regcomp (preg, (char*)item, rd->flags);
+  regex_t *preg;
+
+  if (pattern->rx)
+    return;
+  preg = mu_sieve_malloc (mach, sizeof (*preg));
+  rc = regcomp (preg, pattern->orig, REG_EXTENDED | flags);
   if (rc)
     {
       size_t size = regerror (rc, preg, NULL, 0);
@@ -170,64 +142,39 @@ _regex_compile (void *item, void *data)
       if (errbuf)
        {
          regerror (rc, preg, errbuf, size);
-         mu_diag_at_locus (MU_LOG_ERROR, &rd->mach->locus,
-                           _("regex error: %s"), errbuf);
+         mu_sieve_error (mach, _("regex error: %s"), errbuf);
          free (errbuf);
        }
       else
-       mu_diag_at_locus (MU_LOG_ERROR, &rd->mach->locus, _("regex error"));
-      mu_i_sv_error (rd->mach);
-      return rc;
+       mu_sieve_error (mach, _("regex error"));
+      mu_sieve_abort (mach);
     }
-
-  mu_list_append (rd->list, preg);
-  
-  return 0;
-}
-
-static int
-_free_regex (void *item, void *unused)
-{
-  regfree ((regex_t*)item);
-  return 0;
-}
-
-static void
-_free_reglist (void *data)
-{
-  mu_list_t list = data;
-  mu_list_foreach (list, _free_regex, NULL);
-  mu_list_destroy (&list);
+  pattern->rx = preg;
 }
 
 static int
-comp_false (const char *pattern, const char *text)
+comp_false (mu_sieve_machine_t mach, mu_sieve_string_t *pattern,
+           const char *text)
 {
   return 0;
 }
 
 int
-mu_sieve_match_part_checker (mu_sieve_machine_t mach,
-                            const char *name, mu_list_t tags, mu_list_t args)
+mu_sieve_match_part_checker (mu_sieve_machine_t mach)
 {
-  mu_iterator_t itr;
-  mu_sieve_runtime_tag_t *match = NULL;
-  mu_sieve_runtime_tag_t *comp = NULL;
-  mu_sieve_runtime_tag_t *tmp;
+  size_t i;
+  mu_sieve_value_t *match = NULL;
   mu_sieve_comparator_t compfun = NULL;
-  char *compname = "false";
+  char *compname = NULL;
   
   int matchtype;
-  int err = 0;
-  
-  if (!tags || mu_list_get_iterator (tags, &itr))
+
+  if (mach->tagcount == 0)
     return 0;
 
-  for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr);
-       mu_iterator_next (itr))
+  for (i = 0; i < mach->tagcount; i++)
     {
-      mu_sieve_runtime_tag_t *t;
-      mu_iterator_current (itr, (void **)&t);
+      mu_sieve_value_t *t = mu_sieve_get_tag_n (mach, i);
       
       if (strcmp (t->tag, "is") == 0
          || strcmp (t->tag, "contains") == 0
@@ -240,22 +187,21 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach,
            {
              mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
                                _("match type specified twice in call to `%s'"),
-                               name);
+                               mach->identifier);
              mu_i_sv_error (mach);
-             err = 1;
+             return 1;
            }
          else
            match = t;
        }
-      else if (strcmp (t->tag, "comparator") == 0) 
-       comp = t;
+      else if (strcmp (t->tag, "comparator") == 0)
+       {
+         if (t->type != SVT_STRING)
+           abort ();
+         compname = mu_sieve_string (mach, &t->v.list, 0);
+       }
     }
 
-  mu_iterator_destroy (&itr);
-
-  if (err)
-    return 1;
-
   if (!match || strcmp (match->tag, "is") == 0)
     matchtype = MU_SIEVE_MATCH_IS;
   else if (strcmp (match->tag, "contains") == 0)
@@ -264,42 +210,43 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach,
     matchtype = MU_SIEVE_MATCH_MATCHES;
   else if (strcmp (match->tag, "regex") == 0)
     matchtype = MU_SIEVE_MATCH_REGEX;
-  else
+  else if (match->type == SVT_STRING)
     {
-      char *str = match->arg->v.string;
+      char *str = mu_sieve_string (mach, &match->v.list, 0);
       if (strcmp (match->tag, "count") == 0)
        {
          mu_sieve_value_t *val;
          char *str;
          size_t count;
          
-         if (comp && strcmp (comp->arg->v.string, "i;ascii-numeric"))
+         if (compname && strcmp (compname, "i;ascii-numeric"))
            {
              mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
                                /* TRANSLATORS: Do not translate ':count'.
                                   It is the name of a Sieve tag */
                                _("comparator %s is incompatible with "
                                  ":count in call to `%s'"),
-                               comp->arg->v.string,
-                               name);
+                               compname,
+                               mach->identifier);
              mu_i_sv_error (mach);
              return 1;
            }
 
           matchtype = MU_SIEVE_MATCH_LAST; /* to not leave it undefined */
+         compname = "false";
          compfun = comp_false;
-         if (mu_list_get (args, 1, (void**) &val))
-           return 1; /* shouldn't happen */
-         /* NOTE: Type of v is always SVT_STRING_LIST */
-         mu_list_count (val->v.list, &count);
-         if (count > 1)
+         val = mu_sieve_get_arg_untyped (mach, 1);
+         /* NOTE: Type of val is always SVT_STRING_LIST */
+         if (val->type != SVT_STRING_LIST)
+           abort ();
+         if (val->v.list.count > 1)
            {
              mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
                        _("second argument must be a list of one element"));
              mu_i_sv_error (mach);
              return 1;
            }
-         mu_list_get (val->v.list, 0, (void **) &str);
+         str = mu_sieve_string_raw (mach, &val->v.list, 0)->orig;
          count = strtoul (str, &str, 10);
          if (*str)
            {
@@ -316,72 +263,32 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach,
        {
          mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
                            _("invalid relational match `%s' in call to `%s'"),
-                           str, name);
+                           str, mach->identifier);
          mu_i_sv_error (mach);
          return 1;
        }
     }
-
+  else
+    abort ();//FIXME
+  
   if (!compfun)
     {
-      compname = comp ? comp->arg->v.string : "i;ascii-casemap";
+      if (!compname)
+       compname = "i;ascii-casemap";
       compfun = mu_sieve_comparator_lookup (mach, compname, matchtype);
       if (!compfun)
        {
          mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
                            _("comparator `%s' is incompatible with match type 
`%s' in call to `%s'"),
-                           compname, match ? match->tag : "is", name);
+                           compname, match ? match->tag : "is",
+                           mach->identifier);
          mu_i_sv_error (mach);
          return 1;
        }
     }
 
-  tmp = mu_sieve_malloc (mach, sizeof (*tmp));
-  tmp->tag = TAG_COMPFUN;
-  tmp->arg = mu_sieve_value_create (mach, SVT_POINTER, compfun);
-  mu_list_append (tags, tmp);
+  mach->comparator = compfun;
   
-  if (matchtype == MU_SIEVE_MATCH_REGEX)
-    {
-      /* To speed up things, compile all patterns at once.
-        Notice that it is supposed that patterns are in arg 2 */
-      mu_sieve_value_t *val, *newval;
-      struct regex_data rd;
-      int rc;
-      
-      if (mu_list_get (args, 1, (void**)&val))
-       return 0;
-
-      rd.mach = mach;
-      rd.flags = REG_EXTENDED;
-      if (strcmp (compname, "i;ascii-casemap") == 0)
-       rd.flags |= REG_ICASE;
-
-      mu_list_create (&rd.list);
-      
-      rc = mu_sieve_vlist_do (val, _regex_compile, &rd);
-
-      mu_sieve_machine_add_destructor (rd.mach, _free_reglist, rd.list);
-
-      if (rc)
-       return rc;
-      newval = mu_sieve_value_create (rd.mach, SVT_STRING_LIST, rd.list);
-      mu_list_replace (args, val, newval);
-    }
-#ifndef FNM_CASEFOLD
-  else if (matchtype == MU_SIEVE_MATCH_MATCHES
-          && strcmp (compname, "i;ascii-casemap") == 0)
-    {
-      int rc;
-      mu_sieve_value_t *val;
-
-      if (mu_list_get (args, 1, (void**)&val))
-       return 0;
-      rc = mu_sieve_vlist_do (val, _pattern_upcase, NULL);
-      if (rc)
-       return rc;
-    }
-#endif
   return 0;
 }
 
@@ -390,85 +297,88 @@ mu_sieve_match_part_checker (mu_sieve_machine_t mach,
 /* :comparator i;octet */
 
 static int
-i_octet_is (const char *pattern, const char *text)
+i_octet_is (mu_sieve_machine_t mach, mu_sieve_string_t *pattern,
+           const char *text)
 {
-  return strcmp (pattern, text) == 0;
+  return strcmp (pattern->orig, text) == 0;
 }
 
 static int
-i_octet_contains (const char *pattern, const char *text)
+i_octet_contains (mu_sieve_machine_t mach, mu_sieve_string_t *pattern,
+                 const char *text)
 {
-  return strstr (text, pattern) != NULL;
+  return strstr (text, pattern->orig) != NULL;
 }
 
 static int 
-i_octet_matches (const char *pattern, const char *text)
+i_octet_matches (mu_sieve_machine_t mach, mu_sieve_string_t *pattern,
+                const char *text)
 {
-  return fnmatch (pattern, text, 0) == 0;
+  return fnmatch (pattern->orig, text, 0) == 0;
 }
 
 static int
-i_octet_regex (const char *pattern, const char *text)
+i_octet_regex (mu_sieve_machine_t mach, mu_sieve_string_t *pattern,
+              const char *text)
 {
-  return regexec ((regex_t *) pattern, text, 0, NULL, 0) == 0;
+  compile_pattern (mach, pattern, 0);
+  return regexec ((regex_t *)pattern->rx, text, 0, NULL, 0) == 0;
 }
 
 static int
-i_octet_eq (const char *pattern, const char *text)
+i_octet_eq (mu_sieve_machine_t mach,
+           mu_sieve_string_t *pattern, const char *text)
 {
-  return strcmp (text, pattern);
+  return strcmp (text, pattern->orig);
 }
 
 /* :comparator i;ascii-casemap */
 static int
-i_ascii_casemap_is (const char *pattern, const char *text)
+i_ascii_casemap_is (mu_sieve_machine_t mach,
+                   mu_sieve_string_t *pattern, const char *text)
 {
-  return mu_c_strcasecmp (pattern, text) == 0;
+  return mu_c_strcasecmp (pattern->orig, text) == 0;
 }
 
 static int
-i_ascii_casemap_contains (const char *pattern, const char *text)
+i_ascii_casemap_contains (mu_sieve_machine_t mach,
+                         mu_sieve_string_t *pattern, const char *text)
 {
-  return mu_c_strcasestr (text, pattern) != NULL;
+  return mu_c_strcasestr (text, pattern->orig) != NULL;
 }
 
 static int
-i_ascii_casemap_matches (const char *pattern, const char *text)
+i_ascii_casemap_matches (mu_sieve_machine_t mach,
+                        mu_sieve_string_t *pattern, const char *text)
 {
-#ifdef FNM_CASEFOLD
-  return fnmatch (pattern, text, FNM_CASEFOLD) == 0;
-#else
-  int rc;
-  char *p = strdup (text);
-  if (!p)
-    return 0;
-  _pattern_upcase (p, NULL);
-  rc = fnmatch (pattern, p, 0) == 0;
-  free (p);
-  return rc;
-#endif
+  return fnmatch (pattern->orig, text, FNM_CASEFOLD) == 0;
 }
 
 static int
-i_ascii_casemap_regex (const char *pattern, const char *text)
+i_ascii_casemap_regex (mu_sieve_machine_t mach,
+                      mu_sieve_string_t *pattern, const char *text)
 {
-  return regexec ((regex_t *) pattern, text, 0, NULL, 0) == 0;
+  compile_pattern (mach, pattern, REG_ICASE);
+  return regexec ((regex_t *) pattern->rx, text, 0, NULL, 0) == 0;
 }
 
 static int
-i_ascii_casemap_eq (const char *pattern, const char *text)
+i_ascii_casemap_eq (mu_sieve_machine_t mach,
+                   mu_sieve_string_t *pattern, const char *text)
 {
-  return mu_c_strcasecmp (text, pattern);
+  return mu_c_strcasecmp (text, pattern->orig);
 }
 
 /* :comparator i;ascii-numeric */
 static int
-i_ascii_numeric_is (const char *pattern, const char *text)
+i_ascii_numeric_is (mu_sieve_machine_t mach,
+                   mu_sieve_string_t *pattern, const char *text)
 {
-  if (mu_isdigit (*pattern))
+  if (mu_isdigit (*pattern->orig))
     {
       if (mu_isdigit (*text))
-       return strtol (pattern, NULL, 10) == strtol (text, NULL, 10);
+       //FIXME: Error checking
+       return strtol (pattern->orig, NULL, 10) == strtol (text, NULL, 10);
       else 
        return 0;
     }
@@ -479,13 +389,14 @@ i_ascii_numeric_is (const char *pattern, const char *text)
 }
 
 static int
-i_ascii_numeric_eq (const char *pattern, const char *text)
+i_ascii_numeric_eq (mu_sieve_machine_t mach,
+                   mu_sieve_string_t *pattern, const char *text)
 {
-  if (mu_isdigit (*pattern))
+  if (mu_isdigit (*pattern->orig))
     {
       if (mu_isdigit (*text))
        {
-         size_t a = strtoul (pattern, NULL, 10);
+         size_t a = strtoul (pattern->orig, NULL, 10);
          size_t b = strtoul (text, NULL, 10);
          if (b > a)
            return 1;
diff --git a/libmu_sieve/extensions/editheader.c 
b/libmu_sieve/extensions/editheader.c
index 52c745e..3ef017f 100644
--- a/libmu_sieve/extensions/editheader.c
+++ b/libmu_sieve/extensions/editheader.c
@@ -81,7 +81,6 @@ sieve_deleteheader (mu_sieve_machine_t mach)
 {
   mu_sieve_value_t *val;
   const char *field_name;
-  const char *field_pattern;
   mu_message_t msg;
   mu_header_t hdr;
   int rc;
@@ -91,41 +90,9 @@ sieve_deleteheader (mu_sieve_machine_t mach)
   
   mu_sieve_get_arg (mach, 0, SVT_STRING, &field_name);
   val = mu_sieve_get_arg_optional (mach, 1);
-  if (!val)
-    {
-      field_pattern = NULL;
-      mu_sieve_log_action (mach, "DELETEHEADER", "%s", field_name);
-    }
-  else
-    {
-      switch (val->type)
-       {
-       case SVT_STRING_LIST:
-         if (mu_list_get (val->v.list, 0, (void**)&field_pattern))
-           {
-             mu_sieve_error (mach, "%lu: %s",
-                             (unsigned long) mu_sieve_get_message_num (mach),
-                             _("cannot get list item"));
-             mu_sieve_abort (mach);
-           }
-         mu_sieve_log_action (mach, "DELETEHEADER", "%s: (regexp)",
-                              field_name);
-         break;
-         
-       case SVT_STRING:
-         field_pattern = val->v.string;
-         mu_sieve_log_action (mach, "DELETEHEADER", "%s: %s", field_name,
-                              field_pattern);
-         break;
-
-       default:
-         mu_sieve_error (mach, "%lu: %s: %d",
-                         (unsigned long) mu_sieve_get_message_num (mach),
-                         _("unexpected value type"), val->type);
-         mu_sieve_abort (mach);
-         
-       }
-    }
+
+  mu_sieve_log_action (mach, "DELETEHEADER", "%s%s", field_name,
+                      val ? " (values)" : "" );
   
   if (mu_sieve_is_dry_run (mach))
     return 0;
@@ -141,7 +108,14 @@ sieve_deleteheader (mu_sieve_machine_t mach)
       mu_sieve_abort (mach);
     }
 
-  mu_header_get_iterator (hdr, &itr);
+  rc = mu_header_get_iterator (hdr, &itr);
+  if (rc)
+    {
+      mu_sieve_error (mach, "mu_header_get_iterator: %s",
+                     mu_strerror (rc));
+      mu_sieve_abort (mach);
+    }
+      
   if (mu_sieve_get_tag (mach, "last", SVT_VOID, NULL))
     {
       int backwards = 1;
@@ -162,10 +136,18 @@ sieve_deleteheader (mu_sieve_machine_t mach)
       if (idx && ++i < idx)
        continue;
          
-      if (field_pattern)
+      if (val)
        {
-         if (comp (field_pattern, fv))
-           mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
+         for (i = 0; i < val->v.list.count; i++)
+           {
+             mu_sieve_string_t *s = mu_sieve_string_raw (mach,
+                                                         &val->v.list, i);
+             if (comp (mach, s, fv))
+               {
+                 mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
+                 break;
+               }
+           }
        }
       else
        mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
diff --git a/libmu_sieve/extensions/list.c b/libmu_sieve/extensions/list.c
index 71696c6..3a64e0a 100644
--- a/libmu_sieve/extensions/list.c
+++ b/libmu_sieve/extensions/list.c
@@ -159,7 +159,7 @@ list_test (mu_sieve_machine_t mach)
   h = mu_sieve_get_arg_untyped (mach, 0);
   v = mu_sieve_get_arg_untyped (mach, 1);
   mu_message_get_header (mu_sieve_get_message (mach), &clos.header);
-  result = mu_sieve_vlist_compare (h, v, comp,
+  result = mu_sieve_vlist_compare (mach, h, v, comp,
                                   mu_sieve_get_relcmp (mach),
                                   list_retrieve_header,
                                   &clos, NULL) > 0;
diff --git a/libmu_sieve/extensions/vacation.c 
b/libmu_sieve/extensions/vacation.c
index 989a87a..fa19c87 100644
--- a/libmu_sieve/extensions/vacation.c
+++ b/libmu_sieve/extensions/vacation.c
@@ -161,8 +161,8 @@ _compare (void *item, void *data)
    of the originating mail. Return non-zero if so and store a pointer
    to the matching address in *MY_ADDRESS. */
 static int
-match_addresses (mu_header_t hdr, char *email, mu_sieve_value_t *addresses,
-                char const **my_address)
+match_addresses (mu_sieve_machine_t mach, mu_header_t hdr, char *email,
+                mu_sieve_value_t *addresses, char const **my_address)
 {
   int match = 0;
   const char *str;
@@ -176,7 +176,7 @@ match_addresses (mu_header_t hdr, char *email, 
mu_sieve_value_t *addresses,
          if (_compare (email, &ad))
            match = 1;
          else if (addresses)
-           match += mu_sieve_vlist_do (addresses, _compare, &ad);
+           match += mu_sieve_vlist_do (mach, addresses, _compare, &ad);
          mu_address_destroy (&ad.addr);
        }
     }
@@ -188,7 +188,7 @@ match_addresses (mu_header_t hdr, char *email, 
mu_sieve_value_t *addresses,
          if (_compare (email, &ad))
            match = 1;
          else if (addresses)
-           match += mu_sieve_vlist_do (addresses, _compare, &ad);
+           match += mu_sieve_vlist_do (mach, addresses, _compare, &ad);
          mu_address_destroy (&ad.addr);
        }
     }
@@ -249,8 +249,8 @@ noreply_address_p (mu_sieve_machine_t mach, char *email)
   for (i = 0; rc == 0 && noreply_sender[i]; i++)
     rc = regex_comparator (noreply_sender[i], &rd);
 
-  if (!rc && mu_sieve_get_tag_untyped (mach, "noreply", &arg))
-    rc = mu_sieve_vlist_do (arg, regex_comparator, &rd);
+  if (!rc && (arg = mu_sieve_get_tag_untyped (mach, "noreply")) != NULL)
+    rc = mu_sieve_vlist_do (mach, arg, regex_comparator, &rd);
   
   return rc;
 }
@@ -716,12 +716,13 @@ vacation_reply (mu_sieve_machine_t mach, mu_message_t msg,
     {
       mu_header_set_value (newhdr, MU_HEADER_TO, to, 0);
 
-      if (mu_sieve_get_tag_untyped (mach, "header", &val))
+      val = mu_sieve_get_tag_untyped (mach, "header");
+      if (val)
        {
          struct header_closure hc;
          hc.mach = mach;
          hc.hdr = newhdr;
-         mu_sieve_vlist_do (val, add_header, &hc);
+         mu_sieve_vlist_do (mach, val, add_header, &hc);
        }
       
       vacation_subject (mach, msg, newhdr);
@@ -807,9 +808,8 @@ sieve_action_vacation (mu_sieve_machine_t mach)
     return_address = my_address;
   else
     {
-      mu_sieve_value_t *val = NULL;
-      mu_sieve_get_tag_untyped (mach, "aliases", &val);
-      if (match_addresses (hdr, my_address, val, &return_address) == 0)
+      mu_sieve_value_t *val = mu_sieve_get_tag_untyped (mach, "aliases");
+      if (match_addresses (mach, hdr, my_address, val, &return_address) == 0)
        {
          free (my_address);
          return 0;
diff --git a/libmu_sieve/mem.c b/libmu_sieve/mem.c
index f03b06d..25dc26c 100644
--- a/libmu_sieve/mem.c
+++ b/libmu_sieve/mem.c
@@ -196,11 +196,42 @@ mu_sieve_reclaim_value (void *p)
   /* For now, the same as _default.  Will change in the future */
   free (p);
 }
-
+
+/* Based on gnulib's x2nrealloc */
 void
-mu_sieve_reclaim_tag (void *p)
+mu_i_sv_2nrealloc (mu_sieve_machine_t mach, void **pptr, size_t *pnmemb,
+                  size_t size)
 {
-  mu_sieve_runtime_tag_t *tag = p;
-  mu_sieve_reclaim_value (tag->arg);
-}
+  void *ptr = *pptr;
+  size_t nmemb = *pnmemb;
+  
+  if (!ptr)
+    {
+      if (!nmemb)
+       {
+         /* Initial allocation size */
+         nmemb = 16;
+       }
+    }
+  else
+    {
+      /* Set NMEMB = floor (1.5 * NMEMB) + 1 so that progress is made even
+        if NMEMB == 0.
+        Check for overflow, so that NMEMB * SIZE stays in size_t range.
+        The check may be slightly conservative, but an exact check isn't
+        worth the trouble.  */
+      if ((size_t) -1 / 3 * 2 / size <= nmemb)
+       {
+         mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
+                           _("requested too much memory %zu * %zu"),
+                           nmemb, size);
+         mu_sieve_abort (mach);
+       }
+      nmemb += nmemb / 2 + 1;
+    }
 
+  ptr = mu_sieve_realloc (mach, ptr, nmemb * size);
+  
+  *pptr = ptr;
+  *pnmemb = nmemb;
+}
diff --git a/libmu_sieve/prog.c b/libmu_sieve/prog.c
index 8c6bc6d..17b6587 100644
--- a/libmu_sieve/prog.c
+++ b/libmu_sieve/prog.c
@@ -24,25 +24,15 @@
 #include <assert.h>
 #include <sieve-priv.h>
 
-int
+void
 mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op)
 {
   if (mach->pc >= mach->progsize)
     {
-      size_t newsize = mach->progsize + SIEVE_CODE_INCR;
-      sieve_op_t *newprog =
-       mu_sieve_realloc (mach, mach->prog, newsize * sizeof mach->prog[0]);
-      if (!newprog)
-       {
-         mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, _("not enough memory"));
-         mu_i_sv_error (mach);
-         return 1;
-       }
-      mach->prog = newprog;
-      mach->progsize = newsize;
+      mu_i_sv_2nrealloc (mach, (void**) &mach->prog, &mach->progsize,
+                        sizeof mach->prog[0]);
     }
   mach->prog[mach->pc++] = op;
-  return 0;
 }
 
 static int
@@ -105,249 +95,247 @@ _compare_ptr (void *item, void *data)
 struct check_arg
 {
   struct mu_sieve_machine *mach;
-  const char *name;
-  mu_list_t args;
-  mu_list_t tags;
+  struct mu_sieve_node *node;
 };
 
 static int
 _run_checker (void *item, void *data)
 {
   struct check_arg *arg = data;
-  return (*(mu_sieve_tag_checker_t)item) (arg->mach, arg->name,
-                                         arg->tags, arg->args);
+  mu_sieve_machine_t mach = arg->mach;
+  struct mu_sieve_node *node = arg->node;
+  mu_sieve_tag_checker_t checker = item;
+  int rc;
+
+  mach->comparator = node->v.command.comparator;
+  mach->argstart = node->v.command.argstart;
+  mach->argcount = node->v.command.argcount;
+  mach->tagcount = node->v.command.tagcount;
+  mach->identifier = node->v.command.reg->name;
+  
+  rc = checker (arg->mach);
+
+  /* checker is allowed to alter these values */
+  node->v.command.comparator = mach->comparator;
+  node->v.command.argcount = mach->argcount;
+  node->v.command.tagcount = mach->tagcount;
+  
+  mach->argstart = 0;
+  mach->argcount = 0;
+  mach->tagcount = 0;
+  mach->identifier = NULL;
+
+  return rc;
 }
 
-static int
-sv_code_command (struct mu_sieve_machine *mach,
-                mu_sieve_register_t *reg, mu_list_t arglist)
+void
+mu_i_sv_lint_command (struct mu_sieve_machine *mach,
+                     struct mu_sieve_node *node)
 {
-  mu_iterator_t itr;
-  mu_list_t arg_list = NULL;
-  mu_list_t tag_list = NULL;
+  size_t i;
+  mu_sieve_register_t *reg = node->v.command.reg;
+
+  mu_sieve_value_t *start = mach->valspace + node->v.command.argstart;
+  
   mu_list_t chk_list = NULL;
   mu_sieve_data_type *exp_arg;
   int opt_args = 0;
   int rc, err = 0;
   static mu_sieve_data_type empty[] = { SVT_VOID };
   
-  if (mu_i_sv_code (mach, (sieve_op_t) reg->handler))
-    return 1;
-
   exp_arg = reg->req_args ? reg->req_args : empty;
 
-  if (arglist)
+  /* Pass 1: consolidation */
+  for (i = 0; i < node->v.command.argcount; i++)
     {
-      rc = mu_list_get_iterator (arglist, &itr);
-
-      if (rc)
-       {
-         mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
-                           _("cannot create iterator: %s"),
-                           mu_strerror (rc));
-         mu_i_sv_error (mach);
-         return 1;
-       }
-  
-      for (mu_iterator_first (itr);
-          !mu_iterator_is_done (itr); mu_iterator_next (itr))
-       {
-         mu_sieve_value_t *val;
-         mu_sieve_runtime_tag_t tagrec, *tagptr;
+      mu_sieve_value_t *val = start + i;
          
-         mu_iterator_current (itr, (void **)&val);
+      if (val->type == SVT_TAG)
+       {
+         mu_sieve_tag_checker_t cf;
+         mu_sieve_tag_def_t *tag = find_tag (reg->tags, val->v.string, &cf);
+             
+         if (!tag)
+           {
+             mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                               _("invalid tag name `%s' for `%s'"),
+                               val->v.string, reg->name);
+             mu_i_sv_error (mach);
+             err = 1;
+             break;
+           }
+
+         node->v.command.tagcount++;
          
-         if (val->type == SVT_TAG)
+         if (tag->argtype == SVT_VOID)
+           {
+             val->type = SVT_VOID;
+             val->tag = val->v.string;
+             val->v.string = NULL;
+           }
+         else
            {
-             mu_sieve_tag_checker_t cf;
-             mu_sieve_tag_def_t *tag = find_tag (reg->tags, val->v.string,
-                                                 &cf);
-             if (!tag)
+             if (i + 1 == node->v.command.argcount)
                {
                  mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                   _("invalid tag name `%s' for `%s'"),
-                                   val->v.string, reg->name);
+                                   _("required argument for tag %s is 
missing"),
+                                   tag->name);
                  mu_i_sv_error (mach);
                  err = 1;
                  break;
                }
+
+             val[1].tag = val->v.string;
+             *val = val[1];
+             memmove (val + 1, val + 2,
+                      (node->v.command.argcount - i - 2) * sizeof (val[0]));
+             mach->valcount--;
+             node->v.command.argcount--;
              
-             if (!tag_list && (rc = mu_list_create (&tag_list)))
+             if (val->type != tag->argtype)
                {
                  mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                   _("cannot create tag list: %s"),
-                                   mu_strerror (rc));
+                                   _("type mismatch in argument to "
+                                     "tag `%s'"),
+                                   tag->name);
+                 mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                                   _("expected %s but passed %s"),
+                                   mu_sieve_type_str (tag->argtype),
+                                   mu_sieve_type_str (val->type));
                  mu_i_sv_error (mach);
                  err = 1;
                  break;
                }
-             
-             tagrec.tag = tag->name;
-             if (tag->argtype != SVT_VOID)
-               {
-                 mu_iterator_next (itr);
-                 if (mu_iterator_is_done (itr))
-                   {
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                          _("required argument for tag %s is missing"),
-                                       tag->name);
-                     mu_i_sv_error (mach);
-                     err = 1;
-                     break;
-                   }
-                 mu_iterator_current (itr, (void **)&tagrec.arg);
-                 if (tagrec.arg->type != tag->argtype)
-                   {
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                            _("type mismatch in argument to "
-                                              "tag `%s'"),
-                                            tag->name);
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                            _("expected %s but passed %s"),
-                                            mu_sieve_type_str (tag->argtype),
-                                            mu_sieve_type_str 
(tagrec.arg->type));
-                     mu_i_sv_error (mach);
-                     err = 1;
-                     break;
-                   }
-               }
-             else
-               tagrec.arg = NULL;
-             
-             tagptr = mu_sieve_malloc (mach, sizeof (*tagptr));
-             *tagptr = tagrec;
-             mu_list_append (tag_list, tagptr);
+           }
 
-             if (cf)
+         if (cf)
+           {
+             if (!chk_list && (rc = mu_list_create (&chk_list)))
                {
-                 if (!chk_list && (rc = mu_list_create (&chk_list)))
-                   {
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                       _("cannot create check list: %s"),
-                                       mu_strerror (rc));
-                     mu_i_sv_error (mach);
-                     err = 1;
-                     break;
-                   }
-                 if (mu_list_foreach (chk_list, _compare_ptr, cf) == 0)
-                   mu_list_append (chk_list, cf);
+                 mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                                   _("cannot create check list: %s"),
+                                   mu_strerror (rc));
+                 mu_i_sv_error (mach);
+                 err = 1;
+                 break;
                }
+             //FIXME
+             if (mu_list_foreach (chk_list, _compare_ptr, cf) == 0)
+               mu_list_append (chk_list, cf);
            }
-         else
+       }
+      else
+       {
+         if (*exp_arg == SVT_VOID)
            {
-             if (*exp_arg == SVT_VOID)
+             if (reg->opt_args)
                {
-                 if (reg->opt_args)
-                   {
-                     exp_arg = reg->opt_args;
-                     opt_args = 1;
-                   }
-                 else
-                   {
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                       _("too many arguments in call to `%s'"),
-                                       reg->name);
-                     mu_i_sv_error (mach);
-                     err = 1;
-                     break;
-                   }
+                 exp_arg = reg->opt_args;
+                 opt_args = 1;
                }
-             
-             if (*exp_arg != val->type)
+             else
                {
-                 if (*exp_arg == SVT_STRING_LIST && val->type == SVT_STRING)
-                   {
-                     mu_list_t list;
-
-                     mu_list_create (&list);
-                     mu_list_append (list, val->v.string);
-                     mu_sieve_free (mach, val);
-                     val = mu_sieve_value_create (mach, SVT_STRING_LIST, list);
-                   }
-                 else
-                   {
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                   _("type mismatch in argument %lu to `%s'"),
-                                  (unsigned long) (exp_arg - reg->req_args + 
1),
-                                            reg->name);
-                     mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                       _("expected %s but passed %s"),
-                                       mu_sieve_type_str (*exp_arg),
-                                       mu_sieve_type_str (val->type));
-                     mu_i_sv_error (mach);
-                     err = 1;
-                     break;
-                   }
+                 mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                                   _("too many arguments in call to `%s'"),
+                                   reg->name);
+                 mu_i_sv_error (mach);
+                 err = 1;
+                 break;
                }
-
-             if (!arg_list && (rc = mu_list_create (&arg_list)))
+           }
+             
+         if (*exp_arg != val->type)
+           {
+             if (*exp_arg == SVT_STRING_LIST && val->type == SVT_STRING)
+               /* compatible types */;
+             else
                {
                  mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                                   _("cannot create arg list: %s"),
-                                   mu_strerror (rc));
+                                   _("type mismatch in argument %lu to `%s'"),
+                                   (unsigned long) (exp_arg - reg->req_args + 
1),
+                                   reg->name);
+                 mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                                   _("expected %s but passed %s"),
+                                   mu_sieve_type_str (*exp_arg),
+                                   mu_sieve_type_str (val->type));
                  mu_i_sv_error (mach);
                  err = 1;
                  break;
                }
-             
-             mu_list_append (arg_list, val);
-             exp_arg++;
-           }       
+           }
+         exp_arg++;
        }
-      mu_iterator_destroy (&itr);
     }
 
-  if (!err)
+  if (!err && !opt_args && *exp_arg != SVT_VOID)
     {
-      if (!opt_args && *exp_arg != SVT_VOID)
-       {
-         mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
-                           _("too few arguments in call to `%s'"),
-                           reg->name);
-         mu_i_sv_error (mach);
-         err = 1;
-       }
+      mu_diag_at_locus (MU_LOG_ERROR, &mach->locus, 
+                       _("too few arguments in call to `%s'"),
+                       reg->name);
+      mu_i_sv_error (mach);
+      err = 1;
+    }
+  
+  if (err)
+    {
+      mu_list_destroy (&chk_list);
+      return;
+    }
 
-      if (chk_list)
+  if (node->v.command.tagcount)
+    {
+      /* Move tags to the end of the list */
+      for (i = 1; i < node->v.command.argcount; i++)
        {
-         struct check_arg chk_arg;
-
-         chk_arg.mach = mach;
-         chk_arg.name = reg->name;
-         chk_arg.tags = tag_list;
-         chk_arg.args = arg_list;
-         err = mu_list_foreach (chk_list, _run_checker, &chk_arg);
+         int j;//FIXME
+         mu_sieve_value_t tmp = start[i];
+         for (j = i - 1; j >= 0; j--)
+           {
+             if (!tmp.tag && start[j].tag)
+               start[j + 1] = start[j];
+             else
+               break;
+           }
+         start[j + 1] = tmp;
        }
     }
-  
-  if (!err)
-    err = mu_i_sv_code (mach, (sieve_op_t) arg_list)
-      || mu_i_sv_code (mach, (sieve_op_t) tag_list)
-      || mu_i_sv_code (mach, (sieve_op_t) (char*) reg->name);
 
-  if (err)
+  node->v.command.argcount -= node->v.command.tagcount;
+  
+  if (chk_list)
     {
-      mu_list_destroy (&arg_list);
-      mu_list_destroy (&tag_list);
-      mu_list_destroy (&chk_list);
+      struct check_arg chk_arg;
+
+      chk_arg.mach = mach;
+      chk_arg.node = node;
+      err = mu_list_foreach (chk_list, _run_checker, &chk_arg);
     }
+}  
 
-  return err;
+static void
+sv_code_command (struct mu_sieve_machine *mach,
+                struct mu_sieve_node *node)
+{
+  mu_i_sv_code (mach, (sieve_op_t) node->v.command.reg->handler);
+  mu_i_sv_code (mach, (sieve_op_t) node->v.command.argstart);
+  mu_i_sv_code (mach, (sieve_op_t) node->v.command.argcount);
+  mu_i_sv_code (mach, (sieve_op_t) node->v.command.tagcount);
+  mu_i_sv_code (mach, (sieve_op_t) (char*) node->v.command.reg->name);
+  mu_i_sv_code (mach, (sieve_op_t) node->v.command.comparator);
 }
 
-int
+void
 mu_i_sv_code_action (struct mu_sieve_machine *mach,
-                    mu_sieve_register_t *reg, mu_list_t arglist)
+                    struct mu_sieve_node *node)
 {
-  return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_action)
-         || sv_code_command (mach, reg, arglist);
+  mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_action);
+  sv_code_command (mach, node);
 }
 
-int
-mu_i_sv_code_test (struct mu_sieve_machine *mach,
-                  mu_sieve_register_t *reg, mu_list_t arglist)
+void
+mu_i_sv_code_test (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
-  return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_test)
-         || sv_code_command (mach, reg, arglist);
+  mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_test);
+  sv_code_command (mach, node);
 }
 
diff --git a/libmu_sieve/relational.c b/libmu_sieve/relational.c
index 7d18ea8..81006b4 100644
--- a/libmu_sieve/relational.c
+++ b/libmu_sieve/relational.c
@@ -38,7 +38,8 @@ DCL(ge,>=)
 DCL(lt,<)
 DCL(le,<=)
 
-static struct reltest_tab {
+static struct reltest_tab
+{
   char *name;
   mu_sieve_relcmp_t test;
   mu_sieve_relcmpn_t stest;
@@ -66,7 +67,7 @@ _relcmp_lookup (const char *str)
 
 int
 mu_sieve_str_to_relcmp (const char *str,
-                     mu_sieve_relcmp_t *test, mu_sieve_relcmpn_t *stest)
+                       mu_sieve_relcmp_t *test, mu_sieve_relcmpn_t *stest)
 {
   struct reltest_tab *t = _relcmp_lookup (str);
   if (t)
diff --git a/libmu_sieve/require.c b/libmu_sieve/require.c
index 2f76d05..a04d654 100644
--- a/libmu_sieve/require.c
+++ b/libmu_sieve/require.c
@@ -27,30 +27,17 @@
 #include <sieve-priv.h>
 
 void
-mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist)
+mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list)
 {
-  int status;
-  mu_iterator_t itr;
+  size_t i;
   
-  status = mu_list_get_iterator (slist, &itr);
-  if (status)
+  for (i = 0; i < list->count; i++)
     {
-      mu_diag_at_locus (MU_LOG_ERROR, &mach->locus,
-                       _("cannot create iterator: %s"),
-                       mu_strerror (status));
-      mu_i_sv_error (mach);
-      return;
-    }
-
-  for (mu_iterator_first (itr);
-       !mu_iterator_is_done (itr); mu_iterator_next (itr))
-    {
-      char *name;
+      struct mu_sieve_string *str = mu_sieve_string_raw (mach, list, i);
+      char *name = str->orig;
       int (*reqfn) (mu_sieve_machine_t mach, const char *name) = NULL;
       const char *text = NULL;
       
-      mu_iterator_current (itr, (void **)&name);
-
       if (strncmp (name, "comparator-", 11) == 0)
        {
          name += 11;
@@ -87,6 +74,5 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_list_t slist)
          mu_i_sv_error (mach);
        }
     }
-  mu_iterator_destroy (&itr);
 }
      
diff --git a/libmu_sieve/runtime.c b/libmu_sieve/runtime.c
index 1c0e38b..fea9bf8 100644
--- a/libmu_sieve/runtime.c
+++ b/libmu_sieve/runtime.c
@@ -24,8 +24,8 @@
 #include <assert.h>
 #include <sieve-priv.h>
 
-#define SIEVE_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
-#define SIEVE_ADJUST(m,n) (m)->pc+=(n)
+#define SIEVE_RT_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
+#define SIEVE_RT_ADJUST(m,n) (m)->pc+=(n)
 
 #define INSTR_DISASS(m) ((m)->state == mu_sieve_state_disass)
 #define INSTR_DEBUG(m) \
@@ -34,49 +34,53 @@
 void
 _mu_i_sv_instr_source (mu_sieve_machine_t mach)
 {
-  mach->locus.mu_file = (char*) SIEVE_ARG (mach, 0, string);
+  mach->locus.mu_file = (char*) SIEVE_RT_ARG (mach, 0, string);
   mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
                    MU_IOCTL_LOGSTREAM_SET_LOCUS,
                   &mach->locus);
   if (INSTR_DEBUG (mach))
     mu_i_sv_debug (mach, mach->pc - 1, "SOURCE %s", mach->locus.mu_file);
-  SIEVE_ADJUST (mach, 1);
+  SIEVE_RT_ADJUST (mach, 1);
 }
                 
 void
 _mu_i_sv_instr_line (mu_sieve_machine_t mach)
 {
-  mach->locus.mu_line = SIEVE_ARG (mach, 0, line);
+  mach->locus.mu_line = SIEVE_RT_ARG (mach, 0, line);
   mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
                    MU_IOCTL_LOGSTREAM_SET_LOCUS,
                   &mach->locus);
   if (INSTR_DEBUG (mach))
     mu_i_sv_debug (mach, mach->pc - 1, "LINE %u",
                   mach->locus.mu_line);
-  SIEVE_ADJUST (mach, 1);
+  SIEVE_RT_ADJUST (mach, 1);
 }
                 
 static int
 instr_run (mu_sieve_machine_t mach, char const *what)
 {
   int rc = 0;
-  mu_sieve_handler_t han = SIEVE_ARG (mach, 0, handler);
-  mach->arg_list = SIEVE_ARG (mach, 1, list);
-  mach->tag_list = SIEVE_ARG (mach, 2, list);
-  mach->identifier = SIEVE_ARG (mach, 3, string);
-  
-  SIEVE_ADJUST (mach, 4);
+  mu_sieve_handler_t han = SIEVE_RT_ARG (mach, 0, handler);
+  mach->argstart = SIEVE_RT_ARG (mach, 1, pc);
+  mach->argcount = SIEVE_RT_ARG (mach, 2, pc);
+  mach->tagcount = SIEVE_RT_ARG (mach, 3, pc);
+  mach->identifier = SIEVE_RT_ARG (mach, 4, string);
+  mach->comparator = SIEVE_RT_ARG (mach, 5, comp);
+                                  
+  SIEVE_RT_ADJUST (mach, 6);
 
   if (INSTR_DEBUG (mach))
-    mu_i_sv_debug_command (mach, mach->pc - 1, what);
+    mu_i_sv_debug_command (mach, mach->pc - 7, what);
   else
     mu_i_sv_trace (mach, what);
   
   if (!INSTR_DISASS (mach))
     rc = han (mach);
-  mach->arg_list = NULL;
-  mach->tag_list = NULL;
+  mach->argstart = 0;
+  mach->argcount = 0;
+  mach->tagcount = 0;
   mach->identifier = NULL;
+  mach->comparator = NULL;
   return rc;
 }
 
@@ -138,9 +142,9 @@ _mu_i_sv_instr_not (mu_sieve_machine_t mach)
 void
 _mu_i_sv_instr_branch (mu_sieve_machine_t mach)
 {
-  long num = SIEVE_ARG (mach, 0, number);
+  long num = SIEVE_RT_ARG (mach, 0, number);
 
-  SIEVE_ADJUST (mach, 1);
+  SIEVE_RT_ADJUST (mach, 1);
   if (INSTR_DEBUG (mach))
     mu_i_sv_debug (mach, mach->pc - 2, "BRANCH %lu",
                   (unsigned long)(mach->pc + num));
@@ -153,8 +157,8 @@ _mu_i_sv_instr_branch (mu_sieve_machine_t mach)
 void
 _mu_i_sv_instr_brz (mu_sieve_machine_t mach)
 {
-  long num = SIEVE_ARG (mach, 0, number);
-  SIEVE_ADJUST (mach, 1);
+  long num = SIEVE_RT_ARG (mach, 0, number);
+  SIEVE_RT_ADJUST (mach, 1);
 
   if (INSTR_DEBUG (mach))
     mu_i_sv_debug (mach, mach->pc - 2, "BRZ %lu",
@@ -169,8 +173,8 @@ _mu_i_sv_instr_brz (mu_sieve_machine_t mach)
 void
 _mu_i_sv_instr_brnz (mu_sieve_machine_t mach)
 {
-  long num = SIEVE_ARG (mach, 0, number);
-  SIEVE_ADJUST (mach, 1);
+  long num = SIEVE_RT_ARG (mach, 0, number);
+  SIEVE_RT_ADJUST (mach, 1);
 
   if (INSTR_DEBUG (mach))
     mu_i_sv_debug (mach, mach->pc - 2, "BRNZ %lu",
diff --git a/libmu_sieve/sieve-priv.h b/libmu_sieve/sieve-priv.h
index d7b389b..7ae2fdf 100644
--- a/libmu_sieve/sieve-priv.h
+++ b/libmu_sieve/sieve-priv.h
@@ -19,8 +19,7 @@
 #include <mailutils/sieve.h>
 #include <setjmp.h>
 #include <string.h>
-
-#define SIEVE_CODE_INCR 128
+#include <regex.h>
 
 typedef void (*sieve_instr_t) (mu_sieve_machine_t mach);
 
@@ -29,6 +28,7 @@ typedef union
   sieve_instr_t instr;
   mu_sieve_handler_t handler;
   mu_sieve_value_t *val;
+  mu_sieve_comparator_t comp;
   mu_list_t list;
   long number;
   size_t pc;
@@ -37,7 +37,7 @@ typedef union
   char *string;
   unsigned unum;
 } sieve_op_t;
-
+
 struct mu_locus_range
 {
   struct mu_locus beg;
@@ -73,6 +73,14 @@ struct mu_sieve_machine
   mu_list_t action_list;     /* Actions */
   mu_list_t comp_list;       /* Comparators */
   mu_list_t source_list;     /* Source names (for diagnostics) */
+
+  mu_sieve_string_t *stringspace;
+  size_t stringcount;
+  size_t stringmax;
+  
+  mu_sieve_value_t *valspace;
+  size_t valcount;
+  size_t valmax;
   
   size_t progsize;           /* Number of allocated program cells */
   sieve_op_t *prog;          /* Compiled program */
@@ -85,8 +93,10 @@ struct mu_sieve_machine
 
   /* Call environment */
   const char *identifier;    /* Name of action or test being executed */
-  mu_list_t arg_list;        /* Positional arguments */
-  mu_list_t tag_list;        /* Tagged arguments */
+  size_t argstart;           /* Index of the first argument in valspace */
+  size_t argcount;           /* Number of positional arguments */
+  size_t tagcount;           /* Number of tagged arguments */
+  mu_sieve_comparator_t comparator; /* Comparator (for tests) */
   
   int dry_run;               /* Dry-run mode */
   jmp_buf errbuf;            /* Target location for non-local exits */
@@ -146,7 +156,10 @@ struct mu_sieve_node
     struct
     {
       mu_sieve_register_t *reg;
-      mu_list_t arg;
+      size_t argstart;
+      size_t argcount;
+      size_t tagcount;
+      mu_sieve_comparator_t comparator; /* Comparator (for tests) */
     } command;
   } v;
 };
@@ -161,18 +174,16 @@ void mu_i_sv_lex_finish (struct mu_sieve_machine *mach);
 
 extern mu_sieve_machine_t mu_sieve_machine;
 
-#define TAG_COMPFUN "__compfun__"
-
-int mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op);
+void mu_i_sv_code (struct mu_sieve_machine *mach, sieve_op_t op);
 
 void mu_i_sv_compile_error (struct mu_sieve_machine *mach,
                            const char *fmt, ...) MU_PRINTFLIKE(2,3);
 
 int mu_i_sv_locus (struct mu_sieve_machine *mach, struct mu_locus_range *lr);
-int mu_i_sv_code_action (struct mu_sieve_machine *mach,
-                        mu_sieve_register_t *reg, mu_list_t arglist);
-int mu_i_sv_code_test (struct mu_sieve_machine *mach,
-                      mu_sieve_register_t *reg, mu_list_t arglist);
+void mu_i_sv_code_action (struct mu_sieve_machine *mach,
+                         struct mu_sieve_node *node);
+void mu_i_sv_code_test (struct mu_sieve_machine *mach,
+                       struct mu_sieve_node *node);
 
 /* Opcodes */
 void _mu_i_sv_instr_action (mu_sieve_machine_t mach);
@@ -203,8 +214,7 @@ void mu_i_sv_debug_command (mu_sieve_machine_t mach, size_t 
pc,
                            char const *what);
 void mu_i_sv_trace (mu_sieve_machine_t mach, const char *what);
 
-void mu_i_sv_argf (mu_stream_t str, mu_list_t list);
-void mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val);
+void mu_i_sv_valf (mu_sieve_machine_t mach, mu_stream_t str, mu_sieve_value_t 
*val);
 
 typedef int (*mu_i_sv_interp_t) (char const *, size_t, char **, void *);
 
@@ -216,4 +226,15 @@ int mu_i_sv_expand_encoded_char (char const *input, size_t 
len, char **exp, void
 int mu_sieve_require_encoded_character (mu_sieve_machine_t mach,
                                        const char *name);
 
+void mu_i_sv_2nrealloc (mu_sieve_machine_t mach,
+                       void **pptr, size_t *pnmemb, size_t size);
+
+
+mu_sieve_value_t *mu_i_sv_mach_arg (mu_sieve_machine_t mach, size_t n);
+mu_sieve_value_t *mu_i_sv_mach_tagn (mu_sieve_machine_t mach, size_t n);
+void mu_i_sv_lint_command (struct mu_sieve_machine *mach,
+                          struct mu_sieve_node *node);
+
+
+size_t  mu_i_sv_string_create (mu_sieve_machine_t mach, char *str);
 
diff --git a/libmu_sieve/sieve.y b/libmu_sieve/sieve.y
index b60d44f..a76b3de 100644
--- a/libmu_sieve/sieve.y
+++ b/libmu_sieve/sieve.y
@@ -79,12 +79,13 @@ static void cond_join (struct mu_sieve_node *node);
 %union {
   char *string;
   size_t number;
-  mu_sieve_value_t *value;
-  mu_list_t list;
+  size_t idx;
+  struct mu_sieve_slice slice;
   struct
   {
     char *ident;
-    mu_list_t args;
+    size_t first;
+    size_t count;
   } command;
   struct node_list
   {
@@ -98,8 +99,8 @@ static void cond_join (struct mu_sieve_node *node);
 %token <string> STRING MULTILINE
 %token REQUIRE IF ELSIF ELSE ANYOF ALLOF NOT FALSE TRUE
 
-%type <value> arg
-%type <list> slist stringlist stringorlist arglist maybe_arglist
+%type <idx> arg
+%type <slice> arglist maybe_arglist slist stringlist stringorlist 
 %type <command> command
 %type <node> action test statement block cond
 %type <node> else_part
@@ -138,10 +139,10 @@ list         : statement
 
 statement    : REQUIRE stringorlist ';'
                {
-                mu_sieve_require (mu_sieve_machine, $2);
-                /*  All the items in $2 are registered in memory_pool,
-                    so we don't free them */
-                mu_list_destroy (&$2);
+                mu_sieve_require (mu_sieve_machine, &$2);
+                /* Reclaim string slots.  The string data referred to by
+                   $2 are registered in memory_pool, so we don't free them */
+                mu_sieve_machine->stringcount -= $2.count;
                 $$ = NULL;
               }
              | action ';'
@@ -265,7 +266,11 @@ test         : command
                 
                 $$ = node_alloc (mu_sieve_node_test, &@1);
                 $$->v.command.reg = reg;
-                $$->v.command.arg = $1.args;
+                $$->v.command.argstart = $1.first;
+                $$->v.command.argcount = $1.count;
+                $$->v.command.tagcount = 0;
+                $$->v.command.comparator = NULL;
+                mu_i_sv_lint_command (mu_sieve_machine, $$);
               }
              | TRUE
               {
@@ -280,7 +285,8 @@ test         : command
 command      : IDENT maybe_arglist
                {
                 $$.ident = $1;
-                $$.args = $2;
+                $$.first = $2.first;
+                $$.count = $2.count;
               }
              ;
 
@@ -308,25 +314,29 @@ action       : command
                 
                 $$ = node_alloc(mu_sieve_node_action, &@1);
                 $$->v.command.reg = reg;
-                $$->v.command.arg = $1.args;
+                $$->v.command.argstart = $1.first;
+                $$->v.command.argcount = $1.count;
+                $$->v.command.tagcount = 0;
+                mu_i_sv_lint_command (mu_sieve_machine, $$);            
               }
              ;
 
 maybe_arglist: /* empty */
                {
-                $$ = NULL;
+                $$.first = 0;
+                $$.count = 0;
               }
              | arglist
             ;
 
 arglist      : arg
                {
-                mu_list_create (&$$);
-                mu_list_append ($$, $1);
+                $$.first = $1;
+                $$.count = 1;
               }                 
              | arglist arg
                {
-                mu_list_append ($1, $2);
+                $1.count++;
                 $$ = $1;
               }
              ;
@@ -334,7 +344,7 @@ arglist      : arg
 arg          : stringlist
                {                
                 $$ = mu_sieve_value_create (mu_sieve_machine,
-                                            SVT_STRING_LIST, $1);
+                                            SVT_STRING_LIST, &$1);
               }
              | STRING
                {
@@ -356,8 +366,8 @@ arg          : stringlist
 
 stringorlist : STRING
                {
-                mu_list_create (&$$);
-                mu_list_append ($$, $1);
+                $$.first = mu_i_sv_string_create (mu_sieve_machine, $1);
+                $$.count = 1;
               }
              | stringlist
              ;
@@ -370,12 +380,13 @@ stringlist   : '[' slist ']'
 
 slist        : STRING
                {
-                mu_list_create (&$$);
-                mu_list_append ($$, $1);
+                $$.first = mu_i_sv_string_create (mu_sieve_machine, $1);
+                $$.count = 1;
               }
              | slist ',' STRING
                {
-                mu_list_append ($1, $3);
+                mu_i_sv_string_create (mu_sieve_machine, $3);
+                $1.count++;
                 $$ = $1;
               }
              ;
@@ -396,7 +407,7 @@ yyerror (const char *s)
 static void
 cond_join (struct mu_sieve_node *node)
 {
-  while (node)
+  while (node && node->type == mu_sieve_node_cond)
     {
       struct mu_sieve_node *next = node->next;
       node->prev = node->next = NULL;
@@ -422,16 +433,18 @@ static void node_optimize (struct mu_sieve_node *node);
 static void node_free (struct mu_sieve_node *node);
 static void node_replace (struct mu_sieve_node *node,
                          struct mu_sieve_node *repl);
-static int node_code (struct mu_sieve_machine *mach,
-                     struct mu_sieve_node *node);
+static void node_code (struct mu_sieve_machine *mach,
+                      struct mu_sieve_node *node);
 static void node_dump (mu_stream_t str, struct mu_sieve_node *node,
-                      unsigned level);
+                      unsigned level, struct mu_sieve_machine *mach);
 
 static void tree_free (struct mu_sieve_node **tree);
 static void tree_optimize (struct mu_sieve_node *tree);
-static int tree_code (struct mu_sieve_machine *mach,
-                     struct mu_sieve_node *tree);
-static void tree_dump (mu_stream_t str, struct mu_sieve_node *tree, unsigned 
level);
+static void tree_code (struct mu_sieve_machine *mach,
+                      struct mu_sieve_node *tree);
+static void tree_dump (mu_stream_t str,
+                      struct mu_sieve_node *tree, unsigned level,
+                      struct mu_sieve_machine *mach);
 
 static void
 indent (mu_stream_t str, unsigned level)
@@ -444,7 +457,8 @@ indent (mu_stream_t str, unsigned level)
 
 /* mu_sieve_node_noop */
 static void
-dump_node_noop (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_noop (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+               struct mu_sieve_machine *mach)
 {
   indent (str, level);
   mu_stream_printf (str, "NOOP\n");  
@@ -452,7 +466,8 @@ dump_node_noop (mu_stream_t str, struct mu_sieve_node 
*node, unsigned level)
 
 /* mu_sieve_node_false */
 static void
-dump_node_false (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_false (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+                struct mu_sieve_machine *mach)
 {
   indent (str, level);
   mu_stream_printf (str, "FALSE\n");
@@ -460,7 +475,8 @@ dump_node_false (mu_stream_t str, struct mu_sieve_node 
*node, unsigned level)
 
 /* mu_sieve_node_true */
 static void
-dump_node_true (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_true (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+               struct mu_sieve_machine *mach)
 {
   indent (str, level);
   mu_stream_printf (str, "TRUE\n");
@@ -470,43 +486,32 @@ dump_node_true (mu_stream_t str, struct mu_sieve_node 
*node, unsigned level)
 static void
 free_node_command (struct mu_sieve_node *node)
 {
-  mu_list_destroy (&node->v.command.arg);
+  /* nothing */
 }
 
-static int
+static void
 code_node_test (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
-  return mu_i_sv_code_test (mach, node->v.command.reg, node->v.command.arg);
+  mu_i_sv_code_test (mach, node);
 }
 
-static int
+static void
 code_node_action (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
-  return mu_i_sv_code_action (mach, node->v.command.reg, node->v.command.arg);
-}
-
-struct string_dumper_data
-{
-  int init;
-  mu_stream_t stream;
-};
-
-static int
-string_dumper (void *item, void *data)
-{
-  struct string_dumper_data *dp = data;
-  if (dp->init == 0)
-    dp->init = 1;
-  else
-    mu_stream_printf (dp->stream, ", ");
-  mu_stream_printf (dp->stream, "\"%s\"", (char*)item);
-  return 0;
+  mu_i_sv_code_action (mach, node);
 }
 
 void
-mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val)
+mu_i_sv_valf (mu_sieve_machine_t mach, mu_stream_t str, mu_sieve_value_t *val)
 {
   mu_stream_printf (str, " ");
+  if (val->tag)
+    {
+      mu_stream_printf (str, ":%s", val->tag);
+      if (val->type == SVT_VOID)
+       return;
+      mu_stream_printf (str, " ");
+    }
   switch (val->type)
     {
     case SVT_VOID:
@@ -518,16 +523,22 @@ mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val)
       break;
       
     case SVT_STRING:
-      mu_stream_printf (str, "\"%s\"", val->v.string);
+      mu_stream_printf (str, "\"%s\"",
+                       mu_sieve_string_raw (mach, &val->v.list, 0)->orig);
       break;
       
     case SVT_STRING_LIST:
       {
-       struct string_dumper_data d;
-       d.init = 0;
-       d.stream = str;
+       size_t i;
+       
        mu_stream_printf (str, "[");
-       mu_list_foreach (val->v.list, string_dumper, &d);
+       for (i = 0; i < val->v.list.count; i++)
+         {
+           if (i)
+             mu_stream_printf (str, ", ");
+           mu_stream_printf (str, "\"%s\"",
+                             mu_sieve_string_raw (mach, &val->v.list, 
i)->orig);
+         }
        mu_stream_printf (str, "]");
       }
       break;
@@ -540,36 +551,21 @@ mu_i_sv_valf (mu_stream_t str, mu_sieve_value_t *val)
       mu_stream_printf (str, "%s", val->v.string);
       break;
        
-    case SVT_POINTER:
-      mu_stream_printf (str, "%p", val->v.ptr);
-      break;
-
     default:
       abort ();
     }
 }
   
-static int
-dump_val (void *item, void *data)
-{
-  mu_sieve_value_t *val = item;
-  mu_stream_t str = data;
-  mu_i_sv_valf (str, val);
-  return 0;
-}
-
-void
-mu_i_sv_argf (mu_stream_t str, mu_list_t list)
-{
-  mu_list_foreach (list, dump_val, str);
-}
-
 static void
-dump_node_command (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_command (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+                  struct mu_sieve_machine *mach)
 {
+  size_t i;
+  
   indent (str, level);
   mu_stream_printf (str, "COMMAND %s", node->v.command.reg->name);
-  mu_list_foreach (node->v.command.arg, dump_val, str);
+  for (i = 0; i < node->v.command.argcount + node->v.command.tagcount; i++)
+    mu_i_sv_valf (mach, str, &mach->valspace[node->v.command.argstart + i]);
   mu_stream_printf (str, "\n");
 }
 
@@ -604,7 +600,7 @@ optimize_node_cond (struct mu_sieve_node *node)
     }
 }
 
-static int
+static void
 code_node_cond (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
   size_t br1;
@@ -630,11 +626,11 @@ code_node_cond (struct mu_sieve_machine *mach, struct 
mu_sieve_node *node)
     }
   else
     mach->prog[br1].pc = mach->pc - br1 - 1;
-  return 0;
 }
   
 static void
-dump_node_cond (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_cond (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+               struct mu_sieve_machine *mach)
 {
   indent (str, level);
   mu_stream_printf (str, "COND\n");
@@ -643,15 +639,15 @@ dump_node_cond (mu_stream_t str, struct mu_sieve_node 
*node, unsigned level)
 
   indent (str, level);
   mu_stream_printf (str, "EXPR:\n");
-  tree_dump (str, node->v.cond.expr, level + 1);
+  tree_dump (str, node->v.cond.expr, level + 1, mach);
 
   indent (str, level);
   mu_stream_printf (str, "IFTRUE:\n");
-  tree_dump (str, node->v.cond.iftrue, level + 1);
+  tree_dump (str, node->v.cond.iftrue, level + 1, mach);
 
   indent (str, level);
   mu_stream_printf (str, "IFFALSE:\n");
-  tree_dump (str, node->v.cond.iffalse, level + 1);
+  tree_dump (str, node->v.cond.iffalse, level + 1, mach);
 }
 
 /* mu_sieve_node_anyof & mu_sieve_node_allof */
@@ -703,7 +699,7 @@ optimize_x_of (struct mu_sieve_node *node, enum 
mu_sieve_node_type solve)
     node->type = solve == mu_sieve_node_false ? mu_sieve_node_true : 
mu_sieve_node_false;
 }
 
-static int
+static void
 code_node_x_of (struct mu_sieve_machine *mach, struct mu_sieve_node *node,
                sieve_op_t op)
 {
@@ -731,12 +727,11 @@ code_node_x_of (struct mu_sieve_machine *mach, struct 
mu_sieve_node *node,
       mach->prog[pc].pc = end - pc - 1;
       pc = prev;
     }
-
-  return 0;
 }
 
 static void
-dump_node_x_of (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_x_of (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+               mu_sieve_machine_t mach)
 {
   indent (str, level);
   mu_stream_printf (str, "%s:\n",
@@ -746,7 +741,7 @@ dump_node_x_of (mu_stream_t str, struct mu_sieve_node 
*node, unsigned level)
   node = node->v.node;
   while (node)
     {
-      node_dump (str, node, level + 1);
+      node_dump (str, node, level + 1, mach);
       node = node->next;
       if (node)
        {
@@ -764,10 +759,10 @@ optimize_node_anyof (struct mu_sieve_node *node)
   optimize_x_of (node, mu_sieve_node_true);
 }
 
-static int
+static void
 code_node_anyof (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
-  return code_node_x_of (mach, node, (sieve_op_t) _mu_i_sv_instr_brnz);
+  code_node_x_of (mach, node, (sieve_op_t) _mu_i_sv_instr_brnz);
 }
 
 /* mu_sieve_node_allof */
@@ -777,10 +772,10 @@ optimize_node_allof (struct mu_sieve_node *node)
   return optimize_x_of (node, mu_sieve_node_false);
 }
 
-static int
+static void
 code_node_allof (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
-  return code_node_x_of (mach, node, (sieve_op_t) _mu_i_sv_instr_brz);
+  code_node_x_of (mach, node, (sieve_op_t) _mu_i_sv_instr_brz);
 }
 
 /* mu_sieve_node_not */
@@ -811,27 +806,29 @@ optimize_node_not (struct mu_sieve_node *node)
     }
 }
 
-static int
+static void
 code_node_not (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
   node_code (mach, node->v.node);
-  return mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_not);
+  mu_i_sv_code (mach, (sieve_op_t) _mu_i_sv_instr_not);
 }
 
 static void
-dump_node_not (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+dump_node_not (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+              struct mu_sieve_machine *mach)
 {
   indent (str, level);
   mu_stream_printf (str, "NOT\n");
-  node_dump (str, node->v.node, level + 1);
+  node_dump (str, node->v.node, level + 1, mach);
 }
 
 struct node_descr
 {
-  int (*code_fn) (struct mu_sieve_machine *mach, struct mu_sieve_node *node);
+  void (*code_fn) (struct mu_sieve_machine *mach, struct mu_sieve_node *node);
   void (*optimize_fn) (struct mu_sieve_node *node);
   void (*free_fn) (struct mu_sieve_node *node);
-  void (*dump_fn) (mu_stream_t str, struct mu_sieve_node *node, unsigned 
level);
+  void (*dump_fn) (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+                  mu_sieve_machine_t);
 
 };
 
@@ -913,28 +910,27 @@ node_replace (struct mu_sieve_node *node, struct 
mu_sieve_node *repl)
     node_descr[node->type].free_fn (&copy);
 }
 
-static int
+static void
 node_code (struct mu_sieve_machine *mach, struct mu_sieve_node *node)
 {
   if ((int)node->type >= MU_ARRAY_SIZE (node_descr))
     abort ();
 
-  if (!node_descr[node->type].code_fn)
-    return 0;
-
-  if (mu_i_sv_locus (mach, &node->locus))
-    return 1;
-
-  return node_descr[node->type].code_fn (mach, node);
+  if (node_descr[node->type].code_fn)
+    {
+      mu_i_sv_locus (mach, &node->locus);
+      node_descr[node->type].code_fn (mach, node);
+    }
 }
 
 static void
-node_dump (mu_stream_t str, struct mu_sieve_node *node, unsigned level)
+node_dump (mu_stream_t str, struct mu_sieve_node *node, unsigned level,
+          struct mu_sieve_machine *mach)
 {
   if ((int)node->type >= MU_ARRAY_SIZE (node_descr)
       || !node_descr[node->type].dump_fn) 
     abort ();
-  node_descr[node->type].dump_fn (str, node, level);
+  node_descr[node->type].dump_fn (str, node, level, mach);
 }
 
 
@@ -960,24 +956,23 @@ tree_optimize (struct mu_sieve_node *tree)
     }
 }
 
-static int
+static void
 tree_code (struct mu_sieve_machine *mach, struct mu_sieve_node *tree)
 {
   while (tree)
     {
-      if (node_code (mach, tree))
-       return 1;
+      node_code (mach, tree);
       tree = tree->next;
     }
-  return 0;
 }
 
 static void
-tree_dump (mu_stream_t str, struct mu_sieve_node *tree, unsigned level)
+tree_dump (mu_stream_t str, struct mu_sieve_node *tree, unsigned level,
+          struct mu_sieve_machine *mach)
 {
   while (tree)
     {
-      node_dump (str, tree, level);
+      node_dump (str, tree, level, mach);
       tree = tree->next;
     }
 }  
@@ -1251,7 +1246,21 @@ void
 mu_sieve_machine_destroy (mu_sieve_machine_t *pmach)
 {
   mu_sieve_machine_t mach = *pmach;
-
+  size_t i;
+  
+  for (i = 0; i < mach->stringcount; i++)
+    {
+      if (mach->stringspace[i].rx)
+       {
+         regex_t *rx = mach->stringspace[i].rx;
+         regfree (rx);
+       }
+      /* FIXME: Is it needed?
+      if (mach->stringspace[i].exp)
+       free (mach->stringspace[i].exp);
+      */
+    }
+  
   mu_stream_destroy (&mach->errstream);
   mu_stream_destroy (&mach->dbgstream);
   mu_mailer_destroy (&mach->mailer);
@@ -1320,13 +1329,13 @@ sieve_parse (void)
       if (mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE1))
        {
          mu_error (_("Unoptimized parse tree"));
-         tree_dump (mu_strerr, sieve_tree, 0);
+         tree_dump (mu_strerr, sieve_tree, 0, mu_sieve_machine);
        }
       tree_optimize (sieve_tree);
       if (mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE2))
        {
          mu_error (_("Optimized parse tree"));
-         tree_dump (mu_strerr, sieve_tree, 0);
+         tree_dump (mu_strerr, sieve_tree, 0, mu_sieve_machine);
        }
       mu_i_sv_code (mu_sieve_machine, (sieve_op_t) 0);
 
@@ -1335,9 +1344,7 @@ sieve_parse (void)
       mu_sieve_machine->locus.mu_line = 0;
       mu_sieve_machine->locus.mu_col = 0;
       
-      rc = tree_code (mu_sieve_machine, sieve_tree);
-      if (rc)
-       mu_i_sv_error (mu_sieve_machine);
+      tree_code (mu_sieve_machine, sieve_tree);
       mu_i_sv_code (mu_sieve_machine, (sieve_op_t) 0);
     }
   
diff --git a/libproto/pop/pop3_disconnect.c b/libmu_sieve/string.c
similarity index 50%
copy from libproto/pop/pop3_disconnect.c
copy to libmu_sieve/string.c
index 89f627b..254f3ad 100644
--- a/libproto/pop/pop3_disconnect.c
+++ b/libmu_sieve/string.c
@@ -1,5 +1,5 @@
 /* GNU Mailutils -- a suite of utilities for electronic mail
-   Copyright (C) 1999-2001, 2003, 2007, 2010-2012, 2014-2016 Free
+   Copyright (C) 1999-2002, 2005-2008, 2010-2012, 2014-2016 Free
    Software Foundation, Inc.
 
    This library is free software; you can redistribute it and/or
@@ -18,37 +18,44 @@
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
-#endif
+#endif  
 
 #include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <mailutils/sys/pop3.h>
+#include <sieve-priv.h>
 
-int
-mu_pop3_disconnect (mu_pop3_t pop3)
+size_t 
+mu_i_sv_string_create (mu_sieve_machine_t mach, char *str)
 {
-  /* Sanity checks.  */
-  if (pop3 == NULL)
-    return EINVAL;
+  size_t n;
+  mu_sieve_string_t *s;
+  
+  if (mach->stringcount == mach->stringmax)
+    {
+      mu_i_sv_2nrealloc (mach, (void**) &mach->stringspace,
+                        &mach->stringmax,
+                        sizeof mach->stringspace[0]);
+    }
 
-  /* We can keep some of the fields, if they decide to pop3_connect() again but
-     clear the states.  */
-  pop3->state = MU_POP3_NO_STATE;
-  MU_POP3_FCLR (pop3, MU_POP3_ACK);
+  n = mach->stringcount++;
+  s = &mach->stringspace[n];
+  memset (s, 0, sizeof *s);
+  s->orig = str;
 
-  if (pop3->rdbuf)
-    pop3->rdbuf[0] = 0;
+  return n;
+}
 
-  /* Free the timestamp, it will be different on each connection.  */
-  if (pop3->timestamp)
-    {
-      free (pop3->timestamp);
-      pop3->timestamp = NULL;
-    }
+struct mu_sieve_string *
+mu_sieve_string_raw (mu_sieve_machine_t mach, mu_sieve_slice_t slice,
+                    size_t i)
+{
+  if (i >= slice->count)
+    abort ();
+  return mach->stringspace + slice->first + i;
+}
 
-  /* Close the stream.  */
-  if (mu_stream_is_open (pop3->carrier))
-    return mu_stream_close (pop3->carrier);
-  return 0;
+char *
+mu_sieve_string (mu_sieve_machine_t mach, mu_sieve_slice_t slice,
+                size_t i)
+{
+  return mu_sieve_string_raw (mach, slice, i)->orig;
 }
diff --git a/libmu_sieve/tests.c b/libmu_sieve/tests.c
index 0713373..10c4825 100644
--- a/libmu_sieve/tests.c
+++ b/libmu_sieve/tests.c
@@ -27,32 +27,24 @@
 
 typedef int (*address_aget_t) (mu_address_t addr, size_t no, char **buf);
 
-static int
-_get_address_part (void *item, void *data)
-{
-  mu_sieve_runtime_tag_t *t = item;
-  address_aget_t ret = NULL;
-  
-  if (strcmp (t->tag, "all") == 0)
-    ret =  mu_address_aget_email;
-  else if (strcmp (t->tag, "domain") == 0)
-    ret =  mu_address_aget_domain;
-  else if (strcmp (t->tag, "localpart") == 0)
-    ret = mu_address_aget_local_part;
-  if (ret)
-    {    
-      *(address_aget_t*)data = ret;
-      return 1; /* break the loop */
-    }  
-  return 0; /* continue */
-}
-
 address_aget_t
-sieve_get_address_part (mu_list_t tags)
+sieve_get_address_part (mu_sieve_machine_t mach)
 {
-  address_aget_t ret = mu_address_aget_email;
-  mu_list_foreach (tags, _get_address_part, &ret);
-  return ret;
+  size_t i;
+  
+  for (i = 0; i < mach->tagcount; i++)
+    {
+      mu_sieve_value_t *t = mu_sieve_get_tag_n (mach, i);
+      if (strcmp (t->tag, "all") == 0)
+       return mu_address_aget_email;
+      else if (strcmp (t->tag, "domain") == 0)
+       return  mu_address_aget_domain;
+      else if (strcmp (t->tag, "localpart") == 0)
+       return mu_address_aget_local_part;
+    }
+  /* RFC 3028, 2.7.4.   Comparisons Against Addresses:
+     If an optional address-part is omitted, the default is ":all". */
+  return mu_address_aget_email;
 }
 
 /* Structure shared between address and envelope tests */
@@ -72,11 +64,11 @@ do_count (mu_sieve_machine_t mach, size_t count, int retval)
     {
       size_t limit;
       char *str;
-      mu_list_t list;
+      struct mu_sieve_slice slice;
       mu_sieve_relcmpn_t stest;
       
-      mu_sieve_get_arg (mach, 1, SVT_STRING_LIST, &list);
-      mu_list_get (list, 0, (void **) &str);
+      mu_sieve_get_arg (mach, 1, SVT_STRING_LIST, &slice);
+      str = mu_sieve_string (mach, &slice, 0);
       limit = strtoul (str, &str, 10);
 
       mu_sieve_str_to_relcmp (relcmp, NULL, &stest);
@@ -117,16 +109,16 @@ sieve_test_address (mu_sieve_machine_t mach)
   mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
   struct address_closure clos;
   int rc;
-  size_t count;
+  size_t count = 0;
   
   h = mu_sieve_get_arg_untyped (mach, 0);
   v = mu_sieve_get_arg_untyped (mach, 1);
 
   mu_message_get_header (mu_sieve_get_message (mach), &header);
   clos.data = header;
-  clos.aget = sieve_get_address_part (mach->tag_list);
+  clos.aget = sieve_get_address_part (mach);
   clos.addr = NULL;
-  rc = mu_sieve_vlist_compare (h, v, comp, test, retrieve_address, &clos,
+  rc = mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_address, &clos,
                               &count);
   mu_address_destroy (&clos.addr);
   
@@ -169,7 +161,7 @@ sieve_test_header (mu_sieve_machine_t mach)
   mu_sieve_value_t *h, *v;
   mu_sieve_comparator_t comp = mu_sieve_get_comparator (mach);
   mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
-  size_t count, mcount = 0;
+  size_t count = 0, mcount = 0;
   struct header_closure clos;
   
   h = mu_sieve_get_arg_untyped (mach, 0);
@@ -192,7 +184,7 @@ sieve_test_header (mu_sieve_machine_t mach)
              if (mu_message_get_part (mach->msg, i, &message) == 0)
                {
                  mu_message_get_header (message, &clos.header);
-                 if (mu_sieve_vlist_compare (h, v, comp, test,
+                 if (mu_sieve_vlist_compare (mach, h, v, comp, test,
                                           retrieve_header, &clos, &mcount))
                    return 1;
                }
@@ -200,7 +192,7 @@ sieve_test_header (mu_sieve_machine_t mach)
        }
     }
   mu_message_get_header (mach->msg, &clos.header);
-  if (mu_sieve_vlist_compare (h, v, comp, test, retrieve_header, &clos,
+  if (mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_header, &clos,
                              &count))
     return 1;
 
@@ -242,16 +234,16 @@ sieve_test_envelope (mu_sieve_machine_t mach)
   mu_sieve_relcmp_t test = mu_sieve_get_relcmp (mach);
   struct address_closure clos;
   int rc;
-  size_t count;
+  size_t count = 0;
   
   h = mu_sieve_get_arg_untyped (mach, 0);
   v = mu_sieve_get_arg_untyped (mach, 1);
 
   mu_message_get_envelope (mu_sieve_get_message (mach),
                           (mu_envelope_t*)&clos.data);
-  clos.aget = sieve_get_address_part (mach->tag_list);
+  clos.aget = sieve_get_address_part (mach);
   clos.addr = NULL;
-  rc = mu_sieve_vlist_compare (h, v, comp, test, retrieve_envelope, &clos,
+  rc = mu_sieve_vlist_compare (mach, h, v, comp, test, retrieve_envelope, 
&clos,
                               &count);
   mu_address_destroy (&clos.addr);
   return do_count (mach, count, rc);
@@ -261,19 +253,23 @@ int
 sieve_test_size (mu_sieve_machine_t mach)
 {
   int rc = 1;
-  mu_sieve_runtime_tag_t *tag = NULL;
   size_t size;
   size_t arg;
   
   mu_sieve_get_arg (mach, 0, SVT_NUMBER, &arg);
   mu_message_size (mu_sieve_get_message (mach), &size);
-  mu_list_get (mach->tag_list, 0, (void **)&tag);
-  if (!tag)
+  if (mach->tagcount)
+    {
+      mu_sieve_value_t *tag = mu_sieve_get_tag_n (mach, 0);
+      if (strcmp (tag->tag, "over") == 0)
+       rc = size > arg;
+      else if (strcmp (tag->tag, "under") == 0)
+       rc = size < arg;
+      else
+       abort ();
+    }
+  else
     rc = size == arg;
-  else if (strcmp (tag->tag, "over") == 0)
-    rc = size > arg;
-  else if (strcmp (tag->tag, "under") == 0)
-    rc = size < arg;
 
   return rc;
 }
@@ -295,7 +291,7 @@ sieve_test_exists (mu_sieve_machine_t mach)
 
   mu_message_get_header (mu_sieve_get_message (mach), &header);
   val = mu_sieve_get_arg_untyped (mach, 0);
-  return mu_sieve_vlist_do (val, _test_exists, header) == 0;
+  return mu_sieve_vlist_do (mach, val, _test_exists, header) == 0;
 }
 
 static mu_sieve_tag_def_t address_part_tags[] = {
diff --git a/libmu_sieve/util.c b/libmu_sieve/util.c
index 3df7a2d..9e46bda 100644
--- a/libmu_sieve/util.c
+++ b/libmu_sieve/util.c
@@ -26,29 +26,22 @@
 #include <sieve-priv.h>
 
 
-static int
-_destroy_item (void *item, void *data)
-{
-  free (item);
-  return 0;
-}
-/* FIXME: Not needed? */
-void
-mu_sieve_slist_destroy (mu_list_t *plist)
-{
-  if (!plist)
-    return;
-  mu_list_foreach (*plist, _destroy_item, NULL);
-  mu_list_destroy (plist);
-}
-
-mu_sieve_value_t *
+size_t 
 mu_sieve_value_create (mu_sieve_machine_t mach, mu_sieve_data_type type,
                       void *data)
 {
-  mu_sieve_value_t *val = mu_sieve_alloc_memory (mach, sizeof (*val),
-                                                mu_sieve_reclaim_value);
-
+  size_t idx;
+  mu_sieve_value_t *val;
+  
+  if (mach->valcount == mach->valmax)
+    {
+      mu_i_sv_2nrealloc (mach, (void**) &mach->valspace, &mach->valmax,
+                        sizeof mach->valspace[0]);
+    }
+  idx = mach->valcount++;
+  val = &mach->valspace[idx];
+  memset (val, 0, sizeof *val);
+  
   val->type = type;
   switch (type)
     {
@@ -57,11 +50,12 @@ mu_sieve_value_create (mu_sieve_machine_t mach, 
mu_sieve_data_type type,
       break;
       
     case SVT_STRING:
-      val->v.string = data;
+      val->v.list.first = mu_i_sv_string_create (mach, (char *)data);
+      val->v.list.count = 1;
       break;
       
     case SVT_STRING_LIST:
-      val->v.list = data;
+      val->v.list = *(mu_sieve_slice_t)data;
       break;
       
     case SVT_TAG:
@@ -69,66 +63,140 @@ mu_sieve_value_create (mu_sieve_machine_t mach, 
mu_sieve_data_type type,
       val->v.string = data;
       break;
 
-    case SVT_POINTER:
-      val->v.ptr = data;
-      break;
-       
     default:
       mu_error ("%s", _("invalid data type"));
       abort ();
     }
-  return val;
+  return idx;
 }
 
 mu_sieve_value_t *
 mu_sieve_get_arg_untyped (mu_sieve_machine_t mach, size_t index)
 {
-  mu_sieve_value_t *val = NULL;
-  int rc = mu_list_get (mach->arg_list, index, (void **)&val);
-  if (rc)
+  if (index >= mach->argcount)
     {
-      mu_sieve_error (mach, _("can't get argument %zu: %s"),
-                     index, mu_strerror (rc));
-      mu_sieve_abort (mach);
+      mu_sieve_error (mach, _("INTERNAL ERROR: %s,%zu,%zu,%zu argument index 
%zu out of range"),
+                     mach->identifier,
+                     mach->argstart,
+                     mach->argcount,
+                     mach->tagcount,
+                     index);
+      abort ();
+      //FIXME      mu_sieve_abort (mach);
     }
-  return val;
+  
+  return mach->valspace + mach->argstart + index;
 }
 
 mu_sieve_value_t *
 mu_sieve_get_arg_optional (mu_sieve_machine_t mach, size_t index)
 {
-  mu_sieve_value_t *val = NULL;
-  int rc = mu_list_get (mach->arg_list, index, (void **)&val);
-  if (rc == MU_ERR_NOENT)
+  if (index >= mach->argcount)
     return NULL;
-  else if (rc)
+  return mach->valspace + mach->argstart + index;
+}  
+
+void
+mu_sieve_value_get (mu_sieve_machine_t mach, mu_sieve_value_t *val,
+                   mu_sieve_data_type type, void *ret)
+{
+  if (val->type != type)
     {
-      mu_sieve_error (mach, _("can't get argument %zu: %s"),
-                     index, mu_strerror (rc));
+      if (val->tag)
+       mu_sieve_error (mach,
+                       _("tag :%s has type %s, instead of expected %s"),
+                       val->tag,
+                       mu_sieve_type_str (val->type),
+                       mu_sieve_type_str (type));
+      else
+       {
+         size_t idx = val - mu_sieve_get_arg_untyped (mach, 0);
+         if (idx < mach->argcount)
+           mu_sieve_error (mach,
+                           _("argument %zu has type %s, instead of expected 
%s"),
+                           idx,
+                           mu_sieve_type_str (val->type),
+                           mu_sieve_type_str (type));
+         else
+           abort ();
+       }
       mu_sieve_abort (mach);
     }
-  return val;
-}  
 
-int
+  switch (type)
+    {
+    case SVT_VOID:
+      *(void**) ret = NULL;
+      break;
+      
+    case SVT_NUMBER:
+      *(size_t*) ret = val->v.number;
+      break;
+      
+    case SVT_STRING:
+      *(char**) ret = mu_sieve_string (mach, &val->v.list, 0);
+      break;
+
+    case SVT_STRING_LIST:
+      *(struct mu_sieve_slice *) ret = val->v.list;
+      break;
+
+    case SVT_TAG:
+    case SVT_IDENT:
+      *(char**) ret = val->v.string;
+      break;
+
+    default:
+      abort ();
+    }
+}
+
+void
 mu_sieve_get_arg (mu_sieve_machine_t mach, size_t index,
                  mu_sieve_data_type type, void *ret)
 {
-  mu_sieve_value_t *val = mu_sieve_get_arg_untyped (mach, index);
-  if (val->type != type)
+  mu_sieve_value_get (mach, mu_sieve_get_arg_untyped (mach, index),
+                     type, ret);
+}
+  
+mu_sieve_value_t *
+mu_sieve_get_tag_untyped (mu_sieve_machine_t mach, char const *name)
+{
+  size_t i;
+  mu_sieve_value_t *tag = mach->valspace + mach->argstart + mach->argcount;
+  
+  for (i = 0; i < mach->tagcount; i++)
     {
-      mu_sieve_error (mach,
-                   _("bad type for argument %zu: %s, instead of expected %s"),
-                     index,
-                     mu_sieve_type_str (val->type),
-                     mu_sieve_type_str (type));
-      mu_sieve_abort (mach);
+      if (strcmp (tag[i].tag, name) == 0)
+       return &tag[i];
     }
+  return NULL;
+}
 
-  *(union mu_sieve_value_storage *)ret = val->v;
-  return 0;
+mu_sieve_value_t *
+mu_sieve_get_tag_n (mu_sieve_machine_t mach, size_t n)
+{
+  if (n >= mach->tagcount)
+    abort ();
+  return &mach->valspace[mach->argstart + mach->argcount + n];
 }
 
+int
+mu_sieve_get_tag (mu_sieve_machine_t mach, 
+                 char *name, mu_sieve_data_type type,
+                 void *ret)
+{
+  mu_sieve_value_t *val = mu_sieve_get_tag_untyped (mach, name);
+
+  if (val)
+    {
+      if (ret)
+       mu_sieve_value_get (mach, val, type, ret);
+    }
+
+  return val != NULL;
+}
+
 void
 mu_sieve_error (mu_sieve_machine_t mach, const char *fmt, ...)
 {
@@ -172,31 +240,11 @@ mu_sieve_type_str (mu_sieve_data_type type)
     case SVT_IDENT:
       return "ident";
 
-    case SVT_POINTER:
-      return "pointer";
     }
 
   return "unknown";
 }
 
-static int
-tag_printer (void *item, void *data)
-{
-  mu_sieve_runtime_tag_t *val = item;
-  mu_stream_t str = data;
-  
-  mu_stream_printf (str, " :%s", val->tag);
-  if (val->arg)
-    mu_i_sv_valf (str, val->arg);
-  return 0;
-}
-
-void
-mu_i_sv_tagf (mu_stream_t str, mu_list_t taglist)
-{
-  mu_list_foreach (taglist, tag_printer, str);
-}
-
 void
 mu_i_sv_debug (mu_sieve_machine_t mach, size_t pc, const char *fmt, ...)
 {
@@ -228,6 +276,8 @@ mu_i_sv_debug_command (mu_sieve_machine_t mach,
                       size_t pc,
                       char const *what)
 {
+  size_t i;
+  
   if (mach->state_flags & MU_SV_SAVED_DBG_STATE)
     {
       unsigned severity = MU_LOG_DEBUG;
@@ -243,15 +293,20 @@ mu_i_sv_debug_command (mu_sieve_machine_t mach,
        }
     }
   mu_stream_printf (mach->dbgstream, "%4zu: %s: %s",
-                   pc, what, mach->identifier);  
-  mu_i_sv_tagf (mach->dbgstream, mach->tag_list);
-  mu_i_sv_argf (mach->dbgstream, mach->arg_list);
+                   pc, what, mach->identifier);
+  for (i = 0; i < mach->argcount; i++)
+    mu_i_sv_valf (mach, mach->dbgstream, &mach->valspace[mach->argstart + i]);
+  for (i = 0; i < mach->tagcount; i++)
+    mu_i_sv_valf (mach, mach->dbgstream, mu_sieve_get_tag_n (mach, i));
+  
   mu_stream_write (mach->dbgstream, "\n", 1, NULL);
 }
 
 void
 mu_i_sv_trace (mu_sieve_machine_t mach, const char *what)
 {
+  size_t i;
+  
   if (!mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE4))
     return;
   
@@ -264,8 +319,10 @@ mu_i_sv_trace (mu_sieve_machine_t mach, const char *what)
                      mach->locus.mu_line);
   mu_stream_printf (mach->errstream, "%zu: %s %s", mach->msgno, what,
                    mach->identifier);
-  mu_i_sv_tagf (mach->errstream, mach->tag_list);
-  mu_i_sv_argf (mach->errstream, mach->arg_list);
+  for (i = 0; i < mach->argcount; i++)
+    mu_i_sv_valf (mach, mach->errstream, mu_sieve_get_arg_untyped (mach, i));
+  for (i = 0; i < mach->tagcount; i++)
+    mu_i_sv_valf (mach, mach->errstream, mu_sieve_get_tag_n (mach, i));
   mu_stream_printf (mach->errstream, "\n");
 }
 
@@ -284,146 +341,74 @@ mu_sieve_log_action (mu_sieve_machine_t mach, const char 
*action,
   mach->logger (mach, action, fmt, ap);
   va_end (ap);
 }
-  
-static int
-tag_finder (void *item, void *data)
-{
-  mu_sieve_runtime_tag_t *val = item;
-  mu_sieve_runtime_tag_t *target = data;
-
-  if (strcmp (val->tag, target->tag) == 0)
-    {
-      target->arg = val->arg;
-      return 1;
-    }
-  return 0;
-}
-
-int
-mu_sieve_get_tag_untyped (mu_sieve_machine_t mach, 
-                         char *name, mu_sieve_value_t **ret)
-{
-  mu_sieve_runtime_tag_t t;
-
-  t.tag = name;
-  if (mach->tag_list && mu_list_foreach (mach->tag_list, tag_finder, &t))
-    {
-      if (ret)
-       *ret = t.arg;
-      return 1;
-    }
-  return 0;
-}
-
-int
-mu_sieve_get_tag (mu_sieve_machine_t mach, 
-                 char *name, mu_sieve_data_type type,
-                 void *ret)
-{
-  mu_sieve_value_t *val;
-  int found = mu_sieve_get_tag_untyped (mach, name, &val);
-
-  if (found)
-    {
-      if (ret)
-       {
-         if (val->type != type)
-           {
-             mu_sieve_error (mach,
-                             _("bad type for tag %s: %s, instead of expected 
%s"),
-                             name,
-                             mu_sieve_type_str (val->type),
-                             mu_sieve_type_str (type));
-             mu_sieve_abort (mach);
-           }
-         *(union mu_sieve_value_storage *)ret = val->v;
-       }
-    }
-
-  return found;
-}
-
+
 int
-mu_sieve_vlist_do (mu_sieve_value_t *val, mu_list_action_t ac, void *data)
+mu_sieve_vlist_do (mu_sieve_machine_t mach, mu_sieve_value_t *val,
+                  mu_list_action_t ac, void *data)
 {
+  size_t i;
   switch (val->type)
     {
     case SVT_STRING_LIST:
-      return mu_list_foreach (val->v.list, ac, data);
     case SVT_STRING:
-      return ac (val->v.string, data);
+      for (i = 0; i < val->v.list.count; i++)
+       {
+         int rc = ac (mu_sieve_string (mach, &val->v.list, i), data);
+         if (rc)
+           return rc;
+       }
+      return 0;
     default:
       mu_error ("mu_sieve_vlist_do: unexpected list type %d", val->type);
       return EINVAL;
     }
 }
 
-struct comp_data
-{
-  mu_sieve_value_t *val;
-  mu_sieve_comparator_t comp;
-  mu_sieve_relcmp_t test;
-  mu_sieve_retrieve_t retr;
-  void *data;
-  size_t count;
-};
-
-struct comp_data2
-{
-  char *sample;
-  mu_sieve_comparator_t comp;
-  mu_sieve_relcmp_t test;
-};
-
-int
-_comp_action2 (void *item, void *data)
-{
-  struct comp_data2 *cp = data;
-  return cp->test (cp->comp (item, cp->sample), 0);
-}
-
 int
-_comp_action (void *item, void *data)
-{
-  struct comp_data *cp = data;
-  struct comp_data2 d;
-  int rc = 0;
-  int i;
-
-  d.comp = cp->comp;
-  d.test = cp->test;
-  for (i = 0; rc == 0 && cp->retr (item, cp->data, i, &d.sample) == 0; i++)
-    if (d.sample)
-      {
-       cp->count++;
-        rc = mu_sieve_vlist_do (cp->val, _comp_action2, &d);
-        free (d.sample);
-      }
-  return rc;
-}
-
-int
-mu_sieve_vlist_compare (mu_sieve_value_t *a, mu_sieve_value_t *b,
+mu_sieve_vlist_compare (mu_sieve_machine_t mach,
+                       mu_sieve_value_t *a, mu_sieve_value_t *b,
                        mu_sieve_comparator_t comp, mu_sieve_relcmp_t test,
                        mu_sieve_retrieve_t retr,
                        void *data, size_t *count)
 {
-  struct comp_data d;
-  int rc;
+  int rc = 0;
+  size_t i;
+  
+  switch (a->type)
+    {
+    case SVT_STRING_LIST:
+    case SVT_STRING:
+      for (i = 0; i < a->v.list.count; i++)
+       {
+         char *item = mu_sieve_string (mach, &a->v.list, i);
+         char *sample;
+         size_t j, k;
   
-  d.comp = comp;
-  d.test = test;
-  d.retr = retr;
-  d.data = data;
-  d.val = b;
-  d.count = 0;
-  rc = mu_sieve_vlist_do (a, _comp_action, &d);
-  if (count)
-    *count = d.count;
+         for (j = 0; rc == 0 && retr (item, data, j, &sample) == 0; j++)
+           {
+             if (count)
+               (*count)++;
+             for (k = 0; k < b->v.list.count; k++)
+               {
+                 mu_sieve_string_t *s = mu_sieve_string_raw (mach, &b->v.list, 
k);
+                 rc = test (comp (mach, s, sample), 0);
+                 if (rc)
+                   {
+                     free (sample);
+                     return rc;
+                   }
+               }
+             free (sample);
+           }
+       }
+      break;
+      
+    default:
+      abort ();
+    }
   return rc;
 }
 
-
 void
 mu_sieve_stream_save (mu_sieve_machine_t mach)
 {
diff --git a/sieve/tests/delheader.at b/sieve/tests/delheader.at
index d068ce4..659d77e 100644
--- a/sieve/tests/delheader.at
+++ b/sieve/tests/delheader.at
@@ -125,7 +125,7 @@ Subject: Ping
 Test message, please discard.
 
 ],
-[DELETEHEADER on msg uid 1: X-Agent: (regexp)
+[DELETEHEADER on msg uid 1: X-Agent (values)
 ])
 
 m4_popdef([MUT_SIEVE_EXT_NAME])
diff --git a/sieve/tests/enc-char.at b/sieve/tests/enc-char.at
index 9d82525..d76c0c3 100644
--- a/sieve/tests/enc-char.at
+++ b/sieve/tests/enc-char.at
@@ -19,7 +19,6 @@ AT_KEYWORDS([encoded-character enc-char])
 
 AT_CHECK([
 AT_DATA([prog],[[require ["reject", "encoded-character"];
-
 reject "$${hex:40}";
 reject "${hex: 40 }";
 reject "${HEX: 40}";
@@ -38,25 +37,25 @@ reject "Nested ${hex: 73 65 71 ${hex: 75 65 6E}}ce";
 reject "Invalid ${hex: 73 RE}";
 ]])
 
-sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -D prog | grep ACTION
+sieve MUT_SIEVE_CMDLINE MUT_SIEVE_OPTIONS -D prog | sed -n 's/.*ACTION: //p'
 ],
 [0],
-[   9: ACTION: reject "$@"
-  16: ACTION: reject "@"
-  23: ACTION: reject "@"
-  30: ACTION: reject "${hex:40"
-  37: ACTION: reject "${hex:400}"
-  44: ACTION: reject "${hex:40}"
-  51: ACTION: reject "@"
-  58: ACTION: reject "${ unicode:40}"
-  65: ACTION: reject "@"
-  72: ACTION: reject "@"
-  79: ACTION: reject "@"
-  86: ACTION: reject "${Unicode:Cool}"
-  93: ACTION: reject "Now is the time"
- 100: ACTION: reject "Unbalanced ${hex: 73 65 71 uence"
- 107: ACTION: reject "Nested ${hex: 73 65 71 uen}ce"
- 114: ACTION: reject "Invalid ${hex: 73 RE}"
+[reject "$@"
+reject "@"
+reject "@"
+reject "${hex:40"
+reject "${hex:400}"
+reject "${hex:40}"
+reject "@"
+reject "${ unicode:40}"
+reject "@"
+reject "@"
+reject "@"
+reject "${Unicode:Cool}"
+reject "Now is the time"
+reject "Unbalanced ${hex: 73 65 71 uence"
+reject "Nested ${hex: 73 65 71 uen}ce"
+reject "Invalid ${hex: 73 RE}"
 ])
 
 AT_CLEANUP


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]