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 static struct ec_tk_type_list tk_type_list =
41 TAILQ_HEAD_INITIALIZER(tk_type_list);
43 struct ec_tk_type *ec_tk_type_lookup(const char *name)
45 struct ec_tk_type *type;
47 TAILQ_FOREACH(type, &tk_type_list, next) {
48 if (!strcmp(name, type->name))
55 int ec_tk_type_register(struct ec_tk_type *type)
57 if (ec_tk_type_lookup(type->name) != NULL)
59 TAILQ_INSERT_TAIL(&tk_type_list, type, next);
64 void ec_tk_type_dump(FILE *out)
66 struct ec_tk_type *type;
68 TAILQ_FOREACH(type, &tk_type_list, next)
69 fprintf(out, "%s\n", type->name);
72 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_type *type,
75 struct ec_tk *tk = NULL;
78 assert(size >= sizeof(*tk));
80 ec_log(EC_LOG_DEBUG, "create node type=%s id=%s\n", type->name, id);
82 tk = ec_calloc(1, size);
86 TAILQ_INIT(&tk->children);
91 tk->id = ec_strdup(id);
96 snprintf(buf, sizeof(buf), "<%s>", type->name);
97 tk->desc = ec_strdup(buf); // XXX ec_asprintf ?
101 tk->attrs = ec_keyval_new();
102 if (tk->attrs == NULL)
112 void ec_tk_free(struct ec_tk *tk)
117 assert(tk->refcnt > 0);
119 if (--tk->refcnt > 0)
122 if (tk->type != NULL && tk->type->free_priv != NULL)
123 tk->type->free_priv(tk);
130 struct ec_tk *ec_tk_clone(struct ec_tk *tk)
137 struct ec_tk *ec_tk_find(struct ec_tk *tk, const char *id)
139 struct ec_tk *child, *ret;
140 const char *tk_id = ec_tk_id(tk);
142 if (id != NULL && tk_id != NULL && !strcmp(tk_id, id))
145 TAILQ_FOREACH(child, &tk->children, next) {
146 ret = ec_tk_find(child, id);
154 struct ec_keyval *ec_tk_attrs(const struct ec_tk *tk)
159 const char *ec_tk_id(const struct ec_tk *tk)
164 struct ec_tk *ec_tk_parent(const struct ec_tk *tk)
169 static void __ec_tk_dump(FILE *out,
170 const struct ec_tk *tk, size_t indent)
174 const char *id = "None", *typename = "None";
178 typename = tk->type->name;
181 for (i = 0; i < indent; i++) {
188 fprintf(out, "tk_type=%s id=%s\n", typename, id);
189 TAILQ_FOREACH(child, &tk->children, next)
190 __ec_tk_dump(out, child, indent + 2);
193 void ec_tk_dump(FILE *out, const struct ec_tk *tk)
195 fprintf(out, "------------------- tk dump:\n"); //XXX
198 fprintf(out, "tk is NULL\n");
202 __ec_tk_dump(out, tk, 0);
205 struct ec_parsed_tk *ec_tk_parse(struct ec_tk *tk, const char *str)
207 struct ec_strvec *strvec = NULL;
208 struct ec_parsed_tk *parsed_tk;
211 strvec = ec_strvec_new();
215 if (ec_strvec_add(strvec, str) < 0)
218 parsed_tk = ec_tk_parse_tokens(tk, strvec);
219 if (parsed_tk == NULL)
222 ec_strvec_free(strvec);
226 ec_strvec_free(strvec);
230 struct ec_parsed_tk *ec_tk_parse_tokens(struct ec_tk *tk,
231 const struct ec_strvec *strvec)
233 struct ec_parsed_tk *parsed_tk;
236 /* build the node if required */
237 if (tk->type->build != NULL) {
238 if ((tk->flags & EC_TK_F_BUILT) == 0) {
239 ret = tk->type->build(tk);
246 tk->flags |= EC_TK_F_BUILT;
248 if (tk->type->parse == NULL) {
253 parsed_tk = tk->type->parse(tk, strvec);
259 struct ec_parsed_tk *ec_parsed_tk_new(void)
261 struct ec_parsed_tk *parsed_tk = NULL;
263 parsed_tk = ec_calloc(1, sizeof(*parsed_tk));
264 if (parsed_tk == NULL)
267 TAILQ_INIT(&parsed_tk->children);
275 void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk,
276 const struct ec_tk *tk, struct ec_strvec *strvec)
279 parsed_tk->strvec = strvec;
282 void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk)
284 struct ec_parsed_tk *child;
286 if (parsed_tk == NULL)
289 while (!TAILQ_EMPTY(&parsed_tk->children)) {
290 child = TAILQ_FIRST(&parsed_tk->children);
291 TAILQ_REMOVE(&parsed_tk->children, child, next);
292 ec_parsed_tk_free(child);
296 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
298 if (parsed_tk == NULL)
301 ec_parsed_tk_free_children(parsed_tk);
302 ec_strvec_free(parsed_tk->strvec);
306 static void __ec_parsed_tk_dump(FILE *out,
307 const struct ec_parsed_tk *parsed_tk, size_t indent)
309 struct ec_parsed_tk *child;
310 const struct ec_strvec *vec;
312 const char *id = "None", *typename = "None";
314 if (parsed_tk->tk != NULL) {
315 if (parsed_tk->tk->id != NULL)
316 id = parsed_tk->tk->id;
317 typename = parsed_tk->tk->type->name;
321 for (i = 0; i < indent; i++) {
328 fprintf(out, "tk_type=%s id=%s vec=[", typename, id);
329 vec = ec_parsed_tk_strvec(parsed_tk);
330 for (i = 0; i < ec_strvec_len(vec); i++)
331 fprintf(out, "%s<%s>",
333 ec_strvec_val(vec, i));
336 TAILQ_FOREACH(child, &parsed_tk->children, next)
337 __ec_parsed_tk_dump(out, child, indent + 2);
340 void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
342 fprintf(out, "------------------- parsed_tk dump:\n"); //XXX
344 if (parsed_tk == NULL) {
345 fprintf(out, "parsed_tk is NULL, error in parse\n");
348 if (!ec_parsed_tk_matches(parsed_tk)) {
349 fprintf(out, "no match\n");
353 __ec_parsed_tk_dump(out, parsed_tk, 0);
356 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
357 struct ec_parsed_tk *child)
359 TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
362 void ec_parsed_tk_del_child(struct ec_parsed_tk *parsed_tk,
363 struct ec_parsed_tk *child)
365 TAILQ_REMOVE(&parsed_tk->children, child, next);
368 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
371 struct ec_parsed_tk *child, *ret;
373 if (parsed_tk == NULL)
376 if (parsed_tk->tk != NULL &&
377 parsed_tk->tk->id != NULL &&
378 !strcmp(parsed_tk->tk->id, id))
381 TAILQ_FOREACH(child, &parsed_tk->children, next) {
382 ret = ec_parsed_tk_find_first(child, id);
390 const struct ec_strvec *ec_parsed_tk_strvec(
391 const struct ec_parsed_tk *parsed_tk)
393 if (parsed_tk == NULL || parsed_tk->strvec == NULL)
396 return parsed_tk->strvec;
399 /* number of parsed tokens */
400 size_t ec_parsed_tk_len(const struct ec_parsed_tk *parsed_tk)
402 if (parsed_tk == NULL || parsed_tk->strvec == NULL)
405 return ec_strvec_len(parsed_tk->strvec);
408 size_t ec_parsed_tk_matches(const struct ec_parsed_tk *parsed_tk)
410 if (parsed_tk == NULL)
413 if (parsed_tk->tk == NULL && TAILQ_EMPTY(&parsed_tk->children))
419 struct ec_completed_tk *ec_completed_tk_new(void)
421 struct ec_completed_tk *completed_tk = NULL;
423 completed_tk = ec_calloc(1, sizeof(*completed_tk));
424 if (completed_tk == NULL)
427 TAILQ_INIT(&completed_tk->elts);
428 completed_tk->count_match = 0;
433 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
436 struct ec_completed_tk_elt *elt = NULL;
438 elt = ec_calloc(1, sizeof(*elt));
444 elt->add = ec_strdup(add);
445 if (elt->add == NULL) {
446 ec_completed_tk_elt_free(elt);
454 /* XXX define when to use ec_tk_complete() or tk->complete()
456 * suggestion: tk->op() is internal, user calls the function
457 * other idea: have 2 functions
459 struct ec_completed_tk *ec_tk_complete(struct ec_tk *tk,
462 struct ec_strvec *strvec = NULL;
463 struct ec_completed_tk *completed_tk;
466 strvec = ec_strvec_new();
470 if (ec_strvec_add(strvec, str) < 0)
473 completed_tk = ec_tk_complete_tokens(tk, strvec);
474 if (completed_tk == NULL)
477 ec_strvec_free(strvec);
481 ec_strvec_free(strvec);
485 /* default completion function: return a no-match element */
486 struct ec_completed_tk *ec_tk_default_complete(const struct ec_tk *gen_tk,
487 const struct ec_strvec *strvec)
489 struct ec_completed_tk *completed_tk;
490 struct ec_completed_tk_elt *completed_tk_elt;
494 completed_tk = ec_completed_tk_new();
495 if (completed_tk == NULL)
498 completed_tk_elt = ec_completed_tk_elt_new(gen_tk, NULL);
499 if (completed_tk_elt == NULL) {
500 ec_completed_tk_free(completed_tk);
504 ec_completed_tk_add_elt(completed_tk, completed_tk_elt);
509 struct ec_completed_tk *ec_tk_complete_tokens(struct ec_tk *tk,
510 const struct ec_strvec *strvec)
514 /* build the node if required */
515 if (tk->type->build != NULL) {
516 if ((tk->flags & EC_TK_F_BUILT) == 0) {
517 ret = tk->type->build(tk);
524 tk->flags |= EC_TK_F_BUILT;
526 if (tk->type->complete == NULL) {
531 return tk->type->complete(tk, strvec);
534 /* count the number of identical chars at the beginning of 2 strings */
535 static size_t strcmp_count(const char *s1, const char *s2)
539 while (s1[i] && s2[i] && s1[i] == s2[i])
545 void ec_completed_tk_add_elt(
546 struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
550 TAILQ_INSERT_TAIL(&completed_tk->elts, elt, next);
551 completed_tk->count++;
552 if (elt->add != NULL)
553 completed_tk->count_match++;
554 if (elt->add != NULL) {
555 if (completed_tk->smallest_start == NULL) {
556 completed_tk->smallest_start = ec_strdup(elt->add);
558 n = strcmp_count(elt->add,
559 completed_tk->smallest_start);
560 completed_tk->smallest_start[n] = '\0';
565 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
571 void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1,
572 struct ec_completed_tk *completed_tk2)
574 struct ec_completed_tk_elt *elt;
576 assert(completed_tk1 != NULL);
577 assert(completed_tk2 != NULL);
579 while (!TAILQ_EMPTY(&completed_tk2->elts)) {
580 elt = TAILQ_FIRST(&completed_tk2->elts);
581 TAILQ_REMOVE(&completed_tk2->elts, elt, next);
582 ec_completed_tk_add_elt(completed_tk1, elt);
585 ec_completed_tk_free(completed_tk2);
588 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
590 struct ec_completed_tk_elt *elt;
592 if (completed_tk == NULL)
595 while (!TAILQ_EMPTY(&completed_tk->elts)) {
596 elt = TAILQ_FIRST(&completed_tk->elts);
597 TAILQ_REMOVE(&completed_tk->elts, elt, next);
598 ec_completed_tk_elt_free(elt);
600 ec_free(completed_tk->smallest_start);
601 ec_free(completed_tk);
604 void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
606 struct ec_completed_tk_elt *elt;
608 if (completed_tk == NULL || completed_tk->count == 0) {
609 fprintf(out, "no completion\n");
613 fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
614 completed_tk->count, completed_tk->count_match,
615 completed_tk->smallest_start);
617 TAILQ_FOREACH(elt, &completed_tk->elts, next) {
618 fprintf(out, "add=<%s>, tk=%p, tk_type=%s\n",
619 elt->add, elt->tk, elt->tk->type->name);
623 const char *ec_completed_tk_smallest_start(
624 const struct ec_completed_tk *completed_tk)
626 if (completed_tk == NULL || completed_tk->smallest_start == NULL)
629 return completed_tk->smallest_start;
632 unsigned int ec_completed_tk_count(
633 const struct ec_completed_tk *completed_tk,
634 enum ec_completed_tk_filter_flags flags)
636 unsigned int count = 0;
638 if (completed_tk == NULL)
641 if (flags & EC_MATCH)
642 count += completed_tk->count_match;
643 if (flags & EC_NO_MATCH)
644 count += (completed_tk->count - completed_tk->count_match); //XXX
649 struct ec_completed_tk_iter *
650 ec_completed_tk_iter_new(struct ec_completed_tk *completed_tk,
651 enum ec_completed_tk_filter_flags flags)
653 struct ec_completed_tk_iter *iter;
655 iter = ec_calloc(1, sizeof(*iter));
659 iter->completed_tk = completed_tk;
666 const struct ec_completed_tk_elt *ec_completed_tk_iter_next(
667 struct ec_completed_tk_iter *iter)
669 if (iter->completed_tk == NULL)
673 if (iter->cur == NULL) {
674 iter->cur = TAILQ_FIRST(&iter->completed_tk->elts);
676 iter->cur = TAILQ_NEXT(iter->cur, next);
679 if (iter->cur == NULL)
682 if (iter->cur->add == NULL &&
683 (iter->flags & EC_NO_MATCH))
686 if (iter->cur->add != NULL &&
687 (iter->flags & EC_MATCH))
690 } while (iter->cur != NULL);
695 void ec_completed_tk_iter_free(struct ec_completed_tk_iter *iter)
700 const char *ec_tk_desc(const struct ec_tk *tk)
702 if (tk->type->desc != NULL)
703 return tk->type->desc(tk);