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