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