From ae2c4709444ee6fbbf388b853ab4039fcdde2e95 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 3 Nov 2016 20:29:26 +0100 Subject: [PATCH] option, shlex --- lib/Makefile | 6 +- lib/build/test | Bin 84864 -> 106472 bytes lib/ecoli_test.c | 22 +- lib/ecoli_tk.c | 40 +++- lib/ecoli_tk.h | 10 +- lib/ecoli_tk_empty.c | 5 +- lib/ecoli_tk_int.c | 6 +- lib/ecoli_tk_option.c | 137 +++++++++++++ lib/ecoli_tk_option.h | 40 ++++ lib/ecoli_tk_or.c | 12 +- lib/ecoli_tk_seq.c | 34 ++-- lib/ecoli_tk_shlex.c | 452 ++++++++++++++++++++++++++++++++++++++++++ lib/ecoli_tk_shlex.h | 48 +++++ lib/ecoli_tk_space.c | 39 ++++ lib/ecoli_tk_str.c | 17 +- lib/main-readline.c | 133 +++++++++++++ 16 files changed, 941 insertions(+), 60 deletions(-) create mode 100644 lib/ecoli_tk_option.c create mode 100644 lib/ecoli_tk_option.h create mode 100644 lib/ecoli_tk_shlex.c create mode 100644 lib/ecoli_tk_shlex.h create mode 100644 lib/main-readline.c diff --git a/lib/Makefile b/lib/Makefile index 08a1b40..42a969e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -36,11 +36,15 @@ CFLAGS += -I. srcs := ecoli_tk.c ecoli_tk_str.c ecoli_tk_seq.c srcs += ecoli_tk_space.c ecoli_tk_or.c ecoli_test.c srcs += ecoli_tk_empty.c ecoli_tk_int.c -srcs += ecoli_malloc.c ecoli_log.c +srcs += ecoli_malloc.c ecoli_log.c ecoli_tk_option.c +srcs += ecoli_tk_shlex.c shlib-y-$(O)libecoli.so := $(srcs) exe-y-$(O)test = $(srcs) main.c +ldflags-$(O)readline = -lreadline +exe-y-$(O)readline = $(srcs) main-readline.c + include $(ECOLI)/mk/ecoli-post.mk all: _ecoli_all diff --git a/lib/build/test b/lib/build/test index 8ef7e3e67779de88bc45f316ca2fbe7014effaa5..6484b701ea0da19ca4b39b87c1ef215f5455280e 100755 GIT binary patch literal 106472 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 literal 84864 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 UFKVCC;y1r%!_PVO-;Mu&0R>{jRR910 diff --git a/lib/ecoli_test.c b/lib/ecoli_test.c index f6521da..c859d07 100644 --- a/lib/ecoli_test.c +++ b/lib/ecoli_test.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -75,20 +76,16 @@ int ec_test_check_tk_complete(const struct ec_tk *tk, const char *input, const char *s; int ret = -1; + assert(expected != NULL); + c = ec_tk_complete(tk, input); s = ec_completed_tk_smallest_start(c); - if (s == NULL && expected == NULL) - ret = 0; - else if (s != NULL && expected != NULL && - !strcmp(s, expected)) + if (!strcmp(s, expected)) ret = 0; - if (expected == NULL && ret != 0) - ec_log(EC_LOG_ERR, - "tk should not complete but completes with <%s>\n", s); - if (expected != NULL && ret != 0) + if (ret != 0) ec_log(EC_LOG_ERR, - "tk should complete with <%s> but completes with <%s>\n", + "should complete with <%s> but completes with <%s>\n", expected, s); ec_completed_tk_free(c); @@ -135,6 +132,7 @@ int ec_test_check_tk_complete_list(const struct ec_tk *tk, ec_log(EC_LOG_ERR, "nb_completion (%d) does not match (%d)\n", count, ec_completed_tk_count(c)); + ec_completed_tk_dump(stdout, c); goto out; } @@ -310,10 +308,6 @@ void debug_alloc_dump(void) } } -/* XXX todo */ -/* int ec_test_check_tk_complete_list(const struct ec_tk *tk, */ -/* const char *input, ...) */ - int ec_test_all(void) { struct ec_test *test; @@ -322,7 +316,7 @@ int ec_test_all(void) TAILQ_INIT(&debug_alloc_hdr_list); /* register a new malloc to trac memleaks */ - if (0 && ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) { + if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) { ec_log(EC_LOG_ERR, "cannot register new malloc\n"); return -1; } diff --git a/lib/ecoli_tk.c b/lib/ecoli_tk.c index cdb064e..8f22fbd 100644 --- a/lib/ecoli_tk.c +++ b/lib/ecoli_tk.c @@ -223,6 +223,7 @@ struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk, /* XXX define when to use ec_tk_complete() or tk->complete() * (same for parse) * suggestion: tk->op() is internal, user calls the function + * other idea: have 2 functions */ struct ec_completed_tk *ec_tk_complete(const struct ec_tk *tk, const char *str) @@ -273,17 +274,13 @@ void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt) ec_free(elt); } -struct ec_completed_tk *ec_completed_tk_merge( - struct ec_completed_tk *completed_tk1, +void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1, struct ec_completed_tk *completed_tk2) { struct ec_completed_tk_elt *elt; - if (completed_tk2 == NULL) - return completed_tk1; - - if (completed_tk1 == NULL) - return completed_tk2; + assert(completed_tk1 != NULL); + assert(completed_tk2 != NULL); while (!TAILQ_EMPTY(&completed_tk2->elts)) { elt = TAILQ_FIRST(&completed_tk2->elts); @@ -292,8 +289,6 @@ struct ec_completed_tk *ec_completed_tk_merge( } ec_completed_tk_free(completed_tk2); - - return completed_tk1; } void ec_completed_tk_free(struct ec_completed_tk *completed_tk) @@ -333,8 +328,8 @@ void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk) const char *ec_completed_tk_smallest_start( const struct ec_completed_tk *completed_tk) { - if (completed_tk == NULL) - return NULL; + if (completed_tk == NULL || completed_tk->smallest_start == NULL) + return ""; return completed_tk->smallest_start; } @@ -346,3 +341,26 @@ unsigned int ec_completed_tk_count(const struct ec_completed_tk *completed_tk) return completed_tk->count; } + +void ec_completed_tk_iter_start(struct ec_completed_tk *completed_tk) +{ + if (completed_tk == NULL) + return; + + completed_tk->cur = NULL; +} + +const struct ec_completed_tk_elt *ec_completed_tk_iter_next( + struct ec_completed_tk *completed_tk) +{ + if (completed_tk == NULL) + return NULL; + + if (completed_tk->cur == NULL) { + completed_tk->cur = TAILQ_FIRST(&completed_tk->elts); + } else { + completed_tk->cur = TAILQ_NEXT(completed_tk->cur, next); + } + + return completed_tk->cur; +} diff --git a/lib/ecoli_tk.h b/lib/ecoli_tk.h index cc0a208..72aee30 100644 --- a/lib/ecoli_tk.h +++ b/lib/ecoli_tk.h @@ -97,6 +97,7 @@ TAILQ_HEAD(ec_completed_tk_elt_list, ec_completed_tk_elt); struct ec_completed_tk { struct ec_completed_tk_elt_list elts; + const struct ec_completed_tk_elt *cur; unsigned count; char *smallest_start; }; @@ -113,17 +114,20 @@ struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk, void ec_completed_tk_add_elt(struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt); void ec_completed_tk_elt_free(struct ec_completed_tk_elt *elt); -struct ec_completed_tk *ec_completed_tk_merge( - struct ec_completed_tk *completed_tk1, +void ec_completed_tk_merge(struct ec_completed_tk *completed_tk1, struct ec_completed_tk *completed_tk2); void ec_completed_tk_free(struct ec_completed_tk *completed_tk); void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk); -/* can return NULL */ +/* cannot return NULL */ const char *ec_completed_tk_smallest_start( const struct ec_completed_tk *completed_tk); unsigned int ec_completed_tk_count(const struct ec_completed_tk *completed_tk); +void ec_completed_tk_iter_start(struct ec_completed_tk *completed_tk); +const struct ec_completed_tk_elt *ec_completed_tk_iter_next( + struct ec_completed_tk *completed_tk); + #endif diff --git a/lib/ecoli_tk_empty.c b/lib/ecoli_tk_empty.c index e3e24f9..bc180d7 100644 --- a/lib/ecoli_tk_empty.c +++ b/lib/ecoli_tk_empty.c @@ -64,7 +64,6 @@ static int ec_tk_empty_testcase(void) struct ec_tk *tk; int ret = 0; - /* all inputs match */ tk = ec_tk_empty_new(NULL); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); @@ -81,8 +80,8 @@ static int ec_tk_empty_testcase(void) ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", NULL); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", NULL); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", ""); ec_tk_free(tk); return ret; diff --git a/lib/ecoli_tk_int.c b/lib/ecoli_tk_int.c index 8aeb6bc..a6cc12d 100644 --- a/lib/ecoli_tk_int.c +++ b/lib/ecoli_tk_int.c @@ -198,9 +198,9 @@ static int ec_tk_int_testcase(void) ec_log(EC_LOG_ERR, "cannot create tk\n"); return -1; } - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", NULL); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "1", NULL); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "1", ""); ec_tk_free(tk); return ret; diff --git a/lib/ecoli_tk_option.c b/lib/ecoli_tk_option.c new file mode 100644 index 0000000..2b4e4cb --- /dev/null +++ b/lib/ecoli_tk_option.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static struct ec_parsed_tk *ec_tk_option_parse(const struct ec_tk *gen_tk, + const char *str) +{ + struct ec_tk_option *tk = (struct ec_tk_option *)gen_tk; + struct ec_parsed_tk *parsed_tk, *child_parsed_tk; + + parsed_tk = ec_parsed_tk_new(gen_tk); + if (parsed_tk == NULL) + return NULL; + + child_parsed_tk = ec_tk_parse(tk->child, str); + if (child_parsed_tk != NULL) { + ec_parsed_tk_add_child(parsed_tk, child_parsed_tk); + parsed_tk->str = ec_strndup(child_parsed_tk->str, + strlen(child_parsed_tk->str)); + } else { + parsed_tk->str = ec_strdup(""); + } + + return parsed_tk; +} + +static struct ec_completed_tk *ec_tk_option_complete(const struct ec_tk *gen_tk, + const char *str) +{ + struct ec_tk_option *tk = (struct ec_tk_option *)gen_tk; + + return ec_tk_complete(tk->child, str); +} + +static void ec_tk_option_free_priv(struct ec_tk *gen_tk) +{ + struct ec_tk_option *tk = (struct ec_tk_option *)gen_tk; + + ec_tk_free(tk->child); +} + +static struct ec_tk_ops ec_tk_option_ops = { + .parse = ec_tk_option_parse, + .complete = ec_tk_option_complete, + .free_priv = ec_tk_option_free_priv, +}; + +struct ec_tk *ec_tk_option_new(const char *id, struct ec_tk *child) +{ + struct ec_tk_option *tk = NULL; + + if (child == NULL) + return NULL; + + tk = (struct ec_tk_option *)ec_tk_new(id, &ec_tk_option_ops, + sizeof(*tk)); + if (tk == NULL) + return NULL; + + tk->child = child; + + return &tk->gen; +} + +static int ec_tk_option_testcase(void) +{ + struct ec_tk *tk; + int ret = 0; + + tk = ec_tk_option_new(NULL, ec_tk_str_new(NULL, "foo")); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_PARSE(tk, "", ""); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo"); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "bar", ""); + ec_tk_free(tk); + + /* test completion */ + tk = ec_tk_option_new(NULL, ec_tk_str_new(NULL, "foo")); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "b", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "", + "foo", EC_TK_ENDLIST); + ec_tk_free(tk); + + return ret; +} + +static struct ec_test ec_tk_option_test = { + .name = "tk_option", + .test = ec_tk_option_testcase, +}; + +EC_REGISTER_TEST(ec_tk_option_test); diff --git a/lib/ecoli_tk_option.h b/lib/ecoli_tk_option.h new file mode 100644 index 0000000..cadcc05 --- /dev/null +++ b/lib/ecoli_tk_option.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECOLI_TK_OPTION_ +#define ECOLI_TK_OPTION_ + +#include + +struct ec_tk_option { + struct ec_tk gen; + struct ec_tk *child; +}; + +struct ec_tk *ec_tk_option_new(const char *id, struct ec_tk *tk); + +#endif diff --git a/lib/ecoli_tk_or.c b/lib/ecoli_tk_or.c index 4c782dd..900ee23 100644 --- a/lib/ecoli_tk_or.c +++ b/lib/ecoli_tk_or.c @@ -74,17 +74,20 @@ static struct ec_completed_tk *ec_tk_or_complete(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk; - struct ec_completed_tk *completed_tk = NULL, *child_completed_tk; + struct ec_completed_tk *completed_tk, *child_completed_tk; size_t n; + completed_tk = ec_completed_tk_new(); + if (completed_tk == NULL) + return NULL; + for (n = 0; n < tk->len; n++) { child_completed_tk = ec_tk_complete(tk->table[n], str); if (child_completed_tk == NULL) continue; - completed_tk = ec_completed_tk_merge(completed_tk, - child_completed_tk); + ec_completed_tk_merge(completed_tk, child_completed_tk); } return completed_tk; @@ -174,7 +177,6 @@ static int ec_tk_or_testcase(void) struct ec_tk *tk; int ret = 0; - /* all inputs starting with foo should match */ tk = ec_tk_or_new_list(NULL, ec_tk_str_new(NULL, "foo"), ec_tk_str_new(NULL, "bar"), @@ -206,7 +208,7 @@ static int ec_tk_or_testcase(void) ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "b", "ar"); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "t", ""); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "to", "to"); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", ""); ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "", "foo", "bar", "bar2", "toto", "titi", EC_TK_ENDLIST); ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "f", diff --git a/lib/ecoli_tk_seq.c b/lib/ecoli_tk_seq.c index fb1b434..7f840c0 100644 --- a/lib/ecoli_tk_seq.c +++ b/lib/ecoli_tk_seq.c @@ -36,10 +36,9 @@ #include #include #include +#include #include -// XXX to handle the quote, it will be done in tk_shseq -// it will unquote the string and parse each token separately static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk, const char *str) { @@ -74,16 +73,26 @@ static struct ec_completed_tk *ec_tk_seq_complete(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk; - struct ec_completed_tk *completed_tk; + struct ec_completed_tk *completed_tk, *child_completed_tk; struct ec_parsed_tk *parsed_tk; size_t len = 0; unsigned int i; + completed_tk = ec_completed_tk_new(); + if (completed_tk == NULL) + return NULL; + if (tk->len == 0) - return ec_completed_tk_new(); + return completed_tk; + + for (i = 0; i < tk->len; i++) { + child_completed_tk = ec_tk_complete(tk->table[i], str + len); + if (child_completed_tk == NULL) { + ec_completed_tk_free(completed_tk); + return NULL; + } + ec_completed_tk_merge(completed_tk, child_completed_tk); - /* parse the first tokens */ - for (i = 0; i < tk->len - 1; i++) { parsed_tk = ec_tk_parse(tk->table[i], str + len); if (parsed_tk == NULL) break; @@ -92,8 +101,6 @@ static struct ec_completed_tk *ec_tk_seq_complete(const struct ec_tk *gen_tk, ec_parsed_tk_free(parsed_tk); } - completed_tk = ec_tk_complete(tk->table[i], str + len); - return completed_tk; } @@ -183,7 +190,6 @@ static int ec_tk_seq_testcase(void) struct ec_tk *tk; int ret = 0; - /* all inputs starting with foo should match */ tk = ec_tk_seq_new_list(NULL, ec_tk_str_new(NULL, "foo"), ec_tk_str_new(NULL, "bar"), @@ -202,6 +208,7 @@ static int ec_tk_seq_testcase(void) /* test completion */ tk = ec_tk_seq_new_list(NULL, ec_tk_str_new(NULL, "foo"), + ec_tk_option_new(NULL, ec_tk_str_new(NULL, "toto")), ec_tk_str_new(NULL, "bar"), EC_TK_ENDLIST); if (tk == NULL) { @@ -210,11 +217,14 @@ static int ec_tk_seq_testcase(void) } ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo"); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", "bar"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "foo", + "bar", "toto", EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foot", "oto"); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foob", "ar"); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foobar", ""); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foobarx", NULL); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foobarx", ""); ec_tk_free(tk); return ret; diff --git a/lib/ecoli_tk_shlex.c b/lib/ecoli_tk_shlex.c new file mode 100644 index 0000000..7b62c0c --- /dev/null +++ b/lib/ecoli_tk_shlex.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int isend(char c) +{ + if (c == '\0' || c == '#' || c == '\n' || c == '\r') + return 1; + return 0; +} + +/* Remove quotes and stop when we reach the end of token. Return the + * number of "eaten" bytes from the source buffer, or a negative value + * on error */ +/* XXX support simple quotes, try to be posix-compatible */ +int get_token(const char *src, char **p_dst) +{ + unsigned s = 0, d = 0, dstlen; + int quoted = 0; + char *dst; + + dstlen = strlen(src) + 1; + dst = ec_malloc(dstlen); + if (dst == NULL) + return -ENOMEM; + + /* skip spaces */ + while (isblank(src[s])) + s++; + + /* empty token */ + if (isend(src[s])) { + ec_free(dst); + return -ENOENT; + } + + /* copy token and remove quotes */ + while (src[s] != '\0') { + if (d >= dstlen) { + ec_free(dst); + return -EMSGSIZE; + } + + if ((isblank(src[s]) || isend(src[s])) && quoted == 0) + break; + + if (src[s] == '\\' && src[s+1] == '"') { + dst[d++] = '"'; + s += 2; + continue; + } + if (src[s] == '\\' && src[s+1] == '\\') { + dst[d++] = '\\'; + s += 2; + continue; + } + if (src[s] == '"') { + s++; + quoted = !quoted; + continue; + } + dst[d++] = src[s++]; + } + + /* not enough room in dst buffer */ + if (d >= dstlen) { + ec_free(dst); + return -EMSGSIZE; + } + + /* end of string during quote */ + if (quoted) { + ec_free(dst); + return -EINVAL; + } + + dst[d++] = '\0'; + *p_dst = dst; + return s; +} + +static int safe_realloc(void *arg, size_t size) +{ + void **pptr = arg; + void *new_ptr = ec_realloc(*pptr, size); + + if (new_ptr == NULL) + return -1; + *pptr = new_ptr; + return 0; +} + +static char **tokenize(const char *str, int add_empty) +{ + char **table = NULL, *token; + unsigned i, count = 1, off = 0; + int ret; + + if (safe_realloc(&table, sizeof(char *)) < 0) + return NULL; + + table[0] = NULL; + + while (1) { + ret = get_token(str + off, &token); + if (ret == -ENOENT) + break; + else if (ret < 0) + goto fail; + + off += ret; + count++; + if (safe_realloc(&table, sizeof(char *) * count) < 0) + goto fail; + table[count - 2] = token; + table[count - 1] = NULL; + } + + if (add_empty && (off != strlen(str) || strlen(str) == 0)) { + token = ec_strdup(""); + if (token == NULL) + goto fail; + + count++; + if (safe_realloc(&table, sizeof(char *) * count) < 0) + goto fail; + table[count - 2] = token; + table[count - 1] = NULL; + } + + return table; + + fail: + for (i = 0; i < count; i++) + ec_free(table[i]); + ec_free(table); + return NULL; +} + +static struct ec_parsed_tk *ec_tk_shlex_parse(const struct ec_tk *gen_tk, + const char *str) +{ + struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + struct ec_parsed_tk *parsed_tk, *child_parsed_tk; + unsigned int i; + char **tokens, **t; + + parsed_tk = ec_parsed_tk_new(gen_tk); + if (parsed_tk == NULL) + return NULL; + + tokens = tokenize(str, 0); + if (tokens == NULL) + goto fail; + + t = &tokens[0]; + for (i = 0, t = &tokens[0]; i < tk->len; i++, t++) { + if (*t == NULL) + goto fail; + + child_parsed_tk = ec_tk_parse(tk->table[i], *t); + if (child_parsed_tk == NULL) + goto fail; + + ec_parsed_tk_add_child(parsed_tk, child_parsed_tk); + if (strlen(child_parsed_tk->str) == 0) + t--; + else if (strlen(child_parsed_tk->str) != strlen(*t)) + goto fail; + } + + /* check it was the last token */ + if (*t != NULL) + goto fail; + + if (tokens != NULL) { + for (t = &tokens[0]; *t != NULL; t++) + ec_free(*t); + ec_free(tokens); + tokens = NULL; + } + + parsed_tk->str = ec_strdup(str); + + return parsed_tk; + + fail: + if (tokens != NULL) { + for (t = &tokens[0]; *t != NULL; t++) + ec_free(*t); + ec_free(tokens); + } + ec_parsed_tk_free(parsed_tk); + + return NULL; +} + +static struct ec_completed_tk *ec_tk_shlex_complete(const struct ec_tk *gen_tk, + const char *str) +{ + struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + struct ec_completed_tk *completed_tk, *child_completed_tk = NULL; + struct ec_parsed_tk *child_parsed_tk; + unsigned int i; + char **tokens, **t; + + tokens = tokenize(str, 1); + if (tokens == NULL) + goto fail; + + printf("complete <%s>\n", str); + for (t = &tokens[0]; *t != NULL; t++) + printf(" token <%s> %p\n", *t, *t); + + t = &tokens[0]; + + completed_tk = ec_completed_tk_new(); + if (completed_tk == NULL) + return NULL; + + for (i = 0, t = &tokens[0]; i < tk->len; i++, t++) { + if (*(t + 1) != NULL) { + child_parsed_tk = ec_tk_parse(tk->table[i], *t); + if (child_parsed_tk == NULL) + goto fail; + + if (strlen(child_parsed_tk->str) == 0) + t--; + else if (strlen(child_parsed_tk->str) != strlen(*t)) { + ec_parsed_tk_free(child_parsed_tk); + goto fail; + } + + ec_parsed_tk_free(child_parsed_tk); + } else { + child_completed_tk = ec_tk_complete(tk->table[i], *t); + if (child_completed_tk == NULL) { + ec_completed_tk_free(completed_tk); + return NULL; + } + ec_completed_tk_merge(completed_tk, child_completed_tk); + + child_parsed_tk = ec_tk_parse(tk->table[i], ""); + if (child_parsed_tk == NULL) + break; + ec_parsed_tk_free(child_parsed_tk); + t--; + } + } + + if (tokens != NULL) { + for (t = &tokens[0]; *t != NULL; t++) + ec_free(*t); + ec_free(tokens); + tokens = NULL; + } + + ec_completed_tk_dump(stdout, completed_tk); + + return completed_tk; + + fail: + if (tokens != NULL) { + for (t = &tokens[0]; *t != NULL; t++) + ec_free(*t); + ec_free(tokens); + } + ec_completed_tk_free(completed_tk); + + return NULL; +} + +static void ec_tk_shlex_free_priv(struct ec_tk *gen_tk) +{ + struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + unsigned int i; + + for (i = 0; i < tk->len; i++) + ec_tk_free(tk->table[i]); + ec_free(tk->table); +} + +static struct ec_tk_ops ec_tk_shlex_ops = { + .parse = ec_tk_shlex_parse, + .complete = ec_tk_shlex_complete, + .free_priv = ec_tk_shlex_free_priv, +}; + +struct ec_tk *ec_tk_shlex_new(const char *id) +{ + struct ec_tk_shlex *tk = NULL; + + tk = (struct ec_tk_shlex *)ec_tk_new(id, &ec_tk_shlex_ops, sizeof(*tk)); + if (tk == NULL) + return NULL; + + tk->table = NULL; + tk->len = 0; + + return &tk->gen; +} + +struct ec_tk *ec_tk_shlex_new_list(const char *id, ...) +{ + struct ec_tk_shlex *tk = NULL; + struct ec_tk *child; + va_list ap; + + va_start(ap, id); + + tk = (struct ec_tk_shlex *)ec_tk_shlex_new(id); + if (tk == NULL) + goto fail; + + for (child = va_arg(ap, struct ec_tk *); + child != EC_TK_ENDLIST; + child = va_arg(ap, struct ec_tk *)) { + if (child == NULL) + goto fail; + + ec_tk_shlex_add(&tk->gen, child); + } + + va_end(ap); + return &tk->gen; + +fail: + ec_tk_free(&tk->gen); /* will also free children */ + va_end(ap); + return NULL; +} + +int ec_tk_shlex_add(struct ec_tk *gen_tk, struct ec_tk *child) +{ + struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + struct ec_tk **table; + + // XXX check tk type + + assert(tk != NULL); + assert(child != NULL); + + table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table)); + if (table == NULL) + return -1; + + tk->table = table; + table[tk->len] = child; + tk->len ++; + + return 0; +} + +static int ec_tk_shlex_testcase(void) +{ + struct ec_tk *tk; + int ret = 0; + + tk = ec_tk_shlex_new_list(NULL, + ec_tk_str_new(NULL, "foo"), + ec_tk_option_new(NULL, ec_tk_str_new(NULL, "toto")), + ec_tk_str_new(NULL, "bar"), + EC_TK_ENDLIST); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo bar", "foo bar"); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " \"foo\" \"bar\"", + " \"foo\" \"bar\""); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo toto bar", "foo toto bar"); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " foo bar ", " foo bar "); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo bar xxx", NULL); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo barxxx", NULL); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", NULL); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " \"foo \" \"bar\"", NULL); + ec_tk_free(tk); + + /* test completion */ + tk = ec_tk_shlex_new_list(NULL, + ec_tk_str_new(NULL, "foo"), + ec_tk_option_new(NULL, ec_tk_str_new(NULL, "toto")), + ec_tk_str_new(NULL, "bar"), + ec_tk_str_new(NULL, "titi"), + EC_TK_ENDLIST); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, " ", "foo"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "foo ", + "bar", "toto", EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo t", "oto"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo b", "ar"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo bar", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo bar ", "titi"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo toto bar ", "titi"); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo barx", ""); + ec_tk_free(tk); + + return ret; +} + +static struct ec_test ec_tk_shlex_test = { + .name = "tk_shlex", + .test = ec_tk_shlex_testcase, +}; + +EC_REGISTER_TEST(ec_tk_shlex_test); diff --git a/lib/ecoli_tk_shlex.h b/lib/ecoli_tk_shlex.h new file mode 100644 index 0000000..52bc6a7 --- /dev/null +++ b/lib/ecoli_tk_shlex.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECOLI_TK_SHLEX_ +#define ECOLI_TK_SHLEX_ + +#include + +#include + +struct ec_tk_shlex { + struct ec_tk gen; + struct ec_tk **table; + unsigned int len; +}; + +struct ec_tk *ec_tk_shlex_new(const char *id); + +/* list must be terminated with EC_TK_ENDLIST */ +struct ec_tk *ec_tk_shlex_new_list(const char *id, ...); + +int ec_tk_shlex_add(struct ec_tk *tk, struct ec_tk *child); + +#endif diff --git a/lib/ecoli_tk_space.c b/lib/ecoli_tk_space.c index 20facf8..6c69b3b 100644 --- a/lib/ecoli_tk_space.c +++ b/lib/ecoli_tk_space.c @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include #include @@ -64,3 +66,40 @@ struct ec_tk *ec_tk_space_new(const char *id) return ec_tk_new(id, &ec_tk_space_ops, sizeof(struct ec_tk_space)); } +static int ec_tk_space_testcase(void) +{ + struct ec_tk *tk; + int ret = 0; + + tk = ec_tk_space_new(NULL); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_PARSE(tk, " ", " "); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " ", " "); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " foo", " "); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", NULL); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo ", NULL); + ec_tk_free(tk); + + /* test completion */ + tk = ec_tk_space_new(NULL); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, " ", ""); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", ""); + ec_tk_free(tk); + + return ret; +} + +static struct ec_test ec_tk_space_test = { + .name = "tk_space", + .test = ec_tk_space_testcase, +}; + +EC_REGISTER_TEST(ec_tk_space_test); diff --git a/lib/ecoli_tk_str.c b/lib/ecoli_tk_str.c index ad5d119..61953ef 100644 --- a/lib/ecoli_tk_str.c +++ b/lib/ecoli_tk_str.c @@ -61,17 +61,20 @@ static struct ec_completed_tk *ec_tk_str_complete(const struct ec_tk *gen_tk, struct ec_completed_tk_elt *completed_tk_elt; size_t n; + completed_tk = ec_completed_tk_new(); + if (completed_tk == NULL) + return NULL; + + /* check the string has the same beginning than the token */ for (n = 0; n < tk->len; n++) { if (str[n] != tk->string[n]) break; } if (str[n] != '\0') - return NULL; - - completed_tk = ec_completed_tk_new(); - if (completed_tk == NULL) - return NULL; + return completed_tk; + if (tk->string[n] == '\0') + return completed_tk; completed_tk_elt = ec_completed_tk_elt_new(gen_tk, tk->string + n, tk->string); @@ -127,7 +130,6 @@ static int ec_tk_str_testcase(void) struct ec_tk *tk; int ret = 0; - /* all inputs starting with foo should match */ tk = ec_tk_str_new(NULL, "foo"); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); @@ -140,7 +142,6 @@ static int ec_tk_str_testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", "foo"); ec_tk_free(tk); - /* all inputs starting with foo should match */ tk = ec_tk_str_new(NULL, "Здравствуйте"); if (tk == NULL) { ec_log(EC_LOG_ERR, "cannot create tk\n"); @@ -171,7 +172,7 @@ static int ec_tk_str_testcase(void) ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo"); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo"); ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", ""); - ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL); + ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", ""); ec_tk_free(tk); return ret; diff --git a/lib/main-readline.c b/lib/main-readline.c new file mode 100644 index 0000000..3bdc703 --- /dev/null +++ b/lib/main-readline.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +static struct ec_tk *commands; + +/* Set to a character describing the type of completion being attempted by + rl_complete_internal; available for use by application completion + functions. */ +extern int rl_completion_type; +/* Set to the last key used to invoke one of the completion functions */ +extern int rl_completion_invoking_key; + +int my_complete(int x, int y) +{ + (void)x; + (void)y; + + return 0; +} + +char *my_completion_entry(const char *s, int state) +{ + static struct ec_completed_tk *c; + static const struct ec_completed_tk_elt *elt; + + (void)s; + + if (state == 0) { + char *start; + + if (c != NULL) + ec_completed_tk_free(c); + + start = strdup(rl_line_buffer); + if (start == NULL) + return NULL; + start[rl_point] = '\0'; + + c = ec_tk_complete(commands, start); + ec_completed_tk_iter_start(c); + } + + elt = ec_completed_tk_iter_next(c); + if (elt == NULL) + return NULL; + + return strdup(elt->full); +} + +char **my_attempted_completion(const char *text, int start, int end) +{ + (void)start; + (void)end; + // XXX when it returns NULL, it completes with a file + return rl_completion_matches(text, my_completion_entry); +} + +int main(void) +{ + struct ec_parsed_tk *p; +// const char *name; + char *line; + + commands = ec_tk_seq_new_list(NULL, + ec_tk_str_new(NULL, "hello"), + ec_tk_space_new(NULL), + ec_tk_or_new_list("name", + ec_tk_str_new(NULL, "john"), + ec_tk_str_new(NULL, "mike"), + EC_TK_ENDLIST), + EC_TK_ENDLIST); + if (commands == NULL) { + printf("cannot create token\n"); + return 1; + } + + //rl_bind_key('\t', my_complete); + + //rl_completion_entry_function = my_completion_entry; + rl_attempted_completion_function = my_attempted_completion; + + while (1) { + line = readline("> "); + if (line == NULL) + break; + + // XXX need a "parse_all" + p = ec_tk_parse(commands, line); + ec_parsed_tk_dump(stdout, p); + add_history(line); + ec_parsed_tk_free(p); + } + + + ec_tk_free(commands); + return 0; +} -- 2.39.5