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>
39 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops,
42 struct ec_tk *tk = NULL;
45 assert(size >= sizeof(*tk));
47 tk = ec_calloc(1, size);
51 TAILQ_INIT(&tk->children);
56 tk->id = ec_strdup(id);
61 snprintf(buf, sizeof(buf), "<%s>", ops->typename);
62 tk->desc = ec_strdup(buf); // XXX ec_asprintf ?
66 tk->attrs = ec_keyval_new();
67 if (tk->attrs == NULL)
77 void ec_tk_free(struct ec_tk *tk)
82 assert(tk->refcnt > 0);
87 if (tk->ops != NULL && tk->ops->free_priv != NULL)
88 tk->ops->free_priv(tk);
95 struct ec_tk *ec_tk_clone(struct ec_tk *tk)
102 struct ec_tk *ec_tk_find(struct ec_tk *tk, const char *id)
104 struct ec_tk *child, *ret;
105 const char *tk_id = ec_tk_id(tk);
107 if (id != NULL && tk_id != NULL && !strcmp(tk_id, id))
110 TAILQ_FOREACH(child, &tk->children, next) {
111 ret = ec_tk_find(child, id);
119 struct ec_keyval *ec_tk_attrs(const struct ec_tk *tk)
124 const char *ec_tk_id(const struct ec_tk *tk)
129 struct ec_tk *ec_tk_parent(const struct ec_tk *tk)
134 struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *tk, const char *str)
136 struct ec_strvec *strvec = NULL;
137 struct ec_parsed_tk *parsed_tk;
140 strvec = ec_strvec_new();
144 if (ec_strvec_add(strvec, str) < 0)
147 parsed_tk = ec_tk_parse_tokens(tk, strvec);
148 if (parsed_tk == NULL)
151 ec_strvec_free(strvec);
155 ec_strvec_free(strvec);
159 struct ec_parsed_tk *ec_tk_parse_tokens(const struct ec_tk *tk,
160 const struct ec_strvec *strvec)
162 struct ec_parsed_tk *parsed_tk;
164 if (tk->ops->parse == NULL) {
169 parsed_tk = tk->ops->parse(tk, strvec);
175 struct ec_parsed_tk *ec_parsed_tk_new(void)
177 struct ec_parsed_tk *parsed_tk = NULL;
179 parsed_tk = ec_calloc(1, sizeof(*parsed_tk));
180 if (parsed_tk == NULL)
183 TAILQ_INIT(&parsed_tk->children);
191 void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk,
192 const struct ec_tk *tk, struct ec_strvec *strvec)
195 parsed_tk->strvec = strvec;
198 void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk)
200 struct ec_parsed_tk *child;
202 if (parsed_tk == NULL)
205 while (!TAILQ_EMPTY(&parsed_tk->children)) {
206 child = TAILQ_FIRST(&parsed_tk->children);
207 TAILQ_REMOVE(&parsed_tk->children, child, next);
208 ec_parsed_tk_free(child);
212 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
214 if (parsed_tk == NULL)
217 ec_parsed_tk_free_children(parsed_tk);
218 ec_strvec_free(parsed_tk->strvec);
222 static void __ec_parsed_tk_dump(FILE *out,
223 const struct ec_parsed_tk *parsed_tk, size_t indent)
225 struct ec_parsed_tk *child;
226 const struct ec_strvec *vec;
228 const char *id = "None", *typename = "None";
231 for (i = 0; i < indent; i++)
234 if (parsed_tk->tk != NULL) {
235 if (parsed_tk->tk->id != NULL)
236 id = parsed_tk->tk->id;
237 typename = parsed_tk->tk->ops->typename;
240 fprintf(out, "tk_type=%s id=%s vec=[", typename, id);
241 vec = ec_parsed_tk_strvec(parsed_tk);
242 for (i = 0; i < ec_strvec_len(vec); i++)
243 fprintf(out, "%s<%s>",
245 ec_strvec_val(vec, i));
248 TAILQ_FOREACH(child, &parsed_tk->children, next)
249 __ec_parsed_tk_dump(out, child, indent + 2);
252 void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
254 if (parsed_tk == NULL) {
255 fprintf(out, "parsed_tk is NULL, error in parse\n");
258 if (!ec_parsed_tk_matches(parsed_tk)) {
259 fprintf(out, "no match\n");
263 __ec_parsed_tk_dump(out, parsed_tk, 0);
266 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
267 struct ec_parsed_tk *child)
269 TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
272 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
275 struct ec_parsed_tk *child, *ret;
277 if (parsed_tk == NULL)
280 if (parsed_tk->tk != NULL &&
281 parsed_tk->tk->id != NULL &&
282 !strcmp(parsed_tk->tk->id, id))
285 TAILQ_FOREACH(child, &parsed_tk->children, next) {
286 ret = ec_parsed_tk_find_first(child, id);
294 const struct ec_strvec *ec_parsed_tk_strvec(
295 const struct ec_parsed_tk *parsed_tk)
297 if (parsed_tk == NULL || parsed_tk->strvec == NULL)
300 return parsed_tk->strvec;
303 /* number of parsed tokens */
304 size_t ec_parsed_tk_len(const struct ec_parsed_tk *parsed_tk)
306 if (parsed_tk == NULL || parsed_tk->strvec == NULL)
309 return ec_strvec_len(parsed_tk->strvec);
312 size_t ec_parsed_tk_matches(const struct ec_parsed_tk *parsed_tk)
314 if (parsed_tk == NULL)
317 if (parsed_tk->tk == NULL && TAILQ_EMPTY(&parsed_tk->children))
323 struct ec_completed_tk *ec_completed_tk_new(void)
325 struct ec_completed_tk *completed_tk = NULL;
327 completed_tk = ec_calloc(1, sizeof(*completed_tk));
328 if (completed_tk == NULL)
331 TAILQ_INIT(&completed_tk->elts);
332 completed_tk->count_match = 0;
337 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
340 struct ec_completed_tk_elt *elt = NULL;
342 elt = ec_calloc(1, sizeof(*elt));
348 elt->add = ec_strdup(add);
349 if (elt->add == NULL) {
350 ec_completed_tk_elt_free(elt);
358 /* XXX define when to use ec_tk_complete() or tk->complete()
360 * suggestion: tk->op() is internal, user calls the function
361 * other idea: have 2 functions
363 struct ec_completed_tk *ec_tk_complete(const struct ec_tk *tk,
366 struct ec_strvec *strvec = NULL;
367 struct ec_completed_tk *completed_tk;
370 strvec = ec_strvec_new();
374 if (ec_strvec_add(strvec, str) < 0)
377 completed_tk = ec_tk_complete_tokens(tk, strvec);
378 if (completed_tk == NULL)
381 ec_strvec_free(strvec);
385 ec_strvec_free(strvec);
389 /* default completion function: return a no-match element */
390 struct ec_completed_tk *ec_tk_default_complete(const struct ec_tk *gen_tk,
391 const struct ec_strvec *strvec)
393 struct ec_completed_tk *completed_tk;
394 struct ec_completed_tk_elt *completed_tk_elt;
398 completed_tk = ec_completed_tk_new();
399 if (completed_tk == NULL)
402 completed_tk_elt = ec_completed_tk_elt_new(gen_tk, NULL);
403 if (completed_tk_elt == NULL) {
404 ec_completed_tk_free(completed_tk);
408 ec_completed_tk_add_elt(completed_tk, completed_tk_elt);
413 struct ec_completed_tk *ec_tk_complete_tokens(const struct ec_tk *tk,
414 const struct ec_strvec *strvec)
416 return tk->ops->complete(tk, strvec);
419 /* count the number of identical chars at the beginning of 2 strings */
420 static size_t strcmp_count(const char *s1, const char *s2)
424 while (s1[i] && s2[i] && s1[i] == s2[i])
430 void ec_completed_tk_add_elt(
431 struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
435 TAILQ_INSERT_TAIL(&completed_tk->elts, elt, next);
436 completed_tk->count++;
437 if (elt->add != NULL)
438 completed_tk->count_match++;
439 if (elt->add != NULL) {
440 if (completed_tk->smallest_start == NULL) {
441 completed_tk->smallest_start = ec_strdup(elt->add);
443 n = strcmp_count(elt->add,
444 completed_tk->smallest_start);
445 completed_tk->smallest_start[n] = '\0';
450 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
456 void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1,
457 struct ec_completed_tk *completed_tk2)
459 struct ec_completed_tk_elt *elt;
461 assert(completed_tk1 != NULL);
462 assert(completed_tk2 != NULL);
464 while (!TAILQ_EMPTY(&completed_tk2->elts)) {
465 elt = TAILQ_FIRST(&completed_tk2->elts);
466 TAILQ_REMOVE(&completed_tk2->elts, elt, next);
467 ec_completed_tk_add_elt(completed_tk1, elt);
470 ec_completed_tk_free(completed_tk2);
473 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
475 struct ec_completed_tk_elt *elt;
477 if (completed_tk == NULL)
480 while (!TAILQ_EMPTY(&completed_tk->elts)) {
481 elt = TAILQ_FIRST(&completed_tk->elts);
482 TAILQ_REMOVE(&completed_tk->elts, elt, next);
483 ec_completed_tk_elt_free(elt);
485 ec_free(completed_tk->smallest_start);
486 ec_free(completed_tk);
489 void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
491 struct ec_completed_tk_elt *elt;
493 if (completed_tk == NULL || completed_tk->count == 0) {
494 fprintf(out, "no completion\n");
498 fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
499 completed_tk->count, completed_tk->count_match,
500 completed_tk->smallest_start);
502 TAILQ_FOREACH(elt, &completed_tk->elts, next) {
503 fprintf(out, "add=<%s>, tk=%p, tk_type=%s\n",
504 elt->add, elt->tk, elt->tk->ops->typename);
508 const char *ec_completed_tk_smallest_start(
509 const struct ec_completed_tk *completed_tk)
511 if (completed_tk == NULL || completed_tk->smallest_start == NULL)
514 return completed_tk->smallest_start;
517 unsigned int ec_completed_tk_count(
518 const struct ec_completed_tk *completed_tk,
519 enum ec_completed_tk_filter_flags flags)
521 unsigned int count = 0;
523 if (completed_tk == NULL)
526 if (flags & EC_MATCH)
527 count += completed_tk->count_match;
528 if (flags & EC_NO_MATCH)
529 count += (completed_tk->count - completed_tk->count_match); //XXX
534 struct ec_completed_tk_iter *
535 ec_completed_tk_iter_new(struct ec_completed_tk *completed_tk,
536 enum ec_completed_tk_filter_flags flags)
538 struct ec_completed_tk_iter *iter;
540 iter = ec_calloc(1, sizeof(*iter));
544 iter->completed_tk = completed_tk;
551 const struct ec_completed_tk_elt *ec_completed_tk_iter_next(
552 struct ec_completed_tk_iter *iter)
554 if (iter->completed_tk == NULL)
558 if (iter->cur == NULL) {
559 iter->cur = TAILQ_FIRST(&iter->completed_tk->elts);
561 iter->cur = TAILQ_NEXT(iter->cur, next);
564 if (iter->cur == NULL)
567 if (iter->cur->add == NULL &&
568 (iter->flags & EC_NO_MATCH))
571 if (iter->cur->add != NULL &&
572 (iter->flags & EC_MATCH))
575 } while (iter->cur != NULL);
580 void ec_completed_tk_iter_free(struct ec_completed_tk_iter *iter)
585 const char *ec_tk_desc(const struct ec_tk *tk)
587 if (tk->ops->desc != NULL)
588 return tk->ops->desc(tk);