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.
34 #include <ecoli_malloc.h>
35 #include <ecoli_log.h>
36 #include <ecoli_test.h>
38 #include <ecoli_tk_str.h>
39 #include <ecoli_tk_option.h>
40 #include <ecoli_tk_seq.h>
42 static struct ec_parsed_tk *ec_tk_seq_parse(const struct ec_tk *gen_tk,
45 struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
46 struct ec_parsed_tk *parsed_tk, *child_parsed_tk;
50 parsed_tk = ec_parsed_tk_new(gen_tk);
51 if (parsed_tk == NULL)
54 for (i = 0; i < tk->len; i++) {
55 child_parsed_tk = ec_tk_parse(tk->table[i], str + len);
56 if (child_parsed_tk == NULL)
59 len += strlen(child_parsed_tk->str);
60 ec_parsed_tk_add_child(parsed_tk, child_parsed_tk);
63 parsed_tk->str = ec_strndup(str, len);
68 ec_parsed_tk_free(parsed_tk);
72 static struct ec_completed_tk *ec_tk_seq_complete(const struct ec_tk *gen_tk,
75 struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
76 struct ec_completed_tk *completed_tk, *child_completed_tk;
77 struct ec_parsed_tk *parsed_tk;
81 completed_tk = ec_completed_tk_new();
82 if (completed_tk == NULL)
88 for (i = 0; i < tk->len; i++) {
89 child_completed_tk = ec_tk_complete(tk->table[i], str + len);
90 if (child_completed_tk == NULL) {
91 ec_completed_tk_free(completed_tk);
94 ec_completed_tk_merge(completed_tk, child_completed_tk);
96 parsed_tk = ec_tk_parse(tk->table[i], str + len);
97 if (parsed_tk == NULL)
100 len += strlen(parsed_tk->str);
101 ec_parsed_tk_free(parsed_tk);
107 static void ec_tk_seq_free_priv(struct ec_tk *gen_tk)
109 struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
112 for (i = 0; i < tk->len; i++)
113 ec_tk_free(tk->table[i]);
117 static struct ec_tk_ops ec_tk_seq_ops = {
118 .parse = ec_tk_seq_parse,
119 .complete = ec_tk_seq_complete,
120 .free_priv = ec_tk_seq_free_priv,
123 struct ec_tk *ec_tk_seq_new(const char *id)
125 struct ec_tk_seq *tk = NULL;
127 tk = (struct ec_tk_seq *)ec_tk_new(id, &ec_tk_seq_ops, sizeof(*tk));
137 struct ec_tk *ec_tk_seq_new_list(const char *id, ...)
139 struct ec_tk_seq *tk = NULL;
145 tk = (struct ec_tk_seq *)ec_tk_seq_new(id);
149 for (child = va_arg(ap, struct ec_tk *);
150 child != EC_TK_ENDLIST;
151 child = va_arg(ap, struct ec_tk *)) {
155 ec_tk_seq_add(&tk->gen, child);
162 ec_tk_free(&tk->gen); /* will also free children */
167 int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
169 struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
170 struct ec_tk **table;
175 assert(child != NULL);
177 table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
182 table[tk->len] = child;
188 static int ec_tk_seq_testcase(void)
193 tk = ec_tk_seq_new_list(NULL,
194 ec_tk_str_new(NULL, "foo"),
195 ec_tk_str_new(NULL, "bar"),
198 ec_log(EC_LOG_ERR, "cannot create tk\n");
201 ret |= EC_TEST_CHECK_TK_PARSE(tk, "foobar", "foobar");
202 ret |= EC_TEST_CHECK_TK_PARSE(tk, "foobarxxx", "foobar");
203 ret |= EC_TEST_CHECK_TK_PARSE(tk, " foobar", NULL);
204 ret |= EC_TEST_CHECK_TK_PARSE(tk, "foo", NULL);
205 ret |= EC_TEST_CHECK_TK_PARSE(tk, "bar", NULL);
208 /* test completion */
209 tk = ec_tk_seq_new_list(NULL,
210 ec_tk_str_new(NULL, "foo"),
211 ec_tk_option_new(NULL, ec_tk_str_new(NULL, "toto")),
212 ec_tk_str_new(NULL, "bar"),
215 ec_log(EC_LOG_ERR, "cannot create tk\n");
218 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "", "foo");
219 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "f", "oo");
220 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foo", "");
221 ret |= EC_TEST_CHECK_TK_COMPLETE_LIST(tk, "foo",
222 "bar", "toto", EC_TK_ENDLIST);
223 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foot", "oto");
224 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foob", "ar");
225 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foobar", "");
226 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "x", "");
227 ret |= EC_TEST_CHECK_TK_COMPLETE(tk, "foobarx", "");
233 static struct ec_test ec_tk_seq_test = {
235 .test = ec_tk_seq_testcase,
238 EC_REGISTER_TEST(ec_tk_seq_test);