diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-04-20 14:48:39 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-04-20 14:48:39 +0300 |
commit | 0f081a2643ba0a7f7a5dcfb6a5977d9da1d2b6db (patch) | |
tree | b62e9404cd5dfdfa471ec1202e183f9ca92187e5 /src | |
parent | 0983c9ab7a6ea5b3592a297e029a935cc0e4bebc (diff) | |
download | grecs-0f081a2643ba0a7f7a5dcfb6a5977d9da1d2b6db.tar.gz grecs-0f081a2643ba0a7f7a5dcfb6a5977d9da1d2b6db.tar.bz2 |
Diverge from Wydawca gconf/ subdirectory into a separate project
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 35 | ||||
-rw-r--r-- | src/format.c | 200 | ||||
-rw-r--r-- | src/grecs-gram.y | 891 | ||||
-rw-r--r-- | src/grecs-lex.l | 477 | ||||
-rw-r--r-- | src/grecs.h | 163 | ||||
-rw-r--r-- | src/pp-setup | 106 | ||||
-rw-r--r-- | src/preproc.c | 728 | ||||
-rw-r--r-- | src/text.c | 73 | ||||
-rw-r--r-- | src/wordsplit.c | 568 | ||||
-rw-r--r-- | src/wordsplit.h | 88 |
10 files changed, 3329 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..df98842 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,35 @@ +# This file is part of grecs - Gray's Extensible Configuration System +# Copyright (C) 2007, 2009 Sergey Poznyakoff +# +# Grex 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. +# +# Grex 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 Grex. If not, see <http://www.gnu.org/licenses/>. + +noinst_LIBRARIES=libgrecs.a +libgrecs_a_SOURCES = \ + format.c\ + grecs-gram.y\ + grecs-lex.l\ + preproc.c\ + text.c\ + grecs.h\ + wordsplit.c\ + wordsplit.h + +EXTRA_DIST=gram.h + +INCLUDES = -I$(top_srcdir)/gnu -I../gnu +AM_YFLAGS = -dtv +AM_LFLAGS = -dvp + +incdir=$(pkgdatadir)/$(VERSION)/include +inc_DATA = $(PP_SETUP_FILE) diff --git a/src/format.c b/src/format.c new file mode 100644 index 0000000..165c688 --- /dev/null +++ b/src/format.c @@ -0,0 +1,200 @@ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff + + Grecs 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. + + Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <grecs.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 * +grecs_data_type_string (enum grecs_data_type type) +{ + switch (type) + { + case grecs_type_void: + return "void"; + + case grecs_type_string: + return "string"; + + case grecs_type_short: + case grecs_type_ushort: + case grecs_type_int: + case grecs_type_uint: + case grecs_type_long: + case grecs_type_ulong: + case grecs_type_size: +/* case grecs_type_off:*/ + case grecs_type_uintmax: + case grecs_type_intmax: + return "number"; + + case grecs_type_time: + return "time"; + + case grecs_type_bool: + return "boolean"; + + case grecs_type_ipv4: + return "IPv4"; + + case grecs_type_cidr: + return "CIDR"; + + case grecs_type_host: + return "hostname"; + + case grecs_type_sockaddr: + return "sock-addr"; + + case grecs_type_section: + return "section"; + } + return "UNKNOWN?"; +} + +static void +format_level (FILE *stream, unsigned level) +{ + while (level--) + fprintf (stream, " "); +} + +void +grecs_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 +grecs_format_simple_statement (FILE *stream, struct grecs_keyword *kwp, + unsigned level) +{ + const char *argstr; + + if (kwp->docstring) + grecs_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 (grecs_data_type_string (GCONF_TYPE (kwp->type)))); + else + fprintf (stream, "%s", gettext (grecs_data_type_string (kwp->type))); + fprintf (stream, ">;\n"); + } +} + +void +grecs_format_block_statement (FILE *stream, struct grecs_keyword *kwp, + unsigned level) +{ + if (kwp->docstring) + grecs_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"); + grecs_format_statement_array (stream, kwp->kwd, 0, level + 1); + format_level (stream, level); + fprintf (stream, "}\n"); +} + +void +grecs_format_statement_array (FILE *stream, struct grecs_keyword *kwp, + unsigned n, + unsigned level) +{ + for (; kwp->ident; kwp++, n++) + { + if (n) + fputc ('\n', stream); + if (kwp->type == grecs_type_section) + grecs_format_block_statement (stream, kwp, level); + else + grecs_format_simple_statement (stream, kwp, level); + } +} diff --git a/src/grecs-gram.y b/src/grecs-gram.y new file mode 100644 index 0000000..991f315 --- /dev/null +++ b/src/grecs-gram.y @@ -0,0 +1,891 @@ +%{ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff + + Grecs 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. + + Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <grecs.h> +#include <grecs-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 grecs_keyword config_keywords; +static struct grecs_keyword *cursect; +static gl_list_t sections; +int grecs_error_count; + +int grecs_default_port = 0; + +static void *target_ptr(struct grecs_keyword *kwp); +static void stmt_begin(struct grecs_keyword *kwp, grecs_value_t tag); +static void stmt_end(struct grecs_keyword *kwp); +static struct grecs_keyword *find_keyword(const char *ident); + +static void process_ident(struct grecs_keyword *kwp, grecs_value_t *value); +static gl_list_t simple_list_create (bool dispose); +%} + +%union { + char *string; + grecs_value_t value; + gl_list_t list; + struct grecs_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 (!$$) + grecs_error(&grecs_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) + { + $$ = *(grecs_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] = *(grecs_value_t *)gl_list_get_at ($1, i); + } + gl_list_free ($1); + } + ; + +vlist : value + { + $$ = simple_list_create (false); + gl_list_add_last ($$, grecs_value_dup (&$1)); + } + | vlist value + { + gl_list_add_last ($1, grecs_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); + + grecs_line_begin (); + while (gl_list_iterator_next (&itr, &p, NULL)) + grecs_line_add (p, strlen (p)); + $$ = grecs_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 ($$, grecs_value_dup (&$1)); + } + | values ',' value + { + gl_list_add_last ($1, grecs_value_dup (&$3)); + $$ = $1; + } + ; + +opt_sc : /* empty */ + | ';' + ; + +%% + +int +yyerror(char *s) +{ + grecs_error (&grecs_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 +grecs_warning(grecs_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); + grecs_print_diag (locus, 0, errcode, buf); + free(buf); +} + +void +grecs_error (grecs_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); + grecs_print_diag (locus, 1, errcode, buf); + free (buf); + grecs_error_count++; +} + +void +grecs_set_keywords (struct grecs_keyword *kwd) +{ + config_keywords.kwd = kwd; +} + +int +grecs_parse (const char *name) +{ + int rc; + if (grecs_lex_begin (name)) + return 1; + cursect = &config_keywords; + if (sections) + { + gl_list_free (sections); + sections = NULL; + } + rc = yyparse (); + grecs_lex_end (); + if (grecs_error_count) + rc = 1; + return rc; +} + +void +grecs_gram_trace (int n) +{ + yydebug = n; +} + + + +static void * +target_ptr (struct grecs_keyword *kwp) +{ + char *base; + + if (kwp->varptr) + base = (char*) kwp->varptr + kwp->offset; + else if (cursect && cursect->callback_data) + base = (char*) cursect->callback_data + kwp->offset; + else + base = NULL; + return base; +} + +static int +fake_callback (enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + return 0; +} + +static struct grecs_keyword fake = { + "*", + NULL, + NULL, + grecs_type_void, + NULL, + 0, + fake_callback, + NULL, + &fake +}; + +static void +stmt_begin (struct grecs_keyword *kwp, grecs_value_t tag) +{ + void *target; + + if (!sections) + sections = simple_list_create (false); + gl_list_add_first (sections, cursect); + if (kwp) + { + target = target_ptr (kwp); + cursect = kwp; + if (kwp->callback && kwp->callback (grecs_callback_section_begin, + &grecs_current_locus, /* FIXME */ + target, + &tag, + &kwp->callback_data)) + cursect = &fake; + } + else + /* install "ignore-all" section */ + cursect = kwp; +} + +static void +stmt_end (struct grecs_keyword *kwp) +{ + grecs_callback_fn callback = NULL; + void *dataptr = NULL; + + if (cursect && cursect->callback) + { + callback = cursect->callback; + dataptr = &cursect->callback_data; + } + + if (gl_list_size (sections) == 0) + abort (); + cursect = (struct grecs_keyword *) gl_list_get_at (sections, 0); + gl_list_remove_at (sections, 0); + if (callback) + callback (grecs_callback_section_end, + &grecs_current_locus, /* FIXME */ + kwp ? target_ptr(kwp) : NULL, + NULL, + dataptr); + +} + +static struct grecs_keyword * +find_keyword (const char *ident) +{ + struct grecs_keyword *kwp; + + if (cursect && cursect != &fake) + { + for (kwp = cursect->kwd; kwp->ident; kwp++) + if (strcmp (kwp->ident, ident) == 0) + return kwp; + } + else + { + return &fake; + } + return NULL; +} + +static int +string_to_signed (intmax_t *sval, const char *string, + intmax_t minval, intmax_t maxval) +{ + intmax_t t; + char *p; + + t = strtoimax (string, &p, 0); + if (*p) + { + grecs_error (&grecs_current_locus, 0, _("cannot convert `%s' to number"), + string); + return 1; + } + else if (t < minval || t > maxval) + { + grecs_error (&grecs_current_locus, 0, + _("%s: value out of allowed range %"PRIiMAX"..%"PRIiMAX), + string, minval, maxval); + return 1; + } + *sval = t; + return 0; +} + +static int +string_to_unsigned (uintmax_t *sval, const char *string, uintmax_t maxval, + grecs_locus_t *loc) +{ + uintmax_t t; + char *p; + + t = strtoumax (string, &p, 0); + if (*p) + { + grecs_error (loc, 0, _("cannot convert `%s' to number"), + string); + return 1; + } + else if (t > maxval) + { + grecs_error (loc, 0, + _("%s: value out of allowed range 0..%"PRIuMAX), + string, maxval); + return 1; + } + *sval = t; + return 0; +} + +static int +string_to_bool (const char *string, int *pval) +{ + if (strcmp (string, "yes") == 0 + || strcmp (string, "true") == 0 + || strcmp (string, "t") == 0 + || strcmp (string, "1") == 0) + *pval = 1; + else if (strcmp (string, "no") == 0 + || strcmp (string, "false") == 0 + || strcmp (string, "nil") == 0 + || strcmp (string, "0") == 0) + *pval = 0; + else + { + grecs_error (&grecs_current_locus, 0, + _("%s: not a valid boolean value"), + string); + return 1; + } + return 0; +} + +static int +string_to_host (struct in_addr *in, const char *string) +{ + if (inet_aton (string, in) == 0) + { + struct hostent *hp; + + hp = gethostbyname (string); + if (hp == NULL) + return 1; + memcpy (in, hp->h_addr, sizeof (struct in_addr)); + } + return 0; +} + +static int +string_to_sockaddr (struct grecs_sockaddr *sp, const char *string) +{ + if (string[0] == '/') + { + struct sockaddr_un s_un; + if (strlen (string) >= sizeof (s_un.sun_path)) + { + grecs_error (&grecs_current_locus, 0, + _("%s: UNIX socket name too long"), + string); + return 1; + } + s_un.sun_family = AF_UNIX; + strcpy (s_un.sun_path, string); + sp->len = sizeof (s_un); + sp->sa = xmalloc (sp->len); + memcpy (sp->sa, &s_un, sp->len); + } + else + { + char *p = strchr (string, ':'); + size_t len; + struct sockaddr_in sa; + + sa.sin_family = AF_INET; + if (p) + len = p - string; + else + len = strlen (string); + + if (len == 0) + sa.sin_addr.s_addr = INADDR_ANY; + else + { + char *host = xmalloc (len + 1); + memcpy (host, string, len); + host[len] = 0; + + if (string_to_host (&sa.sin_addr, host)) + { + grecs_error (&grecs_current_locus, 0, + _("%s: not a valid IP address or hostname"), + host); + free (host); + return 1; + } + free (host); + } + + if (p) + { + struct servent *serv; + + p++; + serv = getservbyname (p, "tcp"); + if (serv != NULL) + sa.sin_port = serv->s_port; + else + { + unsigned long l; + char *q; + + /* Not in services, maybe a number? */ + l = strtoul (p, &q, 0); + + if (*q || l > USHRT_MAX) + { + grecs_error (&grecs_current_locus, 0, + _("%s: not a valid port number"), p); + return 1; + } + sa.sin_port = htons (l); + } + } + else if (grecs_default_port) + sa.sin_port = grecs_default_port; + else + { + grecs_error (&grecs_current_locus, 0, _("missing port number")); + return 1; + } + sp->len = sizeof (sa); + sp->sa = xmalloc (sp->len); + memcpy (sp->sa, &sa, sp->len); + } + return 0; +} + +int +grecs_string_convert (void *target, enum grecs_data_type type, + const char *string) +{ + uintmax_t uval; + intmax_t sval; + + switch (type) + { + case grecs_type_void: + abort (); + + case grecs_type_string: + *(const char**)target = string; + break; + + case grecs_type_short: + if (string_to_signed (&sval, string, SHRT_MIN, SHRT_MAX) == 0) + *(short*)target = sval; + else + return 1; + break; + + case grecs_type_ushort: + if (string_to_unsigned (&uval, string, USHRT_MAX, &grecs_current_locus) == 0) + *(unsigned short*)target = uval; + else + return 1; + break; + + case grecs_type_bool: + return string_to_bool (string, (int*)target); + + case grecs_type_int: + if (string_to_signed (&sval, string, INT_MIN, INT_MAX) == 0) + *(int*)target = sval; + else + return 1; + break; + + case grecs_type_uint: + if (string_to_unsigned (&uval, string, UINT_MAX, &grecs_current_locus) == 0) + *(unsigned int*)target = uval; + else + return 1; + break; + + case grecs_type_long: + if (string_to_signed (&sval, string, LONG_MIN, LONG_MAX) == 0) + *(long*)target = sval; + else + return 1; + break; + + case grecs_type_ulong: + if (string_to_unsigned (&uval, string, ULONG_MAX, &grecs_current_locus) == 0) + *(unsigned long*)target = uval; + else + return 1; + break; + + case grecs_type_size: + if (string_to_unsigned (&uval, string, SIZE_MAX, &grecs_current_locus) == 0) + *(size_t*)target = uval; + else + return 1; + break; + + case grecs_type_intmax: + return string_to_signed ((intmax_t*)target, string, + INTMAX_MIN, INTMAX_MAX); + + case grecs_type_uintmax: + return string_to_unsigned ((uintmax_t*)target, string, UINTMAX_MAX, + &grecs_current_locus); + + case grecs_type_time: + /*FIXME: Use getdate */ + if (string_to_unsigned (&uval, string, (time_t)-1, &grecs_current_locus) == 0) + *(time_t*)target = uval; + else + return 1; + break; + + case grecs_type_ipv4: + if (inet_aton (string, (struct in_addr *)target)) + { + grecs_error (&grecs_current_locus, 0, _("%s: not a valid IP address"), string); + return 1; + } + break; + + case grecs_type_host: + if (string_to_host ((struct in_addr *)target, string)) + { + grecs_error (&grecs_current_locus, 0, + _("%s: not a valid IP address or hostname"), string); + return 1; + } + break; + + case grecs_type_sockaddr: + return string_to_sockaddr ((struct grecs_sockaddr *)target, string); + + /* FIXME: */ + case grecs_type_cidr: + grecs_error (&grecs_current_locus, 0, _("INTERNAL ERROR at %s:%d"), __FILE__, + __LINE__); + abort(); + + case grecs_type_section: + grecs_error (&grecs_current_locus, 0, + _("Invalid use of block statement")); + return 1; + } + return 0; +} + +struct grecs_prop +{ + size_t size; + gl_listelement_equals_fn eqfn; +}; + +static bool +string_eq (const void *elt1, const void *elt2) +{ + return strcmp ((const char *)elt1, (const char *)elt2) == 0; +} + +#define __grecs_name_cat__(a,b) a ## b +#define NUMEQ(type) __grecs_name_cat__(type,_eq) +#define __DECL_NUMEQ(type,ctype) \ + static bool \ + NUMEQ(type) (const void *elt1, const void *elt2) \ + { \ + return memcmp (elt1, elt2, sizeof (ctype)) == 0; \ + } +#define DECL_NUMEQ(type) __DECL_NUMEQ(type,type) + +DECL_NUMEQ(short) +DECL_NUMEQ(int) +DECL_NUMEQ(long) +DECL_NUMEQ(size_t) +DECL_NUMEQ(uintmax_t) +DECL_NUMEQ(intmax_t) +DECL_NUMEQ(time_t) +__DECL_NUMEQ(in_addr, struct in_addr) +__DECL_NUMEQ(grecs_sockaddr, struct grecs_sockaddr) + +struct grecs_prop grecs_prop_tab[] = { + { 0, NULL }, /* grecs_type_void */ + { sizeof (char*), string_eq }, /* grecs_type_string */ + { sizeof (short), NUMEQ (short) }, /* grecs_type_short */ + { sizeof (unsigned short), NUMEQ (short) }, /* grecs_type_ushort */ + { sizeof (int), NUMEQ (int) }, /* grecs_type_int */ + { sizeof (unsigned int), NUMEQ (int) }, /* grecs_type_uint */ + { sizeof (long), NUMEQ (long) }, /* grecs_type_long */ + { sizeof (unsigned long), NUMEQ (long) }, /* grecs_type_ulong */ + { sizeof (size_t), NUMEQ (size_t) }, /* grecs_type_size */ + /* grecs_type_off,*/ + { sizeof (uintmax_t), NUMEQ (uintmax_t) }, /* grecs_type_uintmax */ + { sizeof (intmax_t), NUMEQ (intmax_t) }, /* grecs_type_intmax */ + { sizeof (time_t), NUMEQ (time_t) }, /* grecs_type_time */ + { sizeof (int), NUMEQ (int) }, /* grecs_type_bool */ + { sizeof (struct in_addr), NUMEQ (in_addr) }, /* grecs_type_ipv4 */ + { 0, NULL }, /* FIXME: grecs_type_cidr */ + { sizeof (struct in_addr), NUMEQ (in_addr) }, /* grecs_type_host */ + { sizeof (struct grecs_sockaddr), NUMEQ (grecs_sockaddr) }, + /* grecs_type_sockaddr */ + { 0, NULL } /* grecs_type_section */ +}; +#define grecs_prop_count \ + (sizeof (grecs_prop_tab) / sizeof (grecs_prop_tab[0])) + +static void +process_ident (struct grecs_keyword *kwp, grecs_value_t *value) +{ + void *target; + + if (!kwp) + return; + + target = target_ptr (kwp); + + if (kwp->callback) + kwp->callback (grecs_callback_set_value, + &grecs_current_locus, /* FIXME */ + target, + value, + &kwp->callback_data); + else if (value->type == GCONF_TYPE_ARRAY) + { + grecs_error (&grecs_current_locus, 0, + _("too many arguments to `%s'; missing semicolon?"), + kwp->ident); + return; + } + else if (value->type == GCONF_TYPE_LIST) + { + if (GCONF_IS_LIST (kwp->type)) + { + gl_list_iterator_t itr = gl_list_iterator (value->v.list); + enum grecs_data_type type = GCONF_TYPE (kwp->type); + int num = 1; + const void *p; + gl_list_t list; + size_t size; + + if (type >= grecs_prop_count + || (size = grecs_prop_tab[type].size) == 0) + { + grecs_error (&grecs_current_locus, 0, + _("INTERNAL ERROR at %s:%d: " + "unhandled data type %d"), + __FILE__, __LINE__, type); + abort (); + } + + list = gl_list_create_empty (&gl_linked_list_implementation, + grecs_prop_tab[type].eqfn, + NULL, + listel_dispose, + false); + + while (gl_list_iterator_next (&itr, &p, NULL)) + { + const grecs_value_t *vp = p; + + if (vp->type != GCONF_TYPE_STRING) + grecs_error (&grecs_current_locus, 0, + _("%s: incompatible data type in list item #%d"), + kwp->ident, num); + else if (type == grecs_type_string) + gl_list_add_last (list, vp->v.string); + else + { + void *ptr = xmalloc (size); + if (grecs_string_convert (ptr, type, vp->v.string) == 0) + gl_list_add_last (list, ptr); + else + free (ptr); + } + } + gl_list_iterator_free (&itr); + *(gl_list_t*)target = list; + } + else + { + grecs_error (&grecs_current_locus, 0, + _("incompatible data type for `%s'"), + kwp->ident); + return; + } + } + else if (GCONF_IS_LIST (kwp->type)) + { + gl_list_t list; + enum grecs_data_type type = GCONF_TYPE (kwp->type); + size_t size; + void *ptr; + + if (type >= grecs_prop_count + || (size = grecs_prop_tab[type].size) == 0) + { + grecs_error (&grecs_current_locus, 0, + _("INTERNAL ERROR at %s:%d: unhandled data type %d"), + __FILE__, __LINE__, type); + abort(); + } + + list = gl_list_create_empty (&gl_linked_list_implementation, + grecs_prop_tab[type].eqfn, + NULL, + listel_dispose, + false); + if (type == grecs_type_string) + gl_list_add_last (list, value->v.string); + else + { + ptr = xmalloc (size); + if (grecs_string_convert (ptr, type, value->v.string)) + { + free (ptr); + gl_list_free (list); + return; + } + gl_list_add_last (list, ptr); + } + *(gl_list_t*)target = list; + } + else + grecs_string_convert (target, GCONF_TYPE (kwp->type), value->v.string); +} + diff --git a/src/grecs-lex.l b/src/grecs-lex.l new file mode 100644 index 0000000..4d7f9bb --- /dev/null +++ b/src/grecs-lex.l @@ -0,0 +1,477 @@ +/* grecs - Gray's Extensible Configuration System -*- c -*- */ +%{ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff + + Grecs 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. + + Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <grecs.h> +#include <grecs-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 <wordsplit.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_le |