save state in completed objects
[protos/libecoli.git] / lib / ecoli_completed.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_node.h>
39 #include <ecoli_parsed.h>
40 #include <ecoli_completed.h>
41
42 struct ec_completed_item {
43         TAILQ_ENTRY(ec_completed_item) next;
44         enum ec_completed_type type;
45         const struct ec_node *node;
46         struct ec_completed_group *grp;
47         char *str;
48         char *display;
49         struct ec_keyval *attrs;
50 };
51
52 struct ec_completed *ec_completed(void)
53 {
54         struct ec_completed *completed = NULL;
55
56         completed = ec_calloc(1, sizeof(*completed));
57         if (completed == NULL)
58                 goto fail;
59
60         TAILQ_INIT(&completed->groups);
61
62         completed->attrs = ec_keyval();
63         if (completed->attrs == NULL)
64                 goto fail;
65
66         completed->cur_state = NULL;
67
68         return completed;
69
70  fail:
71         if (completed != NULL)
72                 ec_keyval_free(completed->attrs);
73         ec_free(completed);
74
75         return NULL;
76 }
77
78 struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed)
79 {
80         return completed->cur_state;
81 }
82
83 int
84 ec_node_complete_child(struct ec_node *node, struct ec_completed *completed,
85                         const struct ec_strvec *strvec)
86 {
87         struct ec_parsed *child_state, *cur_state;
88         struct ec_completed_group *cur_group;
89         int ret;
90
91         /* build the node if required */
92         if (node->type->build != NULL) {
93                 if ((node->flags & EC_NODE_F_BUILT) == 0) {
94                         ret = node->type->build(node);
95                         if (ret < 0)
96                                 return ret;
97                 }
98         }
99         node->flags |= EC_NODE_F_BUILT;
100
101         if (node->type->complete == NULL)
102                 return -ENOTSUP;
103
104         /* save previous parse state, prepare child state */
105         cur_state = completed->cur_state;
106         child_state = ec_parsed();
107         if (child_state == NULL)
108                 return -ENOMEM;
109
110         if (cur_state != NULL)
111                 ec_parsed_add_child(cur_state, child_state);
112         ec_parsed_set_node(child_state, node);
113         completed->cur_state = child_state;
114         cur_group = completed->cur_group;
115         completed->cur_group = NULL;
116
117         /* complete */
118         ret = node->type->complete(node, completed, strvec);
119
120         /* restore parent parse state */
121         if (cur_state != NULL) {
122                 ec_parsed_del_child(cur_state, child_state);
123                 assert(!ec_parsed_has_child(child_state));
124         }
125         ec_parsed_free(child_state);
126         completed->cur_state = cur_state;
127         completed->cur_group = cur_group;
128
129         if (ret < 0)
130                 return ret;
131
132 #if 0 // XXX dump
133         printf("----------------------------------------------------------\n");
134         ec_node_dump(stdout, node);
135         ec_strvec_dump(stdout, strvec);
136         ec_completed_dump(stdout, completed);
137 #endif
138
139         return 0;
140 }
141
142 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
143         const struct ec_strvec *strvec)
144 {
145         struct ec_completed *completed = NULL;
146         int ret;
147
148         completed = ec_completed();
149         if (completed == NULL)
150                 goto fail;
151
152         ret = ec_node_complete_child(node, completed, strvec);
153         if (ret < 0)
154                 goto fail;
155
156         return completed;
157
158 fail:
159         ec_completed_free(completed);
160         return NULL;
161 }
162
163 struct ec_completed *ec_node_complete(struct ec_node *node,
164         const char *str)
165 {
166         struct ec_strvec *strvec = NULL;
167         struct ec_completed *completed;
168
169         errno = ENOMEM;
170         strvec = ec_strvec();
171         if (strvec == NULL)
172                 goto fail;
173
174         if (ec_strvec_add(strvec, str) < 0)
175                 goto fail;
176
177         completed = ec_node_complete_strvec(node, strvec);
178         if (completed == NULL)
179                 goto fail;
180
181         ec_strvec_free(strvec);
182         return completed;
183
184  fail:
185         ec_strvec_free(strvec);
186         return NULL;
187 }
188
189 static struct ec_completed_group *
190 ec_completed_group(const struct ec_node *node, struct ec_parsed *parsed)
191 {
192         struct ec_completed_group *grp = NULL;
193
194         grp = ec_calloc(1, sizeof(*grp));
195         if (grp == NULL)
196                 return NULL;
197
198         grp->state = ec_parsed_dup(parsed);
199         if (grp->state == NULL)
200                 goto fail;
201
202         grp->node = node;
203         TAILQ_INIT(&grp->items);
204
205         return grp;
206
207 fail:
208         if (grp != NULL)
209                 ec_parsed_free(grp->state);
210         ec_free(grp);
211         return NULL;
212 }
213
214 struct ec_completed_item *
215 ec_completed_item(const struct ec_node *node)
216 {
217         struct ec_completed_item *item = NULL;
218
219         item = ec_calloc(1, sizeof(*item));
220         if (item == NULL)
221                 goto fail;
222
223         item->attrs = ec_keyval();
224         if (item->attrs == NULL)
225                 goto fail;
226
227         item->type = EC_COMP_UNKNOWN;
228         item->node = node;
229
230         return item;
231
232 fail:
233         if (item != NULL) {
234                 ec_free(item->str);
235                 ec_free(item->display);
236                 ec_keyval_free(item->attrs);
237         }
238         ec_free(item);
239
240         return NULL;
241 }
242
243 int
244 ec_completed_item_set(struct ec_completed_item *item,
245                 enum ec_completed_type type, const char *str)
246 {
247         char *str_copy = NULL;
248         char *display_copy = NULL;
249         int ret = 0;
250
251         if (item == NULL)
252                 return -EINVAL;
253         if (item->str != NULL)
254                 return -EEXIST;
255
256         switch (type) {
257         case EC_COMP_UNKNOWN:
258                 if (str != NULL)
259                         return -EINVAL;
260                 break;
261         case EC_COMP_FULL:
262         case EC_PARTIAL_MATCH:
263                 if (str == NULL)
264                         return -EINVAL;
265                 break;
266         default:
267                 return -EINVAL;
268         }
269
270         if (str != NULL) {
271                 ret = -ENOMEM;
272                 str_copy = ec_strdup(str);
273                 if (str_copy == NULL)
274                         goto fail;
275                 display_copy = ec_strdup(str);
276                 if (display_copy == NULL)
277                         goto fail;
278         }
279
280         item->type = type;
281         item->str = str_copy;
282         item->display = display_copy;
283         return 0;
284
285 fail:
286         ec_free(str_copy);
287         ec_free(display_copy);
288         return ret;
289 }
290
291 int ec_completed_item_set_display(struct ec_completed_item *item,
292                                 const char *display)
293 {
294         char *display_copy = NULL;
295         int ret = 0;
296
297         if (item == NULL || display == NULL ||
298                         item->type == EC_COMP_UNKNOWN || item->str == NULL)
299                 return -EINVAL;
300
301         ret = -ENOMEM;
302         display_copy = ec_strdup(display);
303         if (display_copy == NULL)
304                 goto fail;
305
306         ec_free(item->display);
307         item->display = display_copy;
308
309         return 0;
310
311 fail:
312         ec_free(display_copy);
313         return ret;
314 }
315
316 // XXX refactor ec_completed_item(), ec_completed_item_add(), ec_completed_item_set* 
317 int
318 ec_completed_item_add(struct ec_completed *completed,
319                 struct ec_completed_item *item)
320 {
321         if (completed == NULL || item == NULL || item->node == NULL)
322                 return -EINVAL;
323
324         switch (item->type) {
325         case EC_COMP_UNKNOWN:
326                 break;
327         case EC_COMP_FULL:
328         case EC_PARTIAL_MATCH:
329                 completed->count_match++; //XXX
330                 break;
331         default:
332                 return -EINVAL;
333         }
334
335         if (completed->cur_group == NULL) {
336                 struct ec_completed_group *grp;
337
338                 grp = ec_completed_group(item->node, completed->cur_state);
339                 if (grp == NULL)
340                         return -ENOMEM;
341                 TAILQ_INSERT_TAIL(&completed->groups, grp, next);
342                 completed->cur_group = grp;
343         }
344
345         completed->count++;
346         TAILQ_INSERT_TAIL(&completed->cur_group->items, item, next);
347         item->grp = completed->cur_group;
348
349         return 0;
350 }
351
352 const char *
353 ec_completed_item_get_str(const struct ec_completed_item *item)
354 {
355         return item->str;
356 }
357
358 const char *
359 ec_completed_item_get_display(const struct ec_completed_item *item)
360 {
361         return item->display;
362 }
363
364 enum ec_completed_type
365 ec_completed_item_get_type(const struct ec_completed_item *item)
366 {
367         return item->type;
368 }
369
370 const struct ec_node *
371 ec_completed_item_get_node(const struct ec_completed_item *item)
372 {
373         return item->node;
374 }
375
376 const struct ec_completed_group *
377 ec_completed_item_get_grp(const struct ec_completed_item *item)
378 {
379         return item->grp;
380 }
381
382 void ec_completed_item_free(struct ec_completed_item *item)
383 {
384         if (item == NULL)
385                 return;
386
387         ec_free(item->str);
388         ec_free(item->display);
389         ec_keyval_free(item->attrs);
390         ec_free(item);
391 }
392
393 /* default completion function: return a no-match element */
394 int
395 ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch
396                         struct ec_completed *completed,
397                         const struct ec_strvec *strvec)
398 {
399         struct ec_completed_item *item = NULL;
400         int ret;
401
402         if (ec_strvec_len(strvec) != 1)
403                 return 0;
404
405         item = ec_completed_item(gen_node);
406         if (item == NULL)
407                 return -ENOMEM;
408         ret = ec_completed_item_set(item, EC_COMP_UNKNOWN, NULL);
409         if (ret < 0) {
410                 ec_completed_item_free(item);
411                 return ret;
412         }
413         ret = ec_completed_item_add(completed, item);
414         if (ret < 0) {
415                 ec_completed_item_free(item);
416                 return ret;
417         }
418
419         return 0;
420 }
421
422 static void ec_completed_group_free(struct ec_completed_group *grp)
423 {
424         struct ec_completed_item *item;
425
426         if (grp == NULL)
427                 return;
428
429         while (!TAILQ_EMPTY(&grp->items)) {
430                 item = TAILQ_FIRST(&grp->items);
431                 TAILQ_REMOVE(&grp->items, item, next);
432                 ec_completed_item_free(item);
433         }
434         ec_parsed_free(ec_parsed_get_root(grp->state));
435         ec_free(grp);
436 }
437
438 void ec_completed_free(struct ec_completed *completed)
439 {
440         struct ec_completed_group *grp;
441
442         if (completed == NULL)
443                 return;
444
445         while (!TAILQ_EMPTY(&completed->groups)) {
446                 grp = TAILQ_FIRST(&completed->groups);
447                 TAILQ_REMOVE(&completed->groups, grp, next);
448                 ec_completed_group_free(grp);
449         }
450         ec_keyval_free(completed->attrs);
451         ec_free(completed);
452 }
453
454 void ec_completed_dump(FILE *out, const struct ec_completed *completed)
455 {
456         struct ec_completed_group *grp;
457         struct ec_completed_item *item;
458
459         if (completed == NULL || completed->count == 0) {
460                 fprintf(out, "no completion\n");
461                 return;
462         }
463
464         fprintf(out, "completion: count=%u match=%u\n",
465                 completed->count, completed->count_match);
466
467         TAILQ_FOREACH(grp, &completed->groups, next) {
468                 fprintf(out, "node=%p, node_type=%s\n",
469                         grp->node, grp->node->type->name);
470                 TAILQ_FOREACH(item, &grp->items, next) {
471                         const char *typestr;
472
473                         switch (item->type) {
474                         case EC_COMP_UNKNOWN: typestr = "no-match"; break;
475                         case EC_COMP_FULL: typestr = "match"; break;
476                         case EC_PARTIAL_MATCH: typestr = "partial-match"; break;
477                         default: typestr = "unknown"; break;
478                         }
479
480                         fprintf(out, "  type=%s str=<%s> disp=<%s>\n",
481                                 typestr, item->str, item->display);
482                 }
483         }
484 }
485
486 unsigned int ec_completed_count(
487         const struct ec_completed *completed,
488         enum ec_completed_type type)
489 {
490         unsigned int count = 0;
491
492         if (completed == NULL)
493                 return count;
494
495         if (type & EC_COMP_FULL)
496                 count += completed->count_match;
497         if (type & EC_COMP_UNKNOWN)
498                 count += (completed->count - completed->count_match); //XXX
499
500         return count;
501 }
502
503 struct ec_completed_iter *
504 ec_completed_iter(struct ec_completed *completed,
505         enum ec_completed_type type)
506 {
507         struct ec_completed_iter *iter;
508
509         iter = ec_calloc(1, sizeof(*iter));
510         if (iter == NULL)
511                 return NULL;
512
513         iter->completed = completed;
514         iter->type = type;
515         iter->cur_node = NULL;
516         iter->cur_match = NULL;
517
518         return iter;
519 }
520
521 const struct ec_completed_item *ec_completed_iter_next(
522         struct ec_completed_iter *iter)
523 {
524         const struct ec_completed *completed = iter->completed;
525         const struct ec_completed_group *cur_node;
526         const struct ec_completed_item *cur_match;
527
528         if (completed == NULL)
529                 return NULL;
530
531         cur_node = iter->cur_node;
532         cur_match = iter->cur_match;
533
534         /* first call */
535         if (cur_node == NULL) {
536                 TAILQ_FOREACH(cur_node, &completed->groups, next) {
537                         TAILQ_FOREACH(cur_match, &cur_node->items, next) {
538                                 if (cur_match != NULL &&
539                                                 cur_match->type & iter->type)
540                                         goto found;
541                         }
542                 }
543                 return NULL;
544         } else {
545                 cur_match = TAILQ_NEXT(cur_match, next);
546                 if (cur_match != NULL &&
547                                 cur_match->type & iter->type)
548                         goto found;
549                 cur_node = TAILQ_NEXT(cur_node, next);
550                 while (cur_node != NULL) {
551                         cur_match = TAILQ_FIRST(&cur_node->items);
552                         if (cur_match != NULL &&
553                                         cur_match->type & iter->type)
554                                 goto found;
555                         cur_node = TAILQ_NEXT(cur_node, next);
556                 }
557                 return NULL;
558         }
559
560 found:
561         iter->cur_node = cur_node;
562         iter->cur_match = cur_match;
563
564         return iter->cur_match;
565 }
566
567 void ec_completed_iter_free(struct ec_completed_iter *iter)
568 {
569         ec_free(iter);
570 }