libtreestore

view src/treestore.c @ 3:48d75df3ef04

picking this up again, converted to cmake, and started a text format reader/writer
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 10 Nov 2016 16:19:44 +0200
parents e1a825be0eee
children bb873449cf59
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include "treestore.h"
7 struct ts_node *ts_text_load(FILE *fp);
8 int ts_text_save(struct ts_node *tree, FILE *fp);
10 /* ---- ts_value implementation ---- */
12 int ts_init_value(struct ts_value *tsv)
13 {
14 memset(tsv, 0, sizeof *tsv);
15 return 0;
16 }
18 void ts_destroy_value(struct ts_value *tsv)
19 {
20 int i;
22 free(tsv->str);
23 free(tsv->vec);
25 for(i=0; i<tsv->array_size; i++) {
26 ts_destroy_value(tsv->array + i);
27 }
28 }
31 struct ts_value *ts_alloc_value(void)
32 {
33 struct ts_value *v = malloc(sizeof *v);
34 if(!v || ts_init_value(v) == -1) {
35 free(v);
36 return 0;
37 }
38 return v;
39 }
41 void ts_free_value(struct ts_value *tsv)
42 {
43 ts_destroy_value(tsv);
44 free(tsv);
45 }
48 int ts_copy_value(struct ts_value *dest, struct ts_value *src)
49 {
50 int i;
52 if(dest == src) return 0;
54 *dest = *src;
56 dest->str = 0;
57 dest->vec = 0;
58 dest->array = 0;
60 if(src->str) {
61 if(!(dest->str = malloc(strlen(src->str) + 1))) {
62 goto fail;
63 }
64 strcpy(dest->str, src->str);
65 }
66 if(src->vec && src->vec_size > 0) {
67 if(!(dest->vec = malloc(src->vec_size * sizeof *src->vec))) {
68 goto fail;
69 }
70 memcpy(dest->vec, src->vec, src->vec_size * sizeof *src->vec);
71 }
72 if(src->array && src->array_size > 0) {
73 if(!(dest->array = calloc(src->array_size, sizeof *src->array))) {
74 goto fail;
75 }
76 for(i=0; i<src->array_size; i++) {
77 if(ts_copy_value(dest->array + i, src->array + i) == -1) {
78 goto fail;
79 }
80 }
81 }
82 return 0;
84 fail:
85 free(dest->str);
86 free(dest->vec);
87 if(dest->array) {
88 for(i=0; i<dest->array_size; i++) {
89 ts_destroy_value(dest->array + i);
90 }
91 free(dest->array);
92 }
93 return -1;
94 }
97 int ts_set_value(struct ts_value *tsv, const char *str)
98 {
99 if(tsv->str) {
100 ts_destroy_value(tsv);
101 if(ts_init_value(tsv) == -1) {
102 return -1;
103 }
104 }
106 if(!(tsv->str = malloc(strlen(str) + 1))) {
107 return -1;
108 }
109 strcpy(tsv->str, str);
110 return 0;
111 }
113 int ts_set_valueiv(struct ts_value *tsv, int count, ...)
114 {
115 int res;
116 va_list ap;
117 va_start(ap, count);
118 res = ts_set_valueiv_va(tsv, count, ap);
119 va_end(ap);
120 return res;
121 }
123 #define MAKE_NUMSTR_FUNC(typestr, fmt) \
124 static char *make_##typestr##str(int x) \
125 { \
126 static char scrap[128]; \
127 char *str; \
128 int sz = snprintf(scrap, sizeof scrap, fmt, x); \
129 if(!(str = malloc(sz + 1))) return 0; \
130 sprintf(str, fmt, x); \
131 return str; \
132 }
134 MAKE_NUMSTR_FUNC(int, "%d")
135 MAKE_NUMSTR_FUNC(float, "%d")
137 #define ARGS_ARE_INT ((enum ts_value_type)42)
139 int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap)
140 {
141 if(count < 1) return -1;
142 if(count == 1) {
143 int num = va_arg(ap, int);
144 if(!(tsv->str = make_intstr(tsv->inum))) {
145 return -1;
146 }
148 tsv->type = TS_NUMBER;
149 tsv->inum = num;
150 tsv->fnum = (float)num;
151 return 0;
152 }
154 /* otherwise it's an array, let ts_set_valuefv_va handle it */
155 /* XXX: va_arg will need to be called with int instead of float. set a special
156 * value to the type field before calling this, to signify that.
157 */
158 tsv->type = ARGS_ARE_INT;
159 return ts_set_valuefv_va(tsv, count, ap);
160 }
162 int ts_set_valuei(struct ts_value *tsv, int inum)
163 {
164 return ts_set_valueiv(tsv, 1, inum);
165 }
168 int ts_set_valuefv(struct ts_value *tsv, int count, ...)
169 {
170 int res;
171 va_list ap;
172 va_start(ap, count);
173 res = ts_set_valuefv_va(tsv, count, ap);
174 va_end(ap);
175 return res;
176 }
178 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap)
179 {
180 int i;
182 if(count < 1) return -1;
183 if(count == 1) {
184 int num = va_arg(ap, int);
185 if(!(tsv->str = make_floatstr(tsv->inum))) {
186 return -1;
187 }
189 tsv->type = TS_NUMBER;
190 tsv->inum = num;
191 tsv->fnum = (float)num;
192 return 0;
193 }
195 /* otherwise it's an array, we need to create the ts_value array, and
196 * the simplified vector
197 */
198 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
199 return -1;
200 }
201 tsv->vec_size = count;
203 for(i=0; i<count; i++) {
204 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
205 tsv->vec[i] = (float)va_arg(ap, int);
206 } else {
207 tsv->vec[i] = va_arg(ap, double);
208 }
209 }
211 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
212 free(tsv->vec);
213 }
214 tsv->array_size = count;
216 for(i=0; i<count; i++) {
217 ts_init_value(tsv->array + i);
218 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
219 ts_set_valuei(tsv->array + i, (int)tsv->vec[i]);
220 } else {
221 ts_set_valuef(tsv->array + i, tsv->vec[i]);
222 }
223 }
225 tsv->type = TS_VECTOR;
226 return 0;
227 }
229 int ts_set_valuef(struct ts_value *tsv, int fnum)
230 {
231 return ts_set_valuefv(tsv, 1, fnum);
232 }
235 int ts_set_valuev(struct ts_value *tsv, int count, ...)
236 {
237 int res;
238 va_list ap;
239 va_start(ap, count);
240 res = ts_set_valuev_va(tsv, count, ap);
241 va_end(ap);
242 return res;
243 }
245 int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap)
246 {
247 int i;
249 if(count <= 1) return -1;
251 if((tsv->array = malloc(count * sizeof *tsv->array))) {
252 return -1;
253 }
254 tsv->array_size = count;
256 for(i=0; i<count; i++) {
257 struct ts_value *src = va_arg(ap, struct ts_value*);
258 ts_copy_value(tsv->array + i, src);
259 }
260 return 0;
261 }
264 /* ---- ts_attr implementation ---- */
266 int ts_init_attr(struct ts_attr *attr)
267 {
268 memset(attr, 0, sizeof *attr);
269 return ts_init_value(&attr->val);
270 }
272 void ts_destroy_attr(struct ts_attr *attr)
273 {
274 free(attr->name);
275 ts_destroy_value(&attr->val);
276 }
278 struct ts_attr *ts_alloc_attr(void)
279 {
280 struct ts_attr *attr = malloc(sizeof *attr);
281 if(!attr || ts_init_attr(attr) == -1) {
282 free(attr);
283 return 0;
284 }
285 return attr;
286 }
288 void ts_free_attr(struct ts_attr *attr)
289 {
290 ts_destroy_attr(attr);
291 free(attr);
292 }
294 int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src)
295 {
296 if(dest == src) return 0;
298 if(ts_set_attr_name(dest, src->name) == -1) {
299 return -1;
300 }
302 if(ts_copy_value(&dest->val, &src->val) == -1) {
303 ts_destroy_attr(dest);
304 return -1;
305 }
306 return 0;
307 }
309 int ts_set_attr_name(struct ts_attr *attr, const char *name)
310 {
311 char *n = malloc(strlen(name) + 1);
312 if(!n) return -1;
313 strcpy(n, name);
315 free(attr->name);
316 attr->name = n;
317 return 0;
318 }
321 /* ---- ts_node implementation ---- */
323 int ts_init_node(struct ts_node *node)
324 {
325 memset(node, 0, sizeof *node);
326 return 0;
327 }
329 void ts_destroy_node(struct ts_node *node)
330 {
331 free(node->name);
333 while(node->attr_list) {
334 struct ts_attr *attr = node->attr_list;
335 node->attr_list = node->attr_list->next;
336 ts_free_attr(attr);
337 }
338 }
340 struct ts_node *ts_alloc_node(void)
341 {
342 struct ts_node *node = malloc(sizeof *node);
343 if(!node || ts_init_node(node) == -1) {
344 free(node);
345 return 0;
346 }
347 return node;
348 }
350 void ts_free_node(struct ts_node *node)
351 {
352 ts_destroy_node(node);
353 free(node);
354 }
356 void ts_free_tree(struct ts_node *tree)
357 {
358 while(tree->child_list) {
359 struct ts_node *child = tree->child_list;
360 tree->child_list = tree->child_list->next;
361 ts_free_tree(child);
362 }
364 ts_free_node(tree);
365 }
367 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
368 {
369 attr->next = 0;
370 if(node->attr_list) {
371 node->attr_tail->next = attr;
372 node->attr_tail = attr;
373 } else {
374 node->attr_list = node->attr_tail = attr;
375 }
376 }
378 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
379 {
380 struct ts_attr *attr = node->attr_list;
381 while(attr) {
382 if(strcmp(attr->name, name) == 0) {
383 return attr;
384 }
385 attr = attr->next;
386 }
387 return 0;
388 }
390 void ts_add_child(struct ts_node *node, struct ts_node *child)
391 {
392 if(child->parent) {
393 if(child->parent == node) return;
394 ts_remove_child(child->parent, child);
395 }
396 child->parent = node;
397 child->next = 0;
399 if(node->child_list) {
400 node->child_tail->next = child;
401 node->child_tail = child;
402 } else {
403 node->child_list = node->child_tail = child;
404 }
405 }
407 int ts_remove_child(struct ts_node *node, struct ts_node *child)
408 {
409 struct ts_node dummy, *iter = &dummy;
410 dummy.next = node->child_list;
412 while(iter->next && iter->next != child) {
413 iter = iter->next;
414 }
415 if(!iter->next) {
416 return -1;
417 }
419 child->parent = 0;
421 iter->next = child->next;
422 if(!iter->next) {
423 node->child_tail = iter;
424 }
425 node->child_list = dummy.next;
426 return 0;
427 }
429 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
430 {
431 struct ts_node *res = node->child_list;
432 while(res) {
433 if(strcmp(res->name, name) == 0) {
434 return res;
435 }
436 res = res->next;
437 }
438 return 0;
439 }
441 struct ts_node *ts_load(const char *fname)
442 {
443 FILE *fp;
444 struct ts_node *root;
446 if(!(fp = fopen(fname, "rb"))) {
447 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
448 return 0;
449 }
451 root = ts_text_load(fp);
452 fclose(fp);
453 return root;
454 }
456 int ts_save(struct ts_node *tree, const char *fname)
457 {
458 FILE *fp;
459 int res;
461 if(!(fp = fopen(fname, "wb"))) {
462 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
463 return 0;
464 }
465 res = ts_text_save(tree, fp);
466 fclose(fp);
467 return res;
468 }