2 * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
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 #include <ecoli_completed.h>
42 struct ec_completed *ec_completed(void)
44 struct ec_completed *completed = NULL;
46 completed = ec_calloc(1, sizeof(*completed));
47 if (completed == NULL)
50 TAILQ_INIT(&completed->nodes);
51 TAILQ_INIT(&completed->matches);
56 /* XXX on error, states are not freed ?
57 * they can be left in a bad state and should not be reused */
59 ec_node_complete_child(struct ec_node *node,
60 struct ec_completed *completed,
61 struct ec_parsed *parsed_state,
62 const struct ec_strvec *strvec)
64 struct ec_parsed *child_state = NULL;
67 /* build the node if required */
68 if (node->type->build != NULL) {
69 if ((node->flags & EC_NODE_F_BUILT) == 0) {
70 ret = node->type->build(node);
75 node->flags |= EC_NODE_F_BUILT;
77 if (node->type->complete == NULL)
80 child_state = ec_parsed();
81 if (child_state == NULL)
83 child_state->node = node;
84 ec_parsed_add_child(parsed_state, child_state);
86 ret = ec_completed_add_node(completed, child_state, node);
90 ret = node->type->complete(node, completed,
96 printf("----------------------------------------------------------\n");
97 ec_node_dump(stdout, node);
98 ec_strvec_dump(stdout, strvec);
99 ec_completed_dump(stdout, completed);
100 ec_parsed_dump(stdout, parsed_state);
103 ec_parsed_del_child(parsed_state, child_state);
104 assert(TAILQ_EMPTY(&child_state->children));
105 ec_parsed_free(child_state);
110 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
111 const struct ec_strvec *strvec)
113 struct ec_parsed *parsed_state = NULL;
114 struct ec_completed *completed = NULL;
117 parsed_state = ec_parsed();
118 if (parsed_state == NULL)
121 completed = ec_completed();
122 if (completed == NULL)
125 ret = ec_node_complete_child(node, completed,
126 parsed_state, strvec);
130 ec_parsed_free(parsed_state);
135 ec_parsed_free(parsed_state);
136 ec_completed_free(completed);
140 struct ec_completed *ec_node_complete(struct ec_node *node,
143 struct ec_strvec *strvec = NULL;
144 struct ec_completed *completed;
147 strvec = ec_strvec();
151 if (ec_strvec_add(strvec, str) < 0)
154 completed = ec_node_complete_strvec(node, strvec);
155 if (completed == NULL)
158 ec_strvec_free(strvec);
162 ec_strvec_free(strvec);
166 /* count the number of identical chars at the beginning of 2 strings */
167 static size_t strcmp_count(const char *s1, const char *s2)
171 while (s1[i] && s2[i] && s1[i] == s2[i])
177 static struct ec_completed_item *
178 ec_completed_item(enum ec_completed_type type, struct ec_parsed *state,
179 const struct ec_node *node, const char *add)
181 struct ec_completed_item *item = NULL;
183 item = ec_calloc(1, sizeof(*item));
187 /* XXX can state be NULL? */
193 for (p = state, len = 0; p != NULL;
194 p = ec_parsed_get_parent(p), len++)
197 item->path = ec_calloc(len, sizeof(*item->path));
198 if (item->path == NULL)
203 /* write path in array */
204 for (p = state, len = 0; p != NULL;
205 p = ec_parsed_get_parent(p), len++)
206 item->path[len] = p->node;
212 item->add = ec_strdup(add);
213 if (item->add == NULL)
224 ec_completed_item_free(item);
230 ec_completed_add_match(struct ec_completed *completed,
231 struct ec_parsed *parsed_state,
232 const struct ec_node *node, const char *add)
234 struct ec_completed_item *item = NULL;
238 item = ec_completed_item(EC_MATCH, parsed_state, node, add);
242 if (item->add != NULL) {
243 if (completed->smallest_start == NULL) {
244 completed->smallest_start = ec_strdup(item->add);
245 if (completed->smallest_start == NULL)
248 n = strcmp_count(item->add,
249 completed->smallest_start);
250 completed->smallest_start[n] = '\0';
252 completed->count_match++;
255 TAILQ_INSERT_TAIL(&completed->matches, item, next);
261 ec_completed_item_free(item);
266 ec_completed_add_node(struct ec_completed *completed,
267 struct ec_parsed *parsed_state,
268 const struct ec_node *node)
271 struct ec_completed_item *item = NULL;
274 item = ec_completed_item(EC_NO_MATCH, parsed_state, node, NULL);
278 ret = ec_completed_add_item(completed, item);
280 ec_completed_item_free(item);
290 void ec_completed_item_free(struct ec_completed_item *item)
297 /* default completion function: return a no-item element */
299 ec_node_default_complete(const struct ec_node *gen_node,
300 struct ec_completed *completed,
301 struct ec_parsed *parsed,
302 const struct ec_strvec *strvec)
306 if (ec_strvec_len(strvec) != 1) //XXX needed?
309 if (ec_completed_add_node(completed, parsed, gen_node) < 0)
315 void ec_completed_merge(struct ec_completed *completed1,
316 struct ec_completed *completed2)
318 struct ec_completed_item *item;
320 assert(completed1 != NULL);
321 assert(completed2 != NULL);
323 while (!TAILQ_EMPTY(&completed2->matches)) {
324 item = TAILQ_FIRST(&completed2->matches);
325 TAILQ_REMOVE(&completed2->matches, item, next);
326 //ec_completed_add_item(completed1, item);
329 ec_completed_free(completed2);
332 void ec_completed_free(struct ec_completed *completed)
334 struct ec_completed_item *item;
336 if (completed == NULL)
339 while (!TAILQ_EMPTY(&completed->matches)) {
340 item = TAILQ_FIRST(&completed->matches);
341 TAILQ_REMOVE(&completed->matches, item, next);
342 ec_completed_item_free(item);
344 ec_free(completed->smallest_start);
348 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
350 struct ec_completed_item *item;
352 if (completed == NULL || completed->count == 0) {
353 fprintf(out, "no completion\n");
357 fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
358 completed->count, completed->count_match,
359 completed->smallest_start);
361 TAILQ_FOREACH(item, &completed->matches, next) {
362 fprintf(out, "add=<%s>, node=%p, node_type=%s\n",
363 item->add, item->node, item->node->type->name);
367 const char *ec_completed_smallest_start(
368 const struct ec_completed *completed)
370 if (completed == NULL || completed->smallest_start == NULL)
373 return completed->smallest_start;
376 unsigned int ec_completed_count(
377 const struct ec_completed *completed,
378 enum ec_completed_type type)
380 unsigned int count = 0;
382 if (completed == NULL)
386 count += completed->count_match;
387 if (type & EC_NO_MATCH)
388 count += (completed->count - completed->count_match); //XXX
393 struct ec_completed_iter *
394 ec_completed_iter(struct ec_completed *completed,
395 enum ec_completed_type type)
397 struct ec_completed_iter *iter;
399 iter = ec_calloc(1, sizeof(*iter));
403 iter->completed = completed;
405 iter->cur_item = NULL;
410 const struct ec_completed_item *ec_completed_iter_next(
411 struct ec_completed_iter *iter)
413 const struct ec_completed *completed = iter->completed;
415 if (completed == NULL)
419 if (iter->cur_item == NULL)
420 iter->cur_item = TAILQ_FIRST(&completed->matches);
422 iter->cur_item = TAILQ_NEXT(iter->cur_item, next);
424 if (iter->cur_item == NULL)
427 if (iter->cur_item->add == NULL &&
428 (iter->type & EC_NO_MATCH))
431 if (iter->cur_item->add != NULL &&
432 (iter->type & EC_MATCH))
435 } while (iter->cur_item != NULL);
437 return iter->cur_item;
440 void ec_completed_iter_free(struct ec_completed_iter *iter)