enhance dumps
[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_assert.h>
36 #include <ecoli_malloc.h>
37 #include <ecoli_strvec.h>
38 #include <ecoli_keyval.h>
39 #include <ecoli_log.h>
40 #include <ecoli_node.h>
41 #include <ecoli_parsed.h>
42
43 TAILQ_HEAD(ec_parsed_list, ec_parsed);
44
45 struct ec_parsed {
46         TAILQ_ENTRY(ec_parsed) next;
47         struct ec_parsed_list children;
48         struct ec_parsed *parent;
49         const struct ec_node *node;
50         struct ec_strvec *strvec;
51         struct ec_keyval *attrs;
52 };
53
54 static int __ec_node_parse_child(const struct ec_node *node,
55                                 struct ec_parsed *state,
56                                 bool is_root, const struct ec_strvec *strvec)
57 {
58         struct ec_strvec *match_strvec;
59         struct ec_parsed *child = NULL;
60         int ret;
61
62         if (node->type->parse == NULL)
63                 return -ENOTSUP;
64
65         if (!is_root) {
66                 child = ec_parsed(node);
67                 if (child == NULL)
68                         return -ENOMEM;
69
70                 ec_parsed_add_child(state, child);
71         } else {
72                 child = state;
73         }
74         ret = node->type->parse(node, child, strvec);
75         if (ret < 0 || ret == EC_PARSED_NOMATCH)
76                 goto free;
77
78         match_strvec = ec_strvec_ndup(strvec, 0, ret);
79         if (match_strvec == NULL) {
80                 ret = -ENOMEM;
81                 goto free;
82         }
83
84         child->strvec = match_strvec;
85
86         return ret;
87
88 free:
89         if (!is_root) {
90                 ec_parsed_del_child(state, child);
91                 ec_parsed_free(child);
92         }
93         return ret;
94 }
95
96 int ec_node_parse_child(const struct ec_node *node, struct ec_parsed *state,
97                         const struct ec_strvec *strvec)
98 {
99         assert(state != NULL);
100         return __ec_node_parse_child(node, state, false, strvec);
101 }
102
103 struct ec_parsed *ec_node_parse_strvec(const struct ec_node *node,
104                                 const struct ec_strvec *strvec)
105 {
106         struct ec_parsed *parsed = ec_parsed(node);
107         int ret;
108
109         if (parsed == NULL)
110                 return NULL;
111
112         ret = __ec_node_parse_child(node, parsed, true, strvec);
113         if (ret < 0) {
114                 ec_parsed_free(parsed);
115                 return NULL;
116         }
117
118         return parsed;
119 }
120
121 struct ec_parsed *ec_node_parse(const struct ec_node *node, const char *str)
122 {
123         struct ec_strvec *strvec = NULL;
124         struct ec_parsed *parsed = NULL;
125
126         errno = ENOMEM;
127         strvec = ec_strvec();
128         if (strvec == NULL)
129                 goto fail;
130
131         if (ec_strvec_add(strvec, str) < 0)
132                 goto fail;
133
134         parsed = ec_node_parse_strvec(node, strvec);
135         if (parsed == NULL)
136                 goto fail;
137
138         ec_strvec_free(strvec);
139         return parsed;
140
141  fail:
142         ec_strvec_free(strvec);
143         ec_parsed_free(parsed);
144         return NULL;
145 }
146
147 struct ec_parsed *ec_parsed(const struct ec_node *node)
148 {
149         struct ec_parsed *parsed = NULL;
150
151         parsed = ec_calloc(1, sizeof(*parsed));
152         if (parsed == NULL)
153                 goto fail;
154
155         TAILQ_INIT(&parsed->children);
156
157         parsed->node = node;
158         parsed->attrs = ec_keyval();
159         if (parsed->attrs == NULL)
160                 goto fail;
161
162         return parsed;
163
164  fail:
165         if (parsed != NULL)
166                 ec_keyval_free(parsed->attrs);
167         ec_free(parsed);
168
169         return NULL;
170 }
171
172 static struct ec_parsed *
173 __ec_parsed_dup(const struct ec_parsed *root, const struct ec_parsed *ref,
174                 struct ec_parsed **new_ref)
175 {
176         struct ec_parsed *dup = NULL;
177         struct ec_parsed *child, *dup_child;
178         struct ec_keyval *attrs = NULL;
179
180         if (root == NULL)
181                 return NULL;
182
183         dup = ec_parsed(root->node);
184         if (dup == NULL)
185                 return NULL;
186
187         if (root == ref)
188                 *new_ref = dup;
189
190         attrs = ec_keyval_dup(root->attrs);
191         if (attrs == NULL)
192                 goto fail;
193         ec_keyval_free(dup->attrs);
194         dup->attrs = attrs;
195
196         if (root->strvec != NULL) {
197                 dup->strvec = ec_strvec_dup(root->strvec);
198                 if (dup->strvec == NULL)
199                         goto fail;
200         }
201
202         TAILQ_FOREACH(child, &root->children, next) {
203                 dup_child = __ec_parsed_dup(child, ref, new_ref);
204                 if (dup_child == NULL)
205                         goto fail;
206                 ec_parsed_add_child(dup, dup_child);
207         }
208
209         return dup;
210
211 fail:
212         ec_parsed_free(dup);
213         return NULL;
214 }
215
216 struct ec_parsed *ec_parsed_dup(struct ec_parsed *parsed) //XXX const
217 {
218         struct ec_parsed *root, *dup_root, *dup = NULL;
219
220         root = ec_parsed_get_root(parsed);
221         dup_root = __ec_parsed_dup(root, parsed, &dup);
222         if (dup_root == NULL)
223                 return NULL;
224         assert(dup != NULL);
225
226         return dup;
227 }
228
229 void ec_parsed_free_children(struct ec_parsed *parsed)
230 {
231         struct ec_parsed *child;
232
233         if (parsed == NULL)
234                 return;
235
236         while (!TAILQ_EMPTY(&parsed->children)) {
237                 child = TAILQ_FIRST(&parsed->children);
238                 TAILQ_REMOVE(&parsed->children, child, next);
239                 ec_parsed_free(child);
240         }
241 }
242
243 void ec_parsed_free(struct ec_parsed *parsed)
244 {
245         if (parsed == NULL)
246                 return;
247
248         // assert(parsed->parent == NULL); XXX
249         // or
250         // parsed = ec_parsed_get_root(parsed);
251
252         ec_parsed_free_children(parsed);
253         ec_strvec_free(parsed->strvec);
254         ec_keyval_free(parsed->attrs);
255         ec_free(parsed);
256 }
257
258 static void __ec_parsed_dump(FILE *out,
259         const struct ec_parsed *parsed, size_t indent)
260 {
261         struct ec_parsed *child;
262         const struct ec_strvec *vec;
263         const char *id, *typename = "none";
264
265         /* node can be null when parsing is incomplete */
266         if (parsed->node != NULL) {
267                 id = parsed->node->id;
268                 typename = parsed->node->type->name;
269         }
270
271         fprintf(out, "%*s" "type=%s id=%s vec=",
272                 (int)indent * 4, "", typename, id);
273         vec = ec_parsed_strvec(parsed);
274         ec_strvec_dump(out, vec);
275
276         TAILQ_FOREACH(child, &parsed->children, next)
277                 __ec_parsed_dump(out, child, indent + 2);
278 }
279
280 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
281 {
282         fprintf(out, "------------------- parsed dump:\n");
283
284         if (parsed == NULL) {
285                 fprintf(out, "parsed is NULL, error in parse\n");
286                 return;
287         }
288
289         /* only exist if it does not match (strvec == NULL) and if it
290          * does not have children: an incomplete parse, like those
291          * generated by complete() don't match but have children that
292          * may match. */
293         if (!ec_parsed_matches(parsed) && TAILQ_EMPTY(&parsed->children)) {
294                 fprintf(out, "no match\n");
295                 return;
296         }
297
298         __ec_parsed_dump(out, parsed, 0);
299 }
300
301 void ec_parsed_add_child(struct ec_parsed *parsed,
302         struct ec_parsed *child)
303 {
304         TAILQ_INSERT_TAIL(&parsed->children, child, next);
305         child->parent = parsed;
306 }
307
308 // XXX we can remove the first arg ? parsed == child->parent ?
309 void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink?
310         struct ec_parsed *child)
311 {
312         TAILQ_REMOVE(&parsed->children, child, next);
313         child->parent = NULL;
314 }
315
316 struct ec_parsed *
317 ec_parsed_get_first_child(const struct ec_parsed *parsed)
318 {
319         return TAILQ_FIRST(&parsed->children);
320 }
321
322 struct ec_parsed *
323 ec_parsed_get_last_child(const struct ec_parsed *parsed)
324 {
325         return TAILQ_LAST(&parsed->children, ec_parsed_list);
326 }
327
328 struct ec_parsed *ec_parsed_get_next(const struct ec_parsed *parsed)
329 {
330         return TAILQ_NEXT(parsed, next);
331 }
332
333 bool ec_parsed_has_child(const struct ec_parsed *parsed)
334 {
335         return !TAILQ_EMPTY(&parsed->children);
336 }
337
338 const struct ec_node *ec_parsed_get_node(const struct ec_parsed *parsed)
339 {
340         return parsed->node;
341 }
342
343 void ec_parsed_del_last_child(struct ec_parsed *parsed) // rename in free
344 {
345         struct ec_parsed *child;
346
347         child = ec_parsed_get_last_child(parsed);
348         ec_parsed_del_child(parsed, child);
349         ec_parsed_free(child);
350 }
351
352 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
353 {
354         if (parsed == NULL)
355                 return NULL;
356
357         while (parsed->parent != NULL)
358                 parsed = parsed->parent;
359
360         return parsed;
361 }
362
363 struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed)
364 {
365         if (parsed == NULL)
366                 return NULL;
367
368         return parsed->parent;
369 }
370
371 struct ec_parsed *ec_parsed_iter_next(struct ec_parsed *parsed)
372 {
373         struct ec_parsed *child, *parent, *next;
374
375         child = TAILQ_FIRST(&parsed->children);
376         if (child != NULL)
377                 return child;
378         parent = parsed->parent;
379         while (parent != NULL) {
380                 next = TAILQ_NEXT(parsed, next);
381                 if (next != NULL)
382                         return next;
383                 parsed = parent;
384                 parent = parsed->parent;
385         }
386         return NULL;
387 }
388
389 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
390         const char *id)
391 {
392         struct ec_parsed *child, *ret;
393
394         if (parsed == NULL)
395                 return NULL;
396
397         if (parsed->node != NULL &&
398                         parsed->node->id != NULL &&
399                         !strcmp(parsed->node->id, id))
400                 return parsed;
401
402         TAILQ_FOREACH(child, &parsed->children, next) {
403                 ret = ec_parsed_find_first(child, id);
404                 if (ret != NULL)
405                         return ret;
406         }
407
408         return NULL;
409 }
410
411 struct ec_keyval *
412 ec_parsed_get_attrs(struct ec_parsed *parsed)
413 {
414         if (parsed == NULL)
415                 return NULL;
416
417         return parsed->attrs;
418 }
419
420 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
421 {
422         if (parsed == NULL || parsed->strvec == NULL)
423                 return NULL;
424
425         return parsed->strvec;
426 }
427
428 /* number of strings in the parsed vector */
429 size_t ec_parsed_len(const struct ec_parsed *parsed)
430 {
431         if (parsed == NULL || parsed->strvec == NULL)
432                 return 0;
433
434         return ec_strvec_len(parsed->strvec);
435 }
436
437 size_t ec_parsed_matches(const struct ec_parsed *parsed)
438 {
439         if (parsed == NULL)
440                 return 0;
441
442         if (parsed->strvec == NULL)
443                 return 0;
444
445         return 1;
446 }