93d53256fdb5d2ea7600153e47fbfe28001b4ffb
[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 <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
34 #include <ecoli_malloc.h>
35 #include <ecoli_strvec.h>
36 #include <ecoli_keyval.h>
37 #include <ecoli_log.h>
38 #include <ecoli_node.h>
39 #include <ecoli_parsed.h>
40
41 struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
42 {
43         struct ec_strvec *strvec = NULL;
44         struct ec_parsed *parsed;
45
46         errno = ENOMEM;
47         strvec = ec_strvec();
48         if (strvec == NULL)
49                 goto fail;
50
51         if (ec_strvec_add(strvec, str) < 0)
52                 goto fail;
53
54         parsed = ec_node_parse_strvec(node, strvec);
55         if (parsed == NULL)
56                 goto fail;
57
58         ec_strvec_free(strvec);
59         return parsed;
60
61  fail:
62         ec_strvec_free(strvec);
63         return NULL;
64 }
65
66 struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
67         const struct ec_strvec *strvec)
68 {
69         struct ec_parsed *parsed;
70         int ret;
71
72         /* build the node if required */
73         if (node->type->build != NULL) {
74                 if ((node->flags & EC_NODE_F_BUILT) == 0) {
75                         ret = node->type->build(node);
76                         if (ret < 0) {
77                                 errno = -ret;
78                                 return NULL;
79                         }
80                 }
81         }
82         node->flags |= EC_NODE_F_BUILT;
83
84         if (node->type->parse == NULL) {
85                 errno = ENOTSUP;
86                 return NULL;
87         }
88
89         parsed = node->type->parse(node, strvec);
90
91         return parsed;
92 }
93
94
95 struct ec_parsed *ec_parsed(void)
96 {
97         struct ec_parsed *parsed = NULL;
98
99         parsed = ec_calloc(1, sizeof(*parsed));
100         if (parsed == NULL)
101                 goto fail;
102
103         TAILQ_INIT(&parsed->children);
104
105         return parsed;
106
107  fail:
108         return NULL;
109 }
110
111 void ec_parsed_set_match(struct ec_parsed *parsed,
112         const struct ec_node *node, struct ec_strvec *strvec)
113 {
114         parsed->node = node;
115         parsed->strvec = strvec;
116 }
117
118 void ec_parsed_free_children(struct ec_parsed *parsed)
119 {
120         struct ec_parsed *child;
121
122         if (parsed == NULL)
123                 return;
124
125         while (!TAILQ_EMPTY(&parsed->children)) {
126                 child = TAILQ_FIRST(&parsed->children);
127                 TAILQ_REMOVE(&parsed->children, child, next);
128                 ec_parsed_free(child);
129         }
130 }
131
132 void ec_parsed_free(struct ec_parsed *parsed)
133 {
134         if (parsed == NULL)
135                 return;
136
137         ec_parsed_free_children(parsed);
138         ec_strvec_free(parsed->strvec);
139         ec_free(parsed);
140 }
141
142 static void __ec_parsed_dump(FILE *out,
143         const struct ec_parsed *parsed, size_t indent)
144 {
145         struct ec_parsed *child;
146         const struct ec_strvec *vec;
147         size_t i;
148         const char *id = "None", *typename = "None";
149
150         if (parsed->node != NULL) {
151                 if (parsed->node->id != NULL)
152                         id = parsed->node->id;
153                 typename = parsed->node->type->name;
154         }
155
156         /* XXX enhance */
157         for (i = 0; i < indent; i++) {
158                 if (i % 2)
159                         fprintf(out, " ");
160                 else
161                         fprintf(out, "|");
162         }
163
164         fprintf(out, "node_type=%s id=%s vec=[", typename, id);
165         vec = ec_parsed_strvec(parsed);
166         for (i = 0; i < ec_strvec_len(vec); i++)
167                 fprintf(out, "%s<%s>",
168                         i == 0 ? "" : ",",
169                         ec_strvec_val(vec, i));
170         fprintf(out, "]\n");
171
172         TAILQ_FOREACH(child, &parsed->children, next)
173                 __ec_parsed_dump(out, child, indent + 2);
174 }
175
176 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
177 {
178         fprintf(out, "------------------- parsed dump:\n"); //XXX
179
180         if (parsed == NULL) {
181                 fprintf(out, "parsed is NULL, error in parse\n");
182                 return;
183         }
184         if (!ec_parsed_matches(parsed)) {
185                 fprintf(out, "no match\n");
186                 return;
187         }
188
189         __ec_parsed_dump(out, parsed, 0);
190 }
191
192 void ec_parsed_add_child(struct ec_parsed *parsed,
193         struct ec_parsed *child)
194 {
195         TAILQ_INSERT_TAIL(&parsed->children, child, next);
196 }
197
198 void ec_parsed_del_child(struct ec_parsed *parsed,
199         struct ec_parsed *child)
200 {
201         TAILQ_REMOVE(&parsed->children, child, next);
202 }
203
204 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
205         const char *id)
206 {
207         struct ec_parsed *child, *ret;
208
209         if (parsed == NULL)
210                 return NULL;
211
212         if (parsed->node != NULL &&
213                         parsed->node->id != NULL &&
214                         !strcmp(parsed->node->id, id))
215                 return parsed;
216
217         TAILQ_FOREACH(child, &parsed->children, next) {
218                 ret = ec_parsed_find_first(child, id);
219                 if (ret != NULL)
220                         return ret;
221         }
222
223         return NULL;
224 }
225
226 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
227 {
228         if (parsed == NULL || parsed->strvec == NULL)
229                 return NULL;
230
231         return parsed->strvec;
232 }
233
234 /* number of parsed strings in the vector */
235 size_t ec_parsed_len(const struct ec_parsed *parsed)
236 {
237         if (parsed == NULL || parsed->strvec == NULL)
238                 return 0;
239
240         return ec_strvec_len(parsed->strvec);
241 }
242
243 size_t ec_parsed_matches(const struct ec_parsed *parsed)
244 {
245         if (parsed == NULL)
246                 return 0;
247
248         if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children))
249                 return 0;
250
251         return 1;
252 }