remove max parse len
[protos/libecoli.git] / lib / ecoli_node_seq.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 <stdarg.h>
34 #include <errno.h>
35
36 #include <ecoli_malloc.h>
37 #include <ecoli_log.h>
38 #include <ecoli_test.h>
39 #include <ecoli_strvec.h>
40 #include <ecoli_node.h>
41 #include <ecoli_parsed.h>
42 #include <ecoli_completed.h>
43 #include <ecoli_node_str.h>
44 #include <ecoli_node_option.h>
45 #include <ecoli_node_or.h>
46 #include <ecoli_node_many.h>
47 #include <ecoli_node_seq.h>
48
49 EC_LOG_TYPE_REGISTER(node_seq);
50
51 struct ec_node_seq {
52         struct ec_node gen;
53         struct ec_node **table;
54         size_t len;
55 };
56
57 static int
58 ec_node_seq_parse(const struct ec_node *gen_node,
59                 struct ec_parsed *state,
60                 const struct ec_strvec *strvec)
61 {
62         struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
63         struct ec_strvec *childvec = NULL;
64         size_t len = 0;
65         unsigned int i;
66         int ret;
67
68         for (i = 0; i < node->len; i++) {
69                 childvec = ec_strvec_ndup(strvec, len,
70                         ec_strvec_len(strvec) - len);
71                 if (childvec == NULL) {
72                         ret = -ENOMEM;
73                         goto fail;
74                 }
75
76                 ret = ec_node_parse_child(node->table[i], state, childvec);
77                 if (ret < 0)
78                         goto fail;
79
80                 ec_strvec_free(childvec);
81                 childvec = NULL;
82
83                 if (ret == EC_PARSED_NOMATCH) {
84                         ec_parsed_free_children(state);
85                         return EC_PARSED_NOMATCH;
86                 }
87
88                 len += ret;
89         }
90
91         return len;
92
93 fail:
94         ec_strvec_free(childvec);
95         return ret;
96 }
97
98 static int
99 __ec_node_seq_complete(struct ec_node **table, size_t table_len,
100                 struct ec_completed *completed,
101                 const struct ec_strvec *strvec)
102 {
103         struct ec_parsed *parsed = ec_completed_get_state(completed);
104         struct ec_strvec *childvec = NULL;
105         unsigned int i;
106         int ret;
107
108         if (table_len == 0)
109                 return 0;
110
111         /*
112          * Example of completion for a sequence node = [n1,n2] and an
113          * input = [a,b,c,d]:
114          *
115          * result = complete(n1, [a,b,c,d]) +
116          *    complete(n2, [b,c,d]) if n1 matches [a] +
117          *    complete(n2, [c,d]) if n1 matches [a,b] +
118          *    complete(n2, [d]) if n1 matches [a,b,c] +
119          *    complete(n2, []) if n1 matches [a,b,c,d]
120          */
121
122         /* first, try to complete with the first node of the table */
123         ret = ec_node_complete_child(table[0], completed, strvec);
124         if (ret < 0)
125                 goto fail;
126
127         /* then, if the first node of the table matches the beginning of the
128          * strvec, try to complete the rest */
129         for (i = 0; i < ec_strvec_len(strvec); i++) {
130                 childvec = ec_strvec_ndup(strvec, 0, i);
131                 if (childvec == NULL)
132                         goto fail;
133
134                 ret = ec_node_parse_child(table[0], parsed, childvec);
135                 if (ret < 0)
136                         goto fail;
137
138                 ec_strvec_free(childvec);
139                 childvec = NULL;
140
141                 if ((unsigned int)ret != i) {
142                         if (ret != EC_PARSED_NOMATCH)
143                                 ec_parsed_del_last_child(parsed);
144                         continue;
145                 }
146
147                 childvec = ec_strvec_ndup(strvec, i, ec_strvec_len(strvec) - i);
148                 if (childvec == NULL) {
149                         ec_parsed_del_last_child(parsed);
150                         goto fail;
151                 }
152
153                 ret = __ec_node_seq_complete(&table[1],
154                                         table_len - 1,
155                                         completed, childvec);
156                 ec_parsed_del_last_child(parsed);
157                 ec_strvec_free(childvec);
158                 childvec = NULL;
159
160                 if (ret < 0)
161                         goto fail;
162         }
163
164         return 0;
165
166 fail:
167         ec_strvec_free(childvec);
168         return -1;
169 }
170
171 static int
172 ec_node_seq_complete(const struct ec_node *gen_node,
173                 struct ec_completed *completed,
174                 const struct ec_strvec *strvec)
175 {
176         struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
177
178         return __ec_node_seq_complete(node->table, node->len, completed,
179                                 strvec);
180 }
181
182 static void ec_node_seq_free_priv(struct ec_node *gen_node)
183 {
184         struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
185         unsigned int i;
186
187         for (i = 0; i < node->len; i++)
188                 ec_node_free(node->table[i]);
189         ec_free(node->table);
190 }
191
192 static struct ec_node_type ec_node_seq_type = {
193         .name = "seq",
194         .parse = ec_node_seq_parse,
195         .complete = ec_node_seq_complete,
196         .size = sizeof(struct ec_node_seq),
197         .free_priv = ec_node_seq_free_priv,
198 };
199
200 EC_NODE_TYPE_REGISTER(ec_node_seq_type);
201
202 int ec_node_seq_add(struct ec_node *gen_node, struct ec_node *child)
203 {
204         struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
205         struct ec_node **table;
206
207         assert(node != NULL);
208
209         if (child == NULL) {
210                 errno = EINVAL;
211                 goto fail;
212         }
213
214         if (ec_node_check_type(gen_node, &ec_node_seq_type) < 0)
215                 goto fail;
216
217         table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
218         if (table == NULL)
219                 goto fail;
220
221         node->table = table;
222
223         if (ec_node_add_child(gen_node, child) < 0)
224                 goto fail;
225
226         table[node->len] = child;
227         node->len++;
228
229         return 0;
230
231 fail:
232         ec_node_free(child);
233         return -1;
234 }
235
236 struct ec_node *__ec_node_seq(const char *id, ...)
237 {
238         struct ec_node *gen_node = NULL;
239         struct ec_node_seq *node = NULL;
240         struct ec_node *child;
241         va_list ap;
242         int fail = 0;
243
244         va_start(ap, id);
245
246         gen_node = __ec_node(&ec_node_seq_type, id);
247         node = (struct ec_node_seq *)gen_node;
248         if (node == NULL)
249                 fail = 1;;
250
251         for (child = va_arg(ap, struct ec_node *);
252              child != EC_NODE_ENDLIST;
253              child = va_arg(ap, struct ec_node *)) {
254
255                 /* on error, don't quit the loop to avoid leaks */
256                 if (fail == 1 || child == NULL ||
257                                 ec_node_seq_add(&node->gen, child) < 0) {
258                         fail = 1;
259                         ec_node_free(child);
260                 }
261         }
262
263         if (fail == 1)
264                 goto fail;
265
266         va_end(ap);
267         return gen_node;
268
269 fail:
270         ec_node_free(gen_node); /* will also free children */
271         va_end(ap);
272         return NULL;
273 }
274
275 /* LCOV_EXCL_START */
276 static int ec_node_seq_testcase(void)
277 {
278         struct ec_node *node;
279         int ret = 0;
280
281         node = EC_NODE_SEQ(EC_NO_ID,
282                 ec_node_str(EC_NO_ID, "foo"),
283                 ec_node_str(EC_NO_ID, "bar")
284         );
285         if (node == NULL) {
286                 EC_LOG(EC_LOG_ERR, "cannot create node\n");
287                 return -1;
288         }
289         ret |= EC_TEST_CHECK_PARSE(node, 2, "foo", "bar");
290         ret |= EC_TEST_CHECK_PARSE(node, 2, "foo", "bar", "toto");
291         ret |= EC_TEST_CHECK_PARSE(node, -1, "foo");
292         ret |= EC_TEST_CHECK_PARSE(node, -1, "foox", "bar");
293         ret |= EC_TEST_CHECK_PARSE(node, -1, "foo", "barx");
294         ret |= EC_TEST_CHECK_PARSE(node, -1, "bar", "foo");
295         ret |= EC_TEST_CHECK_PARSE(node, -1, "", "foo");
296         ec_node_free(node);
297
298         /* test completion */
299         node = EC_NODE_SEQ(EC_NO_ID,
300                 ec_node_str(EC_NO_ID, "foo"),
301                 ec_node_option(EC_NO_ID, ec_node_str(EC_NO_ID, "toto")),
302                 ec_node_str(EC_NO_ID, "bar")
303         );
304         if (node == NULL) {
305                 EC_LOG(EC_LOG_ERR, "cannot create node\n");
306                 return -1;
307         }
308         ret |= EC_TEST_CHECK_COMPLETE(node,
309                 "", EC_NODE_ENDLIST,
310                 "foo", EC_NODE_ENDLIST);
311         ec_node_free(node);
312         return 0;
313         ret |= EC_TEST_CHECK_COMPLETE(node,
314                 "f", EC_NODE_ENDLIST,
315                 "foo", EC_NODE_ENDLIST);
316         ret |= EC_TEST_CHECK_COMPLETE(node,
317                 "foo", EC_NODE_ENDLIST,
318                 "foo", EC_NODE_ENDLIST);
319         ret |= EC_TEST_CHECK_COMPLETE(node,
320                 "foo", "", EC_NODE_ENDLIST,
321                 "bar", "toto", EC_NODE_ENDLIST);
322         ret |= EC_TEST_CHECK_COMPLETE(node,
323                 "foo", "t", EC_NODE_ENDLIST,
324                 "toto", EC_NODE_ENDLIST);
325         ret |= EC_TEST_CHECK_COMPLETE(node,
326                 "foo", "b", EC_NODE_ENDLIST,
327                 "bar", EC_NODE_ENDLIST);
328         ret |= EC_TEST_CHECK_COMPLETE(node,
329                 "foo", "bar", EC_NODE_ENDLIST,
330                 "bar", EC_NODE_ENDLIST);
331         ret |= EC_TEST_CHECK_COMPLETE(node,
332                 "x", EC_NODE_ENDLIST,
333                 EC_NODE_ENDLIST);
334         ret |= EC_TEST_CHECK_COMPLETE(node,
335                 "foobarx", EC_NODE_ENDLIST,
336                 EC_NODE_ENDLIST);
337         ec_node_free(node);
338
339         return ret;
340 }
341 /* LCOV_EXCL_STOP */
342
343 static struct ec_test ec_node_seq_test = {
344         .name = "node_seq",
345         .test = ec_node_seq_testcase,
346 };
347
348 EC_TEST_REGISTER(ec_node_seq_test);