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_item {
43 TAILQ_ENTRY(ec_completed_item) next;
44 enum ec_completed_type type;
45 const struct ec_node *node;
48 struct ec_keyval *attrs;
50 /* reverse order: [0] = last, [len-1] = root */
51 const struct ec_node **path;
55 struct ec_completed *ec_completed(void)
57 struct ec_completed *completed = NULL;
59 completed = ec_calloc(1, sizeof(*completed));
60 if (completed == NULL)
63 TAILQ_INIT(&completed->nodes);
65 completed->attrs = ec_keyval();
66 if (completed->attrs == NULL)
72 if (completed != NULL)
73 ec_keyval_free(completed->attrs);
79 /* XXX on error, states are not freed ?
80 * they can be left in a bad state and should not be reused */
82 ec_node_complete_child(struct ec_node *node,
83 struct ec_completed *completed,
84 struct ec_parsed *parsed_state,
85 const struct ec_strvec *strvec)
87 struct ec_parsed *child_state = NULL;
90 /* build the node if required */
91 if (node->type->build != NULL) {
92 if ((node->flags & EC_NODE_F_BUILT) == 0) {
93 ret = node->type->build(node);
98 node->flags |= EC_NODE_F_BUILT;
100 if (node->type->complete == NULL)
103 child_state = ec_parsed();
104 if (child_state == NULL)
106 child_state->node = node;
107 ec_parsed_add_child(parsed_state, child_state);
109 ret = node->type->complete(node, completed, child_state, strvec);
114 printf("----------------------------------------------------------\n");
115 ec_node_dump(stdout, node);
116 ec_strvec_dump(stdout, strvec);
117 ec_completed_dump(stdout, completed);
118 ec_parsed_dump(stdout, parsed_state);
121 ec_parsed_del_child(parsed_state, child_state);
122 assert(TAILQ_EMPTY(&child_state->children));
123 ec_parsed_free(child_state);
128 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
129 const struct ec_strvec *strvec)
131 struct ec_parsed *parsed_state = NULL;
132 struct ec_completed *completed = NULL;
135 parsed_state = ec_parsed();
136 if (parsed_state == NULL)
139 completed = ec_completed();
140 if (completed == NULL)
143 ret = ec_node_complete_child(node, completed,
144 parsed_state, strvec);
148 ec_parsed_free(parsed_state);
153 ec_parsed_free(parsed_state);
154 ec_completed_free(completed);
158 struct ec_completed *ec_node_complete(struct ec_node *node,
161 struct ec_strvec *strvec = NULL;
162 struct ec_completed *completed;
165 strvec = ec_strvec();
169 if (ec_strvec_add(strvec, str) < 0)
172 completed = ec_node_complete_strvec(node, strvec);
173 if (completed == NULL)
176 ec_strvec_free(strvec);
180 ec_strvec_free(strvec);
184 static struct ec_completed_node *
185 ec_completed_node(const struct ec_node *node)
187 struct ec_completed_node *compnode = NULL;
189 compnode = ec_calloc(1, sizeof(*compnode));
190 if (compnode == NULL)
193 compnode->node = node;
194 TAILQ_INIT(&compnode->items);
199 struct ec_completed_item *
200 ec_completed_item(struct ec_parsed *state, const struct ec_node *node)
202 struct ec_completed_item *item = NULL;
206 item = ec_calloc(1, sizeof(*item));
210 item->attrs = ec_keyval();
211 if (item->attrs == NULL)
215 for (p = state, len = 0; p != NULL;
216 p = ec_parsed_get_parent(p), len++)
218 /* allocate room for path */
219 item->path = ec_calloc(len, sizeof(*item->path));
220 if (item->path == NULL)
223 /* write path in array */
224 for (p = state, len = 0; p != NULL;
225 p = ec_parsed_get_parent(p), len++)
226 item->path[len] = p->node;
228 item->type = EC_NO_MATCH;
237 ec_free(item->display);
238 ec_keyval_free(item->attrs);
246 ec_completed_item_set(struct ec_completed_item *item,
247 enum ec_completed_type type, const char *str)
249 char *str_copy = NULL;
250 char *display_copy = NULL;
255 if (item->str != NULL)
264 case EC_PARTIAL_MATCH:
274 str_copy = ec_strdup(str);
275 if (str_copy == NULL)
277 display_copy = ec_strdup(str);
278 if (display_copy == NULL)
283 item->str = str_copy;
284 item->display = display_copy;
289 ec_free(display_copy);
293 int ec_completed_item_set_display(struct ec_completed_item *item,
296 char *display_copy = NULL;
299 if (item == NULL || display == NULL ||
300 item->type == EC_NO_MATCH || item->str == NULL)
304 display_copy = ec_strdup(display);
305 if (display_copy == NULL)
308 ec_free(item->display);
309 item->display = display_copy;
314 ec_free(display_copy);
319 ec_completed_item_add(struct ec_completed *completed,
320 struct ec_completed_item *item)
322 struct ec_completed_node *compnode = NULL;
324 if (completed == NULL || item == NULL || item->node == NULL)
327 switch (item->type) {
331 case EC_PARTIAL_MATCH:
332 completed->count_match++; //XXX
338 /* find the compnode entry corresponding to this node */
339 TAILQ_FOREACH(compnode, &completed->nodes, next) {
340 if (compnode->node == item->node)
343 if (compnode == NULL) {
344 compnode = ec_completed_node(item->node);
345 if (compnode == NULL)
347 TAILQ_INSERT_TAIL(&completed->nodes, compnode, next);
351 TAILQ_INSERT_TAIL(&compnode->items, item, next);
357 ec_completed_item_get_str(const struct ec_completed_item *item)
363 ec_completed_item_get_display(const struct ec_completed_item *item)
365 return item->display;
368 enum ec_completed_type
369 ec_completed_item_get_type(const struct ec_completed_item *item)
374 void ec_completed_item_free(struct ec_completed_item *item)
380 ec_free(item->display);
382 ec_keyval_free(item->attrs);
386 /* default completion function: return a no-match element */
388 ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch
389 struct ec_completed *completed,
390 struct ec_parsed *parsed_state,
391 const struct ec_strvec *strvec)
393 struct ec_completed_item *item = NULL;
396 if (ec_strvec_len(strvec) != 1)
399 item = ec_completed_item(parsed_state, gen_node);
402 ret = ec_completed_item_set(item, EC_NO_MATCH, NULL);
404 ec_completed_item_free(item);
407 ret = ec_completed_item_add(completed, item);
409 ec_completed_item_free(item);
416 void ec_completed_free(struct ec_completed *completed)
418 struct ec_completed_node *compnode;
419 struct ec_completed_item *item;
421 if (completed == NULL)
424 while (!TAILQ_EMPTY(&completed->nodes)) {
425 compnode = TAILQ_FIRST(&completed->nodes);
426 TAILQ_REMOVE(&completed->nodes, compnode, next);
428 while (!TAILQ_EMPTY(&compnode->items)) {
429 item = TAILQ_FIRST(&compnode->items);
430 TAILQ_REMOVE(&compnode->items, item, next);
431 ec_completed_item_free(item);
435 ec_keyval_free(completed->attrs);
439 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
441 struct ec_completed_node *compnode;
442 struct ec_completed_item *item;
444 if (completed == NULL || completed->count == 0) {
445 fprintf(out, "no completion\n");
449 fprintf(out, "completion: count=%u match=%u\n",
450 completed->count, completed->count_match);
452 TAILQ_FOREACH(compnode, &completed->nodes, next) {
453 fprintf(out, "node=%p, node_type=%s\n",
454 compnode->node, compnode->node->type->name);
455 TAILQ_FOREACH(item, &compnode->items, next) {
458 switch (item->type) {
459 case EC_NO_MATCH: typestr = "no-match"; break;
460 case EC_MATCH: typestr = "match"; break;
461 case EC_PARTIAL_MATCH: typestr = "partial-match"; break;
462 default: typestr = "unknown"; break;
465 fprintf(out, " type=%s str=<%s> disp=<%s>\n",
466 typestr, item->str, item->display);
471 unsigned int ec_completed_count(
472 const struct ec_completed *completed,
473 enum ec_completed_type type)
475 unsigned int count = 0;
477 if (completed == NULL)
481 count += completed->count_match;
482 if (type & EC_NO_MATCH)
483 count += (completed->count - completed->count_match); //XXX
488 struct ec_completed_iter *
489 ec_completed_iter(struct ec_completed *completed,
490 enum ec_completed_type type)
492 struct ec_completed_iter *iter;
494 iter = ec_calloc(1, sizeof(*iter));
498 iter->completed = completed;
500 iter->cur_node = NULL;
501 iter->cur_match = NULL;
506 const struct ec_completed_item *ec_completed_iter_next(
507 struct ec_completed_iter *iter)
509 const struct ec_completed *completed = iter->completed;
510 const struct ec_completed_node *cur_node;
511 const struct ec_completed_item *cur_match;
513 if (completed == NULL)
516 cur_node = iter->cur_node;
517 cur_match = iter->cur_match;
520 if (cur_node == NULL) {
521 TAILQ_FOREACH(cur_node, &completed->nodes, next) {
522 TAILQ_FOREACH(cur_match, &cur_node->items, next) {
523 if (cur_match != NULL &&
524 cur_match->type & iter->type)
530 cur_match = TAILQ_NEXT(cur_match, next);
531 if (cur_match != NULL &&
532 cur_match->type & iter->type)
534 cur_node = TAILQ_NEXT(cur_node, next);
535 while (cur_node != NULL) {
536 cur_match = TAILQ_FIRST(&cur_node->items);
537 if (cur_match != NULL &&
538 cur_match->type & iter->type)
540 cur_node = TAILQ_NEXT(cur_node, next);
546 iter->cur_node = cur_node;
547 iter->cur_match = cur_match;
549 return iter->cur_match;
552 void ec_completed_iter_free(struct ec_completed_iter *iter)