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;
46 struct ec_completed_group *grp;
49 struct ec_keyval *attrs;
52 struct ec_completed *ec_completed(void)
54 struct ec_completed *completed = NULL;
56 completed = ec_calloc(1, sizeof(*completed));
57 if (completed == NULL)
60 TAILQ_INIT(&completed->groups);
62 completed->attrs = ec_keyval();
63 if (completed->attrs == NULL)
66 completed->cur_state = NULL;
71 if (completed != NULL)
72 ec_keyval_free(completed->attrs);
78 struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed)
80 return completed->cur_state;
84 ec_node_complete_child(struct ec_node *node, struct ec_completed *completed,
85 const struct ec_strvec *strvec)
87 struct ec_parsed *child_state, *cur_state;
88 struct ec_completed_group *cur_group;
91 /* build the node if required */
92 if (node->type->build != NULL) {
93 if ((node->flags & EC_NODE_F_BUILT) == 0) {
94 ret = node->type->build(node);
99 node->flags |= EC_NODE_F_BUILT;
101 if (node->type->complete == NULL)
104 /* save previous parse state, prepare child state */
105 cur_state = completed->cur_state;
106 child_state = ec_parsed();
107 if (child_state == NULL)
110 if (cur_state != NULL)
111 ec_parsed_add_child(cur_state, child_state);
112 ec_parsed_set_node(child_state, node);
113 completed->cur_state = child_state;
114 cur_group = completed->cur_group;
115 completed->cur_group = NULL;
118 ret = node->type->complete(node, completed, strvec);
120 /* restore parent parse state */
121 if (cur_state != NULL) {
122 ec_parsed_del_child(cur_state, child_state);
123 assert(!ec_parsed_has_child(child_state));
125 ec_parsed_free(child_state);
126 completed->cur_state = cur_state;
127 completed->cur_group = cur_group;
133 printf("----------------------------------------------------------\n");
134 ec_node_dump(stdout, node);
135 ec_strvec_dump(stdout, strvec);
136 ec_completed_dump(stdout, completed);
142 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
143 const struct ec_strvec *strvec)
145 struct ec_completed *completed = NULL;
148 completed = ec_completed();
149 if (completed == NULL)
152 ret = ec_node_complete_child(node, completed, strvec);
159 ec_completed_free(completed);
163 struct ec_completed *ec_node_complete(struct ec_node *node,
166 struct ec_strvec *strvec = NULL;
167 struct ec_completed *completed;
170 strvec = ec_strvec();
174 if (ec_strvec_add(strvec, str) < 0)
177 completed = ec_node_complete_strvec(node, strvec);
178 if (completed == NULL)
181 ec_strvec_free(strvec);
185 ec_strvec_free(strvec);
189 static struct ec_completed_group *
190 ec_completed_group(const struct ec_node *node, struct ec_parsed *parsed)
192 struct ec_completed_group *grp = NULL;
194 grp = ec_calloc(1, sizeof(*grp));
198 grp->state = ec_parsed_dup(parsed);
199 if (grp->state == NULL)
203 TAILQ_INIT(&grp->items);
209 ec_parsed_free(grp->state);
214 struct ec_completed_item *
215 ec_completed_item(const struct ec_node *node)
217 struct ec_completed_item *item = NULL;
219 item = ec_calloc(1, sizeof(*item));
223 item->attrs = ec_keyval();
224 if (item->attrs == NULL)
227 item->type = EC_COMP_UNKNOWN;
235 ec_free(item->display);
236 ec_keyval_free(item->attrs);
244 ec_completed_item_set(struct ec_completed_item *item,
245 enum ec_completed_type type, const char *str)
247 char *str_copy = NULL;
248 char *display_copy = NULL;
253 if (item->str != NULL)
257 case EC_COMP_UNKNOWN:
262 case EC_PARTIAL_MATCH:
272 str_copy = ec_strdup(str);
273 if (str_copy == NULL)
275 display_copy = ec_strdup(str);
276 if (display_copy == NULL)
281 item->str = str_copy;
282 item->display = display_copy;
287 ec_free(display_copy);
291 int ec_completed_item_set_display(struct ec_completed_item *item,
294 char *display_copy = NULL;
297 if (item == NULL || display == NULL ||
298 item->type == EC_COMP_UNKNOWN || item->str == NULL)
302 display_copy = ec_strdup(display);
303 if (display_copy == NULL)
306 ec_free(item->display);
307 item->display = display_copy;
312 ec_free(display_copy);
316 // XXX refactor ec_completed_item(), ec_completed_item_add(), ec_completed_item_set*
318 ec_completed_item_add(struct ec_completed *completed,
319 struct ec_completed_item *item)
321 if (completed == NULL || item == NULL || item->node == NULL)
324 switch (item->type) {
325 case EC_COMP_UNKNOWN:
328 case EC_PARTIAL_MATCH:
329 completed->count_match++; //XXX
335 if (completed->cur_group == NULL) {
336 struct ec_completed_group *grp;
338 grp = ec_completed_group(item->node, completed->cur_state);
341 TAILQ_INSERT_TAIL(&completed->groups, grp, next);
342 completed->cur_group = grp;
346 TAILQ_INSERT_TAIL(&completed->cur_group->items, item, next);
347 item->grp = completed->cur_group;
353 ec_completed_item_get_str(const struct ec_completed_item *item)
359 ec_completed_item_get_display(const struct ec_completed_item *item)
361 return item->display;
364 enum ec_completed_type
365 ec_completed_item_get_type(const struct ec_completed_item *item)
370 const struct ec_node *
371 ec_completed_item_get_node(const struct ec_completed_item *item)
376 const struct ec_completed_group *
377 ec_completed_item_get_grp(const struct ec_completed_item *item)
382 void ec_completed_item_free(struct ec_completed_item *item)
388 ec_free(item->display);
389 ec_keyval_free(item->attrs);
393 /* default completion function: return a no-match element */
395 ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch
396 struct ec_completed *completed,
397 const struct ec_strvec *strvec)
399 struct ec_completed_item *item = NULL;
402 if (ec_strvec_len(strvec) != 1)
405 item = ec_completed_item(gen_node);
408 ret = ec_completed_item_set(item, EC_COMP_UNKNOWN, NULL);
410 ec_completed_item_free(item);
413 ret = ec_completed_item_add(completed, item);
415 ec_completed_item_free(item);
422 static void ec_completed_group_free(struct ec_completed_group *grp)
424 struct ec_completed_item *item;
429 while (!TAILQ_EMPTY(&grp->items)) {
430 item = TAILQ_FIRST(&grp->items);
431 TAILQ_REMOVE(&grp->items, item, next);
432 ec_completed_item_free(item);
434 ec_parsed_free(ec_parsed_get_root(grp->state));
438 void ec_completed_free(struct ec_completed *completed)
440 struct ec_completed_group *grp;
442 if (completed == NULL)
445 while (!TAILQ_EMPTY(&completed->groups)) {
446 grp = TAILQ_FIRST(&completed->groups);
447 TAILQ_REMOVE(&completed->groups, grp, next);
448 ec_completed_group_free(grp);
450 ec_keyval_free(completed->attrs);
454 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
456 struct ec_completed_group *grp;
457 struct ec_completed_item *item;
459 if (completed == NULL || completed->count == 0) {
460 fprintf(out, "no completion\n");
464 fprintf(out, "completion: count=%u match=%u\n",
465 completed->count, completed->count_match);
467 TAILQ_FOREACH(grp, &completed->groups, next) {
468 fprintf(out, "node=%p, node_type=%s\n",
469 grp->node, grp->node->type->name);
470 TAILQ_FOREACH(item, &grp->items, next) {
473 switch (item->type) {
474 case EC_COMP_UNKNOWN: typestr = "no-match"; break;
475 case EC_COMP_FULL: typestr = "match"; break;
476 case EC_PARTIAL_MATCH: typestr = "partial-match"; break;
477 default: typestr = "unknown"; break;
480 fprintf(out, " type=%s str=<%s> disp=<%s>\n",
481 typestr, item->str, item->display);
486 unsigned int ec_completed_count(
487 const struct ec_completed *completed,
488 enum ec_completed_type type)
490 unsigned int count = 0;
492 if (completed == NULL)
495 if (type & EC_COMP_FULL)
496 count += completed->count_match;
497 if (type & EC_COMP_UNKNOWN)
498 count += (completed->count - completed->count_match); //XXX
503 struct ec_completed_iter *
504 ec_completed_iter(struct ec_completed *completed,
505 enum ec_completed_type type)
507 struct ec_completed_iter *iter;
509 iter = ec_calloc(1, sizeof(*iter));
513 iter->completed = completed;
515 iter->cur_node = NULL;
516 iter->cur_match = NULL;
521 const struct ec_completed_item *ec_completed_iter_next(
522 struct ec_completed_iter *iter)
524 const struct ec_completed *completed = iter->completed;
525 const struct ec_completed_group *cur_node;
526 const struct ec_completed_item *cur_match;
528 if (completed == NULL)
531 cur_node = iter->cur_node;
532 cur_match = iter->cur_match;
535 if (cur_node == NULL) {
536 TAILQ_FOREACH(cur_node, &completed->groups, next) {
537 TAILQ_FOREACH(cur_match, &cur_node->items, next) {
538 if (cur_match != NULL &&
539 cur_match->type & iter->type)
545 cur_match = TAILQ_NEXT(cur_match, next);
546 if (cur_match != NULL &&
547 cur_match->type & iter->type)
549 cur_node = TAILQ_NEXT(cur_node, next);
550 while (cur_node != NULL) {
551 cur_match = TAILQ_FIRST(&cur_node->items);
552 if (cur_match != NULL &&
553 cur_match->type & iter->type)
555 cur_node = TAILQ_NEXT(cur_node, next);
561 iter->cur_node = cur_node;
562 iter->cur_match = cur_match;
564 return iter->cur_match;
567 void ec_completed_iter_free(struct ec_completed_iter *iter)