save
[protos/libecoli.git] / lib / ecoli_tk.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
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.
15  *
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.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
34 #include <ecoli_malloc.h>
35 #include <ecoli_strvec.h>
36 #include <ecoli_keyval.h>
37 #include <ecoli_log.h>
38 #include <ecoli_tk.h>
39
40 static struct ec_tk_type_list tk_type_list =
41         TAILQ_HEAD_INITIALIZER(tk_type_list);
42
43 struct ec_tk_type *ec_tk_type_lookup(const char *name)
44 {
45         struct ec_tk_type *type;
46
47         TAILQ_FOREACH(type, &tk_type_list, next) {
48                 if (!strcmp(name, type->name))
49                         return type;
50         }
51
52         return NULL;
53 }
54
55 int ec_tk_type_register(struct ec_tk_type *type)
56 {
57         if (ec_tk_type_lookup(type->name) != NULL)
58                 return -EEXIST;
59         TAILQ_INSERT_TAIL(&tk_type_list, type, next);
60
61         return 0;
62 }
63
64 void ec_tk_type_dump(FILE *out)
65 {
66         struct ec_tk_type *type;
67
68         TAILQ_FOREACH(type, &tk_type_list, next)
69                 fprintf(out, "%s\n", type->name);
70 }
71
72 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_type *type,
73         size_t size)
74 {
75         struct ec_tk *tk = NULL;
76         char buf[256]; // XXX
77
78         assert(size >= sizeof(*tk));
79
80         ec_log(EC_LOG_DEBUG, "create node type=%s id=%s\n", type->name, id);
81
82         tk = ec_calloc(1, size);
83         if (tk == NULL)
84                 goto fail;
85
86         TAILQ_INIT(&tk->children);
87         tk->type = type;
88         tk->refcnt = 1;
89
90         if (id != NULL) {
91                 tk->id = ec_strdup(id);
92                 if (tk->id == NULL)
93                         goto fail;
94         }
95
96         snprintf(buf, sizeof(buf), "<%s>", type->name);
97         tk->desc = ec_strdup(buf); // XXX ec_asprintf ?
98         if (tk->desc == NULL)
99                 goto fail;
100
101         tk->attrs = ec_keyval_new();
102         if (tk->attrs == NULL)
103                 goto fail;
104
105         return tk;
106
107  fail:
108         ec_tk_free(tk);
109         return NULL;
110 }
111
112 void ec_tk_free(struct ec_tk *tk)
113 {
114         if (tk == NULL)
115                 return;
116
117         assert(tk->refcnt > 0);
118
119         if (--tk->refcnt > 0)
120                 return;
121
122         if (tk->type != NULL && tk->type->free_priv != NULL)
123                 tk->type->free_priv(tk);
124         ec_free(tk->id);
125         ec_free(tk->desc);
126         ec_free(tk->attrs);
127         ec_free(tk);
128 }
129
130 struct ec_tk *ec_tk_clone(struct ec_tk *tk)
131 {
132         if (tk != NULL)
133                 tk->refcnt++;
134         return tk;
135 }
136
137 struct ec_tk *ec_tk_find(struct ec_tk *tk, const char *id)
138 {
139         struct ec_tk *child, *ret;
140         const char *tk_id = ec_tk_id(tk);
141
142         if (id != NULL && tk_id != NULL && !strcmp(tk_id, id))
143                 return tk;
144
145         TAILQ_FOREACH(child, &tk->children, next) {
146                 ret = ec_tk_find(child, id);
147                 if (ret != NULL)
148                         return ret;
149         }
150
151         return NULL;
152 }
153
154 struct ec_keyval *ec_tk_attrs(const struct ec_tk *tk)
155 {
156         return tk->attrs;
157 }
158
159 const char *ec_tk_id(const struct ec_tk *tk)
160 {
161         return tk->id;
162 }
163
164 struct ec_tk *ec_tk_parent(const struct ec_tk *tk)
165 {
166         return tk->parent;
167 }
168
169 static void __ec_tk_dump(FILE *out,
170         const struct ec_tk *tk, size_t indent)
171 {
172         struct ec_tk *child;
173         size_t i;
174         const char *id = "None", *typename = "None";
175
176         if (tk->id != NULL)
177                 id = tk->id;
178         typename = tk->type->name;
179
180         /* XXX enhance */
181         for (i = 0; i < indent; i++) {
182                 if (i % 2)
183                         fprintf(out, " ");
184                 else
185                         fprintf(out, "|");
186         }
187
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);
191 }
192
193 void ec_tk_dump(FILE *out, const struct ec_tk *tk)
194 {
195         fprintf(out, "------------------- tk dump:\n"); //XXX
196
197         if (tk == NULL) {
198                 fprintf(out, "tk is NULL\n");
199                 return;
200         }
201
202         __ec_tk_dump(out, tk, 0);
203 }
204
205 struct ec_parsed_tk *ec_tk_parse(struct ec_tk *tk, const char *str)
206 {
207         struct ec_strvec *strvec = NULL;
208         struct ec_parsed_tk *parsed_tk;
209
210         errno = ENOMEM;
211         strvec = ec_strvec_new();
212         if (strvec == NULL)
213                 goto fail;
214
215         if (ec_strvec_add(strvec, str) < 0)
216                 goto fail;
217
218         parsed_tk = ec_tk_parse_tokens(tk, strvec);
219         if (parsed_tk == NULL)
220                 goto fail;
221
222         ec_strvec_free(strvec);
223         return parsed_tk;
224
225  fail:
226         ec_strvec_free(strvec);
227         return NULL;
228 }
229
230 struct ec_parsed_tk *ec_tk_parse_tokens(struct ec_tk *tk,
231         const struct ec_strvec *strvec)
232 {
233         struct ec_parsed_tk *parsed_tk;
234         int ret;
235
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);
240                         if (ret < 0) {
241                                 errno = -ret;
242                                 return NULL;
243                         }
244                 }
245         }
246         tk->flags |= EC_TK_F_BUILT;
247
248         if (tk->type->parse == NULL) {
249                 errno = ENOTSUP;
250                 return NULL;
251         }
252
253         parsed_tk = tk->type->parse(tk, strvec);
254
255         return parsed_tk;
256 }
257
258
259 struct ec_parsed_tk *ec_parsed_tk_new(void)
260 {
261         struct ec_parsed_tk *parsed_tk = NULL;
262
263         parsed_tk = ec_calloc(1, sizeof(*parsed_tk));
264         if (parsed_tk == NULL)
265                 goto fail;
266
267         TAILQ_INIT(&parsed_tk->children);
268
269         return parsed_tk;
270
271  fail:
272         return NULL;
273 }
274
275 void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk,
276         const struct ec_tk *tk, struct ec_strvec *strvec)
277 {
278         parsed_tk->tk = tk;
279         parsed_tk->strvec = strvec;
280 }
281
282 void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk)
283 {
284         struct ec_parsed_tk *child;
285
286         if (parsed_tk == NULL)
287                 return;
288
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);
293         }
294 }
295
296 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
297 {
298         if (parsed_tk == NULL)
299                 return;
300
301         ec_parsed_tk_free_children(parsed_tk);
302         ec_strvec_free(parsed_tk->strvec);
303         ec_free(parsed_tk);
304 }
305
306 static void __ec_parsed_tk_dump(FILE *out,
307         const struct ec_parsed_tk *parsed_tk, size_t indent)
308 {
309         struct ec_parsed_tk *child;
310         const struct ec_strvec *vec;
311         size_t i;
312         const char *id = "None", *typename = "None";
313
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;
318         }
319
320         /* XXX enhance */
321         for (i = 0; i < indent; i++) {
322                 if (i % 2)
323                         fprintf(out, " ");
324                 else
325                         fprintf(out, "|");
326         }
327
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>",
332                         i == 0 ? "" : ",",
333                         ec_strvec_val(vec, i));
334         fprintf(out, "]\n");
335
336         TAILQ_FOREACH(child, &parsed_tk->children, next)
337                 __ec_parsed_tk_dump(out, child, indent + 2);
338 }
339
340 void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
341 {
342         fprintf(out, "------------------- parsed_tk dump:\n"); //XXX
343
344         if (parsed_tk == NULL) {
345                 fprintf(out, "parsed_tk is NULL, error in parse\n");
346                 return;
347         }
348         if (!ec_parsed_tk_matches(parsed_tk)) {
349                 fprintf(out, "no match\n");
350                 return;
351         }
352
353         __ec_parsed_tk_dump(out, parsed_tk, 0);
354 }
355
356 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
357         struct ec_parsed_tk *child)
358 {
359         TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
360 }
361
362 void ec_parsed_tk_del_child(struct ec_parsed_tk *parsed_tk,
363         struct ec_parsed_tk *child)
364 {
365         TAILQ_REMOVE(&parsed_tk->children, child, next);
366 }
367
368 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
369         const char *id)
370 {
371         struct ec_parsed_tk *child, *ret;
372
373         if (parsed_tk == NULL)
374                 return NULL;
375
376         if (parsed_tk->tk != NULL &&
377                         parsed_tk->tk->id != NULL &&
378                         !strcmp(parsed_tk->tk->id, id))
379                 return parsed_tk;
380
381         TAILQ_FOREACH(child, &parsed_tk->children, next) {
382                 ret = ec_parsed_tk_find_first(child, id);
383                 if (ret != NULL)
384                         return ret;
385         }
386
387         return NULL;
388 }
389
390 const struct ec_strvec *ec_parsed_tk_strvec(
391         const struct ec_parsed_tk *parsed_tk)
392 {
393         if (parsed_tk == NULL || parsed_tk->strvec == NULL)
394                 return NULL;
395
396         return parsed_tk->strvec;
397 }
398
399 /* number of parsed tokens */
400 size_t ec_parsed_tk_len(const struct ec_parsed_tk *parsed_tk)
401 {
402         if (parsed_tk == NULL || parsed_tk->strvec == NULL)
403                 return 0;
404
405         return ec_strvec_len(parsed_tk->strvec);
406 }
407
408 size_t ec_parsed_tk_matches(const struct ec_parsed_tk *parsed_tk)
409 {
410         if (parsed_tk == NULL)
411                 return 0;
412
413         if (parsed_tk->tk == NULL && TAILQ_EMPTY(&parsed_tk->children))
414                 return 0;
415
416         return 1;
417 }
418
419 struct ec_completed_tk *ec_completed_tk_new(void)
420 {
421         struct ec_completed_tk *completed_tk = NULL;
422
423         completed_tk = ec_calloc(1, sizeof(*completed_tk));
424         if (completed_tk == NULL)
425                 return NULL;
426
427         TAILQ_INIT(&completed_tk->elts);
428         completed_tk->count_match = 0;
429
430         return completed_tk;
431 }
432
433 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
434         const char *add)
435 {
436         struct ec_completed_tk_elt *elt = NULL;
437
438         elt = ec_calloc(1, sizeof(*elt));
439         if (elt == NULL)
440                 return NULL;
441
442         elt->tk = tk;
443         if (add != NULL) {
444                 elt->add = ec_strdup(add);
445                 if (elt->add == NULL) {
446                         ec_completed_tk_elt_free(elt);
447                         return NULL;
448                 }
449         }
450
451         return elt;
452 }
453
454 /* XXX define when to use ec_tk_complete() or tk->complete()
455  * (same for parse)
456  * suggestion: tk->op() is internal, user calls the function
457  * other idea: have 2 functions
458  */
459 struct ec_completed_tk *ec_tk_complete(struct ec_tk *tk,
460         const char *str)
461 {
462         struct ec_strvec *strvec = NULL;
463         struct ec_completed_tk *completed_tk;
464
465         errno = ENOMEM;
466         strvec = ec_strvec_new();
467         if (strvec == NULL)
468                 goto fail;
469
470         if (ec_strvec_add(strvec, str) < 0)
471                 goto fail;
472
473         completed_tk = ec_tk_complete_tokens(tk, strvec);
474         if (completed_tk == NULL)
475                 goto fail;
476
477         ec_strvec_free(strvec);
478         return completed_tk;
479
480  fail:
481         ec_strvec_free(strvec);
482         return NULL;
483 }
484
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)
488 {
489         struct ec_completed_tk *completed_tk;
490         struct ec_completed_tk_elt *completed_tk_elt;
491
492         (void)strvec;
493
494         completed_tk = ec_completed_tk_new();
495         if (completed_tk == NULL)
496                 return NULL;
497
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);
501                 return NULL;
502         }
503
504         ec_completed_tk_add_elt(completed_tk, completed_tk_elt);
505
506         return completed_tk;
507 }
508
509 struct ec_completed_tk *ec_tk_complete_tokens(struct ec_tk *tk,
510         const struct ec_strvec *strvec)
511 {
512         int ret;
513
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);
518                         if (ret < 0) {
519                                 errno = -ret;
520                                 return NULL;
521                         }
522                 }
523         }
524         tk->flags |= EC_TK_F_BUILT;
525
526         if (tk->type->complete == NULL) {
527                 errno = ENOTSUP;
528                 return NULL;
529         }
530
531         return tk->type->complete(tk, strvec);
532 }
533
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)
536 {
537         size_t i = 0;
538
539         while (s1[i] && s2[i] && s1[i] == s2[i])
540                 i++;
541
542         return i;
543 }
544
545 void ec_completed_tk_add_elt(
546         struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
547 {
548         size_t n;
549
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);
557                 } else {
558                         n = strcmp_count(elt->add,
559                                 completed_tk->smallest_start);
560                         completed_tk->smallest_start[n] = '\0';
561                 }
562         }
563 }
564
565 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
566 {
567         ec_free(elt->add);
568         ec_free(elt);
569 }
570
571 void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1,
572         struct ec_completed_tk *completed_tk2)
573 {
574         struct ec_completed_tk_elt *elt;
575
576         assert(completed_tk1 != NULL);
577         assert(completed_tk2 != NULL);
578
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);
583         }
584
585         ec_completed_tk_free(completed_tk2);
586 }
587
588 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
589 {
590         struct ec_completed_tk_elt *elt;
591
592         if (completed_tk == NULL)
593                 return;
594
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);
599         }
600         ec_free(completed_tk->smallest_start);
601         ec_free(completed_tk);
602 }
603
604 void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
605 {
606         struct ec_completed_tk_elt *elt;
607
608         if (completed_tk == NULL || completed_tk->count == 0) {
609                 fprintf(out, "no completion\n");
610                 return;
611         }
612
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);
616
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);
620         }
621 }
622
623 const char *ec_completed_tk_smallest_start(
624         const struct ec_completed_tk *completed_tk)
625 {
626         if (completed_tk == NULL || completed_tk->smallest_start == NULL)
627                 return "";
628
629         return completed_tk->smallest_start;
630 }
631
632 unsigned int ec_completed_tk_count(
633         const struct ec_completed_tk *completed_tk,
634         enum ec_completed_tk_filter_flags flags)
635 {
636         unsigned int count = 0;
637
638         if (completed_tk == NULL)
639                 return count;
640
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
645
646         return count;
647 }
648
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)
652 {
653         struct ec_completed_tk_iter *iter;
654
655         iter = ec_calloc(1, sizeof(*iter));
656         if (iter == NULL)
657                 return NULL;
658
659         iter->completed_tk = completed_tk;
660         iter->flags = flags;
661         iter->cur = NULL;
662
663         return iter;
664 }
665
666 const struct ec_completed_tk_elt *ec_completed_tk_iter_next(
667         struct ec_completed_tk_iter *iter)
668 {
669         if (iter->completed_tk == NULL)
670                 return NULL;
671
672         do {
673                 if (iter->cur == NULL) {
674                         iter->cur = TAILQ_FIRST(&iter->completed_tk->elts);
675                 } else {
676                         iter->cur = TAILQ_NEXT(iter->cur, next);
677                 }
678
679                 if (iter->cur == NULL)
680                         break;
681
682                 if (iter->cur->add == NULL &&
683                                 (iter->flags & EC_NO_MATCH))
684                         break;
685
686                 if (iter->cur->add != NULL &&
687                                 (iter->flags & EC_MATCH))
688                         break;
689
690         } while (iter->cur != NULL);
691
692         return iter->cur;
693 }
694
695 void ec_completed_tk_iter_free(struct ec_completed_tk_iter *iter)
696 {
697         ec_free(iter);
698 }
699
700 const char *ec_tk_desc(const struct ec_tk *tk)
701 {
702         if (tk->type->desc != NULL)
703                 return tk->type->desc(tk);
704
705         return tk->desc;
706 }