summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2002-11-12 16:27:47 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2002-11-12 16:27:47 +0000
commit2233fe22de4e6ff71d711b833cff595bd98b2b09 (patch)
tree16120b9787ed52f41dd868e26f70d88d988ed987
parent0ba30cb1092adadc9cfef3bb9217f13fe272f612 (diff)
downloadmailutils-2233fe22de4e6ff71d711b833cff595bd98b2b09.tar.gz
mailutils-2233fe22de4e6ff71d711b833cff595bd98b2b09.tar.bz2
Added basic code generation and debugging
-rw-r--r--include/mailutils/libsieve.h34
-rw-r--r--libsieve/actions.c18
-rw-r--r--libsieve/register.c14
-rw-r--r--libsieve/sieve.h66
-rw-r--r--libsieve/sieve.l18
-rw-r--r--libsieve/sieve.y89
-rw-r--r--libsieve/sv.c20
-rw-r--r--libsieve/tests.c21
-rw-r--r--libsieve/util.c228
9 files changed, 462 insertions, 46 deletions
diff --git a/include/mailutils/libsieve.h b/include/mailutils/libsieve.h
index bb99c3581..064e7176c 100644
--- a/include/mailutils/libsieve.h
+++ b/include/mailutils/libsieve.h
@@ -16,11 +16,15 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
+#include <stdarg.h>
#include <mailutils/mailutils.h>
typedef struct sieve_machine sieve_machine_t;
-typedef int (*sieve_instr_t) __P((sieve_machine_t *mach, list_t *args));
+typedef int (*sieve_handler_t) __P((sieve_machine_t *mach,
+ list_t args, list_t tags));
+typedef int (*sieve_printf_t) __P((void *data, const char *fmt, va_list ap));
+typedef int (*sieve_vprintf_t) __P((void *data, const char *fmt, va_list ap));
typedef enum {
SVT_VOID,
@@ -32,12 +36,15 @@ typedef enum {
SVT_VALUE_LIST
} sieve_data_type;
+typedef struct sieve_runtime_tag sieve_runtime_tag_t;
+
typedef struct {
sieve_data_type type;
union {
char *string;
long number;
list_t list;
+ sieve_runtime_tag_t *tag;
} v;
} sieve_value_t;
@@ -47,10 +54,15 @@ typedef struct {
sieve_data_type argtype;
} sieve_tag_def_t;
+struct sieve_runtime_tag {
+ int tag;
+ sieve_value_t *arg;
+};
+
typedef struct {
char *name;
int required;
- sieve_instr_t instr;
+ sieve_handler_t handler;
int num_req_args;
sieve_data_type *req_args;
int num_tags;
@@ -59,18 +71,28 @@ typedef struct {
void *sieve_alloc __P((size_t size));
-int sieve_open_source __P((const char *name));
-int sieve_parse __P((const char *name));
+void *sieve_palloc __P((list_t *pool, size_t size));
+void *sieve_prealloc __P((list_t *pool, void *ptr, size_t size));
+void sieve_pfree __P((list_t *pool, void *ptr));
+char *sieve_pstrdup __P((list_t *pool, const char *str));
+
+int sieve_compile __P((sieve_machine_t *mach, const char *name, void *data,
+ sieve_printf_t errfn));
+void sieve_set_debug __P((sieve_machine_t *mach, sieve_printf_t debug,
+ int level));
+
sieve_value_t * sieve_value_create __P((sieve_data_type type, void *data));
sieve_register_t *sieve_test_lookup __P((const char *name));
sieve_register_t *sieve_action_lookup __P((const char *name));
-int sieve_register_test __P((const char *name, sieve_instr_t instr,
+int sieve_register_test __P((const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required));
-int sieve_register_action __P((const char *name, sieve_instr_t instr,
+int sieve_register_action __P((const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required));
void sieve_slist_destroy __P((list_t *plist));
void sieve_require __P((list_t slist));
+
+void sieve_abort __P((sieve_machine_t *mach));
diff --git a/libsieve/actions.c b/libsieve/actions.c
index 6272c1271..954b629cf 100644
--- a/libsieve/actions.c
+++ b/libsieve/actions.c
@@ -26,33 +26,39 @@
#include <sieve.h>
int
-sieve_action_stop (sieve_machine_t *mach, list_t *args)
+sieve_action_stop (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_action_keep (sieve_machine_t *mach, list_t *args)
+sieve_action_keep (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_action_discard (sieve_machine_t *mach, list_t *args)
+sieve_action_discard (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_action_fileinto (sieve_machine_t *mach, list_t *args)
+sieve_action_fileinto (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_action_reject (sieve_machine_t *mach, list_t *args)
+sieve_action_reject (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_action_redirect (sieve_machine_t *mach, list_t *args)
+sieve_action_redirect (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
sieve_data_type fileinto_args[] = {
diff --git a/libsieve/register.c b/libsieve/register.c
index 8f69b0125..67b25bfd4 100644
--- a/libsieve/register.c
+++ b/libsieve/register.c
@@ -35,7 +35,7 @@ sieve_lookup (list_t list, const char *name)
sieve_register_t *reg;
if (!list || iterator_create (&itr, list))
- return;
+ return NULL;
for (iterator_first (itr); !iterator_is_done (itr); iterator_next (itr))
{
@@ -63,7 +63,7 @@ sieve_action_lookup (const char *name)
static int
sieve_register (list_t *list,
- const char *name, sieve_instr_t instr,
+ const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required)
{
@@ -73,7 +73,7 @@ sieve_register (list_t *list,
if (!reg)
return ENOMEM;
reg->name = name;
- reg->instr = instr;
+ reg->handler = handler;
if (arg_types)
{
@@ -111,17 +111,17 @@ sieve_register (list_t *list,
int
-sieve_register_test (const char *name, sieve_instr_t instr,
+sieve_register_test (const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required)
{
- return sieve_register (&test_list, name, instr, arg_types, tags, required);
+ return sieve_register (&test_list, name, handler, arg_types, tags, required);
}
int
-sieve_register_action (const char *name, sieve_instr_t instr,
+sieve_register_action (const char *name, sieve_handler_t handler,
sieve_data_type *arg_types,
sieve_tag_def_t *tags, int required)
{
- return sieve_register (&action_list, name, instr, arg_types, tags, required);
+ return sieve_register (&action_list, name, handler, arg_types, tags, required);
}
diff --git a/libsieve/sieve.h b/libsieve/sieve.h
index ac2f9487c..ad6b78be9 100644
--- a/libsieve/sieve.h
+++ b/libsieve/sieve.h
@@ -16,20 +16,78 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mailutils/libsieve.h>
+#include <setjmp.h>
+
+#define SIEVE_CODE_INCR 128
+
+typedef void (*sieve_instr_t) __P((sieve_machine_t *mach));
typedef union {
sieve_instr_t instr;
- sieve_value_t val;
+ sieve_handler_t handler;
+ sieve_value_t *val;
+ list_t list;
+ long number;
+ char *string;
} sieve_op_t;
struct sieve_machine {
- size_t progsize;
- sieve_op_t *prog;
+ list_t memory_pool; /* Pool of allocated memory objects */
+
+ size_t progsize; /* Number of allocated program cells */
+ size_t pc; /* Current program counter */
+ sieve_op_t *prog; /* Compiled program */
+
+ long reg; /* Numeric register */
+ list_t stack; /* Runtime stack */
+
+ int debug_level;
+
+ sieve_printf_t error_printer;
+ sieve_printf_t debug_printer;
+
+ void *data;
+
+ jmp_buf errbuf;
};
extern char *sieve_filename;
extern int sieve_line_num;
extern int sieve_yydebug;
+extern sieve_machine_t *sieve_machine;
+extern int sieve_error_count;
+
+void sieve_error __P((const char *fmt, ...));
+void sieve_debug_internal __P((sieve_printf_t printer, void *data,
+ const char *fmt, ...));
+void sieve_debug __P((sieve_machine_t *mach, const char *fmt, ...));
+void sieve_print_value __P((sieve_value_t *val, sieve_printf_t printer,
+ void *data));
+void sieve_print_value_list __P((list_t list, sieve_printf_t printer,
+ void *data));
+void sieve_print_tag_list __P((list_t list, sieve_printf_t printer,
+ void *data));
+
+int _sieve_default_error_printer __P((void*data, const char *fmt, va_list ap));
+
+int sieve_lex_begin __P((const char *name));
+void sieve_lex_finish __P((void));
-#define sieve_error mu_error
+void sieve_register_standard_actions __P((void));
+void sieve_register_standard_tests __P((void));
+int sieve_code __P((sieve_op_t *op));
+int sieve_code_instr __P((sieve_instr_t instr));
+int sieve_code_handler __P((sieve_handler_t handler));
+int sieve_code_list __P((list_t list));
+int sieve_code_number __P((long num));
+int sieve_code_test __P((sieve_register_t *reg, list_t arglist));
+int sieve_code_action __P((sieve_register_t *reg, list_t arglist));
+
+void instr_action __P((sieve_machine_t *mach));
+void instr_test __P((sieve_machine_t *mach));
+void instr_push __P((sieve_machine_t *mach));
+void instr_pop __P((sieve_machine_t *mach));
+void instr_allof __P((sieve_machine_t *mach));
+void instr_anyof __P((sieve_machine_t *mach));
+void instr_not __P((sieve_machine_t *mach));
diff --git a/libsieve/sieve.l b/libsieve/sieve.l
index b9e18ee60..65bd2997d 100644
--- a/libsieve/sieve.l
+++ b/libsieve/sieve.l
@@ -282,8 +282,9 @@ int
pop_source ()
{
struct buffer_ctx *ctx;
-
- fclose (yyin);
+
+ if (yyin)
+ fclose (yyin);
#ifndef FLEX_SCANNER
lex_delete_buffer (current_buffer);
#endif
@@ -402,10 +403,17 @@ sieve_include ()
}
int
-sieve_open_source (const char *name)
+sieve_lex_begin (const char *name)
{
return push_source (name);
}
+
+void
+sieve_lex_finish ()
+{
+ while (pop_source () == 0)
+ ;
+}
int
number ()
@@ -434,7 +442,7 @@ number ()
int
string ()
{
- yylval.string = sieve_alloc (yyleng - 1);
+ yylval.string = sieve_palloc (&sieve_machine->memory_pool, yyleng - 1);
memcpy (yylval.string, yytext + 1, yyleng - 2);
yylval.string[yyleng - 2] = 0;
return STRING;
@@ -486,7 +494,7 @@ multiline_finish ()
}
/* Copy the contents */
- yylval.string = sieve_alloc (length + 1);
+ yylval.string = sieve_palloc (&sieve_machine->memory_pool, length + 1);
p = yylval.string;
for (iterator_first (itr); !iterator_is_done (itr); iterator_next (itr))
{
diff --git a/libsieve/sieve.y b/libsieve/sieve.y
index 0fb8408d7..e56d5a1fd 100644
--- a/libsieve/sieve.y
+++ b/libsieve/sieve.y
@@ -23,6 +23,9 @@
#include <stdlib.h>
#include <assert.h>
#include <sieve.h>
+
+sieve_machine_t *sieve_machine;
+int sieve_error_count;
%}
%union {
@@ -31,6 +34,7 @@
sieve_instr_t instr;
sieve_value_t *value;
list_t list;
+ size_t pc;
struct {
char *ident;
list_t args;
@@ -45,11 +49,14 @@
%type <value> arg
%type <list> slist stringlist arglist maybe_arglist
%type <command> command
+%type <number> testlist
+%type <pc> action test statement list
%%
input : /* empty */
| list
+ { /* to placate bison */ }
;
list : statement
@@ -59,10 +66,15 @@ list : statement
statement : REQUIRE stringlist ';'
{
sieve_require ($2);
- sieve_slist_destroy ($2);
+ sieve_slist_destroy (&$2);
+ $$ = sieve_machine->pc;
}
| action ';'
| IF cond block maybe_elsif maybe_else
+ {
+ /* FIXME!! */
+ $$ = sieve_machine->pc;
+ }
;
maybe_elsif : /* empty */
@@ -82,18 +94,45 @@ block : '{' list '}'
testlist : cond
+ {
+ if (sieve_code_instr (instr_push))
+ YYERROR;
+ $$ = 1;
+ }
| testlist ',' cond
+ {
+ if (sieve_code_instr (instr_push))
+ YYERROR;
+ $$ = $1 + 1;
+ }
;
cond : test
+ { /* to placate bison */ }
| ANYOF '(' testlist ')'
+ {
+ if (sieve_code_instr (instr_anyof)
+ || sieve_code_number ($3))
+ YYERROR;
+ }
| ALLOF '(' testlist ')'
+ {
+ if (sieve_code_instr (instr_allof)
+ || sieve_code_number ($3))
+ YYERROR;
+ }
| NOT cond
+ {
+ if (sieve_code_instr (instr_not))
+ YYERROR;
+ }
;
test : command
{
sieve_register_t *reg = sieve_test_lookup ($1.ident);
+ $$ = sieve_machine->pc;
+
if (!reg)
sieve_error ("%s:%d: unknown test: %s",
sieve_filename, sieve_line_num,
@@ -102,7 +141,8 @@ test : command
sieve_error ("%s:%d: test `%s' has not been required",
sieve_filename, sieve_line_num,
$1.ident);
- /*free unneeded memory */
+ if (sieve_code_test (reg, $1.args))
+ YYERROR;
}
;
@@ -116,6 +156,8 @@ command : IDENT maybe_arglist
action : command
{
sieve_register_t *reg = sieve_action_lookup ($1.ident);
+
+ $$ = sieve_machine->pc;
if (!reg)
sieve_error ("%s:%d: unknown action: %s",
sieve_filename, sieve_line_num,
@@ -124,7 +166,8 @@ action : command
sieve_error ("%s:%d: action `%s' has not been required",
sieve_filename, sieve_line_num,
$1.ident);
- /*free unneeded memory */
+ if (sieve_code_action (reg, $1.args))
+ YYERROR;
}
;
@@ -138,11 +181,11 @@ maybe_arglist: /* empty */
arglist : arg
{
list_create (&$$);
- list_append ($$, &$1);
+ list_append ($$, $1);
}
| arglist arg
{
- list_append ($1, &$2);
+ list_append ($1, $2);
$$ = $1;
}
;
@@ -197,12 +240,42 @@ yyerror (char *s)
return 0;
}
+/* FIXME: When posix thread support is added, sieve_machine_begin() should
+ aquire the global mutex, locking the current compilation session, and
+ sieve_machine_finish() should release it */
+void
+sieve_machine_begin (sieve_machine_t *mach, sieve_printf_t err, void *data)
+{
+ memset (mach, 0, sizeof (*mach));
+
+ mach->error_printer = err ? err : _sieve_default_error_printer;
+ mach->data = data;
+ sieve_machine = mach;
+ sieve_error_count = 0;
+ sieve_code_instr (NULL);
+}
+
+void
+sieve_machine_finish (sieve_machine_t *mach)
+{
+ sieve_code_instr (NULL);
+}
+
int
-sieve_parse (const char *name)
+sieve_compile (sieve_machine_t *mach, const char *name,
+ void *extra_data, sieve_printf_t err)
{
+ int rc;
+
+ sieve_machine_begin (mach, err, extra_data);
sieve_register_standard_actions ();
sieve_register_standard_tests ();
- sieve_open_source (name);
- return yyparse ();
+ sieve_lex_begin (name);
+ rc = yyparse ();
+ sieve_lex_finish ();
+ sieve_machine_finish (mach);
+ if (sieve_error_count)
+ rc = 1;
+ return rc;
}
diff --git a/libsieve/sv.c b/libsieve/sv.c
index 03a9157ec..551111e84 100644
--- a/libsieve/sv.c
+++ b/libsieve/sv.c
@@ -24,18 +24,34 @@
#include <sieve.h>
int
+debug_printer (void *unused, const char *fmt, va_list ap)
+{
+ return vfprintf (stderr, fmt, ap);
+}
+
+int
main (int argc, char **argv)
{
- int n;
+ int n, rc, debug = 0;
+ sieve_machine_t mach;
assert (argc > 1);
if (strcmp (argv[1], "-d") == 0)
{
sieve_yydebug++;
n = 2;
+ debug++;
assert (argc > 2);
}
else
n = 1;
- return sieve_parse (argv[n]);
+
+ rc = sieve_compile (&mach, argv[n], NULL, NULL);
+ if (rc == 0)
+ {
+ if (debug)
+ sieve_set_debug (&mach, debug_printer, 100);
+ sieve_run (&mach);
+ }
+ return rc;
}
diff --git a/libsieve/tests.c b/libsieve/tests.c
index 4ab0f14f7..8d09a00d9 100644
--- a/libsieve/tests.c
+++ b/libsieve/tests.c
@@ -37,38 +37,45 @@
#define TAG_OVER 9
int
-sieve_test_address (sieve_machine_t *mach, list_t *args)
+sieve_test_address (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_test_header (sieve_machine_t *mach, list_t *args)
+sieve_test_header (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_test_envelope (sieve_machine_t *mach, list_t *args)
+sieve_test_envelope (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_test_size (sieve_machine_t *mach, list_t *args)
+sieve_test_size (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_test_true (sieve_machine_t *mach, list_t *args)
+sieve_test_true (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_test_false (sieve_machine_t *mach, list_t *args)
+sieve_test_false (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
int
-sieve_test_exists (sieve_machine_t *mach, list_t *args)
+sieve_test_exists (sieve_machine_t *mach, list_t args, list_t tags)
{
+ return 0;
}
#define ADDRESS_PART \
diff --git a/libsieve/util.c b/libsieve/util.c
index a75fb7bff..2fadeeb55 100644
--- a/libsieve/util.c
+++ b/libsieve/util.c
@@ -21,12 +21,13 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <sieve.h>
void *
sieve_alloc (size_t size)
{
- char *p = malloc (size);
+ void *p = malloc (size);
if (!p)
{
mu_error ("not enough memory");
@@ -35,6 +36,70 @@ sieve_alloc (size_t size)
return p;
}
+void *
+sieve_palloc (list_t *pool, size_t size)
+{
+ void *p = malloc (size);
+ if (p)
+ {
+ if (!*pool && list_create (pool))
+ {
+ free (p);
+ return NULL;
+ }
+ list_append (*pool, p);
+ }
+ return p;
+}
+
+char *
+sieve_pstrdup (list_t *pool, const char *str)
+{
+ size_t len;
+ char *p;
+
+ if (!str)
+ return NULL;
+ len = strlen (str);
+ p = sieve_palloc (pool, len + 1);
+ if (p)
+ {
+ memcpy (p, str, len);
+ p[len] = 0;
+ }
+ return p;
+}
+
+void *
+sieve_prealloc (list_t *pool, void *ptr, size_t size)
+{
+ void *newptr;
+
+ if (*pool)
+ list_remove (*pool, ptr);
+
+ newptr = realloc (ptr, size);
+ if (newptr)
+ {
+ if (!*pool && list_create (pool))
+ {
+ free (newptr);
+ return NULL;
+ }
+ list_append (*pool, newptr);
+ }
+ return newptr;
+}
+
+void
+sieve_pfree (list_t *pool, void *ptr)
+{
+
+ if (*pool)
+ list_remove (*pool, ptr);
+ free (ptr);
+}
+
void
sieve_slist_destroy (list_t *plist)
{
@@ -85,3 +150,164 @@ sieve_value_create (sieve_data_type type, void *data)
return val;
}
+void
+sieve_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ sieve_error_count++;
+ sieve_machine->error_printer (sieve_machine->data, fmt, ap);
+ va_end (ap);
+}
+
+void
+sieve_debug_internal (sieve_printf_t printer, void *data, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ printer (data, fmt, ap);
+ va_end (ap);
+}
+
+void
+sieve_debug (sieve_machine_t *mach, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ mach->debug_printer (mach->data, fmt, ap);
+ va_end (ap);
+}
+
+int
+_sieve_default_error_printer (void *unused, const char *fmt, va_list ap)
+{
+ return mu_verror (fmt, ap);
+}
+
+char *
+sieve_type_str (sieve_data_type type)
+{
+ switch (type)
+ {
+ case SVT_VOID:
+ return "void";
+
+ case SVT_NUMBER:
+ return "number";
+
+ case SVT_STRING:
+ return "string";
+
+ case SVT_STRING_LIST:
+ return "string-list";
+
+ case SVT_TAG:
+ return "tag";
+
+ case SVT_IDENT:
+ return "ident";
+
+ case SVT_VALUE_LIST:
+ return "value-list";
+ }
+
+ return "unknown";
+}
+
+struct debug_data {
+ sieve_printf_t printer;
+ void *data;
+};
+
+static int
+string_printer (char *s, struct debug_data *dbg)
+{
+ sieve_debug_internal (dbg->printer, dbg->data, "\"%s\" ", s);
+ return 0;
+}
+
+static int
+value_printer (sieve_value_t *val, struct debug_data *dbg)
+{
+ sieve_print_value (val, dbg->printer, dbg->data);
+ sieve_debug_internal (dbg->printer, dbg->data, " ");
+ return 0;
+}
+
+void
+sieve_print_value (sieve_value_t *val, sieve_printf_t printer, void *data)
+{
+ struct debug_data dbg;
+
+ dbg.printer = printer;
+ dbg.data = data;
+
+ sieve_debug_internal (printer, data, "%s(", sieve_type_str (val->type));
+ switch (val->type)
+ {
+ case SVT_VOID:
+ break;
+
+ case SVT_NUMBER:
+ sieve_debug_internal (printer, data, "%ld", val->v.number);
+ break;
+
+ case SVT_TAG:
+ case SVT_IDENT:
+ case SVT_STRING:
+ sieve_debug_internal (printer, data, "%s", val->v.string);
+ break;
+
+ case SVT_STRING_LIST:
+ list_do (val->v.list, (list_action_t*) string_printer, &dbg);
+ break;
+
+ case SVT_VALUE_LIST:
+ list_do (val->v.list, (list_action_t*) value_printer, &dbg);
+ }
+ sieve_debug_internal (printer, data, ")");
+}
+
+void
+sieve_print_value_list (list_t list, sieve_printf_t printer, void *data)
+{
+ sieve_value_t val;
+
+ val.type = SVT_VALUE_LIST;
+ val.v.list = list;
+ sieve_print_value (&val, printer, data);
+}
+
+static int
+tag_printer (sieve_runtime_tag_t *val, struct debug_data *dbg)
+{
+ sieve_debug_internal (dbg->printer, dbg->data, "%d", val->tag);
+ if (val->arg)
+ {
+ sieve_debug_internal (dbg->printer, dbg->data, "(");
+ sieve_print_value (val->arg, dbg->printer, dbg->data);
+ sieve_debug_internal (dbg->printer, dbg->data, ")");
+ }
+ sieve_debug_internal (dbg->printer, dbg->data, " ");
+}
+
+void
+sieve_print_tag_list (list_t list, sieve_printf_t printer, void *data)
+{
+ struct debug_data dbg;
+
+ dbg.printer = printer;
+ dbg.data = data;
+ list_do (list, (list_action_t*) tag_printer, &dbg);
+}
+
+void
+sieve_set_debug (sieve_machine_t *mach, sieve_printf_t debug, int level)
+{
+ mach->debug_printer = debug;
+ mach->debug_level = level;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.