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 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
533 if(node->attr_list) {
534 node->attr_tail->next = attr;
535 node->attr_tail = attr;
537 node->attr_list = node->attr_tail = attr;
542 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
544 struct ts_attr *attr = node->attr_list;
546 if(strcmp(attr->name, name) == 0) {
554 const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val)
556 struct ts_attr *attr = ts_get_attr(node, aname);
557 if(!attr || !attr->val.str) {
560 return attr->val.str;
563 float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val)
565 struct ts_attr *attr = ts_get_attr(node, aname);
566 if(!attr || attr->val.type != TS_NUMBER) {
569 return attr->val.fnum;
572 int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val)
574 struct ts_attr *attr = ts_get_attr(node, aname);
575 if(!attr || attr->val.type != TS_NUMBER) {
578 return attr->val.inum;
581 float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val)
583 struct ts_attr *attr = ts_get_attr(node, aname);
584 if(!attr || !attr->val.vec) {
587 return attr->val.vec;
590 struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val)
592 struct ts_attr *attr = ts_get_attr(node, aname);
593 if(!attr || !attr->val.array) {
596 return attr->val.array;
599 void ts_add_child(struct ts_node *node, struct ts_node *child)
602 if(child->parent == node) return;
603 ts_remove_child(child->parent, child);
605 child->parent = node;
608 if(node->child_list) {
609 node->child_tail->next = child;
610 node->child_tail = child;
612 node->child_list = node->child_tail = child;
617 int ts_remove_child(struct ts_node *node, struct ts_node *child)
619 struct ts_node dummy, *iter = &dummy;
620 dummy.next = node->child_list;
622 while(iter->next && iter->next != child) {
631 iter->next = child->next;
633 node->child_tail = iter;
635 node->child_list = dummy.next;
637 assert(node->child_count >= 0);
641 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
643 struct ts_node *res = node->child_list;
645 if(strcmp(res->name, name) == 0) {
653 struct ts_node *ts_load(const char *fname)
656 struct ts_node *root;
658 if(!(fp = fopen(fname, "rb"))) {
659 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
663 root = ts_load_file(fp);
668 struct ts_node *ts_load_file(FILE *fp)
670 struct ts_io io = {0};
674 return ts_load_io(&io);
677 struct ts_node *ts_load_io(struct ts_io *io)
679 return ts_text_load(io);
682 int ts_save(struct ts_node *tree, const char *fname)
687 if(!(fp = fopen(fname, "wb"))) {
688 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
691 res = ts_save_file(tree, fp);
696 int ts_save_file(struct ts_node *tree, FILE *fp)
698 struct ts_io io = {0};
702 return ts_save_io(tree, &io);
705 int ts_save_io(struct ts_node *tree, struct ts_io *io)
707 return ts_text_save(tree, io);
710 static const char *pathtok(const char *path, char *tok)
713 const char *dot = strchr(path, '.');
720 memcpy(tok, path, len);
725 struct ts_attr *ts_lookup(struct ts_node *node, const char *path)
727 char *name = alloca(strlen(path) + 1);
731 if(!(path = pathtok(path, name)) || strcmp(name, node->name) != 0) {
735 while((path = pathtok(path, name)) && (node = ts_get_child(node, name)));
737 if(path || !node) return 0;
738 return ts_get_attr(node, name);
741 const char *ts_lookup_str(struct ts_node *root, const char *path, const char *def_val)
743 struct ts_attr *attr = ts_lookup(root, path);
744 if(!attr || !attr->val.str) {
747 return attr->val.str;
750 float ts_lookup_num(struct ts_node *root, const char *path, float def_val)
752 struct ts_attr *attr = ts_lookup(root, path);
753 if(!attr || attr->val.type != TS_NUMBER) {
756 return attr->val.fnum;
759 int ts_lookup_int(struct ts_node *root, const char *path, int def_val)
761 struct ts_attr *attr = ts_lookup(root, path);
762 if(!attr || attr->val.type != TS_NUMBER) {
765 return attr->val.inum;
768 float *ts_lookup_vec(struct ts_node *root, const char *path, float *def_val)
770 struct ts_attr *attr = ts_lookup(root, path);
771 if(!attr || !attr->val.vec) {
774 return attr->val.vec;
777 struct ts_value *ts_lookup_array(struct ts_node *node, const char *path, struct ts_value *def_val)
779 struct ts_attr *attr = ts_lookup(node, path);
780 if(!attr || !attr->val.array) {
783 return attr->val.array;
786 static long io_read(void *buf, size_t bytes, void *uptr)
788 size_t sz = fread(buf, 1, bytes, uptr);
789 if(sz < bytes && errno) return -1;
793 static long io_write(const void *buf, size_t bytes, void *uptr)
795 size_t sz = fwrite(buf, 1, bytes, uptr);
796 if(sz < bytes && errno) return -1;