1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
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>
20 TAILQ_HEAD(ec_parsed_list, 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;
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)
35 struct ec_strvec *match_strvec;
36 struct ec_parsed *child = NULL;
39 if (node->type->parse == NULL)
43 child = ec_parsed(node);
47 ec_parsed_link_child(state, child);
51 ret = node->type->parse(node, child, strvec);
52 if (ret < 0 || ret == EC_PARSED_NOMATCH)
55 match_strvec = ec_strvec_ndup(strvec, 0, ret);
56 if (match_strvec == NULL) {
61 child->strvec = match_strvec;
67 ec_parsed_unlink_child(state, child);
68 ec_parsed_free(child);
73 int ec_node_parse_child(const struct ec_node *node, struct ec_parsed *state,
74 const struct ec_strvec *strvec)
76 assert(state != NULL);
77 return __ec_node_parse_child(node, state, false, strvec);
80 struct ec_parsed *ec_node_parse_strvec(const struct ec_node *node,
81 const struct ec_strvec *strvec)
83 struct ec_parsed *parsed = ec_parsed(node);
89 ret = __ec_node_parse_child(node, parsed, true, strvec);
91 ec_parsed_free(parsed);
98 struct ec_parsed *ec_node_parse(const struct ec_node *node, const char *str)
100 struct ec_strvec *strvec = NULL;
101 struct ec_parsed *parsed = NULL;
104 strvec = ec_strvec();
108 if (ec_strvec_add(strvec, str) < 0)
111 parsed = ec_node_parse_strvec(node, strvec);
115 ec_strvec_free(strvec);
119 ec_strvec_free(strvec);
120 ec_parsed_free(parsed);
124 struct ec_parsed *ec_parsed(const struct ec_node *node)
126 struct ec_parsed *parsed = NULL;
128 parsed = ec_calloc(1, sizeof(*parsed));
132 TAILQ_INIT(&parsed->children);
135 parsed->attrs = ec_keyval();
136 if (parsed->attrs == NULL)
143 ec_keyval_free(parsed->attrs);
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)
153 struct ec_parsed *dup = NULL;
154 struct ec_parsed *child, *dup_child;
155 struct ec_keyval *attrs = NULL;
160 dup = ec_parsed(root->node);
167 attrs = ec_keyval_dup(root->attrs);
170 ec_keyval_free(dup->attrs);
173 if (root->strvec != NULL) {
174 dup->strvec = ec_strvec_dup(root->strvec);
175 if (dup->strvec == NULL)
179 TAILQ_FOREACH(child, &root->children, next) {
180 dup_child = __ec_parsed_dup(child, ref, new_ref);
181 if (dup_child == NULL)
183 ec_parsed_link_child(dup, dup_child);
193 struct ec_parsed *ec_parsed_dup(const struct ec_parsed *parsed)
195 const struct ec_parsed *root;
196 struct ec_parsed *dup_root, *dup = NULL;
198 root = ec_parsed_get_root(parsed);
199 dup_root = __ec_parsed_dup(root, parsed, &dup);
200 if (dup_root == NULL)
207 void ec_parsed_free_children(struct ec_parsed *parsed)
209 struct ec_parsed *child;
214 while (!TAILQ_EMPTY(&parsed->children)) {
215 child = TAILQ_FIRST(&parsed->children);
216 TAILQ_REMOVE(&parsed->children, child, next);
217 child->parent = NULL;
218 ec_parsed_free(child);
222 void ec_parsed_free(struct ec_parsed *parsed)
227 ec_assert_print(parsed->parent == NULL,
228 "parent not NULL in ec_parsed_free()");
230 ec_parsed_free_children(parsed);
231 ec_strvec_free(parsed->strvec);
232 ec_keyval_free(parsed->attrs);
236 static void __ec_parsed_dump(FILE *out,
237 const struct ec_parsed *parsed, size_t indent)
239 struct ec_parsed *child;
240 const struct ec_strvec *vec;
241 const char *id, *typename = "none";
243 /* node can be null when parsing is incomplete */
244 if (parsed->node != NULL) {
245 id = parsed->node->id;
246 typename = parsed->node->type->name;
249 fprintf(out, "%*s" "type=%s id=%s vec=",
250 (int)indent * 4, "", typename, id);
251 vec = ec_parsed_strvec(parsed);
252 ec_strvec_dump(out, vec);
254 TAILQ_FOREACH(child, &parsed->children, next)
255 __ec_parsed_dump(out, child, indent + 1);
258 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
260 fprintf(out, "------------------- parsed dump:\n");
262 if (parsed == NULL) {
263 fprintf(out, "parsed is NULL, error in parse\n");
267 /* only exist if it does not match (strvec == NULL) and if it
268 * does not have children: an incomplete parse, like those
269 * generated by complete() don't match but have children that
271 if (!ec_parsed_matches(parsed) && TAILQ_EMPTY(&parsed->children)) {
272 fprintf(out, "no match\n");
276 __ec_parsed_dump(out, parsed, 0);
279 void ec_parsed_link_child(struct ec_parsed *parsed,
280 struct ec_parsed *child)
282 TAILQ_INSERT_TAIL(&parsed->children, child, next);
283 child->parent = parsed;
286 void ec_parsed_unlink_child(struct ec_parsed *parsed,
287 struct ec_parsed *child)
289 TAILQ_REMOVE(&parsed->children, child, next);
290 child->parent = NULL;
294 ec_parsed_get_first_child(const struct ec_parsed *parsed)
296 return TAILQ_FIRST(&parsed->children);
300 ec_parsed_get_last_child(const struct ec_parsed *parsed)
302 return TAILQ_LAST(&parsed->children, ec_parsed_list);
305 struct ec_parsed *ec_parsed_get_next(const struct ec_parsed *parsed)
307 return TAILQ_NEXT(parsed, next);
310 bool ec_parsed_has_child(const struct ec_parsed *parsed)
312 return !TAILQ_EMPTY(&parsed->children);
315 const struct ec_node *ec_parsed_get_node(const struct ec_parsed *parsed)
320 void ec_parsed_del_last_child(struct ec_parsed *parsed)
322 struct ec_parsed *child;
324 child = ec_parsed_get_last_child(parsed);
325 ec_parsed_unlink_child(parsed, child);
326 ec_parsed_free(child);
329 struct ec_parsed *__ec_parsed_get_root(struct ec_parsed *parsed)
334 while (parsed->parent != NULL)
335 parsed = parsed->parent;
340 struct ec_parsed *ec_parsed_get_parent(const struct ec_parsed *parsed)
345 return parsed->parent;
348 struct ec_parsed *ec_parsed_iter_next(struct ec_parsed *parsed)
350 struct ec_parsed *child, *parent, *next;
352 child = TAILQ_FIRST(&parsed->children);
355 parent = parsed->parent;
356 while (parent != NULL) {
357 next = TAILQ_NEXT(parsed, next);
361 parent = parsed->parent;
366 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
369 struct ec_parsed *child, *ret;
374 if (parsed->node != NULL &&
375 parsed->node->id != NULL &&
376 !strcmp(parsed->node->id, id))
379 TAILQ_FOREACH(child, &parsed->children, next) {
380 ret = ec_parsed_find_first(child, id);
389 ec_parsed_get_attrs(struct ec_parsed *parsed)
394 return parsed->attrs;
397 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
399 if (parsed == NULL || parsed->strvec == NULL)
402 return parsed->strvec;
405 /* number of strings in the parsed vector */
406 size_t ec_parsed_len(const struct ec_parsed *parsed)
408 if (parsed == NULL || parsed->strvec == NULL)
411 return ec_strvec_len(parsed->strvec);
414 size_t ec_parsed_matches(const struct ec_parsed *parsed)
419 if (parsed->strvec == NULL)