14 struct ts_node *ts_text_load(struct ts_io *io);
15 int ts_text_save(struct ts_node *tree, struct ts_io *io);
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);
21 /* ---- ts_value implementation ---- */
23 int ts_init_value(struct ts_value *tsv)
25 memset(tsv, 0, sizeof *tsv);
29 void ts_destroy_value(struct ts_value *tsv)
36 for(i=0; i<tsv->array_size; i++) {
37 ts_destroy_value(tsv->array + i);
43 struct ts_value *ts_alloc_value(void)
45 struct ts_value *v = malloc(sizeof *v);
46 if(!v || ts_init_value(v) == -1) {
53 void ts_free_value(struct ts_value *tsv)
55 ts_destroy_value(tsv);
60 int ts_copy_value(struct ts_value *dest, struct ts_value *src)
64 if(dest == src) return 0;
73 if(!(dest->str = malloc(strlen(src->str) + 1))) {
76 strcpy(dest->str, src->str);
78 if(src->vec && src->vec_size > 0) {
79 if(!(dest->vec = malloc(src->vec_size * sizeof *src->vec))) {
82 memcpy(dest->vec, src->vec, src->vec_size * sizeof *src->vec);
84 if(src->array && src->array_size > 0) {
85 if(!(dest->array = calloc(src->array_size, sizeof *src->array))) {
88 for(i=0; i<src->array_size; i++) {
89 if(ts_copy_value(dest->array + i, src->array + i) == -1) {
100 for(i=0; i<dest->array_size; i++) {
101 ts_destroy_value(dest->array + i);
108 #define MAKE_NUMSTR_FUNC(type, fmt) \
109 static char *make_##type##str(type x) \
111 static char scrap[128]; \
113 int sz = snprintf(scrap, sizeof scrap, fmt, x); \
114 if(!(str = malloc(sz + 1))) return 0; \
115 sprintf(str, fmt, x); \
119 MAKE_NUMSTR_FUNC(int, "%d")
120 MAKE_NUMSTR_FUNC(float, "%g")
123 struct val_list_node {
125 struct val_list_node *next;
128 int ts_set_value_str(struct ts_value *tsv, const char *str)
131 ts_destroy_value(tsv);
132 if(ts_init_value(tsv) == -1) {
137 tsv->type = TS_STRING;
138 if(!(tsv->str = malloc(strlen(str) + 1))) {
141 strcpy(tsv->str, str);
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;
149 char endsym = *str++ + 2; /* ']' is '[' + 2 and '}' is '{' + 2 */
151 while(*str && *str != endsym) {
152 float val = strtod(str, &endp);
153 if(endp == str || !(node = malloc(sizeof *node))) {
156 ts_init_value(&node->val);
157 ts_set_valuef(&node->val, val);
170 if(nelem && (tsv->array = malloc(nelem * sizeof *tsv->array)) &&
171 (tsv->vec = malloc(nelem * sizeof *tsv->vec))) {
177 tsv->array[idx] = node->val;
178 tsv->vec[idx] = node->val.fnum;
182 tsv->type = TS_VECTOR;
185 } else if((tsv->fnum = strtod(str, &endp)), endp != str) {
186 /* it's a number I guess... */
187 tsv->type = TS_NUMBER;
194 int ts_set_valuei_arr(struct ts_value *tsv, int count, const int *arr)
198 if(count < 1) return -1;
200 if(!(tsv->str = make_intstr(*arr))) {
204 tsv->type = TS_NUMBER;
205 tsv->fnum = (float)*arr;
210 /* otherwise it's an array, we need to create the ts_value array, and
211 * the simplified vector
213 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
216 tsv->vec_size = count;
218 for(i=0; i<count; i++) {
219 tsv->vec[i] = arr[i];
222 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
225 tsv->array_size = count;
227 for(i=0; i<count; i++) {
228 ts_init_value(tsv->array + i);
229 ts_set_valuef(tsv->array + i, arr[i]);
232 tsv->type = TS_VECTOR;
236 int ts_set_valueiv(struct ts_value *tsv, int count, ...)
241 res = ts_set_valueiv_va(tsv, count, ap);
246 int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap)
250 if(count < 1) return -1;
252 int num = va_arg(ap, int);
253 ts_set_valuei(tsv, num);
257 vec = alloca(count * sizeof *vec);
258 for(i=0; i<count; i++) {
259 vec[i] = va_arg(ap, int);
261 return ts_set_valuei_arr(tsv, count, vec);
264 int ts_set_valuei(struct ts_value *tsv, int inum)
266 return ts_set_valuei_arr(tsv, 1, &inum);
269 int ts_set_valuef_arr(struct ts_value *tsv, int count, const float *arr)
273 if(count < 1) return -1;
275 if(!(tsv->str = make_floatstr(*arr))) {
279 tsv->type = TS_NUMBER;
281 tsv->inum = (int)*arr;
285 /* otherwise it's an array, we need to create the ts_value array, and
286 * the simplified vector
288 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
291 tsv->vec_size = count;
293 for(i=0; i<count; i++) {
294 tsv->vec[i] = arr[i];
297 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
300 tsv->array_size = count;
302 for(i=0; i<count; i++) {
303 ts_init_value(tsv->array + i);
304 ts_set_valuef(tsv->array + i, arr[i]);
307 tsv->type = TS_VECTOR;
311 int ts_set_valuefv(struct ts_value *tsv, int count, ...)
316 res = ts_set_valuefv_va(tsv, count, ap);
321 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap)
326 if(count < 1) return -1;
328 float num = va_arg(ap, double);
329 ts_set_valuef(tsv, num);
333 vec = alloca(count * sizeof *vec);
334 for(i=0; i<count; i++) {
335 vec[i] = va_arg(ap, double);
337 return ts_set_valuef_arr(tsv, count, vec);
340 int ts_set_valuef(struct ts_value *tsv, float fnum)
342 return ts_set_valuef_arr(tsv, 1, &fnum);
345 int ts_set_value_arr(struct ts_value *tsv, int count, const struct ts_value *arr)
349 if(count <= 1) return -1;
351 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
354 tsv->array_size = count;
356 for(i=0; i<count; i++) {
357 if(arr[i].type != TS_NUMBER) {
360 if(ts_copy_value(tsv->array + i, (struct ts_value*)arr + i) == -1) {
362 ts_destroy_value(tsv->array + i);
371 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
372 ts_destroy_value(tsv);
375 tsv->type = TS_VECTOR;
376 tsv->vec_size = count;
378 for(i=0; i<count; i++) {
379 tsv->vec[i] = tsv->array[i].fnum;
382 tsv->type = TS_ARRAY;
387 int ts_set_valuev(struct ts_value *tsv, int count, ...)
392 res = ts_set_valuev_va(tsv, count, ap);
397 int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap)
401 if(count <= 1) return -1;
403 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
406 tsv->array_size = count;
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) {
412 ts_destroy_value(tsv->array + i);
423 /* ---- ts_attr implementation ---- */
425 int ts_init_attr(struct ts_attr *attr)
427 memset(attr, 0, sizeof *attr);
428 return ts_init_value(&attr->val);
431 void ts_destroy_attr(struct ts_attr *attr)
434 ts_destroy_value(&attr->val);
437 struct ts_attr *ts_alloc_attr(void)
439 struct ts_attr *attr = malloc(sizeof *attr);
440 if(!attr || ts_init_attr(attr) == -1) {
447 void ts_free_attr(struct ts_attr *attr)
449 ts_destroy_attr(attr);
453 int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src)
455 if(dest == src) return 0;
457 if(ts_set_attr_name(dest, src->name) == -1) {
461 if(ts_copy_value(&dest->val, &src->val) == -1) {
462 ts_destroy_attr(dest);
468 int ts_set_attr_name(struct ts_attr *attr, const char *name)
470 char *n = malloc(strlen(name) + 1);
480 /* ---- ts_node implementation ---- */
482 int ts_init_node(struct ts_node *node)
484 memset(node, 0, sizeof *node);
488 void ts_destroy_node(struct ts_node *node)
494 while(node->attr_list) {
495 struct ts_attr *attr = node->attr_list;
496 node->attr_list = node->attr_list->next;
501 struct ts_node *ts_alloc_node(void)
503 struct ts_node *node = malloc(sizeof *node);
504 if(!node || ts_init_node(node) == -1) {
511 void ts_free_node(struct ts_node *node)
513 ts_destroy_node(node);
517 void ts_free_tree(struct ts_node *tree)
521 while(tree->child_list) {
522 struct ts_node *child = tree->child_list;
523 tree->child_list = tree->child_list->next;
530 int ts_set_node_name(struct ts_node *node, const char *name)
532 char *n = malloc(strlen(name) + 1);
541 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
544 if(node->attr_list) {
545 node->attr_tail->next = attr;
546 node->attr_tail = attr;
548 node->attr_list = node->attr_tail = attr;
553 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
555 struct ts_attr *attr = node->attr_list;
557 if(strcmp(attr->name, name) == 0) {
565 const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val)
567 struct ts_attr *attr = ts_get_attr(node, aname);
568 if(!attr || !attr->val.str) {
571 return attr->val.str;
574 float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val)
576 struct ts_attr *attr = ts_get_attr(node, aname);
577 if(!attr || attr->val.type != TS_NUMBER) {
580 return attr->val.fnum;
583 int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val)
585 struct ts_attr *attr = ts_get_attr(node, aname);
586 if(!attr || attr->val.type != TS_NUMBER) {
589 return attr->val.inum;
592 float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val)
594 struct ts_attr *attr = ts_get_attr(node, aname);
595 if(!attr || !attr->val.vec) {
598 return attr->val.vec;
601 struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val)
603 struct ts_attr *attr = ts_get_attr(node, aname);
604 if(!attr || !attr->val.array) {
607 return attr->val.array;
610 void ts_add_child(struct ts_node *node, struct ts_node *child)
613 if(child->parent == node) return;
614 ts_remove_child(child->parent, child);
616 child->parent = node;
619 if(node->child_list) {
620 node->child_tail->next = child;
621 node->child_tail = child;
623 node->child_list = node->child_tail = child;
628 int ts_remove_child(struct ts_node *node, struct ts_node *child)
630 struct ts_node dummy, *iter = &dummy;
631 dummy.next = node->child_list;
633 while(iter->next && iter->next != child) {
642 iter->next = child->next;
644 node->child_tail = iter;
646 node->child_list = dummy.next;
648 assert(node->child_count >= 0);
652 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
654 struct ts_node *res = node->child_list;
656 if(strcmp(res->name, name) == 0) {
664 struct ts_node *ts_load(const char *fname)
667 struct ts_node *root;
669 if(!(fp = fopen(fname, "rb"))) {
670 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
674 root = ts_load_file(fp);
679 struct ts_node *ts_load_file(FILE *fp)
681 struct ts_io io = {0};
685 return ts_load_io(&io);
688 struct ts_node *ts_load_io(struct ts_io *io)
690 return ts_text_load(io);
693 int ts_save(struct ts_node *tree, const char *fname)
698 if(!(fp = fopen(fname, "wb"))) {
699 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
702 res = ts_save_file(tree, fp);
707 int ts_save_file(struct ts_node *tree, FILE *fp)
709 struct ts_io io = {0};
713 return ts_save_io(tree, &io);
716 int ts_save_io(struct ts_node *tree, struct ts_io *io)
718 return ts_text_save(tree, io);
721 static const char *pathtok(const char *path, char *tok)
724 const char *dot = strchr(path, '.');
731 memcpy(tok, path, len);
736 struct ts_attr *ts_lookup(struct ts_node *node, const char *path)
738 char *name = alloca(strlen(path) + 1);
742 if(!(path = pathtok(path, name)) || strcmp(name, node->name) != 0) {
746 while((path = pathtok(path, name)) && (node = ts_get_child(node, name)));
748 if(path || !node) return 0;
749 return ts_get_attr(node, name);
752 const char *ts_lookup_str(struct ts_node *root, const char *path, const char *def_val)
754 struct ts_attr *attr = ts_lookup(root, path);
755 if(!attr || !attr->val.str) {
758 return attr->val.str;
761 float ts_lookup_num(struct ts_node *root, const char *path, float def_val)
763 struct ts_attr *attr = ts_lookup(root, path);
764 if(!attr || attr->val.type != TS_NUMBER) {
767 return attr->val.fnum;
770 int ts_lookup_int(struct ts_node *root, const char *path, int def_val)
772 struct ts_attr *attr = ts_lookup(root, path);
773 if(!attr || attr->val.type != TS_NUMBER) {
776 return attr->val.inum;
779 float *ts_lookup_vec(struct ts_node *root, const char *path, float *def_val)
781 struct ts_attr *attr = ts_lookup(root, path);
782 if(!attr || !attr->val.vec) {
785 return attr->val.vec;
788 struct ts_value *ts_lookup_array(struct ts_node *node, const char *path, struct ts_value *def_val)
790 struct ts_attr *attr = ts_lookup(node, path);
791 if(!attr || !attr->val.array) {
794 return attr->val.array;
797 static long io_read(void *buf, size_t bytes, void *uptr)
799 size_t sz = fread(buf, 1, bytes, uptr);
800 if(sz < bytes && errno) return -1;
804 static long io_write(const void *buf, size_t bytes, void *uptr)
806 size_t sz = fwrite(buf, 1, bytes, uptr);
807 if(sz < bytes && errno) return -1;