spdx tags for c and h files
[protos/libecoli.git] / lib / ecoli_node.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <errno.h>
11
12 #include <ecoli_malloc.h>
13 #include <ecoli_string.h>
14 #include <ecoli_strvec.h>
15 #include <ecoli_keyval.h>
16 #include <ecoli_log.h>
17 #include <ecoli_node.h>
18
19 EC_LOG_TYPE_REGISTER(node);
20
21 static struct ec_node_type_list node_type_list =
22         TAILQ_HEAD_INITIALIZER(node_type_list);
23
24 struct ec_node_type *ec_node_type_lookup(const char *name)
25 {
26         struct ec_node_type *type;
27
28         TAILQ_FOREACH(type, &node_type_list, next) {
29                 if (!strcmp(name, type->name))
30                         return type;
31         }
32
33         return NULL;
34 }
35
36 int ec_node_type_register(struct ec_node_type *type)
37 {
38         if (ec_node_type_lookup(type->name) != NULL)
39                 return -EEXIST;
40         if (type->size < sizeof(struct ec_node))
41                 return -EINVAL;
42
43         TAILQ_INSERT_TAIL(&node_type_list, type, next);
44
45         return 0;
46 }
47
48 void ec_node_type_dump(FILE *out)
49 {
50         struct ec_node_type *type;
51
52         TAILQ_FOREACH(type, &node_type_list, next)
53                 fprintf(out, "%s\n", type->name);
54 }
55
56 struct ec_node *__ec_node(const struct ec_node_type *type, const char *id)
57 {
58         struct ec_node *node = NULL;
59
60         EC_LOG(EC_LOG_DEBUG, "create node type=%s id=%s\n",
61                 type->name, id);
62         if (id == NULL) {
63                 errno = EINVAL;
64                 goto fail;
65         }
66
67         node = ec_calloc(1, type->size);
68         if (node == NULL)
69                 goto fail;
70
71         node->type = type;
72         node->refcnt = 1;
73
74         node->id = ec_strdup(id);
75         if (node->id == NULL)
76                 goto fail;
77
78         if (ec_asprintf(&node->desc, "<%s>", type->name) < 0)
79                 goto fail;
80
81         node->attrs = ec_keyval();
82         if (node->attrs == NULL)
83                 goto fail;
84
85         if (type->init_priv != NULL) {
86                 if (type->init_priv(node) < 0)
87                         goto fail;
88         }
89
90         return node;
91
92  fail:
93         if (node != NULL) {
94                 ec_keyval_free(node->attrs);
95                 ec_free(node->desc);
96                 ec_free(node->id);
97         }
98         ec_free(node);
99
100         return NULL;
101 }
102
103 struct ec_node *ec_node(const char *typename, const char *id)
104 {
105         struct ec_node_type *type;
106
107         type = ec_node_type_lookup(typename);
108         if (type == NULL) {
109                 EC_LOG(EC_LOG_ERR, "type=%s does not exist\n",
110                         typename);
111                 return NULL;
112         }
113
114         return __ec_node(type, id);
115 }
116
117 void ec_node_free(struct ec_node *node)
118 {
119         if (node == NULL)
120                 return;
121
122         assert(node->refcnt > 0);
123
124         if (--node->refcnt > 0)
125                 return;
126
127         if (node->type != NULL && node->type->free_priv != NULL)
128                 node->type->free_priv(node);
129         ec_free(node->children);
130         ec_free(node->id);
131         ec_free(node->desc);
132         ec_free(node->attrs);
133         ec_free(node);
134 }
135
136 struct ec_node *ec_node_clone(struct ec_node *node)
137 {
138         if (node != NULL)
139                 node->refcnt++;
140         return node;
141 }
142
143 size_t ec_node_get_children_count(const struct ec_node *node)
144 {
145         return node->n_children;
146 }
147
148 struct ec_node *
149 ec_node_get_child(const struct ec_node *node, size_t i)
150 {
151         if (i >= ec_node_get_children_count(node))
152                 return NULL;
153         return node->children[i];
154 }
155
156 int ec_node_add_child(struct ec_node *node, struct ec_node *child)
157 {
158         struct ec_node **children = NULL;
159         size_t n;
160
161         if (node == NULL || child == NULL) {
162                 errno = EINVAL;
163                 goto fail;
164         }
165
166         n = node->n_children;
167         children = ec_realloc(node->children,
168                         (n + 1) * sizeof(child));
169         if (children == NULL)
170                 goto fail;
171
172         children[n] = child;
173         node->children = children;
174         node->n_children = n + 1;
175
176         return 0;
177
178 fail:
179         ec_free(children);
180         return -1;
181 }
182
183 int ec_node_del_child(struct ec_node *node, struct ec_node *child)
184 {
185         size_t i, n;
186
187         if (node == NULL || child == NULL)
188                 goto fail;
189
190         n = node->n_children;
191         for (i = 0; i < n; i++) {
192                 if (node->children[i] != child)
193                         continue;
194                 memcpy(&node->children[i], &node->children[i+1],
195                         (n - i - 1) * sizeof(child));
196                 return 0;
197         }
198
199 fail:
200         errno = EINVAL;
201         return -1;
202 }
203
204 struct ec_node *ec_node_find(struct ec_node *node, const char *id)
205 {
206         struct ec_node *child, *ret;
207         const char *node_id = ec_node_id(node);
208         size_t i, n;
209
210         if (id != NULL && node_id != NULL && !strcmp(node_id, id))
211                 return node;
212
213         n = node->n_children;
214         for (i = 0; i < n; i++) {
215                 child = node->children[i];
216                 ret = ec_node_find(child, id);
217                 if (ret != NULL)
218                         return ret;
219         }
220
221         return NULL;
222 }
223
224 struct ec_keyval *ec_node_attrs(const struct ec_node *node)
225 {
226         return node->attrs;
227 }
228
229 const char *ec_node_id(const struct ec_node *node)
230 {
231         if (node->id == NULL)
232                 return "None";
233         return node->id;
234 }
235
236 static void __ec_node_dump(FILE *out,
237         const struct ec_node *node, size_t indent)
238 {
239         const char *id, *typename;
240         struct ec_node *child;
241         size_t i, n;
242
243         id = ec_node_id(node);
244         typename = node->type->name;
245
246         fprintf(out, "%*s" "type=%s id=%s %p\n",
247                 (int)indent * 4, "", typename, id, node);
248         n = node->n_children;
249         for (i = 0; i < n; i++) {
250                 child = node->children[i];
251                 __ec_node_dump(out, child, indent + 1);
252         }
253 }
254
255 void ec_node_dump(FILE *out, const struct ec_node *node)
256 {
257         fprintf(out, "------------------- node dump:\n");
258
259         if (node == NULL) {
260                 fprintf(out, "node is NULL\n");
261                 return;
262         }
263
264         __ec_node_dump(out, node, 0);
265 }
266
267 const char *ec_node_desc(const struct ec_node *node)
268 {
269         if (node->type->desc != NULL)
270                 return node->type->desc(node);
271
272         return node->desc;
273 }
274
275 int ec_node_check_type(const struct ec_node *node,
276                 const struct ec_node_type *type)
277 {
278         if (strcmp(node->type->name, type->name)) {
279                 errno = EINVAL;
280                 return -1;
281         }
282         return 0;
283 }