2 * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
33 #include <ecoli_malloc.h>
36 struct ec_tk *ec_tk_new(const char *id, const struct ec_tk_ops *ops,
39 struct ec_tk *tk = NULL;
41 assert(size >= sizeof(*tk));
43 tk = ec_calloc(1, size);
48 tk->id = ec_strdup(id);
62 void ec_tk_free(struct ec_tk *tk)
67 if (tk->ops != NULL && tk->ops->free_priv != NULL)
68 tk->ops->free_priv(tk);
73 struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *tk, const char *str)
75 struct ec_parsed_tk *parsed_tk;
77 /* by default, it does not match anything */
78 if (tk->ops->parse == NULL)
81 parsed_tk = tk->ops->parse(tk, str);
87 struct ec_parsed_tk *ec_parsed_tk_new(const struct ec_tk *tk)
89 struct ec_parsed_tk *parsed_tk;
91 parsed_tk = ec_calloc(1, sizeof(*parsed_tk));
92 if (parsed_tk == NULL)
96 TAILQ_INIT(&parsed_tk->children);
104 void ec_parsed_tk_free(struct ec_parsed_tk *parsed_tk)
106 struct ec_parsed_tk *child;
108 if (parsed_tk == NULL)
111 while (!TAILQ_EMPTY(&parsed_tk->children)) {
112 child = TAILQ_FIRST(&parsed_tk->children);
113 TAILQ_REMOVE(&parsed_tk->children, child, next);
114 ec_parsed_tk_free(child);
116 ec_free(parsed_tk->str);
120 static void __ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk,
123 struct ec_parsed_tk *child;
128 for (i = 0; i < indent; i++)
130 s = ec_parsed_tk_to_string(parsed_tk);
131 fprintf(out, "id=%s, s=<%s>\n", parsed_tk->tk->id, s);
133 TAILQ_FOREACH(child, &parsed_tk->children, next)
134 __ec_parsed_tk_dump(out, child, indent + 2);
137 void ec_parsed_tk_dump(FILE *out, const struct ec_parsed_tk *parsed_tk)
139 if (parsed_tk == NULL) {
140 fprintf(out, "no match\n");
144 __ec_parsed_tk_dump(out, parsed_tk, 0);
147 void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk,
148 struct ec_parsed_tk *child)
150 TAILQ_INSERT_TAIL(&parsed_tk->children, child, next);
153 struct ec_parsed_tk *ec_parsed_tk_find_first(struct ec_parsed_tk *parsed_tk,
156 struct ec_parsed_tk *child, *ret;
158 if (parsed_tk == NULL)
161 if (parsed_tk->tk->id != NULL && !strcmp(parsed_tk->tk->id, id))
164 TAILQ_FOREACH(child, &parsed_tk->children, next) {
165 ret = ec_parsed_tk_find_first(child, id);
173 const char *ec_parsed_tk_to_string(const struct ec_parsed_tk *parsed_tk)
175 if (parsed_tk == NULL)
178 return parsed_tk->str;
181 struct ec_completed_tk *ec_completed_tk_new(void)
183 struct ec_completed_tk *completed_tk = NULL;
185 completed_tk = ec_calloc(1, sizeof(*completed_tk));
186 if (completed_tk == NULL)
189 TAILQ_INIT(&completed_tk->elts);
190 completed_tk->count = 0;
195 struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk,
196 const char *add, const char *full)
198 struct ec_completed_tk_elt *elt = NULL;
200 elt = ec_calloc(1, sizeof(*elt));
206 elt->add = ec_strdup(add);
207 if (elt->add == NULL) {
208 ec_completed_tk_elt_free(elt);
213 elt->full = ec_strdup(full);
214 if (elt->full == NULL) {
215 ec_completed_tk_elt_free(elt);
223 /* XXX define when to use ec_tk_complete() or tk->complete()
225 * suggestion: tk->op() is internal, user calls the function
226 * other idea: have 2 functions
228 struct ec_completed_tk *ec_tk_complete(const struct ec_tk *tk,
231 struct ec_completed_tk *completed_tk;
233 if (tk->ops->complete == NULL)
234 return ec_completed_tk_new();
236 completed_tk = tk->ops->complete(tk, str);
241 /* count the number of identical chars at the beginning of 2 strings */
242 static size_t strcmp_count(const char *s1, const char *s2)
246 while (s1[i] && s2[i] && s1[i] == s2[i])
252 void ec_completed_tk_add_elt(
253 struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt)
257 TAILQ_INSERT_TAIL(&completed_tk->elts, elt, next);
258 completed_tk->count++;
259 if (elt->add != NULL) {
260 if (completed_tk->smallest_start == NULL) {
261 completed_tk->smallest_start = ec_strdup(elt->add);
263 n = strcmp_count(elt->add,
264 completed_tk->smallest_start);
265 completed_tk->smallest_start[n] = '\0';
270 void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt)
277 void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1,
278 struct ec_completed_tk *completed_tk2)
280 struct ec_completed_tk_elt *elt;
282 assert(completed_tk1 != NULL);
283 assert(completed_tk2 != NULL);
285 while (!TAILQ_EMPTY(&completed_tk2->elts)) {
286 elt = TAILQ_FIRST(&completed_tk2->elts);
287 TAILQ_REMOVE(&completed_tk2->elts, elt, next);
288 ec_completed_tk_add_elt(completed_tk1, elt);
291 ec_completed_tk_free(completed_tk2);
294 void ec_completed_tk_free(struct ec_completed_tk *completed_tk)
296 struct ec_completed_tk_elt *elt;
298 if (completed_tk == NULL)
301 while (!TAILQ_EMPTY(&completed_tk->elts)) {
302 elt = TAILQ_FIRST(&completed_tk->elts);
303 TAILQ_REMOVE(&completed_tk->elts, elt, next);
304 ec_completed_tk_elt_free(elt);
306 ec_free(completed_tk->smallest_start);
307 ec_free(completed_tk);
310 void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk)
312 struct ec_completed_tk_elt *elt;
314 if (completed_tk == NULL || completed_tk->count == 0) {
315 fprintf(out, "no completion\n");
319 fprintf(out, "completion: count=%u smallest_start=<%s>\n",
320 completed_tk->count, completed_tk->smallest_start);
322 TAILQ_FOREACH(elt, &completed_tk->elts, next) {
323 fprintf(out, "add=<%s>, full=<%s>, tk=%p\n",
324 elt->add, elt->full, elt->tk);
328 const char *ec_completed_tk_smallest_start(
329 const struct ec_completed_tk *completed_tk)
331 if (completed_tk == NULL || completed_tk->smallest_start == NULL)
334 return completed_tk->smallest_start;
337 unsigned int ec_completed_tk_count(const struct ec_completed_tk *completed_tk)
339 if (completed_tk == NULL)
342 return completed_tk->count;
345 void ec_completed_tk_iter_start(struct ec_completed_tk *completed_tk)
347 if (completed_tk == NULL)
350 completed_tk->cur = NULL;
353 const struct ec_completed_tk_elt *ec_completed_tk_iter_next(
354 struct ec_completed_tk *completed_tk)
356 if (completed_tk == NULL)
359 if (completed_tk->cur == NULL) {
360 completed_tk->cur = TAILQ_FIRST(&completed_tk->elts);
362 completed_tk->cur = TAILQ_NEXT(completed_tk->cur, next);
365 return completed_tk->cur;