libtreestore

view src/treestore.c @ 5:f3ade599cfbb

ts_free*/ts_destroy* functions shouldn't bork when passed a null pointer
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 13 Nov 2016 20:40:07 +0200
parents bb873449cf59
children
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 }
96 struct val_list_node {
97 struct ts_value val;
98 struct val_list_node *next;
99 };
101 int ts_set_value(struct ts_value *tsv, const char *str)
102 {
103 char *endp;
105 if(tsv->str) {
106 ts_destroy_value(tsv);
107 if(ts_init_value(tsv) == -1) {
108 return -1;
109 }
110 }
112 tsv->type = TS_STRING;
113 if(!(tsv->str = malloc(strlen(str) + 1))) {
114 return -1;
115 }
116 strcpy(tsv->str, str);
118 /* try to parse the string and see if it fits any of the value types */
119 if(*str == '[' || *str == '{') {
120 /* try to parse as a vector */
121 struct val_list_node *list = 0, *tail = 0, *node;
122 int nelem = 0;
123 char endsym = *str++ + 2; /* ']' is '[' + 2 and '}' is '{' + 2 */
125 while(*str && *str != endsym) {
126 float val = strtod(str, &endp);
127 if(endp == str || !(node = malloc(sizeof *node))) {
128 break;
129 }
130 ts_init_value(&node->val);
131 ts_set_valuef(&node->val, val);
132 node->next = 0;
134 if(list) {
135 tail->next = node;
136 tail = node;
137 } else {
138 list = tail = node;
139 }
140 ++nelem;
141 str = endp;
142 }
144 if(nelem && (tsv->array = malloc(nelem * sizeof *tsv->array)) &&
145 (tsv->vec = malloc(nelem * sizeof *tsv->vec))) {
146 int idx = 0;
147 while(list) {
148 node = list;
149 list = list->next;
151 tsv->array[idx] = node->val;
152 tsv->vec[idx] = node->val.fnum;
153 ++idx;
154 free(node);
155 }
156 tsv->type = TS_VECTOR;
157 }
159 } else if((tsv->fnum = strtod(str, &endp)), endp != str) {
160 /* it's a number I guess... */
161 tsv->type = TS_NUMBER;
162 }
164 return 0;
165 }
167 int ts_set_valueiv(struct ts_value *tsv, int count, ...)
168 {
169 int res;
170 va_list ap;
171 va_start(ap, count);
172 res = ts_set_valueiv_va(tsv, count, ap);
173 va_end(ap);
174 return res;
175 }
177 #define MAKE_NUMSTR_FUNC(typestr, fmt) \
178 static char *make_##typestr##str(int x) \
179 { \
180 static char scrap[128]; \
181 char *str; \
182 int sz = snprintf(scrap, sizeof scrap, fmt, x); \
183 if(!(str = malloc(sz + 1))) return 0; \
184 sprintf(str, fmt, x); \
185 return str; \
186 }
188 MAKE_NUMSTR_FUNC(int, "%d")
189 MAKE_NUMSTR_FUNC(float, "%d")
191 #define ARGS_ARE_INT ((enum ts_value_type)42)
193 int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap)
194 {
195 if(count < 1) return -1;
196 if(count == 1) {
197 int num = va_arg(ap, int);
198 if(!(tsv->str = make_intstr(tsv->inum))) {
199 return -1;
200 }
202 tsv->type = TS_NUMBER;
203 tsv->inum = num;
204 tsv->fnum = (float)num;
205 return 0;
206 }
208 /* otherwise it's an array, let ts_set_valuefv_va handle it */
209 /* XXX: va_arg will need to be called with int instead of float. set a special
210 * value to the type field before calling this, to signify that.
211 */
212 tsv->type = ARGS_ARE_INT;
213 return ts_set_valuefv_va(tsv, count, ap);
214 }
216 int ts_set_valuei(struct ts_value *tsv, int inum)
217 {
218 return ts_set_valueiv(tsv, 1, inum);
219 }
222 int ts_set_valuefv(struct ts_value *tsv, int count, ...)
223 {
224 int res;
225 va_list ap;
226 va_start(ap, count);
227 res = ts_set_valuefv_va(tsv, count, ap);
228 va_end(ap);
229 return res;
230 }
232 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap)
233 {
234 int i;
236 if(count < 1) return -1;
237 if(count == 1) {
238 int num = va_arg(ap, int);
239 if(!(tsv->str = make_floatstr(tsv->inum))) {
240 return -1;
241 }
243 tsv->type = TS_NUMBER;
244 tsv->inum = num;
245 tsv->fnum = (float)num;
246 return 0;
247 }
249 /* otherwise it's an array, we need to create the ts_value array, and
250 * the simplified vector
251 */
252 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
253 return -1;
254 }
255 tsv->vec_size = count;
257 for(i=0; i<count; i++) {
258 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
259 tsv->vec[i] = (float)va_arg(ap, int);
260 } else {
261 tsv->vec[i] = va_arg(ap, double);
262 }
263 }
265 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
266 free(tsv->vec);
267 }
268 tsv->array_size = count;
270 for(i=0; i<count; i++) {
271 ts_init_value(tsv->array + i);
272 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
273 ts_set_valuei(tsv->array + i, (int)tsv->vec[i]);
274 } else {
275 ts_set_valuef(tsv->array + i, tsv->vec[i]);
276 }
277 }
279 tsv->type = TS_VECTOR;
280 return 0;
281 }
283 int ts_set_valuef(struct ts_value *tsv, float fnum)
284 {
285 return ts_set_valuefv(tsv, 1, fnum);
286 }
289 int ts_set_valuev(struct ts_value *tsv, int count, ...)
290 {
291 int res;
292 va_list ap;
293 va_start(ap, count);
294 res = ts_set_valuev_va(tsv, count, ap);
295 va_end(ap);
296 return res;
297 }
299 int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap)
300 {
301 int i;
303 if(count <= 1) return -1;
305 if((tsv->array = malloc(count * sizeof *tsv->array))) {
306 return -1;
307 }
308 tsv->array_size = count;
310 for(i=0; i<count; i++) {
311 struct ts_value *src = va_arg(ap, struct ts_value*);
312 ts_copy_value(tsv->array + i, src);
313 }
314 return 0;
315 }
318 /* ---- ts_attr implementation ---- */
320 int ts_init_attr(struct ts_attr *attr)
321 {
322 memset(attr, 0, sizeof *attr);
323 return ts_init_value(&attr->val);
324 }
326 void ts_destroy_attr(struct ts_attr *attr)
327 {
328 free(attr->name);
329 ts_destroy_value(&attr->val);
330 }
332 struct ts_attr *ts_alloc_attr(void)
333 {
334 struct ts_attr *attr = malloc(sizeof *attr);
335 if(!attr || ts_init_attr(attr) == -1) {
336 free(attr);
337 return 0;
338 }
339 return attr;
340 }
342 void ts_free_attr(struct ts_attr *attr)
343 {
344 ts_destroy_attr(attr);
345 free(attr);
346 }
348 int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src)
349 {
350 if(dest == src) return 0;
352 if(ts_set_attr_name(dest, src->name) == -1) {
353 return -1;
354 }
356 if(ts_copy_value(&dest->val, &src->val) == -1) {
357 ts_destroy_attr(dest);
358 return -1;
359 }
360 return 0;
361 }
363 int ts_set_attr_name(struct ts_attr *attr, const char *name)
364 {
365 char *n = malloc(strlen(name) + 1);
366 if(!n) return -1;
367 strcpy(n, name);
369 free(attr->name);
370 attr->name = n;
371 return 0;
372 }
375 /* ---- ts_node implementation ---- */
377 int ts_init_node(struct ts_node *node)
378 {
379 memset(node, 0, sizeof *node);
380 return 0;
381 }
383 void ts_destroy_node(struct ts_node *node)
384 {
385 if(!node) return;
387 free(node->name);
389 while(node->attr_list) {
390 struct ts_attr *attr = node->attr_list;
391 node->attr_list = node->attr_list->next;
392 ts_free_attr(attr);
393 }
394 }
396 struct ts_node *ts_alloc_node(void)
397 {
398 struct ts_node *node = malloc(sizeof *node);
399 if(!node || ts_init_node(node) == -1) {
400 free(node);
401 return 0;
402 }
403 return node;
404 }
406 void ts_free_node(struct ts_node *node)
407 {
408 ts_destroy_node(node);
409 free(node);
410 }
412 void ts_free_tree(struct ts_node *tree)
413 {
414 if(!tree) return;
416 while(tree->child_list) {
417 struct ts_node *child = tree->child_list;
418 tree->child_list = tree->child_list->next;
419 ts_free_tree(child);
420 }
422 ts_free_node(tree);
423 }
425 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
426 {
427 attr->next = 0;
428 if(node->attr_list) {
429 node->attr_tail->next = attr;
430 node->attr_tail = attr;
431 } else {
432 node->attr_list = node->attr_tail = attr;
433 }
434 }
436 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
437 {
438 struct ts_attr *attr = node->attr_list;
439 while(attr) {
440 if(strcmp(attr->name, name) == 0) {
441 return attr;
442 }
443 attr = attr->next;
444 }
445 return 0;
446 }
448 const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val)
449 {
450 struct ts_attr *attr = ts_get_attr(node, aname);
451 if(!attr || !attr->val.str) {
452 return def_val;
453 }
454 return attr->val.str;
455 }
457 float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val)
458 {
459 struct ts_attr *attr = ts_get_attr(node, aname);
460 if(!attr || attr->val.type != TS_NUMBER) {
461 return def_val;
462 }
463 return attr->val.fnum;
464 }
466 int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val)
467 {
468 struct ts_attr *attr = ts_get_attr(node, aname);
469 if(!attr || attr->val.type != TS_NUMBER) {
470 return def_val;
471 }
472 return attr->val.inum;
473 }
475 float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val)
476 {
477 struct ts_attr *attr = ts_get_attr(node, aname);
478 if(!attr || !attr->val.vec) {
479 return def_val;
480 }
481 return attr->val.vec;
482 }
484 struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val)
485 {
486 struct ts_attr *attr = ts_get_attr(node, aname);
487 if(!attr || !attr->val.array) {
488 return def_val;
489 }
490 return attr->val.array;
491 }
493 void ts_add_child(struct ts_node *node, struct ts_node *child)
494 {
495 if(child->parent) {
496 if(child->parent == node) return;
497 ts_remove_child(child->parent, child);
498 }
499 child->parent = node;
500 child->next = 0;
502 if(node->child_list) {
503 node->child_tail->next = child;
504 node->child_tail = child;
505 } else {
506 node->child_list = node->child_tail = child;
507 }
508 }
510 int ts_remove_child(struct ts_node *node, struct ts_node *child)
511 {
512 struct ts_node dummy, *iter = &dummy;
513 dummy.next = node->child_list;
515 while(iter->next && iter->next != child) {
516 iter = iter->next;
517 }
518 if(!iter->next) {
519 return -1;
520 }
522 child->parent = 0;
524 iter->next = child->next;
525 if(!iter->next) {
526 node->child_tail = iter;
527 }
528 node->child_list = dummy.next;
529 return 0;
530 }
532 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
533 {
534 struct ts_node *res = node->child_list;
535 while(res) {
536 if(strcmp(res->name, name) == 0) {
537 return res;
538 }
539 res = res->next;
540 }
541 return 0;
542 }
544 struct ts_node *ts_load(const char *fname)
545 {
546 FILE *fp;
547 struct ts_node *root;
549 if(!(fp = fopen(fname, "rb"))) {
550 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
551 return 0;
552 }
554 root = ts_text_load(fp);
555 fclose(fp);
556 return root;
557 }
559 int ts_save(struct ts_node *tree, const char *fname)
560 {
561 FILE *fp;
562 int res;
564 if(!(fp = fopen(fname, "wb"))) {
565 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
566 return 0;
567 }
568 res = ts_text_save(tree, fp);
569 fclose(fp);
570 return res;
571 }