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>
40 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops,
43 struct ec_tk *tk = NULL;
46 assert(size >= sizeof(*tk));
48 ec_log(EC_LOG_DEBUG, "create node type=%s id=%s\n", ops->typename, id);
50 tk = ec_calloc(1, size);
54 TAILQ_INIT(&tk->children);
59 tk->id = ec_strdup(id);
64 snprintf(buf, sizeof(buf), "<%s>", ops->typename);
65 tk->desc = ec_strdup(buf); // XXX ec_asprintf ?
69 tk->attrs = ec_keyval_new();
70 if (tk->attrs == NULL)
80 void ec_tk_free(struct ec_tk *tk)
85 assert(tk->refcnt > 0);
90 if (tk->ops != NULL && tk->ops->free_priv != NULL)
91 tk->ops->free_priv(tk);
98 struct ec_tk *ec_tk_clone(struct ec_tk *tk)
105 struct ec_tk *ec_tk_find(struct ec_tk *tk, const char *id)
107 struct ec_tk *child, *ret;
108 const char *tk_id = ec_tk_id(tk);
110 if (id != NULL && tk_id != NULL && !strcmp(tk_id, id))
113 TAILQ_FOREACH(child, &tk->children, next) {
114 ret = ec_tk_find(child, id);
122 struct ec_keyval *ec_tk_attrs(const struct ec_tk *tk)
127 const char *ec_tk_id(const struct ec_tk *tk)
132 struct ec_tk *ec_tk_parent(const struct ec_tk *tk)
137 struct ec_parsed_tk *ec_tk_parse(struct ec_tk *tk, const char *str)
139 struct ec_strvec *strvec = NULL;
140 struct ec_parsed_tk *parsed_tk;
143 strvec = ec_strvec_new();
147 if (ec_strvec_add(strvec, str) < 0)
150 parsed_tk = ec_tk_parse_tokens(tk, strvec);
151 if (parsed_tk == NULL)
154 ec_strvec_free(strvec);
158 ec_strvec_free(strvec);
162 struct ec_parsed_tk *ec_tk_parse_tokens(struct ec_tk *tk,
163 const struct ec_strvec *strvec)
165 struct ec_parsed_tk *parsed_tk;
168 /* build the node if required */
169 if (tk->ops->build != NULL) {
170 if ((tk->flags & EC_TK_F_BUILT) == 0) {
171 ret = tk->ops->build(tk);
178 tk->flags |= EC_TK_F_BUILT;
180 if (tk->ops->parse == NULL) {
185 parsed_tk = tk->ops->parse(tk, strvec);
191 struct ec_parsed_tk *ec_parsed_tk_new(void)
193 struct ec_parsed_tk *parsed_tk = NULL;
195 parsed_tk = ec_calloc(1, sizeof(*parsed_tk));
196 if (parsed_tk == NULL)
199 TAILQ_INIT(&parsed_tk->children);
207 void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk,
208 const struct ec_tk *tk, struct ec_strvec *strvec)
211 parsed_tk->strvec = strvec;
214 void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk)
216 struct ec_parsed_tk *child;
218 if (parsed_tk == NULL)
221 while (!TAILQ_EMPTY(&parsed_tk->children)) {
222 child = TAILQ_FIRST(&parsed_tk->children);
223 TAILQ_REMOVE(&parsed_tk->children, child, next);
224 ec_parsed_tk_free(child);
228 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
230 if (parsed_tk == NULL)
233 ec_parsed_tk_free_children(parsed_tk);
234 ec_strvec_free(parsed_tk->strvec);
238 static void __ec_parsed_tk_dump(FILE *out,
239 const struct ec_parsed_tk *parsed_tk, size_t indent)
241 struct ec_parsed_tk *child;
242 const struct ec_strvec *vec;
244 const char *id = "None", *typename = "None";
246 if (parsed_tk->tk != NULL) {
247 if (parsed_tk->tk->id != NULL)
248 id = parsed_tk->tk->id;
249 typename = parsed_tk->tk->ops->typename;
252 /* XXX remove this debug hack */
253 if (!strcmp(typename, "str") || !strcmp(typename, "int"))
254 fprintf(out, ">>> ");
259 for (i = 0; i < indent; i++) {
266 fprintf(out, "tk_type=%s id=%s vec=[", typename, id);
267 vec = ec_parsed_tk_strvec(parsed_tk);
268 for (i = 0; i < ec_strvec_len(vec); i++)
269 fprintf(out, "%s<%s>",
271 ec_strvec_val(vec, i));
274 TAILQ_FOREACH(child, &parsed_tk->children, next)
275 __ec_parsed_tk_dump(out, child, indent + 2);
278 void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
280 fprintf(out, "------------------- dump:\n");
282 if (parsed_tk == NULL) {
283 fprintf(out, "parsed_tk is NULL, error in parse\n");
286 if (!ec_parsed_tk_matches(parsed_tk)) {
287 fprintf(out, "no match\n");
291 __ec_parsed_tk_dump(out, parsed_tk, 0);
294 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
295 struct ec_parsed_tk *child)
297 TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
300 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
303 struct ec_parsed_tk *child, *ret;
305 if (parsed_tk == NULL)
308 if (parsed_tk->tk != NULL &&
309 parsed_tk->tk->id != NULL &&
310 !strcmp(parsed_tk->tk->id, id))
313 TAILQ_FOREACH(child, &parsed_tk->children, next) {
314 ret = ec_parsed_tk_find_first(child, id);
322 const struct ec_strvec *ec_parsed_tk_strvec(
323 const struct ec_parsed_tk *parsed_tk)
325 if (parsed_tk == NULL || parsed_tk->strvec == NULL)
328 return parsed_tk->strvec;
331 /* number of parsed tokens */
332 size_t ec_parsed_tk_len(const struct ec_parsed_tk *parsed_tk)
334 if (parsed_tk == NULL || parsed_tk->strvec == NULL)
337 return ec_strvec_len(parsed_tk->strvec);
340 size_t ec_parsed_tk_matches(const struct ec_parsed_tk *parsed_tk)
342 if (parsed_tk == NULL)
345 if (parsed_tk->tk == NULL && TAILQ_EMPTY(&parsed_tk->children))
351 struct ec_completed_tk *ec_completed_tk_new(void)
353 struct ec_completed_tk *completed_tk = NULL;
355 completed_tk = ec_calloc(1, sizeof(*completed_tk));
356 if (completed_tk == NULL)
359 TAILQ_INIT(&completed_tk->elts);
360 completed_tk->count_match = 0;
365 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
368 struct ec_completed_tk_elt *elt = NULL;
370 elt = ec_calloc(1, sizeof(*elt));
376 elt->add = ec_strdup(add);
377 if (elt->add == NULL) {
378 ec_completed_tk_elt_free(elt);
386 /* XXX define when to use ec_tk_complete() or tk->complete()
388 * suggestion: tk->op() is internal, user calls the function
389 * other idea: have 2 functions
391 struct ec_completed_tk *ec_tk_complete(const struct ec_tk *tk,
394 struct ec_strvec *strvec = NULL;
395 struct ec_completed_tk *completed_tk;
398 strvec = ec_strvec_new();
402 if (ec_strvec_add(strvec, str) < 0)
405 completed_tk = ec_tk_complete_tokens(tk, strvec);
406 if (completed_tk == NULL)
409 ec_strvec_free(strvec);
413 ec_strvec_free(strvec);
417 /* default completion function: return a no-match element */
418 struct ec_completed_tk *ec_tk_default_complete(const struct ec_tk *gen_tk,
419 const struct ec_strvec *strvec)
421 struct ec_completed_tk *completed_tk;
422 struct ec_completed_tk_elt *completed_tk_elt;
426 completed_tk = ec_completed_tk_new();
427 if (completed_tk == NULL)
430 completed_tk_elt = ec_completed_tk_elt_new(gen_tk, NULL);
431 if (completed_tk_elt == NULL) {
432 ec_completed_tk_free(completed_tk);
436 ec_completed_tk_add_elt(completed_tk, completed_tk_elt);
441 struct ec_completed_tk *ec_tk_complete_tokens(const struct ec_tk *tk,
442 const struct ec_strvec *strvec)
444 return tk->ops->complete(tk, strvec);
447 /* count the number of identical chars at the beginning of 2 strings */
448 static size_t strcmp_count(const char *s1, const char *s2)
452 while (s1[i] && s2[i] && s1[i] == s2[i])
458 void ec_completed_tk_add_elt(
459 struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
463 TAILQ_INSERT_TAIL(&completed_tk->elts, elt, next);
464 completed_tk->count++;
465 if (elt->add != NULL)
466 completed_tk->count_match++;
467 if (elt->add != NULL) {
468 if (completed_tk->smallest_start == NULL) {
469 completed_tk->smallest_start = ec_strdup(elt->add);
471 n = strcmp_count(elt->add,
472 completed_tk->smallest_start);
473 completed_tk->smallest_start[n] = '\0';
478 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
484 void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1,
485 struct ec_completed_tk *completed_tk2)
487 struct ec_completed_tk_elt *elt;
489 assert(completed_tk1 != NULL);
490 assert(completed_tk2 != NULL);
492 while (!TAILQ_EMPTY(&completed_tk2->elts)) {
493 elt = TAILQ_FIRST(&completed_tk2->elts);
494 TAILQ_REMOVE(&completed_tk2->elts, elt, next);
495 ec_completed_tk_add_elt(completed_tk1, elt);
498 ec_completed_tk_free(completed_tk2);
501 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
503 struct ec_completed_tk_elt *elt;
505 if (completed_tk == NULL)
508 while (!TAILQ_EMPTY(&completed_tk->elts)) {
509 elt = TAILQ_FIRST(&completed_tk->elts);
510 TAILQ_REMOVE(&completed_tk->elts, elt, next);
511 ec_completed_tk_elt_free(elt);
513 ec_free(completed_tk->smallest_start);
514 ec_free(completed_tk);
517 void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
519 struct ec_completed_tk_elt *elt;
521 if (completed_tk == NULL || completed_tk->count == 0) {
522 fprintf(out, "no completion\n");
526 fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
527 completed_tk->count, completed_tk->count_match,
528 completed_tk->smallest_start);
530 TAILQ_FOREACH(elt, &completed_tk->elts, next) {
531 fprintf(out, "add=<%s>, tk=%p, tk_type=%s\n",
532 elt->add, elt->tk, elt->tk->ops->typename);
536 const char *ec_completed_tk_smallest_start(
537 const struct ec_completed_tk *completed_tk)
539 if (completed_tk == NULL || completed_tk->smallest_start == NULL)
542 return completed_tk->smallest_start;
545 unsigned int ec_completed_tk_count(
546 const struct ec_completed_tk *completed_tk,
547 enum ec_completed_tk_filter_flags flags)
549 unsigned int count = 0;
551 if (completed_tk == NULL)
554 if (flags & EC_MATCH)
555 count += completed_tk->count_match;
556 if (flags & EC_NO_MATCH)
557 count += (completed_tk->count - completed_tk->count_match); //XXX
562 struct ec_completed_tk_iter *
563 ec_completed_tk_iter_new(struct ec_completed_tk *completed_tk,
564 enum ec_completed_tk_filter_flags flags)
566 struct ec_completed_tk_iter *iter;
568 iter = ec_calloc(1, sizeof(*iter));
572 iter->completed_tk = completed_tk;
579 const struct ec_completed_tk_elt *ec_completed_tk_iter_next(
580 struct ec_completed_tk_iter *iter)
582 if (iter->completed_tk == NULL)
586 if (iter->cur == NULL) {
587 iter->cur = TAILQ_FIRST(&iter->completed_tk->elts);
589 iter->cur = TAILQ_NEXT(iter->cur, next);
592 if (iter->cur == NULL)
595 if (iter->cur->add == NULL &&
596 (iter->flags & EC_NO_MATCH))
599 if (iter->cur->add != NULL &&
600 (iter->flags & EC_MATCH))
603 } while (iter->cur != NULL);
608 void ec_completed_tk_iter_free(struct ec_completed_tk_iter *iter)
613 const char *ec_tk_desc(const struct ec_tk *tk)
615 if (tk->ops->desc != NULL)
616 return tk->ops->desc(tk);