# HG changeset patch # User John Tsiombikas # Date 1478787584 -7200 # Node ID 48d75df3ef04b06bf67dccfad21d5666701154c8 # Parent e1a825be0eee200f64ab165f0f8f37dffb8f90d0 picking this up again, converted to cmake, and started a text format reader/writer diff -r e1a825be0eee -r 48d75df3ef04 .hgignore --- a/.hgignore Sat Apr 12 13:50:01 2014 +0300 +++ b/.hgignore Thu Nov 10 16:19:44 2016 +0200 @@ -2,4 +2,8 @@ \.d$ \.swp$ \.so\. +\.so$ \.a$ +CMakeFiles/ +\.cmake$ +\.txt$ diff -r e1a825be0eee -r 48d75df3ef04 CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CMakeLists.txt Thu Nov 10 16:19:44 2016 +0200 @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.0) +project(libtreestore) + +include(GNUInstallDirs) + +set(SO_MAJOR 0) +set(SO_MINOR 1) + +file(GLOB src "src/*.c") +file(GLOB hdr "src/*.h") +file(GLOB pubhdr "include/*.h") + +add_library(treestore SHARED ${src} ${hdr} ${pubhdr}) +add_library(treestore-static STATIC ${src} ${hdr} ${pubhdr}) + +set_target_properties(treestore PROPERTIES VERSION ${SO_MAJOR}.${SO_MINOR}) +set_target_properties(treestore PROPERTIES SOVERSION ${SO_MAJOR}) + +if(NOT WIN32) + set_target_properties(treestore-static PROPERTIES OUTPUT_NAME treestore) +endif() + +target_include_directories(treestore PUBLIC include) +target_include_directories(treestore-static PUBLIC include) + +install(TARGETS treestore + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install(TARGETS treestore-static + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install(FILES ${pubhdr} DESTINATION include) diff -r e1a825be0eee -r 48d75df3ef04 Makefile --- a/Makefile Sat Apr 12 13:50:01 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -PREFIX = /usr/local - -csrc = $(wildcard src/*.c) -ccsrc = $(wildcard src/*.cc) -cobj = $(csrc:.c=.o) -ccobj = $(ccsrc:.cc=.o) -obj = $(cobj) $(ccobj) -dep = $(obj:.o=.d) - -cname = treestore -ccname = treestorepp - -capi_major = 0 -capi_minor = 1 -ccapi_major = 0 -ccapi_minor = 1 - -clib_a = lib$(cname).a -cclib_a = lib$(ccname).a - -ifeq ($(shell uname -s), Darwin) - clib_so = lib$(cname).dylib - cclib_so = lib$(ccname).dylib - cshared = -dynamiclib - ccshared = -dynamiclib -else - clib_so = lib$(cname).so.$(capi_major).$(capi_minor) - csoname = lib$(cname).so.$(capi_major) - cdevlink = lib$(cname).so - cclib_so = lib$(ccname).so.$(ccapi_major).$(ccapi_minor) - ccsoname = lib$(ccname).so.$(ccapi_major) - ccdevlink = lib$(ccname).so - - cshared = -shared -Wl,-soname=$(csoname) - ccshared = -shared -Wl,-soname=$(ccsoname) - pic = -fPIC -endif - -dbg = -g -cxx11 = -std=c++11 -DTS_USE_CPP11 - -CFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic) -CXXFLAGS = $(cxx11) $(CFLAGS) - -.PHONY: all -all: $(clib_so) $(clib_a) $(cclib_so) $(cclib_a) - -$(clib_a): $(cobj) - $(AR) rcs $@ $(cobj) - -$(clib_so): $(cobj) - $(CC) -o $@ $(cshared) $(cobj) $(LDFLAGS) - -$(cclib_a): $(ccobj) - $(AR) rcs $@ $(ccobj) - -$(cclib_so): $(ccobj) - $(CXX) -o $@ $(ccshared) $(ccobj) $(LDFLAGS) - --include $(dep) - -%.d: %.c - @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ - -%.d: %.cc - @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ - -.PHONY: clean -clean: - rm -f $(obj) $(clib_so) $(cclib_so) $(clib_a) $(cclib_a) - -.PHONY: cleandep -cleandep: clean - rm -f $(dep) - - -.PHONY: install -install: all - mkdir -p $(DESTDIR)$(PREFIX)/include $(DESTDIR)$(PREFIX)/lib - cp src/treestore.h src/treestorepp.h $(DESTDIR)$(PREFIX)/include - cp $(clib_a) $(clib_so) $(cclib_a) $(cclib_so) $(DESTDIR)$(PREFIX)/lib - [ -n "$(csoname)" ] && \ - cd $(DESTDIR)$(PREFIX) && \ - rm -f $(csoname) $(cdevlink) $(ccsoname) $(ccdevlink) && \ - ln -s $(clib_so) $(csoname) && \ - ln -s $(cclib_so) $(ccsoname) && \ - ln -s $(csoname) $(cdevlink) && \ - ln -s $(ccsoname) $(ccdevlink) || \ - true diff -r e1a825be0eee -r 48d75df3ef04 include/treestore.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/treestore.h Thu Nov 10 16:19:44 2016 +0200 @@ -0,0 +1,114 @@ +#ifndef TREESTORE_H_ +#define TREESTORE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum ts_value_type { TS_UNKNOWN, TS_NUMBER, TS_VECTOR, TS_ARRAY }; + +/** treestore node attribute value */ +struct ts_value { + enum ts_value_type type; + + char *str; /**< all values have a string representation */ + int inum; /**< numeric values TS_NUMBER will have this set */ + float fnum; /**< numeric values TS_NUMBER will have this set */ + + /** vector values (arrays containing ONLY numbers) will have this set */ + float *vec; /**< elements of the vector */ + int vec_size; /**< size of the vector (in elements), same as array_size */ + + /** array values (including vectors) will have this set */ + struct ts_value *array; /**< elements of the array */ + int array_size; /**< size of the array (in elements) */ +}; + +int ts_init_value(struct ts_value *tsv); +void ts_destroy_value(struct ts_value *tsv); + +struct ts_value *ts_alloc_value(void); /**< also calls ts_init_value */ +void ts_free_value(struct ts_value *tsv); /**< also calls ts_destroy_value */ + +/** perform a deep-copy of a ts_value */ +int ts_copy_value(struct ts_value *dest, struct ts_value *src); + +/** ts_set_value will try to parse the string and initialize the value type fields */ +int ts_set_value(struct ts_value *tsv, const char *str); + +/** set a ts_value from a list of integers */ +int ts_set_valueiv(struct ts_value *tsv, int count, ...); +int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap); +int ts_set_valuei(struct ts_value *tsv, int inum); /**< equiv: ts_set_valueiv(val, 1, inum) */ + +/** set a ts_value from a list of floats */ +int ts_set_valuefv(struct ts_value *tsv, int count, ...); +int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap); +int ts_set_valuef(struct ts_value *tsv, int fnum); /**< equiv: ts_set_valuefv(val, 1, fnum) */ + +/** set a ts_value from a list of ts_value pointers. they are deep-copied as per ts_copy_value */ +int ts_set_valuev(struct ts_value *tsv, int count, ...); +int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap); + + +/** treestore node attribute */ +struct ts_attr { + char *name; + struct ts_value val; + + struct ts_attr *next; +}; + +int ts_init_attr(struct ts_attr *attr); +void ts_destroy_attr(struct ts_attr *attr); + +struct ts_attr *ts_alloc_attr(void); /**< also calls ts_init_attr */ +void ts_free_attr(struct ts_attr *attr); /**< also calls ts_destroy_attr */ + +/** perform a deep-copy of a ts_attr */ +int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src); + +int ts_set_attr_name(struct ts_attr *attr, const char *name); + + + +/** treestore node */ +struct ts_node { + char *name; + + int attr_count; + struct ts_attr *attr_list, *attr_tail; + + int child_count; + struct ts_node *child_list, *child_tail; + struct ts_node *parent; + + struct ts_node *next; /* next sibling */ +}; + +int ts_init_node(struct ts_node *node); +void ts_destroy_node(struct ts_node *node); + +struct ts_node *ts_alloc_node(void); /**< also calls ts_init_node */ +void ts_free_node(struct ts_node *n); /**< also calls ts_destroy_node */ + +/** recursively destroy all the nodes of the tree */ +void ts_free_tree(struct ts_node *tree); + +void ts_add_attr(struct ts_node *node, struct ts_attr *attr); +struct ts_attr *ts_get_attr(struct ts_node *node, const char *name); + +void ts_add_child(struct ts_node *node, struct ts_node *child); +int ts_remove_child(struct ts_node *node, struct ts_node *child); +struct ts_node *ts_get_child(struct ts_node *node, const char *name); + +struct ts_node *ts_load(const char *fname); +int ts_save(struct ts_node *tree, const char *fname); + +#ifdef __cplusplus +} +#endif + +#endif /* TREESTORE_H_ */ diff -r e1a825be0eee -r 48d75df3ef04 src/text.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/text.c Thu Nov 10 16:19:44 2016 +0200 @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include "treestore.h" + +enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR }; + +static struct ts_node *read_node(FILE *fp); +static int next_token(FILE *fp, char *buf, int bsz); + +static void print_attr(struct ts_attr *attr, FILE *fp, int level); +static void print_value(struct ts_value *value, FILE *fp); +static int tree_level(struct ts_node *n); +static const char *indent(int x); + +struct ts_node *ts_text_load(FILE *fp) +{ + char token[256]; + struct ts_node *node; + + if(next_token(fp, token, sizeof token) != TOK_ID || + !(next_token(fp, token, sizeof token) == TOK_SYM && token[0] == '{')) { + fprintf(stderr, "ts_text_load: invalid file format\n"); + return 0; + } + if(!(node = read_node(fp))) { + return 0; + } + if(!(node->name = strdup(token))) { + perror("failed to allocate node name"); + free(node); + return 0; + } + return node; +} + + +#define EXPECT(type) \ + if(next_token(fp, token, sizeof token) != (type)) goto err +#define EXPECT_SYM(c) \ + if(next_token(fp, token, sizeof token) != TOK_SYM || token[0] != (c)) goto err + +static struct ts_node *read_node(FILE *fp) +{ + char token[256]; + struct ts_node *node; + + if(!(node = ts_alloc_node())) { + perror("failed to allocate treestore node"); + return 0; + } + + while(next_token(fp, token, sizeof token) == TOK_ID) { + char *id; + + if(!(id = strdup(token))) { + goto err; + } + + EXPECT(TOK_SYM); + + if(token[0] == '=') { + /* attribute */ + struct ts_attr *attr; + int toktype; + + if(!(attr = ts_alloc_attr())) { + goto err; + } + + if((toktype = next_token(fp, token, sizeof token)) == -1) { + ts_free_attr(attr); + goto err; + } + attr->name = id; + ts_set_value(&attr->val, token); + + ts_add_attr(node, attr); + + } else if(token[0] == '{') { + /* child */ + struct ts_node *child; + + if(!(child = read_node(fp))) { + ts_free_node(node); + return 0; + } + child->name = id; + + ts_add_child(node, child); + + } else { + fprintf(stderr, "unexpected token: %s\n", token); + goto err; + } + } + +err: + fprintf(stderr, "treestore read_node failed\n"); + ts_free_node(node); + return 0; +} + +static int next_token(FILE *fp, char *buf, int bsz) +{ + int c; + char *ptr; + + // skip whitespace + while((c = fgetc(fp)) != -1 && isspace(c)) { + if(c == '#') { // skip to end of line + while((c = fgetc(fp)) != -1 && c != '\n'); + if(c == -1) return -1; + } + } + if(c == -1) return -1; + + buf[0] = c; + buf[1] = 0; + + if(isdigit(c)) { + // token is a number + ptr = buf + 1; + while((c = fgetc(fp)) != -1 && isdigit(c)) { + *ptr++ = c; + } + if(c != -1) ungetc(c, fp); + *ptr = 0; + return TOK_NUM; + } + if(isalpha(c)) { + // token is an identifier + ptr = buf + 1; + while((c = fgetc(fp)) != -1 && isalnum(c)) { + *ptr++ = c; + } + if(c != -1) ungetc(c, fp); + *ptr = 0; + return TOK_ID; + } + if(c == '"') { + // token is a string constant + ptr = buf; + while((c = fgetc(fp)) != -1 && c != '"' && c != '\r' && c != '\n') { + *ptr++ = c; + } + if(c != '"') { + return -1; + } + *ptr = 0; + return TOK_STR; + } + + return TOK_SYM; +} + +int ts_text_save(struct ts_node *tree, FILE *fp) +{ + struct ts_node *c; + struct ts_attr *attr; + int lvl = tree_level(tree); + + fprintf(fp, "%s%s {\n", indent(lvl), tree->name); + + attr = tree->attr_list; + while(attr) { + print_attr(attr, fp, lvl); + attr = attr->next; + } + + c = tree->child_list; + while(c) { + ts_text_save(c, fp); + } + + fprintf(fp, "%s}\n", indent(lvl)); +} + +static void print_attr(struct ts_attr *attr, FILE *fp, int level) +{ + fprintf(fp, "%s%s = ", indent(level + 1), attr->name); + print_value(&attr->val, fp); + fputc('\n', fp); +} + +static void print_value(struct ts_value *value, FILE *fp) +{ + int i; + + switch(value->type) { + case TS_NUMBER: + fprintf(fp, "%g", value->fnum); + break; + + case TS_VECTOR: + fputc('[', fp); + for(i=0; ivec_size; i++) { + if(i == 0) { + fprintf(fp, "%g", value->vec[i]); + } else { + fprintf(fp, ", %g", value->vec[i]); + } + } + fputc(']', fp); + break; + + case TS_ARRAY: + fputc('[', fp); + for(i=0; iarray_size; i++) { + if(i > 0) { + fprintf(fp, ", "); + } + print_value(value->array + i, fp); + } + fputc(']', fp); + break; + + default: + fputs(value->str, fp); + } +} + +static int tree_level(struct ts_node *n) +{ + if(!n->parent) return 0; + return tree_level(n->parent) + 1; +} + +static const char *indent(int x) +{ + static const char *buf = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + const char *end = buf + sizeof buf - 1; + return x > sizeof buf - 1 ? buf : end - x; +} diff -r e1a825be0eee -r 48d75df3ef04 src/treestore.c --- a/src/treestore.c Sat Apr 12 13:50:01 2014 +0300 +++ b/src/treestore.c Thu Nov 10 16:19:44 2016 +0200 @@ -1,8 +1,12 @@ #include #include #include +#include #include "treestore.h" +struct ts_node *ts_text_load(FILE *fp); +int ts_text_save(struct ts_node *tree, FILE *fp); + /* ---- ts_value implementation ---- */ int ts_init_value(struct ts_value *tsv) @@ -359,3 +363,106 @@ ts_free_node(tree); } + +void ts_add_attr(struct ts_node *node, struct ts_attr *attr) +{ + attr->next = 0; + if(node->attr_list) { + node->attr_tail->next = attr; + node->attr_tail = attr; + } else { + node->attr_list = node->attr_tail = attr; + } +} + +struct ts_attr *ts_get_attr(struct ts_node *node, const char *name) +{ + struct ts_attr *attr = node->attr_list; + while(attr) { + if(strcmp(attr->name, name) == 0) { + return attr; + } + attr = attr->next; + } + return 0; +} + +void ts_add_child(struct ts_node *node, struct ts_node *child) +{ + if(child->parent) { + if(child->parent == node) return; + ts_remove_child(child->parent, child); + } + child->parent = node; + child->next = 0; + + if(node->child_list) { + node->child_tail->next = child; + node->child_tail = child; + } else { + node->child_list = node->child_tail = child; + } +} + +int ts_remove_child(struct ts_node *node, struct ts_node *child) +{ + struct ts_node dummy, *iter = &dummy; + dummy.next = node->child_list; + + while(iter->next && iter->next != child) { + iter = iter->next; + } + if(!iter->next) { + return -1; + } + + child->parent = 0; + + iter->next = child->next; + if(!iter->next) { + node->child_tail = iter; + } + node->child_list = dummy.next; + return 0; +} + +struct ts_node *ts_get_child(struct ts_node *node, const char *name) +{ + struct ts_node *res = node->child_list; + while(res) { + if(strcmp(res->name, name) == 0) { + return res; + } + res = res->next; + } + return 0; +} + +struct ts_node *ts_load(const char *fname) +{ + FILE *fp; + struct ts_node *root; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "ts_load: failed to open file: %s: %s\n", fname, strerror(errno)); + return 0; + } + + root = ts_text_load(fp); + fclose(fp); + return root; +} + +int ts_save(struct ts_node *tree, const char *fname) +{ + FILE *fp; + int res; + + if(!(fp = fopen(fname, "wb"))) { + fprintf(stderr, "ts_save: failed to open file: %s: %s\n", fname, strerror(errno)); + return 0; + } + res = ts_text_save(tree, fp); + fclose(fp); + return res; +} diff -r e1a825be0eee -r 48d75df3ef04 src/treestore.h --- a/src/treestore.h Sat Apr 12 13:50:01 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -#ifndef TREESTORE_H_ -#define TREESTORE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -enum ts_value_type { TS_UNKNOWN, TS_NUMBER, TS_VECTOR, TS_ARRAY }; - -/** treestore node attribute value */ -struct ts_value { - enum ts_value_type type; - - char *str; /**< all values have a string representation */ - int inum; /**< numeric values (TS_INT/TS_FLOAT) will have this set */ - float fnum; /**< numeric values (TS_INT/TS_FLOAT) will have this set */ - - /** vector values (arrays containing ONLY numbers) will have this set */ - float *vec; /**< elements of the vector */ - int vec_size; /**< size of the vector (in elements), same as array_size */ - - /** array values (including vectors) will have this set */ - struct ts_value *array; /**< elements of the array */ - int array_size; /**< size of the array (in elements) */ -}; - -int ts_init_value(struct ts_value *tsv); -void ts_destroy_value(struct ts_value *tsv); - -struct ts_value *ts_alloc_value(void); /**< also calls ts_init_value */ -void ts_free_value(struct ts_value *tsv); /**< also calls ts_destroy_value */ - -/** perform a deep-copy of a ts_value */ -int ts_copy_value(struct ts_value *dest, struct ts_value *src); - -/** ts_set_value will try to parse the string and initialize the value type fields */ -int ts_set_value(struct ts_value *tsv, const char *str); - -/** set a ts_value from a list of integers */ -int ts_set_valueiv(struct ts_value *tsv, int count, ...); -int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap); -int ts_set_valuei(struct ts_value *tsv, int inum); /**< equiv: ts_set_valueiv(val, 1, inum) */ - -/** set a ts_value from a list of floats */ -int ts_set_valuefv(struct ts_value *tsv, int count, ...); -int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap); -int ts_set_valuef(struct ts_value *tsv, int fnum); /**< equiv: ts_set_valuefv(val, 1, fnum) */ - -/** set a ts_value from a list of ts_value pointers. they are deep-copied as per ts_copy_value */ -int ts_set_valuev(struct ts_value *tsv, int count, ...); -int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap); - - -/** treestore node attribute */ -struct ts_attr { - char *name; - struct ts_value val; - - struct ts_attr *next; -}; - -int ts_init_attr(struct ts_attr *attr); -void ts_destroy_attr(struct ts_attr *attr); - -struct ts_attr *ts_alloc_attr(void); /**< also calls ts_init_attr */ -void ts_free_attr(struct ts_attr *attr); /**< also calls ts_destroy_attr */ - -/** perform a deep-copy of a ts_attr */ -int ts_copy_attr(struct ts_attr *dest, struct ts_attr *src); - -int ts_set_attr_name(struct ts_attr *attr, const char *name); - - - -/** treestore node */ -struct ts_node { - char *name; - - int attr_count; - struct ts_attr *attr_list, *attr_tail; - - int child_count; - struct ts_node *child_list, *child_tail; - struct ts_node *parent; - - struct ts_node *next; /* next sibling */ -}; - -int ts_init_node(struct ts_node *node); -void ts_destroy_node(struct ts_node *node); - -struct ts_node *ts_alloc_node(void); /**< also calls ts_init_node */ -void ts_free_node(struct ts_node *n); /**< also calls ts_destroy_node */ - -void ts_free_tree(struct ts_node *tree); - -#ifdef __cplusplus -} -#endif - -#endif /* TREESTORE_H_ */ diff -r e1a825be0eee -r 48d75df3ef04 src/treestorepp.h --- a/src/treestorepp.h Sat Apr 12 13:50:01 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -#ifndef TREESTOREPP_H_ -#define TREESTOREPP_H_ - -#include "treestore.h" - -/// wraps a C ts_value in a convenient class -class TSValue { -private: - ts_value *ctsv; - -public: - TSValue(); - ~TSValue(); - - TSValue(const TSValue &tsv); - TSValue &operator =(const TSValue &tsv); - -#ifdef TS_USE_CPP11 - TSValue(const TSValue &&tsv); - TSValue &operator =(const TSValue &&tsv); -#endif - - bool set(const char *str); - bool set_int(int inum); - bool set_int(int count, ...); - bool set_float(float fnum); - bool set_float(int count, ...); - bool set_array(int count, const TSValue &v0, ...); - - const char *get() const; - - int get_int() const; - int *get_intv() const; - - float get_float() const; - float *get_floatv() const; - - const TSValue *get_array() const; - int get_array_size() const; - - int get_vec_size() const; //< equiv: get_array_size */ -}; - -#endif // TREESTOREPP_H_