From 0ae8acfbbe4820ccf222c49d8c49aa45202f4f18 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Wed, 2 Nov 2016 09:04:48 +0100 Subject: [PATCH] completion --- lib/build/test | Bin 71480 -> 84864 bytes lib/ecoli_test.c | 99 ++++++++++++++++++++++++++++++++++++++----- lib/ecoli_test.h | 16 +++++-- lib/ecoli_tk.c | 67 +++++++++++++++++------------ lib/ecoli_tk.h | 14 +++--- lib/ecoli_tk_empty.c | 48 ++++++++++++++++++--- lib/ecoli_tk_int.c | 37 ++++++++-------- lib/ecoli_tk_or.c | 32 ++++++++------ lib/ecoli_tk_seq.c | 95 ++++++++++++++++++++++++++++++++++++++--- lib/ecoli_tk_space.c | 8 ++-- lib/ecoli_tk_str.c | 24 +++++------ 11 files changed, 337 insertions(+), 103 deletions(-) diff --git a/lib/build/test b/lib/build/test index 2913edbfea5dab61b4cfb6a408acb65259c774f1..8ef7e3e67779de88bc45f316ca2fbe7014effaa5 100755 GIT binary patch literal 84864 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 UFKVCC;y1r%!_PVO-;Mu&0R>{jRR910 literal 71480 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 but completes with <%s>\n", expected, s); - ec_completed_tk_free(p); + ec_completed_tk_free(c); return ret; } +int ec_test_check_tk_complete_list(const struct ec_tk *tk, + const char *input, ...) +{ + struct ec_completed_tk *c = NULL; + struct ec_completed_tk_elt *elt; + const char *s; + int ret = -1; + unsigned int count = 0; + va_list ap; + + va_start(ap, input); + + c = ec_tk_complete(tk, input); + if (c == NULL) + goto out; + + for (s = va_arg(ap, const char *); + s != EC_TK_ENDLIST; + s = va_arg(ap, const char *)) { + if (s == NULL) + goto out; + + count++; + TAILQ_FOREACH(elt, &c->elts, next) { + if (strcmp(elt->add, s) == 0) + break; + } + + if (elt == NULL) { + ec_log(EC_LOG_ERR, + "completion <%s> not in list\n", s); + goto out; + } + } + + if (count != ec_completed_tk_count(c)) { + ec_log(EC_LOG_ERR, + "nb_completion (%d) does not match (%d)\n", + count, ec_completed_tk_count(c)); + goto out; + } + + ret = 0; + +out: + ec_completed_tk_free(c); + va_end(ap); + return ret; +} + TAILQ_HEAD(debug_alloc_hdr_list, debug_alloc_hdr); static struct debug_alloc_hdr_list debug_alloc_hdr_list = TAILQ_HEAD_INITIALIZER(debug_alloc_hdr_list); @@ -108,10 +158,15 @@ struct debug_alloc_hdr { unsigned int cookie; }; +struct debug_alloc_ftr { + unsigned int cookie; +} __attribute__((packed)); + static void *debug_malloc(size_t size, const char *file, unsigned int line) { struct debug_alloc_hdr *hdr; - size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int); + struct debug_alloc_ftr *ftr; + size_t new_size = size + sizeof(*hdr) + sizeof(*ftr); void *ret; hdr = malloc(new_size); @@ -124,6 +179,9 @@ static void *debug_malloc(size_t size, const char *file, unsigned int line) hdr->cookie = 0x12345678; TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next); ret = hdr + 1; + ftr = (struct debug_alloc_ftr *)( + (char *)hdr + size + sizeof(*hdr)); + ftr->cookie = 0x12345678; } ec_log(EC_LOG_INFO, "%s:%d: info: malloc(%zd) -> %p\n", @@ -135,6 +193,7 @@ static void *debug_malloc(size_t size, const char *file, unsigned int line) static void debug_free(void *ptr, const char *file, unsigned int line) { struct debug_alloc_hdr *hdr, *h; + struct debug_alloc_ftr *ftr; (void)file; (void)line; @@ -151,6 +210,13 @@ static void debug_free(void *ptr, const char *file, unsigned int line) abort(); } + ftr = (ptr + hdr->size); + if (ftr->cookie != 0x12345678) { + ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad end cookie\n", + file, line, ptr); + abort(); + } + TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) { if (h == hdr) break; @@ -168,14 +234,24 @@ static void debug_free(void *ptr, const char *file, unsigned int line) void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line) { - struct debug_alloc_hdr *hdr = (ptr - sizeof(*hdr)); - struct debug_alloc_hdr *h; + struct debug_alloc_hdr *hdr, *h; + struct debug_alloc_ftr *ftr; size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int); void *ret; if (ptr != NULL) { + hdr = (ptr - sizeof(*hdr)); if (hdr->cookie != 0x12345678) { - ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad start cookie\n", + ec_log(EC_LOG_ERR, + "%s:%d: error: realloc(%p): bad start cookie\n", + file, line, ptr); + abort(); + } + + ftr = (ptr + hdr->size); + if (ftr->cookie != 0x12345678) { + ec_log(EC_LOG_ERR, + "%s:%d: error: realloc(%p): bad end cookie\n", file, line, ptr); abort(); } @@ -204,7 +280,7 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line) if (hdr == NULL) ret = NULL; else - ret= hdr + 1; + ret = hdr + 1; } if (hdr != NULL) { @@ -213,6 +289,9 @@ void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line) hdr->size = size; hdr->cookie = 0x12345678; TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next); + ftr = (struct debug_alloc_ftr *)( + (char *)hdr + size + sizeof(*hdr)); + ftr->cookie = 0x12345678; } ec_log(EC_LOG_INFO, "%s:%d: info: realloc(%p, %zd) -> %p\n", @@ -243,7 +322,7 @@ int ec_test_all(void) TAILQ_INIT(&debug_alloc_hdr_list); /* register a new malloc to trac memleaks */ - if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) { + if (0 && 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_test.h b/lib/ecoli_test.h index 61d9950..45d1d4e 100644 --- a/lib/ecoli_test.h +++ b/lib/ecoli_test.h @@ -30,6 +30,7 @@ #include +#include #include #define EC_REGISTER_TEST(t) \ @@ -66,13 +67,12 @@ void ec_test_register(struct ec_test *test); int ec_test_all(void); -// XXX could be a macro that display file:line int ec_test_check_tk_parse(const struct ec_tk *tk, const char *input, const char *expected); #define TEST_ERR() \ - printf("%s:%d: error: test failed\n", \ - __FILE__, __LINE__); \ + ec_log(EC_LOG_ERR, "%s:%d: error: test failed\n", \ + __FILE__, __LINE__); \ #define EC_TEST_CHECK_TK_PARSE(tk, input, expected) ({ \ int ret = ec_test_check_tk_parse(tk, input, expected); \ @@ -91,4 +91,14 @@ int ec_test_check_tk_complete(const struct ec_tk *tk, const char *input, ret; \ }) +int ec_test_check_tk_complete_list(const struct ec_tk *tk, + const char *input, ...); + +#define EC_TEST_CHECK_TK_COMPLETE_LIST(tk, input, expected...) ({ \ + int ret = ec_test_check_tk_complete_list(tk, input, expected); \ + if (ret) \ + TEST_ERR(); \ + ret; \ +}) + #endif diff --git a/lib/ecoli_tk.c b/lib/ecoli_tk.c index e814b68..cdb064e 100644 --- a/lib/ecoli_tk.c +++ b/lib/ecoli_tk.c @@ -70,11 +70,15 @@ void ec_tk_free(struct ec_tk *tk) ec_free(tk); } -struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *token, const char *str) +struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *tk, const char *str) { struct ec_parsed_tk *parsed_tk; - parsed_tk = token->ops->parse(token, str); + /* by default, it does not match anything */ + if (tk->ops->parse == NULL) + return NULL; + + parsed_tk = tk->ops->parse(tk, str); return parsed_tk; } @@ -174,16 +178,6 @@ const char *ec_parsed_tk_to_string(const struct ec_parsed_tk *parsed_tk) return parsed_tk->str; } -struct ec_completed_tk *ec_tk_complete(const struct ec_tk *token, - const char *str) -{ - struct ec_completed_tk *completed_tk; - - completed_tk = token->ops->complete(token, str); - - return completed_tk; -} - struct ec_completed_tk *ec_completed_tk_new(void) { struct ec_completed_tk *completed_tk = NULL; @@ -208,16 +202,41 @@ struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk, return NULL; elt->tk = tk; - elt->add = ec_strdup(add); - elt->full = ec_strdup(full); - if (elt->add == NULL || elt->full == NULL) { - ec_completed_tk_elt_free(elt); - return NULL; + if (add != NULL) { + elt->add = ec_strdup(add); + if (elt->add == NULL) { + ec_completed_tk_elt_free(elt); + return NULL; + } + } + if (full != NULL) { + elt->full = ec_strdup(full); + if (elt->full == NULL) { + ec_completed_tk_elt_free(elt); + return NULL; + } } return elt; } +/* XXX define when to use ec_tk_complete() or tk->complete() + * (same for parse) + * suggestion: tk->op() is internal, user calls the function + */ +struct ec_completed_tk *ec_tk_complete(const struct ec_tk *tk, + const char *str) +{ + struct ec_completed_tk *completed_tk; + + if (tk->ops->complete == NULL) + return ec_completed_tk_new(); + + completed_tk = tk->ops->complete(tk, str); + + return completed_tk; +} + /* count the number of identical chars at the beginning of 2 strings */ static size_t strcmp_count(const char *s1, const char *s2) { @@ -305,8 +324,10 @@ void ec_completed_tk_dump(FILE *out, const struct ec_completed_tk *completed_tk) fprintf(out, "completion: count=%u smallest_start=<%s>\n", completed_tk->count, completed_tk->smallest_start); - TAILQ_FOREACH(elt, &completed_tk->elts, next) - fprintf(out, "add=<%s> full=<%s>\n", elt->add, elt->full); + TAILQ_FOREACH(elt, &completed_tk->elts, next) { + fprintf(out, "add=<%s>, full=<%s>, tk=%p\n", + elt->add, elt->full, elt->tk); + } } const char *ec_completed_tk_smallest_start( @@ -320,14 +341,8 @@ const char *ec_completed_tk_smallest_start( unsigned int ec_completed_tk_count(const struct ec_completed_tk *completed_tk) { - struct ec_completed_tk_elt *elt; - unsigned int count = 0; - if (completed_tk == NULL) return 0; - TAILQ_FOREACH(elt, &completed_tk->elts, next) - count++; - - return count; + return completed_tk->count; } diff --git a/lib/ecoli_tk.h b/lib/ecoli_tk.h index 490c5e1..cc0a208 100644 --- a/lib/ecoli_tk.h +++ b/lib/ecoli_tk.h @@ -69,6 +69,10 @@ struct ec_parsed_tk { char *str; }; +/* XXX we could use a cache to store possible completions or match: the + * cache would be per-node, and would be reset for each call to parse() + * or complete() ? */ + struct ec_parsed_tk *ec_parsed_tk_new(const struct ec_tk *tk); struct ec_parsed_tk *ec_tk_parse(const struct ec_tk *token, const char *str); void ec_parsed_tk_add_child(struct ec_parsed_tk *parsed_tk, @@ -98,17 +102,16 @@ struct ec_completed_tk { }; /* - * return NULL if it does not match the beginning of the token - * return "" if it matches but does not know how to complete - * return "xyz" if it knows how to complete + * return a completed_tk object filled with elts + * return NULL on error (nomem?) */ struct ec_completed_tk *ec_tk_complete(const struct ec_tk *token, const char *str); struct ec_completed_tk *ec_completed_tk_new(void); struct ec_completed_tk_elt *ec_completed_tk_elt_new(const struct ec_tk *tk, const char *add, const char *full); -void ec_completed_tk_add_elt( - struct ec_completed_tk *completed_tk, struct ec_completed_tk_elt *elt); +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, @@ -117,6 +120,7 @@ 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 */ const char *ec_completed_tk_smallest_start( const struct ec_completed_tk *completed_tk); diff --git a/lib/ecoli_tk_empty.c b/lib/ecoli_tk_empty.c index 61d29b5..e3e24f9 100644 --- a/lib/ecoli_tk_empty.c +++ b/lib/ecoli_tk_empty.c @@ -29,10 +29,13 @@ #include #include +#include +#include +#include #include #include -static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_empty_parse(const struct ec_tk *gen_tk, const char *str) { struct ec_parsed_tk *parsed_tk; @@ -42,17 +45,52 @@ static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, return NULL; (void)str; - parsed_tk->str = strdup(""); + parsed_tk->str = ec_strdup(""); return parsed_tk; } -static struct ec_tk_ops empty_ops = { - .parse = parse, +static struct ec_tk_ops ec_tk_empty_ops = { + .parse = ec_tk_empty_parse, }; struct ec_tk *ec_tk_empty_new(const char *id) { - return ec_tk_new(id, &empty_ops, sizeof(struct ec_tk_empty)); + return ec_tk_new(id, &ec_tk_empty_ops, sizeof(struct ec_tk_empty)); } +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"); + return -1; + } + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", ""); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " foo", ""); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "", ""); + ec_tk_free(tk); + + /* never completes */ + tk = ec_tk_empty_new(NULL); + if (tk == NULL) { + 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); + ec_tk_free(tk); + + return ret; +} + +static struct ec_test ec_tk_empty_test = { + .name = "tk_empty", + .test = ec_tk_empty_testcase, +}; + +EC_REGISTER_TEST(ec_tk_empty_test); diff --git a/lib/ecoli_tk_int.c b/lib/ecoli_tk_int.c index 6296b8b..8aeb6bc 100644 --- a/lib/ecoli_tk_int.c +++ b/lib/ecoli_tk_int.c @@ -61,7 +61,7 @@ static size_t parse_llint(struct ec_tk_int *tk, const char *str, return endptr - str; } -static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_int_parse(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_int *tk = (struct ec_tk_int *)gen_tk; @@ -82,8 +82,8 @@ static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, return parsed_tk; } -static struct ec_tk_ops int_ops = { - .parse = parse, +static struct ec_tk_ops ec_tk_int_ops = { + .parse = ec_tk_int_parse, }; struct ec_tk *ec_tk_int_new(const char *id, long long int min, @@ -91,7 +91,7 @@ struct ec_tk *ec_tk_int_new(const char *id, long long int min, { struct ec_tk_int *tk = NULL; - tk = (struct ec_tk_int *)ec_tk_new(id, &int_ops, sizeof(*tk)); + tk = (struct ec_tk_int *)ec_tk_new(id, &ec_tk_int_ops, sizeof(*tk)); if (tk == NULL) return NULL; @@ -115,7 +115,7 @@ long long ec_tk_int_getval(struct ec_tk *gen_tk, const char *str) return val; } -static int testcase(void) +static int ec_tk_int_testcase(void) { struct ec_parsed_tk *p; struct ec_tk *tk; @@ -192,24 +192,23 @@ static int testcase(void) ret |= EC_TEST_CHECK_TK_PARSE(tk, "1", NULL); ec_tk_free(tk); - /* /\* test completion *\/ */ - /* tk = ec_tk_int_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, "foo", ""); */ - /* ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", NULL); */ - /* ec_tk_free(tk); */ + /* test completion */ + tk = ec_tk_int_new(NULL, 0, 10, 0); + if (tk == NULL) { + 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); + ec_tk_free(tk); return ret; } -static struct ec_test test = { +static struct ec_test ec_tk_int_test = { .name = "tk_int", - .test = testcase, + .test = ec_tk_int_testcase, }; -EC_REGISTER_TEST(test); +EC_REGISTER_TEST(ec_tk_int_test); diff --git a/lib/ecoli_tk_or.c b/lib/ecoli_tk_or.c index b498dcb..4c782dd 100644 --- a/lib/ecoli_tk_or.c +++ b/lib/ecoli_tk_or.c @@ -38,7 +38,7 @@ #include #include -static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_or_parse(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk; @@ -70,7 +70,7 @@ static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, return NULL; } -static struct ec_completed_tk *complete(const struct ec_tk *gen_tk, +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; @@ -90,7 +90,7 @@ static struct ec_completed_tk *complete(const struct ec_tk *gen_tk, return completed_tk; } -static void free_priv(struct ec_tk *gen_tk) +static void ec_tk_or_free_priv(struct ec_tk *gen_tk) { struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk; unsigned int i; @@ -100,17 +100,17 @@ static void free_priv(struct ec_tk *gen_tk) ec_free(tk->table); } -static struct ec_tk_ops or_ops = { - .parse = parse, - .complete = complete, - .free_priv = free_priv, +static struct ec_tk_ops ec_tk_or_ops = { + .parse = ec_tk_or_parse, + .complete = ec_tk_or_complete, + .free_priv = ec_tk_or_free_priv, }; struct ec_tk *ec_tk_or_new(const char *id) { struct ec_tk_or *tk = NULL; - tk = (struct ec_tk_or *)ec_tk_new(id, &or_ops, sizeof(*tk)); + tk = (struct ec_tk_or *)ec_tk_new(id, &ec_tk_or_ops, sizeof(*tk)); if (tk == NULL) return NULL; @@ -169,7 +169,7 @@ int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child) return 0; } -static int testcase(void) +static int ec_tk_or_testcase(void) { struct ec_tk *tk; int ret = 0; @@ -207,14 +207,22 @@ static int testcase(void) 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_LIST(tk, "", + "foo", "bar", "bar2", "toto", "titi", EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "f", + "oo", EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "b", + "ar", "ar2", EC_TK_ENDLIST); + ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "t", + "oto", "iti", EC_TK_ENDLIST); ec_tk_free(tk); return ret; } -static struct ec_test test = { +static struct ec_test ec_tk_or_test = { .name = "tk_or", - .test = testcase, + .test = ec_tk_or_testcase, }; -EC_REGISTER_TEST(test); +EC_REGISTER_TEST(ec_tk_or_test); diff --git a/lib/ecoli_tk_seq.c b/lib/ecoli_tk_seq.c index 4c182c4..fb1b434 100644 --- a/lib/ecoli_tk_seq.c +++ b/lib/ecoli_tk_seq.c @@ -32,12 +32,15 @@ #include #include +#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 *parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk; @@ -67,7 +70,34 @@ static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, return NULL; } -static void free_priv(struct ec_tk *gen_tk) +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_parsed_tk *parsed_tk; + size_t len = 0; + unsigned int i; + + if (tk->len == 0) + return ec_completed_tk_new(); + + /* 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; + + len += strlen(parsed_tk->str); + ec_parsed_tk_free(parsed_tk); + } + + completed_tk = ec_tk_complete(tk->table[i], str + len); + + return completed_tk; +} + +static void ec_tk_seq_free_priv(struct ec_tk *gen_tk) { struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk; unsigned int i; @@ -77,16 +107,17 @@ static void free_priv(struct ec_tk *gen_tk) ec_free(tk->table); } -static struct ec_tk_ops seq_ops = { - .parse = parse, - .free_priv = free_priv, +static struct ec_tk_ops ec_tk_seq_ops = { + .parse = ec_tk_seq_parse, + .complete = ec_tk_seq_complete, + .free_priv = ec_tk_seq_free_priv, }; struct ec_tk *ec_tk_seq_new(const char *id) { struct ec_tk_seq *tk = NULL; - tk = (struct ec_tk_seq *)ec_tk_new(id, &seq_ops, sizeof(*tk)); + tk = (struct ec_tk_seq *)ec_tk_new(id, &ec_tk_seq_ops, sizeof(*tk)); if (tk == NULL) return NULL; @@ -131,10 +162,12 @@ int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child) struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk; struct ec_tk **table; + // XXX check tk type + assert(tk != NULL); assert(child != NULL); - table = ec_realloc(tk->table, tk->len + 1); + table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table)); if (table == NULL) return -1; @@ -145,3 +178,51 @@ int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child) return 0; } +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"), + EC_TK_ENDLIST); + if (tk == NULL) { + ec_log(EC_LOG_ERR, "cannot create tk\n"); + return -1; + } + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foobar", "foobar"); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foobarxxx", "foobar"); + ret |= EC_TEST_CHECK_TK_PARSE(tk, " foobar", NULL); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", NULL); + ret |= EC_TEST_CHECK_TK_PARSE(tk, "bar", NULL); + ec_tk_free(tk); + + /* test completion */ + tk = ec_tk_seq_new_list(NULL, + ec_tk_str_new(NULL, "foo"), + 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_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, "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); + ec_tk_free(tk); + + return ret; +} + +static struct ec_test ec_tk_seq_test = { + .name = "tk_seq", + .test = ec_tk_seq_testcase, +}; + +EC_REGISTER_TEST(ec_tk_seq_test); diff --git a/lib/ecoli_tk_space.c b/lib/ecoli_tk_space.c index adc57c4..20facf8 100644 --- a/lib/ecoli_tk_space.c +++ b/lib/ecoli_tk_space.c @@ -34,7 +34,7 @@ #include #include -static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_space_parse(const struct ec_tk *gen_tk, const char *str) { struct ec_parsed_tk *parsed_tk; @@ -55,12 +55,12 @@ static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, return parsed_tk; } -static struct ec_tk_ops space_ops = { - .parse = parse, +static struct ec_tk_ops ec_tk_space_ops = { + .parse = ec_tk_space_parse, }; struct ec_tk *ec_tk_space_new(const char *id) { - return ec_tk_new(id, &space_ops, sizeof(struct ec_tk_space)); + return ec_tk_new(id, &ec_tk_space_ops, sizeof(struct ec_tk_space)); } diff --git a/lib/ecoli_tk_str.c b/lib/ecoli_tk_str.c index f7b18fb..ad5d119 100644 --- a/lib/ecoli_tk_str.c +++ b/lib/ecoli_tk_str.c @@ -35,7 +35,7 @@ #include #include -static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_str_parse(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_str *tk = (struct ec_tk_str *)gen_tk; @@ -53,7 +53,7 @@ static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk, return parsed_tk; } -static struct ec_completed_tk *complete(const struct ec_tk *gen_tk, +static struct ec_completed_tk *ec_tk_str_complete(const struct ec_tk *gen_tk, const char *str) { struct ec_tk_str *tk = (struct ec_tk_str *)gen_tk; @@ -85,17 +85,17 @@ static struct ec_completed_tk *complete(const struct ec_tk *gen_tk, return completed_tk; } -static void free_priv(struct ec_tk *gen_tk) +static void ec_tk_str_free_priv(struct ec_tk *gen_tk) { struct ec_tk_str *tk = (struct ec_tk_str *)gen_tk; ec_free(tk->string); } -static struct ec_tk_ops str_ops = { - .parse = parse, - .complete = complete, - .free_priv = free_priv, +static struct ec_tk_ops ec_tk_str_ops = { + .parse = ec_tk_str_parse, + .complete = ec_tk_str_complete, + .free_priv = ec_tk_str_free_priv, }; struct ec_tk *ec_tk_str_new(const char *id, const char *str) @@ -103,7 +103,7 @@ struct ec_tk *ec_tk_str_new(const char *id, const char *str) struct ec_tk_str *tk = NULL; char *s = NULL; - tk = (struct ec_tk_str *)ec_tk_new(id, &str_ops, sizeof(*tk)); + tk = (struct ec_tk_str *)ec_tk_new(id, &ec_tk_str_ops, sizeof(*tk)); if (tk == NULL) goto fail; @@ -122,7 +122,7 @@ fail: return NULL; } -static int testcase(void) +static int ec_tk_str_testcase(void) { struct ec_tk *tk; int ret = 0; @@ -177,9 +177,9 @@ static int testcase(void) return ret; } -static struct ec_test test = { +static struct ec_test ec_tk_str_test = { .name = "tk_str", - .test = testcase, + .test = ec_tk_str_testcase, }; -EC_REGISTER_TEST(test); +EC_REGISTER_TEST(ec_tk_str_test); -- 2.20.1