summaryrefslogtreecommitdiff
path: root/libmailutils/cfg/lexer.l
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils/cfg/lexer.l')
-rw-r--r--libmailutils/cfg/lexer.l405
1 files changed, 405 insertions, 0 deletions
diff --git a/libmailutils/cfg/lexer.l b/libmailutils/cfg/lexer.l
new file mode 100644
index 000000000..fa7a11a17
--- /dev/null
+++ b/libmailutils/cfg/lexer.l
@@ -0,0 +1,405 @@
+%top {
+/* cfg_lexer.l -- default lexer for Mailutils configuration files
+ Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+ GNU Mailutils 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 3, 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, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+}
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <mailutils/cctype.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/debug.h>
+#include <mailutils/argcv.h>
+#include <mailutils/alloc.h>
+#include <mailutils/nls.h>
+#include <mailutils/cfg.h>
+#include <mailutils/list.h>
+#include <mailutils/mutil.h>
+
+#include "parser.h"
+
+void _mu_line_begin (void);
+void _mu_line_add (char *text, size_t len);
+char *_mu_line_finish (void);
+
+extern void mu_cfg_set_debug (void);
+static void
+mu_cfg_set_lex_debug (void)
+{
+ yy_flex_debug = mu_debug_check_level (mu_cfg_get_debug (),
+ MU_DEBUG_TRACE2);
+}
+
+static void _mu_line_add_unescape_last (char *text, size_t len);
+static void multiline_begin (char *p);
+static char *multiline_strip_tabs (char *text);
+static void multiline_add (char *s);
+static char *multiline_finish (void);
+
+static char *multiline_delimiter;
+static size_t multiline_delimiter_len;
+static int multiline_unescape; /* Unescape here-document contents */
+static int (*char_to_strip)(char); /* Strip matching characters of each
+ here-document line */
+static int isemptystr(int off);
+
+static mu_opool_t pool;
+
+%}
+
+%x COMMENT ML STR
+
+WS [ \t\f][ \t\f]*
+ID [a-zA-Z_][a-zA-Z_0-9-]+
+P [1-9][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 ++mu_cfg_locus.line;
+<COMMENT>"*"+"/" BEGIN (INITIAL);
+ /* End-of-line comments */
+#debug=.*\n {
+ mu_log_level_t lev;
+ mu_debug_t dbg = mu_cfg_get_debug ();
+ if (mu_debug_level_from_string (yytext + 7, &lev, dbg) == 0)
+ {
+ mu_debug_set_level (dbg, lev);
+ mu_cfg_set_debug ();
+ mu_cfg_set_lex_debug ();
+ }
+ }
+#.*\n { mu_cfg_locus.line++; }
+#.* /* end-of-file comment */;
+"//".*\n { mu_cfg_locus.line++; }
+"//".* /* end-of-file comment */;
+ /* Identifiers */
+<INITIAL>{ID} {
+ _mu_line_begin ();
+ _mu_line_add (yytext, yyleng);
+ yylval.string = _mu_line_finish ();
+ return MU_TOK_IDENT; }
+ /* Strings */
+[a-zA-Z0-9_\./:\*=-]+ { _mu_line_begin ();
+ _mu_line_add (yytext, yyleng);
+ yylval.string = _mu_line_finish ();
+ return MU_TOK_STRING; }
+ /* Quoted strings */
+\"[^\\"\n]*\" { _mu_line_begin ();
+ _mu_line_add (yytext + 1, yyleng - 2);
+ yylval.string = _mu_line_finish ();
+ return MU_TOK_QSTRING; }
+\"[^\\"\n]*\\. |
+\"[^\\"\n]*\\\n { BEGIN (STR);
+ _mu_line_begin ();
+ _mu_line_add_unescape_last (yytext + 1, yyleng - 1); }
+<STR>[^\\"\n]*\\. |
+<STR>\"[^\\"\n]*\\\n { _mu_line_add_unescape_last (yytext, yyleng); }
+<STR>[^\\"\n]*\" { BEGIN (INITIAL);
+ if (yyleng > 1)
+ _mu_line_add (yytext, yyleng - 1);
+ yylval.string = _mu_line_finish ();
+ return MU_TOK_QSTRING; }
+ /* Multiline strings */
+"<<"(-" "?)?\\?{ID}[ \t]*#.*\n |
+"<<"(-" "?)?\\?{ID}[ \t]*"//".*\n |
+"<<"(-" "?)?\\?{ID}[ \t]*\n |
+"<<"(-" "?)?\"{ID}\"[ \t]*#.*\n |
+"<<"(-" "?)?\"{ID}\"[ \t]*"//".*\n |
+"<<"(-" "?)?\"{ID}\"[ \t]*\n {
+ BEGIN (ML);
+ multiline_begin (yytext+2);
+ mu_cfg_locus.line++;
+ }
+<ML>.*\n { char *p = multiline_strip_tabs (yytext);
+
+ if (!strncmp (p, multiline_delimiter, multiline_delimiter_len)
+ && isemptystr (p + multiline_delimiter_len - yytext))
+ {
+ free (multiline_delimiter);
+ multiline_delimiter = NULL;
+ BEGIN (INITIAL);
+ yylval.string = multiline_finish ();
+ return MU_TOK_MSTRING;
+ }
+ mu_cfg_locus.line++;
+ multiline_add (p); }
+{WS} ;
+ /* Other tokens */
+\n { mu_cfg_locus.line++; }
+[,;{}()] return yytext[0];
+. { if (mu_isprint (yytext[0]))
+ mu_cfg_parse_error (_("stray character %c"), yytext[0]);
+ else
+ mu_cfg_parse_error (_("stray character \\%03o"),
+ (unsigned char) yytext[0]);
+ }
+%%
+
+int
+yywrap ()
+{
+ return 1;
+}
+
+static void
+unescape_to_line (int c)
+{
+ if (c != '\n')
+ {
+ char t = mu_argcv_unquote_char (c);
+ if (t == c && t != '\\' && t != '\"')
+ mu_cfg_parse_error (_("unknown escape sequence '\\%c'"), c);
+ mu_opool_append_char (pool, t);
+ }
+}
+
+void
+_mu_line_add (char *text, size_t len)
+{
+ mu_opool_append (pool, text, len);
+}
+
+void
+_mu_line_add_unescape_last (char *text, size_t len)
+{
+ mu_opool_append (pool, text, len - 2);
+ unescape_to_line (text[len - 1]);
+}
+
+void
+_mu_line_begin ()
+{
+ if (!pool)
+ mu_opool_create (&pool, 1);
+ else
+ mu_opool_clear (pool);
+}
+
+char *
+_mu_line_finish ()
+{
+ mu_opool_append_char (pool, 0);
+ return mu_opool_finish (pool, NULL);
+}
+
+
+
+static int
+is_tab (char c)
+{
+ return c == '\t';
+}
+
+static int
+is_ws (char c)
+{
+ return c == '\t' || c == ' ';
+}
+
+static int
+isemptystr (int off)
+{
+ for (; yytext[off] && mu_isspace (yytext[off]); off++)
+ ;
+ if (yytext[off] == ';')
+ {
+ int i;
+ for (i = off + 1; yytext[i]; i++)
+ if (!mu_isspace (yytext[i]))
+ return 0;
+ yyless (off);
+ return 1;
+ }
+ return yytext[off] == 0;
+}
+
+static void
+multiline_begin (char *p)
+{
+ if (*p == '-')
+ {
+ if (*++p == ' ')
+ {
+ char_to_strip = is_ws;
+ p++;
+ }
+ else
+ char_to_strip = is_tab;
+ }
+ else
+ char_to_strip = NULL;
+ if (*p == '\\')
+ {
+ p++;
+ multiline_unescape = 0;
+ }
+ else if (*p == '"')
+ {
+ char *q;
+
+ p++;
+ multiline_unescape = 0;
+ q = strchr (p, '"');
+ multiline_delimiter_len = q - p;
+ }
+ else
+ {
+ multiline_delimiter_len = strcspn (p, " \t");
+ multiline_unescape = 1;
+ }
+
+ /* Remove trailing newline */
+ multiline_delimiter_len--;
+ multiline_delimiter = mu_alloc (multiline_delimiter_len + 1);
+ memcpy (multiline_delimiter, p, multiline_delimiter_len);
+ multiline_delimiter[multiline_delimiter_len] = 0;
+ _mu_line_begin ();
+}
+
+static char *
+multiline_strip_tabs (char *text)
+{
+ if (char_to_strip)
+ for (; *text && char_to_strip (*text); text++)
+ ;
+ return text;
+}
+
+static void
+multiline_add (char *s)
+{
+ if (multiline_unescape)
+ {
+ for (; *s; s++)
+ {
+ if (*s == '\\')
+ {
+ unescape_to_line (s[1]);
+ ++s;
+ }
+ else
+ _mu_line_add (s, 1);
+ }
+ }
+ else
+ _mu_line_add (s, strlen (s));
+}
+
+static char *
+multiline_finish ()
+{
+ return _mu_line_finish ();
+}
+
+
+int
+mu_cfg_parse_file (mu_cfg_tree_t **return_tree, const char *file, int flags)
+{
+ struct stat st;
+ FILE *fp;
+ int rc;
+ char *full_name = mu_tilde_expansion (file, "/", NULL);
+
+ if (stat (full_name, &st))
+ {
+ if (errno != ENOENT)
+ mu_error (_("cannot stat `%s': %s"), full_name, mu_strerror (errno));
+ free (full_name);
+ return ENOENT;
+ }
+ else if (!S_ISREG (st.st_mode))
+ {
+ if (flags & MU_PARSE_CONFIG_VERBOSE)
+ mu_diag_output (MU_DIAG_INFO, _("%s: not a regular file"), full_name);
+ free (full_name);
+ return ENOENT;
+ }
+
+ fp = fopen (full_name, "r");
+ if (!fp)
+ {
+ mu_error (_("cannot open config file `%s': %s"), full_name,
+ mu_strerror (errno));
+ free (full_name);
+ return errno;
+ }
+
+ if (flags & MU_PARSE_CONFIG_VERBOSE)
+ mu_diag_output (MU_DIAG_INFO, _("parsing file `%s'"), full_name);
+
+ mu_cfg_set_lex_debug ();
+
+ /* Initialize locus: */
+ /* 1. Save file name in the lexer object pool and point `file' member
+ to this copy. Free full_name: it is not used after that. */
+ _mu_line_begin ();
+ _mu_line_add (full_name, strlen (full_name));
+ mu_cfg_locus.file = _mu_line_finish ();
+ free (full_name);
+ /* 2. Initialize line number */
+ mu_cfg_locus.line = 1;
+
+ /* Parse configuration */
+ yyrestart (fp);
+ rc = mu_cfg_parse (return_tree);
+ fclose (fp);
+ if (flags & MU_PARSE_CONFIG_VERBOSE)
+ mu_diag_output (MU_DIAG_INFO, _("finished parsing file `%s'"),
+ mu_cfg_locus.file);
+
+ return rc == 0 ? 0 : MU_ERR_FAILURE;
+}
+
+/* FIXME: Deprecated interface */
+int
+mu_get_config (const char *file, const char *progname,
+ struct mu_cfg_param *progparam, int flags, void *target_ptr)
+{
+ mu_cfg_tree_t *parse_tree;
+ int rc = mu_cfg_parse_file (&parse_tree, file, flags);
+ if (rc == 0)
+ {
+ rc = mu_cfg_tree_postprocess (parse_tree, flags);
+ if (rc == 0)
+ rc = mu_cfg_tree_reduce (parse_tree, progname, progparam, flags,
+ target_ptr);
+ mu_cfg_destroy_tree (&parse_tree);
+ }
+
+ return rc == 0 ? 0 : MU_ERR_FAILURE;
+}
+
+
+mu_opool_t
+mu_cfg_lexer_pool ()
+{
+ mu_opool_t p = pool;
+ pool = NULL;
+ return p;
+}

Return to:

Send suggestions and report system problems to the System administrator.