cde43b5d421fc7159613a6b38a2b5603d14cc860
[protos/libecoli.git] / lib / ecoli_node.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 <stdint.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <errno.h>
34
35 #include <ecoli_malloc.h>
36 #include <ecoli_strvec.h>
37 #include <ecoli_keyval.h>
38 #include <ecoli_log.h>
39 #include <ecoli_node.h>
40
41 EC_LOG_TYPE_REGISTER(node);
42
43 static struct ec_node_type_list node_type_list =
44         TAILQ_HEAD_INITIALIZER(node_type_list);
45
46 struct ec_node_type *ec_node_type_lookup(const char *name)
47 {
48         struct ec_node_type *type;
49
50         TAILQ_FOREACH(type, &node_type_list, next) {
51                 if (!strcmp(name, type->name))
52                         return type;
53         }
54
55         return NULL;
56 }
57
58 int ec_node_type_register(struct ec_node_type *type)
59 {
60         if (ec_node_type_lookup(type->name) != NULL)
61                 return -EEXIST;
62         if (type->size < sizeof(struct ec_node))
63                 return -EINVAL;
64
65         TAILQ_INSERT_TAIL(&node_type_list, type, next);
66
67         return 0;
68 }
69
70 void ec_node_type_dump(FILE *out)
71 {
72         struct ec_node_type *type;
73
74         TAILQ_FOREACH(type, &node_type_list, next)
75                 fprintf(out, "%s\n", type->name);
76 }
77
78 struct ec_node *__ec_node(const struct ec_node_type *type, const char *id)
79 {
80         struct ec_node *node = NULL;
81         char buf[256]; // XXX
82
83         EC_LOG(EC_LOG_DEBUG, "create node type=%s id=%s\n",
84                 type->name, id);
85         if (id == NULL) {
86                 errno = -EINVAL;
87                 goto fail;
88         }
89
90         node = ec_calloc(1, type->size);
91         if (node == NULL)
92                 goto fail;
93
94         TAILQ_INIT(&node->children);
95         node->type = type;
96         node->refcnt = 1;
97
98         if (id != NULL) {
99                 node->id = ec_strdup(id);
100                 if (node->id == NULL)
101                         goto fail;
102         }
103
104         snprintf(buf, sizeof(buf), "<%s>", type->name);
105         node->desc = ec_strdup(buf); // XXX ec_asprintf ?
106         if (node->desc == NULL)
107                 goto fail;
108
109         node->attrs = ec_keyval();
110         if (node->attrs == NULL)
111                 goto fail;
112
113         return node;
114
115  fail:
116         ec_node_free(node);
117         return NULL;
118 }
119
120 struct ec_node *ec_node(const char *typename, const char *id)
121 {
122         struct ec_node_type *type;
123
124         type = ec_node_type_lookup(typename);
125         if (type == NULL) {
126                 EC_LOG(EC_LOG_ERR, "type=%s does not exist\n",
127                         typename);
128                 return NULL;
129         }
130
131         return __ec_node(type, id);
132 }
133
134 void ec_node_free(struct ec_node *node)
135 {
136         if (node == NULL)
137                 return;
138
139         assert(node->refcnt > 0);
140
141         if (--node->refcnt > 0)
142                 return;
143
144         if (node->type != NULL && node->type->free_priv != NULL)
145                 node->type->free_priv(node);
146         ec_free(node->id);
147         ec_free(node->desc);
148         ec_free(node->attrs);
149         ec_free(node);
150 }
151
152 size_t ec_node_get_max_parse_len(const struct ec_node *node)
153 {
154         if (node->type->get_max_parse_len == NULL)
155                 return SIZE_MAX;
156         return node->type->get_max_parse_len(node);
157 }
158
159 struct ec_node *ec_node_clone(struct ec_node *node)
160 {
161         if (node != NULL)
162                 node->refcnt++;
163         return node;
164 }
165
166 struct ec_node *ec_node_find(struct ec_node *node, const char *id)
167 {
168         struct ec_node *child, *ret;
169         const char *node_id = ec_node_id(node);
170
171         if (id != NULL && node_id != NULL && !strcmp(node_id, id))
172                 return node;
173
174         TAILQ_FOREACH(child, &node->children, next) {
175                 ret = ec_node_find(child, id);
176                 if (ret != NULL)
177                         return ret;
178         }
179
180         return NULL;
181 }
182
183 struct ec_keyval *ec_node_attrs(const struct ec_node *node)
184 {
185         return node->attrs;
186 }
187
188 const char *ec_node_id(const struct ec_node *node)
189 {
190         if (node->id == NULL)
191                 return "None";
192         return node->id;
193 }
194
195 struct ec_node *ec_node_parent(const struct ec_node *node)
196 {
197         return node->parent;
198 }
199
200 static void __ec_node_dump(FILE *out,
201         const struct ec_node *node, size_t indent)
202 {
203         const char *id, *typename, *desc;
204         struct ec_node *child;
205         size_t maxlen;
206         size_t i;
207
208         maxlen = ec_node_get_max_parse_len(node);
209         id = ec_node_id(node);
210         typename = node->type->name;
211         desc = ec_node_desc(node);
212
213         /* XXX enhance */
214         for (i = 0; i < indent; i++) {
215                 if (i % 2)
216                         fprintf(out, " ");
217                 else
218                         fprintf(out, "|");
219         }
220
221         fprintf(out, "node %p type=%s id=%s desc=%s ",
222                 node, typename, id, desc);
223         if (maxlen == SIZE_MAX)
224                 fprintf(out, "maxlen=no\n");
225         else
226                 fprintf(out, "maxlen=%zu\n", maxlen);
227         TAILQ_FOREACH(child, &node->children, next)
228                 __ec_node_dump(out, child, indent + 2);
229 }
230
231 void ec_node_dump(FILE *out, const struct ec_node *node)
232 {
233         fprintf(out, "------------------- node dump:\n"); //XXX
234
235         if (node == NULL) {
236                 fprintf(out, "node is NULL\n");
237                 return;
238         }
239
240         __ec_node_dump(out, node, 0);
241 }
242
243 const char *ec_node_desc(const struct ec_node *node)
244 {
245         if (node->type->desc != NULL)
246                 return node->type->desc(node);
247
248         return node->desc;
249 }
250
251 int ec_node_check_type(const struct ec_node *node,
252                 const struct ec_node_type *type)
253 {
254         if (strcmp(node->type->name, type->name))
255                 return -EINVAL;
256         return 0;
257 }