aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore4
-rw-r--r--src/Make.am19
-rw-r--r--src/asprintf.c85
-rw-r--r--src/grecs-gram.y80
-rw-r--r--src/grecs-lex.l133
-rw-r--r--src/grecs.h35
-rw-r--r--src/lineacc.c82
-rw-r--r--src/meta1-gram.y217
-rw-r--r--src/meta1-lex.l114
-rw-r--r--src/parser.c60
-rw-r--r--src/txtacc.c187
-rw-r--r--src/wordsplit.c2
-rw-r--r--src/yygrecs.h28
-rw-r--r--src/yytrans20
14 files changed, 834 insertions, 232 deletions
diff --git a/src/.gitignore b/src/.gitignore
index 9ef1b57..feb5040 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -2,6 +2,10 @@ grecs-gram.c
grecs-gram.h
grecs-gram.output
grecs-lex.c
+meta1-gram.c
+meta1-gram.h
+meta1-gram.output
+meta1-lex.c
Make-inst.in
Make-shared.in
Make-static.in
diff --git a/src/Make.am b/src/Make.am
index 915e6c4..60c0f06 100644
--- a/src/Make.am
+++ b/src/Make.am
@@ -14,26 +14,36 @@
# You should have received a copy of the GNU General Public License
# along with Grecs. If not, see <http://www.gnu.org/licenses/>.
+if GRECS_COND_META1_PARSER
+ GRECS_PARSER_META1 = meta1-gram.y meta1-lex.l
+ GRECS_EXTRA_META1 = meta1-gram.h
+endif
+
GRECS_SRC = \
+ asprintf.c\
diag.c\
format.c\
grecs-gram.y\
grecs-lex.l\
join.c\
+ lineacc.c\
list.c\
lookup.c\
mem.c\
+ parser.c\
preproc.c\
sort.c\
symtab.c\
text.c\
tree.c\
+ txtacc.c\
version.c\
- wordsplit.c
+ wordsplit.c\
+ $(GRECS_PARSER_META1)
-noinst_HEADERS = yygrecs.h
+noinst_HEADERS =
-EXTRA_DIST=grecs-gram.h $(PP_SETUP_FILE) Make.am Make-inst.am Make-shared.am Make-static.am
+EXTRA_DIST=grecs-gram.h $(GRECS_EXTRA_META1) $(PP_SETUP_FILE) Make.am Make-inst.am Make-shared.am Make-static.am
INCLUDES = -I$(srcdir) -I$(top_srcdir)/@GRECS_SUBDIR@ @GRECS_INCLUDES@ @GRECS_HOST_PROJECT_INCLUDES@
AM_YFLAGS = -dtv
@@ -41,3 +51,6 @@ AM_LFLAGS = -d
incdir=$(pkgdatadir)/$(VERSION)/include
inc_DATA = $(PP_SETUP_FILE)
+
+LEXCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(LEX) $(LFLAGS) $(AM_LFLAGS)'
+YACCCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(YACC) $(YFLAGS) $(AM_YFLAGS)' \ No newline at end of file
diff --git a/src/asprintf.c b/src/asprintf.c
new file mode 100644
index 0000000..d493fcb
--- /dev/null
+++ b/src/asprintf.c
@@ -0,0 +1,85 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "grecs.h"
+
+int
+grecs_vasprintf(char **pbuf, size_t *psize, const char *fmt, va_list ap)
+{
+ char *buf = *pbuf;
+ size_t buflen = *psize;
+ int rc = 0;
+
+ if (!buf) {
+ if (buflen == 0)
+ buflen = 512; /* Initial allocation */
+
+ buf = calloc(1, buflen);
+ if (buf == NULL)
+ return ENOMEM;
+ }
+
+ for (;;) {
+ ssize_t n = vsnprintf(buf, buflen, fmt, ap);
+ if (n < 0 || n >= buflen || !memchr(buf, '\0', n + 1)) {
+ char *newbuf;
+ size_t newlen = buflen * 2;
+ if (newlen < buflen) {
+ rc = ENOMEM;
+ break;
+ }
+ newbuf = realloc(buf, newlen);
+ if (newbuf == NULL) {
+ rc = ENOMEM;
+ break;
+ }
+ buflen = newlen;
+ buf = newbuf;
+ } else
+ break;
+ }
+
+ if (rc) {
+ if (!*pbuf) {
+ /* We made first allocation, now free it */
+ free(buf);
+ buf = NULL;
+ buflen = 0;
+ }
+ }
+
+ *pbuf = buf;
+ *psize = buflen;
+ return rc;
+}
+
+int
+grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = grecs_vasprintf(pbuf, psize, fmt, ap);
+ va_end(ap);
+ return rc;
+}
diff --git a/src/grecs-gram.y b/src/grecs-gram.y
index 9f8d000..3452074 100644
--- a/src/grecs-gram.y
+++ b/src/grecs-gram.y
@@ -18,7 +18,6 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#include "yygrecs.h"
#include <grecs.h>
#include <grecs-gram.h>
#include <stdlib.h>
@@ -26,11 +25,10 @@
#include <string.h>
#include <errno.h>
-static struct grecs_node *parse_tree;
-int grecs_error_count;
-
-int grecs_default_port = 0;
+int yylex(void);
+int yyerror(char *s);
+static struct grecs_node *parse_tree;
%}
%union {
@@ -239,74 +237,13 @@ yyerror(char *s)
return 0;
}
-int
-grecs_vasprintf(char **pbuf, size_t *psize, const char *fmt, va_list ap)
-{
- char *buf = *pbuf;
- size_t buflen = *psize;
- int rc = 0;
-
- if (!buf) {
- if (buflen == 0)
- buflen = 512; /* Initial allocation */
-
- buf = calloc(1, buflen);
- if (buf == NULL)
- return ENOMEM;
- }
-
- for (;;) {
- ssize_t n = vsnprintf(buf, buflen, fmt, ap);
- if (n < 0 || n >= buflen || !memchr(buf, '\0', n + 1)) {
- char *newbuf;
- size_t newlen = buflen * 2;
- if (newlen < buflen) {
- rc = ENOMEM;
- break;
- }
- newbuf = realloc(buf, newlen);
- if (newbuf == NULL) {
- rc = ENOMEM;
- break;
- }
- buflen = newlen;
- buf = newbuf;
- } else
- break;
- }
-
- if (rc) {
- if (!*pbuf) {
- /* We made first allocation, now free it */
- free(buf);
- buf = NULL;
- buflen = 0;
- }
- }
-
- *pbuf = buf;
- *psize = buflen;
- return rc;
-}
-
-int
-grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...)
-{
- int rc;
- va_list ap;
-
- va_start(ap, fmt);
- rc = grecs_vasprintf(pbuf, psize, fmt, ap);
- va_end(ap);
- return rc;
-}
-
struct grecs_node *
-grecs_parse(const char *name)
+grecs_grecs_parser(const char *name, int traceflags)
{
int rc;
- if (grecs_lex_begin(name))
+ if (grecs_lex_begin(name, traceflags & GRECS_TRACE_LEX))
return NULL;
+ yydebug = traceflags & GRECS_TRACE_GRAM;
parse_tree = NULL;
rc = yyparse();
if (grecs_error_count)
@@ -319,11 +256,6 @@ grecs_parse(const char *name)
return parse_tree;
}
-void
-grecs_gram_trace(int n)
-{
- yydebug = n;
-}
diff --git a/src/grecs-lex.l b/src/grecs-lex.l
index 4d491fe..84ee858 100644
--- a/src/grecs-lex.l
+++ b/src/grecs-lex.l
@@ -3,7 +3,6 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#include "yygrecs.h"
}
%{
/* grecs - Gray's Extensible Configuration System
@@ -48,12 +47,9 @@ grecs_locus_t grecs_current_locus; /* Input file location */
*/
static size_t xlines;
-static struct grecs_list *line_acc;
-
static void multiline_begin(char *);
static void multiline_add(char *);
static char *multiline_strip_tabs(char *text);
-static void line_add_unescape_last(char *text, size_t len);
static int ident(void);
static int isemptystr(int off);
@@ -113,9 +109,10 @@ P [1-9][0-9]*
\"[^\\"\n]*\\. |
\"[^\\"\n]*\\\n { BEGIN(STR);
grecs_line_begin();
- line_add_unescape_last(yytext + 1, yyleng - 1); }
+ grecs_line_acc_grow_unescape_last(yytext + 1,
+ yyleng - 1); }
<STR>[^\\"\n]*\\. |
-<STR>\"[^\\"\n]*\\\n { line_add_unescape_last(yytext, yyleng); }
+<STR>\"[^\\"\n]*\\\n { grecs_line_acc_grow_unescape_last(yytext, yyleng); }
<STR>[^\\"\n]*\" { BEGIN(INITIAL);
if (yyleng > 1)
grecs_line_add(yytext, yyleng - 1);
@@ -170,20 +167,12 @@ yywrap()
return 1;
}
-static void
-line_acc_free_entry(void *ptr)
-{
- grecs_free(ptr);
-}
-
int
-grecs_lex_begin(const char *name)
+grecs_lex_begin(const char *name, int trace)
{
- if (yy_flex_debug > 0)
- yy_flex_debug = 0;
+ yy_flex_debug = trace;
- line_acc = grecs_list_create();
- line_acc->free_entry = line_acc_free_entry;
+ grecs_line_acc_create();
if (grecs_preprocessor) {
int fd;
@@ -211,7 +200,7 @@ grecs_lex_begin(const char *name)
void
grecs_lex_end(int err)
{
- grecs_list_clear(line_acc);
+ grecs_line_acc_free();
}
static int
@@ -239,95 +228,21 @@ multiline_strip_tabs(char *text)
return text;
}
-static int
-unquote_char(int c)
-{
- static char quote_transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
-
- char *p;
-
- for (p = quote_transtab; *p; p += 2) {
- if (*p == c)
- return p[1];
- }
- return -1;
-}
-
-struct line_acc_entry
-{
- size_t size;
-};
-#define line_acc_ptr(entry) (char*)(entry + 1)
-
-static void
-line_acc_add_string(const char *str, size_t len)
-{
- struct line_acc_entry *ent = grecs_malloc(sizeof(*ent) + len + 1);
- char *p = line_acc_ptr(ent);
- memcpy(p, str, len);
- p[len] = 0;
- ent->size = len;
- grecs_list_append(line_acc, ent);
-}
-
-static void
-line_acc_add_char(int c)
-{
- char t = c;
- line_acc_add_string(&t, 1);
-}
-
-static void
-list_acc_unescape_char(int c)
-{
- if (c != '\n') {
- int t = unquote_char(c);
- if (t != -1)
- line_acc_add_char(t);
- else {
- grecs_warning(&grecs_current_locus, 0,
- _("unknown escape sequence '\\%c'"),
- c);
- line_acc_add_char(c);
- }
- }
-}
-
-void
-grecs_line_add(const char *text, size_t len)
-{
- line_acc_add_string(text, len);
-}
-
-/* Same, but unescapes the last character from yytext */
-static void
-line_add_unescape_last(char *text, size_t len)
-{
- line_acc_add_string(text, len - 2);
- list_acc_unescape_char(text[len - 1]);
-}
-
static void
multiline_add(char *s)
{
if (multiline_unescape) {
for (; *s; s++) {
if (*s == '\\') {
- list_acc_unescape_char(s[1]);
+ grecs_line_acc_grow_char_unescape(s[1]);
++s;
} else
- line_acc_add_char(*s);
+ grecs_line_acc_grow_char(*s);
}
} else
grecs_line_add(s, strlen(s));
}
-void
-grecs_line_begin()
-{
- /* FIXME: nothing so far. Maybe prepare stk by calling obstack_finish? */
-}
-
static int
is_tab(char c)
{
@@ -374,30 +289,6 @@ multiline_begin(char *p)
grecs_line_begin();
}
-char *
-grecs_line_finish()
-{
- struct grecs_list_entry *ep;
- size_t size = 0;
- char *str, *p;
-
- for (ep = line_acc->head; ep; ep = ep->next) {
- struct line_acc_entry *ent = ep->data;
- size += ent->size;
- }
-
- str = grecs_malloc(size + 1);
- for (ep = line_acc->head, p = str; ep; ep = ep->next) {
- struct line_acc_entry *ent = ep->data;
- char *str = line_acc_ptr(ent);
- memcpy(p, str, ent->size);
- p += ent->size;
- }
- *p = 0;
- grecs_list_clear(line_acc);
- return str;
-}
-
static int
ident()
{
@@ -416,12 +307,6 @@ ident()
return IDENT;
}
-void
-grecs_lex_trace(int n)
-{
- yy_flex_debug = -n;
-}
-
grecs_value_t *
grecs_value_ptr_from_static(grecs_value_t *input)
{
diff --git a/src/grecs.h b/src/grecs.h
index 61a915b..ff47698 100644
--- a/src/grecs.h
+++ b/src/grecs.h
@@ -198,18 +198,39 @@ 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)));
+
+
+extern int grecs_trace_flags;
+
+#define GRECS_TRACE_GRAM 0x01
+#define GRECS_TRACE_LEX 0x02
void grecs_gram_trace(int n);
void grecs_lex_trace(int n);
+
-int grecs_lex_begin(const char*);
+int grecs_lex_begin(const char*, int);
void grecs_lex_end(int err);
struct grecs_node *grecs_parse(const char *name);
+
+extern struct grecs_node *(*grecs_parser_fun)(const char *name, int trace);
+
+/* Parsers: */
+struct grecs_node *grecs_grecs_parser(const char *name, int traceflags);
+struct grecs_node *grecs_meta1_parser(const char *name, int traceflags);
+
struct grecs_list *_grecs_simple_list_create(int dispose);
struct grecs_list *grecs_value_list_create(void);
+void grecs_line_acc_create(void);
+void grecs_line_acc_free(void);
+void grecs_line_acc_grow_char(int c);
+void grecs_line_acc_grow_char_unescape(int c);
+void grecs_line_acc_grow(const char *text, size_t len);
+void grecs_line_acc_grow_unescape_last(char *text, size_t len);
+
void grecs_line_begin(void);
-void grecs_line_add(const char *text, size_t len);
+#define grecs_line_add grecs_line_acc_grow
char *grecs_line_finish(void);
extern int grecs_string_convert(void *target, enum grecs_data_type type,
@@ -295,6 +316,13 @@ void grecs_list_add(struct grecs_list *dst, struct grecs_list *src);
int grecs_vasprintf(char **pbuf, size_t *psize, const char *fmt, va_list ap);
int grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...);
+#define GRECS_TXTACC_BUFSIZE 1024
+struct grecs_txtacc *grecs_txtacc_create(void);
+void grecs_txtacc_free(struct grecs_txtacc *acc);
+void grecs_txtacc_grow(struct grecs_txtacc *acc, const char *buf, size_t size);
+char *grecs_txtacc_finish(struct grecs_txtacc *acc, int steal);
+void grecs_txtacc_free_string(struct grecs_txtacc *acc, char *str);
+
struct grecs_symtab;
struct grecs_syment {
@@ -363,6 +391,9 @@ struct grecs_node *grecs_match_next(struct grecs_match_buf *buf);
void grecs_match_buf_free(struct grecs_match_buf *buf);
int grecs_value_eq(struct grecs_value *a, struct grecs_value *b);
+int grecs_value_match(struct grecs_value *pat, struct grecs_value *b,
+ int flags);
+
struct grecs_node *grecs_find_node(struct grecs_node *node, const char *path);
struct grecs_node *grecs_node_from_path(const char *path, const char *value);
diff --git a/src/lineacc.c b/src/lineacc.c
new file mode 100644
index 0000000..a3f4836
--- /dev/null
+++ b/src/lineacc.c
@@ -0,0 +1,82 @@
+/* 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 <wordsplit.h>
+
+static struct grecs_txtacc *line_acc;
+
+void
+grecs_line_acc_create()
+{
+ line_acc = grecs_txtacc_create();
+}
+
+void
+grecs_line_acc_free()
+{
+ grecs_txtacc_free(line_acc);
+ line_acc = NULL;
+}
+
+void
+grecs_line_acc_grow_char(int c)
+{
+ char t = c;
+ grecs_txtacc_grow(line_acc, &t, 1);
+}
+
+void
+grecs_line_acc_grow_char_unescape(int c)
+{
+ if (c != '\n')
+ grecs_line_acc_grow_char(wordsplit_c_unquote_char(c));
+}
+
+void
+grecs_line_acc_grow(const char *text, size_t len)
+{
+ grecs_txtacc_grow(line_acc, text, len);
+}
+
+/* Same, but unescapes the last character from text */
+void
+grecs_line_acc_grow_unescape_last(char *text, size_t len)
+{
+ grecs_txtacc_grow(line_acc, text, len - 2);
+ grecs_line_acc_grow_char_unescape(text[len - 1]);
+}
+
+void
+grecs_line_begin()
+{
+ if (!line_acc)
+ grecs_line_acc_create();
+}
+
+char *
+grecs_line_finish()
+{
+ grecs_line_acc_grow_char(0);
+ return grecs_txtacc_finish(line_acc, 1);
+}
+
+
+
+
diff --git a/src/meta1-gram.y b/src/meta1-gram.y
new file mode 100644
index 0000000..8ddcbfb
--- /dev/null
+++ b/src/meta1-gram.y
@@ -0,0 +1,217 @@
+%{
+/* MeTA1 configuration parser for Grecs.
+ 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 <errno.h>
+#include <string.h>
+#include "grecs.h"
+
+int yylex(void);
+int yyerror(char *s);
+
+static struct grecs_node *parse_tree;
+extern int yy_flex_debug;
+%}
+
+%union {
+ struct {
+ grecs_locus_t locus;
+ char *string;
+ } ident;
+ char *string;
+ grecs_value_t svalue, *pvalue;
+ struct grecs_list *list;
+ struct { struct grecs_node *head, *tail; } node_list;
+ struct grecs_node *node;
+}
+
+%token <ident> META1_IDENT
+%token <string> META1_STRING
+%type <node> stmt simple block
+%type <node_list> stmtlist
+%type <pvalue> tag value
+%type <string> string slist
+%type <list> slist0
+%type <list> values list
+%%
+
+input : stmtlist
+ {
+ parse_tree = grecs_node_create(grecs_node_root,
+ &grecs_current_locus);
+ parse_tree->v.texttab = grecs_text_table();
+ grecs_node_bind(parse_tree, $1.head, 1);
+ }
+ ;
+
+stmtlist: stmt
+ {
+ $$.head = $$.tail = $1;
+ }
+ | stmtlist stmt
+ {
+ grecs_node_bind($1.tail, $2, 0);
+ }
+ ;
+
+stmt : simple
+ | block
+ ;
+
+simple : META1_IDENT '=' value opt_sc
+ {
+ $$ = grecs_node_create(grecs_node_stmt,
+ &$1.locus);
+ $$->ident = $1.string;
+ $$->v.value = $3;
+ }
+ ;
+
+block : META1_IDENT tag '{' stmtlist '}' opt_sc
+ {
+ $$ = grecs_node_create(grecs_node_block,
+ &$1.locus);
+ $$->ident = $1.string;
+ $$->v.value = $2;
+ grecs_node_bind($$, $4.head, 1);
+ }
+ ;
+
+tag : /* empty */
+ {
+ $$ = NULL;
+ }
+ | META1_IDENT
+ {
+ $$ = grecs_malloc(sizeof($$[0]));
+ $$->type = GRECS_TYPE_STRING;
+ $$->v.string = $1.string;
+ }
+ ;
+
+value : string
+ {
+ $$ = grecs_malloc(sizeof($$[0]));
+ $$->type = GRECS_TYPE_STRING;
+ $$->v.string = $1;
+ }
+ | list
+ {
+ $$ = grecs_malloc(sizeof($$[0]));
+ $$->type = GRECS_TYPE_LIST;
+ $$->v.list = $1;
+ }
+ ;
+
+string : META1_IDENT
+ {
+ $$ = $1.string;
+ }
+ | slist
+ ;
+
+slist : slist0
+ {
+ struct grecs_list_entry *ep;
+
+ grecs_line_begin();
+ for (ep = $1->head; ep; ep = ep->next) {
+ grecs_line_add(ep->data, strlen(ep->data));
+ free(ep->data);
+ ep->data = NULL;
+ }
+ $$ = grecs_line_finish();
+ grecs_list_free($1);
+ }
+
+slist0 : META1_STRING
+ {
+ $$ = grecs_list_create();
+ grecs_list_append($$, $1);
+ }
+ | slist0 META1_STRING
+ {
+ grecs_list_append($1, $2);
+ $$ = $1;
+ }
+ ;
+
+list : '{' values '}'
+ {
+ $$ = $2;
+ }
+ | '{' values ',' '}'
+ {
+ $$ = $2;
+ }
+ ;
+
+values : value
+ {
+ $$ = grecs_value_list_create();
+ grecs_list_append($$, $1);
+ }
+ | values ',' value
+ {
+ grecs_list_append($1, $3);
+ $$ = $1;
+ }
+ ;
+
+opt_sc : /* empty */
+ | ';'
+ ;
+
+%%
+int
+yyerror(char *s)
+{
+ grecs_error(&grecs_current_locus, 0, "%s", s);
+ return 0;
+}
+
+struct grecs_node *
+grecs_meta1_parser(const char *name, int traceflags)
+{
+ int rc;
+ FILE *fp;
+
+ fp = fopen(name, "r");
+ if (!fp) {
+ grecs_error(NULL, errno, _("Cannot open `%s'"), name);
+ return NULL;
+ }
+ yyset_in(fp);
+
+ yy_flex_debug = traceflags & GRECS_TRACE_LEX;
+ yydebug = traceflags & GRECS_TRACE_GRAM;
+ parse_tree = NULL;
+ grecs_line_acc_create();
+ rc = yyparse();
+ fclose(fp);
+ if (grecs_error_count)
+ rc = 1;
+ grecs_line_acc_free();
+ if (rc) {
+ grecs_tree_free(parse_tree);
+ parse_tree = NULL;
+ }
+ return parse_tree;
+}
+
diff --git a/src/meta1-lex.l b/src/meta1-lex.l
new file mode 100644
index 0000000..cb2931d
--- /dev/null
+++ b/src/meta1-lex.l
@@ -0,0 +1,114 @@
+/* MeTA1 configuration lexer for Grecs. -*- c -*- */
+%top {
+/* MeTA1 configuration lexer for Grecs.
+ 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/>. */
+
+/* This file implements a lexical analyzer for MeTA1 main configuration file.
+ */
+
+#ifndef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "grecs.h"
+#include "meta1-gram.h"
+#include <ctype.h>
+}
+
+%{
+static int yywrap(void);
+static void meta1_line_add_unescape_hex(const char *text, size_t len);
+%}
+
+%x COMMENT STR
+X [0-9a-fA-F]
+%%
+ /* C-style comments */
+"/*" BEGIN (COMMENT);
+<COMMENT>[^*\n]* /* eat anything that's not a '*' */
+<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<COMMENT>\n ++grecs_current_locus.line;
+<COMMENT>"*"+"/" BEGIN (INITIAL);
+ /* End-of-line comments */
+#.*\n { grecs_current_locus.line++; }
+#.* /* end-of-file comment */;
+ /* Number */
+0[xX]{X}+ |
+0[0-7]+ |
+[1-9][0-9]+ { grecs_line_begin();
+ grecs_line_add(yytext, yyleng);
+ yylval.string = grecs_line_finish();
+ return META1_STRING; }
+ /* Identifiers (unquoted strings) */
+[a-zA-Z0-9_\./:\*-]+ { grecs_line_begin();
+ grecs_line_add(yytext, yyleng);
+ yylval.ident.locus = grecs_current_locus;
+ yylval.ident.string = grecs_line_finish();
+ return META1_IDENT; }
+ /* Quoted strings */
+\"[^\\"\n]*\" { grecs_line_begin();
+ grecs_line_add(yytext + 1, yyleng - 2);
+ yylval.string = grecs_line_finish();
+ return META1_STRING; }
+\"[^\\"\n]*\\x{X}{1,2} { BEGIN(STR);
+ grecs_line_begin();
+ meta1_line_add_unescape_hex(yytext + 1, yyleng - 1);
+ }
+\"[^\\"\n]*\\. { BEGIN(STR);
+ grecs_line_begin();
+ grecs_line_acc_grow_unescape_last(yytext + 1,
+ yyleng - 1); }
+<STR>[^\\"\n]*\\x{X}{1,2} { meta1_line_add_unescape_hex(yytext, yyleng); }
+<STR>[^\\"\n]*\\. { grecs_line_acc_grow_unescape_last(yytext, yyleng); }
+<STR>[^\\"\n]*\" { BEGIN(INITIAL);
+ if (yyleng > 1)
+ grecs_line_add(yytext, yyleng - 1);
+ yylval.string = grecs_line_finish();
+ return META1_STRING; }
+<STR>[^\\"\n]*\n { BEGIN(INITIAL);
+ grecs_error(&grecs_current_locus, 0,
+ _("newline in a string"));
+ grecs_line_add (yytext, yyleng - 1);
+ yylval.string = grecs_line_finish ();
+ return META1_STRING; }
+ /* Other tokens */
+[ \t\f][ \t\f]* ;
+\n { grecs_current_locus.line++; }
+[,;{}=] return yytext[0];
+. { grecs_error(&grecs_current_locus, 0,
+ (isascii(yytext[0]) && isprint(yytext[0])) ?
+ _("stray character %c") :
+ _("stray character \\%03o"),
+ (unsigned char) yytext[0]); }
+%%
+
+int
+yywrap()
+{
+ return 1;
+}
+
+static void
+meta1_line_add_unescape_hex(const char *text, size_t len)
+{
+ for (; text[len-1] != 'x' && len > 0; len--)
+ ;
+ grecs_line_acc_grow(text, len - 2);
+ grecs_line_acc_grow_char((char) strtoul (text + len, NULL, 16));
+}
+
+
+
+
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..6f84bd8
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,60 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "grecs.h"
+
+int grecs_error_count;
+int grecs_default_port = 0;
+
+int grecs_trace_flags = 0;
+
+#ifndef GRECS_DEFAULT_PARSER
+# define GRECS_DEFAULT_PARSER grecs_grecs_parser
+#endif
+
+struct grecs_node *(*grecs_parser_fun)(const char *name, int trace) =
+ GRECS_DEFAULT_PARSER;
+
+void
+grecs_gram_trace(int n)
+{
+ if (n)
+ grecs_trace_flags |= GRECS_TRACE_GRAM;
+ else
+ grecs_trace_flags &= ~GRECS_TRACE_GRAM;
+}
+
+void
+grecs_lex_trace(int n)
+{
+ if (n)
+ grecs_trace_flags |= GRECS_TRACE_LEX;
+ else
+ grecs_trace_flags &= ~GRECS_TRACE_LEX;
+}
+
+struct grecs_node *
+grecs_parse(const char *name)
+{
+ grecs_error_count = 0;
+ return grecs_parser_fun(name, grecs_trace_flags);
+}
diff --git a/src/txtacc.c b/src/txtacc.c
new file mode 100644
index 0000000..ff13e42
--- /dev/null
+++ b/src/txtacc.c
@@ -0,0 +1,187 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2007, 2009-2011 Sergey Poznyakoff
+
+ Wydawca 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.
+
+ Wydawca 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 wydawca. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <string.h>
+#include "grecs.h"
+
+struct grecs_txtacc_entry
+{
+ char *buf; /* Text buffer */
+ size_t size; /* Buffer size */
+ size_t len; /* Actual number of bytes in buffer */
+};
+#define TXTACC_BUFSIZE 1024
+#define grecs_txtacc_entry_freesize(e) ((e)->size - (e)->len)
+
+struct grecs_txtacc
+{
+ struct grecs_list *cur; /* Current build list */
+ struct grecs_list *mem; /* List of already allocated elements */
+};
+
+static struct grecs_txtacc_entry *
+grecs_txtacc_alloc_entry(struct grecs_list *list, size_t size)
+{
+ struct grecs_txtacc_entry *p = grecs_malloc(sizeof (*p));
+ p->buf = grecs_malloc(size);
+ p->size = size;
+ p->len = 0;
+ grecs_list_append(list, p);
+ return p;
+}
+
+static struct grecs_txtacc_entry *
+grecs_txtacc_cur_entry(struct grecs_txtacc *acc)
+{
+ struct grecs_txtacc_entry *ent;
+
+ if (grecs_list_size(acc->cur) == 0)
+ return grecs_txtacc_alloc_entry(acc->cur,
+ GRECS_TXTACC_BUFSIZE);
+ ent = acc->cur->tail->data;
+ if (grecs_txtacc_entry_freesize(ent) == 0)
+ ent = grecs_txtacc_alloc_entry(acc->cur,
+ GRECS_TXTACC_BUFSIZE);
+ return ent;
+}
+
+static void
+grecs_txtacc_entry_append(struct grecs_txtacc_entry *ent,
+ const char *p, size_t size)
+{
+ memcpy(ent->buf + ent->len, p, size);
+ ent->len += size;
+}
+
+static void
+grecs_txtacc_entry_tailor(struct grecs_txtacc_entry *ent)
+{
+ if (ent->size > ent->len) {
+ char *p = realloc(ent->buf, ent->len);
+ if (!p)
+ return;
+ ent->buf = p;
+ ent->size = ent->len;
+ }
+}
+
+static void
+grecs_txtacc_entry_free(void *p)
+{
+ if (p) {
+ struct grecs_txtacc_entry *ent = p;
+ free(ent->buf);
+ free(ent);
+ }
+}
+
+struct grecs_txtacc *
+grecs_txtacc_create()
+{
+ struct grecs_txtacc *acc = grecs_malloc(sizeof (*acc));
+ acc->cur = grecs_list_create();
+ acc->cur->free_entry = grecs_txtacc_entry_free;
+ acc->mem = grecs_list_create();
+ acc->mem->free_entry = grecs_txtacc_entry_free;
+ return acc;
+}
+
+void
+grecs_txtac