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 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops,
41         size_t size)
42 {
43         struct ec_tk *tk = NULL;
44         char buf[256]; // XXX
45
46         assert(size >= sizeof(*tk));
47
48         ec_log(EC_LOG_DEBUG, "create node type=%s id=%s\n", ops->typename, id);
49
50         tk = ec_calloc(1, size);
51         if (tk == NULL)
52                 goto fail;
53
54         TAILQ_INIT(&tk->children);
55         tk->ops = ops;
56         tk->refcnt = 1;
57
58         if (id != NULL) {
59                 tk->id = ec_strdup(id);
60                 if (tk->id == NULL)
61                         goto fail;
62         }
63
64         snprintf(buf, sizeof(buf), "<%s>", ops->typename);
65         tk->desc = ec_strdup(buf); // XXX ec_asprintf ?
66         if (tk->desc == NULL)
67                 goto fail;
68
69         tk->attrs = ec_keyval_new();
70         if (tk->attrs == NULL)
71                 goto fail;
72
73         return tk;
74
75  fail:
76         ec_tk_free(tk);
77         return NULL;
78 }
79
80 void ec_tk_free(struct ec_tk *tk)
81 {
82         if (tk == NULL)
83                 return;
84
85         assert(tk->refcnt > 0);
86
87         if (--tk->refcnt > 0)
88                 return;
89
90         if (tk->ops != NULL && tk->ops->free_priv != NULL)
91                 tk->ops->free_priv(tk);
92         ec_free(tk->id);
93         ec_free(tk->desc);
94         ec_free(tk->attrs);
95         ec_free(tk);
96 }
97
98 struct ec_tk *ec_tk_clone(struct ec_tk *tk)
99 {
100         if (tk != NULL)
101                 tk->refcnt++;
102         return tk;
103 }
104
105 struct ec_tk *ec_tk_find(struct ec_tk *tk, const char *id)
106 {
107         struct ec_tk *child, *ret;
108         const char *tk_id = ec_tk_id(tk);
109
110         if (id != NULL && tk_id != NULL && !strcmp(tk_id, id))
111                 return tk;
112
113         TAILQ_FOREACH(child, &tk->children, next) {
114                 ret = ec_tk_find(child, id);
115                 if (ret != NULL)
116                         return ret;
117         }
118
119         return NULL;
120 }
121
122 struct ec_keyval *ec_tk_attrs(const struct ec_tk *tk)
123 {
124         return tk->attrs;
125 }
126
127 const char *ec_tk_id(const struct ec_tk *tk)
128 {
129         return tk->id;
130 }
131
132 struct ec_tk *ec_tk_parent(const struct ec_tk *tk)
133 {
134         return tk->parent;
135 }
136
137 struct ec_parsed_tk *ec_tk_parse(struct ec_tk *tk, const char *str)
138 {
139         struct ec_strvec *strvec = NULL;
140         struct ec_parsed_tk *parsed_tk;
141
142         errno = ENOMEM;
143         strvec = ec_strvec_new();
144         if (strvec == NULL)
145                 goto fail;
146
147         if (ec_strvec_add(strvec, str) < 0)
148                 goto fail;
149
150         parsed_tk = ec_tk_parse_tokens(tk, strvec);
151         if (parsed_tk == NULL)
152                 goto fail;
153
154         ec_strvec_free(strvec);
155         return parsed_tk;
156
157  fail:
158         ec_strvec_free(strvec);
159         return NULL;
160 }
161
162 struct ec_parsed_tk *ec_tk_parse_tokens(struct ec_tk *tk,
163         const struct ec_strvec *strvec)
164 {
165         struct ec_parsed_tk *parsed_tk;
166         int ret;
167
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);
172                         if (ret < 0) {
173                                 errno = -ret;
174                                 return NULL;
175                         }
176                 }
177         }
178         tk->flags |= EC_TK_F_BUILT;
179
180         if (tk->ops->parse == NULL) {
181                 errno = ENOTSUP;
182                 return NULL;
183         }
184
185         parsed_tk = tk->ops->parse(tk, strvec);
186
187         return parsed_tk;
188 }
189
190
191 struct ec_parsed_tk *ec_parsed_tk_new(void)
192 {
193         struct ec_parsed_tk *parsed_tk = NULL;
194
195         parsed_tk = ec_calloc(1, sizeof(*parsed_tk));
196         if (parsed_tk == NULL)
197                 goto fail;
198
199         TAILQ_INIT(&parsed_tk->children);
200
201         return parsed_tk;
202
203  fail:
204         return NULL;
205 }
206
207 void ec_parsed_tk_set_match(struct ec_parsed_tk *parsed_tk,
208         const struct ec_tk *tk, struct ec_strvec *strvec)
209 {
210         parsed_tk->tk = tk;
211         parsed_tk->strvec = strvec;
212 }
213
214 void ec_parsed_tk_free_children(struct ec_parsed_tk *parsed_tk)
215 {
216         struct ec_parsed_tk *child;
217
218         if (parsed_tk == NULL)
219                 return;
220
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);
225         }
226 }
227
228 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
229 {
230         if (parsed_tk == NULL)
231                 return;
232
233         ec_parsed_tk_free_children(parsed_tk);
234         ec_strvec_free(parsed_tk->strvec);
235         ec_free(parsed_tk);
236 }
237
238 static void __ec_parsed_tk_dump(FILE *out,
239         const struct ec_parsed_tk *parsed_tk, size_t indent)
240 {
241         struct ec_parsed_tk *child;
242         const struct ec_strvec *vec;
243         size_t i;
244         const char *id = "None", *typename = "None";
245
246         /* XXX enhance */
247         for (i = 0; i < indent; i++)
248                 fprintf(out, " ");
249
250         if (parsed_tk->tk != NULL) {
251                 if (parsed_tk->tk->id != NULL)
252                         id = parsed_tk->tk->id;
253                 typename = parsed_tk->tk->ops->typename;
254         }
255
256         fprintf(out, "tk_type=%s id=%s vec=[", typename, id);
257         vec = ec_parsed_tk_strvec(parsed_tk);
258         for (i = 0; i < ec_strvec_len(vec); i++)
259                 fprintf(out, "%s<%s>",
260                         i == 0 ? "" : ",",
261                         ec_strvec_val(vec, i));
262         fprintf(out, "]\n");
263
264         TAILQ_FOREACH(child, &parsed_tk->children, next)
265                 __ec_parsed_tk_dump(out, child, indent + 2);
266 }
267
268 void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
269 {
270         if (parsed_tk == NULL) {
271                 fprintf(out, "parsed_tk is NULL, error in parse\n");
272                 return;
273         }
274         if (!ec_parsed_tk_matches(parsed_tk)) {
275                 fprintf(out, "no match\n");
276                 return;
277         }
278
279         __ec_parsed_tk_dump(out, parsed_tk, 0);
280 }
281
282 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
283         struct ec_parsed_tk *child)
284 {
285         TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
286 }
287
288 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
289         const char *id)
290 {
291         struct ec_parsed_tk *child, *ret;
292
293         if (parsed_tk == NULL)
294                 return NULL;
295
296         if (parsed_tk->tk != NULL &&
297                         parsed_tk->tk->id != NULL &&
298                         !strcmp(parsed_tk->tk->id, id))
299                 return parsed_tk;
300
301         TAILQ_FOREACH(child, &parsed_tk->children, next) {
302                 ret = ec_parsed_tk_find_first(child, id);
303                 if (ret != NULL)
304                         return ret;
305         }
306
307         return NULL;
308 }
309
310 const struct ec_strvec *ec_parsed_tk_strvec(
311         const struct ec_parsed_tk *parsed_tk)
312 {
313         if (parsed_tk == NULL || parsed_tk->strvec == NULL)
314                 return NULL;
315
316         return parsed_tk->strvec;
317 }
318
319 /* number of parsed tokens */
320 size_t ec_parsed_tk_len(const struct ec_parsed_tk *parsed_tk)
321 {
322         if (parsed_tk == NULL || parsed_tk->strvec == NULL)
323                 return 0;
324
325         return ec_strvec_len(parsed_tk->strvec);
326 }
327
328 size_t ec_parsed_tk_matches(const struct ec_parsed_tk *parsed_tk)
329 {
330         if (parsed_tk == NULL)
331                 return 0;
332
333         if (parsed_tk->tk == NULL && TAILQ_EMPTY(&parsed_tk->children))
334                 return 0;
335
336         return 1;
337 }
338
339 struct ec_completed_tk *ec_completed_tk_new(void)
340 {
341         struct ec_completed_tk *completed_tk = NULL;
342
343         completed_tk = ec_calloc(1, sizeof(*completed_tk));
344         if (completed_tk == NULL)
345                 return NULL;
346
347         TAILQ_INIT(&completed_tk->elts);
348         completed_tk->count_match = 0;
349
350         return completed_tk;
351 }
352
353 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
354         const char *add)
355 {
356         struct ec_completed_tk_elt *elt = NULL;
357
358         elt = ec_calloc(1, sizeof(*elt));
359         if (elt == NULL)
360                 return NULL;
361
362         elt->tk = tk;
363         if (add != NULL) {
364                 elt->add = ec_strdup(add);
365                 if (elt->add == NULL) {
366                         ec_completed_tk_elt_free(elt);
367                         return NULL;
368                 }
369         }
370
371         return elt;
372 }
373
374 /* XXX define when to use ec_tk_complete() or tk->complete()
375  * (same for parse)
376  * suggestion: tk->op() is internal, user calls the function
377  * other idea: have 2 functions
378  */
379 struct ec_completed_tk *ec_tk_complete(const struct ec_tk *tk,
380         const char *str)
381 {
382         struct ec_strvec *strvec = NULL;
383         struct ec_completed_tk *completed_tk;
384
385         errno = ENOMEM;
386         strvec = ec_strvec_new();
387         if (strvec == NULL)
388                 goto fail;
389
390         if (ec_strvec_add(strvec, str) < 0)
391                 goto fail;
392
393         completed_tk = ec_tk_complete_tokens(tk, strvec);
394         if (completed_tk == NULL)
395                 goto fail;
396
397         ec_strvec_free(strvec);
398         return completed_tk;
399
400  fail:
401         ec_strvec_free(strvec);
402         return NULL;
403 }
404
405 /* default completion function: return a no-match element */
406 struct ec_completed_tk *ec_tk_default_complete(const struct ec_tk *gen_tk,
407         const struct ec_strvec *strvec)
408 {
409         struct ec_completed_tk *completed_tk;
410         struct ec_completed_tk_elt *completed_tk_elt;
411
412         (void)strvec;
413
414         completed_tk = ec_completed_tk_new();
415         if (completed_tk == NULL)
416                 return NULL;
417
418         completed_tk_elt = ec_completed_tk_elt_new(gen_tk, NULL);
419         if (completed_tk_elt == NULL) {
420                 ec_completed_tk_free(completed_tk);
421                 return NULL;
422         }
423
424         ec_completed_tk_add_elt(completed_tk, completed_tk_elt);
425
426         return completed_tk;
427 }
428
429 struct ec_completed_tk *ec_tk_complete_tokens(const struct ec_tk *tk,
430         const struct ec_strvec *strvec)
431 {
432         return tk->ops->complete(tk, strvec);
433 }
434
435 /* count the number of identical chars at the beginning of 2 strings */
436 static size_t strcmp_count(const char *s1, const char *s2)
437 {
438         size_t i = 0;
439
440         while (s1[i] && s2[i] && s1[i] == s2[i])
441                 i++;
442
443         return i;
444 }
445
446 void ec_completed_tk_add_elt(
447         struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
448 {
449         size_t n;
450
451         TAILQ_INSERT_TAIL(&completed_tk->elts, elt, next);
452         completed_tk->count++;
453         if (elt->add != NULL)
454                 completed_tk->count_match++;
455         if (elt->add != NULL) {
456                 if (completed_tk->smallest_start == NULL) {
457                         completed_tk->smallest_start = ec_strdup(elt->add);
458                 } else {
459                         n = strcmp_count(elt->add,
460                                 completed_tk->smallest_start);
461                         completed_tk->smallest_start[n] = '\0';
462                 }
463         }
464 }
465
466 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
467 {
468         ec_free(elt->add);
469         ec_free(elt);
470 }
471
472 void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1,
473         struct ec_completed_tk *completed_tk2)
474 {
475         struct ec_completed_tk_elt *elt;
476
477         assert(completed_tk1 != NULL);
478         assert(completed_tk2 != NULL);
479
480         while (!TAILQ_EMPTY(&completed_tk2->elts)) {
481                 elt = TAILQ_FIRST(&completed_tk2->elts);
482                 TAILQ_REMOVE(&completed_tk2->elts, elt, next);
483                 ec_completed_tk_add_elt(completed_tk1, elt);
484         }
485
486         ec_completed_tk_free(completed_tk2);
487 }
488
489 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
490 {
491         struct ec_completed_tk_elt *elt;
492
493         if (completed_tk == NULL)
494                 return;
495
496         while (!TAILQ_EMPTY(&completed_tk->elts)) {
497                 elt = TAILQ_FIRST(&completed_tk->elts);
498                 TAILQ_REMOVE(&completed_tk->elts, elt, next);
499                 ec_completed_tk_elt_free(elt);
500         }
501         ec_free(completed_tk->smallest_start);
502         ec_free(completed_tk);
503 }
504
505 void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
506 {
507         struct ec_completed_tk_elt *elt;
508
509         if (completed_tk == NULL || completed_tk->count == 0) {
510                 fprintf(out, "no completion\n");
511                 return;
512         }
513
514         fprintf(out, "completion: count=%u match=%u smallest_start=<%s>\n",
515                 completed_tk->count, completed_tk->count_match,
516                 completed_tk->smallest_start);
517
518         TAILQ_FOREACH(elt, &completed_tk->elts, next) {
519                 fprintf(out, "add=<%s>, tk=%p, tk_type=%s\n",
520                         elt->add, elt->tk, elt->tk->ops->typename);
521         }
522 }
523
524 const char *ec_completed_tk_smallest_start(
525         const struct ec_completed_tk *completed_tk)
526 {
527         if (completed_tk == NULL || completed_tk->smallest_start == NULL)
528                 return "";
529
530         return completed_tk->smallest_start;
531 }
532
533 unsigned int ec_completed_tk_count(
534         const struct ec_completed_tk *completed_tk,
535         enum ec_completed_tk_filter_flags flags)
536 {
537         unsigned int count = 0;
538
539         if (completed_tk == NULL)
540                 return count;
541
542         if (flags & EC_MATCH)
543                 count += completed_tk->count_match;
544         if (flags & EC_NO_MATCH)
545                 count += (completed_tk->count - completed_tk->count_match); //XXX
546
547         return count;
548 }
549
550 struct ec_completed_tk_iter *
551 ec_completed_tk_iter_new(struct ec_completed_tk *completed_tk,
552         enum ec_completed_tk_filter_flags flags)
553 {
554         struct ec_completed_tk_iter *iter;
555
556         iter = ec_calloc(1, sizeof(*iter));
557         if (iter == NULL)
558                 return NULL;
559
560         iter->completed_tk = completed_tk;
561         iter->flags = flags;
562         iter->cur = NULL;
563
564         return iter;
565 }
566
567 const struct ec_completed_tk_elt *ec_completed_tk_iter_next(
568         struct ec_completed_tk_iter *iter)
569 {
570         if (iter->completed_tk == NULL)
571                 return NULL;
572
573         do {
574                 if (iter->cur == NULL) {
575                         iter->cur = TAILQ_FIRST(&iter->completed_tk->elts);
576                 } else {
577                         iter->cur = TAILQ_NEXT(iter->cur, next);
578                 }
579
580                 if (iter->cur == NULL)
581                         break;
582
583                 if (iter->cur->add == NULL &&
584                                 (iter->flags & EC_NO_MATCH))
585                         break;
586
587                 if (iter->cur->add != NULL &&
588                                 (iter->flags & EC_MATCH))
589                         break;
590
591         } while (iter->cur != NULL);
592
593         return iter->cur;
594 }
595
596 void ec_completed_tk_iter_free(struct ec_completed_tk_iter *iter)
597 {
598         ec_free(iter);
599 }
600
601 const char *ec_tk_desc(const struct ec_tk *tk)
602 {
603         if (tk->ops->desc != NULL)
604                 return tk->ops->desc(tk);
605
606         return tk->desc;
607 }