options/config
[demo_prior] / libs / treestore / src / treestore.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6 #include "treestore.h"
7
8 #ifdef WIN32
9 #include <malloc.h>
10 #else
11 #ifndef __FreeBSD__
12 #include <alloca.h>
13 #endif
14 #endif
15
16 struct ts_node *ts_text_load(struct ts_io *io);
17 int ts_text_save(struct ts_node *tree, struct ts_io *io);
18
19 static long io_read(void *buf, size_t bytes, void *uptr);
20 static long io_write(const void *buf, size_t bytes, void *uptr);
21
22
23 /* ---- ts_value implementation ---- */
24
25 int ts_init_value(struct ts_value *tsv)
26 {
27         memset(tsv, 0, sizeof *tsv);
28         return 0;
29 }
30
31 void ts_destroy_value(struct ts_value *tsv)
32 {
33         int i;
34
35         free(tsv->str);
36         free(tsv->vec);
37
38         for(i=0; i<tsv->array_size; i++) {
39                 ts_destroy_value(tsv->array + i);
40         }
41         free(tsv->array);
42 }
43
44
45 struct ts_value *ts_alloc_value(void)
46 {
47         struct ts_value *v = malloc(sizeof *v);
48         if(!v || ts_init_value(v) == -1) {
49                 free(v);
50                 return 0;
51         }
52         return v;
53 }
54
55 void ts_free_value(struct ts_value *tsv)
56 {
57         ts_destroy_value(tsv);
58         free(tsv);
59 }
60
61
62 int ts_copy_value(struct ts_value *dest, struct ts_value *src)
63 {
64         int i;
65
66         if(dest == src) return 0;
67
68         *dest = *src;
69
70         dest->str = 0;
71         dest->vec = 0;
72         dest->array = 0;
73
74         if(src->str) {
75                 if(!(dest->str = malloc(strlen(src->str) + 1))) {
76                         goto fail;
77                 }
78                 strcpy(dest->str, src->str);
79         }
80         if(src->vec && src->vec_size > 0) {
81                 if(!(dest->vec = malloc(src->vec_size * sizeof *src->vec))) {
82                         goto fail;
83                 }
84                 memcpy(dest->vec, src->vec, src->vec_size * sizeof *src->vec);
85         }
86         if(src->array && src->array_size > 0) {
87                 if(!(dest->array = calloc(src->array_size, sizeof *src->array))) {
88                         goto fail;
89                 }
90                 for(i=0; i<src->array_size; i++) {
91                         if(ts_copy_value(dest->array + i, src->array + i) == -1) {
92                                 goto fail;
93                         }
94                 }
95         }
96         return 0;
97
98 fail:
99         free(dest->str);
100         free(dest->vec);
101         if(dest->array) {
102                 for(i=0; i<dest->array_size; i++) {
103                         ts_destroy_value(dest->array + i);
104                 }
105                 free(dest->array);
106         }
107         return -1;
108 }
109
110 #define MAKE_NUMSTR_FUNC(type, fmt) \
111         static char *make_##type##str(type x) \
112         { \
113                 static char scrap[128]; \
114                 char *str; \
115                 int sz = snprintf(scrap, sizeof scrap, fmt, x); \
116                 if(!(str = malloc(sz + 1))) return 0; \
117                 sprintf(str, fmt, x); \
118                 return str; \
119         }
120
121 MAKE_NUMSTR_FUNC(int, "%d")
122 MAKE_NUMSTR_FUNC(float, "%g")
123
124
125 struct val_list_node {
126         struct ts_value val;
127         struct val_list_node *next;
128 };
129
130 int ts_set_value_str(struct ts_value *tsv, const char *str)
131 {
132         if(tsv->str) {
133                 ts_destroy_value(tsv);
134                 if(ts_init_value(tsv) == -1) {
135                         return -1;
136                 }
137         }
138
139         tsv->type = TS_STRING;
140         if(!(tsv->str = malloc(strlen(str) + 1))) {
141                 return -1;
142         }
143         strcpy(tsv->str, str);
144
145 #if 0
146         /* try to parse the string and see if it fits any of the value types */
147         if(*str == '[' || *str == '{') {
148                 /* try to parse as a vector */
149                 struct val_list_node *list = 0, *tail = 0, *node;
150                 int nelem = 0;
151                 char endsym = *str++ + 2;       /* ']' is '[' + 2 and '}' is '{' + 2 */
152
153                 while(*str && *str != endsym) {
154                         float val = strtod(str, &endp);
155                         if(endp == str || !(node = malloc(sizeof *node))) {
156                                 break;
157                         }
158                         ts_init_value(&node->val);
159                         ts_set_valuef(&node->val, val);
160                         node->next = 0;
161
162                         if(list) {
163                                 tail->next = node;
164                                 tail = node;
165                         } else {
166                                 list = tail = node;
167                         }
168                         ++nelem;
169                         str = endp;
170                 }
171
172                 if(nelem && (tsv->array = malloc(nelem * sizeof *tsv->array)) &&
173                                 (tsv->vec = malloc(nelem * sizeof *tsv->vec))) {
174                         int idx = 0;
175                         while(list) {
176                                 node = list;
177                                 list = list->next;
178
179                                 tsv->array[idx] = node->val;
180                                 tsv->vec[idx] = node->val.fnum;
181                                 ++idx;
182                                 free(node);
183                         }
184                         tsv->type = TS_VECTOR;
185                 }
186
187         } else if((tsv->fnum = strtod(str, &endp)), endp != str) {
188                 /* it's a number I guess... */
189                 tsv->type = TS_NUMBER;
190         }
191 #endif
192
193         return 0;
194 }
195
196 int ts_set_valuei_arr(struct ts_value *tsv, int count, const int *arr)
197 {
198         int i;
199
200         if(count < 1) return -1;
201         if(count == 1) {
202                 if(!(tsv->str = make_intstr(*arr))) {
203                         return -1;
204                 }
205
206                 tsv->type = TS_NUMBER;
207                 tsv->fnum = (float)*arr;
208                 tsv->inum = *arr;
209                 return 0;
210         }
211
212         /* otherwise it's an array, we need to create the ts_value array, and
213          * the simplified vector
214          */
215         if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
216                 return -1;
217         }
218         tsv->vec_size = count;
219
220         for(i=0; i<count; i++) {
221                 tsv->vec[i] = arr[i];
222         }
223
224         if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
225                 free(tsv->vec);
226         }
227         tsv->array_size = count;
228
229         for(i=0; i<count; i++) {
230                 ts_init_value(tsv->array + i);
231                 ts_set_valuef(tsv->array + i, arr[i]);
232         }
233
234         tsv->type = TS_VECTOR;
235         return 0;
236 }
237
238 int ts_set_valueiv(struct ts_value *tsv, int count, ...)
239 {
240         int res;
241         va_list ap;
242         va_start(ap, count);
243         res = ts_set_valueiv_va(tsv, count, ap);
244         va_end(ap);
245         return res;
246 }
247
248 int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap)
249 {
250         int i, *vec;
251
252         if(count < 1) return -1;
253         if(count == 1) {
254                 int num = va_arg(ap, int);
255                 ts_set_valuei(tsv, num);
256                 return 0;
257         }
258
259         vec = alloca(count * sizeof *vec);
260         for(i=0; i<count; i++) {
261                 vec[i] = va_arg(ap, int);
262         }
263         return ts_set_valuei_arr(tsv, count, vec);
264 }
265
266 int ts_set_valuei(struct ts_value *tsv, int inum)
267 {
268         return ts_set_valuei_arr(tsv, 1, &inum);
269 }
270
271 int ts_set_valuef_arr(struct ts_value *tsv, int count, const float *arr)
272 {
273         int i;
274
275         if(count < 1) return -1;
276         if(count == 1) {
277                 if(!(tsv->str = make_floatstr(*arr))) {
278                         return -1;
279                 }
280
281                 tsv->type = TS_NUMBER;
282                 tsv->fnum = *arr;
283                 tsv->inum = (int)*arr;
284                 return 0;
285         }
286
287         /* otherwise it's an array, we need to create the ts_value array, and
288          * the simplified vector
289          */
290         if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
291                 return -1;
292         }
293         tsv->vec_size = count;
294
295         for(i=0; i<count; i++) {
296                 tsv->vec[i] = arr[i];
297         }
298
299         if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
300                 free(tsv->vec);
301         }
302         tsv->array_size = count;
303
304         for(i=0; i<count; i++) {
305                 ts_init_value(tsv->array + i);
306                 ts_set_valuef(tsv->array + i, arr[i]);
307         }
308
309         tsv->type = TS_VECTOR;
310         return 0;
311 }
312
313 int ts_set_valuefv(struct ts_value *tsv, int count, ...)
314 {
315         int res;
316         va_list ap;
317         va_start(ap, count);
318         res = ts_set_valuefv_va(tsv, count, ap);
319         va_end(ap);
320         return res;
321 }
322
323 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap)
324 {
325         int i;
326         float *vec;
327
328         if(count < 1) return -1;
329         if(count == 1) {
330                 float num = va_arg(ap, double);
331                 ts_set_valuef(tsv, num);
332                 return 0;
333         }
334
335         vec = alloca(count * sizeof *vec);
336         for(i=0; i<count; i++) {
337                 vec[i] = va_arg(ap, double);
338         }
339         return ts_set_valuef_arr(tsv, count, vec);
340 }
341
342 int ts_set_valuef(struct ts_value *tsv, float fnum)
343 {
344         return ts_set_valuef_arr(tsv, 1, &fnum);
345 }
346
347 int ts_set_value_arr(struct ts_value *tsv, int count, const struct ts_value *arr)
348 {
349         int i, allnum = 1;
350
351         if(count <= 1) return -1;
352
353         if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
354                 return -1;
355         }
356         tsv->array_size = count;
357
358         for(i=0; i<count; i++) {
359                 if(arr[i].type != TS_NUMBER) {
360                         allnum = 0;
361                 }
362                 if(ts_copy_value(tsv->array + i, (struct ts_value*)arr + i) == -1) {
363                         while(--i >= 0) {
364                                 ts_destroy_value(tsv->array + i);
365                         }
366                         free(tsv->array);
367                         tsv->array = 0;
368                         return -1;
369                 }
370         }
371
372         if(allnum) {
373                 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
374                         ts_destroy_value(tsv);
375                         return -1;
376                 }
377                 tsv->type = TS_VECTOR;
378                 tsv->vec_size = count;
379
380                 for(i=0; i<count; i++) {
381                         tsv->vec[i] = tsv->array[i].fnum;
382                 }
383         } else {
384                 tsv->type = TS_ARRAY;
385         }
386         return 0;
387 }
388
389 int ts_set_valuev(struct ts_value *tsv, int count, ...)
390 {
391         int res;
392         va_list ap;
393         va_start(ap, count);
394         res = ts_set_valuev_va(tsv, count, ap);
395         va_end(ap);
396         return res;
397 }
398
399 int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap)
400 {
401         int i;
402
403         if(count <= 1) return -1;
404
405         if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
406                 return -1;
407         }
408         tsv->array_size = count;
409
410         for(i=0; i<count; i++) {
411                 struct ts_value *src = va_arg(ap, struct ts_value*);
412                 if(ts_copy_value(tsv->array + i, src) == -1) {
413                         while(--i >= 0) {
414                                 ts_destroy_value(tsv->array + i);
415                         }
416                         free(tsv->array);
417                         tsv->array = 0;
418                         return -1;
419                 }
420         }
421         return 0;
422 }
423
424
425 /* ---- ts_attr implementation ---- */
426
427 int ts_init_attr(struct ts_attr *attr)
428 {
429         memset(attr, 0, sizeof *attr);
430         return ts_init_value(&attr->val);
431 }
432
433 void ts_destroy_attr(struct ts_attr *attr)
434 {
435         free(attr->name);
436         ts_destroy_value(&attr->val);
437 }
438
439 struct ts_attr *ts_alloc_attr(void)
440 {
441         struct ts_attr *attr = malloc(sizeof *attr);
442         if(!attr || ts_init_attr(attr) == -1) {
443                 free(attr);
444                 return 0;
445         }
446         return attr;
447 }
448
449 void ts_free_attr(struct ts_attr *attr)
450 {
451         ts_destroy_attr(attr);
452         free(attr);
453 }
454
455 int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src)
456 {
457         if(dest == src) return 0;
458
459         if(ts_set_attr_name(dest, src->name) == -1) {
460                 return -1;
461         }
462
463         if(ts_copy_value(&dest->val, &src->val) == -1) {
464                 ts_destroy_attr(dest);
465                 return -1;
466         }
467         return 0;
468 }
469
470 int ts_set_attr_name(struct ts_attr *attr, const char *name)
471 {
472         char *n = malloc(strlen(name) + 1);
473         if(!n) return -1;
474         strcpy(n, name);
475
476         free(attr->name);
477         attr->name = n;
478         return 0;
479 }
480
481
482 /* ---- ts_node implementation ---- */
483
484 int ts_init_node(struct ts_node *node)
485 {
486         memset(node, 0, sizeof *node);
487         return 0;
488 }
489
490 void ts_destroy_node(struct ts_node *node)
491 {
492         if(!node) return;
493
494         free(node->name);
495
496         while(node->attr_list) {
497                 struct ts_attr *attr = node->attr_list;
498                 node->attr_list = node->attr_list->next;
499                 ts_free_attr(attr);
500         }
501 }
502
503 struct ts_node *ts_alloc_node(void)
504 {
505         struct ts_node *node = malloc(sizeof *node);
506         if(!node || ts_init_node(node) == -1) {
507                 free(node);
508                 return 0;
509         }
510         return node;
511 }
512
513 void ts_free_node(struct ts_node *node)
514 {
515         ts_destroy_node(node);
516         free(node);
517 }
518
519 void ts_free_tree(struct ts_node *tree)
520 {
521         if(!tree) return;
522
523         while(tree->child_list) {
524                 struct ts_node *child = tree->child_list;
525                 tree->child_list = tree->child_list->next;
526                 ts_free_tree(child);
527         }
528
529         ts_free_node(tree);
530 }
531
532 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
533 {
534         if(attr->node) {
535                 if(attr->node == node) return;
536                 ts_remove_attr(attr->node, attr);
537         }
538         attr->node = node;
539
540         attr->next = 0;
541         if(node->attr_list) {
542                 node->attr_tail->next = attr;
543                 node->attr_tail = attr;
544         } else {
545                 node->attr_list = node->attr_tail = attr;
546         }
547         node->attr_count++;
548 }
549
550 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
551 {
552         struct ts_attr *attr = node->attr_list;
553         while(attr) {
554                 if(strcmp(attr->name, name) == 0) {
555                         return attr;
556                 }
557                 attr = attr->next;
558         }
559         return 0;
560 }
561
562 int ts_remove_attr(struct ts_node *node, struct ts_attr *attr)
563 {
564         struct ts_attr dummy, *iter = &dummy;
565         dummy.next = node->attr_list;
566
567         while(iter->next && iter->next != attr) {
568                 iter = iter->next;
569         }
570         if(!iter->next) {
571                 return -1;
572         }
573
574         attr->node = 0;
575
576         iter->next = attr->next;
577         if(!iter->next) {
578                 node->attr_tail = iter;
579         }
580         node->attr_list = dummy.next;
581         node->attr_count--;
582         assert(node->attr_count >= 0);
583         return 0;
584 }
585
586 const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val)
587 {
588         struct ts_attr *attr = ts_get_attr(node, aname);
589         if(!attr || !attr->val.str) {
590                 return def_val;
591         }
592         return attr->val.str;
593 }
594
595 float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val)
596 {
597         struct ts_attr *attr = ts_get_attr(node, aname);
598         if(!attr || attr->val.type != TS_NUMBER) {
599                 return def_val;
600         }
601         return attr->val.fnum;
602 }
603
604 int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val)
605 {
606         struct ts_attr *attr = ts_get_attr(node, aname);
607         if(!attr || attr->val.type != TS_NUMBER) {
608                 return def_val;
609         }
610         return attr->val.inum;
611 }
612
613 float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val)
614 {
615         struct ts_attr *attr = ts_get_attr(node, aname);
616         if(!attr || !attr->val.vec) {
617                 return def_val;
618         }
619         return attr->val.vec;
620 }
621
622 struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val)
623 {
624         struct ts_attr *attr = ts_get_attr(node, aname);
625         if(!attr || !attr->val.array) {
626                 return def_val;
627         }
628         return attr->val.array;
629 }
630
631 void ts_add_child(struct ts_node *node, struct ts_node *child)
632 {
633         if(child->parent) {
634                 if(child->parent == node) return;
635                 ts_remove_child(child->parent, child);
636         }
637         child->parent = node;
638         child->next = 0;
639
640         if(node->child_list) {
641                 node->child_tail->next = child;
642                 node->child_tail = child;
643         } else {
644                 node->child_list = node->child_tail = child;
645         }
646         node->child_count++;
647 }
648
649 int ts_remove_child(struct ts_node *node, struct ts_node *child)
650 {
651         struct ts_node dummy, *iter = &dummy;
652         dummy.next = node->child_list;
653
654         while(iter->next && iter->next != child) {
655                 iter = iter->next;
656         }
657         if(!iter->next) {
658                 return -1;
659         }
660
661         child->parent = 0;
662
663         iter->next = child->next;
664         if(!iter->next) {
665                 node->child_tail = iter;
666         }
667         node->child_list = dummy.next;
668         node->child_count--;
669         assert(node->child_count >= 0);
670         return 0;
671 }
672
673 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
674 {
675         struct ts_node *res = node->child_list;
676         while(res) {
677                 if(strcmp(res->name, name) == 0) {
678                         return res;
679                 }
680                 res = res->next;
681         }
682         return 0;
683 }
684
685 struct ts_node *ts_load(const char *fname)
686 {
687         FILE *fp;
688         struct ts_node *root;
689
690         if(!(fp = fopen(fname, "rb"))) {
691                 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
692                 return 0;
693         }
694
695         root = ts_load_file(fp);
696         fclose(fp);
697         return root;
698 }
699
700 struct ts_node *ts_load_file(FILE *fp)
701 {
702         struct ts_io io = {0};
703         io.data = fp;
704         io.read = io_read;
705
706         return ts_load_io(&io);
707 }
708
709 struct ts_node *ts_load_io(struct ts_io *io)
710 {
711         return ts_text_load(io);
712 }
713
714 int ts_save(struct ts_node *tree, const char *fname)
715 {
716         FILE *fp;
717         int res;
718
719         if(!(fp = fopen(fname, "wb"))) {
720                 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
721                 return 0;
722         }
723         res = ts_save_file(tree, fp);
724         fclose(fp);
725         return res;
726 }
727
728 int ts_save_file(struct ts_node *tree, FILE *fp)
729 {
730         struct ts_io io = {0};
731         io.data = fp;
732         io.write = io_write;
733
734         return ts_save_io(tree, &io);
735 }
736
737 int ts_save_io(struct ts_node *tree, struct ts_io *io)
738 {
739         return ts_text_save(tree, io);
740 }
741
742 static const char *pathtok(const char *path, char *tok)
743 {
744         int len;
745         const char *dot = strchr(path, '.');
746         if(!dot) {
747                 strcpy(tok, path);
748                 return 0;
749         }
750
751         len = dot - path;
752         memcpy(tok, path, len);
753         tok[len] = 0;
754         return dot + 1;
755 }
756
757 struct ts_attr *ts_lookup(struct ts_node *node, const char *path)
758 {
759         char *name = alloca(strlen(path) + 1);
760
761         if(!node) return 0;
762
763         if(!(path = pathtok(path, name)) || strcmp(name, node->name) != 0) {
764                 return 0;
765         }
766
767         while((path = pathtok(path, name)) && (node = ts_get_child(node, name)));
768
769         if(path || !node) return 0;
770         return ts_get_attr(node, name);
771 }
772
773 const char *ts_lookup_str(struct ts_node *root, const char *path, const char *def_val)
774 {
775         struct ts_attr *attr = ts_lookup(root, path);
776         if(!attr || !attr->val.str) {
777                 return def_val;
778         }
779         return attr->val.str;
780 }
781
782 float ts_lookup_num(struct ts_node *root, const char *path, float def_val)
783 {
784         struct ts_attr *attr = ts_lookup(root, path);
785         if(!attr || attr->val.type != TS_NUMBER) {
786                 return def_val;
787         }
788         return attr->val.fnum;
789 }
790
791 int ts_lookup_int(struct ts_node *root, const char *path, int def_val)
792 {
793         struct ts_attr *attr = ts_lookup(root, path);
794         if(!attr || attr->val.type != TS_NUMBER) {
795                 return def_val;
796         }
797         return attr->val.inum;
798 }
799
800 float *ts_lookup_vec(struct ts_node *root, const char *path, float *def_val)
801 {
802         struct ts_attr *attr = ts_lookup(root, path);
803         if(!attr || !attr->val.vec) {
804                 return def_val;
805         }
806         return attr->val.vec;
807 }
808
809 struct ts_value *ts_lookup_array(struct ts_node *node, const char *path, struct ts_value *def_val)
810 {
811         struct ts_attr *attr = ts_lookup(node, path);
812         if(!attr || !attr->val.array) {
813                 return def_val;
814         }
815         return attr->val.array;
816 }
817
818 static long io_read(void *buf, size_t bytes, void *uptr)
819 {
820         size_t sz = fread(buf, 1, bytes, uptr);
821         if(sz < bytes && errno) return -1;
822         return sz;
823 }
824
825 static long io_write(const void *buf, size_t bytes, void *uptr)
826 {
827         size_t sz = fwrite(buf, 1, bytes, uptr);
828         if(sz < bytes && errno) return -1;
829         return sz;
830 }