diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-12-02 17:11:01 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-12-02 17:11:01 +0200 |
commit | 15f6dbf66eed6bed5c084d97077e7cc5f8e192a7 (patch) | |
tree | 1debcb9960f990af390cf3930c539736d0179960 /libmu_sieve | |
parent | ed04bc837e353e61e4c43f6bdbd9a67859c61f61 (diff) | |
download | mailutils-15f6dbf66eed6bed5c084d97077e7cc5f8e192a7.tar.gz mailutils-15f6dbf66eed6bed5c084d97077e7cc5f8e192a7.tar.bz2 |
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.
Diffstat (limited to 'libmu_sieve')
-rw-r--r-- | libmu_sieve/Makefile.am | 1 | ||||
-rw-r--r-- | libmu_sieve/actions.c | 17 | ||||
-rw-r--r-- | libmu_sieve/comparator.c | 297 | ||||
-rw-r--r-- | libmu_sieve/extensions/editheader.c | 62 | ||||
-rw-r--r-- | libmu_sieve/extensions/list.c | 2 | ||||
-rw-r--r-- | libmu_sieve/extensions/vacation.c | 22 | ||||
-rw-r--r-- | libmu_sieve/mem.c | 41 | ||||
-rw-r--r-- | libmu_sieve/prog.c | 366 | ||||
-rw-r--r-- | libmu_sieve/relational.c | 5 | ||||
-rw-r--r-- | libmu_sieve/require.c | 24 | ||||
-rw-r--r-- | libmu_sieve/runtime.c | 46 | ||||
-rw-r--r-- | libmu_sieve/sieve-priv.h | 51 | ||||
-rw-r--r-- | libmu_sieve/sieve.y | 257 | ||||
-rw-r--r-- | libmu_sieve/string.c | 61 | ||||
-rw-r--r-- | libmu_sieve/tests.c | 84 | ||||
-rw-r--r-- | libmu_sieve/util.c | 379 |
16 files changed, 843 insertions, 872 deletions
diff --git a/libmu_sieve/Makefile.am b/libmu_sieve/Makefile.am index 0b06ffe3e..b9f3a0ada 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 077b8cd06..f3ef7f472 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 a2ac34b0f..a0d5836d3 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 52c745eb4..3ef017f0d 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 71696c6ec..3a64e0a69 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 989a87a8e..fa19c8785 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 f03b06dd5..25dc26c5b 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 8c6bc6d8e..17b65870f 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_lo |