libtreestore

annotate src/treestore.c @ 3:48d75df3ef04

picking this up again, converted to cmake, and started a text format reader/writer
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 10 Nov 2016 16:19:44 +0200
parents e1a825be0eee
children bb873449cf59
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@0 96
nuclear@0 97 int ts_set_value(struct ts_value *tsv, const char *str)
nuclear@0 98 {
nuclear@0 99 if(tsv->str) {
nuclear@0 100 ts_destroy_value(tsv);
nuclear@0 101 if(ts_init_value(tsv) == -1) {
nuclear@0 102 return -1;
nuclear@0 103 }
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 if(!(tsv->str = malloc(strlen(str) + 1))) {
nuclear@0 107 return -1;
nuclear@0 108 }
nuclear@0 109 strcpy(tsv->str, str);
nuclear@0 110 return 0;
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 int ts_set_valueiv(struct ts_value *tsv, int count, ...)
nuclear@0 114 {
nuclear@0 115 int res;
nuclear@0 116 va_list ap;
nuclear@0 117 va_start(ap, count);
nuclear@0 118 res = ts_set_valueiv_va(tsv, count, ap);
nuclear@0 119 va_end(ap);
nuclear@0 120 return res;
nuclear@0 121 }
nuclear@0 122
nuclear@0 123 #define MAKE_NUMSTR_FUNC(typestr, fmt) \
nuclear@0 124 static char *make_##typestr##str(int x) \
nuclear@0 125 { \
nuclear@0 126 static char scrap[128]; \
nuclear@0 127 char *str; \
nuclear@0 128 int sz = snprintf(scrap, sizeof scrap, fmt, x); \
nuclear@0 129 if(!(str = malloc(sz + 1))) return 0; \
nuclear@0 130 sprintf(str, fmt, x); \
nuclear@0 131 return str; \
nuclear@0 132 }
nuclear@0 133
nuclear@0 134 MAKE_NUMSTR_FUNC(int, "%d")
nuclear@0 135 MAKE_NUMSTR_FUNC(float, "%d")
nuclear@0 136
nuclear@0 137 #define ARGS_ARE_INT ((enum ts_value_type)42)
nuclear@0 138
nuclear@0 139 int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap)
nuclear@0 140 {
nuclear@0 141 if(count < 1) return -1;
nuclear@0 142 if(count == 1) {
nuclear@0 143 int num = va_arg(ap, int);
nuclear@0 144 if(!(tsv->str = make_intstr(tsv->inum))) {
nuclear@0 145 return -1;
nuclear@0 146 }
nuclear@0 147
nuclear@0 148 tsv->type = TS_NUMBER;
nuclear@0 149 tsv->inum = num;
nuclear@0 150 tsv->fnum = (float)num;
nuclear@0 151 return 0;
nuclear@0 152 }
nuclear@0 153
nuclear@0 154 /* otherwise it's an array, let ts_set_valuefv_va handle it */
nuclear@0 155 /* XXX: va_arg will need to be called with int instead of float. set a special
nuclear@0 156 * value to the type field before calling this, to signify that.
nuclear@0 157 */
nuclear@0 158 tsv->type = ARGS_ARE_INT;
nuclear@0 159 return ts_set_valuefv_va(tsv, count, ap);
nuclear@0 160 }
nuclear@0 161
nuclear@0 162 int ts_set_valuei(struct ts_value *tsv, int inum)
nuclear@0 163 {
nuclear@0 164 return ts_set_valueiv(tsv, 1, inum);
nuclear@0 165 }
nuclear@0 166
nuclear@0 167
nuclear@0 168 int ts_set_valuefv(struct ts_value *tsv, int count, ...)
nuclear@0 169 {
nuclear@0 170 int res;
nuclear@0 171 va_list ap;
nuclear@0 172 va_start(ap, count);
nuclear@0 173 res = ts_set_valuefv_va(tsv, count, ap);
nuclear@0 174 va_end(ap);
nuclear@0 175 return res;
nuclear@0 176 }
nuclear@0 177
nuclear@0 178 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap)
nuclear@0 179 {
nuclear@0 180 int i;
nuclear@0 181
nuclear@0 182 if(count < 1) return -1;
nuclear@0 183 if(count == 1) {
nuclear@0 184 int num = va_arg(ap, int);
nuclear@0 185 if(!(tsv->str = make_floatstr(tsv->inum))) {
nuclear@0 186 return -1;
nuclear@0 187 }
nuclear@0 188
nuclear@0 189 tsv->type = TS_NUMBER;
nuclear@0 190 tsv->inum = num;
nuclear@0 191 tsv->fnum = (float)num;
nuclear@0 192 return 0;
nuclear@0 193 }
nuclear@0 194
nuclear@0 195 /* otherwise it's an array, we need to create the ts_value array, and
nuclear@0 196 * the simplified vector
nuclear@0 197 */
nuclear@0 198 if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) {
nuclear@0 199 return -1;
nuclear@0 200 }
nuclear@0 201 tsv->vec_size = count;
nuclear@0 202
nuclear@0 203 for(i=0; i<count; i++) {
nuclear@0 204 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
nuclear@0 205 tsv->vec[i] = (float)va_arg(ap, int);
nuclear@0 206 } else {
nuclear@0 207 tsv->vec[i] = va_arg(ap, double);
nuclear@0 208 }
nuclear@0 209 }
nuclear@0 210
nuclear@0 211 if(!(tsv->array = malloc(count * sizeof *tsv->array))) {
nuclear@0 212 free(tsv->vec);
nuclear@0 213 }
nuclear@0 214 tsv->array_size = count;
nuclear@0 215
nuclear@0 216 for(i=0; i<count; i++) {
nuclear@0 217 ts_init_value(tsv->array + i);
nuclear@0 218 if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */
nuclear@0 219 ts_set_valuei(tsv->array + i, (int)tsv->vec[i]);
nuclear@0 220 } else {
nuclear@0 221 ts_set_valuef(tsv->array + i, tsv->vec[i]);
nuclear@0 222 }
nuclear@0 223 }
nuclear@0 224
nuclear@0 225 tsv->type = TS_VECTOR;
nuclear@0 226 return 0;
nuclear@0 227 }
nuclear@0 228
nuclear@0 229 int ts_set_valuef(struct ts_value *tsv, int fnum)
nuclear@0 230 {
nuclear@0 231 return ts_set_valuefv(tsv, 1, fnum);
nuclear@0 232 }
nuclear@0 233
nuclear@0 234
nuclear@0 235 int ts_set_valuev(struct ts_value *tsv, int count, ...)
nuclear@0 236 {
nuclear@0 237 int res;
nuclear@0 238 va_list ap;
nuclear@0 239 va_start(ap, count);
nuclear@0 240 res = ts_set_valuev_va(tsv, count, ap);
nuclear@0 241 va_end(ap);
nuclear@0 242 return res;
nuclear@0 243 }
nuclear@0 244
nuclear@0 245 int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap)
nuclear@0 246 {
nuclear@1 247 int i;
nuclear@1 248
nuclear@0 249 if(count <= 1) return -1;
nuclear@1 250
nuclear@1 251 if((tsv->array = malloc(count * sizeof *tsv->array))) {
nuclear@1 252 return -1;
nuclear@1 253 }
nuclear@1 254 tsv->array_size = count;
nuclear@1 255
nuclear@1 256 for(i=0; i<count; i++) {
nuclear@1 257 struct ts_value *src = va_arg(ap, struct ts_value*);
nuclear@1 258 ts_copy_value(tsv->array + i, src);
nuclear@1 259 }
nuclear@1 260 return 0;
nuclear@0 261 }
nuclear@1 262
nuclear@1 263
nuclear@1 264 /* ---- ts_attr implementation ---- */
nuclear@1 265
nuclear@1 266 int ts_init_attr(struct ts_attr *attr)
nuclear@1 267 {
nuclear@1 268 memset(attr, 0, sizeof *attr);
nuclear@1 269 return ts_init_value(&attr->val);
nuclear@1 270 }
nuclear@1 271
nuclear@1 272 void ts_destroy_attr(struct ts_attr *attr)
nuclear@1 273 {
nuclear@1 274 free(attr->name);
nuclear@1 275 ts_destroy_value(&attr->val);
nuclear@1 276 }
nuclear@1 277
nuclear@1 278 struct ts_attr *ts_alloc_attr(void)
nuclear@1 279 {
nuclear@1 280 struct ts_attr *attr = malloc(sizeof *attr);
nuclear@1 281 if(!attr || ts_init_attr(attr) == -1) {
nuclear@1 282 free(attr);
nuclear@1 283 return 0;
nuclear@1 284 }
nuclear@1 285 return attr;
nuclear@1 286 }
nuclear@1 287
nuclear@1 288 void ts_free_attr(struct ts_attr *attr)
nuclear@1 289 {
nuclear@1 290 ts_destroy_attr(attr);
nuclear@1 291 free(attr);
nuclear@1 292 }
nuclear@1 293
nuclear@1 294 int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src)
nuclear@1 295 {
nuclear@1 296 if(dest == src) return 0;
nuclear@1 297
nuclear@1 298 if(ts_set_attr_name(dest, src->name) == -1) {
nuclear@1 299 return -1;
nuclear@1 300 }
nuclear@1 301
nuclear@1 302 if(ts_copy_value(&dest->val, &src->val) == -1) {
nuclear@1 303 ts_destroy_attr(dest);
nuclear@1 304 return -1;
nuclear@1 305 }
nuclear@1 306 return 0;
nuclear@1 307 }
nuclear@1 308
nuclear@1 309 int ts_set_attr_name(struct ts_attr *attr, const char *name)
nuclear@1 310 {
nuclear@1 311 char *n = malloc(strlen(name) + 1);
nuclear@1 312 if(!n) return -1;
nuclear@1 313 strcpy(n, name);
nuclear@1 314
nuclear@1 315 free(attr->name);
nuclear@1 316 attr->name = n;
nuclear@1 317 return 0;
nuclear@1 318 }
nuclear@1 319
nuclear@1 320
nuclear@1 321 /* ---- ts_node implementation ---- */
nuclear@1 322
nuclear@1 323 int ts_init_node(struct ts_node *node)
nuclear@1 324 {
nuclear@1 325 memset(node, 0, sizeof *node);
nuclear@1 326 return 0;
nuclear@1 327 }
nuclear@1 328
nuclear@1 329 void ts_destroy_node(struct ts_node *node)
nuclear@1 330 {
nuclear@1 331 free(node->name);
nuclear@1 332
nuclear@1 333 while(node->attr_list) {
nuclear@1 334 struct ts_attr *attr = node->attr_list;
nuclear@1 335 node->attr_list = node->attr_list->next;
nuclear@1 336 ts_free_attr(attr);
nuclear@1 337 }
nuclear@1 338 }
nuclear@1 339
nuclear@1 340 struct ts_node *ts_alloc_node(void)
nuclear@1 341 {
nuclear@1 342 struct ts_node *node = malloc(sizeof *node);
nuclear@1 343 if(!node || ts_init_node(node) == -1) {
nuclear@1 344 free(node);
nuclear@1 345 return 0;
nuclear@1 346 }
nuclear@1 347 return node;
nuclear@1 348 }
nuclear@1 349
nuclear@1 350 void ts_free_node(struct ts_node *node)
nuclear@1 351 {
nuclear@1 352 ts_destroy_node(node);
nuclear@1 353 free(node);
nuclear@1 354 }
nuclear@1 355
nuclear@1 356 void ts_free_tree(struct ts_node *tree)
nuclear@1 357 {
nuclear@1 358 while(tree->child_list) {
nuclear@2 359 struct ts_node *child = tree->child_list;
nuclear@1 360 tree->child_list = tree->child_list->next;
nuclear@1 361 ts_free_tree(child);
nuclear@1 362 }
nuclear@1 363
nuclear@1 364 ts_free_node(tree);
nuclear@1 365 }
nuclear@3 366
nuclear@3 367 void ts_add_attr(struct ts_node *node, struct ts_attr *attr)
nuclear@3 368 {
nuclear@3 369 attr->next = 0;
nuclear@3 370 if(node->attr_list) {
nuclear@3 371 node->attr_tail->next = attr;
nuclear@3 372 node->attr_tail = attr;
nuclear@3 373 } else {
nuclear@3 374 node->attr_list = node->attr_tail = attr;
nuclear@3 375 }
nuclear@3 376 }
nuclear@3 377
nuclear@3 378 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name)
nuclear@3 379 {
nuclear@3 380 struct ts_attr *attr = node->attr_list;
nuclear@3 381 while(attr) {
nuclear@3 382 if(strcmp(attr->name, name) == 0) {
nuclear@3 383 return attr;
nuclear@3 384 }
nuclear@3 385 attr = attr->next;
nuclear@3 386 }
nuclear@3 387 return 0;
nuclear@3 388 }
nuclear@3 389
nuclear@3 390 void ts_add_child(struct ts_node *node, struct ts_node *child)
nuclear@3 391 {
nuclear@3 392 if(child->parent) {
nuclear@3 393 if(child->parent == node) return;
nuclear@3 394 ts_remove_child(child->parent, child);
nuclear@3 395 }
nuclear@3 396 child->parent = node;
nuclear@3 397 child->next = 0;
nuclear@3 398
nuclear@3 399 if(node->child_list) {
nuclear@3 400 node->child_tail->next = child;
nuclear@3 401 node->child_tail = child;
nuclear@3 402 } else {
nuclear@3 403 node->child_list = node->child_tail = child;
nuclear@3 404 }
nuclear@3 405 }
nuclear@3 406
nuclear@3 407 int ts_remove_child(struct ts_node *node, struct ts_node *child)
nuclear@3 408 {
nuclear@3 409 struct ts_node dummy, *iter = &dummy;
nuclear@3 410 dummy.next = node->child_list;
nuclear@3 411
nuclear@3 412 while(iter->next && iter->next != child) {
nuclear@3 413 iter = iter->next;
nuclear@3 414 }
nuclear@3 415 if(!iter->next) {
nuclear@3 416 return -1;
nuclear@3 417 }
nuclear@3 418
nuclear@3 419 child->parent = 0;
nuclear@3 420
nuclear@3 421 iter->next = child->next;
nuclear@3 422 if(!iter->next) {
nuclear@3 423 node->child_tail = iter;
nuclear@3 424 }
nuclear@3 425 node->child_list = dummy.next;
nuclear@3 426 return 0;
nuclear@3 427 }
nuclear@3 428
nuclear@3 429 struct ts_node *ts_get_child(struct ts_node *node, const char *name)
nuclear@3 430 {
nuclear@3 431 struct ts_node *res = node->child_list;
nuclear@3 432 while(res) {
nuclear@3 433 if(strcmp(res->name, name) == 0) {
nuclear@3 434 return res;
nuclear@3 435 }
nuclear@3 436 res = res->next;
nuclear@3 437 }
nuclear@3 438 return 0;
nuclear@3 439 }
nuclear@3 440
nuclear@3 441 struct ts_node *ts_load(const char *fname)
nuclear@3 442 {
nuclear@3 443 FILE *fp;
nuclear@3 444 struct ts_node *root;
nuclear@3 445
nuclear@3 446 if(!(fp = fopen(fname, "rb"))) {
nuclear@3 447 fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno));
nuclear@3 448 return 0;
nuclear@3 449 }
nuclear@3 450
nuclear@3 451 root = ts_text_load(fp);
nuclear@3 452 fclose(fp);
nuclear@3 453 return root;
nuclear@3 454 }
nuclear@3 455
nuclear@3 456 int ts_save(struct ts_node *tree, const char *fname)
nuclear@3 457 {
nuclear@3 458 FILE *fp;
nuclear@3 459 int res;
nuclear@3 460
nuclear@3 461 if(!(fp = fopen(fname, "wb"))) {
nuclear@3 462 fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno));
nuclear@3 463 return 0;
nuclear@3 464 }
nuclear@3 465 res = ts_text_save(tree, fp);
nuclear@3 466 fclose(fp);
nuclear@3 467 return res;
nuclear@3 468 }