summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS4
-rw-r--r--configure.ac2
-rw-r--r--lib/.gitignore4
-rw-r--r--lib/Makefile.am15
-rw-r--r--lib/diag.c181
-rw-r--r--lib/forlan.c258
-rw-r--r--lib/forlan.h123
-rw-r--r--lib/forlangrm.y237
-rw-r--r--lib/forlanlex.l137
-rw-r--r--lib/libeclat.h33
-rw-r--r--src/Makefile.am1
-rw-r--r--src/cmdline.opt10
-rw-r--r--src/config.c2
-rw-r--r--src/diag.c108
-rw-r--r--src/eclat.c77
-rw-r--r--src/eclat.h19
-rw-r--r--src/error.c64
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/forlan01.at77
-rw-r--r--tests/testsuite.at4
-rw-r--r--tests/tforlan.c100
22 files changed, 1198 insertions, 261 deletions
diff --git a/NEWS b/NEWS
index a38e2aa..ebe5900 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,11 @@
-Eclat NEWS -- history of user-visible changes. 2012-09-19
+Eclat NEWS -- history of user-visible changes. 2012-09-22
Copyright (C) 2012 Sergey Poznyakoff
See the end of file for copying conditions.
Please send Eclat bug reports to <gray+eclat@gnu.org.ua>
-No news is good news.
+Version 0.1 - No news is good news.
=========================================================================
Copyright information:
diff --git a/configure.ac b/configure.ac
index fd22d37..b0aba5e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,6 +27,8 @@ AM_SILENT_RULES([yes])
# Checks for programs.
AC_PROG_CC
+AC_PROG_LEX
+AC_PROG_YACC
AC_PROG_RANLIB
# Checks for header files.
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 0000000..e0d9b22
--- a/dev/null
+++ b/lib/.gitignore
@@ -0,0 +1,4 @@
+forlangrm.c
+forlangrm.h
+forlangrm.output
+forlanlex.c
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 2c1d3a8..50b28a5 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -18,6 +18,12 @@ noinst_LIBRARIES=libeclat.a
libeclat_a_SOURCES=\
base64.c\
+ diag.c\
+ forlan.c\
+ forlan.h\
+ forlangrm.h\
+ forlangrm.y\
+ forlanlex.l\
hmac_sha1.c\
libeclat.h\
q2url.c\
@@ -33,3 +39,12 @@ libeclat_a_SOURCES=\
AM_LDFLAGS = $(CURL_LIBS)
INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS)
+
+forlanlex.c: forlangrm.h
+forlangrm.c forlangrm.h: forlangrm.y
+
+AM_YFLAGS=-tdv
+AM_LFLAGS=-dvp
+
+
+
diff --git a/lib/diag.c b/lib/diag.c
new file mode 100644
index 0000000..d061e9e
--- a/dev/null
+++ b/lib/diag.c
@@ -0,0 +1,181 @@
+/* This file is part of Eclat.
+ Copyright (C) 2012 Sergey Poznyakoff.
+
+ Eclat 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.
+
+ Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "libeclat.h"
+#include <string.h>
+#include <sysexits.h>
+
+const char *program_name;
+struct debug_category debug_category[LIBECLAT_DBG_MAX];
+int debug_avail;
+
+void
+set_program_name(const char *arg)
+{
+ program_name = strrchr(arg, '/');
+ if (!program_name)
+ program_name = arg;
+ else
+ program_name++;
+}
+
+void
+vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt,
+ va_list ap)
+{
+ if (program_name)
+ fprintf(stderr, "%s: ", program_name);
+
+ if (locus) {
+ size_t size = 0;
+
+ if (locus->beg.col == 0)
+ fprintf(stderr, "%s:%u",
+ locus->beg.file,
+ locus->beg.line);
+ else if (strcmp(locus->beg.file, locus->end.file))
+ fprintf(stderr, "%s:%u.%u-%s:%u.%u",
+ locus->beg.file,
+ locus->beg.line, locus->beg.col,
+ locus->end.file,
+ locus->end.line, locus->end.col);
+ else if (locus->beg.line != locus->end.line)
+ fprintf(stderr, "%s:%u.%u-%u.%u",
+ locus->beg.file,
+ locus->beg.line, locus->beg.col,
+ locus->end.line, locus->end.col);
+ else
+ fprintf(stderr, "%s:%u.%u-%u",
+ locus->beg.file,
+ locus->beg.line, locus->beg.col,
+ locus->end.col);
+ fprintf(stderr, ": ");
+ }
+
+ if (qual)
+ fprintf(stderr, "%s: ", qual);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+}
+
+void
+diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vdiag(locus, qual, fmt, ap);
+ va_end(ap);
+}
+
+void
+die(int status, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vdiag(NULL, NULL, fmt, ap);
+ va_end(ap);
+ exit(status);
+}
+
+void
+err(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vdiag(NULL, NULL, fmt, ap);
+ va_end(ap);
+}
+
+void
+warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vdiag(NULL, "warning", fmt, ap);
+ va_end(ap);
+}
+
+void
+debug_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vdiag(NULL, "debug", fmt, ap);
+ va_end(ap);
+}
+
+static struct debug_category *
+find_category(const char *arg, size_t len)
+{
+ struct debug_category *dp;
+
+ for (dp = debug_category; dp < debug_category + debug_avail; dp++)
+ if (dp->length == len && memcmp(dp->name, arg, len) == 0)
+ return dp;
+ return NULL;
+}
+
+int
+parse_debug_level(const char *arg)
+{
+ unsigned long lev;
+ char *p;
+ size_t len = strcspn(arg, ".");
+ struct debug_category *dp;
+
+ if (arg[len] == 0) {
+ lev = strtoul(arg, &p, 10);
+ if (*p)
+ return -1;
+ for (dp = debug_category; dp < debug_category + debug_avail;
+ dp++)
+ dp->level = lev;
+ return 0;
+ }
+
+ dp = find_category(arg, len);
+ if (!dp)
+ return -1;
+
+ p = (char*) arg + len;
+ if (*p == 0)
+ lev = 100;
+ else if (*p != '.')
+ return -1;
+ else {
+ lev = strtoul(p + 1, &p, 10);
+ if (*p)
+ return -1;
+ }
+ dp->level = lev;
+ return 0;
+}
+
+int
+debug_register(char *name)
+{
+ if (debug_avail >= LIBECLAT_DBG_MAX)
+ die(EX_SOFTWARE, "no more debug slots available");
+ debug_category[debug_avail].name = grecs_strdup(name);
+ debug_category[debug_avail].length = strlen(name);
+ debug_category[debug_avail].level = 0;
+ return debug_avail++;
+}
diff --git a/lib/forlan.c b/lib/forlan.c
new file mode 100644
index 0000000..0854d08
--- a/dev/null
+++ b/lib/forlan.c
@@ -0,0 +1,258 @@
+/* This file is part of Eclat.
+ Copyright (C) 2012 Sergey Poznyakoff.
+
+ Eclat 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.
+
+ Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "libeclat.h"
+#include "grecs.h"
+#include "forlan.h"
+
+int forlan_dbg = -1;
+
+void
+forlan_init()
+{
+ forlan_dbg = debug_register("forlan");
+}
+
+union forlan_node *
+forlan_node_create(enum forlan_type type)
+{
+ union forlan_node *p = grecs_zalloc(sizeof(*p));
+ p->type = type;
+ return p;
+}
+
+static void f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev);
+
+
+static void
+free_type_null(union forlan_node *p)
+{
+ warn("freeing undefined forlan_node");
+}
+
+void
+dump_null(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ fprintf(fp, "[undefined node]\n");
+}
+
+static void
+free_type_comp(union forlan_node *p)
+{
+ forlan_node_free(p->comp.node);
+}
+void
+dump_comp(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ fprintf(fp, "COMP");
+ if (p->comp.abs)
+ fprintf(fp, " ABS");
+ fputc('\n', fp);
+ forlan_dump_node(fp, p->comp.node, num, lev + 1);
+}
+
+static void
+free_type_test(union forlan_node *p)
+{
+ free(p->test.comp);
+ free(p->test.value);
+}
+void
+dump_test(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ fprintf(fp, "TEST: %s[%s]\n", p->test.comp, p->test.value);
+}
+
+static void
+free_type_func(union forlan_node *p)
+{
+ grecs_list_free(p->func.args);
+}
+void
+dump_func(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ struct grecs_list_entry *ep;
+ fprintf(fp, "CALL: %s\n", p->func.fp);
+ if (p->func.args)
+ for (ep = p->func.args->head; ep; ep = ep->next)
+ forlan_dump_node(fp, ep->data, num, lev + 1);
+}
+
+static void
+free_type_cond(union forlan_node *p)
+{
+ forlan_node_free((union forlan_node *)p->cond.expr);
+ forlan_node_free(p->cond.iftrue);
+ forlan_node_free(p->cond.iffalse);
+}
+void
+dump_cond(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ int n = *num;
+ fprintf(fp, "COND\n");
+ forlan_dump_node(fp, p->cond.expr, num, lev + 1);
+ fprintf(fp, "%04d: %*.*sIFTRUE %04d\n", ++*num, lev, lev, "", n);
+ forlan_dump_node(fp, p->cond.iftrue, num, lev + 1);
+ fprintf(fp, "%04d: %*.*sIFFALSE %04d\n", ++*num, lev, lev, "", n);
+ forlan_dump_node(fp, p->cond.iffalse, num, lev + 1);
+}
+
+static void
+free_type_stmt(union forlan_node *p)
+{
+ forlan_node_free(p->stmt.stmt);
+ forlan_node_free(p->stmt.next);
+}
+void
+dump_stmt(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ f_dump_node(fp, p->stmt.stmt, num, lev);
+ forlan_dump_node(fp, p->stmt.next, num, lev);
+}
+
+static void
+free_type_lit(union forlan_node *p)
+{
+ free(p->lit.string);
+}
+void
+dump_lit(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ fprintf(fp, "LIT: \"%s\"\n", p->lit.string);
+}
+
+static void
+free_type_expr(union forlan_node *p)
+{
+ forlan_node_free(p->expr.arg[0]);
+ forlan_node_free(p->expr.arg[1]);
+}
+void
+dump_expr(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ static char *opstr[] = { "NODE", "AND", "OR", "NOT" };
+
+ fprintf(fp, "%s\n", opstr[p->expr.opcode]);
+ forlan_dump_node(fp, p->expr.arg[0], num, lev + 1);
+ if (p->expr.arg[1])
+ forlan_dump_node(fp, p->expr.arg[1], num, lev + 1);
+}
+
+static void
+free_type_last(union forlan_node *p)
+{
+}
+void
+dump_last(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ fprintf(fp, "LAST\n");
+}
+
+struct forlan_node_method {
+ void (*f_free)(union forlan_node *);
+ void (*f_dump)(FILE *fp, union forlan_node *node, int *num, int lev);
+};
+
+static struct forlan_node_method f_tab[] = {
+ free_type_null, dump_null, /* Unknown/unset type */
+ free_type_comp, dump_comp, /* A path component */
+ free_type_test, dump_test, /* Value test (f[X]) */
+ free_type_func, dump_func, /* Function call */
+ free_type_cond, dump_cond, /* Conditional */
+ free_type_stmt, dump_stmt, /* Statement */
+ free_type_lit, dump_lit, /* Literal */
+ free_type_expr, dump_expr, /* Boolean expression */
+ free_type_last, dump_last, /* "last" */
+};
+
+void
+forlan_node_free(union forlan_node *p)
+{
+ if (!p)
+ return;
+ if (p->type > sizeof(f_tab) / sizeof(f_tab[0]))
+ abort();
+ if (f_tab[p->type].f_free)
+ f_tab[p->type].f_free(p);
+ free(p);
+}
+
+static void
+stmt_list_free_entry(void *p)
+{
+ forlan_node_free(p);
+}
+
+struct grecs_list *
+forlan_stmt_list()
+{
+ struct grecs_list *lp;
+
+ lp = grecs_list_create();
+ lp->free_entry = stmt_list_free_entry;
+ return lp;
+}
+
+union forlan_node *
+forlan_stmt_from_list(struct grecs_list *list)
+{
+ union forlan_node **tail = NULL, *ret = NULL;
+ struct grecs_list_entry *ep;
+
+ for (ep = list->head; ep; ep = ep->next) {
+ union forlan_node *sp = forlan_node_create(forlan_type_stmt);
+ sp->stmt.stmt = ep->data;
+ if (tail)
+ *tail = sp;
+ else
+ ret = sp;
+ tail = &sp->stmt.next;
+ }
+ list->free_entry = NULL;
+ grecs_list_free(list);
+ return ret;
+}
+
+static void
+f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ if (p) {
+ if (p->type > sizeof(f_tab) / sizeof(f_tab[0]))
+ abort();
+ if (f_tab[p->type].f_dump)
+ f_tab[p->type].f_dump(fp, p, num, lev);
+ else
+ fprintf(fp, "type %d", p->type);
+ } else
+ fprintf(fp, "NULL");
+}
+
+void
+forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev)
+{
+ if (!p)
+ return;
+ ++*num;
+ fprintf(fp, "%04d: %*.*s", *num, lev, lev, "");
+ f_dump_node(fp, p, num, lev);
+}
+
+void
+forlan_dump_tree(FILE *fp, union forlan_node *node)
+{
+ int n = 0;
+ forlan_dump_node(fp, node, &n, 0);
+}
diff --git a/lib/forlan.h b/lib/forlan.h
new file mode 100644
index 0000000..4dadc70
--- a/dev/null
+++ b/lib/forlan.h
@@ -0,0 +1,123 @@
+/* This file is part of Eclat.
+ Copyright (C) 2012 Sergey Poznyakoff.
+
+ Eclat 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.
+
+ Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
+
+#define FORLAN_DBG_LEX 3
+#define FORLAN_DBG_GRAM 2
+#define FORLAN_DBG_EVAL 1
+
+extern int forlan_dbg;
+
+void forlan_init();
+void forlan_lex_begin(const char *input, size_t length,
+ struct grecs_locus_point *pt);
+void forlan_lex_end(void);
+int forlan_parse(const char *input, size_t length,
+ struct grecs_locus_point *pt);
+
+union forlan_node; /* Declared below */
+
+enum forlan_type {
+ forlan_type_null, /* Unknown/unset type */
+ forlan_type_comp, /* A path component */
+ forlan_type_test, /* Value test (f[X]) */
+ forlan_type_func, /* Function call */
+ forlan_type_cond, /* Conditional */
+ forlan_type_stmt, /* Statement */
+ forlan_type_lit, /* Literal */
+ forlan_type_expr, /* Boolean expression */
+ forlan_type_last /* Return last evaluated grecs_node */
+};
+
+/* A path component */
+struct forlan_node_comp {
+ enum forlan_type type;
+ int abs;
+ union forlan_node *node;
+};
+
+/* Path test: .path.comp[value] */
+struct forlan_node_test {
+ enum forlan_type type;
+ char *comp;
+ char *value;
+};
+
+/* Function call */
+struct forlan_node_func {
+ enum forlan_type type;
+ void *fp; /* FIXME: replace with typedef */
+ struct grecs_list *args; /* Arguments are struct forlan_node * */
+};
+
+/* Conditional */
+struct forlan_node_cond {
+ enum forlan_type type;
+ union forlan_node *expr; /* Controlling expression */
+ union forlan_node *iftrue; /* Run this if expr yields true */
+ union forlan_node *iffalse; /* Run this if expr yields false */
+};
+
+/* Statement or statement list */
+struct forlan_node_stmt {
+ enum forlan_type type;
+ union forlan_node *stmt;
+ union forlan_node *next;
+};
+
+/* Literal string */
+struct forlan_node_lit {
+ enum forlan_type type;
+ char *string;
+};
+
+/* Boolean opcodes */
+enum forlan_opcode {
+ forlan_opcode_node, /* Evaluate node, set 'last' */
+ forlan_opcode_and, /* Boolean AND */
+ forlan_opcode_or, /* Boolean OR */
+ forlan_opcode_not /* Boolean NOT */
+};
+
+/* Boolean expression */
+struct forlan_node_expr {
+ enum forlan_type type;
+ enum forlan_opcode opcode;
+ union forlan_node *arg[2];
+};
+
+/* Now get all this together */
+union forlan_node {
+ enum forlan_type type;
+ struct forlan_node_comp comp; /* A path component */
+ struct forlan_node_test test; /* Value test (f[X]) */
+ struct forlan_node_func func; /* Function call */
+ struct forlan_node_cond cond; /* Conditional */
+ struct forlan_node_stmt stmt; /* Statement */
+ struct forlan_node_lit lit; /* Literal */
+ struct forlan_node_expr expr; /* Boolean expression */
+ /* forlan_type_last needs no additional data */
+};
+
+union forlan_node *forlan_node_create(enum forlan_type type);
+void forlan_node_free(union forlan_node *);
+struct grecs_list *forlan_stmt_list(void);
+struct grecs_list *forlan_complist(void);
+union forlan_node *forlan_stmt_from_list(struct grecs_list *list);
+
+extern union forlan_node *forlan_parse_tree;
+
+void forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev);
+void forlan_dump_tree(FILE *fp, union forlan_node *node);
diff --git a/lib/forlangrm.y b/lib/forlangrm.y
new file mode 100644
index 0000000..1b7781d
--- a/dev/null
+++ b/lib/forlangrm.y
@@ -0,0 +1,237 @@
+%{
+/* This file is part of Eclat.
+ Copyright (C) 2012 Sergey Poznyakoff.
+
+ Eclat 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.
+
+ Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "libeclat.h"
+#include <grecs.h>
+#include <grecs-locus.h>
+#include "forlangrm.h"
+#include "forlan.h"
+
+static int yyerror(char *);
+union forlan_node *forlan_parse_tree;
+%}
+%error-verbose
+%locations
+
+%union {
+ char *string;
+ union forlan_node *node;
+ struct grecs_list *list;
+};
+
+%token <string> STRING IDENT
+%token LAST IF ELSE
+
+%left OR
+%left AND
+%left NOT
+
+%type <node> stmt stmt_cond stmt_expr stmt_blk cond bool node comp funcall arg
+%type <list> stmtlist complist arglist
+%type <string> string
+
+%%
+input : stmtlist
+ {
+ forlan_parse_tree = forlan_stmt_from_list($1);
+ }
+ ;
+
+stmtlist : stmt
+ {
+ $$ = forlan_stmt_list();
+ grecs_list_append($$, $1);
+ }
+ | stmtlist stmt
+ {
+ grecs_list_append($1, $2);
+ $$ = $1;
+ }
+ ;
+
+stmt : stmt_cond
+ | stmt_expr
+ | stmt_blk
+ ;
+
+stmt_blk : '{' stmtlist '}'
+ {
+ $$ = forlan_stmt_from_list($2);
+ }
+ ;
+
+stmt_cond : IF cond stmt
+ {
+ $$ = forlan_node_create(forlan_type_cond);
+ $$->cond.expr = $2;
+ $$->cond.iftrue = $3;
+ $$->cond.iffalse = NULL;
+ }
+ | IF cond stmt ELSE stmt
+ {
+ $$ = forlan_node_create(forlan_type_cond);
+ $$->cond.expr = $2;
+ $$->cond.iftrue = $3;
+ $$->cond.iffalse = $5;
+ }
+ ;
+
+cond : bool
+ ;
+
+bool : node
+ {
+ $$ = forlan_node_create(forlan_type_expr);
+ $$->expr.opcode = forlan_opcode_node;
+ $$->expr.arg[0] = $1;
+ }
+ | bool AND bool
+ {
+ $$ = forlan_node_create(forlan_type_expr);
+ $$->expr.opcode = forlan_opcode_and;
+ $$->expr.arg[0] = $1;
+ $$->expr.arg[1] = $3;
+ }
+ | bool OR bool
+ {
+ $$ = forlan_node_create(forlan_type_expr);
+ $$->expr.opcode = forlan_opcode_or;
+ $$->expr.arg[0] = $1;
+ $$->expr.arg[1] = $3;
+ }
+ | NOT bool
+ {
+ $$ = forlan_node_create(forlan_type_expr);
+ $$->expr.opcode = forlan_opcode_not;
+ $$->expr.arg[0] = $2;
+ }
+ | '(' bool ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+node : complist
+ {
+ $$ = forlan_node_create(forlan_type_comp);
+ $$->comp.abs = 0;
+ $$->comp.node = forlan_stmt_from_list($1);
+ }
+ | '.' complist
+ {
+ $$ = forlan_node_create(forlan_type_comp);
+ $$->comp.abs = 1;
+ $$->comp.node = forlan_stmt_from_list($2);
+ }
+ | LAST
+ {
+ $$ = forlan_node_create(forlan_type_last);
+ }
+ ;
+
+complist : comp
+ {
+ $$ = forlan_stmt_list();
+ grecs_list_append($$, $1);
+ }
+ | complist '.' comp
+ {
+ grecs_list_append($1, $3);
+ $$ = $1;
+ }
+ ;
+
+comp : IDENT
+ {
+ $$ = forlan_node_create(forlan_type_lit);
+ $$->lit.string = $1;
+ }
+ | IDENT '[' string ']'
+ {
+ $$ = forlan_node_create(forlan_type_test);
+ $$->test.comp = $1;
+ $$->test.value = $3;
+ }
+ | funcall
+ ;
+
+string : IDENT
+ | STRING
+ ;
+
+funcall : IDENT '(' ')'
+ {
+ $$ = forlan_node_create(forlan_type_func);
+ $$->func.fp = $1; //FIXME
+ $$->func.args = NULL;
+ }
+ | IDENT '(' arglist ')'
+ {
+ $$ = forlan_node_create(forlan_type_func);
+ $$->func.fp = $1; //FIXME
+ $$->func.args = $3;
+ }
+ ;
+
+arglist : arg
+ {
+ $$ = forlan_stmt_list();
+ grecs_list_append($$, $1);
+ }
+ | arglist ',' arg
+ {
+ grecs_list_append($1, $3);
+ $$ = $1;
+ }
+ ;
+
+arg : node
+ | STRING
+ {
+ $$ = forlan_node_create(forlan_type_lit);
+ $$->lit.string = $1;
+ }
+ ;
+
+stmt_expr : funcall ';'
+ ;
+%%
+static int
+yyerror(char *s)
+{
+ grecs_error(&yylloc, 0, "%s", s);
+ return 0;
+}
+
+int
+forlan_parser()
+{
+ yydebug = debug_level(forlan_dbg) >= FORLAN_DBG_GRAM;
+ return yyparse();
+}
+
+int
+forlan_parse(const char *input, size_t length, struct grecs_locus_point *pt)
+{
+ int rc;
+ forlan_lex_begin(input, length, pt);
+ rc = forlan_parser();
+ forlan_lex_end();
+ return rc;
+}
+
+
diff --git a/lib/forlanlex.l b/lib/forlanlex.l
new file mode 100644
index 0000000..99966ed
--- a/dev/null
+++ b/lib/forlanlex.l
@@ -0,0 +1,137 @@
+%{
+/* This file is part of Eclat.
+ Copyright (C) 2012 Sergey Poznyakoff.
+
+ Eclat 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.
+
+ Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "libeclat.h"
+#include <grecs.h>
+#include <grecs-locus.h>
+#include "forlangrm.h"
+#include "forlan.h"
+
+static const char *forlan_input_base;
+static size_t forlan_input_len;
+static size_t forlan_input_pos;
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ do { \
+ size_t __s = forlan_input_len - forlan_input_pos; \
+ if (__s > max_size) \
+ __s = max_size; \
+ if (__s > 0) { \
+ memcpy(buf, forlan_input_base, __s); \
+ forlan_input_pos += __s; \
+ } \
+ result = __s; \
+ } while(0)
+
+#define YY_USER_ACTION do { \
+ if (YYSTATE == 0) { \
+ yylloc.beg = grecs_current_locus_point; \
+ yylloc.beg.col++; \
+ } \
+ grecs_current_locus_point.col += yyleng; \
+ yylloc.end = grecs_current_locus_point; \
+ } while (0);
+
+static int yywrap(void);
+
+%}
+
+WS [ \t\f][ \t\f]*
+IDC [a-zA-Z_0-9-]
+%x COMMENT ML STR
+%%
+ /* Comments */
+"/*" BEGIN(COMMENT);
+<COMMENT>[^*\n]* /* eat anything that's not a '*' */
+<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<COMMENT>\n grecs_locus_point_advance_line(grecs_current_locus_point);
+<COMMENT>"*"+"/" BEGIN(INITIAL);
+"//".* ;
+ /* Keywords */
+if return IF;
+else return ELSE;
+last return LAST;
+! return NOT;
+"&&" return AND;
+"||" return OR;
+{IDC}{IDC}* { grecs_line_begin();
+ grecs_line_add(yytext, yyleng);
+ yylval.string = grecs_line_finish();
+ return IDENT; }
+ /* Quoted strings */
+\"[^\\"\n]*\" { grecs_line_begin();
+ grecs_line_add(yytext + 1, yyleng - 2);
+ yylval.string = grecs_line_finish();
+ return STRING; }
+\"[^\\"\n]*\\\n { BEGIN(STR);
+ grecs_line_begin();
+ grecs_line_acc_grow_unescape_last(yytext + 1,
+ yyleng - 1);
+ grecs_locus_point_advance_line(grecs_current_locus_point); }
+\"[^\\"\n]*\\. { BEGIN(STR);
+ grecs_line_begin();
+ grecs_line_acc_grow_unescape_last(yytext + 1,
+ yyleng - 1); }
+<STR>\"[^\\"\n]*\\\n { grecs_line_acc_grow_unescape_last(yytext, yyleng);
+ grecs_locus_point_advance_line(grecs_current_locus_point); }
+<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 STRING; }
+ /* Other tokens */
+{WS} ;
+\n { grecs_locus_point_advance_line(grecs_current_locus_point); }
+[.,;{}()\[\]] return yytext[0];
+. { if (isascii(yytext[0]) && isprint(yytext[0]))
+ grecs_error(&yylloc, 0,
+ _("stray character %c"), yytext[0]);
+ else
+ grecs_error(&yylloc, 0,
+ _("stray character \\%03o"),
+ (unsigned char) yytext[0]); }
+%%
+
+static int
+yywrap()
+{
+ return 1;
+}
+
+void
+forlan_lex_begin(const char *input, size_t length,
+ struct grecs_locus_point *pt)
+{
+ forlan_input_base = input;
+ forlan_input_len = length;
+ grecs_current_locus_point = *pt;
+ yy_flex_debug = debug_level(forlan_dbg) >= FORLAN_DBG_LEX;
+ grecs_line_acc_create();
+}
+
+void
+forlan_lex_end()
+{
+ grecs_line_acc_free();
+}
+
+
+
+
+
diff --git a/lib/libeclat.h b/lib/libeclat.h
index 670c51b..5f37cc9 100644
--- a/lib/libeclat.h
+++ b/lib/libeclat.h
@@ -18,6 +18,39 @@
#include <expat.h>
#include "grecs.h"
+extern const char *program_name;
+
+struct debug_category {
+ const char *name;
+ size_t length;
+ int level;
+};
+
+extern struct debug_category debug_category[];
+#define LIBECLAT_DBG_MAX 64
+
+#define debug_level(cat) ((cat >= 0 && cat < LIBECLAT_DBG_MAX) ? \
+ debug_category[cat].level : 0)
+#define debug(cat, lev, s) \
+ do { \
+ if (debug_level(cat) >= (lev)) \
+ debug_printf s; \
+ } while(0)
+
+void set_program_name(const char *arg);
+
+void die(int status, const char *fmt, ...);
+void vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt,
+ va_list ap);
+void diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...);
+void err(const char *fmt, ...);
+void warn(const char *fmt, ...);
+void debug_printf(const char *fmt, ...);
+
+int parse_debug_level(const char *arg);
+int debug_register(char *name);
+
+
void hmac_sha1(const void *text, size_t textlen,
const void *key, size_t keylen,
void *digest);
diff --git a/src/Makefile.am b/src/Makefile.am
index b5f7912..bda0584 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,7 +21,6 @@ eclat_SOURCES=\
cmdline.h\
config.c\
descrtags.c\
- diag.c\
eclat.c\
eclat.h\
startinst.c
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 82e0e95..1f8d56d 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -208,16 +208,6 @@ END
OPTIONS_END
void
-set_program_name(const char *arg)
-{
- program_name = strrchr(arg, '/');
- if (!program_name)
- program_name = arg;
- else
- program_name++;
-}
-
-void
parse_options(int argc, char *argv[], int *index)
{
GETOPT(argc, argv, *index, exit(EX_USAGE))
diff --git a/src/config.c b/src/config.c
index c40d307..b718486 100644
--- a/src/config.c
+++ b/src/config.c
@@ -149,7 +149,7 @@ config_finish(struct grecs_node *tree)
struct grecs_node *node;
grecs_tree_reduce(tree, eclat_kw, GRECS_AGGR);
- if (debug_level[ECLAT_DEBCAT_CONF]) {
+ if (debug_level(ECLAT_DEBCAT_CONF)) {
grecs_print_node(tree, GRECS_NODE_FLAG_DEFAULT, stderr);
fputc('\n', stdout);
}
diff --git a/src/diag.c b/src/diag.c
deleted file mode 100644
index 30ffa34..0000000
--- a/src/diag.c
+++ b/dev/null
@@ -1,108 +0,0 @@
-/* This file is part of Eclat.
- Copyright (C) 2012 Sergey Poznyakoff.
-
- Eclat 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.
-
- Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "eclat.h"
-
-const char *program_name;
-
-void
-vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, va_list ap)
-{
- if (program_name)
- fprintf(stderr, "%s: ", program_name);
-
- if (locus) {
- size_t size = 0;
-
- if (locus->beg.col == 0)
- fprintf(stderr, "%s:%u",
- locus->beg.file,
- locus->beg.line);
- else if (strcmp(locus->beg.file, locus->end.file))
- fprintf(stderr, "%s:%u.%u-%s:%u.%u",
- locus->beg.file,
- locus->beg.line, locus->beg.col,
- locus->end.file,
- locus->end.line, locus->end.col);
- else if (locus->beg.line != locus->end.line)
- fprintf(stderr, "%s:%u.%u-%u.%u",
- locus->beg.file,
- locus->beg.line, locus->beg.col,
- locus->end.line, locus->end.col);
- else
- fprintf(stderr, "%s:%u.%u-%u",
- locus->beg.file,
- locus->beg.line, locus->beg.col,
- locus->end.col);
- fprintf(stderr, ": ");
- }
-
- if (qual)
- fprintf(stderr, "%s: ", qual);
- vfprintf(stderr, fmt, ap);
- fputc('\n', stderr);
-}
-
-void
-diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vdiag(locus, qual, fmt, ap);
- va_end(ap);
-}
-
-void
-die(int status, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vdiag(NULL, NULL, fmt, ap);
- va_end(ap);
- exit(status);
-}
-
-void
-err(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vdiag(NULL, NULL, fmt, ap);
- va_end(ap);
-}
-
-void
-warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vdiag(NULL, "warning", fmt, ap);
- va_end(ap);
-}
-
-void
-debug_printf(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vdiag(NULL, "debug", fmt, ap);
- va_end(ap);
-}
diff --git a/src/eclat.c b/src/eclat.c
index 3703376..86b4627 100644
--- a/src/eclat.c
+++ b/src/eclat.c
@@ -18,7 +18,6 @@
char *conffile = SYSCONFDIR "/eclat.conf" ;
int lint_mode;
-int debug_level[ECLAT_DEBCAT_MAX];
int dry_run_mode;
int preprocess_only = 0;
@@ -30,59 +29,23 @@ char *region_name;
enum eclat_command eclat_command;
-struct debug_trans {
- const char *name;
- size_t length;
- int cat;
+static char *categories[] = {
+ "main",
+ "cfgram",
+ "cflex",
+ "conf",
+ "curl",
};
-static struct debug_trans debug_trans[] = {
-#define S(s) #s, sizeof(#s)-1
- { S(main), ECLAT_DEBCAT_MAIN },
- { S(cfgram), ECLAT_DEBCAT_CFGRAM },
- { S(cflex), ECLAT_DEBCAT_CFLEX },
- { S(conf), ECLAT_DEBCAT_CONF },
- { S(curl), ECLAT_DEBCAT_CURL },
- { NULL }
-};
-
-static int
-parse_debug_level(const char *arg)
+static void
+debug_init()
{
- unsigned long cat, lev;
- char *p;
+ int i;
- if (isascii(*arg) && isdigit(*arg)) {
- cat = strtoul(arg, &p, 10);
- if (cat > ECLAT_DEBCAT_MAX)
- return -1;
- } else {
- size_t len = strcspn(arg, ".");
- struct debug_trans *dp;
-
- for (dp = debug_trans; dp->name; dp++)
- if (dp->length == len &&
- memcmp(dp->name, arg, len) == 0)
- break;
-
- if (!dp->name)
- return -1;
- cat = dp->cat;
- p = (char*) arg + len;
- }
-
- if (*p == 0)
- lev = 100;
- else if (*p != '.')
- return -1;
- else {
- lev = strtoul(p + 1, &p, 10);
- if (*p)
- return -1;
- }
- debug_level[cat] = lev;
- return 0;
+ for (i = 0; i < sizeof(categories)/sizeof(categories[0]); i++)
+ debug_register(categories[i]);
}
+
static void
dump(const char *text, FILE *stream, unsigned char *ptr, size_t size)
@@ -90,7 +53,7 @@ dump(const char *text, FILE *stream, unsigned char *ptr, size_t size)
size_t i;
size_t c;
unsigned int width = 0x10;
- int hex = debug_level[ECLAT_DEBCAT_CURL] > 2;
+ int hex = debug_level(ECLAT_DEBCAT_CURL) > 2;
if (!hex)
/* without the hex output, we can fit more on screen */
@@ -199,7 +162,7 @@ write_callback(void *ptr, size_t size, size_t nmemb, void *data)
int column = XML_GetCurrentColumnNumber(parser);
/* FIXME: Debugging level. */
- if (debug_level[ECLAT_DEBCAT_MAIN] > 10) {
+ if (debug_level(ECLAT_DEBCAT_MAIN) > 10) {
dump_text(stderr, line, column, ptr, realsize);
}
status = XML_Parse(parser, ptr, realsize, 0);
@@ -215,7 +178,6 @@ write_callback(void *ptr, size_t size, size_t nmemb, void *data)
}
return realsize;
}
-
#include "cmdline.h"
@@ -237,14 +199,15 @@ main(int argc, char **argv)
struct grecs_node *xmltree;
set_program_name(argv[0]);
+ debug_init();
config_init();
parse_options(argc, argv, &index);
argc -= index;
argv += index;
-
- grecs_gram_trace(debug_level[ECLAT_DEBCAT_CFGRAM]);
- grecs_lex_trace(debug_level[ECLAT_DEBCAT_CFLEX]);
+
+ grecs_gram_trace(debug_level(ECLAT_DEBCAT_CFGRAM));
+ grecs_lex_trace(debug_level(ECLAT_DEBCAT_CFLEX));
if (preprocess_only)
exit(grecs_preproc_run(conffile, grecs_preprocessor) ?
@@ -292,9 +255,9 @@ main(int argc, char **argv)
if (!curl)
die(EX_UNAVAILABLE, "curl_easy_init failed");
- if (debug_level[ECLAT_DEBCAT_CURL]) {
+ if (debug_level(ECLAT_DEBCAT_CURL)) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- if (debug_level[ECLAT_DEBCAT_CURL] > 1)
+ if (debug_level(ECLAT_DEBCAT_CURL) > 1)
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
eclat_trace_fun);
}
diff --git a/src/eclat.h b/src/eclat.h
index b0d46ac..e588b57 100644
--- a/src/eclat.h
+++ b/src/eclat.h
@@ -33,10 +33,7 @@
#define ECLAT_DEBCAT_CFLEX 2
#define ECLAT_DEBCAT_CONF 3
#define ECLAT_DEBCAT_CURL 4
-#define ECLAT_DEBCAT_MAX 5
-
-extern const char *program_name;
-extern int debug_level[];
+#define ECLAT_DEBCAT_FORLAN 5
extern char *endpoint;
extern int use_ssl;
@@ -46,20 +43,6 @@ extern char *access_file_name;
extern char *access_key;
extern char *secret_key;
-#define debug(cat, lev, s) \
- do { \
- if (debug_level[cat] >= (lev)) \
- debug_printf s; \
- } while(0)
-
-void die(int status, const char *fmt, ...);
-void vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt,
- va_list ap);
-void diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...);
-void err(const char *fmt, ...);
-void warn(const char *fmt, ...);
-void debug_printf(const char *fmt, ...);
-
typedef int (*config_finish_hook_t) (void*);
void add_config_finish_hook(config_finish_hook_t fun, void *data);
diff --git a/src/error.c b/src/error.c
deleted file mode 100644
index 6c86d34..0000000
--- a/src/error.c
+++ b/dev/null
@@ -1,64 +0,0 @@
-/* This file is part of Eclat.
- Copyright (C) 2012 Sergey Poznyakoff.
-
- Eclat 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.
-
- Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "eclat.h"
-#include <stdargs.h>
-#include <stdio.h>
-
-char *program_name;
-
-void
-diag(const char *qual, const char *fmt, va_list ap)
-{
- if (program_name)
- fprintf(stderr, "%s: ", program_name);
- if (qual)
- fprintf(stderr, "%s: ", qual);
- va_start(ap, fmt);
- vfprintf(stderr, ftm, ap);
- va_end(ap);
- fputc('\n', stderr);
-}
-
-void
-err(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- diag(NULL, ftm, ap);
- va_end(ap);
-}
-
-void
-warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- diag("warning", ftm, ap);
- va_end(ap);
-}
-
-void
-debug_printf(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- diag("debug", ftm, ap);
- va_end(ap);
-}
diff --git a/tests/.gitignore b/tests/.gitignore
index 99d3c9c..8b76ee0 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -4,6 +4,7 @@ package.m4
testsuite
testsuite.dir
testsuite.log
+tforlan
thmac
turlenc
txml
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 82cae7e..4d567b3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -40,6 +40,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
## ------------ ##
TESTSUITE_AT = \
+ forlan01.at\
hmac01.at\
hmac02.at\
hmac03.at\
@@ -69,6 +70,7 @@ check-local: atconfig atlocal $(TESTSUITE)
# $(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin
noinst_PROGRAMS = \
+ tforlan\
thmac\
turlenc\
txml
diff --git a/tests/forlan01.at b/tests/forlan01.at
new file mode 100644
index 0000000..cf826e9
--- a/dev/null
+++ b/tests/forlan01.at
@@ -0,0 +1,77 @@
+# This file is part of Eclat -*- Autotest -*-
+# Copyright (C) 2012 Sergey Poznyakoff
+#
+# Eclat 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.
+#
+# Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([dump])
+AT_KEYWORDS([forlan forlan01])
+
+AT_DATA([input],[// test format for DescribeTags
+if (.DescribeTagsResponse) {
+ if (.DescribeTagsResponse.tagSet.item.resourceId[[i-deadbeef]] &&
+ parent(last).key[[hostname]])
+ print(parent(last).value);
+} else if (.Response.Errors)
+ error(.Response.Errors.Error.Message);
+else
+ dump();
+])
+
+AT_CHECK([tforlan -D input],
+[0],
+[0001: COND
+0002: NODE
+0003: COMP ABS
+0004: LIT: "DescribeTagsResponse"
+0005: IFTRUE 0001
+0006: COND
+0007: AND
+0008: NODE
+0009: COMP ABS
+0010: LIT: "DescribeTagsResponse"
+0011: LIT: "tagSet"
+0012: LIT: "item"
+0013: TEST: resourceId[[i-deadbeef]]
+0014: NODE
+0015: COMP
+0016: CALL: parent
+0017: LAST
+0018: TEST: key[[hostname]]
+0019: IFTRUE 0006
+0020: CALL: print
+0021: COMP
+0022: CALL: parent
+0023: LAST
+0024: LIT: "value"
+0025: IFFALSE 0006
+0026: IFFALSE 0001
+0027: COND
+0028: NODE
+0029: COMP ABS
+0030: LIT: "Response"
+0031: LIT: "Errors"
+0032: IFTRUE 0027
+0033: CALL: error
+0034: COMP ABS
+0035: LIT: "Response"
+0036: LIT: "Errors"
+0037: LIT: "Error"
+0038: LIT: "Message"
+0039: IFFALSE 0027
+0040: CALL: dump
+])
+
+AT_CLEANUP
+
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index f40b8a7..81e91f4 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -29,4 +29,8 @@ m4_include([urlenc01.at])
AT_BANNER([XML Processing])
m4_include([xml01.at])
+
+AT_BANNER([Forlan])
+m4_include([forlan01.at])
+
# End of testsuite.at
diff --git a/tests/tforlan.c b/tests/tforlan.c
new file mode 100644
index 0000000..9fc3495
--- a/dev/null
+++ b/tests/tforlan.c
@@ -0,0 +1,100 @@
+/* This file is part of Eclat.
+ Copyright (C) 2012 Sergey Poznyakoff.
+
+ Eclat 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.
+
+ Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+#include <errno.h>
+#include <sysexits.h>
+#include <libeclat.h>
+#include "forlan.h"
+#include <sys/stat.h>
+
+void
+usage()
+{
+ printf("usage: %s [-dD] FILE [INPUT]\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ FILE *fp;
+ char *buf;
+ size_t len;
+ struct stat st;
+ struct grecs_locus_point pt;
+ int rc;
+ int dump_option = 0;
+
+ set_program_name(argv[0]);
+ forlan_init();
+
+ while ((rc = getopt(argc, argv, "Dd:h")) != EOF)
+ switch (rc) {
+ case 'D':
+ dump_option++;
+ break;
+
+ case 'd':
+ if (parse_debug_level(optarg))
+ die(EX_USAGE, "bad debug category or level");
+ break;
+
+ case 'h':
+ usage();
+ return 0;
+
+ default:
+ exit(EX_USAGE);
+ }
+ argc -= optind;
+ argv += optind;
+
+
+ if (argc == 0 || argc > 2)
+ die(EX_USAGE, "one or two arguments expected");
+ if (stat(argv[0], &st))
+ die(EX_UNAVAILABLE, "cannot stat input file \"%s\": %s",
+ argv[0], strerror(errno));
+ len = st.st_size;
+ buf = grecs_malloc(len);
+ fp = fopen(argv[0], "r");
+ if (!fp)
+ die(EX_UNAVAILABLE, "cannot open input file \"%s\": %s",
+ argv[0], strerror(errno));
+ if (fread(buf, len, 1, fp) != 1)
+ die(EX_UNAVAILABLE, "error reading from \"%s\": %s",
+ argv[0], strerror(errno));
+ fclose(fp);
+
+ pt.file = argv[0];
+ pt.line = 1;
+ pt.col = 0;
+
+ rc = forlan_parse(buf, len, &pt);
+ if (rc == 0) {
+ if (dump_option)
+ forlan_dump_tree(stdout, forlan_parse_tree);
+ forlan_node_free(forlan_parse_tree);
+ }
+ return rc ? EX_UNAVAILABLE : 0;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.