diff options
Diffstat (limited to 'libsieve')
-rw-r--r-- | libsieve/actions.c | 18 | ||||
-rw-r--r-- | libsieve/register.c | 14 | ||||
-rw-r--r-- | libsieve/sieve.h | 66 | ||||
-rw-r--r-- | libsieve/sieve.l | 18 | ||||
-rw-r--r-- | libsieve/sieve.y | 89 | ||||
-rw-r--r-- | libsieve/sv.c | 20 | ||||
-rw-r--r-- | libsieve/tests.c | 21 | ||||
-rw-r--r-- | libsieve/util.c | 228 |
8 files changed, 434 insertions, 40 deletions
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; +} + |