diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2002-11-07 14:48:23 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2002-11-07 14:48:23 +0000 |
commit | 740b1c8401ec6139449ab717b83232afcb60620b (patch) | |
tree | 883acb0cafd3ca057290fd14884812d52467f034 | |
parent | a250bc91a29211e4792f2098769363a820b16823 (diff) | |
download | mailutils-740b1c8401ec6139449ab717b83232afcb60620b.tar.gz mailutils-740b1c8401ec6139449ab717b83232afcb60620b.tar.bz2 |
Added to the repository
-rw-r--r-- | libsieve/.cvsignore | 9 | ||||
-rw-r--r-- | libsieve/Makefile.am | 36 | ||||
-rw-r--r-- | libsieve/sieve.h | 30 | ||||
-rw-r--r-- | libsieve/sieve.l | 398 | ||||
-rw-r--r-- | libsieve/sieve.y | 119 | ||||
-rw-r--r-- | libsieve/sv.c | 41 | ||||
-rw-r--r-- | libsieve/util.c | 37 |
7 files changed, 670 insertions, 0 deletions
diff --git a/libsieve/.cvsignore b/libsieve/.cvsignore new file mode 100644 index 000000000..91f5ca920 --- /dev/null +++ b/libsieve/.cvsignore @@ -0,0 +1,9 @@ +Makefile.in +Makefile +.deps +.libs +.gdbinit +*.la +*.lo +*.output +*.tab.[ch] diff --git a/libsieve/Makefile.am b/libsieve/Makefile.am new file mode 100644 index 000000000..4ce0bd5d6 --- /dev/null +++ b/libsieve/Makefile.am @@ -0,0 +1,36 @@ +# This file is part of GNU Mailutils +# Copyright (C) 2000,2001,2002 Free Software Foundation +# See file COPYING in the distribution root directory for copying conditions. + +INCLUDES = -I${top_srcdir}/include -I${top_srcdir}/lib +YLWRAP = $(SHELL) $(top_srcdir)/scripts/ylwrap +AM_YFLAGS = -dtv + +lib_LTLIBRARIES = libsieve.la + +noinst_PROGRAMS = sv + +libsieve_la_SOURCES = sieve-gram.c sieve-gram.h sieve-lex.c util.c +sv_SOURCES = sv.c +sv_LDADD = ./libsieve.la ../mailbox/libmailbox.la +noinst_HEADERS = sieve.h + +BUILT_SOURCES= \ + sieve-gram.c sieve-gram.h \ + sieve-lex.c + +MAINTAINERCLEANFILES=$(BUILT_SOURCES) + +EXTRA_DIST = sieve.y sieve.l + +sieve-lex.c: $(srcdir)/sieve.l sieve-gram.h + $(YLWRAP) "$(LEX) $(AM_LEXFLAGS) $(LEXFLAGS)" \ + $(srcdir)/sieve.l lex.yy.c sieve-lex.c \ + -- -yy sieve_yy + +sieve-gram.c sieve-gram.h: $(srcdir)/sieve.y + $(YLWRAP) "$(YACC) $(AM_YFLAGS) $(YFLAGS)" $(srcdir)/sieve.y \ + y.tab.c sieve-gram.c y.tab.h sieve-gram.h y.output y.output \ + -- -yy sieve_yy + + diff --git a/libsieve/sieve.h b/libsieve/sieve.h new file mode 100644 index 000000000..68c631f94 --- /dev/null +++ b/libsieve/sieve.h @@ -0,0 +1,30 @@ +/* GNU mailutils - a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <sys/types.h> + +#define sieve_error mu_error + +extern char *sieve_filename; +extern int sieve_line_num; +extern int sieve_yydebug; + +void *sieve_alloc (size_t size); + +int sieve_open_source (const char *name); + +int sieve_parse (const char *name); diff --git a/libsieve/sieve.l b/libsieve/sieve.l new file mode 100644 index 000000000..4e1d10dbb --- /dev/null +++ b/libsieve/sieve.l @@ -0,0 +1,398 @@ +%{ +/* GNU mailutils - a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <errno.h> +#include <sieve.h> +#include <sieve-gram.h> + + +char *sieve_filename; +int sieve_line_num; +ino_t sieve_source_inode; + +#ifdef FLEX_SCANNER +#define xinput() (yyin ? getc(yyin) : EOF) +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) do { \ + int i; \ + for (i = 0; i < max_size; i++) { \ + int ch = xinput(); \ + if (ch == EOF) \ + break; \ + buf[i] = ch; \ + } \ + result = i; \ +} while (0) +#define LEX_BUFFER_STATE YY_BUFFER_STATE +#define SET_BUFFER_STATE(s) do { \ + (s) = YY_CURRENT_BUFFER; \ + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); \ +} while (0) +#define RESTORE_BUFFER_STATE(s) do { \ + yy_delete_buffer(YY_CURRENT_BUFFER); \ + yy_switch_to_buffer(s); \ +} while (0) + +#else +/* AT&T Lex */ + +static void lex_set_buffer __P((FILE *fp)); +static void lex_delete_buffer __P((LEX_BUFFER_STATE buf)); +static int xinput __P((void)); +static int xunput __P((void)); + +#undef unput +#define unput(c) xunput(c) +#undef input +#define input() xinput() + +#define LEX_BUF_SIZE 16384 +#define LEX_PUTBACK_SIZE 32 + +typedef struct { + FILE *yyin; + char *buffer; + size_t bufsize; + size_t level; + char *ptr; + char *putback; + size_t pb_size; + size_t pb_level; +} LEX_BUFFER_STATE; +LEX_BUFFER_STATE current_buffer; + +#define SET_BUFFER_STATE(s) do { \ + (s) = current_buffer; \ + lex_set_buffer(yyin); \ +} while (0) +#define RESTORE_BUFFER_STATE(s) do { \ + lex_delete_buffer(current_buffer); \ + current_buffer = (s); \ + yyin = current_buffer.yyin; \ +} while (0) + +void +lex_set_buffer (FILE *fp) +{ + char *buf; + size_t size; + + for (size = LEX_BUF_SIZE; size > 1; size /= 2) + if (buf = malloc (size)) + break; + + if (!buf) + { + sieve_error ("not enough memory"); + abort (); + } + + current_buffer.yyin = yyin; + current_buffer.buffer = buf; + current_buffer.bufsize = size; + current_buffer.level = 0; + current_buffer.ptr = current_buffer.buffer; + current_buffer.pb_size = current_buffer.pb_level = 0; + current_buffer.putback = NULL; +} + +void +lex_delete_buffer (LEX_BUFFER_STATE buf) +{ + free (buf.buffer); + if (buf.putback) + free (buf.putback); +} + +int +xinput () +{ + if (!yyin) + return EOF; + + if (current_buffer.pb_level) + return current_buffer.putback[--current_buffer.pb_level]; + + if (current_buffer.level <= 0) + { + int n; + + if (feof (yyin)) + return 0; + n = fread (current_buffer.buffer, 1, + current_buffer.bufsize, yyin); + if (n <= 0) + return 0; + current_buffer.level = n; + current_buffer.ptr = current_buffer.buffer; + } + current_buffer.level--; + return *current_buffer.ptr++; +} + +int +xunput (int c) +{ + if (current_buffer.pb_level == current_buffer.pb_size) + { + char *putback; + current_buffer.pb_size += LEX_PUTBACK_SIZE; + putback = sieve_alloc (current_buffer.pb_size); + memcpy (putback, current_buffer.putback, + current_buffer.pb_level); + free (current_buffer.putback); + current_buffer.putback = putback; + } + current_buffer.putback[current_buffer.pb_level++] = c; + return c; +} + +#endif + +struct buffer_ctx { + struct buffer_ctx *prev; + char *filename; + int line; + ino_t i_node; + FILE *yyin; + LEX_BUFFER_STATE state; +}; + +static struct buffer_ctx *context_stack; + +static struct buffer_ctx *ctx_lookup __P((ino_t ino)); +static int push_source __P((char *name)); +static int pop_source __P((void)); + +struct buffer_ctx * +ctx_lookup (ino_t ino) +{ + struct buffer_ctx *ctx; + + for (ctx = context_stack; ctx; ctx = ctx->prev) + if (ctx->i_node == ino) + break; + return ctx; +} + +int +push_source (char *name) +{ + FILE *fp; + struct buffer_ctx *ctx; + struct stat st; + + if (stat (name, &st)) + { + sieve_error ("can't stat `%s': %s", name, strerror (errno)); + yyerror ("can't include file"); + return 1; + } + + if (sieve_filename && st.st_ino == sieve_source_inode) + { + yyerror ("recursive inclusion"); + return 1; + } + if (ctx = ctx_lookup (st.st_ino)) + { + yyerror ("recursive inclusion"); + if (ctx->prev) + sieve_error ("%s:%d: `%s' already included here", + ctx->prev->filename, ctx->prev->line, name); + else + sieve_error ("`%s' already included at top level", + name); + return 1; + } + + fp = fopen (name, "r"); + if (!fp) + { + sieve_error ("can't open `%s': %s", name, strerror (errno)); + yyerror ("can't include file"); + return 1; + } + + /* Push current context */ + if (sieve_filename) + { + ctx = sieve_alloc (sizeof (*ctx)); + ctx->filename = sieve_filename; + ctx->line = sieve_line_num; + ctx->i_node = sieve_source_inode; + ctx->yyin = yyin; + ctx->prev = context_stack; + context_stack = ctx; + + /* Switch to the new context */ + yyin = fp; + SET_BUFFER_STATE (ctx->state); + } + else + { +#ifdef FLEX_SCANNER + yyrestart (fp); +#else + yyin = fp; + lex_set_buffer (yyin); +#endif + } + sieve_filename = strdup (name); + sieve_line_num = 1; + sieve_source_inode = st.st_ino; + return 0; +} + +int +pop_source () +{ + struct buffer_ctx *ctx; + + fclose (yyin); +#ifndef FLEX_SCANNER + lex_delete_buffer (current_buffer); +#endif + if (!context_stack) + { + yyin = NULL; + return 1; + } + if (sieve_filename) + free (sieve_filename); + /* Restore previous context */ + sieve_filename = context_stack->filename; + sieve_line_num = context_stack->line + 1; /* #include rule did not increment + it */ + sieve_source_inode = context_stack->i_node; + RESTORE_BUFFER_STATE (context_stack->state); + ctx = context_stack->prev; + free (context_stack); + context_stack = ctx; + return 0; +} +%} +%x COMMENT ML + +WS [ \t][ \t]* +IDENT [a-zA-Z_][a-zA-Z_0-9]+ + +%% + /* C-style comments */ +"/*" BEGIN(COMMENT); +<COMMENT>[^*\n]* /* eat anything that's not a '*' */ +<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +<COMMENT>\n ++sieve_line_num; +<COMMENT>"*"+"/" BEGIN(INITIAL); + /* Preprocessor directives (an extension) */ +#[ \t]*include.*\n { sieve_include (); } + /* End-of-line comments */ +#.*\n { sieve_line_num++; } +#.* /* end-of-file comment */; + /* Reserved words */ +require return REQUIRE; +if return IF; +elsif return ELSIF; +else return ELSE; +anyof return ANYOF; +allof return ALLOF; +true return TRUE; +false return FALSE; +not return NOT; + /* Other tokens */ +{IDENT} return IDENT; +:{IDENT} { return TAG; } +0[0-7]* { return NUMBER; } +0x[0-9a-fA-F][0-9a-fA-F]+ { return NUMBER; } +[1-9][0-9]* { return NUMBER; } +\"[^"\n]*\" { return STRING; } +text: { BEGIN(ML); } +<ML>.[ \t]*\n { BEGIN(INITIAL); sieve_line_num++; return MULTILINE; } +<ML>.*\n { sieve_line_num++; } +{WS} ; +\n { sieve_line_num++; } +. return yytext[0]; + +%% + +int +yywrap () +{ + return pop_source(); +} + +void +sieve_include () +{ + char *p, *startp, *endp = yytext + yyleng, exp, *name; + int n; + + p = strstr (yytext, "include"); + for (p += 7; p < endp && isspace (*p); p++) + ; + + switch (*p) + { + case '"': + exp = '"'; + break; + + case '<': + exp = '>'; + break; + + default: + yyerror ("include syntax"); + return; + } + + for (startp = ++p; p < endp && *p != exp; p++) + ; + + if (*p != exp) + { + yyerror ("missing closing quote in include statement"); + return; + } + + n = p - startp; + name = sieve_alloc (n + 1); + memcpy (name, startp, n); + name[n] = 0; + + push_source (name); + free (name); +} + +int +sieve_open_source (const char *name) +{ + return push_source (name); +} + + + diff --git a/libsieve/sieve.y b/libsieve/sieve.y new file mode 100644 index 000000000..1341a5c0c --- /dev/null +++ b/libsieve/sieve.y @@ -0,0 +1,119 @@ +%{ +/* GNU mailutils - a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdio.h> +#include <assert.h> +#include <sieve.h> + +%} + +%token IDENT TAG NUMBER STRING MULTILINE +%token REQUIRE IF ELSIF ELSE ANYOF ALLOF TRUE FALSE NOT +%% + +input : /* empty */ + | list + ; + +list : statement + | list statement + ; + +statement : REQUIRE stringlist ';' + | action ';' + | IF cond block maybe_elsif maybe_else + ; + +maybe_elsif : /* empty */ + | elsif + ; + +elsif : ELSIF cond block + | elsif ELSIF cond block + ; + +maybe_else : /* empty */ + | ELSE block + ; + +block : '{' list '}' + ; + + +testlist : test + | testlist ',' test + ; + +cond : test + | ANYOF '(' testlist ')' + | ALLOF '(' testlist ')' + | NOT cond + ; + +test : FALSE + | TRUE + | command + ; + +command : IDENT maybe_arglist + ; + +action : command + ; + +maybe_arglist: /* empty */ + | arglist + ; + +arglist : arg + | arglist arg + ; + +arg : stringlist + | MULTILINE + | NUMBER + | TAG + ; + +stringlist : STRING + | '[' slist ']' + ; + +slist : STRING + | slist ',' STRING + ; + +%% + +int +yyerror (char *s) +{ + fprintf (stderr, "%s:%d: ", sieve_filename, sieve_line_num); + fprintf (stderr, "%s\n", s); +} + +int +sieve_parse (const char *name) +{ + sieve_open_source (name); + return yyparse (); +} + diff --git a/libsieve/sv.c b/libsieve/sv.c new file mode 100644 index 000000000..03a9157ec --- /dev/null +++ b/libsieve/sv.c @@ -0,0 +1,41 @@ +/* GNU mailutils - a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is just a test program for libsieve. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <assert.h> +#include <sieve.h> + +int +main (int argc, char **argv) +{ + int n; + + assert (argc > 1); + if (strcmp (argv[1], "-d") == 0) + { + sieve_yydebug++; + n = 2; + assert (argc > 2); + } + else + n = 1; + return sieve_parse (argv[n]); +} diff --git a/libsieve/util.c b/libsieve/util.c new file mode 100644 index 000000000..c432876a3 --- /dev/null +++ b/libsieve/util.c @@ -0,0 +1,37 @@ +/* GNU mailutils - a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <sieve.h> + +void * +sieve_alloc (size_t size) +{ + char *p = malloc (size); + if (!p) + { + mu_error ("not enough memory"); + abort (); + } + return p; +} + |