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