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);
57 ec_node_complete_child(struct ec_node *node,
58 struct ec_parsed *state,
59 const struct ec_strvec *strvec)
61 struct ec_completed *completed;
62 struct ec_parsed *child;
65 /* build the node if required */
66 if (node->type->build != NULL) {
67 if ((node->flags & EC_NODE_F_BUILT) == 0) {
68 ret = node->type->build(node);
75 node->flags |= EC_NODE_F_BUILT;
77 if (node->type->complete == NULL) {
87 ec_parsed_add_child(state, child);
88 completed = node->type->complete(node, child, strvec);
91 printf("----------------------------------------------------------\n");
92 ec_node_dump(stdout, node);
93 ec_strvec_dump(stdout, strvec);
94 ec_completed_dump(stdout, completed);
95 ec_parsed_dump(stdout, state);
98 ec_parsed_del_child(state, child);
99 assert(TAILQ_EMPTY(&child->children));
100 ec_parsed_free(child);
105 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
106 const struct ec_strvec *strvec)
108 struct ec_parsed *state = ec_parsed();
109 struct ec_completed *completed;
114 completed = ec_node_complete_child(node, state, strvec);
115 ec_parsed_free(state);
120 struct ec_completed *ec_node_complete(struct ec_node *node,
123 struct ec_strvec *strvec = NULL;
124 struct ec_completed *completed;
127 strvec = ec_strvec();
131 if (ec_strvec_add(strvec, str) < 0)
134 completed = ec_node_complete_strvec(node, strvec);
135 if (completed == NULL)
138 ec_strvec_free(strvec);
142 ec_strvec_free(strvec);
146 /* count the number of identical chars at the beginning of 2 strings */
147 static size_t strcmp_count(const char *s1, const char *s2)
151 while (s1[i] && s2[i] && s1[i] == s2[i])
157 static struct ec_completed_item *
158 ec_completed_item(enum ec_completed_type type, struct ec_parsed *state,
159 const struct ec_node *node, const char *add)
161 struct ec_completed_item *item = NULL;
163 item = ec_calloc(1, sizeof(*item));
167 /* XXX can state be NULL? */
173 for (p = state, len = 0; p != NULL;
174 p = ec_parsed_get_parent(p), len++)
177 item->path = ec_calloc(len, sizeof(*item->path));
178 if (item->path == NULL)
183 /* write path in array */
184 for (p = state, len = 0; p != NULL;
185 p = ec_parsed_get_parent(p), len++)
186 item->path[len] = p->node;
192 item->add = ec_strdup(add);
193 if (item->add == NULL)
204 ec_completed_item_free(item);
209 static int ec_completed_add_item(struct ec_completed *completed,
210 struct ec_completed_item *item)
214 if (item->add != NULL) {
215 if (completed->smallest_start == NULL) {
216 completed->smallest_start = ec_strdup(item->add);
217 if (completed->smallest_start == NULL)
220 n = strcmp_count(item->add,
221 completed->smallest_start);
222 completed->smallest_start[n] = '\0';
224 completed->count_match++;
227 TAILQ_INSERT_TAIL(&completed->matches, item, next);
233 int ec_completed_add_match(struct ec_completed *completed,
234 struct ec_parsed *state,
235 const struct ec_node *node, const char *add)
237 struct ec_completed_item *item;
240 item = ec_completed_item(EC_MATCH, state, node, add);
244 ret = ec_completed_add_item(completed, item);
246 ec_completed_item_free(item);
253 int ec_completed_add_no_match(struct ec_completed *completed,
254 struct ec_parsed *state, const struct ec_node *node)
256 struct ec_completed_item *item;
259 item = ec_completed_item(EC_NO_MATCH, state, node, NULL);
263 ret = ec_completed_add_item(completed, item);
265 ec_completed_item_free(item);
272 void ec_completed_item_free(struct ec_completed_item *item)
279 /* default completion function: return a no-match element */
280 struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node,
281 struct ec_parsed *state,
282 const struct ec_strvec *strvec)
284 struct ec_completed *completed;
289 completed = ec_completed();
290 if (completed == NULL)
293 if (ec_strvec_len(strvec) != 1)
296 if (ec_completed_add_no_match(completed, state, gen_node) < 0) {
297 ec_completed_free(completed);
304 void ec_completed_merge(struct ec_completed *completed1,
305 struct ec_completed *completed2)
307 struct ec_completed_item *item;
309 assert(completed1 != NULL);
310 assert(completed2 != NULL);
312 while (!TAILQ_EMPTY(&completed2->matches)) {
313 item = TAILQ_FIRST(&completed2->matches);
314 TAILQ_REMOVE(&completed2->matches, item, next);
315 ec_completed_add_item(completed1, item);
318 ec_completed_free(completed2);
321 void ec_completed_free(struct ec_completed *completed)
323 struct ec_completed_item *item;
325 if (completed == NULL)
328 while (!TAILQ_EMPTY(&completed->matches)) {
329 item = TAILQ_FIRST(&completed->matches);
330 TAILQ_REMOVE(&completed->matches, item, next);
331 ec_completed_item_free(item);
333 ec_free(completed->smallest_start);
337 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
339 struct ec_completed_item *item;
341 if (completed == NULL || completed->count == 0) {
342 fprintf(out, "no completion\n");
346 fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
347 completed->count, completed->count_match,
348 completed->smallest_start);
350 TAILQ_FOREACH(item, &completed->matches, next) {
351 fprintf(out, "add=<%s>, node=%p, node_type=%s\n",
352 item->add, item->node, item->node->type->name);
356 const char *ec_completed_smallest_start(
357 const struct ec_completed *completed)
359 if (completed == NULL || completed->smallest_start == NULL)
362 return completed->smallest_start;
365 unsigned int ec_completed_count(
366 const struct ec_completed *completed,
367 enum ec_completed_type type)
369 unsigned int count = 0;
371 if (completed == NULL)
375 count += completed->count_match;
376 if (type & EC_NO_MATCH)
377 count += (completed->count - completed->count_match); //XXX
382 struct ec_completed_iter *
383 ec_completed_iter(struct ec_completed *completed,
384 enum ec_completed_type type)
386 struct ec_completed_iter *iter;
388 iter = ec_calloc(1, sizeof(*iter));
392 iter->completed = completed;
394 iter->cur_item = NULL;
399 const struct ec_completed_item *ec_completed_iter_next(
400 struct ec_completed_iter *iter)
402 const struct ec_completed *completed = iter->completed;
404 if (completed == NULL)
408 if (iter->cur_item == NULL)
409 iter->cur_item = TAILQ_FIRST(&completed->matches);
411 iter->cur_item = TAILQ_NEXT(iter->cur_item, next);
413 if (iter->cur_item == NULL)
416 if (iter->cur_item->add == NULL &&
417 (iter->type & EC_NO_MATCH))
420 if (iter->cur_item->add != NULL &&
421 (iter->type & EC_MATCH))
424 } while (iter->cur_item != NULL);
426 return iter->cur_item;
429 void ec_completed_iter_free(struct ec_completed_iter *iter)