save
[protos/libecoli.git] / lib / ecoli_parsed.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <errno.h>
34
35 #include <ecoli_malloc.h>
36 #include <ecoli_strvec.h>
37 #include <ecoli_keyval.h>
38 #include <ecoli_log.h>
39 #include <ecoli_node.h>
40 #include <ecoli_parsed.h>
41
42 int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
43                         const struct ec_strvec *strvec)
44 {
45         struct ec_strvec *match_strvec;
46         struct ec_parsed *child;
47         int ret;
48
49         assert(state != NULL);
50
51         /* build the node if required */
52         if (node->type->build != NULL) {
53                 if ((node->flags & EC_NODE_F_BUILT) == 0) {
54                         ret = node->type->build(node);
55                         if (ret < 0)
56                                 return ret;
57                 }
58         }
59         node->flags |= EC_NODE_F_BUILT;
60
61         if (node->type->parse == NULL)
62                 return -ENOTSUP;
63
64         child = ec_parsed();
65         if (child == NULL)
66                 return -ENOMEM;
67
68         child->node = node;
69         ec_parsed_add_child(state, child);
70         ret = node->type->parse(node, child, strvec);
71         if (ret == EC_PARSED_NOMATCH) {
72                 ec_parsed_del_child(state, child);
73                 assert(TAILQ_EMPTY(&child->children));
74                 ec_parsed_free(child);
75                 return ret;
76         } else if (ret < 0) {
77                 return ret;
78         }
79
80         match_strvec = ec_strvec_ndup(strvec, 0, ret);
81         if (match_strvec == NULL)
82                 return -ENOMEM;
83
84         child->strvec = match_strvec;
85
86         return ret;
87 }
88
89 struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
90                                 const struct ec_strvec *strvec)
91 {
92         struct ec_parsed *parsed = ec_parsed();
93         struct ec_parsed *child_parsed;
94         int ret;
95
96         if (parsed == NULL)
97                 return NULL;
98
99         ret = ec_node_parse_child(node, parsed, strvec);
100         if (ret < 0 && ret != EC_PARSED_NOMATCH) {
101                 ec_parsed_free(parsed);
102                 parsed = NULL;
103         } else if (ret != EC_PARSED_NOMATCH) {
104                 /* remove dummy root node */
105                 child_parsed = ec_parsed_get_last_child(parsed);
106                 ec_parsed_del_child(parsed, child_parsed);
107                 ec_parsed_free(parsed);
108                 parsed = child_parsed;
109         }
110
111         return parsed;
112 }
113
114 struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
115 {
116         struct ec_strvec *strvec = NULL;
117         struct ec_parsed *parsed = NULL;
118
119         errno = ENOMEM;
120         strvec = ec_strvec();
121         if (strvec == NULL)
122                 goto fail;
123
124         if (ec_strvec_add(strvec, str) < 0)
125                 goto fail;
126
127         parsed = ec_node_parse_strvec(node, strvec);
128         if (parsed == NULL)
129                 goto fail;
130
131         ec_strvec_free(strvec);
132         return parsed;
133
134  fail:
135         ec_strvec_free(strvec);
136         ec_parsed_free(parsed);
137         return NULL;
138 }
139
140 struct ec_parsed *ec_parsed(void)
141 {
142         struct ec_parsed *parsed = NULL;
143
144         parsed = ec_calloc(1, sizeof(*parsed));
145         if (parsed == NULL)
146                 goto fail;
147
148         TAILQ_INIT(&parsed->children);
149
150         parsed->attrs = ec_keyval();
151         if (parsed->attrs == NULL)
152                 goto fail;
153
154         return parsed;
155
156  fail:
157         if (parsed != NULL)
158                 ec_keyval_free(parsed->attrs);
159         ec_free(parsed);
160
161         return NULL;
162 }
163
164 void ec_parsed_free_children(struct ec_parsed *parsed)
165 {
166         struct ec_parsed *child;
167
168         if (parsed == NULL)
169                 return;
170
171         while (!TAILQ_EMPTY(&parsed->children)) {
172                 child = TAILQ_FIRST(&parsed->children);
173                 TAILQ_REMOVE(&parsed->children, child, next);
174                 ec_parsed_free(child);
175         }
176 }
177
178 void ec_parsed_free(struct ec_parsed *parsed)
179 {
180         if (parsed == NULL)
181                 return;
182
183         ec_parsed_free_children(parsed);
184         ec_strvec_free(parsed->strvec);
185         ec_keyval_free(parsed->attrs);
186         ec_free(parsed);
187 }
188
189 static void __ec_parsed_dump(FILE *out,
190         const struct ec_parsed *parsed, size_t indent)
191 {
192         struct ec_parsed *child;
193         const struct ec_strvec *vec;
194         size_t i;
195         const char *id = "none", *typename = "none";
196
197         if (parsed->node != NULL) {
198                 if (parsed->node->id != NULL)
199                         id = parsed->node->id;
200                 typename = parsed->node->type->name;
201         }
202
203         /* XXX enhance */
204         for (i = 0; i < indent; i++) {
205                 if (i % 2)
206                         fprintf(out, " ");
207                 else
208                         fprintf(out, "|");
209         }
210
211         fprintf(out, "node_type=%s id=%s vec=", typename, id);
212         vec = ec_parsed_strvec(parsed);
213         ec_strvec_dump(out, vec);
214
215         TAILQ_FOREACH(child, &parsed->children, next)
216                 __ec_parsed_dump(out, child, indent + 2);
217 }
218
219 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
220 {
221         fprintf(out, "------------------- parsed dump:\n"); //XXX
222
223         if (parsed == NULL) {
224                 fprintf(out, "parsed is NULL, error in parse\n");
225                 return;
226         }
227         if (!ec_parsed_matches(parsed)) {
228                 fprintf(out, "no match\n");
229                 return;
230         }
231
232         __ec_parsed_dump(out, parsed, 0);
233 }
234
235 void ec_parsed_add_child(struct ec_parsed *parsed,
236         struct ec_parsed *child)
237 {
238         TAILQ_INSERT_TAIL(&parsed->children, child, next);
239         child->parent = parsed;
240 }
241
242 void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink?
243         struct ec_parsed *child)
244 {
245         TAILQ_REMOVE(&parsed->children, child, next);
246         child->parent = NULL;
247 }
248
249 struct ec_parsed *
250 ec_parsed_get_last_child(struct ec_parsed *parsed)
251 {
252         return TAILQ_LAST(&parsed->children, ec_parsed_list);
253 }
254
255 void ec_parsed_del_last_child(struct ec_parsed *parsed) // rename in free
256 {
257         struct ec_parsed *child;
258
259         child = ec_parsed_get_last_child(parsed);
260         ec_parsed_del_child(parsed, child);
261         ec_parsed_free(child);
262 }
263
264 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
265 {
266         if (parsed == NULL)
267                 return NULL;
268
269         while (parsed->parent != NULL)
270                 parsed = parsed->parent;
271
272         return parsed;
273 }
274
275 struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed)
276 {
277         if (parsed == NULL)
278                 return NULL;
279
280         return parsed->parent;
281 }
282
283 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
284         const char *id)
285 {
286         struct ec_parsed *child, *ret;
287
288         if (parsed == NULL)
289                 return NULL;
290
291         if (parsed->node != NULL &&
292                         parsed->node->id != NULL &&
293                         !strcmp(parsed->node->id, id))
294                 return parsed;
295
296         TAILQ_FOREACH(child, &parsed->children, next) {
297                 ret = ec_parsed_find_first(child, id);
298                 if (ret != NULL)
299                         return ret;
300         }
301
302         return NULL;
303 }
304
305 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
306 {
307         if (parsed == NULL || parsed->strvec == NULL)
308                 return NULL;
309
310         return parsed->strvec;
311 }
312
313 /* number of parsed strings in the vector */
314 size_t ec_parsed_len(const struct ec_parsed *parsed)
315 {
316         if (parsed == NULL || parsed->strvec == NULL)
317                 return 0;
318
319         return ec_strvec_len(parsed->strvec);
320 }
321
322 size_t ec_parsed_matches(const struct ec_parsed *parsed)
323 {
324         if (parsed == NULL)
325                 return 0;
326
327         if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
328                 return 0;
329
330         return 1;
331 }