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->elts);
51 completed->count_match = 0;
56 static struct ec_completed_elt *
57 ec_completed_elt(const struct ec_node *node, const char *add)
59 struct ec_completed_elt *elt = NULL;
61 elt = ec_calloc(1, sizeof(*elt));
67 elt->add = ec_strdup(add);
68 if (elt->add == NULL) {
69 ec_completed_elt_free(elt);
78 ec_node_complete_child(struct ec_node *node,
79 struct ec_parsed *state,
80 const struct ec_strvec *strvec)
82 struct ec_completed *completed;
83 struct ec_parsed *child;
86 /* build the node if required */
87 if (node->type->build != NULL) {
88 if ((node->flags & EC_NODE_F_BUILT) == 0) {
89 ret = node->type->build(node);
96 node->flags |= EC_NODE_F_BUILT;
98 if (node->type->complete == NULL) {
108 ec_parsed_add_child(state, child);
109 completed = node->type->complete(node, child, strvec);
112 printf("----------------------------------------------------------\n");
113 ec_node_dump(stdout, node);
114 ec_strvec_dump(stdout, strvec);
115 ec_completed_dump(stdout, completed);
116 ec_parsed_dump(stdout, state);
119 ec_parsed_del_child(state, child);
120 assert(TAILQ_EMPTY(&child->children));
121 ec_parsed_free(child);
126 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
127 const struct ec_strvec *strvec)
129 struct ec_parsed *state = ec_parsed();
130 struct ec_completed *completed;
135 completed = ec_node_complete_child(node, state, strvec);
136 ec_parsed_free(state);
141 struct ec_completed *ec_node_complete(struct ec_node *node,
144 struct ec_strvec *strvec = NULL;
145 struct ec_completed *completed;
148 strvec = ec_strvec();
152 if (ec_strvec_add(strvec, str) < 0)
155 completed = ec_node_complete_strvec(node, strvec);
156 if (completed == NULL)
159 ec_strvec_free(strvec);
163 ec_strvec_free(strvec);
167 /* default completion function: return a no-match element */
168 struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node,
169 struct ec_parsed *state,
170 const struct ec_strvec *strvec)
172 struct ec_completed *completed;
177 completed = ec_completed();
178 if (completed == NULL)
181 if (ec_strvec_len(strvec) != 1)
184 if (ec_completed_add_elt(completed, gen_node, NULL) < 0) {
185 ec_completed_free(completed);
192 /* count the number of identical chars at the beginning of 2 strings */
193 static size_t strcmp_count(const char *s1, const char *s2)
197 while (s1[i] && s2[i] && s1[i] == s2[i])
203 static int __ec_completed_add_elt(struct ec_completed *completed,
204 struct ec_completed_elt *elt)
208 TAILQ_INSERT_TAIL(&completed->elts, elt, next);
210 if (elt->add != NULL) {
211 completed->count_match++;
212 if (completed->smallest_start == NULL) {
213 completed->smallest_start = ec_strdup(elt->add);
215 n = strcmp_count(elt->add,
216 completed->smallest_start);
217 completed->smallest_start[n] = '\0';
224 int ec_completed_add_elt(struct ec_completed *completed,
225 const struct ec_node *node, const char *add)
227 struct ec_completed_elt *elt;
229 elt = ec_completed_elt(node, add);
233 return __ec_completed_add_elt(completed, elt);
236 void ec_completed_elt_free(struct ec_completed_elt *elt)
242 void ec_completed_merge(struct ec_completed *completed1,
243 struct ec_completed *completed2)
245 struct ec_completed_elt *elt;
247 assert(completed1 != NULL);
248 assert(completed2 != NULL);
250 while (!TAILQ_EMPTY(&completed2->elts)) {
251 elt = TAILQ_FIRST(&completed2->elts);
252 TAILQ_REMOVE(&completed2->elts, elt, next);
253 __ec_completed_add_elt(completed1, elt);
256 ec_completed_free(completed2);
259 void ec_completed_free(struct ec_completed *completed)
261 struct ec_completed_elt *elt;
263 if (completed == NULL)
266 while (!TAILQ_EMPTY(&completed->elts)) {
267 elt = TAILQ_FIRST(&completed->elts);
268 TAILQ_REMOVE(&completed->elts, elt, next);
269 ec_completed_elt_free(elt);
271 ec_free(completed->smallest_start);
275 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
277 struct ec_completed_elt *elt;
279 if (completed == NULL || completed->count == 0) {
280 fprintf(out, "no completion\n");
284 fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
285 completed->count, completed->count_match,
286 completed->smallest_start);
288 TAILQ_FOREACH(elt, &completed->elts, next) {
289 fprintf(out, "add=<%s>, node=%p, node_type=%s\n",
290 elt->add, elt->node, elt->node->type->name);
294 const char *ec_completed_smallest_start(
295 const struct ec_completed *completed)
297 if (completed == NULL || completed->smallest_start == NULL)
300 return completed->smallest_start;
303 unsigned int ec_completed_count(
304 const struct ec_completed *completed,
305 enum ec_completed_filter_flags flags)
307 unsigned int count = 0;
309 if (completed == NULL)
312 if (flags & EC_MATCH)
313 count += completed->count_match;
314 if (flags & EC_NO_MATCH)
315 count += (completed->count - completed->count_match); //XXX
320 struct ec_completed_iter *
321 ec_completed_iter(struct ec_completed *completed,
322 enum ec_completed_filter_flags flags)
324 struct ec_completed_iter *iter;
326 iter = ec_calloc(1, sizeof(*iter));
330 iter->completed = completed;
337 const struct ec_completed_elt *ec_completed_iter_next(
338 struct ec_completed_iter *iter)
340 if (iter->completed == NULL)
344 if (iter->cur == NULL) {
345 iter->cur = TAILQ_FIRST(&iter->completed->elts);
347 iter->cur = TAILQ_NEXT(iter->cur, next);
350 if (iter->cur == NULL)
353 if (iter->cur->add == NULL &&
354 (iter->flags & EC_NO_MATCH))
357 if (iter->cur->add != NULL &&
358 (iter->flags & EC_MATCH))
361 } while (iter->cur != NULL);
366 void ec_completed_iter_free(struct ec_completed_iter *iter)