libtreestore

annotate src/treestore.c @ 4:bb873449cf59

fixed ts_set_value and added convenience value-get functions
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 13 Nov 2016 19:46:01 +0200
parents 48d75df3ef04
children f3ade599cfbb
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <string.h>
nuclear@3 4 #include <errno.h>
nuclear@0 5 #include "treestore.h"
nuclear@0 6
nuclear@3 7 struct ts_node *ts_text_load(FILE *fp);
nuclear@3 8 int ts_text_save(struct ts_node *tree, FILE *fp);
nuclear@3 9
nuclear@0 10 /* ---- ts_value implementation ---- */
nuclear@0 11
nuclear@0 12 int ts_init_value(struct ts_value *tsv)
nuclear@0 13 {
nuclear@0 14 memset(tsv, 0, sizeof *tsv);
nuclear@0 15 return 0;
nuclear@0 16 }
nuclear@0 17
nuclear@0 18 void ts_destroy_value(struct ts_value *tsv)
nuclear@0 19 {
nuclear@0 20 int i;
nuclear@0 21
nuclear@0 22 free(tsv->str);
nuclear@0 23 free(tsv->vec);
nuclear@0 24
nuclear@0 25 for(i=0; i<tsv->array_size; i++) {
nuclear@0 26 ts_destroy_value(tsv->array + i);
nuclear@0 27 }
nuclear@0 28 }
nuclear@0 29
nuclear@0 30
nuclear@0 31 struct ts_value *ts_alloc_value(void)
nuclear@0 32 {
nuclear@0 33 struct ts_value *v = malloc(sizeof *v);
nuclear@0 34 if(!v || ts_init_value(v) == -1) {
nuclear@0 35 free(v);
nuclear@0 36 return 0;
nuclear@0 37 }
nuclear@0 38 return v;
nuclear@0 39 }
nuclear@0 40
nuclear@0 41 void ts_free_value(struct ts_value *tsv)
nuclear@0 42 {
nuclear@0 43 ts_destroy_value(tsv);
nuclear@0 44 free(tsv);
nuclear@0 45 }
nuclear@0 46
nuclear@0 47
nuclear@0 48 int ts_copy_value(struct ts_value *dest, struct ts_value *src)
nuclear@0 49 {
nuclear@0 50 int i;
nuclear@0 51
nuclear@0 52 if(dest == src) return 0;
nuclear@0 53
nuclear@0 54 *dest = *src;
nuclear@0 55
nuclear@0 56 dest->str = 0;
nuclear@0 57 dest->vec = 0;
nuclear@0 58 dest->array = 0;
nuclear@0 59
nuclear@0 60 if(src->str) {
nuclear@0 61 if(!(dest->str = malloc(strlen(src->str) + 1))) {
nuclear@0 62 goto fail;
nuclear@0 63 }
nuclear@0 64 strcpy(dest->str, src->str);
nuclear@0 65 }
nuclear@0 66 if(src->vec && src->vec_size > 0) {
nuclear@0 67 if(!(dest->vec = malloc(src->vec_size * sizeof *src->vec))) {
nuclear@0 68 goto fail;
nuclear@0 69 }
nuclear@0 70 memcpy(dest->vec, src->vec, src->vec_size * sizeof *src->vec);
nuclear@0 71 }
nuclear@0 72 if(src->array && src->array_size > 0) {
nuclear@0 73 if(!(dest->array = calloc(src->array_size, sizeof *src->array))) {
nuclear@0 74 goto fail;
nuclear@0 75 }
nuclear@0 76 for(i=0; i<src->array_size; i++) {
nuclear@0 77 if(ts_copy_value(dest->array + i, src->array + i) == -1) {
nuclear@0 78 goto fail;
nuclear@0 79 }
nuclear@0 80 }
nuclear@0 81 }
nuclear@0 82 return 0;
nuclear@0 83
nuclear@0 84 fail:
nuclear@0 85 free(dest->str);
nuclear@0 86 free(dest->vec);
nuclear@0 87 if(dest->array) {
nuclear@0 88 for(i=0; i<dest->array_size; i++) {
nuclear@0 89 ts_destroy_value(dest->array + i);
nuclear@0 90 }
nuclear@0 91 free(dest->array);
nuclear@0 92 }
nuclear@0 93 return -1;
nuclear@0 94 }
nuclear@0 95
nuclear@4 96 struct val_list_node {
nuclear@4 97 struct ts_value val;
nuclear@4 98 struct val_list_node *next;
nuclear@4 99 };
nuclear@0 100
nuclear@0 101 int ts_set_value(struct ts_value *tsv, const char *str)
nuclear@0 102 {
nuclear@4 103 char *endp;
nuclear@4 104
nuclear@0 105 if(tsv->str) {
nuclear@0 106 ts_destroy_value(tsv);
nuclear@0 107 if(ts_init_value(tsv) == -1) {
nuclear@0 108 return -1;
nuclear@0 109 }
nuclear@0 110 }
nuclear@0 111
nuclear@4 112 tsv->type = TS_STRING;
nuclear@0 113 if(!(tsv->str = malloc(strlen(str) + 1))) {
nuclear@0 114 return -1;
nuclear@0 115 }
nuclear@0 116 strcpy(tsv->str, str);
nuclear@4 117
nuclear@4 118 /* try to parse the string and see if it fits any of the value types */
nuclear@4 119 if(*str == '[' || *str == '{') {
nuclear@4 120 /* try to parse as a vector */
nuclear@4 121 struct val_list_node *list = 0, *tail = 0, *node;
nuclear@4 122 int nelem = 0;
nuclear@4 123 char endsym = *str++ + 2; /* ']' is '[' + 2 and '}' is '{' + 2 */
nuclear@4 124
nuclear@4 125 while(*str && *str != endsym) {
nuclear@4 126 float val = strtod(str, &endp);
nuclear@4 127 if(endp == str || !(node = malloc(sizeof *node))) {
nuclear@4 128 break;
nuclear@4 129 }
nuclear@4 130 ts_init_value(&node->val);
nuclear@4 131 ts_set_valuef(&node->val, val);
nuclear@4 132 node->next = 0;
nuclear@4 133
nuclear@4 134 if(list) {
nuclear@4 135 tail->next = node;
nuclear@4 136 tail = node;
nuclear@4 137 } else {
nuclear@4 138 list = tail = node;
nuclear@4 139 }
nuclear@4 140 ++nelem;
nuclear@4 141 str = endp;
nuclear@4 142 }
nuclear@4 143
nuclear@4 144 if(nelem && (tsv->array = malloc(nelem * sizeof *tsv->array)) &&
nuclear@4 145 (tsv->vec = malloc(nelem * sizeof *tsv->vec))) {
nuclear@4 146 int idx = 0;
nuclear@4 147 while(list) {
nuclear@4 148 node = list;
nuclear@4 149 list = list->next;
nuclear@4 150
nuclear@4 151 tsv->array[idx] = node->val;
nuclear@4 152 tsv->vec[idx] = node->val.fnum;
nuclear@4 153 ++idx;
nuclear@4 154 free(node);
nuclear@4 155 }
nuclear@4 156 tsv->type = TS_VECTOR;
nuclear@4 157 }
nuclear@4 158
nuclear@4 159 } else if((tsv->fnum = strtod(str, &endp)), endp != str) {
nuclear@4 160 /* it's a number I guess... */
nuclear@4 161 tsv->type = TS_NUMBER;
nuclear@4 162 }
nuclear@4 163
nuclear@0 164 return 0;
nuclear@0 165 }
nuclear@0 166
nuclear@0 167 int ts_set_valueiv(struct ts_value *tsv, int count, ...)
nuclear@0 168 {
nuclear@0 169 int res;
nuclear@0 170 va_list ap;
nuclear@0 171 va_start(ap, count);
nuclear@0 172 res = ts_set_valueiv_va(tsv, count, ap);
nuclear@0 173 va_end(ap);
nuclear@0 174 return res;
nuclear@0 175 }
nuclear@0 176
nuclear@0 177 #define MAKE_NUMSTR_FUNC(typestr, fmt) \
nuclear@0 178 static char *make_##typestr##str(int x) \
nuclear@0 179 { \
nuclear@0 180 static char scrap[128]; \
nuclear@0 181 char *str; \
nuclear@0 182 int sz = snprintf(scrap, sizeof scrap, fmt, x); \
nuclear@0 183 if(!(str = malloc(sz + 1))) return 0; \
nuclear@0 184 sprintf(str, fmt, x); \
nuclear@0 185 return str; \
nuclear@0 186 }
nuclear@0 187
nuclear@0 188 MAKE_NUMSTR_FUNC(int, "%d")
nuclear@0 189 MAKE_NUMSTR_FUNC(float, "%d")
nuclear@0 190
nuclear@0 191 #define ARGS_ARE_INT ((enum ts_value_type)42)
nuclear@0 192
nuclear@0 193 int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap)
nuclear@0 194 {
nuclear@0 195 if(count < 1) return -1;
nuclear@0 196 if(count == 1) {
nuclear@0 197 int num = va_arg(ap, int);
nuclear@0 198 if(!(tsv->str = make_intstr(tsv->inum))) {
nuclear@0 199 return -1;
nuclear@0 200 }
nuclear@0 201
nuclear@0 202 tsv->type = TS_NUMBER;
nuclear@0 203 tsv->inum = num;
nuclear@0 204 tsv->fnum = (float)num;
nuclear@0 205 return 0;
nuclear@0 206 }
nuclear@0 207
nuclear@0 208 /* otherwise it's an array, let ts_set_valuefv_va handle it */
nuclear@0 209 /* XXX: va_arg will need to be called with int instead of float. set a special
nuclear@0 210 * value to the type field before calling this, to signify that.
nuclear@0 211 */
nuclear@0 212 tsv->type = ARGS_ARE_INT;
nuclear@0 213 return ts_set_valuefv_va(tsv, count, ap);
nuclear@0 214 }
nuclear@0 215
nuclear@0 216 int ts_set_valuei(struct ts_value *tsv, int inum)
nuclear@0 217 {
nuclear@0 218 return ts_set_valueiv(tsv, 1, inum);
nuclear@0 219 }
nuclear@0 220
nuclear@0 221
nuclear@0 222 int ts_set_valuefv(struct ts_value *tsv, int count, ...)
nuclear@0 223 {
nuclear@0 224 int res;
nuclear@0 225 va_list ap;
nuclear@0 226 va_start(ap, count);
nuclear@0 227 res = ts_set_valuefv_va(tsv, count, ap);
nuclear@0 228 va_end(ap);
nuclear@0 229 return res;
nuclear@0 230 }
nuclear@0 231
nuclear@0 232 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap)
nuclear@0 233 {
nuclear@0 234 int i;
nuclear@0 235
nuclear@0 236 if(count < 1) return -1;
nuclear@0 237 if(count == 1) {
nuclear@0 238 int num = va_arg(ap, int);
nuclear@0 239 if(!(tsv->str = make_floatstr(tsv->inum))) {
nuclear@0 240 return -1;
nuclear@0 241 }
nuclear@0 242
nuclear@0 243 tsv->type = TS_NUMBER;
nuclear@0 244 tsv->inum = num;
nuclear@0 245 tsv->fnum = (float)num;
nuclear@0 246 return 0;
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 /* otherwise it's an array, we need to create the ts_value array, and
nuclear@0 250 * the simplified vector
nuclear@0 251 */
nuclear@0 252 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
nuclear@0 253 return -1;
nuclear@0 254 }
nuclear@0 255 tsv->vec_size = count;
nuclear@0 256
nuclear@0 257 for(i=0; i<count; i++) {
nuclear@0 258 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
nuclear@0 259 tsv->vec[i] = (float)va_arg(ap, int);
nuclear@0 260 } else {
nuclear@0 261 tsv->vec[i] = va_arg(ap, double);
nuclear@0 262 }
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
nuclear@0 266 free(tsv->vec);
nuclear@0 267 }
nuclear@0 268 tsv->array_size = count;
nuclear@0 269
nuclear@0 270 for(i=0; i<count; i++) {
nuclear@0 271 ts_init_value(tsv->array + i);
nuclear@0 272 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
nuclear@0 273 ts_set_valuei(tsv->array + i, (int)tsv->vec[i]);
nuclear@0 274 } else {
nuclear@0 275 ts_set_valuef(tsv->array + i, tsv->vec[i]);
nuclear@0 276 }
nuclear@0 277 }
nuclear@0 278
nuclear@0 279 tsv->type = TS_VECTOR;
nuclear@0 280 return 0;
nuclear@0 281 }
nuclear@0 282
nuclear@4 283 int ts_set_valuef(struct ts_value *tsv, float fnum)
nuclear@0 284 {
nuclear@0 285 return ts_set_valuefv(tsv, 1, fnum);
nuclear@0 286 }
nuclear@0 287
nuclear@0 288
nuclear@0 289 int ts_set_valuev(struct ts_value *tsv, int count, ...)
nuclear@0 290 {
nuclear@0 291 int res;
nuclear@0 292 va_list ap;
nuclear@0 293 va_start(ap, count);
nuclear@0 294 res = ts_set_valuev_va(tsv, count, ap);
nuclear@0 295 va_end(ap);
nuclear@0 296 return res;
nuclear@0 297 }
nuclear@0 298
nuclear@0 299 int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap)
nuclear@0 300 {
nuclear@1 301 int i;
nuclear@1 302
nuclear@0 303 if(count <= 1) return -1;
nuclear@1 304
nuclear@1 305 if((tsv->array = malloc(count * sizeof *tsv->array))) {
nuclear@1 306 return -1;
nuclear@1 307 }
nuclear@1 308 tsv->array_size = count;
nuclear@1 309
nuclear@1 310 for(i=0; i<count; i++) {
nuclear@1 311 struct ts_value *src = va_arg(ap, struct ts_value*);
nuclear@1 312 ts_copy_value(tsv->array + i, src);
nuclear@1 313 }
nuclear@1 314 return 0;
nuclear@0 315 }
nuclear@1 316
nuclear@1 317
nuclear@1 318 /* ---- ts_attr implementation ---- */
nuclear@1 319
nuclear@1 320 int ts_init_attr(struct ts_attr *attr)
nuclear@1 321 {
nuclear@1 322 memset(attr, 0, sizeof *attr);
nuclear@1 323 return ts_init_value(&attr->val);
nuclear@1 324 }
nuclear@1 325
nuclear@1 326 void ts_destroy_attr(struct ts_attr *attr)
nuclear@1 327 {
nuclear@1 328 free(attr->name);
nuclear@1 329 ts_destroy_value(&attr->val);
nuclear@1 330 }
nuclear@1 331
nuclear@1 332 struct ts_attr *ts_alloc_attr(void)
nuclear@1 333 {
nuclear@1 334 struct ts_attr *attr = malloc(sizeof *attr);
nuclear@1 335 if(!attr || ts_init_attr(attr) == -1) {
nuclear@1 336 free(attr);
nuclear@1 337 return 0;
nuclear@1 338 }
nuclear@1 339 return attr;
nuclear@1 340 }
nuclear@1 341
nuclear@1 342 void ts_free_attr(struct ts_attr *attr)
nuclear@1 343 {
nuclear@1 344 ts_destroy_attr(attr);
nuclear@1 345 free(attr);
nuclear@1 346 }
nuclear@1 347
nuclear@1 348 int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src)
nuclear@1 349 {
nuclear@1 350 if(dest == src) return 0;
nuclear@1 351
nuclear@1 352 if(ts_set_attr_name(dest, src->name) == -1) {
nuclear@1 353 return -1;
nuclear@1 354 }
nuclear@1 355
nuclear@1 356 if(ts_copy_value(&dest->val, &src->val) == -1) {
nuclear@1 357 ts_destroy_attr(dest);
nuclear@1 358 return -1;
nuclear@1 359 }
nuclear@1 360 return 0;
nuclear@1 361 }
nuclear@1 362
nuclear@1 363 int ts_set_attr_name(struct ts_attr *attr, const char *name)
nuclear@1 364 {
nuclear@1 365 char *n = malloc(strlen(name) + 1);
nuclear@1 366 if(!n) return -1;
nuclear@1 367 strcpy(n, name);
nuclear@1 368
nuclear@1 369 free(attr->name);
nuclear@1 370 attr->name = n;
nuclear@1 371 return 0;
nuclear@1 372 }
nuclear@1 373
nuclear@1 374
nuclear@1 375 /* ---- ts_node implementation ---- */
nuclear@1 376
nuclear@1 377 int ts_init_node(struct ts_node *node)
nuclear@1 378 {
nuclear@1 379 memset(node, 0, sizeof *node);
nuclear@1 380 return 0;
nuclear@1 381 }
nuclear@1 382
nuclear@1 383 void ts_destroy_node(struct ts_node *node)
nuclear@1 384 {
nuclear@1 385 free(node->name);
nuclear@1 386
nuclear@1 387 while(node->attr_list) {
nuclear@1 388 struct ts_attr *attr = node->attr_list;
nuclear@1 389 node->attr_list = node->attr_list->next;
nuclear@1 390 ts_free_attr(attr);
nuclear@1 391 }
nuclear@1 392 }
nuclear@1 393
nuclear@1 394 struct ts_node *ts_alloc_node(void)
nuclear@1 395 {
nuclear@1 396 struct ts_node *node = malloc(sizeof *node);
nuclear@1 397 if(!node || ts_init_node(node) == -1) {
nuclear@1 398 free(node);
nuclear@1 399 return 0;
nuclear@1 400 }
nuclear@1 401 return node;
nuclear@1 402 }
nuclear@1 403
nuclear@1 404 void ts_free_node(struct ts_node *node)
nuclear@1 405 {
nuclear@1 406 ts_destroy_node(node);
nuclear@1 407 free(node);
nuclear@1 408 }
nuclear@1 409
nuclear@1 410 void ts_free_tree(struct ts_node *tree)
nuclear@1 411 {
nuclear@1 412 while(tree->child_list) {
nuclear@2 413 struct ts_node *child = tree->child_list;
nuclear@1 414 tree->child_list = tree->child_list->next;
nuclear@1 415 ts_free_tree(child);
nuclear@1 416 }
nuclear@1 417
nuclear@1 418 ts_free_node(tree);
nuclear@1 419 }
nuclear@3 420
nuclear@3 421 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
nuclear@3 422 {
nuclear@3 423 attr->next = 0;
nuclear@3 424 if(node->attr_list) {
nuclear@3 425 node->attr_tail->next = attr;
nuclear@3 426 node->attr_tail = attr;
nuclear@3 427 } else {
nuclear@3 428 node->attr_list = node->attr_tail = attr;
nuclear@3 429 }
nuclear@3 430 }
nuclear@3 431
nuclear@3 432 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
nuclear@3 433 {
nuclear@3 434 struct ts_attr *attr = node->attr_list;
nuclear@3 435 while(attr) {
nuclear@3 436 if(strcmp(attr->name, name) == 0) {
nuclear@3 437 return attr;
nuclear@3 438 }
nuclear@3 439 attr = attr->next;
nuclear@3 440 }
nuclear@3 441 return 0;
nuclear@3 442 }
nuclear@3 443
nuclear@4 444 const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val)
nuclear@4 445 {
nuclear@4 446 struct ts_attr *attr = ts_get_attr(node, aname);
nuclear@4 447 if(!attr || !attr->val.str) {
nuclear@4 448 return def_val;
nuclear@4 449 }
nuclear@4 450 return attr->val.str;
nuclear@4 451 }
nuclear@4 452
nuclear@4 453 float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val)
nuclear@4 454 {
nuclear@4 455 struct ts_attr *attr = ts_get_attr(node, aname);
nuclear@4 456 if(!attr || attr->val.type != TS_NUMBER) {
nuclear@4 457 return def_val;
nuclear@4 458 }
nuclear@4 459 return attr->val.fnum;
nuclear@4 460 }
nuclear@4 461
nuclear@4 462 int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val)
nuclear@4 463 {
nuclear@4 464 struct ts_attr *attr = ts_get_attr(node, aname);
nuclear@4 465 if(!attr || attr->val.type != TS_NUMBER) {
nuclear@4 466 return def_val;
nuclear@4 467 }
nuclear@4 468 return attr->val.inum;
nuclear@4 469 }
nuclear@4 470
nuclear@4 471 float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val)
nuclear@4 472 {
nuclear@4 473 struct ts_attr *attr = ts_get_attr(node, aname);
nuclear@4 474 if(!attr || !attr->val.vec) {
nuclear@4 475 return def_val;
nuclear@4 476 }
nuclear@4 477 return attr->val.vec;
nuclear@4 478 }
nuclear@4 479
nuclear@4 480 struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val)
nuclear@4 481 {
nuclear@4 482 struct ts_attr *attr = ts_get_attr(node, aname);
nuclear@4 483 if(!attr || !attr->val.array) {
nuclear@4 484 return def_val;
nuclear@4 485 }
nuclear@4 486 return attr->val.array;
nuclear@4 487 }
nuclear@4 488
nuclear@3 489 void ts_add_child(struct ts_node *node, struct ts_node *child)
nuclear@3 490 {
nuclear@3 491 if(child->parent) {
nuclear@3 492 if(child->parent == node) return;
nuclear@3 493 ts_remove_child(child->parent, child);
nuclear@3 494 }
nuclear@3 495 child->parent = node;
nuclear@3 496 child->next = 0;
nuclear@3 497
nuclear@3 498 if(node->child_list) {
nuclear@3 499 node->child_tail->next = child;
nuclear@3 500 node->child_tail = child;
nuclear@3 501 } else {
nuclear@3 502 node->child_list = node->child_tail = child;
nuclear@3 503 }
nuclear@3 504 }
nuclear@3 505
nuclear@3 506 int ts_remove_child(struct ts_node *node, struct ts_node *child)
nuclear@3 507 {
nuclear@3 508 struct ts_node dummy, *iter = &dummy;
nuclear@3 509 dummy.next = node->child_list;
nuclear@3 510
nuclear@3 511 while(iter->next && iter->next != child) {
nuclear@3 512 iter = iter->next;
nuclear@3 513 }
nuclear@3 514 if(!iter->next) {
nuclear@3 515 return -1;
nuclear@3 516 }
nuclear@3 517
nuclear@3 518 child->parent = 0;
nuclear@3 519
nuclear@3 520 iter->next = child->next;
nuclear@3 521 if(!iter->next) {
nuclear@3 522 node->child_tail = iter;
nuclear@3 523 }
nuclear@3 524 node->child_list = dummy.next;
nuclear@3 525 return 0;
nuclear@3 526 }
nuclear@3 527
nuclear@3 528 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
nuclear@3 529 {
nuclear@3 530 struct ts_node *res = node->child_list;
nuclear@3 531 while(res) {
nuclear@3 532 if(strcmp(res->name, name) == 0) {
nuclear@3 533 return res;
nuclear@3 534 }
nuclear@3 535 res = res->next;
nuclear@3 536 }
nuclear@3 537 return 0;
nuclear@3 538 }
nuclear@3 539
nuclear@3 540 struct ts_node *ts_load(const char *fname)
nuclear@3 541 {
nuclear@3 542 FILE *fp;
nuclear@3 543 struct ts_node *root;
nuclear@3 544
nuclear@3 545 if(!(fp = fopen(fname, "rb"))) {
nuclear@3 546 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
nuclear@3 547 return 0;
nuclear@3 548 }
nuclear@3 549
nuclear@3 550 root = ts_text_load(fp);
nuclear@3 551 fclose(fp);
nuclear@3 552 return root;
nuclear@3 553 }
nuclear@3 554
nuclear@3 555 int ts_save(struct ts_node *tree, const char *fname)
nuclear@3 556 {
nuclear@3 557 FILE *fp;
nuclear@3 558 int res;
nuclear@3 559
nuclear@3 560 if(!(fp = fopen(fname, "wb"))) {
nuclear@3 561 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
nuclear@3 562 return 0;
nuclear@3 563 }
nuclear@3 564 res = ts_text_save(tree, fp);
nuclear@3 565 fclose(fp);
nuclear@3 566 return res;
nuclear@3 567 }