diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-16 01:30:44 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-16 01:37:24 +0200 |
commit | 5000c56d29cf616c8df80f8ec9a19682769f512e (patch) | |
tree | d2cc46fda9e8905bdd2fb81bffdaf3a58898be53 /gconf/gconf-lex.l | |
parent | a72cd5987c404080f18ba40bdc4c06811493ab1c (diff) | |
download | wydawca-5000c56d29cf616c8df80f8ec9a19682769f512e.tar.gz wydawca-5000c56d29cf616c8df80f8ec9a19682769f512e.tar.bz2 |
Rewrite configuration parser, drop dependency on GSC
* bootstrap: Replaced with a modified version from gnulib.
* configure.ac: Bump version to 1.9.90
(--without-preprocessor): New option
Require Mailutils 2.0
(AC_CONFIG_FILES): Remove lib, add gconf
* gconf/: New directory. Contains general-purpose configuration file
parser, distilled from Dico and Mailutils.
* src/Makefile.am (wydawca_SOURCES): Add interval.c
* src/pp-setup, src/update-2.0.awk: New files.
* src/config.c: Full rewrite.
* src/exec.c (start_prog): Use getdtablesize unconditionally.
* src/mail.c: Keep templates in a hash table.
Template references begin with a single @
* src/process.c, src/triplet.c, src/verify.c: Reflect changes to struct
directory_pair
* src/wydawca.c: Change configuration parsing.
* src/wydawca.h (enum access_method_id): New constants
(struct directory_pair): Replace four access methods with an array.
* Makefile.am (SUBDIRS): Remove lib, add gconf
* .gitignore, NEWS, doc/.gitignore, src/.gitignore
Diffstat (limited to 'gconf/gconf-lex.l')
-rw-r--r-- | gconf/gconf-lex.l | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/gconf/gconf-lex.l b/gconf/gconf-lex.l new file mode 100644 index 0000000..1cdaada --- /dev/null +++ b/gconf/gconf-lex.l @@ -0,0 +1,479 @@ +/* gconf - General purpose configuration parser. -*- c -*- */ +%{ +/* gconf - General purpose configuration parser. + Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff + + 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 3 of the License, 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 <gconf.h> +#include <gconf-gram.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <stdlib.h> +#include <errno.h> + +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free +#include <obstack.h> +#include <xalloc.h> +#include <argcv.h> + +#if ENABLE_NLS +# include "gettext.h" +# define _(msgid) gettext (msgid) +#else +# define _(msgid) msgid +#endif + +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 */ + +gconf_locus_t gconf_current_locus; /* Input file location */ +/* Line correction. Equals to the number of #line directives inserted into + the input by the preprocessor instance. The external preprocessor, if + any, counts these as input lines and therefore the line numbers in *its* + #line directives are offset by the value of XLINES. + + Uff, running two preprocessors is confusing... +*/ +static size_t xlines; +static struct obstack stk; + +static void multiline_begin (char *); +static void multiline_add (char *); +static char *multiline_strip_tabs (char *text); +static void line_add_unescape_last (char *text, size_t len); +static int ident (void); +static int isemptystr (int off); + +static void parse_line (char *text, gconf_locus_t *ploc, size_t *pxlines); +static void parse_line_cpp (char *text, gconf_locus_t *ploc, size_t *pxlines); + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + do \ + { \ + if (gconf_preprocessor) \ + result = fread (buf, 1, max_size, yyin); \ + else \ + result = gconf_preproc_fill_buffer(buf, max_size); \ + } \ + while (0) + +%} + + +%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 ++gconf_current_locus.line; +<COMMENT>"*"+"/" BEGIN (INITIAL); + /* Line directive */ +^[ \t]*#[ \t]*{P}[ \t]+\".*\".*\n { parse_line_cpp (yytext, + &gconf_current_locus, + &xlines); } +^[ \t]*#[ \t]*line[ \t].*\n { parse_line (yytext, &gconf_current_locus, + &xlines); } + /* End-of-line comments */ +#.*\n { gconf_current_locus.line++; } +#.* /* end-of-file comment */; +"//".*\n { gconf_current_locus.line++; } +"//".* /* end-of-file comment */; + /* Identifiers */ +<INITIAL>{ID} return ident (); + /* Strings */ +[a-zA-Z0-9_\.\*/:@-]+ { gconf_line_begin (); + gconf_line_add (yytext, yyleng); + yylval.string = gconf_line_finish (); + return STRING; } + /* Quoted strings */ +\"[^\\"\n]*\" { gconf_line_begin (); + gconf_line_add (yytext + 1, yyleng - 2); + yylval.string = gconf_line_finish (); + return QSTRING; } +\"[^\\"\n]*\\. | +\"[^\\"\n]*\\\n { BEGIN (STR); + gconf_line_begin (); + line_add_unescape_last (yytext + 1, yyleng - 1); } +<STR>[^\\"\n]*\\. | +<STR>\"[^\\"\n]*\\\n { line_add_unescape_last (yytext, yyleng); } +<STR>[^\\"\n]*\" { BEGIN(INITIAL); + if (yyleng > 1) + gconf_line_add (yytext, yyleng - 1); + yylval.string = gconf_line_finish (); + return 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); + gconf_current_locus.line++; } + /* Ignore m4 line statements */ +<ML>^"#line ".*\n { gconf_current_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 = gconf_line_finish (); + return MSTRING; + } + gconf_current_locus.line++; + multiline_add (p); } +{WS} ; + /* Other tokens */ +\n { gconf_current_locus.line++; } +[,;{}()] return yytext[0]; +. { if (isascii (yytext[0]) && isprint (yytext[0])) + gconf_error (&gconf_current_locus, 0, _("stray character %c"), yytext[0]); + else + gconf_error (&gconf_current_locus, 0, _("stray character \\%03o"), + (unsigned char) yytext[0]); } +%% + +pid_t gconf_preproc_pid; + +int +yywrap () +{ + if (yyin) + gconf_preproc_extrn_shutdown (gconf_preproc_pid); + else + gconf_preproc_done (); + gconf_current_locus.file = NULL; + return 1; +} + +int +gconf_lex_begin (const char *name) +{ + if (yy_flex_debug > 0) + yy_flex_debug = 0; + obstack_init (&stk); + if (gconf_preprocessor) + { + int fd; + + fd = open (name, O_RDONLY); + if (fd == -1) + { + gconf_error (NULL, errno, _("Cannot open `%s'"), name); + return 1; + } + close (fd); + + yyin = gconf_preproc_extrn_start (name, &gconf_preproc_pid); + if (!yyin) + { + gconf_error (NULL, errno, + _("Unable to start external preprocessor `%s'"), + gconf_preprocessor); + return 1; + } + } + else + return gconf_preproc_init (name); + + return 0; +} + +void +gconf_lex_end () +{ +} + +static int +isemptystr (int off) +{ + for (; yytext[off] && isspace (yytext[off]); off++) + ; + if (yytext[off] == ';') + { + int i; + for (i = off + 1; yytext[i]; i++) + if (!isspace (yytext[i])) + return 0; + yyless (off); + return 1; + } + return yytext[off] == 0; +} + +char * +multiline_strip_tabs (char *text) +{ + if (char_to_strip) + for (; *text && char_to_strip (*text); text++) + ; + return text; +} + +static int +unquote_char (int c) +{ + static char quote_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t"; + + char *p; + + for (p = quote_transtab; *p; p += 2) + { + if (*p == c) + return p[1]; + } + return -1; +} + +static void +unescape_to_obstack (int c) +{ + if (c != '\n') + { + int t = unquote_char (c); + if (t != -1) + obstack_1grow (&stk, t); + else + { + gconf_warning(&gconf_current_locus, 0, + _("unknown escape sequence '\\%c'"), + c); + obstack_1grow (&stk, c); + } + } +} + +void +gconf_line_add (const char *text, size_t len) +{ + obstack_grow (&stk, text, len); +} + +/* Same, but unescapes the last character from yytext */ +static void +line_add_unescape_last (char *text, size_t len) +{ + obstack_grow (&stk, text, len - 2); + unescape_to_obstack (text[len - 1]); +} + +static void +multiline_add (char *s) +{ + if (multiline_unescape) + { + for (; *s; s++) + { + if (*s == '\\') + { + unescape_to_obstack (s[1]); + ++s; + } + else + obstack_1grow (&stk, *s); + } + } + else + gconf_line_add (s, strlen (s)); +} + +void +gconf_line_begin () +{ + /* FIXME: nothing so far. Maybe prepare stk by calling obstack_finish? */ +} + +static int +is_tab (char c) +{ + return c == '\t'; +} + +static int +is_ws (char c) +{ + return c == '\t' || c == ' '; +} + +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 = xmalloc (multiline_delimiter_len + 1); + memcpy (multiline_delimiter, p, multiline_delimiter_len); + multiline_delimiter[multiline_delimiter_len] = 0; + gconf_line_begin (); +} + +char * +gconf_line_finish () +{ + obstack_1grow (&stk, 0); + return obstack_finish (&stk); +} + +static int +ident () +{ + char *p; + + for (p = yytext; *p && isspace (*p); p++) + ; + obstack_grow (&stk, p, strlen (p)); + obstack_1grow (&stk, 0); + yylval.string = obstack_finish (&stk); + return IDENT; +} + +void +gconf_lex_trace (int n) +{ + yy_flex_debug = -n; +} + +gconf_value_t * +gconf_value_dup(gconf_value_t *input) +{ + gconf_value_t *ptr = obstack_alloc (&stk, sizeof (*ptr)); + *ptr = *input; + return ptr; +} + + +static int +assign_locus (gconf_locus_t *ploc, char *name, char *line, size_t *pxlines) +{ + char *p; + + if (name) + { + if (pxlines && (!ploc->file || strcmp(name, ploc->file))) + *pxlines = 0; + ploc->file = gconf_install_text (name); + } + ploc->line = strtoul (line, &p, 10) - (pxlines ? *pxlines : 0); + return *p != 0; +} + +static void +parse_line (char *text, gconf_locus_t *ploc, size_t *pxlines) +{ + int rc = 1; + int argc; + char **argv; + + while (*text && isspace (*text)) + text++; + text++; + + if (argcv_get (text, "", NULL, &argc, &argv)) + gconf_error (ploc, 0, _("cannot parse #line line")); + else + { + if (argc == 2) + rc = assign_locus (ploc, NULL, argv[1], pxlines); + else if (argc == 3) + rc = assign_locus (ploc, argv[2], argv[1], pxlines); + else if (argc == 4) + { + rc = assign_locus (ploc, argv[2], argv[1], 0); + if (rc == 0) + { + char *p; + unsigned long x = strtoul (argv[3], &p, 10); + rc = *p != 0; + if (rc == 0) + *pxlines = x; + } + } + else + gconf_error (ploc, 0, _("invalid #line statement")); + + if (rc) + gconf_error (ploc, 0, _("malformed #line statement")); + } + argcv_free (argc, argv); +} + +static void +parse_line_cpp (char *text, gconf_locus_t *ploc, size_t *pxlines) +{ + int argc; + char **argv; + + if (argcv_get (text, "", NULL, &argc, &argv)) + gconf_error (ploc, 0, _("cannot parse #line line")); + else if (argc < 3) + gconf_error (ploc, 0, _("invalid #line statement")); + else + { + if (assign_locus (ploc, argv[2], argv[1], pxlines)) + gconf_error (ploc, 0, _("malformed #line statement")); + } + argcv_free (argc, argv); +} + |