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);
52 completed->attrs = ec_keyval();
53 if (completed->attrs == NULL)
59 if (completed != NULL)
60 ec_keyval_free(completed->attrs);
66 /* XXX on error, states are not freed ?
67 * they can be left in a bad state and should not be reused */
69 ec_node_complete_child(struct ec_node *node,
70 struct ec_completed *completed,
71 struct ec_parsed *parsed_state,
72 const struct ec_strvec *strvec)
74 struct ec_parsed *child_state = NULL;
77 /* build the node if required */
78 if (node->type->build != NULL) {
79 if ((node->flags & EC_NODE_F_BUILT) == 0) {
80 ret = node->type->build(node);
85 node->flags |= EC_NODE_F_BUILT;
87 if (node->type->complete == NULL)
90 child_state = ec_parsed();
91 if (child_state == NULL)
93 child_state->node = node;
94 ec_parsed_add_child(parsed_state, child_state);
96 ret = node->type->complete(node, completed, child_state, strvec);
101 printf("----------------------------------------------------------\n");
102 ec_node_dump(stdout, node);
103 ec_strvec_dump(stdout, strvec);
104 ec_completed_dump(stdout, completed);
105 ec_parsed_dump(stdout, parsed_state);
108 ec_parsed_del_child(parsed_state, child_state);
109 assert(TAILQ_EMPTY(&child_state->children));
110 ec_parsed_free(child_state);
115 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
116 const struct ec_strvec *strvec)
118 struct ec_parsed *parsed_state = NULL;
119 struct ec_completed *completed = NULL;
122 parsed_state = ec_parsed();
123 if (parsed_state == NULL)
126 completed = ec_completed();
127 if (completed == NULL)
130 ret = ec_node_complete_child(node, completed,
131 parsed_state, strvec);
135 ec_parsed_free(parsed_state);
140 ec_parsed_free(parsed_state);
141 ec_completed_free(completed);
145 struct ec_completed *ec_node_complete(struct ec_node *node,
148 struct ec_strvec *strvec = NULL;
149 struct ec_completed *completed;
152 strvec = ec_strvec();
156 if (ec_strvec_add(strvec, str) < 0)
159 completed = ec_node_complete_strvec(node, strvec);
160 if (completed == NULL)
163 ec_strvec_free(strvec);
167 ec_strvec_free(strvec);
171 static struct ec_completed_node *
172 ec_completed_node(const struct ec_node *node)
174 struct ec_completed_node *compnode = NULL;
176 compnode = ec_calloc(1, sizeof(*compnode));
177 if (compnode == NULL)
180 compnode->node = node;
181 TAILQ_INIT(&compnode->items);
186 struct ec_completed_item *
187 ec_completed_item(struct ec_parsed *state, const struct ec_node *node)
189 struct ec_completed_item *item = NULL;
193 item = ec_calloc(1, sizeof(*item));
197 item->attrs = ec_keyval();
198 if (item->attrs == NULL)
202 for (p = state, len = 0; p != NULL;
203 p = ec_parsed_get_parent(p), len++)
205 /* allocate room for path */
206 item->path = ec_calloc(len, sizeof(*item->path));
207 if (item->path == NULL)
210 /* write path in array */
211 for (p = state, len = 0; p != NULL;
212 p = ec_parsed_get_parent(p), len++)
213 item->path[len] = p->node;
215 item->type = EC_NO_MATCH;
224 ec_free(item->display);
225 ec_keyval_free(item->attrs);
233 ec_completed_item_set(struct ec_completed_item *item,
234 enum ec_completed_type type, const char *str)
236 char *str_copy = NULL;
237 char *display_copy = NULL;
242 if (item->str != NULL)
251 case EC_PARTIAL_MATCH:
261 str_copy = ec_strdup(str);
262 if (str_copy == NULL)
264 display_copy = ec_strdup(str);
265 if (display_copy == NULL)
270 item->str = str_copy;
271 item->display = display_copy;
276 ec_free(display_copy);
280 int ec_completed_item_set_display(struct ec_completed_item *item,
283 char *display_copy = NULL;
286 if (item == NULL || display == NULL ||
287 item->type == EC_NO_MATCH || item->str == NULL)
291 display_copy = ec_strdup(display);
292 if (display_copy == NULL)
295 ec_free(item->display);
296 item->display = display_copy;
301 ec_free(display_copy);
306 ec_completed_item_add(struct ec_completed *completed,
307 struct ec_completed_item *item)
309 struct ec_completed_node *compnode = NULL;
311 if (completed == NULL || item == NULL || item->node == NULL)
314 switch (item->type) {
318 case EC_PARTIAL_MATCH:
319 completed->count_match++; //XXX
325 /* find the compnode entry corresponding to this node */
326 TAILQ_FOREACH(compnode, &completed->nodes, next) {
327 if (compnode->node == item->node)
330 if (compnode == NULL) {
331 compnode = ec_completed_node(item->node);
332 if (compnode == NULL)
334 TAILQ_INSERT_TAIL(&completed->nodes, compnode, next);
338 TAILQ_INSERT_TAIL(&compnode->items, item, next);
343 void ec_completed_item_free(struct ec_completed_item *item)
349 ec_free(item->display);
351 ec_keyval_free(item->attrs);
355 /* default completion function: return a no-match element */
357 ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch
358 struct ec_completed *completed,
359 struct ec_parsed *parsed_state,
360 const struct ec_strvec *strvec)
362 struct ec_completed_item *item = NULL;
365 if (ec_strvec_len(strvec) != 1)
368 item = ec_completed_item(parsed_state, gen_node);
371 ret = ec_completed_item_set(item, EC_NO_MATCH, NULL);
373 ec_completed_item_free(item);
376 ret = ec_completed_item_add(completed, item);
378 ec_completed_item_free(item);
385 void ec_completed_free(struct ec_completed *completed)
387 struct ec_completed_node *compnode;
388 struct ec_completed_item *item;
390 if (completed == NULL)
393 while (!TAILQ_EMPTY(&completed->nodes)) {
394 compnode = TAILQ_FIRST(&completed->nodes);
395 TAILQ_REMOVE(&completed->nodes, compnode, next);
397 while (!TAILQ_EMPTY(&compnode->items)) {
398 item = TAILQ_FIRST(&compnode->items);
399 TAILQ_REMOVE(&compnode->items, item, next);
400 ec_completed_item_free(item);
404 ec_keyval_free(completed->attrs);
408 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
410 struct ec_completed_node *compnode;
411 struct ec_completed_item *item;
413 if (completed == NULL || completed->count == 0) {
414 fprintf(out, "no completion\n");
418 fprintf(out, "completion: count=%u match=%u\n",
419 completed->count, completed->count_match);
421 TAILQ_FOREACH(compnode, &completed->nodes, next) {
422 fprintf(out, "node=%p, node_type=%s\n",
423 compnode->node, compnode->node->type->name);
424 TAILQ_FOREACH(item, &compnode->items, next) {
427 switch (item->type) {
428 case EC_NO_MATCH: typestr = "no-match"; break;
429 case EC_MATCH: typestr = "match"; break;
430 case EC_PARTIAL_MATCH: typestr = "partial-match"; break;
431 default: typestr = "unknown"; break;
434 fprintf(out, " type=%s str=<%s> disp=<%s>\n",
435 typestr, item->str, item->display);
440 unsigned int ec_completed_count(
441 const struct ec_completed *completed,
442 enum ec_completed_type type)
444 unsigned int count = 0;
446 if (completed == NULL)
450 count += completed->count_match;
451 if (type & EC_NO_MATCH)
452 count += (completed->count - completed->count_match); //XXX
457 struct ec_completed_iter *
458 ec_completed_iter(struct ec_completed *completed,
459 enum ec_completed_type type)
461 struct ec_completed_iter *iter;
463 iter = ec_calloc(1, sizeof(*iter));
467 iter->completed = completed;
469 iter->cur_node = NULL;
470 iter->cur_match = NULL;
475 const struct ec_completed_item *ec_completed_iter_next(
476 struct ec_completed_iter *iter)
478 const struct ec_completed *completed = iter->completed;
479 const struct ec_completed_node *cur_node;
480 const struct ec_completed_item *cur_match;
482 if (completed == NULL)
485 cur_node = iter->cur_node;
486 cur_match = iter->cur_match;
489 if (cur_node == NULL) {
490 TAILQ_FOREACH(cur_node, &completed->nodes, next) {
491 TAILQ_FOREACH(cur_match, &cur_node->items, next) {
492 if (cur_match != NULL &&
493 cur_match->type & iter->type)
499 cur_match = TAILQ_NEXT(cur_match, next);
500 if (cur_match != NULL &&
501 cur_match->type & iter->type)
503 cur_node = TAILQ_NEXT(cur_node, next);
504 while (cur_node != NULL) {
505 cur_match = TAILQ_FIRST(&cur_node->items);
506 if (cur_match != NULL &&
507 cur_match->type & iter->type)
509 cur_node = TAILQ_NEXT(cur_node, next);
515 iter->cur_node = cur_node;
516 iter->cur_match = cur_match;
518 return iter->cur_match;
521 void ec_completed_iter_free(struct ec_completed_iter *iter)