-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | lib/.gitignore | 4 | ||||
-rw-r--r-- | lib/Makefile.am | 15 | ||||
-rw-r--r-- | lib/diag.c | 181 | ||||
-rw-r--r-- | lib/forlan.c | 258 | ||||
-rw-r--r-- | lib/forlan.h | 123 | ||||
-rw-r--r-- | lib/forlangrm.y | 237 | ||||
-rw-r--r-- | lib/forlanlex.l | 137 | ||||
-rw-r--r-- | lib/libeclat.h | 33 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/cmdline.opt | 10 | ||||
-rw-r--r-- | src/config.c | 2 | ||||
-rw-r--r-- | src/diag.c | 108 | ||||
-rw-r--r-- | src/eclat.c | 77 | ||||
-rw-r--r-- | src/eclat.h | 19 | ||||
-rw-r--r-- | src/error.c | 64 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/forlan01.at | 77 | ||||
-rw-r--r-- | tests/testsuite.at | 4 | ||||
-rw-r--r-- | tests/tforlan.c | 100 |
22 files changed, 1198 insertions, 261 deletions
@@ -1,11 +1,11 @@ | |||
1 | Eclat NEWS -- history of user-visible changes. 2012-09-19 | 1 | Eclat NEWS -- history of user-visible changes. 2012-09-22 |
2 | Copyright (C) 2012 Sergey Poznyakoff | 2 | Copyright (C) 2012 Sergey Poznyakoff |
3 | See the end of file for copying conditions. | 3 | See the end of file for copying conditions. |
4 | 4 | ||
5 | Please send Eclat bug reports to <gray+eclat@gnu.org.ua> | 5 | Please send Eclat bug reports to <gray+eclat@gnu.org.ua> |
6 | 6 | ||
7 | 7 | ||
8 | No news is good news. | 8 | Version 0.1 - No news is good news. |
9 | 9 | ||
10 | ========================================================================= | 10 | ========================================================================= |
11 | Copyright information: | 11 | 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]) | |||
27 | 27 | ||
28 | # Checks for programs. | 28 | # Checks for programs. |
29 | AC_PROG_CC | 29 | AC_PROG_CC |
30 | AC_PROG_LEX | ||
31 | AC_PROG_YACC | ||
30 | AC_PROG_RANLIB | 32 | AC_PROG_RANLIB |
31 | 33 | ||
32 | # Checks for header files. | 34 | # 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 @@ | |||
1 | forlangrm.c | ||
2 | forlangrm.h | ||
3 | forlangrm.output | ||
4 | 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 | |||
18 | 18 | ||
19 | libeclat_a_SOURCES=\ | 19 | libeclat_a_SOURCES=\ |
20 | base64.c\ | 20 | base64.c\ |
21 | diag.c\ | ||
22 | forlan.c\ | ||
23 | forlan.h\ | ||
24 | forlangrm.h\ | ||
25 | forlangrm.y\ | ||
26 | forlanlex.l\ | ||
21 | hmac_sha1.c\ | 27 | hmac_sha1.c\ |
22 | libeclat.h\ | 28 | libeclat.h\ |
23 | q2url.c\ | 29 | q2url.c\ |
@@ -33,3 +39,12 @@ libeclat_a_SOURCES=\ | |||
33 | 39 | ||
34 | AM_LDFLAGS = $(CURL_LIBS) | 40 | AM_LDFLAGS = $(CURL_LIBS) |
35 | INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) | 41 | INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) |
42 | |||
43 | forlanlex.c: forlangrm.h | ||
44 | forlangrm.c forlangrm.h: forlangrm.y | ||
45 | |||
46 | AM_YFLAGS=-tdv | ||
47 | AM_LFLAGS=-dvp | ||
48 | |||
49 | |||
50 | |||
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 @@ | |||
1 | /* This file is part of Eclat. | ||
2 | Copyright (C) 2012 Sergey Poznyakoff. | ||
3 | |||
4 | Eclat is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | Eclat is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include "libeclat.h" | ||
18 | #include <string.h> | ||
19 | #include <sysexits.h> | ||
20 | |||
21 | const char *program_name; | ||
22 | struct debug_category debug_category[LIBECLAT_DBG_MAX]; | ||
23 | int debug_avail; | ||
24 | |||
25 | void | ||
26 | set_program_name(const char *arg) | ||
27 | { | ||
28 | program_name = strrchr(arg, '/'); | ||
29 | if (!program_name) | ||
30 | program_name = arg; | ||
31 | else | ||
32 | program_name++; | ||
33 | } | ||
34 | |||
35 | void | ||
36 | vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, | ||
37 | va_list ap) | ||
38 | { | ||
39 | if (program_name) | ||
40 | fprintf(stderr, "%s: ", program_name); | ||
41 | |||
42 | if (locus) { | ||
43 | size_t size = 0; | ||
44 | |||
45 | if (locus->beg.col == 0) | ||
46 | fprintf(stderr, "%s:%u", | ||
47 | locus->beg.file, | ||
48 | locus->beg.line); | ||
49 | else if (strcmp(locus->beg.file, locus->end.file)) | ||
50 | fprintf(stderr, "%s:%u.%u-%s:%u.%u", | ||
51 | locus->beg.file, | ||
52 | locus->beg.line, locus->beg.col, | ||
53 | locus->end.file, | ||
54 | locus->end.line, locus->end.col); | ||
55 | else if (locus->beg.line != locus->end.line) | ||
56 | fprintf(stderr, "%s:%u.%u-%u.%u", | ||
57 | locus->beg.file, | ||
58 | locus->beg.line, locus->beg.col, | ||
59 | locus->end.line, locus->end.col); | ||
60 | else | ||
61 | fprintf(stderr, "%s:%u.%u-%u", | ||
62 | locus->beg.file, | ||
63 | locus->beg.line, locus->beg.col, | ||
64 | locus->end.col); | ||
65 | fprintf(stderr, ": "); | ||
66 | } | ||
67 | |||
68 | if (qual) | ||
69 | fprintf(stderr, "%s: ", qual); | ||
70 | vfprintf(stderr, fmt, ap); | ||
71 | fputc('\n', stderr); | ||
72 | } | ||
73 | |||
74 | void | ||
75 | diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...) | ||
76 | { | ||
77 | va_list ap; | ||
78 | |||
79 | va_start(ap, fmt); | ||
80 | vdiag(locus, qual, fmt, ap); | ||
81 | va_end(ap); | ||
82 | } | ||
83 | |||
84 | void | ||
85 | die(int status, const char *fmt, ...) | ||
86 | { | ||
87 | va_list ap; | ||
88 | |||
89 | va_start(ap, fmt); | ||
90 | vdiag(NULL, NULL, fmt, ap); | ||
91 | va_end(ap); | ||
92 | exit(status); | ||
93 | } | ||
94 | |||
95 | void | ||
96 | err(const char *fmt, ...) | ||
97 | { | ||
98 | va_list ap; | ||
99 | |||
100 | va_start(ap, fmt); | ||
101 | vdiag(NULL, NULL, fmt, ap); | ||
102 | va_end(ap); | ||
103 | } | ||
104 | |||
105 | void | ||
106 | warn(const char *fmt, ...) | ||
107 | { | ||
108 | va_list ap; | ||
109 | |||
110 | va_start(ap, fmt); | ||
111 | vdiag(NULL, "warning", fmt, ap); | ||
112 | va_end(ap); | ||
113 | } | ||
114 | |||
115 | void | ||
116 | debug_printf(const char *fmt, ...) | ||
117 | { | ||
118 | va_list ap; | ||
119 | |||
120 | va_start(ap, fmt); | ||
121 | vdiag(NULL, "debug", fmt, ap); | ||
122 | va_end(ap); | ||
123 | } | ||
124 | |||
125 | static struct debug_category * | ||
126 | find_category(const char *arg, size_t len) | ||
127 | { | ||
128 | struct debug_category *dp; | ||
129 | |||
130 | for (dp = debug_category; dp < debug_category + debug_avail; dp++) | ||
131 | if (dp->length == len && memcmp(dp->name, arg, len) == 0) | ||
132 | return dp; | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | int | ||
137 | parse_debug_level(const char *arg) | ||
138 | { | ||
139 | unsigned long lev; | ||
140 | char *p; | ||
141 | size_t len = strcspn(arg, "."); | ||
142 | struct debug_category *dp; | ||
143 | |||
144 | if (arg[len] == 0) { | ||
145 | lev = strtoul(arg, &p, 10); | ||
146 | if (*p) | ||
147 | return -1; | ||
148 | for (dp = debug_category; dp < debug_category + debug_avail; | ||
149 | dp++) | ||
150 | dp->level = lev; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | dp = find_category(arg, len); | ||
155 | if (!dp) | ||
156 | return -1; | ||
157 | |||
158 | p = (char*) arg + len; | ||
159 | if (*p == 0) | ||
160 | lev = 100; | ||
161 | else if (*p != '.') | ||
162 | return -1; | ||
163 | else { | ||
164 | lev = strtoul(p + 1, &p, 10); | ||
165 | if (*p) | ||
166 | return -1; | ||
167 | } | ||
168 | dp->level = lev; | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | int | ||
173 | debug_register(char *name) | ||
174 | { | ||
175 | if (debug_avail >= LIBECLAT_DBG_MAX) | ||
176 | die(EX_SOFTWARE, "no more debug slots available"); | ||
177 | debug_category[debug_avail].name = grecs_strdup(name); | ||
178 | debug_category[debug_avail].length = strlen(name); | ||
179 | debug_category[debug_avail].level = 0; | ||
180 | return debug_avail++; | ||
181 | } | ||
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 @@ | |||
1 | /* This file is part of Eclat. | ||
2 | Copyright (C) 2012 Sergey Poznyakoff. | ||
3 | |||
4 | Eclat is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | Eclat is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include "libeclat.h" | ||
18 | #include "grecs.h" | ||
19 | #include "forlan.h" | ||
20 | |||
21 | int forlan_dbg = -1; | ||
22 | |||
23 | void | ||
24 | forlan_init() | ||
25 | { | ||
26 | forlan_dbg = debug_register("forlan"); | ||
27 | } | ||
28 | |||
29 | union forlan_node * | ||
30 | forlan_node_create(enum forlan_type type) | ||
31 | { | ||
32 | union forlan_node *p = grecs_zalloc(sizeof(*p)); | ||
33 | p->type = type; | ||
34 | return p; | ||
35 | } | ||
36 | |||
37 | static void f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev); | ||
38 | |||
39 | |||
40 | static void | ||
41 | free_type_null(union forlan_node *p) | ||
42 | { | ||
43 | warn("freeing undefined forlan_node"); | ||
44 | } | ||
45 | |||
46 | void | ||
47 | dump_null(FILE *fp, union forlan_node *p, int *num, int lev) | ||
48 | { | ||
49 | fprintf(fp, "[undefined node]\n"); | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | free_type_comp(union forlan_node *p) | ||
54 | { | ||
55 | forlan_node_free(p->comp.node); | ||
56 | } | ||
57 | void | ||
58 | dump_comp(FILE *fp, union forlan_node *p, int *num, int lev) | ||
59 | { | ||
60 | fprintf(fp, "COMP"); | ||
61 | if (p->comp.abs) | ||
62 | fprintf(fp, " ABS"); | ||
63 | fputc('\n', fp); | ||
64 | forlan_dump_node(fp, p->comp.node, num, lev + 1); | ||
65 | } | ||
66 | |||
67 | static void | ||
68 | free_type_test(union forlan_node *p) | ||
69 | { | ||
70 | free(p->test.comp); | ||
71 | free(p->test.value); | ||
72 | } | ||
73 | void | ||
74 | dump_test(FILE *fp, union forlan_node *p, int *num, int lev) | ||
75 | { | ||
76 | fprintf(fp, "TEST: %s[%s]\n", p->test.comp, p->test.value); | ||
77 | } | ||
78 | |||
79 | static void | ||
80 | free_type_func(union forlan_node *p) | ||
81 | { | ||
82 | grecs_list_free(p->func.args); | ||
83 | } | ||
84 | void | ||
85 | dump_func(FILE *fp, union forlan_node *p, int *num, int lev) | ||
86 | { | ||
87 | struct grecs_list_entry *ep; | ||
88 | fprintf(fp, "CALL: %s\n", p->func.fp); | ||
89 | if (p->func.args) | ||
90 | for (ep = p->func.args->head; ep; ep = ep->next) | ||
91 | forlan_dump_node(fp, ep->data, num, lev + 1); | ||
92 | } | ||
93 | |||
94 | static void | ||
95 | free_type_cond(union forlan_node *p) | ||
96 | { | ||
97 | forlan_node_free((union forlan_node *)p->cond.expr); | ||
98 | forlan_node_free(p->cond.iftrue); | ||
99 | forlan_node_free(p->cond.iffalse); | ||
100 | } | ||
101 | void | ||
102 | dump_cond(FILE *fp, union forlan_node *p, int *num, int lev) | ||
103 | { | ||
104 | int n = *num; | ||
105 | fprintf(fp, "COND\n"); | ||
106 | forlan_dump_node(fp, p->cond.expr, num, lev + 1); | ||
107 | fprintf(fp, "%04d: %*.*sIFTRUE %04d\n", ++*num, lev, lev, "", n); | ||
108 | forlan_dump_node(fp, p->cond.iftrue, num, lev + 1); | ||
109 | fprintf(fp, "%04d: %*.*sIFFALSE %04d\n", ++*num, lev, lev, "", n); | ||
110 | forlan_dump_node(fp, p->cond.iffalse, num, lev + 1); | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | free_type_stmt(union forlan_node *p) | ||
115 | { | ||
116 | forlan_node_free(p->stmt.stmt); | ||
117 | forlan_node_free(p->stmt.next); | ||
118 | } | ||
119 | void | ||
120 | dump_stmt(FILE *fp, union forlan_node *p, int *num, int lev) | ||
121 | { | ||
122 | f_dump_node(fp, p->stmt.stmt, num, lev); | ||
123 | forlan_dump_node(fp, p->stmt.next, num, lev); | ||
124 | } | ||
125 | |||
126 | static void | ||
127 | free_type_lit(union forlan_node *p) | ||
128 | { | ||
129 | free(p->lit.string); | ||
130 | } | ||
131 | void | ||
132 | dump_lit(FILE *fp, union forlan_node *p, int *num, int lev) | ||
133 | { | ||
134 | fprintf(fp, "LIT: \"%s\"\n", p->lit.string); | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | free_type_expr(union forlan_node *p) | ||
139 | { | ||
140 | forlan_node_free(p->expr.arg[0]); | ||
141 | forlan_node_free(p->expr.arg[1]); | ||
142 | } | ||
143 | void | ||
144 | dump_expr(FILE *fp, union forlan_node *p, int *num, int lev) | ||
145 | { | ||
146 | static char *opstr[] = { "NODE", "AND", "OR", "NOT" }; | ||
147 | |||
148 | fprintf(fp, "%s\n", opstr[p->expr.opcode]); | ||
149 | forlan_dump_node(fp, p->expr.arg[0], num, lev + 1); | ||
150 | if (p->expr.arg[1]) | ||
151 | forlan_dump_node(fp, p->expr.arg[1], num, lev + 1); | ||
152 | } | ||
153 | |||
154 | static void | ||
155 | free_type_last(union forlan_node *p) | ||
156 | { | ||
157 | } | ||
158 | void | ||
159 | dump_last(FILE *fp, union forlan_node *p, int *num, int lev) | ||
160 | { | ||
161 | fprintf(fp, "LAST\n"); | ||
162 | } | ||
163 | |||
164 | struct forlan_node_method { | ||
165 | void (*f_free)(union forlan_node *); | ||
166 | void (*f_dump)(FILE *fp, union forlan_node *node, int *num, int lev); | ||
167 | }; | ||
168 | |||
169 | static struct forlan_node_method f_tab[] = { | ||
170 | free_type_null, dump_null, /* Unknown/unset type */ | ||
171 | free_type_comp, dump_comp, /* A path component */ | ||
172 | free_type_test, dump_test, /* Value test (f[X]) */ | ||
173 | free_type_func, dump_func, /* Function call */ | ||
174 | free_type_cond, dump_cond, /* Conditional */ | ||
175 | free_type_stmt, dump_stmt, /* Statement */ | ||
176 | free_type_lit, dump_lit, /* Literal */ | ||
177 | free_type_expr, dump_expr, /* Boolean expression */ | ||
178 | free_type_last, dump_last, /* "last" */ | ||
179 | }; | ||
180 | |||
181 | void | ||
182 | forlan_node_free(union forlan_node *p) | ||
183 | { | ||
184 | if (!p) | ||
185 | return; | ||
186 | if (p->type > sizeof(f_tab) / sizeof(f_tab[0])) | ||
187 | abort(); | ||
188 | if (f_tab[p->type].f_free) | ||
189 | f_tab[p->type].f_free(p); | ||
190 | free(p); | ||
191 | } | ||
192 | |||
193 | static void | ||
194 | stmt_list_free_entry(void *p) | ||
195 | { | ||
196 | forlan_node_free(p); | ||
197 | } | ||
198 | |||
199 | struct grecs_list * | ||
200 | forlan_stmt_list() | ||
201 | { | ||
202 | struct grecs_list *lp; | ||
203 | |||
204 | lp = grecs_list_create(); | ||
205 | lp->free_entry = stmt_list_free_entry; | ||
206 | return lp; | ||
207 | } | ||
208 | |||
209 | union forlan_node * | ||
210 | forlan_stmt_from_list(struct grecs_list *list) | ||
211 | { | ||
212 | union forlan_node **tail = NULL, *ret = NULL; | ||
213 | struct grecs_list_entry *ep; | ||
214 | |||
215 | for (ep = list->head; ep; ep = ep->next) { | ||
216 | union forlan_node *sp = forlan_node_create(forlan_type_stmt); | ||
217 | sp->stmt.stmt = ep->data; | ||
218 | if (tail) | ||
219 | *tail = sp; | ||
220 | else | ||
221 | ret = sp; | ||
222 | tail = &sp->stmt.next; | ||
223 | } | ||
224 | list->free_entry = NULL; | ||
225 | grecs_list_free(list); | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static void | ||
230 | f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev) | ||
231 | { | ||
232 | if (p) { | ||
233 | if (p->type > sizeof(f_tab) / sizeof(f_tab[0])) | ||
234 | abort(); | ||
235 | if (f_tab[p->type].f_dump) | ||
236 | f_tab[p->type].f_dump(fp, p, num, lev); | ||
237 | else | ||
238 | fprintf(fp, "type %d", p->type); | ||
239 | } else | ||
240 | fprintf(fp, "NULL"); | ||
241 | } | ||
242 | |||
243 | void | ||
244 | forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev) | ||
245 | { | ||
246 | if (!p) | ||
247 | return; | ||
248 | ++*num; | ||
249 | fprintf(fp, "%04d: %*.*s", *num, lev, lev, ""); | ||
250 | f_dump_node(fp, p, num, lev); | ||
251 | } | ||
252 | |||
253 | void | ||
254 | forlan_dump_tree(FILE *fp, union forlan_node *node) | ||
255 | { | ||
256 | int n = 0; | ||
257 | forlan_dump_node(fp, node, &n, 0); | ||
258 | } | ||
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 @@ | |||
1 | /* This file is part of Eclat. | ||
2 | Copyright (C) 2012 Sergey Poznyakoff. | ||
3 | |||
4 | Eclat is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | Eclat is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #define FORLAN_DBG_LEX 3 | ||
18 | #define FORLAN_DBG_GRAM 2 | ||
19 | #define FORLAN_DBG_EVAL 1 | ||
20 | |||
21 | extern int forlan_dbg; | ||
22 | |||
23 | void forlan_init(); | ||
24 | void forlan_lex_begin(const char *input, size_t length, | ||
25 | struct grecs_locus_point *pt); | ||
26 | void forlan_lex_end(void); | ||
27 | int forlan_parse(const char *input, size_t length, | ||
28 | struct grecs_locus_point *pt); | ||
29 | |||
30 | union forlan_node; /* Declared below */ | ||
31 | |||
32 | enum forlan_type { | ||
33 | forlan_type_null, /* Unknown/unset type */ | ||
34 | forlan_type_comp, /* A path component */ | ||
35 | forlan_type_test,/* Value test (f[X]) */ | ||
36 | forlan_type_func,/* Function call */ | ||
37 | forlan_type_cond,/* Conditional */ | ||
38 | forlan_type_stmt,/* Statement */ | ||
39 | forlan_type_lit,/* Literal */ | ||
40 | forlan_type_expr, /* Boolean expression */ | ||
41 | forlan_type_last /* Return last evaluated grecs_node */ | ||
42 | }; | ||
43 | |||
44 | /* A path component */ | ||
45 | struct forlan_node_comp { | ||
46 | enum forlan_type type; | ||
47 | int abs; | ||
48 | union forlan_node *node; | ||
49 | }; | ||
50 | |||
51 | /* Path test: .path.comp[value] */ | ||
52 | struct forlan_node_test { | ||
53 | enum forlan_type type; | ||
54 | char *comp; | ||
55 | char *value; | ||
56 | }; | ||
57 | |||
58 | /* Function call */ | ||
59 | struct forlan_node_func { | ||
60 | enum forlan_type type; | ||
61 | void *fp; /* FIXME: replace with typedef */ | ||
62 | struct grecs_list *args; /* Arguments are struct forlan_node * */ | ||
63 | }; | ||
64 | |||
65 | /* Conditional */ | ||
66 | struct forlan_node_cond { | ||
67 | enum forlan_type type; | ||
68 | union forlan_node *expr; /* Controlling expression */ | ||
69 | union forlan_node *iftrue; /* Run this if expr yields true */ | ||
70 | union forlan_node *iffalse; /* Run this if expr yields false */ | ||
71 | }; | ||
72 | |||
73 | /* Statement or statement list */ | ||
74 | struct forlan_node_stmt { | ||
75 | enum forlan_type type; | ||
76 | union forlan_node *stmt; | ||
77 | union forlan_node *next; | ||
78 | }; | ||
79 | |||
80 | /* Literal string */ | ||
81 | struct forlan_node_lit { | ||
82 | enum forlan_type type; | ||
83 | char *string; | ||
84 | }; | ||
85 | |||
86 | /* Boolean opcodes */ | ||
87 | enum forlan_opcode { | ||
88 | forlan_opcode_node, /* Evaluate node, set 'last' */ | ||
89 | forlan_opcode_and, /* Boolean AND */ | ||
90 | forlan_opcode_or, /* Boolean OR */ | ||
91 | forlan_opcode_not /* Boolean NOT */ | ||
92 | }; | ||
93 | |||
94 | /* Boolean expression */ | ||
95 | struct forlan_node_expr { | ||
96 | enum forlan_type type; | ||
97 | enum forlan_opcode opcode; | ||
98 | union forlan_node *arg[2]; | ||
99 | }; | ||
100 | |||
101 | /* Now get all this together */ | ||
102 | union forlan_node { | ||
103 | enum forlan_type type; | ||
104 | struct forlan_node_comp comp; /* A path component */ | ||
105 | struct forlan_node_test test; /* Value test (f[X]) */ | ||
106 | struct forlan_node_func func; /* Function call */ | ||
107 | struct forlan_node_cond cond; /* Conditional */ | ||
108 | struct forlan_node_stmt stmt; /* Statement */ | ||
109 | struct forlan_node_lit lit; /* Literal */ | ||
110 | struct forlan_node_expr expr; /* Boolean expression */ | ||
111 | /* forlan_type_last needs no additional data */ | ||
112 | }; | ||
113 | |||
114 | union forlan_node *forlan_node_create(enum forlan_type type); | ||
115 | void forlan_node_free(union forlan_node *); | ||
116 | struct grecs_list *forlan_stmt_list(void); | ||
117 | struct grecs_list *forlan_complist(void); | ||
118 | union forlan_node *forlan_stmt_from_list(struct grecs_list *list); | ||
119 | |||
120 | extern union forlan_node *forlan_parse_tree; | ||
121 | |||
122 | void forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev); | ||
123 | 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 @@ | |||
1 | %{ | ||
2 | /* This file is part of Eclat. | ||
3 | Copyright (C) 2012 Sergey Poznyakoff. | ||
4 | |||
5 | Eclat is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 3, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | Eclat is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #include "libeclat.h" | ||
19 | #include <grecs.h> | ||
20 | #include <grecs-locus.h> | ||
21 | #include "forlangrm.h" | ||
22 | #include "forlan.h" | ||
23 | |||
24 | static int yyerror(char *); | ||
25 | union forlan_node *forlan_parse_tree; | ||
26 | %} | ||
27 | %error-verbose | ||
28 | %locations | ||
29 | |||
30 | %union { | ||
31 | char *string; | ||
32 | union forlan_node *node; | ||
33 | struct grecs_list *list; | ||
34 | }; | ||
35 | |||
36 | %token <string> STRING IDENT | ||
37 | %token LAST IF ELSE | ||
38 | |||
39 | %left OR | ||
40 | %left AND | ||
41 | %left NOT | ||
42 | |||
43 | %type <node> stmt stmt_cond stmt_expr stmt_blk cond bool node comp funcall arg | ||
44 | %type <list> stmtlist complist arglist | ||
45 | %type <string> string | ||
46 | |||
47 | %% | ||
48 | input : stmtlist | ||
49 | { | ||
50 | forlan_parse_tree = forlan_stmt_from_list($1); | ||
51 | } | ||
52 | ; | ||
53 | |||
54 | stmtlist : stmt | ||
55 | { | ||
56 | $$ = forlan_stmt_list(); | ||
57 | grecs_list_append($$, $1); | ||
58 | } | ||
59 | | stmtlist stmt | ||
60 | { | ||
61 | grecs_list_append($1, $2); | ||
62 | $$ = $1; | ||
63 | } | ||
64 | ; | ||
65 | |||
66 | stmt : stmt_cond | ||
67 | | stmt_expr | ||
68 | | stmt_blk | ||
69 | ; | ||
70 | |||
71 | stmt_blk : '{' stmtlist '}' | ||
72 | { | ||
73 | $$ = forlan_stmt_from_list($2); | ||
74 | } | ||
75 | ; | ||
76 | |||
77 | stmt_cond : IF cond stmt | ||
78 | { | ||
79 | $$ = forlan_node_create(forlan_type_cond); | ||
80 | $$->cond.expr = $2; | ||
81 | $$->cond.iftrue = $3; | ||
82 | $$->cond.iffalse = NULL; | ||
83 | } | ||
84 | | IF cond stmt ELSE stmt | ||
85 | { | ||
86 | $$ = forlan_node_create(forlan_type_cond); | ||
87 | $$->cond.expr = $2; | ||
88 | $$->cond.iftrue = $3; | ||
89 | $$->cond.iffalse = $5; | ||
90 | } | ||
91 | ; | ||
92 | |||
93 | cond : bool | ||
94 | ; | ||
95 | |||
96 | bool : node | ||
97 | { | ||
98 | $$ = forlan_node_create(forlan_type_expr); | ||
99 | $$->expr.opcode = forlan_opcode_node; | ||
100 | $$->expr.arg[0] = $1; | ||
101 | } | ||
102 | | bool AND bool | ||
103 | { | ||
104 | $$ = forlan_node_create(forlan_type_expr); | ||
105 | $$->expr.opcode = forlan_opcode_and; | ||
106 | $$->expr.arg[0] = $1; | ||
107 | $$->expr.arg[1] = $3; | ||
108 | } | ||
109 | | bool OR bool | ||
110 | { | ||
111 | $$ = forlan_node_create(forlan_type_expr); | ||
112 | $$->expr.opcode = forlan_opcode_or; | ||
113 | $$->expr.arg[0] = $1; | ||
114 | $$->expr.arg[1] = $3; | ||
115 | } | ||
116 | | NOT bool | ||
117 | { | ||
118 | $$ = forlan_node_create(forlan_type_expr); | ||
119 | $$->expr.opcode = forlan_opcode_not; | ||
120 | $$->expr.arg[0] = $2; | ||
121 | } | ||
122 | | '(' bool ')' | ||
123 | { | ||
124 | $$ = $2; | ||
125 | } | ||
126 | ; | ||
127 | |||
128 | node : complist | ||
129 | { | ||
130 | $$ = forlan_node_create(forlan_type_comp); | ||
131 | $$->comp.abs = 0; | ||
132 | $$->comp.node = forlan_stmt_from_list($1); | ||
133 | } | ||
134 | | '.' complist | ||
135 | { | ||
136 | $$ = forlan_node_create(forlan_type_comp); | ||
137 | $$->comp.abs = 1; | ||
138 | $$->comp.node = forlan_stmt_from_list($2); | ||
139 | } | ||
140 | | LAST | ||
141 | { | ||
142 | $$ = forlan_node_create(forlan_type_last); | ||
143 | } | ||
144 | ; | ||
145 | |||
146 | complist : comp | ||
147 | { | ||
148 | $$ = forlan_stmt_list(); | ||
149 | grecs_list_append($$, $1); | ||
150 | } | ||
151 | | complist '.' comp | ||
152 | { | ||
153 | grecs_list_append($1, $3); | ||
154 | $$ = $1; | ||
155 | } | ||
156 | ; | ||
157 | |||
158 | comp : IDENT | ||
159 | { | ||
160 | $$ = forlan_node_create(forlan_type_lit); | ||
161 | $$->lit.string = $1; | ||
162 | } | ||
163 | | IDENT '[' string ']' | ||
164 | { | ||
165 | $$ = forlan_node_create(forlan_type_test); | ||
166 | $$->test.comp = $1; | ||
167 | $$->test.value = $3; | ||
168 | } | ||
169 | | funcall | ||
170 | ; | ||
171 | |||
172 | string : IDENT | ||
173 | | STRING | ||
174 | ; | ||
175 | |||
176 | funcall : IDENT '(' ')' | ||
177 | { | ||
178 | $$ = forlan_node_create(forlan_type_func); | ||
179 | $$->func.fp = $1; //FIXME | ||
180 | $$->func.args = NULL; | ||
181 | } | ||
182 | | IDENT '(' arglist ')' | ||
183 | { | ||
184 | $$ = forlan_node_create(forlan_type_func); | ||
185 | $$->func.fp = $1; //FIXME | ||
186 | $$->func.args = $3; | ||
187 | } | ||
188 | ; | ||
189 | |||
190 | arglist : arg | ||
191 | { | ||
192 | $$ = forlan_stmt_list(); | ||
193 | grecs_list_append($$, $1); | ||
194 | } | ||
195 | | arglist ',' arg | ||
196 | { | ||
197 | grecs_list_append($1, $3); | ||
198 | $$ = $1; | ||
199 | } | ||
200 | ; | ||
201 | |||
202 | arg : node | ||
203 | | STRING | ||
204 | { | ||
205 | $$ = forlan_node_create(forlan_type_lit); | ||
206 | $$->lit.string = $1; | ||
207 | } | ||
208 | ; | ||
209 | |||
210 | stmt_expr : funcall ';' | ||
211 | ; | ||
212 | %% | ||
213 | static int | ||
214 | yyerror(char *s) | ||
215 | { | ||
216 | grecs_error(&yylloc, 0, "%s", s); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | int | ||
221 | forlan_parser() | ||
222 | { | ||
223 | yydebug = debug_level(forlan_dbg) >= FORLAN_DBG_GRAM; | ||
224 | return yyparse(); | ||
225 | } | ||
226 | |||
227 | int | ||
228 | forlan_parse(const char *input, size_t length, struct grecs_locus_point *pt) | ||
229 | { | ||
230 | int rc; | ||
231 | forlan_lex_begin(input, length, pt); | ||
232 | rc = forlan_parser(); | ||
233 | forlan_lex_end(); | ||
234 | return rc; | ||
235 | } | ||
236 | |||
237 | |||
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 @@ | |||
1 | %{ | ||
2 | /* This file is part of Eclat. | ||
3 | Copyright (C) 2012 Sergey Poznyakoff. | ||
4 | |||
5 | Eclat is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 3, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | Eclat is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #include "libeclat.h" | ||
19 | #include <grecs.h> | ||
20 | #include <grecs-locus.h> | ||
21 | #include "forlangrm.h" | ||
22 | #include "forlan.h" | ||
23 | |||
24 | static const char *forlan_input_base; | ||
25 | static size_t forlan_input_len; | ||
26 | static size_t forlan_input_pos; | ||
27 | |||
28 | #undef YY_INPUT | ||
29 | #define YY_INPUT(buf,result,max_size) \ | ||
30 | do { \ | ||
31 | size_t __s = forlan_input_len - forlan_input_pos; \ | ||
32 | if (__s > max_size) \ | ||
33 | __s = max_size; \ | ||
34 | if (__s > 0) { \ | ||
35 | memcpy(buf, forlan_input_base, __s); \ | ||
36 | forlan_input_pos += __s; \ | ||
37 | } \ | ||
38 | result = __s; \ | ||
39 | } while(0) | ||
40 | |||
41 | #define YY_USER_ACTION do { \ | ||
42 | if (YYSTATE == 0) { \ | ||
43 | yylloc.beg = grecs_current_locus_point; \ | ||
44 | yylloc.beg.col++; \ | ||
45 | } \ | ||
46 | grecs_current_locus_point.col += yyleng; \ | ||
47 | yylloc.end = grecs_current_locus_point; \ | ||
48 | } while (0); | ||
49 | |||
50 | static int yywrap(void); | ||
51 | |||
52 | %} | ||
53 | |||
54 | WS [ \t\f][ \t\f]* | ||
55 | IDC [a-zA-Z_0-9-] | ||
56 | %x COMMENT ML STR | ||
57 | %% | ||
58 | /* Comments */ | ||
59 | "/*" BEGIN(COMMENT); | ||
60 | <COMMENT>[^*\n]* /* eat anything that's not a '*' */ | ||
61 | <COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ | ||
62 | <COMMENT>\n grecs_locus_point_advance_line(grecs_current_locus_point); | ||
63 | <COMMENT>"*"+"/" BEGIN(INITIAL); | ||
64 | "//".* ; | ||
65 | /* Keywords */ | ||
66 | if return IF; | ||
67 | else return ELSE; | ||
68 | last return LAST; | ||
69 | ! return NOT; | ||
70 | "&&" return AND; | ||
71 | "||" return OR; | ||
72 | {IDC}{IDC}* { grecs_line_begin(); | ||
73 | grecs_line_add(yytext, yyleng); | ||
74 | yylval.string = grecs_line_finish(); | ||
75 | return IDENT; } | ||
76 | /* Quoted strings */ | ||
77 | \"[^\\"\n]*\" { grecs_line_begin(); | ||
78 | grecs_line_add(yytext + 1, yyleng - 2); | ||
79 | yylval.string = grecs_line_finish(); | ||
80 | return STRING; } | ||
81 | \"[^\\"\n]*\\\n { BEGIN(STR); | ||
82 | grecs_line_begin(); | ||
83 | grecs_line_acc_grow_unescape_last(yytext + 1, | ||
84 | yyleng - 1); | ||
85 | grecs_locus_point_advance_line(grecs_current_locus_point); } | ||
86 | \"[^\\"\n]*\\. { BEGIN(STR); | ||
87 | grecs_line_begin(); | ||
88 | grecs_line_acc_grow_unescape_last(yytext + 1, | ||
89 | yyleng - 1); } | ||
90 | <STR>\"[^\\"\n]*\\\n { grecs_line_acc_grow_unescape_last(yytext, yyleng); | ||
91 | grecs_locus_point_advance_line(grecs_current_locus_point); } | ||
92 | <STR>[^\\"\n]*\\. { grecs_line_acc_grow_unescape_last(yytext, yyleng); } | ||
93 | <STR>[^\\"\n]*\" { BEGIN(INITIAL); | ||
94 | if (yyleng > 1) | ||
95 | grecs_line_add(yytext, yyleng - 1); | ||
96 | yylval.string = grecs_line_finish(); | ||
97 | return STRING; } | ||
98 | /* Other tokens */ | ||
99 | {WS} ; | ||
100 | \n { grecs_locus_point_advance_line(grecs_current_locus_point); } | ||
101 | [.,;{}()\[\]] return yytext[0]; | ||
102 | . { if (isascii(yytext[0]) && isprint(yytext[0])) | ||
103 | grecs_error(&yylloc, 0, | ||
104 | _("stray character %c"), yytext[0]); | ||
105 | else | ||
106 | grecs_error(&yylloc, 0, | ||
107 | _("stray character \\%03o"), | ||
108 | (unsigned char) yytext[0]); } | ||
109 | %% | ||
110 | |||
111 | static int | ||
112 | yywrap() | ||
113 | { | ||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | void | ||
118 | forlan_lex_begin(const char *input, size_t length, | ||
119 | struct grecs_locus_point *pt) | ||
120 | { | ||
121 | forlan_input_base = input; | ||
122 | forlan_input_len = length; | ||
123 | grecs_current_locus_point = *pt; | ||
124 | yy_flex_debug = debug_level(forlan_dbg) >= FORLAN_DBG_LEX; | ||
125 | grecs_line_acc_create(); | ||
126 | } | ||
127 | |||
128 | void | ||
129 | forlan_lex_end() | ||
130 | { | ||
131 | grecs_line_acc_free(); | ||
132 | } | ||
133 | |||
134 | |||
135 | |||
136 | |||
137 | |||
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 @@ | |||
18 | #include <expat.h> | 18 | #include <expat.h> |
19 | #include "grecs.h" | 19 | #include "grecs.h" |
20 | 20 | ||
21 | extern const char *program_name; | ||
22 | |||
23 | struct debug_category { | ||
24 | const char *name; | ||
25 | size_t length; | ||
26 | int level; | ||
27 | }; | ||
28 | |||
29 | extern struct debug_category debug_category[]; | ||
30 | #define LIBECLAT_DBG_MAX 64 | ||
31 | |||
32 | #define debug_level(cat) ((cat >= 0 && cat < LIBECLAT_DBG_MAX) ?\ | ||
33 | debug_category[cat].level : 0) | ||
34 | #define debug(cat, lev, s) \ | ||
35 | do { \ | ||
36 | if (debug_level(cat) >= (lev)) \ | ||
37 | debug_printf s; \ | ||
38 | } while(0) | ||
39 | |||
40 | void set_program_name(const char *arg); | ||
41 | |||
42 | void die(int status, const char *fmt, ...); | ||
43 | void vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, | ||
44 | va_list ap); | ||
45 | void diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...); | ||
46 | void err(const char *fmt, ...); | ||
47 | void warn(const char *fmt, ...); | ||
48 | void debug_printf(const char *fmt, ...); | ||
49 | |||
50 | int parse_debug_level(const char *arg); | ||
51 | int debug_register(char *name); | ||
52 | |||
53 | |||
21 | void hmac_sha1(const void *text, size_t textlen, | 54 | void hmac_sha1(const void *text, size_t textlen, |
22 | const void *key, size_t keylen, | 55 | const void *key, size_t keylen, |
23 | void *digest); | 56 | 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=\ | |||
21 | cmdline.h\ | 21 | cmdline.h\ |
22 | config.c\ | 22 | config.c\ |
23 | descrtags.c\ | 23 | descrtags.c\ |
24 | diag.c\ | ||
25 | eclat.c\ | 24 | eclat.c\ |
26 | eclat.h\ | 25 | eclat.h\ |
27 | startinst.c | 26 | 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 | |||
208 | OPTIONS_END | 208 | OPTIONS_END |
209 | 209 | ||
210 | void | 210 | void |
211 | set_program_name(const char *arg) | ||
212 | { | ||
213 | program_name = strrchr(arg, '/'); | ||
214 | if (!program_name) | ||
215 | program_name = arg; | ||
216 | else | ||
217 | program_name++; | ||
218 | } | ||
219 | |||
220 | void | ||
221 | parse_options(int argc, char *argv[], int *index) | 211 | parse_options(int argc, char *argv[], int *index) |
222 | { | 212 | { |
223 | GETOPT(argc, argv, *index, exit(EX_USAGE)) | 213 | 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) | |||
149 | struct grecs_node *node; | 149 | struct grecs_node *node; |
150 | 150 | ||
151 | grecs_tree_reduce(tree, eclat_kw, GRECS_AGGR); | 151 | grecs_tree_reduce(tree, eclat_kw, GRECS_AGGR); |
152 | if (debug_level[ECLAT_DEBCAT_CONF]) { | 152 | if (debug_level(ECLAT_DEBCAT_CONF)) { |
153 | grecs_print_node(tree, GRECS_NODE_FLAG_DEFAULT, stderr); | 153 | grecs_print_node(tree, GRECS_NODE_FLAG_DEFAULT, stderr); |
154 | fputc('\n', stdout); | 154 | fputc('\n', stdout); |
155 | } | 155 | } |
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 @@ | |||
1 | /* This file is part of Eclat. | ||
2 | Copyright (C) 2012 Sergey Poznyakoff. | ||
3 | |||
4 | Eclat is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | Eclat is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include "eclat.h" | ||
18 | |||
19 | const char *program_name; | ||
20 | |||
21 | void | ||
22 | vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, va_list ap) | ||
23 | { | ||
24 | if (program_name) | ||
25 | fprintf(stderr, "%s: ", program_name); | ||
26 | |||
27 | if (locus) { | ||
28 | size_t size = 0; | ||
29 | |||
30 | if (locus->beg.col == 0) | ||
31 | fprintf(stderr, "%s:%u", | ||
32 | locus->beg.file, | ||
33 | locus->beg.line); | ||
34 | else if (strcmp(locus->beg.file, locus->end.file)) | ||
35 | fprintf(stderr, "%s:%u.%u-%s:%u.%u", | ||
36 | locus->beg.file, | ||
37 | locus->beg.line, locus->beg.col, | ||
38 | locus->end.file, | ||
39 | locus->end.line, locus->end.col); | ||
40 | else if (locus->beg.line != locus->end.line) | ||
41 | fprintf(stderr, "%s:%u.%u-%u.%u", | ||
42 | locus->beg.file, | ||
43 | locus->beg.line, locus->beg.col, | ||
44 | locus->end.line, locus->end.col); | ||
45 | else | ||
46 | fprintf(stderr, "%s:%u.%u-%u", | ||
47 | locus->beg.file, | ||
48 | locus->beg.line, locus->beg.col, | ||
49 | locus->end.col); | ||
50 | fprintf(stderr, ": "); | ||
51 | } | ||
52 | |||
53 | if (qual) | ||
54 | fprintf(stderr, "%s: ", qual); | ||
55 | vfprintf(stderr, fmt, ap); | ||
56 | fputc('\n', stderr); | ||
57 | } | ||
58 | |||
59 | void | ||
60 | diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...) | ||
61 | { | ||
62 | va_list ap; | ||
63 | |||
64 | va_start(ap, fmt); | ||
65 | vdiag(locus, qual, fmt, ap); | ||
66 | va_end(ap); | ||
67 | } | ||
68 | |||
69 | void | ||
70 | die(int status, const char *fmt, ...) | ||
71 | { | ||
72 | va_list ap; | ||
73 | |||
74 | va_start(ap, fmt); | ||
75 | vdiag(NULL, NULL, fmt, ap); | ||
76 | va_end(ap); | ||
77 | exit(status); | ||
78 | } | ||
79 | |||
80 | void | ||
81 | err(const char *fmt, ...) | ||
82 | { | ||
83 | va_list ap; | ||
84 | |||
85 | va_start(ap, fmt); | ||
86 | vdiag(NULL, NULL, fmt, ap); | ||
87 | va_end(ap); | ||
88 | } | ||
89 | |||
90 | void | ||
91 | warn(const char *fmt, ...) | ||
92 | { | ||
93 | va_list ap; | ||
94 | |||
95 | va_start(ap, fmt); | ||
96 | vdiag(NULL, "warning", fmt, ap); | ||
97 | va_end(ap); | ||
98 | } | ||
99 | |||
100 | void | ||
101 | debug_printf(const char *fmt, ...) | ||
102 | { | ||
103 | va_list ap; | ||
104 | |||
105 | va_start(ap, fmt); | ||
106 | vdiag(NULL, "debug", fmt, ap); | ||
107 | va_end(ap); | ||
108 | } | ||
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 @@ | |||
18 | 18 | ||
19 | char *conffile = SYSCONFDIR "/eclat.conf" ; | 19 | char *conffile = SYSCONFDIR "/eclat.conf" ; |
20 | int lint_mode; | 20 | int lint_mode; |
21 | int debug_level[ECLAT_DEBCAT_MAX]; | ||
22 | int dry_run_mode; | 21 | int dry_run_mode; |
23 | int preprocess_only = 0; | 22 | int preprocess_only = 0; |
24 | 23 | ||
@@ -30,59 +29,23 @@ char *region_name; | |||
30 | enum eclat_command eclat_command; | 29 | enum eclat_command eclat_command; |
31 | 30 | ||
32 | 31 | ||
33 | struct debug_trans { | 32 | static char *categories[] = { |
34 | const char *name; | 33 | "main", |
35 | size_t length; | 34 | "cfgram", |
36 | int cat; | 35 | "cflex", |
36 | "conf", | ||
37 | "curl", | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | static struct debug_trans debug_trans[] = { | 40 | static void |
40 | #define S(s) #s, sizeof(#s)-1 | 41 | debug_init() |
41 | { S(main), ECLAT_DEBCAT_MAIN }, | ||
42 | { S(cfgram), ECLAT_DEBCAT_CFGRAM }, | ||
43 | { S(cflex), ECLAT_DEBCAT_CFLEX }, | ||
44 | { S(conf), ECLAT_DEBCAT_CONF }, | ||
45 | { S(curl), ECLAT_DEBCAT_CURL }, | ||
46 | { NULL } | ||
47 | }; | ||
48 | |||
49 | static int | ||
50 | parse_debug_level(const char *arg) | ||
51 | { | 42 | { |
52 | unsigned long cat, lev; | 43 | int i; |
53 | char *p; | ||
54 | 44 | ||
55 | if (isascii(*arg) && isdigit(*arg)) { | 45 | for (i = 0; i < sizeof(categories)/sizeof(categories[0]); i++) |
56 | cat = strtoul(arg, &p, 10); | 46 | debug_register(categories[i]); |
57 | if (cat > ECLAT_DEBCAT_MAX) | ||
58 | return -1; | ||
59 | } else { | ||
60 | size_t len = strcspn(arg, "."); | ||
61 | struct debug_trans *dp; | ||
62 | |||
63 | for (dp = debug_trans; dp->name; dp++) | ||
64 | if (dp->length == len && | ||
65 | memcmp(dp->name, arg, len) == 0) | ||
66 | break; | ||
67 | |||
68 | if (!dp->name) | ||
69 | return -1; | ||
70 | cat = dp->cat; | ||
71 | p = (char*) arg + len; | ||
72 | } | ||
73 | |||
74 | if (*p == 0) | ||
75 | lev = 100; | ||
76 | else if (*p != '.') | ||
77 | return -1; | ||
78 | else { | ||
79 | lev = strtoul(p + 1, &p, 10); | ||
80 | if (*p) | ||
81 | return -1; | ||
82 | } | ||
83 | debug_level[cat] = lev; | ||
84 | return 0; | ||
85 | } | 47 | } |
48 | |||
86 | 49 | ||
87 | static void | 50 | static void |
88 | dump(const char *text, FILE *stream, unsigned char *ptr, size_t size) | 51 | 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) | |||
90 | size_t i; | 53 | size_t i; |
91 | size_t c; | 54 | size_t c; |
92 | unsigned int width = 0x10; | 55 | unsigned int width = 0x10; |
93 | int hex = debug_level[ECLAT_DEBCAT_CURL] > 2; | 56 | int hex = debug_level(ECLAT_DEBCAT_CURL) > 2; |
94 | 57 | ||
95 | if (!hex) | 58 | if (!hex) |
96 | /* without the hex output, we can fit more on screen */ | 59 | /* 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) | |||
199 | int column = XML_GetCurrentColumnNumber(parser); | 162 | int column = XML_GetCurrentColumnNumber(parser); |
200 | 163 | ||
201 | /* FIXME: Debugging level. */ | 164 | /* FIXME: Debugging level. */ |
202 | if (debug_level[ECLAT_DEBCAT_MAIN] > 10) { | 165 | if (debug_level(ECLAT_DEBCAT_MAIN) > 10) { |
203 | dump_text(stderr, line, column, ptr, realsize); | 166 | dump_text(stderr, line, column, ptr, realsize); |
204 | } | 167 | } |
205 | status = XML_Parse(parser, ptr, realsize, 0); | 168 | status = XML_Parse(parser, ptr, realsize, 0); |
@@ -215,7 +178,6 @@ write_callback(void *ptr, size_t size, size_t nmemb, void *data) | |||
215 | } | 178 | } |
216 | return realsize; | 179 | return realsize; |
217 | } | 180 | } |
218 | |||
219 | 181 | ||
220 | #include "cmdline.h" | 182 | #include "cmdline.h" |
221 | 183 | ||
@@ -237,14 +199,15 @@ main(int argc, char **argv) | |||
237 | struct grecs_node *xmltree; | 199 | struct grecs_node *xmltree; |
238 | 200 | ||
239 | set_program_name(argv[0]); | 201 | set_program_name(argv[0]); |
202 | debug_init(); | ||
240 | config_init(); | 203 | config_init(); |
241 | parse_options(argc, argv, &index); | 204 | parse_options(argc, argv, &index); |
242 | 205 | ||
243 | argc -= index; | 206 | argc -= index; |
244 | argv += index; | 207 | argv += index; |
245 | 208 | ||
246 | grecs_gram_trace(debug_level[ECLAT_DEBCAT_CFGRAM]); | 209 | grecs_gram_trace(debug_level(ECLAT_DEBCAT_CFGRAM)); |
247 | grecs_lex_trace(debug_level[ECLAT_DEBCAT_CFLEX]); | 210 | grecs_lex_trace(debug_level(ECLAT_DEBCAT_CFLEX)); |
248 | 211 | ||
249 | if (preprocess_only) | 212 | if (preprocess_only) |
250 | exit(grecs_preproc_run(conffile, grecs_preprocessor) ? | 213 | exit(grecs_preproc_run(conffile, grecs_preprocessor) ? |
@@ -292,9 +255,9 @@ main(int argc, char **argv) | |||
292 | if (!curl) | 255 | if (!curl) |
293 | die(EX_UNAVAILABLE, "curl_easy_init failed"); | 256 | die(EX_UNAVAILABLE, "curl_easy_init failed"); |
294 | 257 | ||
295 | if (debug_level[ECLAT_DEBCAT_CURL]) { | 258 | if (debug_level(ECLAT_DEBCAT_CURL)) { |
296 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); | 259 | curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); |
297 | if (debug_level[ECLAT_DEBCAT_CURL] > 1) | 260 | if (debug_level(ECLAT_DEBCAT_CURL) > 1) |
298 | curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, | 261 | curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, |
299 | eclat_trace_fun); | 262 | eclat_trace_fun); |
300 | } | 263 | } |
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 @@ | |||
33 | #define ECLAT_DEBCAT_CFLEX 2 | 33 | #define ECLAT_DEBCAT_CFLEX 2 |
34 | #define ECLAT_DEBCAT_CONF 3 | 34 | #define ECLAT_DEBCAT_CONF 3 |
35 | #define ECLAT_DEBCAT_CURL 4 | 35 | #define ECLAT_DEBCAT_CURL 4 |
36 | #define ECLAT_DEBCAT_MAX 5 | 36 | #define ECLAT_DEBCAT_FORLAN 5 |
37 | |||
38 | extern const char *program_name; | ||
39 | extern int debug_level[]; | ||
40 | 37 | ||
41 | extern char *endpoint; | 38 | extern char *endpoint; |
42 | extern int use_ssl; | 39 | extern int use_ssl; |
@@ -46,20 +43,6 @@ extern char *access_file_name; | |||
46 | extern char *access_key; | 43 | extern char *access_key; |
47 | extern char *secret_key; | 44 | extern char *secret_key; |
48 | 45 | ||
49 | #define debug(cat, lev, s) \ | ||
50 | do { \ | ||
51 | if (debug_level[cat] >= (lev)) \ | ||
52 | debug_printf s; \ | ||
53 | } while(0) | ||
54 | |||
55 | void die(int status, const char *fmt, ...); | ||
56 | void vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, | ||
57 | va_list ap); | ||
58 | void diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...); | ||
59 | void err(const char *fmt, ...); | ||
60 | void warn(const char *fmt, ...); | ||
61 | void debug_printf(const char *fmt, ...); | ||
62 | |||
63 | typedef int (*config_finish_hook_t) (void*); | 46 | typedef int (*config_finish_hook_t) (void*); |
64 | 47 | ||
65 | void add_config_finish_hook(config_finish_hook_t fun, void *data); | 48 | 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 @@ | |||
1 | /* This file is part of Eclat. | ||
2 | Copyright (C) 2012 Sergey Poznyakoff. | ||
3 | |||
4 | Eclat is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | Eclat is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include "eclat.h" | ||
18 | #include <stdargs.h> | ||
19 | #include <stdio.h> | ||
20 | |||
21 | char *program_name; | ||
22 | |||
23 | void | ||
24 | diag(const char *qual, const char *fmt, va_list ap) | ||
25 | { | ||
26 | if (program_name) | ||
27 | fprintf(stderr, "%s: ", program_name); | ||
28 | if (qual) | ||
29 | fprintf(stderr, "%s: ", qual); | ||
30 | va_start(ap, fmt); | ||
31 | vfprintf(stderr, ftm, ap); | ||
32 | va_end(ap); | ||
33 | fputc('\n', stderr); | ||
34 | } | ||
35 | |||
36 | void | ||
37 | err(const char *fmt, ...) | ||
38 | { | ||
39 | va_list ap; | ||
40 | |||
41 | va_start(ap, fmt); | ||
42 | diag(NULL, ftm, ap); | ||
43 | va_end(ap); | ||
44 | } | ||
45 | |||
46 | void | ||
47 | warn(const char *fmt, ...) | ||
48 | { | ||
49 | va_list ap; | ||
50 | |||
51 | va_start(ap, fmt); | ||
52 | diag("warning", ftm, ap); | ||
53 | va_end(ap); | ||
54 | } | ||
55 | |||
56 | void | ||
57 | debug_printf(const char *fmt, ...) | ||
58 | { | ||
59 | va_list ap; | ||
60 | |||
61 | va_start(ap, fmt); | ||
62 | diag("debug", ftm, ap); | ||
63 | va_end(ap); | ||
64 | } | ||
diff --git a/tests/.gitignore b/tests/.gitignore index 99d3c9c..8b76ee0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore | |||
@@ -4,6 +4,7 @@ package.m4 | |||
4 | testsuite | 4 | testsuite |
5 | testsuite.dir | 5 | testsuite.dir |
6 | testsuite.log | 6 | testsuite.log |
7 | tforlan | ||
7 | thmac | 8 | thmac |
8 | turlenc | 9 | turlenc |
9 | txml | 10 | 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 | |||
40 | ## ------------ ## | 40 | ## ------------ ## |
41 | 41 | ||
42 | TESTSUITE_AT = \ | 42 | TESTSUITE_AT = \ |
43 | forlan01.at\ | ||
43 | hmac01.at\ | 44 | hmac01.at\ |
44 | hmac02.at\ | 45 | hmac02.at\ |
45 | hmac03.at\ | 46 | hmac03.at\ |
@@ -69,6 +70,7 @@ check-local: atconfig atlocal $(TESTSUITE) | |||
69 | #$(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin | 70 | #$(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin |
70 | 71 | ||
71 | noinst_PROGRAMS = \ | 72 | noinst_PROGRAMS = \ |
73 | tforlan\ | ||
72 | thmac\ | 74 | thmac\ |
73 | turlenc\ | 75 | turlenc\ |
74 | txml | 76 | 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 @@ | |||
1 | # This file is part of Eclat -*- Autotest -*- | ||
2 | # Copyright (C) 2012 Sergey Poznyakoff | ||
3 | # | ||
4 | # Eclat is free software; you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License as published by | ||
6 | # the Free Software Foundation; either version 3, or (at your option) | ||
7 | # any later version. | ||
8 | # | ||
9 | # Eclat is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with Eclat. If not, see <http://www.gnu.org/licenses/>. | ||
16 | |||
17 | AT_SETUP([dump]) | ||
18 | AT_KEYWORDS([forlan forlan01]) | ||
19 | |||
20 | AT_DATA([input],[// test format for DescribeTags | ||
21 | if (.DescribeTagsResponse) { | ||
22 | if (.DescribeTagsResponse.tagSet.item.resourceId[[i-deadbeef]] && | ||
23 | parent(last).key[[hostname]]) | ||
24 | print(parent(last).value); | ||
25 | } else if (.Response.Errors) | ||
26 | error(.Response.Errors.Error.Message); | ||
27 | else | ||
28 | dump(); | ||
29 | ]) | ||
30 | |||
31 | AT_CHECK([tforlan -D input], | ||
32 | [0], | ||
33 | [0001: COND | ||
34 | 0002: NODE | ||
35 | 0003: COMP ABS | ||
36 | 0004: LIT: "DescribeTagsResponse" | ||
37 | 0005: IFTRUE 0001 | ||
38 | 0006: COND | ||
39 | 0007: AND | ||
40 | 0008: NODE | ||
41 | 0009: COMP ABS | ||
42 | 0010: LIT: "DescribeTagsResponse" | ||
43 | 0011: LIT: "tagSet" | ||
44 | 0012: LIT: "item" | ||
45 | 0013: TEST: resourceId[[i-deadbeef]] | ||
46 | 0014: NODE | ||
47 | 0015: COMP | ||
48 | 0016: CALL: parent | ||
49 | 0017: LAST | ||
50 | 0018: TEST: key[[hostname]] | ||
51 | 0019: IFTRUE 0006 | ||
52 | 0020: CALL: print | ||
53 | 0021: COMP | ||
54 | 0022: CALL: parent | ||
55 | 0023: LAST | ||
56 | 0024: LIT: "value" | ||
57 | 0025: IFFALSE 0006 | ||
58 | 0026: IFFALSE 0001 | ||
59 | 0027: COND | ||
60 | 0028: NODE | ||
61 | 0029: COMP ABS | ||
62 | 0030: LIT: "Response" | ||
63 | 0031: LIT: "Errors" | ||
64 | 0032: IFTRUE 0027 | ||
65 | 0033: CALL: error | ||
66 | 0034: COMP ABS | ||
67 | 0035: LIT: "Response" | ||
68 | 0036: LIT: "Errors" | ||
69 | 0037: LIT: "Error" | ||
70 | 0038: LIT: "Message" | ||
71 | 0039: IFFALSE 0027 | ||
72 | 0040: CALL: dump | ||
73 | ]) | ||
74 | |||
75 | AT_CLEANUP | ||
76 | |||
77 | |||
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]) | |||
29 | 29 | ||
30 | AT_BANNER([XML Processing]) | 30 | AT_BANNER([XML Processing]) |
31 | m4_include([xml01.at]) | 31 | m4_include([xml01.at]) |
32 | |||
33 | AT_BANNER([Forlan]) | ||
34 | m4_include([forlan01.at]) | ||
35 | |||
32 | # End of testsuite.at | 36 | # 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 @@ | |||
1 | /* This file is part of Eclat. | ||
2 | Copyright (C) 2012 Sergey Poznyakoff. | ||
3 | |||
4 | Eclat is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | Eclat is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <unistd.h> | ||
21 | #ifdef HAVE_GETOPT_H | ||
22 | # include <getopt.h> | ||
23 | #endif | ||
24 | #include <errno.h> | ||
25 | #include <sysexits.h> | ||
26 | #include <libeclat.h> | ||
27 | #include "forlan.h" | ||
28 | #include <sys/stat.h> | ||
29 | |||
30 | void | ||
31 | usage() | ||
32 | { | ||
33 | printf("usage: %s [-dD] FILE [INPUT]\n"); | ||
34 | } | ||
35 | |||
36 | int | ||
37 | main(int argc, char **argv) | ||
38 | { | ||
39 | FILE *fp; | ||
40 | char *buf; | ||
41 | size_t len; | ||
42 | struct stat st; | ||
43 | struct grecs_locus_point pt; | ||
44 | int rc; | ||
45 | int dump_option = 0; | ||
46 | |||
47 | set_program_name(argv[0]); | ||
48 | forlan_init(); | ||
49 | |||
50 | while ((rc = getopt(argc, argv, "Dd:h")) != EOF) | ||
51 | switch (rc) { | ||
52 | case 'D': | ||
53 | dump_option++; | ||
54 | break; | ||
55 | |||
56 | case 'd': | ||
57 | if (parse_debug_level(optarg)) | ||
58 | die(EX_USAGE, "bad debug category or level"); | ||
59 | break; | ||
60 | |||
61 | case 'h': | ||
62 | usage(); | ||
63 | return 0; | ||
64 | |||
65 | default: | ||
66 | exit(EX_USAGE); | ||
67 | } | ||
68 | argc -= optind; | ||
69 | argv += optind; | ||
70 | |||
71 | |||
72 | if (argc == 0 || argc > 2) | ||
73 | die(EX_USAGE, "one or two arguments expected"); | ||
74 | if (stat(argv[0], &st)) | ||
75 | die(EX_UNAVAILABLE, "cannot stat input file \"%s\": %s", | ||
76 | argv[0], strerror(errno)); | ||
77 | len = st.st_size; | ||
78 | buf = grecs_malloc(len); | ||
79 | fp = fopen(argv[0], "r"); | ||
80 | if (!fp) | ||
81 | die(EX_UNAVAILABLE, "cannot open input file \"%s\": %s", | ||
82 | argv[0], strerror(errno)); | ||
83 | if (fread(buf, len, 1, fp) != 1) | ||
84 | die(EX_UNAVAILABLE, "error reading from \"%s\": %s", | ||
85 | argv[0], strerror(errno)); | ||
86 | fclose(fp); | ||
87 | |||
88 | pt.file = argv[0]; | ||
89 | pt.line = 1; | ||
90 | pt.col = 0; | ||
91 | |||
92 | rc = forlan_parse(buf, len, &pt); | ||
93 | if (rc == 0) { | ||
94 | if (dump_option) | ||
95 | forlan_dump_tree(stdout, forlan_parse_tree); | ||
96 | forlan_node_free(forlan_parse_tree); | ||
97 | } | ||
98 | return rc ? EX_UNAVAILABLE : 0; | ||
99 | } | ||
100 | |||