parsed
[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         return parsed;
151
152  fail:
153         return NULL;
154 }
155
156 void ec_parsed_free_children(struct ec_parsed *parsed)
157 {
158         struct ec_parsed *child;
159
160         if (parsed == NULL)
161                 return;
162
163         while (!TAILQ_EMPTY(&parsed->children)) {
164                 child = TAILQ_FIRST(&parsed->children);
165                 TAILQ_REMOVE(&parsed->children, child, next);
166                 ec_parsed_free(child);
167         }
168 }
169
170 void ec_parsed_free(struct ec_parsed *parsed)
171 {
172         if (parsed == NULL)
173                 return;
174
175         ec_parsed_free_children(parsed);
176         ec_strvec_free(parsed->strvec);
177         ec_free(parsed);
178 }
179
180 static void __ec_parsed_dump(FILE *out,
181         const struct ec_parsed *parsed, size_t indent)
182 {
183         struct ec_parsed *child;
184         const struct ec_strvec *vec;
185         size_t i;
186         const char *id = "none", *typename = "none";
187
188         if (parsed->node != NULL) {
189                 if (parsed->node->id != NULL)
190                         id = parsed->node->id;
191                 typename = parsed->node->type->name;
192         }
193
194         /* XXX enhance */
195         for (i = 0; i < indent; i++) {
196                 if (i % 2)
197                         fprintf(out, " ");
198                 else
199                         fprintf(out, "|");
200         }
201
202         fprintf(out, "node_type=%s id=%s vec=", typename, id);
203         vec = ec_parsed_strvec(parsed);
204         ec_strvec_dump(out, vec);
205
206         TAILQ_FOREACH(child, &parsed->children, next)
207                 __ec_parsed_dump(out, child, indent + 2);
208 }
209
210 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
211 {
212         fprintf(out, "------------------- parsed dump:\n"); //XXX
213
214         if (parsed == NULL) {
215                 fprintf(out, "parsed is NULL, error in parse\n");
216                 return;
217         }
218         if (!ec_parsed_matches(parsed)) {
219                 fprintf(out, "no match\n");
220                 return;
221         }
222
223         __ec_parsed_dump(out, parsed, 0);
224 }
225
226 void ec_parsed_add_child(struct ec_parsed *parsed,
227         struct ec_parsed *child)
228 {
229         TAILQ_INSERT_TAIL(&parsed->children, child, next);
230         child->parent = parsed;
231 }
232
233 void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink?
234         struct ec_parsed *child)
235 {
236         TAILQ_REMOVE(&parsed->children, child, next);
237         child->parent = NULL;
238 }
239
240 struct ec_parsed *
241 ec_parsed_get_last_child(struct ec_parsed *parsed)
242 {
243         return TAILQ_LAST(&parsed->children, ec_parsed_list);
244 }
245
246 void ec_parsed_del_last_child(struct ec_parsed *parsed) // rename in free
247 {
248         struct ec_parsed *child;
249
250         child = ec_parsed_get_last_child(parsed);
251         ec_parsed_del_child(parsed, child);
252         ec_parsed_free(child);
253 }
254
255 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
256 {
257         if (parsed == NULL)
258                 return NULL;
259
260         while (parsed->parent != NULL)
261                 parsed = parsed->parent;
262
263         return parsed;
264 }
265
266 struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed)
267 {
268         if (parsed == NULL)
269                 return NULL;
270
271         return parsed->parent;
272 }
273
274 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
275         const char *id)
276 {
277         struct ec_parsed *child, *ret;
278
279         if (parsed == NULL)
280                 return NULL;
281
282         if (parsed->node != NULL &&
283                         parsed->node->id != NULL &&
284                         !strcmp(parsed->node->id, id))
285                 return parsed;
286
287         TAILQ_FOREACH(child, &parsed->children, next) {
288                 ret = ec_parsed_find_first(child, id);
289                 if (ret != NULL)
290                         return ret;
291         }
292
293         return NULL;
294 }
295
296 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
297 {
298         if (parsed == NULL || parsed->strvec == NULL)
299                 return NULL;
300
301         return parsed->strvec;
302 }
303
304 /* number of parsed strings in the vector */
305 size_t ec_parsed_len(const struct ec_parsed *parsed)
306 {
307         if (parsed == NULL || parsed->strvec == NULL)
308                 return 0;
309
310         return ec_strvec_len(parsed->strvec);
311 }
312
313 size_t ec_parsed_matches(const struct ec_parsed *parsed)
314 {
315         if (parsed == NULL)
316                 return 0;
317
318         if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
319                 return 0;
320
321         return 1;
322 }