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