aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-05-03 17:49:29 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-05-03 21:23:21 +0300
commit3d679b3df641f59fb81ca1651799f4e2965ed67e (patch)
tree5a614ee25cff44d015ee9e6f6920e2ba19379bba /src
parent24ec67c9f6375d34d88e79981ed8abbe15a78169 (diff)
downloadgrecs-3d679b3df641f59fb81ca1651799f4e2965ed67e.tar.gz
grecs-3d679b3df641f59fb81ca1651799f4e2965ed67e.tar.bz2
Switch to the two-layer model. Add testsuite.
The configuration file parser creates a syntax tree. This step does not require any knowledge about which keywords are allowed. The user can then either use that tree directly, or post-process it using parser tables. The latter approach is equivalent to previous versions of grecs.
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore4
-rw-r--r--src/Makefile.am3
-rw-r--r--src/diag.c73
-rw-r--r--src/format.c121
-rw-r--r--src/grecs-gram.y715
-rw-r--r--src/grecs.h86
-rw-r--r--src/lookup.c272
-rw-r--r--src/tree.c773
8 files changed, 1341 insertions, 706 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..7c38320
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,4 @@
+grecs-gram.c
+grecs-gram.h
+grecs-gram.output
+grecs-lex.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 759716b..0c2c444 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,20 +13,23 @@
#
# 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 = \
+ diag.c\
format.c\
grecs-gram.y\
grecs-lex.l\
list.c\
+ lookup.c\
mem.c\
preproc.c\
symtab.c\
text.c\
+ tree.c\
grecs.h\
wordsplit.c\
wordsplit.h
EXTRA_DIST=grecs-gram.h $(PP_SETUP_FILE)
diff --git a/src/diag.c b/src/diag.c
new file mode 100644
index 0000000..fcb8fd2
--- /dev/null
+++ b/src/diag.c
@@ -0,0 +1,73 @@
+/* grecs - Gray's Extensible Configuration System
+ Copyright (C) 2007-2011 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static void
+default_print_diag(grecs_locus_t *locus, int err, int errcode, const char *msg)
+{
+ if (locus)
+ fprintf(stderr, "%s:%d: ", locus->file, locus->line);
+ if (!err)
+ fprintf(stderr, "warning: ");
+ fprintf(stderr, "%s", msg);
+ if (errcode)
+ fprintf(stderr, ": %s", strerror(errno));
+ fputc('\n', stderr);
+}
+
+void (*grecs_print_diag_fun)(grecs_locus_t *, int, int, const char *msg) =
+ default_print_diag;
+
+void
+grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+ size_t size = 0;
+
+ va_start(ap, fmt);
+ if (grecs_vasprintf(&buf, &size, fmt, ap))
+ grecs_alloc_die();
+ va_end(ap);
+ grecs_print_diag_fun(locus, 0, errcode, buf);
+ free(buf);
+}
+
+void
+grecs_error(grecs_locus_t *locus, int errcode, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf = NULL;
+ size_t size = 0;
+
+ va_start(ap, fmt);
+ if (grecs_vasprintf(&buf, &size, fmt, ap))
+ grecs_alloc_die();
+ va_end(ap);
+ grecs_print_diag_fun(locus, 1, errcode, buf);
+ free(buf);
+ grecs_error_count++;
+}
+
+
diff --git a/src/format.c b/src/format.c
index fc6c8d6..11b405a 100644
--- a/src/format.c
+++ b/src/format.c
@@ -21,13 +21,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
const char *
-grecs_data_type_string (enum grecs_data_type type)
+grecs_data_type_string(enum grecs_data_type type)
{
switch (type) {
case grecs_type_void:
return "void";
case grecs_type_string:
@@ -65,20 +65,20 @@ grecs_data_type_string (enum grecs_data_type type)
return "section";
}
return "UNKNOWN?";
}
static void
-format_level(FILE *stream, unsigned level)
+format_level(unsigned level, FILE *stream)
{
while (level--)
fprintf(stream, " ");
}
void
-grecs_format_docstring(FILE *stream, const char *docstring, unsigned level)
+grecs_format_docstring(const char *docstring, unsigned level, FILE *stream)
{
size_t len = strlen(docstring);
int width = 78 - level * 2;
if (width < 0) {
width = 78;
@@ -98,13 +98,13 @@ grecs_format_docstring(FILE *stream, const char *docstring, unsigned level)
if (isspace(*p))
seglen = p - docstring;
}
if (seglen == 0 || *p == 0)
seglen = p - docstring;
- format_level(stream, level);
+ format_level(level, stream);
fprintf(stream, "# ");
fwrite(docstring, seglen, 1, stream);
fputc('\n', stream);
len -= seglen;
docstring += seglen;
if (*docstring == '\n') {
@@ -116,30 +116,30 @@ grecs_format_docstring(FILE *stream, const char *docstring, unsigned level)
len--;
}
}
}
void
-grecs_format_simple_statement(FILE *stream, struct grecs_keyword *kwp,
- unsigned level)
+grecs_format_simple_statement(struct grecs_keyword *kwp, unsigned level,
+ FILE *stream)
{
const char *argstr;
if (kwp->docstring)
- grecs_format_docstring(stream, kwp->docstring, level);
- format_level(stream, level);
+ grecs_format_docstring(kwp->docstring, level, stream);
+ format_level(level, stream);
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));
+ fprintf(stream, "%s <%s>;\n", kwp->ident, gettext(argstr));
else {
fprintf(stream, "%s <%s: ", kwp->ident, gettext(argstr));
if (GRECS_IS_LIST(kwp->type))
fprintf(stream, "list of %s",
gettext(grecs_data_type_string(
GRECS_TYPE (kwp->type))));
@@ -148,37 +148,120 @@ grecs_format_simple_statement(FILE *stream, struct grecs_keyword *kwp,
gettext(grecs_data_type_string(kwp->type)));
fprintf(stream, ">;\n");
}
}
void
-grecs_format_block_statement(FILE *stream, struct grecs_keyword *kwp,
- unsigned level)
+grecs_format_block_statement(struct grecs_keyword *kwp, unsigned level,
+ FILE *stream)
{
if (kwp->docstring)
- grecs_format_docstring(stream, kwp->docstring, level);
- format_level(stream, level);
+ grecs_format_docstring(kwp->docstring, level, stream);
+ format_level(level, stream);
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);
+ grecs_format_statement_array(kwp->kwd, 0, level + 1, stream);
+ format_level(level, stream);
fprintf(stream, "}\n");
}
void
-grecs_format_statement_array(FILE *stream, struct grecs_keyword *kwp,
+grecs_format_statement_array(struct grecs_keyword *kwp,
unsigned n,
- unsigned level)
+ unsigned level,
+ FILE *stream)
{
for (; kwp->ident; kwp++, n++) {
if (n)
fputc('\n', stream);
if (kwp->type == grecs_type_section)
- grecs_format_block_statement(stream, kwp, level);
+ grecs_format_block_statement(kwp, level, stream);
else
- grecs_format_simple_statement(stream, kwp, level);
+ grecs_format_simple_statement(kwp, level, stream);
}
}
+
+void
+grecs_format_locus(grecs_locus_t *locus, FILE *fp)
+{
+ fprintf(fp, "%s:%d:", locus->file, locus->line);
+}
+
+void
+grecs_format_node_ident(struct grecs_node *node, int delim, FILE *fp)
+{
+ if (node->up)
+ grecs_format_node_ident(node->up, delim, fp);
+ fputc(delim, fp);
+ fprintf(fp, "%s", node->ident);
+ if (node->type == grecs_node_block &&
+ !GRECS_VALUE_EMPTY_P(&node->value)) {
+ fputc('=', fp);
+ grecs_format_value(&node->value, fp);
+ }
+}
+
+void
+grecs_format_value(struct grecs_value *val, FILE *fp)
+{
+ int i;
+ struct grecs_list_entry *ep;
+
+ switch (val->type) {
+ case GRECS_TYPE_STRING:
+ fprintf(fp, "\"%s\"", val->v.string); /*FIXME: Quoting*/
+ break;
+
+ case GRECS_TYPE_LIST:
+ fputc('(', fp);
+ for (ep = val->v.list->head; ep; ep = ep->next) {
+ grecs_format_value(ep->data, fp);
+ if (ep->next) {
+ fputc(',', fp);
+ fputc(' ', fp);
+ }
+ }
+ fputc(')', fp);
+ break;
+
+ case GRECS_TYPE_ARRAY:
+ for (i = 0; i < val->v.arg.c; i++) {
+ if (i)
+ fputc(' ', fp);
+ grecs_format_value(&val->v.arg.v[i], fp);
+ }
+ }
+}
+
+void
+grecs_format_node(struct grecs_node *node, int flags, FILE *fp)
+{
+ int delim = flags & 0xff;
+
+ if (!delim)
+ delim = '.';
+ switch (node->type) {
+ case grecs_node_block:
+ for (node = node->down; node; node = node->next) {
+ grecs_format_node(node, flags, fp);
+ if (node->next)
+ fputc('\n', fp);
+ }
+ break;
+
+ case grecs_node_stmt:
+ if (flags & GRECS_NODE_FLAG_LOCUS) {
+ grecs_format_locus(&node->locus, fp);
+ fputc(' ', fp);
+ }
+ grecs_format_node_ident(node, delim, fp);
+ fputc(':', fp);
+ fputc(' ', fp);
+ grecs_format_value(&node->value, fp);
+ }
+}
+
+
diff --git a/src/grecs-gram.y b/src/grecs-gram.y
index f65e2dd..c2429a4 100644
--- a/src/grecs-gram.y
+++ b/src/grecs-gram.y
@@ -19,91 +19,76 @@
# include <config.h>
#endif
#include <grecs.h>
#include <grecs-gram.h>
#include <stdlib.h>
#include <stdarg.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 <string.h>
#include <errno.h>
-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;
-#define CURRENT_BASE ((char*)(cursect ? cursect->callback_data : NULL))
-static struct grecs_list *sections;
+static struct grecs_node *parse_tree;
int grecs_error_count;
int grecs_default_port = 0;
-static void *target_ptr(struct grecs_keyword *kwp, char *base);
-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 struct grecs_list *simple_list_create(int dispose);
%}
%union {
- char *string;
- grecs_value_t value;
- struct grecs_list *list;
- struct grecs_keyword *kw;
+ char *string;
+ grecs_value_t value;
+ struct grecs_list *list;
+ struct grecs_node *node;
+ struct { struct grecs_node *head, *tail; } node_list;
}
%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
+%type <node> stmt simple block
+%type <node_list> stmtlist
%%
input : stmtlist
+ {
+ parse_tree = $1.head;
+ }
;
stmtlist: stmt
+ {
+ $$.head = $$.tail = $1;
+ }
| stmtlist stmt
+ {
+ grecs_node_bind($1.tail, $2, 0);
+ }
;
stmt : simple
| block
;
-simple : ident vallist ';'
+simple : IDENT vallist ';'
{
- process_ident($1, &$2);
+ $$ = grecs_node_create(grecs_node_stmt,
+ &grecs_current_locus);
+ $$->ident = $1;
+ $$->value = $2;
}
;
-block : ident tag { stmt_begin($<kw>1, $<value>2); } '{' stmtlist '}' opt_sc
+block : IDENT tag '{' stmtlist '}' opt_sc
{
- stmt_end($1);
- }
- ;
-
-ident : IDENT
- {
- $$ = find_keyword($1);
- if (!$$)
- grecs_error(&grecs_current_locus, 0,
- _("Unknown keyword"));
+ $$ = grecs_node_create(grecs_node_block,
+ &grecs_current_locus);
+ $$->ident = $1;
+ $$->value = $2;
+ grecs_node_bind($$, $4.head, 1);
}
;
tag : /* empty */
{
$$.type = GRECS_TYPE_STRING;
@@ -132,13 +117,13 @@ vallist : vlist
grecs_list_free($1);
}
;
vlist : value
{
- $$ = simple_list_create(0);
+ $$ = _grecs_simple_list_create(0);
grecs_list_append($$, grecs_value_dup(&$1));
}
| vlist value
{
grecs_list_append($1, grecs_value_dup(&$2));
}
@@ -166,25 +151,24 @@ string : STRING
| slist
;
slist : slist0
{
struct grecs_list_entry *ep;
- const void *p;
grecs_line_begin();
for (ep = $1->head; ep; ep = ep->next)
grecs_line_add(ep->data, strlen(ep->data));
$$ = grecs_line_finish();
grecs_list_free($1);
}
;
slist0 : QSTRING
{
- $$ = simple_list_create(0);
+ $$ = _grecs_simple_list_create(0);
grecs_list_append($$, $1);
}
| slist0 QSTRING
{
grecs_list_append($1, $2);
$$ = $1;
@@ -204,13 +188,13 @@ list : '(' ')'
$$ = $2;
}
;
values : value
{
- $$ = simple_list_create(0);
+ $$ = _grecs_simple_list_create(0);
grecs_list_append($$, grecs_value_dup(&$1));
}
| values ',' value
{
grecs_list_append($1, grecs_value_dup(&$3));
$$ = $1;
@@ -233,14 +217,14 @@ yyerror(char *s)
static void
listel_dispose(void *el)
{
free(el);
}
-static struct grecs_list *
-simple_list_create(int dispose)
+struct grecs_list *
+_grecs_simple_list_create(int dispose)
{
struct grecs_list *lp = grecs_list_create();
if (dispose)
lp->free_entry = listel_dispose;
return lp;
}
@@ -304,649 +288,32 @@ grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...)
va_start(ap, fmt);
rc = grecs_vasprintf(pbuf, psize, fmt, ap);
va_end(ap);
return rc;
}
-void
-grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...)
-{
- va_list ap;
- char *buf = NULL;
- size_t size = 0;
-
- va_start(ap, fmt);
- if (grecs_vasprintf(&buf, &size, fmt, ap))
- grecs_alloc_die();
- 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;
- size_t size = 0;
-
- va_start(ap, fmt);
- if (grecs_vasprintf(&buf, &size, fmt, ap))
- grecs_alloc_die();
- 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
+struct grecs_node *
grecs_parse(const char *name)
{
int rc;
if (grecs_lex_begin(name))
- return 1;
- cursect = &config_keywords;
- if (sections) {
- grecs_list_free(sections);
- sections = NULL;
- }
+ return NULL;
+ parse_tree = NULL;
rc = yyparse();
grecs_lex_end();
- if (grecs_error_count)
- rc = 1;
- return rc;
+ if (grecs_error_count) {
+ grecs_tree_free(parse_tree);
+ parse_tree = NULL;
+ }
+ return parse_tree;
}
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 (base)
- base += kwp->offset;
-
- 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 = grecs_list_create();
- grecs_list_push(sections, cursect);
- if (kwp) {
- target = target_ptr(kwp, CURRENT_BASE);
- 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;
- }
-
- cursect = (struct grecs_keyword *) grecs_list_pop(sections);
- if (!cursect)
- abort();
- if (callback)
- callback(grecs_callback_section_end,
- &grecs_current_locus, /* FIXME */
- kwp ? target_ptr(kwp, CURRENT_BASE) : 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_bool(const char *string, int *pval, grecs_locus_t *locus)
-{
- 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(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, grecs_locus_t *locus)
-{
- 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,
- grecs_locus_t *locus)
-{
- if (string[0] == '/') {
- struct sockaddr_un s_un;
- if (strlen(string) >= sizeof(s_un.sun_path)) {
- grecs_error(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 = grecs_malloc(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 = grecs_malloc(len + 1);
- memcpy(host, string, len);
- host[len] = 0;
-
- if (string_to_host(&sa.sin_addr, host, locus)) {
- grecs_error(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(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(locus, 0, _("missing port number"));
- return 1;
- }
- sp->len = sizeof(sa);
- sp->sa = grecs_malloc(sp->len);
- memcpy(sp->sa, &sa, sp->len);
- }
- return 0;
-}
-
-
-/* The TYPE_* defines come from gnulib's intprops.h */
-
-/* True if the arithmetic type T is signed. */
-# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-
-/* The maximum and minimum values for the integer type T. These
- macros have undefined behavior if T is signed and has padding bits. */
-# define TYPE_MINIMUM(t) \
- ((t) (! TYPE_SIGNED(t) \
- ? (t) 0 \
- : TYPE_SIGNED_MAGNITUDE(t) \
- ? ~ (t) 0 \
- : ~ TYPE_MAXIMUM(t)))
-# define TYPE_MAXIMUM(t) \
- ((t) (! TYPE_SIGNED(t) \
- ? (t) -1 \
- : ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
-# define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
-
-
-#define STRTONUM(s, type, base, res, limit, loc) \
- { \
- type sum = 0; \
- \
- for (; *s; s++) \
- { \
- type x; \
- \
- if ('0' <= *s && *s <= '9') \
- x = sum * base + *s - '0'; \
- else if (base == 16 && 'a' <= *s && *s <= 'f') \
- x = sum * base + *s - 'a'; \
- else if (base == 16 && 'A' <= *s && *s <= 'F') \
- x = sum * base + *s - 'A'; \
- else \
- break; \
- if (x <= sum) \
- { \
- grecs_error(loc, 0, _("numeric overflow")); \
- return 1; \
- } \
- else if (limit && x > limit) \
- { \
- grecs_error(loc, 0, _("value out of allowed range")); \
- return 1; \
- } \
- sum = x; \
- } \
- res = sum; \
- }
-
-#define STRxTONUM(s, type, res, limit, loc) \
- { \
- int base; \
- if (*s == '0') \
- { \
- s++; \
- if (*s == 0) \
- base = 10; \
- else if (*s == 'x' || *s == 'X') \
- { \
- s++; \
- base = 16; \
- } \
- else \
- base = 8; \
- } else \
- base = 10; \
- STRTONUM(s, type, base, res, limit, loc); \
- }
-
-#define GETUNUM(str, type, res, loc) \
- { \
- type tmpres; \
- const char *s = str; \
- STRxTONUM(s, type, tmpres, 0, loc); \
- if (*s) \
- { \
- grecs_error(loc, 0, _("not a number (stopped near `%s')"), \
- s); \
- return 1; \
- } \
- res = tmpres; \
- }
-
-#define GETSNUM(str, type, res, loc) \
- { \
- unsigned type tmpres; \
- const char *s = str; \
- int sign; \
- unsigned type limit; \
- \
- if (*s == '-') \
- { \
- sign = 1; \
- s++; \
- limit = TYPE_MINIMUM(type); \
- limit = - limit; \
- } \
- else \
- { \
- sign = 0; \
- limit = TYPE_MAXIMUM(type); \
- } \
- \
- STRxTONUM(s, unsigned type, tmpres, limit, loc); \
- if (*s) \
- { \
- grecs_error(loc, 0, _("not a number (stopped near `%s')"), s); \
- return 1; \
- } \
- res = sign ? - tmpres : tmpres; \
- }
-
-
-int
-grecs_string_convert(void *target, enum grecs_data_type type,
- const char *string, grecs_locus_t *locus)
-{
- switch (type) {
- case grecs_type_void:
- abort();
-
- case grecs_type_string:
- *(const char**)target = string;
- break;
-
- case grecs_type_short:
- GETUNUM(string, short, *(short*)target, locus);
- break;
-
- case grecs_type_ushort:
- GETUNUM(string, unsigned short, *(unsigned short*)target, locus);
- break;
-
- case grecs_type_bool:
- return string_to_bool(string, (int*)target, locus);
-
- case grecs_type_int:
- GETSNUM(string, int, *(int*)target, locus);
- break;
-
- case grecs_type_uint:
- GETUNUM(string, unsigned int, *(unsigned int*)target, locus);
- break;
-
- case grecs_type_long:
- GETSNUM(string, long, *(long*)target, locus);
- break;
-
- case grecs_type_ulong:
- GETUNUM(string, unsigned long, *(unsigned long*)target, locus);
- break;
-
- case grecs_type_size:
- GETUNUM(string, size_t, *(size_t*)target, locus);
- break;
- /*FIXME
- case grecs_type_off:
- GETSNUM(string, off_t, *(off_t*)target, locus);
- break;
- */
- case grecs_type_time:
- /*FIXME: Use getdate */
- GETUNUM(string, time_t, *(time_t*)target, locus);
- break;
-
- case grecs_type_ipv4:
- if (inet_aton(string, (struct in_addr *)target)) {
- grecs_error(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, locus)) {
- grecs_error(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,
- locus);
-
- /* FIXME: */
- case grecs_type_cidr:
- grecs_error(locus, 0,
- _("INTERNAL ERROR at %s:%d"), __FILE__, __LINE__);
- abort();
-
- case grecs_type_section:
- grecs_error(locus, 0,
- _("invalid use of block statement"));
- return 1;
- }
- return 0;
-}
-
-struct grecs_prop
-{
- size_t size;
- int (*cmp)(const void *, const void *);
-};
-
-static int
-string_cmp(const void *elt1, const void *elt2)
-{
- return strcmp((const char *)elt1,(const char *)elt2);
-}
-
-#define __grecs_name_cat__(a,b) a ## b
-#define NUMCMP(type) __grecs_name_cat__(type,_cmp)
-#define __DECL_NUMCMP(type,ctype) \
- static int \
- NUMCMP(type)(const void *elt1, const void *elt2) \
- { \
- return memcmp(elt1, elt2, sizeof(ctype)); \
- }
-#define DECL_NUMCMP(type) __DECL_NUMCMP(type,type)
-
-DECL_NUMCMP(short)
-DECL_NUMCMP(int)
-DECL_NUMCMP(long)
-DECL_NUMCMP(size_t)
-/*FIXME DECL_NUMCMP(off_t)*/
-DECL_NUMCMP(time_t)
-__DECL_NUMCMP(in_addr, struct in_addr)
-__DECL_NUMCMP(grecs_sockaddr, struct grecs_sockaddr)
-
-struct grecs_prop grecs_prop_tab[] = {
- { 0, NULL }, /* grecs_type_void */
- { sizeof(char*), string_cmp }, /* grecs_type_string */
- { sizeof(short), NUMCMP(short) }, /* grecs_type_short */
- { sizeof(unsigned short), NUMCMP(short) }, /* grecs_type_ushort */
- { sizeof(int), NUMCMP(int) }, /* grecs_type_int */
- { sizeof(unsigned int), NUMCMP(int) }, /* grecs_type_uint */
- { sizeof(long), NUMCMP(long) }, /* grecs_type_long */
- { sizeof(unsigned long), NUMCMP(long) }, /* grecs_type_ulong */
- { sizeof(size_t), NUMCMP(size_t) }, /* grecs_type_size */
-#if 0
- FIXME
- { sizeof(off_t), NUMCMP(off_t) }, /* grecs_type_off */
-#endif
- { sizeof(time_t), NUMCMP(time_t) }, /* grecs_type_time */
- { sizeof(int), NUMCMP(int) }, /* grecs_type_bool */
- { sizeof(struct in_addr), NUMCMP(in_addr) }, /* grecs_type_ipv4 */
- { 0, NULL }, /* FIXME: grecs_type_cidr */
- { sizeof(struct in_addr), NUMCMP(in_addr) }, /* grecs_type_host */
- { sizeof(struct grecs_sockaddr), NUMCMP(grecs_sockaddr) },
- /* grecs_type_sockaddr */
- { 0, NULL } /* grecs_type_section */
-};
-#define grecs_prop_count \
- (sizeof(grecs_prop_tab) / sizeof(grecs_prop_tab[0]))
-
-void
-grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value,
- void *base, grecs_locus_t *locus)
-{
- void *target;
-
- if (!kwp)
- return;
-
- target = target_ptr(kwp, (char *) base);
-
- if (kwp->callback)
- kwp->callback(grecs_callback_set_value,
- locus,
- target,
- value,
- &kwp->callback_data);
- else if (value->type == GRECS_TYPE_ARRAY) {
- grecs_error(locus, 0,
- _("too many arguments to `%s'; missing semicolon?"),
- kwp->ident);
- return;
- } else if (value->type == GRECS_TYPE_LIST) {
- if (GRECS_IS_LIST(kwp->type)) {
- struct grecs_list_entry *ep;
- enum grecs_data_type type = GRECS_TYPE(kwp->type);
- int num = 1;
- struct grecs_list *list;
- size_t size;
-
- if (type >= grecs_prop_count
- || (size = grecs_prop_tab[type].size) == 0) {
- grecs_error(locus, 0,
- _("INTERNAL ERROR at %s:%d: "
- "unhandled data type %d"),
- __FILE__, __LINE__, type);
- abort();
- }
-
- list = grecs_list_create();
- list->cmp = grecs_prop_tab[type].cmp;
-
- for (ep = value->v.list->head; ep; ep = ep->next) {
- const grecs_value_t *vp = ep->data;
-
- if (vp->type != GRECS_TYPE_STRING)
- grecs_error(locus, 0,
- _("%s: incompatible data type in list item #%d"),
- kwp->ident, num);
- else if (type == grecs_type_string)
- grecs_list_append(list,
- (void*) vp->v.string);
- else {
- void *ptr = grecs_malloc(size);
- if (grecs_string_convert(ptr,
- type,
- vp->v.string,
- locus) == 0)
- grecs_list_append(list, ptr);
- else
- free(ptr);
- }
- }
- *(struct grecs_list**)target = list;
- } else {
- grecs_error(locus, 0,
- _("incompatible data type for `%s'"),
- kwp->ident);
- return;
- }
- } else if (GRECS_IS_LIST(kwp->type)) {
- struct grecs_list *list;
- enum grecs_data_type type = GRECS_TYPE(kwp->type);
- size_t size;
- void *ptr;
-
- if (type >= grecs_prop_count
- || (size = grecs_prop_tab[type].size) == 0) {
- grecs_error(locus, 0,
- _("INTERNAL ERROR at %s:%d: unhandled data type %d"),
- __FILE__, __LINE__, type);
- abort();
- }
-
- list = grecs_list_create();
- list->cmp = grecs_prop_tab[type].cmp;
- list->free_entry = listel_dispose;
- if (type == grecs_type_string)
- grecs_list_append(list, value->v.string);
- else {
- ptr = grecs_ma