38c633abc703857d6d999e252d4369a978aa7c49
[protos/libecoli.git] / lib / ecoli_tk_seq.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 #include <stdarg.h>
33
34 #include <ecoli_tk.h>
35 #include <ecoli_tk_seq.h>
36
37 static struct ec_parsed_tk *parse(const struct ec_tk *tk,
38         const char *str, size_t off)
39 {
40         struct ec_tk_seq *seq = (struct ec_tk_seq *)tk;
41         struct ec_parsed_tk *parsed_tk, *child_parsed_tk;
42         size_t len = 0;
43         unsigned int i;
44
45         parsed_tk = ec_parsed_tk_new(tk);
46         if (parsed_tk == NULL)
47                 return NULL;
48
49         for (i = 0; i < seq->len; i++) {
50                 child_parsed_tk = ec_tk_parse(seq->table[i], str, off + len);
51                 if (child_parsed_tk == NULL)
52                         goto fail;
53
54                 len += strlen(child_parsed_tk->str);
55                 ec_parsed_tk_add_child(parsed_tk, child_parsed_tk);
56         }
57
58         parsed_tk->str = strndup(str + off, len);
59
60         return parsed_tk;
61
62  fail:
63         ec_parsed_tk_free(parsed_tk);
64         return NULL;
65 }
66
67 static struct ec_tk_ops seq_ops = {
68         .parse = parse,
69 };
70
71 struct ec_tk *ec_tk_seq_new(const char *id)
72 {
73         struct ec_tk_seq *tk = NULL;
74
75         tk = (struct ec_tk_seq *)ec_tk_new(id, &seq_ops, sizeof(*tk));
76         if (tk == NULL)
77                 goto fail;
78
79         tk->table = NULL;
80         tk->len = 0;
81
82         return &tk->gen;
83
84 fail:
85         free(tk);
86         return NULL;
87 }
88
89 struct ec_tk *ec_tk_seq_new_list(const char *id, ...)
90 {
91         struct ec_tk_seq *tk = NULL;
92         struct ec_tk *child;
93         va_list ap;
94
95         va_start(ap, id);
96
97         tk = (struct ec_tk_seq *)ec_tk_seq_new(id);
98         if (tk == NULL)
99                 goto fail;
100
101         for (child = va_arg(ap, struct ec_tk *);
102              child != EC_TK_ENDLIST;
103              child = va_arg(ap, struct ec_tk *)) {
104                 if (child == NULL)
105                         goto fail;
106
107                 ec_tk_seq_add(&tk->gen, child);
108         }
109
110         va_end(ap);
111         return &tk->gen;
112
113 fail:
114         free(tk); // XXX use tk_free? we need to delete all child on error
115         va_end(ap);
116         return NULL;
117 }
118
119 int ec_tk_seq_add(struct ec_tk *tk, struct ec_tk *child)
120 {
121         struct ec_tk_seq *seq = (struct ec_tk_seq *)tk;
122         struct ec_tk **table;
123
124         assert(tk != NULL);
125         assert(child != NULL);
126
127         table = realloc(seq->table, seq->len + 1);
128         if (table == NULL)
129                 return -1;
130
131         seq->table = table;
132         table[seq->len] = child;
133         seq->len ++;
134
135         return 0;
136 }
137