diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 4 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/diag.c | 73 | ||||
-rw-r--r-- | src/format.c | 121 | ||||
-rw-r--r-- | src/grecs-gram.y | 715 | ||||
-rw-r--r-- | src/grecs.h | 86 | ||||
-rw-r--r-- | src/lookup.c | 272 | ||||
-rw-r--r-- | src/tree.c | 773 |
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 @@ -16,14 +16,17 @@ 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 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 @@ -24,7 +24,7 @@ #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: @@ -68,14 +68,14 @@ grecs_data_type_string (enum grecs_data_type type) } 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; @@ -101,7 +101,7 @@ grecs_format_docstring(FILE *stream, const char *docstring, unsigned level) 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); @@ -119,14 +119,14 @@ grecs_format_docstring(FILE *stream, const char *docstring, unsigned level) } 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; @@ -136,7 +136,7 @@ grecs_format_simple_statement(FILE *stream, struct grecs_keyword *kwp, 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)) @@ -151,34 +151,117 @@ grecs_format_simple_statement(FILE *stream, struct grecs_keyword *kwp, } 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 @@ -22,45 +22,22 @@ #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 @@ -68,39 +45,47 @@ static struct grecs_list *simple_list_create(int dispose); %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); } ; @@ -135,7 +120,7 @@ vallist : vlist vlist : value { - $$ = simple_list_create(0); + $$ = _grecs_simple_list_create(0); grecs_list_append($$, grecs_value_dup(&$1)); } | vlist value @@ -169,7 +154,6 @@ string : STRING slist : slist0 { struct grecs_list_entry *ep; - const void *p; grecs_line_begin(); for (ep = $1->head; ep; ep = ep->next) @@ -181,7 +165,7 @@ slist : slist0 slist0 : QSTRING { - $$ = simple_list_create(0); + $$ = _grecs_simple_list_create(0); grecs_list_append($$, $1); } | slist0 QSTRING @@ -207,7 +191,7 @@ list : '(' ')' values : value { - $$ = simple_list_create(0); + $$ = _grecs_simple_list_create(0); grecs_list_append($$, grecs_value_dup(&$1)); } | values ',' value @@ -236,8 +220,8 @@ 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) @@ -307,59 +291,20 @@ grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...) 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 @@ -370,583 +315,5 @@ grecs_gram_trace(int 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_malloc(size); - if (grecs_string_convert(ptr, type, value->v.string, locus)) { - free(ptr); - grecs_list_free(list); - return; - } - grecs_list_append(list, ptr); - } - *(struct grecs_list**)target = list; - } else - grecs_string_convert(target, GRECS_TYPE(kwp->type), - value->v.string, - locus); -} - -static void -process_ident(struct grecs_keyword *kwp, grecs_value_t *value) -{ - grecs_process_ident(kwp, value, CURRENT_BASE, &grecs_current_locus); -} diff --git a/src/grecs.h b/src/grecs.h index 5769736..e0f0fa5 100644 --- a/src/grecs.h +++ b/src/grecs.h @@ -100,6 +100,25 @@ typedef struct grecs_value { } v; } grecs_value_t; +#define GRECS_VALUE_EMPTY_P(val) \ + (!(val) || \ + ((val)->type == GRECS_TYPE_STRING && (val)->v.string == NULL)) + +enum grecs_node_type { + grecs_node_stmt, + grecs_node_block +}; + +typedef struct grecs_node { + enum grecs_node_type type; + grecs_locus_t locus; + struct grecs_node *up; + struct grecs_node *down; + struct grecs_node *next; + char *ident; + struct grecs_value value; +} grecs_node_t; + typedef int (*grecs_callback_fn)( enum grecs_callback_command cmd, grecs_locus_t * /* locus */, @@ -138,19 +157,20 @@ char *grecs_strdup(const char *str); grecs_value_t *grecs_value_dup(grecs_value_t *input); -extern void grecs_print_diag(grecs_locus_t *, int, int, const char*); +extern void (*grecs_print_diag_fun)(grecs_locus_t *, int, int, const char*); void grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); void grecs_error(grecs_locus_t *locus, int errcode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); -void grecs_set_keywords(struct grecs_keyword *kwd); void grecs_gram_trace(int n); void grecs_lex_trace(int n); int grecs_lex_begin(const char*); void grecs_lex_end(void); -int grecs_parse(const char *name); +struct grecs_node *grecs_parse(const char *name); + +struct grecs_list *_grecs_simple_list_create(int dispose); void grecs_line_begin(void); void grecs_line_add(const char *text, size_t len); @@ -163,6 +183,12 @@ extern void grecs_process_ident(struct grecs_keyword *kwp, void *base, grecs_locus_t *locus); +struct grecs_node *grecs_node_create(enum grecs_node_type type, + |