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 | 4ea235014b22e357c7a6e283ce52b80a1778c0bd (patch) | |
tree | 7b79814ed11bcb02d08a13d92138ea9215778723 | |
download | grecs-4ea235014b22e357c7a6e283ce52b80a1778c0bd.tar.gz grecs-4ea235014b22e357c7a6e283ce52b80a1778c0bd.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
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile.am | 17 | ||||
-rw-r--r-- | argcv.c | 632 | ||||
-rw-r--r-- | argcv.h | 79 | ||||
-rw-r--r-- | gconf-format.c | 200 | ||||
-rw-r--r-- | gconf-gram.y | 819 | ||||
-rw-r--r-- | gconf-lex.l | 479 | ||||
-rw-r--r-- | gconf-preproc.c | 727 | ||||
-rw-r--r-- | gconf-text.c | 73 | ||||
-rw-r--r-- | gconf.h | 153 | ||||
-rw-r--r-- | gnulib.modules | 13 |
11 files changed, 3196 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42c88b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +gconf-gram.c +gconf-gram.h +gconf-gram.output +gconf-lex.c diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..4f50bd6 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,17 @@ +noinst_LIBRARIES=libgconf.a +libgconf_a_SOURCES = \ + argcv.c\ + argcv.h\ + gconf-format.c\ + gconf-gram.y\ + gconf-lex.l\ + gconf-preproc.c\ + gconf-text.c\ + gconf.h + +EXTRA_DIST=gconf-gram.h + +INCLUDES = -I$(top_srcdir)/gnu -I../gnu +AM_YFLAGS = -dtv +AM_LFLAGS = -dvp + @@ -0,0 +1,632 @@ +/* argcv.c - simple functions for parsing input based on whitespace + Copyright (C) 1999, 2000, 2001, 2003, 2004, + 2005, 2006, 2008, 2009 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <c-ctype.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <argcv.h> + +enum argcv_quoting_style argcv_quoting_style; + +#define _ARGCV_WORD_SED_EXPR 0x1000 +#define _ARGCV_WORD_MASK 0xf000 + +/* + * takes a string and splits it into several strings, breaking at ' ' + * command is the string to split + * the number of strings is placed into argc + * the split strings are put into argv + * returns 0 on success, nonzero on failure + */ + +#define isws(c) ((c)==' '||(c)=='\t'||(c)=='\n') +#define isdelim(c,delim) (strchr(delim,(c))!=NULL) + +struct argcv_info +{ + int len; + const char *command; + const char *delim; + const char *comment; + int flags; + + int start; + int end; + int save; + int finish_pos; +}; + +static void +init_argcv_info (struct argcv_info *ap, int flags, + int len, const char *command, const char *delim, + const char *comment) +{ + memset (ap, 0, sizeof *ap); + ap->len = len; + ap->command = command; + ap->delim = delim; + ap->comment = comment; + ap->flags = flags; +} + +static int +skip_sed_expr(const char *command, int i, int len) +{ + int state; + + do + { + int delim; + + if (command[i] == ';') + i++; + if (!(command[i] == 's' && i + 3 < len && c_ispunct(command[i+1]))) + break; + + delim = command[++i]; + state = 1; + for (i++; i < len; i++) + { + if (state == 3) + { + if (command[i] == delim || !c_isalnum(command[i])) + break; + } + else if (command[i] == '\\') + i++; + else if (command[i] == delim) + state++; + } + } + while (state == 3 && i < len && command[i] == ';'); + i--; + return i; +} + +static int +argcv_scan (struct argcv_info *ap) +{ + int i = 0; + int len = ap->len; + const char *command = ap->command; + const char *delim = ap->delim; + const char *comment = ap->comment; + + for (;;) + { + i = ap->save; + + if (i >= len) + return i + 1; + + if (ap->flags & ARGCV_WS) + { + /* Skip initial whitespace */ + while (i < len && isws (command[i])) + i++; + } + ap->start = i; + + ap->flags &= ~_ARGCV_WORD_MASK; + + if (ap->flags & ARGCV_SED_EXPR + && command[i] == 's' && i + 3 < len && c_ispunct(command[i+1])) + { + ap->flags |= _ARGCV_WORD_SED_EXPR; + i = skip_sed_expr(command, i, len); + } + else if (!isdelim (command[i], delim)) + { + while (i < len) + { + if (ap->flags & ARGCV_QUOTE) + { + if (command[i] == '\\') + { + if (++i == len) + break; + i++; + continue; + } + + if (command[i] == '\'' || command[i] == '"') + { + int j; + for (j = i + 1; j < len && command[j] != command[i]; j++) + if (command[j] == '\\') + j++; + if (j < len) + i = j + 1; + else + i++; + continue; + } + } + if ((ap->flags & ARGCV_WS && isws (command[i])) + || isdelim (command[i], delim)) + break; + else + i++; + } + i--; + } + else if (!(ap->flags & ARGCV_RETURN_DELIMS)) + { + if (ap->flags & ARGCV_SQUEEZE_DELIMS) + while (i < len && isdelim (command[i], delim)) + i++; + else if (i < len) + i++; + + ap->save = i; + continue; + } + + + ap->end = i; + ap->save = ap->finish_pos = i + 1; + + /* If we have a token, and it starts with a comment character, skip + to the newline and restart the token search. */ + if (ap->save <= len) + { + if (strchr (comment, command[ap->start]) != NULL) + { + ap->finish_pos = ap->start; + i = ap->save; + while (i < len && command[i] != '\n') + i++; + + ap->save = i; + continue; + } + } + break; + } + return ap->save; +} + +static char quote_transtab[] = "\\\\a\ab\bf\fn\nr\rt\tv\v"; + +int +argcv_unquote_char (int c) +{ + char *p; + + for (p = quote_transtab; *p; p += 2) + { + if (*p == c) + return p[1]; + } + return c; +} + +int +argcv_quote_char (int c) +{ + char *p; + + for (p = quote_transtab + sizeof(quote_transtab) - 2; + p > quote_transtab; p -= 2) + { + if (*p == c) + return p[-1]; + } + return -1; +} + +#define to_num(c) \ + (isdigit(c) ? c - '0' : (isxdigit(c) ? toupper(c) - 'A' + 10 : 255 )) + +static int +xtonum (int *pval, const char *src, int base, int cnt) +{ + int i, val; + + for (i = 0, val = 0; i < cnt; i++, src++) + { + int n = *(unsigned char*)src; + if (n > 127 || (n = to_num(n)) >= base) + break; + val = val*base + n; + } + *pval = val; + return i; +} + +size_t +argcv_quoted_length (const char *str, int *quote) +{ + size_t len = 0; + + *quote = 0; + for (; *str; str++) + { + if (*str == ' ') + { + len++; + *quote = 1; + } + else if (*str == '"') + { + len += 2; + *quote = 1; + } + else if (*str != '\t' && *str != '\\' && isprint (*str)) + len++; + else + { + switch (argcv_quoting_style) + { + case argcv_quoting_octal: + if (argcv_quote_char (*str) != -1) + len += 2; + else + len += 4; + break; + + case argcv_quoting_hex: + len += 3; + break; + } + } + } + return len; +} + +void +argcv_unquote_copy (char *dst, const char *src, size_t n) +{ + int i = 0; + int c; + int expect_delim = 0; + + while (i < n) + { + switch (src[i]) + { + case '\'': + case '"': + if (!expect_delim) + { + const char *p; + + for (p = src+i+1; *p && *p != src[i]; p++) + if (*p == '\\') + p++; + if (*p) + expect_delim = src[i++]; + else + *dst++ = src[i++]; + } + else if (expect_delim == src[i]) + ++i; + else + *dst++ = src[i++]; + break; + + case '\\': + ++i; + if (src[i] == 'x' || src[i] == 'X') + { + if (n - i < 2) + { + *dst++ = '\\'; + *dst++ = src[i++]; + } + else + { + int off = xtonum(&c, src + i + 1, 16, 2); + if (off == 0) + { + *dst++ = '\\'; + *dst++ = src[i++]; + } + else + { + *dst++ = c; + i += off + 1; + } + } + } + else if ((unsigned char)src[i] < 128 && isdigit (src[i])) + { + if (n - i < 1) + { + *dst++ = '\\'; + *dst++ = src[i++]; + } + else + { + int off = xtonum (&c, src+i, 8, 3); + if (off == 0) + { + *dst++ = '\\'; + *dst++ = src[i++]; + } + else + { + *dst++ = c; + i += off; + } + } + } + else + *dst++ = argcv_unquote_char (src[i++]); + break; + + default: + *dst++ = src[i++]; + } + } + *dst = 0; +} + +void +argcv_quote_copy (char *dst, const char *src) +{ + for (; *src; src++) + { + if (*src == '"') + { + *dst++ = '\\'; + *dst++ = *src; + } + else if (*src != '\t' && *src != '\\' && isprint(*src)) + *dst++ = *src; + else + { + char tmp[4]; + + switch (argcv_quoting_style) + { + case argcv_quoting_octal: + { + int c = argcv_quote_char (*src); + *dst++ = '\\'; + if (c != -1) + *dst++ = c; + else + { + snprintf (tmp, sizeof tmp, "%03o", *(unsigned char*)src); + memcpy (dst, tmp, 3); + dst += 3; + } + break; + } + + case argcv_quoting_hex: + snprintf (tmp, sizeof tmp, "%%%02X", *(unsigned char*)src); + memcpy (dst, tmp, 3); + dst += 3; + break; + } + } + } +} + +int +argcv_get_np (const char *command, int len, + const char *delim, const char *cmnt, + int flags, + int *pargc, char ***pargv, char **endp) +{ + int i = 0; + struct argcv_info info; + int argc; + char **argv; + + if (!delim) + delim = " "; + if (!cmnt) + cmnt = ""; + + init_argcv_info (&info, flags, len, command, delim, cmnt); + + /* Count number of arguments */ + argc = 0; + while (argcv_scan (&info) <= len) + argc++; + + argv = calloc ((argc + 1), sizeof (char *)); + if (argv == NULL) + return ENOMEM; + + i = 0; + info.save = 0; + for (i = 0; i < argc; i++) + { + int n; + int unquote; + + argcv_scan (&info); + + if (info.flags & ARGCV_QUOTE && !(info.flags & _ARGCV_WORD_SED_EXPR)) + { + if ((command[info.start] == '"' || command[info.end] == '\'') + && command[info.end] == command[info.start]) + { + if (info.start < info.end) + { + info.start++; + info.end--; + } + unquote = 0; + } + else + unquote = 1; + } + else + unquote = 0; + + n = info.end - info.start + 1; + argv[i] = calloc (n + 1, sizeof (char)); + if (argv[i] == NULL) + { + argcv_free (i, argv); + return ENOMEM; + } + if (unquote) + argcv_unquote_copy (argv[i], &command[info.start], n); + else + memcpy (argv[i], &command[info.start], n); + argv[i][n] = 0; + } + argv[i] = NULL; + + *pargc = argc; + *pargv = argv; + if (endp) + *endp = (char*) (command + info.finish_pos); + return 0; +} + +int +argcv_get_n (const char *command, int len, const char *delim, const char *cmnt, + int *pargc, char ***pargv) +{ + return argcv_get_np (command, len, delim, cmnt, ARGCV_DEFFLAGS, + pargc, pargv, NULL); +} + +int +argcv_get (const char *command, const char *delim, const char *cmnt, + int *argc, char ***argv) +{ + return argcv_get_np (command, strlen (command), delim, cmnt, + ARGCV_DEFFLAGS, + argc, argv, NULL); +} + + +/* + * frees all elements of an argv array + * argc is the number of elements + * argv is the array + */ +void +argcv_free (int argc, char **argv) +{ + if (argc) + { + while (--argc >= 0) + if (argv[argc]) + free (argv[argc]); + free (argv); + } +} + +void +argv_free (char **argv) +{ + int i; + + for (i = 0; argv[i]; i++) + free (argv[i]); + free (argv); +} + +/* Make a argv an make string separated by ' '. */ + +int +argcv_string (int argc, char **argv, char **pstring) +{ + size_t i, j, len; + char *buffer; + + /* No need. */ + if (pstring == NULL) + return EINVAL; + + buffer = malloc (1); + if (buffer == NULL) + return ENOMEM; + *buffer = '\0'; + + for (len = i = j = 0; i < argc; i++) + { + int quote; + int toklen; + + toklen = argcv_quoted_length (argv[i], "e); + + len += toklen + 2; + if (quote) + len += 2; + + buffer = realloc (buffer, len); + if (buffer == NULL) + return ENOMEM; + + if (i != 0) + buffer[j++] = ' '; + if (quote) + buffer[j++] = '"'; + argcv_quote_copy (buffer + j, argv[i]); + j += toklen; + if (quote) + buffer[j++] = '"'; + } + + for (; j > 0 && isspace (buffer[j-1]); j--) + ; + buffer[j] = 0; + if (pstring) + *pstring = buffer; + return 0; +} + +void +argcv_remove (int *pargc, char ***pargv, + int (*sel) (const char *, void *), void *data) +{ + int i, j; + int argc = *pargc; + char **argv = *pargv; + int cnt = 0; + + for (i = j = 0; i < argc; i++) + { + if (sel (argv[i], data)) + { + free (argv[i]); + cnt++; + } + else + { + if (i != j) + argv[j] = argv[i]; + j++; + } + } + if (i != j) + argv[j] = NULL; + argc -= cnt; + + *pargc = argc; + *pargv = argv; +} + + @@ -0,0 +1,79 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2005, 2007, + 2008, 2009 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA */ + +#ifndef _ARGCV_H +#define _ARGCV_H 1 + +#include <stdio.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + + /* Treat whitespace as delimiters */ +#define ARGCV_WS 0x01 + /* Handle quotes and escape directives */ +#define ARGCV_QUOTE 0x02 + /* replace each input sequence of repeated delimiters into a single + delimiter */ +#define ARGCV_SQUEEZE_DELIMS 0x04 + /* Return delimiters */ +#define ARGCV_RETURN_DELIMS 0x08 + /* Treat sed expressions as words */ +#define ARGCV_SED_EXPR 0x10 + +#define ARGCV_DEFFLAGS \ + (ARGCV_WS | ARGCV_QUOTE | ARGCV_SQUEEZE_DELIMS | ARGCV_RETURN_DELIMS) + +enum argcv_quoting_style { + argcv_quoting_octal, + argcv_quoting_hex +}; + +extern enum argcv_quoting_style argcv_quoting_style; + +extern int argcv_get (const char *command, const char *delim, + const char *cmnt, + int *argc, char ***argv); +extern int argcv_get_n (const char *command, int len, + const char *delim, const char *cmnt, + int *argc, char ***argv); +extern int argcv_get_np (const char *command, int len, + const char *delim, const char *cmnt, + int flags, + int *pargc, char ***pargv, char **endp); + +extern int argcv_string (int argc, char **argv, char **string); +extern void argcv_free (int argc, char **argv); +extern void argv_free (char **argv); + +extern int argcv_unquote_char (int c); +extern int argcv_quote_char (int c); +extern size_t argcv_quoted_length (const char *str, int *quote); +extern void argcv_unquote_copy (char *dst, const char *src, size_t n); +extern void argcv_quote_copy (char *dst, const char *src); +extern void argcv_remove (int *pargc, char ***pargv, + int (*sel) (const char *, void *), void *); + +#ifdef __cplusplus +} +#endif + +#endif /* _ARGCV_H */ diff --git a/gconf-format.c b/gconf-format.c new file mode 100644 index 0000000..ea8a808 --- /dev/null +++ b/gconf-format.c @@ -0,0 +1,200 @@ +/* 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 <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#if ENABLE_NLS +# include "gettext.h" +#else +# define gettext(s) s +#endif + +#define _(s) gettext (s) +#define N_(s) s + +const char * +gconf_data_type_string (enum gconf_data_type type) +{ + switch (type) + { + case gconf_type_void: + return "void"; + + case gconf_type_string: + return "string"; + + case gconf_type_short: + case gconf_type_ushort: + case gconf_type_int: + case gconf_type_uint: + case gconf_type_long: + case gconf_type_ulong: + case gconf_type_size: +/* case gconf_type_off:*/ + case gconf_type_uintmax: + case gconf_type_intmax: + return "number"; + + case gconf_type_time: + return "time"; + + case gconf_type_bool: + return "boolean"; + + case gconf_type_ipv4: + return "IPv4"; + + case gconf_type_cidr: + return "CIDR"; + + case gconf_type_host: + return "hostname"; + + case gconf_type_sockaddr: + return "sock-addr"; + + case gconf_type_section: + return "section"; + } + return "UNKNOWN?"; +} + +static void +format_level (FILE *stream, unsigned level) +{ + while (level--) + fprintf (stream, " "); +} + +void +gconf_format_docstring (FILE *stream, const char *docstring, unsigned level) +{ + size_t len = strlen (docstring); + int width = 78 - level * 2; + + if (width < 0) + { + width = 78; + level = 0; + } + + while (len) + { + size_t seglen; + const char *p; + + for (seglen = 0, p = docstring; p < docstring + width && *p; p++) + { + if (*p == '\n') + { + seglen = p - docstring; + break; + } + if (isspace (*p)) + seglen = p - docstring; + } + if (seglen == 0 || *p == 0) + seglen = p - docstring; + + format_level (stream, level); + fprintf (stream, "# "); + fwrite (docstring, seglen, 1, stream); + fputc ('\n', stream); + len -= seglen; + docstring += seglen; + if (*docstring == '\n') + { + docstring++; + len--; + } + else + while (*docstring && isspace (*docstring)) + { + docstring++; + len--; + } + } +} + +void +gconf_format_simple_statement (FILE *stream, struct gconf_keyword *kwp, + unsigned level) +{ + const char *argstr; + + if (kwp->docstring) + gconf_format_docstring (stream, kwp->docstring, level); + format_level (stream, level); + + if (kwp->argname) + argstr = kwp->argname; + else + argstr = N_("arg"); + + if (strchr ("<[", argstr[0])) + fprintf (stream, "%s %s;\n", kwp->ident, gettext (argstr)); + else if (strchr (argstr, ':')) + fprintf (stream, "%s <%s>;\n", kwp->ident, gettext (argstr)); + else + { + fprintf (stream, "%s <%s: ", kwp->ident, gettext (argstr)); + if (GCONF_IS_LIST (kwp->type)) + fprintf (stream, "list of %s", + gettext (gconf_data_type_string (GCONF_TYPE (kwp->type)))); + else + fprintf (stream, "%s", gettext (gconf_data_type_string (kwp->type))); + fprintf (stream, ">;\n"); + } +} + +void +gconf_format_block_statement (FILE *stream, struct gconf_keyword *kwp, + unsigned level) +{ + if (kwp->docstring) + gconf_format_docstring (stream, kwp->docstring, level); + format_level (stream, level); + fprintf (stream, "%s", kwp->ident); + if (kwp->argname) + fprintf (stream, " <%s>", gettext (kwp->argname)); + fprintf (stream, " {\n"); + gconf_format_statement_array (stream, kwp->kwd, 0, level + 1); + format_level (stream, level); + fprintf (stream, "}\n"); +} + +void +gconf_format_statement_array (FILE *stream, struct gconf_keyword *kwp, + unsigned n, + unsigned level) +{ + for (; kwp->ident; kwp++, n++) + { + if (n) + fputc ('\n', stream); + if (kwp->type == gconf_type_section) + gconf_format_block_statement (stream, kwp, level); + else + gconf_format_simple_statement (stream, kwp, level); + } +} diff --git a/gconf-gram.y b/gconf-gram.y new file mode 100644 index 0000000..ed685d0 --- /dev/null +++ b/gconf-gram.y @@ -0,0 +1,819 @@ +%{ +/* 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 <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <xalloc.h> +#include <inttypes.h> + +#if ENABLE_NLS +# include "gettext.h" +# define _(msgid) gettext (msgid) +#else +# define _(msgid) msgid +#endif + +typedef union +{ + struct sockaddr s; + struct sockaddr_in s_in; + struct sockaddr_un s_un; +} sockaddr_union_t; + +static struct gconf_keyword config_keywords; +static struct gconf_keyword *cursect; +static gl_list_t sections; +int gconf_error_count; + +int gconf_default_port = 0; + +static void *target_ptr(struct gconf_keyword *kwp); +static void stmt_begin(struct gconf_keyword *kwp, gconf_value_t tag); +static void stmt_end(struct gconf_keyword *kwp); +static struct gconf_keyword *find_keyword(const char *ident); + +static void process_ident(struct gconf_keyword *kwp, gconf_value_t *value); +static gl_list_t simple_list_create (bool dispose); +%} + +%union { + char *string; + gconf_value_t value; + gl_list_t list; + struct gconf_keyword *kw; +} + +%token <string> IDENT STRING QSTRING MSTRING +%type <string> string slist +%type <list> slist0 +%type <value> value tag vallist +%type <list> values list vlist +%type <kw> ident + +%% + +input : stmtlist + ; + +stmtlist: stmt + | stmtlist stmt + ; + +stmt : simple + | block + ; + +simple : ident vallist ';' + { + process_ident($1, &$2); + } + ; + +block : ident tag { stmt_begin($<kw>1, $<value>2); } '{' stmtlist '}' opt_sc + { + stmt_end($1); + } + ; + +ident : IDENT + { + $$ = find_keyword($1); + if (!$$) + gconf_error(&gconf_current_locus, 0, _("Unknown keyword")); + } + ; + +tag : /* empty */ + { + $$.type = GCONF_TYPE_STRING; + $$.v.string = NULL; + } + | value + ; + +vallist : vlist + { + size_t n; + + if ((n = gl_list_size ($1)) == 1) + { + $$ = *(gconf_value_t *)gl_list_get_at ($1, 0); + } + else + { + size_t i; + + $$.type = GCONF_TYPE_ARRAY; + $$.v.arg.c = n; + $$.v.arg.v = xcalloc (n, sizeof ($$.v.arg.v[0])); + for (i = 0; i < n; i++) + $$.v.arg.v[i] = *(gconf_value_t *)gl_list_get_at ($1, i); + } + gl_list_free ($1); + } + ; + +vlist : value + { + $$ = simple_list_create (false); + gl_list_add_last ($$, gconf_value_dup (&$1)); + } + | vlist value + { + gl_list_add_last ($1, gconf_value_dup (&$2)); + } + ; + +value : string + { + $$.type = GCONF_TYPE_STRING; + $$.v.string = $1; + } + | list + { + $$.type = GCONF_TYPE_LIST; + $$.v.list = $1; + } + | MSTRING + { + $$.type = GCONF_TYPE_STRING; + $$.v.string = $1; + } + ; + +string : STRING + | IDENT + | slist + ; + +slist : slist0 + { + const void *p; + gl_list_iterator_t itr = gl_list_iterator ($1); + + gconf_line_begin (); + while (gl_list_iterator_next (&itr, &p, NULL)) + gconf_line_add (p, strlen (p)); + $$ = gconf_line_finish (); + gl_list_iterator_free (&itr); + gl_list_free ($1); + } + ; + +slist0 : QSTRING + { + $$ = simple_list_create (false); + gl_list_add_last ($$, $1); + } + | slist0 QSTRING + { + gl_list_add_last ($1, $2); + $$ = $1; + } + ; + +list : '(' ')' + { + $$ = NULL; + } + | '(' values ')' + { + $$ = $2; + } + | '(' values ',' ')' + { + $$ = $2; + } + ; + +values : value + { + $$ = simple_list_create (true); + gl_list_add_last ($$, gconf_value_dup (&$1)); + } + | values ',' value + { + gl_list_add_last ($1, gconf_value_dup (&$3)); + $$ = $1; + } + ; + +opt_sc : /* empty */ + | ';' + ; + +%% + +int +yyerror(char *s) +{ + gconf_error (&gconf_current_locus, 0, "%s", s); + return 0; +} + +static void +listel_dispose(const void *el) +{ + free((void*)el); +} + +static gl_list_t +simple_list_create (bool dispose) +{ + return gl_list_create_empty(&gl_linked_list_implementation, + NULL, + NULL, + dispose ? listel_dispose : NULL, + false); +} + + +void +gconf_warning(gconf_locus_t *locus, int errcode, const char *fmt, ...) +{ + va_list ap; + char *buf = NULL; + + va_start (ap, fmt); + vasprintf (&buf, fmt, ap); + va_end (ap); + gconf_print_diag (locus, 0, errcode, buf); + free(buf); +} + +void +gconf_error (gconf_locus_t *locus, int errcode, const char *fmt, ...) +{ + va_list ap; + char *buf = NULL; + + va_start (ap, fmt); + vasprintf (&buf, fmt, ap);< |