init
[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
33 #include <ecoli_tk.h>
34
35 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops,
36         size_t size)
37 {
38         struct ec_tk *tk = NULL;
39
40         assert(size >= sizeof(*tk));
41
42         tk = calloc(1, size);
43         if (tk == NULL)
44                 goto fail;
45
46         if (id != NULL) {
47                 tk->id = strdup(id);
48                 if (tk->id == NULL)
49                         goto fail;
50         }
51
52         tk->ops = ops;
53
54         return tk;
55
56  fail:
57         ec_tk_free(tk);
58         return NULL;
59 }
60
61 void ec_tk_free(struct ec_tk *tk)
62 {
63         if (tk == NULL)
64                 return;
65
66         if (tk->ops != NULL && tk->ops->free_priv != NULL)
67                 tk->ops->free_priv(tk);
68         free(tk->id);
69         free(tk);
70 }
71
72 struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *token, const char *str,
73         size_t off)
74 {
75         struct ec_parsed_tk *parsed_tk;
76
77         parsed_tk = token->ops->parse(token, str, off);
78
79         return parsed_tk;
80 }
81
82
83 struct ec_parsed_tk *ec_parsed_tk_new(const struct ec_tk *tk)
84 {
85         struct ec_parsed_tk *parsed_tk;
86
87         parsed_tk = calloc(1, sizeof(*parsed_tk));
88         if (parsed_tk == NULL)
89                 goto fail;
90
91         parsed_tk->tk = tk;
92         TAILQ_INIT(&parsed_tk->children);
93
94         return parsed_tk;
95
96  fail:
97         return NULL;
98 }
99
100 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
101 {
102         struct ec_parsed_tk *child;
103
104         if (parsed_tk == NULL)
105                 return;
106
107         while (!TAILQ_EMPTY(&parsed_tk->children)) {
108                 child = TAILQ_FIRST(&parsed_tk->children);
109                 TAILQ_REMOVE(&parsed_tk->children, child, next);
110                 ec_parsed_tk_free(child);
111         }
112         free(parsed_tk->str);
113         free(parsed_tk);
114 }
115
116 static void __ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk,
117         size_t indent)
118 {
119         struct ec_parsed_tk *child;
120         size_t i;
121         const char *s;
122
123         /* XXX enhance */
124         for (i = 0; i < indent; i++)
125                 printf(" ");
126         s = ec_parsed_tk_to_string(parsed_tk);
127         printf("id=%s, s=<%s>\n", parsed_tk->tk->id, s);
128
129         TAILQ_FOREACH(child, &parsed_tk->children, next)
130                 __ec_parsed_tk_dump(child, indent + 2);
131 }
132
133 void ec_parsed_tk_dump(const struct ec_parsed_tk *parsed_tk)
134 {
135         if (parsed_tk == NULL) {
136                 printf("no match\n");
137                 return;
138         }
139
140         __ec_parsed_tk_dump(parsed_tk, 0);
141 }
142
143 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
144         struct ec_parsed_tk *child)
145 {
146         TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
147 }
148
149 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
150         const char *id)
151 {
152         struct ec_parsed_tk *child, *ret;
153
154         if (parsed_tk == NULL)
155                 return NULL;
156
157         if (parsed_tk->tk->id != NULL && !strcmp(parsed_tk->tk->id, id))
158                 return parsed_tk;
159
160         TAILQ_FOREACH(child, &parsed_tk->children, next) {
161                 ret = ec_parsed_tk_find_first(child, id);
162                 if (ret != NULL)
163                         return ret;
164         }
165
166         return NULL;
167 }
168
169 const char *ec_parsed_tk_to_string(const struct ec_parsed_tk *parsed_tk)
170 {
171         if (parsed_tk == NULL)
172                 return NULL;
173
174         return parsed_tk->str;
175 }
176
177 struct ec_completed_tk *ec_tk_complete(const struct ec_tk *token,
178         const char *str, size_t off)
179 {
180         struct ec_completed_tk *completed_tk;
181
182         completed_tk = token->ops->complete(token, str, off);
183
184         return completed_tk;
185 }
186
187 struct ec_completed_tk *ec_completed_tk_new(void)
188 {
189         struct ec_completed_tk *completed_tk = NULL;
190
191         completed_tk = calloc(1, sizeof(*completed_tk));
192         if (completed_tk == NULL)
193                 return NULL;
194
195         TAILQ_INIT(&completed_tk->elts);
196         completed_tk->count = 0;
197
198         return completed_tk;
199 }
200
201 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
202         const char *add, const char *full)
203 {
204         struct ec_completed_tk_elt *elt = NULL;
205
206         elt = calloc(1, sizeof(*elt));
207         if (elt == NULL)
208                 return NULL;
209
210         elt->tk = tk;
211         elt->add = strdup(add);
212         elt->full = strdup(full);
213         if (elt->add == NULL || elt->full == NULL) {
214                 ec_completed_tk_elt_free(elt);
215                 return NULL;
216         }
217
218         return elt;
219 }
220
221 /* count the number of identical chars at the beginning of 2 strings */
222 static size_t strcmp_count(const char *s1, const char *s2)
223 {
224         size_t i = 0;
225
226         while (s1[i] && s2[i] && s1[i] == s2[i])
227                 i++;
228
229         return i;
230 }
231
232 void ec_completed_tk_add_elt(
233         struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
234 {
235         size_t n;
236
237         TAILQ_INSERT_TAIL(&completed_tk->elts, elt, next);
238         completed_tk->count++;
239         if (elt->add != NULL) {
240                 if (completed_tk->smallest_start == NULL) {
241                         completed_tk->smallest_start = strdup(elt->add);
242                 } else {
243                         n = strcmp_count(elt->add,
244                                 completed_tk->smallest_start);
245                         completed_tk->smallest_start[n] = '\0';
246                 }
247         }
248 }
249
250 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
251 {
252         free(elt->add);
253         free(elt->full);
254         free(elt);
255 }
256
257 struct ec_completed_tk *ec_completed_tk_merge(
258         struct ec_completed_tk *completed_tk1,
259         struct ec_completed_tk *completed_tk2)
260 {
261         struct ec_completed_tk_elt *elt;
262
263         if (completed_tk2 == NULL)
264                 return completed_tk1;
265
266         if (completed_tk1 == NULL)
267                 return completed_tk2;
268
269         while (!TAILQ_EMPTY(&completed_tk2->elts)) {
270                 elt = TAILQ_FIRST(&completed_tk2->elts);
271                 TAILQ_REMOVE(&completed_tk2->elts, elt, next);
272                 ec_completed_tk_add_elt(completed_tk1, elt);
273         }
274
275         ec_completed_tk_free(completed_tk2);
276
277         return completed_tk1;
278 }
279
280 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
281 {
282         struct ec_completed_tk_elt *elt;
283
284         if (completed_tk == NULL)
285                 return;
286
287         while (!TAILQ_EMPTY(&completed_tk->elts)) {
288                 elt = TAILQ_FIRST(&completed_tk->elts);
289                 TAILQ_REMOVE(&completed_tk->elts, elt, next);
290                 ec_completed_tk_elt_free(elt);
291         }
292         free(completed_tk->smallest_start);
293         free(completed_tk);
294 }
295
296 void ec_completed_tk_dump(const struct ec_completed_tk *completed_tk)
297 {
298         struct ec_completed_tk_elt *elt;
299
300         if (completed_tk == NULL || completed_tk->count == 0) {
301                 printf("no completion\n");
302                 return;
303         }
304
305         printf("completion: count=%u smallest_start=<%s>\n",
306                 completed_tk->count, completed_tk->smallest_start);
307
308         TAILQ_FOREACH(elt, &completed_tk->elts, next)
309                 printf("add=<%s> full=<%s>\n", elt->add, elt->full);
310 }
311
312 const char *ec_completed_tk_smallest_start(
313         const struct ec_completed_tk *completed_tk)
314 {
315         if (completed_tk == NULL)
316                 return NULL;
317
318         return completed_tk->smallest_start;
319 }
320
321 unsigned int ec_completed_tk_count(const struct ec_completed_tk *completed_tk)
322 {
323         struct ec_completed_tk_elt *elt;
324         unsigned int count = 0;
325
326         if (completed_tk == NULL)
327                 return 0;
328
329         TAILQ_FOREACH(elt, &completed_tk->elts, next)
330                 count++;
331
332         return count;
333 }