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