libtreestore
changeset 0:740fec9866b1
treestore initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 11 Apr 2014 08:56:46 +0300 |
parents | |
children | a31eae25c0e6 |
files | .hgignore Makefile src/treestore.c src/treestore.h src/treestorepp.h src/xmltree.c src/xmltree.h |
diffstat | 7 files changed, 982 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Fri Apr 11 08:56:46 2014 +0300 1.3 @@ -0,0 +1,5 @@ 1.4 +\.o$ 1.5 +\.d$ 1.6 +\.swp$ 1.7 +\.so\. 1.8 +\.a$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Fri Apr 11 08:56:46 2014 +0300 2.3 @@ -0,0 +1,89 @@ 2.4 +PREFIX = /usr/local 2.5 + 2.6 +csrc = $(wildcard src/*.c) 2.7 +ccsrc = $(wildcard src/*.cc) 2.8 +cobj = $(csrc:.c=.o) 2.9 +ccobj = $(ccsrc:.cc=.o) 2.10 +obj = $(cobj) $(ccobj) 2.11 +dep = $(obj:.o=.d) 2.12 + 2.13 +cname = treestore 2.14 +ccname = treestorepp 2.15 + 2.16 +capi_major = 0 2.17 +capi_minor = 1 2.18 +ccapi_major = 0 2.19 +ccapi_minor = 1 2.20 + 2.21 +clib_a = lib$(cname).a 2.22 +cclib_a = lib$(ccname).a 2.23 + 2.24 +ifeq ($(shell uname -s), Darwin) 2.25 + clib_so = lib$(cname).dylib 2.26 + cclib_so = lib$(ccname).dylib 2.27 + cshared = -dynamiclib 2.28 + ccshared = -dynamiclib 2.29 +else 2.30 + clib_so = lib$(cname).so.$(capi_major).$(capi_minor) 2.31 + csoname = lib$(cname).so.$(capi_major) 2.32 + cdevlink = lib$(cname).so 2.33 + cclib_so = lib$(ccname).so.$(ccapi_major).$(ccapi_minor) 2.34 + ccsoname = lib$(ccname).so.$(ccapi_major) 2.35 + ccdevlink = lib$(ccname).so 2.36 + 2.37 + cshared = -shared -Wl,-soname=$(csoname) 2.38 + ccshared = -shared -Wl,-soname=$(ccsoname) 2.39 + pic = -fPIC 2.40 +endif 2.41 + 2.42 +dbg = -g 2.43 +cxx11 = -std=c++11 -DTS_USE_CPP11 2.44 + 2.45 +CFLAGS = -pedantic -Wall $(dbg) $(opt) $(pic) 2.46 +CXXFLAGS = $(cxx11) $(CFLAGS) 2.47 + 2.48 +.PHONY: all 2.49 +all: $(clib_so) $(clib_a) $(cclib_so) $(cclib_a) 2.50 + 2.51 +$(clib_a): $(cobj) 2.52 + $(AR) rcs $@ $(cobj) 2.53 + 2.54 +$(clib_so): $(cobj) 2.55 + $(CC) -o $@ $(cshared) $(cobj) $(LDFLAGS) 2.56 + 2.57 +$(cclib_a): $(ccobj) 2.58 + $(AR) rcs $@ $(ccobj) 2.59 + 2.60 +$(cclib_so): $(ccobj) 2.61 + $(CXX) -o $@ $(ccshared) $(ccobj) $(LDFLAGS) 2.62 + 2.63 +-include $(dep) 2.64 + 2.65 +%.d: %.c 2.66 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 2.67 + 2.68 +%.d: %.cc 2.69 + @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ 2.70 + 2.71 +.PHONY: clean 2.72 +clean: 2.73 + rm -f $(obj) $(clib_so) $(cclib_so) $(clib_a) $(cclib_a) 2.74 + 2.75 +.PHONY: cleandep 2.76 +cleandep: clean 2.77 + rm -f $(dep) 2.78 + 2.79 + 2.80 +.PHONY: install 2.81 +install: all 2.82 + mkdir -p $(DESTDIR)$(PREFIX)/include $(DESTDIR)$(PREFIX)/lib 2.83 + cp src/treestore.h src/treestorepp.h $(DESTDIR)$(PREFIX)/include 2.84 + cp $(clib_a) $(clib_so) $(cclib_a) $(cclib_so) $(DESTDIR)$(PREFIX)/lib 2.85 + [ -n "$(csoname)" ] && \ 2.86 + cd $(DESTDIR)$(PREFIX) && \ 2.87 + rm -f $(csoname) $(cdevlink) $(ccsoname) $(ccdevlink) && \ 2.88 + ln -s $(clib_so) $(csoname) && \ 2.89 + ln -s $(cclib_so) $(ccsoname) && \ 2.90 + ln -s $(csoname) $(cdevlink) && \ 2.91 + ln -s $(ccsoname) $(ccdevlink) || \ 2.92 + true
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/treestore.c Fri Apr 11 08:56:46 2014 +0300 3.3 @@ -0,0 +1,245 @@ 3.4 +#include <stdio.h> 3.5 +#include <stdlib.h> 3.6 +#include <string.h> 3.7 +#include "treestore.h" 3.8 + 3.9 +/* ---- ts_value implementation ---- */ 3.10 + 3.11 +int ts_init_value(struct ts_value *tsv) 3.12 +{ 3.13 + memset(tsv, 0, sizeof *tsv); 3.14 + return 0; 3.15 +} 3.16 + 3.17 +void ts_destroy_value(struct ts_value *tsv) 3.18 +{ 3.19 + int i; 3.20 + 3.21 + free(tsv->str); 3.22 + free(tsv->vec); 3.23 + 3.24 + for(i=0; i<tsv->array_size; i++) { 3.25 + ts_destroy_value(tsv->array + i); 3.26 + } 3.27 +} 3.28 + 3.29 + 3.30 +struct ts_value *ts_alloc_value(void) 3.31 +{ 3.32 + struct ts_value *v = malloc(sizeof *v); 3.33 + if(!v || ts_init_value(v) == -1) { 3.34 + free(v); 3.35 + return 0; 3.36 + } 3.37 + return v; 3.38 +} 3.39 + 3.40 +void ts_free_value(struct ts_value *tsv) 3.41 +{ 3.42 + ts_destroy_value(tsv); 3.43 + free(tsv); 3.44 +} 3.45 + 3.46 + 3.47 +int ts_copy_value(struct ts_value *dest, struct ts_value *src) 3.48 +{ 3.49 + int i; 3.50 + 3.51 + if(dest == src) return 0; 3.52 + 3.53 + *dest = *src; 3.54 + 3.55 + dest->str = 0; 3.56 + dest->vec = 0; 3.57 + dest->array = 0; 3.58 + 3.59 + if(src->str) { 3.60 + if(!(dest->str = malloc(strlen(src->str) + 1))) { 3.61 + goto fail; 3.62 + } 3.63 + strcpy(dest->str, src->str); 3.64 + } 3.65 + if(src->vec && src->vec_size > 0) { 3.66 + if(!(dest->vec = malloc(src->vec_size * sizeof *src->vec))) { 3.67 + goto fail; 3.68 + } 3.69 + memcpy(dest->vec, src->vec, src->vec_size * sizeof *src->vec); 3.70 + } 3.71 + if(src->array && src->array_size > 0) { 3.72 + if(!(dest->array = calloc(src->array_size, sizeof *src->array))) { 3.73 + goto fail; 3.74 + } 3.75 + for(i=0; i<src->array_size; i++) { 3.76 + if(ts_copy_value(dest->array + i, src->array + i) == -1) { 3.77 + goto fail; 3.78 + } 3.79 + } 3.80 + } 3.81 + return 0; 3.82 + 3.83 +fail: 3.84 + free(dest->str); 3.85 + free(dest->vec); 3.86 + if(dest->array) { 3.87 + for(i=0; i<dest->array_size; i++) { 3.88 + ts_destroy_value(dest->array + i); 3.89 + } 3.90 + free(dest->array); 3.91 + } 3.92 + return -1; 3.93 +} 3.94 + 3.95 + 3.96 +int ts_set_value(struct ts_value *tsv, const char *str) 3.97 +{ 3.98 + if(tsv->str) { 3.99 + ts_destroy_value(tsv); 3.100 + if(ts_init_value(tsv) == -1) { 3.101 + return -1; 3.102 + } 3.103 + } 3.104 + 3.105 + if(!(tsv->str = malloc(strlen(str) + 1))) { 3.106 + return -1; 3.107 + } 3.108 + strcpy(tsv->str, str); 3.109 + return 0; 3.110 +} 3.111 + 3.112 +int ts_set_valueiv(struct ts_value *tsv, int count, ...) 3.113 +{ 3.114 + int res; 3.115 + va_list ap; 3.116 + va_start(ap, count); 3.117 + res = ts_set_valueiv_va(tsv, count, ap); 3.118 + va_end(ap); 3.119 + return res; 3.120 +} 3.121 + 3.122 +#define MAKE_NUMSTR_FUNC(typestr, fmt) \ 3.123 + static char *make_##typestr##str(int x) \ 3.124 + { \ 3.125 + static char scrap[128]; \ 3.126 + char *str; \ 3.127 + int sz = snprintf(scrap, sizeof scrap, fmt, x); \ 3.128 + if(!(str = malloc(sz + 1))) return 0; \ 3.129 + sprintf(str, fmt, x); \ 3.130 + return str; \ 3.131 + } 3.132 + 3.133 +MAKE_NUMSTR_FUNC(int, "%d") 3.134 +MAKE_NUMSTR_FUNC(float, "%d") 3.135 + 3.136 +#define ARGS_ARE_INT ((enum ts_value_type)42) 3.137 + 3.138 +int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap) 3.139 +{ 3.140 + if(count < 1) return -1; 3.141 + if(count == 1) { 3.142 + int num = va_arg(ap, int); 3.143 + if(!(tsv->str = make_intstr(tsv->inum))) { 3.144 + return -1; 3.145 + } 3.146 + 3.147 + tsv->type = TS_NUMBER; 3.148 + tsv->inum = num; 3.149 + tsv->fnum = (float)num; 3.150 + return 0; 3.151 + } 3.152 + 3.153 + /* otherwise it's an array, let ts_set_valuefv_va handle it */ 3.154 + /* XXX: va_arg will need to be called with int instead of float. set a special 3.155 + * value to the type field before calling this, to signify that. 3.156 + */ 3.157 + tsv->type = ARGS_ARE_INT; 3.158 + return ts_set_valuefv_va(tsv, count, ap); 3.159 +} 3.160 + 3.161 +int ts_set_valuei(struct ts_value *tsv, int inum) 3.162 +{ 3.163 + return ts_set_valueiv(tsv, 1, inum); 3.164 +} 3.165 + 3.166 + 3.167 +int ts_set_valuefv(struct ts_value *tsv, int count, ...) 3.168 +{ 3.169 + int res; 3.170 + va_list ap; 3.171 + va_start(ap, count); 3.172 + res = ts_set_valuefv_va(tsv, count, ap); 3.173 + va_end(ap); 3.174 + return res; 3.175 +} 3.176 + 3.177 +int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap) 3.178 +{ 3.179 + int i; 3.180 + 3.181 + if(count < 1) return -1; 3.182 + if(count == 1) { 3.183 + int num = va_arg(ap, int); 3.184 + if(!(tsv->str = make_floatstr(tsv->inum))) { 3.185 + return -1; 3.186 + } 3.187 + 3.188 + tsv->type = TS_NUMBER; 3.189 + tsv->inum = num; 3.190 + tsv->fnum = (float)num; 3.191 + return 0; 3.192 + } 3.193 + 3.194 + /* otherwise it's an array, we need to create the ts_value array, and 3.195 + * the simplified vector 3.196 + */ 3.197 + if(!(tsv->vec = malloc(count * sizeof *tsv->vec))) { 3.198 + return -1; 3.199 + } 3.200 + tsv->vec_size = count; 3.201 + 3.202 + for(i=0; i<count; i++) { 3.203 + if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */ 3.204 + tsv->vec[i] = (float)va_arg(ap, int); 3.205 + } else { 3.206 + tsv->vec[i] = va_arg(ap, double); 3.207 + } 3.208 + } 3.209 + 3.210 + if(!(tsv->array = malloc(count * sizeof *tsv->array))) { 3.211 + free(tsv->vec); 3.212 + } 3.213 + tsv->array_size = count; 3.214 + 3.215 + for(i=0; i<count; i++) { 3.216 + ts_init_value(tsv->array + i); 3.217 + if(tsv->type == ARGS_ARE_INT) { /* only when called by ts_set_valueiv_va */ 3.218 + ts_set_valuei(tsv->array + i, (int)tsv->vec[i]); 3.219 + } else { 3.220 + ts_set_valuef(tsv->array + i, tsv->vec[i]); 3.221 + } 3.222 + } 3.223 + 3.224 + tsv->type = TS_VECTOR; 3.225 + return 0; 3.226 +} 3.227 + 3.228 +int ts_set_valuef(struct ts_value *tsv, int fnum) 3.229 +{ 3.230 + return ts_set_valuefv(tsv, 1, fnum); 3.231 +} 3.232 + 3.233 + 3.234 +int ts_set_valuev(struct ts_value *tsv, int count, ...) 3.235 +{ 3.236 + int res; 3.237 + va_list ap; 3.238 + va_start(ap, count); 3.239 + res = ts_set_valuev_va(tsv, count, ap); 3.240 + va_end(ap); 3.241 + return res; 3.242 +} 3.243 + 3.244 +int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap) 3.245 +{ 3.246 + if(count <= 1) return -1; 3.247 + return -1; /* TODO */ 3.248 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/treestore.h Fri Apr 11 08:56:46 2014 +0300 4.3 @@ -0,0 +1,88 @@ 4.4 +#ifndef TREESTORE_H_ 4.5 +#define TREESTORE_H_ 4.6 + 4.7 +#include <stdarg.h> 4.8 + 4.9 +#ifdef __cplusplus 4.10 +extern "C" { 4.11 +#endif 4.12 + 4.13 +enum ts_value_type { TS_UNKNOWN, TS_NUMBER, TS_VECTOR, TS_ARRAY }; 4.14 + 4.15 +/** treestore node attribute value */ 4.16 +struct ts_value { 4.17 + enum ts_value_type type; 4.18 + 4.19 + char *str; /**< all values have a string representation */ 4.20 + int inum; /**< numeric values (TS_INT/TS_FLOAT) will have this set */ 4.21 + float fnum; /**< numeric values (TS_INT/TS_FLOAT) will have this set */ 4.22 + 4.23 + /** vector values (arrays containing ONLY numbers) will have this set */ 4.24 + float *vec; /**< elements of the vector */ 4.25 + int vec_size; /**< size of the vector (in elements), same as array_size */ 4.26 + 4.27 + /** array values (including vectors) will have this set */ 4.28 + struct ts_value *array; /**< elements of the array */ 4.29 + int array_size; /**< size of the array (in elements) */ 4.30 +}; 4.31 + 4.32 +int ts_init_value(struct ts_value *tsv); 4.33 +void ts_destroy_value(struct ts_value *tsv); 4.34 + 4.35 +struct ts_value *ts_alloc_value(void); /**< also calls ts_init_value */ 4.36 +void ts_free_value(struct ts_value *tsv); /**< also calls ts_destroy_value */ 4.37 + 4.38 +/** perform a deep-copy of a ts_value */ 4.39 +int ts_copy_value(struct ts_value *dest, struct ts_value *src); 4.40 + 4.41 +/** ts_set_value will try to parse the string and initialize the value type fields */ 4.42 +int ts_set_value(struct ts_value *tsv, const char *str); 4.43 + 4.44 +/** set a ts_value from a list of integers */ 4.45 +int ts_set_valueiv(struct ts_value *tsv, int count, ...); 4.46 +int ts_set_valueiv_va(struct ts_value *tsv, int count, va_list ap); 4.47 +int ts_set_valuei(struct ts_value *tsv, int inum); /**< equiv: ts_set_valueiv(val, 1, inum) */ 4.48 + 4.49 +/** set a ts_value from a list of floats */ 4.50 +int ts_set_valuefv(struct ts_value *tsv, int count, ...); 4.51 +int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap); 4.52 +int ts_set_valuef(struct ts_value *tsv, int fnum); /**< equiv: ts_set_valuefv(val, 1, fnum) */ 4.53 + 4.54 +/** set a ts_value from a list of ts_value pointers. they are deep-copied as per ts_copy_value */ 4.55 +int ts_set_valuev(struct ts_value *tsv, int count, ...); 4.56 +int ts_set_valuev_va(struct ts_value *tsv, int count, va_list ap); 4.57 + 4.58 + 4.59 +/** treestore node attribute */ 4.60 +struct ts_attr { 4.61 + char *name; 4.62 + 4.63 + struct ts_value val; 4.64 + 4.65 + struct ts_attr *next; 4.66 +}; 4.67 + 4.68 + 4.69 +/** treestore node */ 4.70 +struct ts_node { 4.71 + char *name; 4.72 + 4.73 + int attr_count; 4.74 + struct ts_attr *attr_list, *attr_tail; 4.75 + 4.76 + int child_count; 4.77 + struct ts_node *child_list, *child_tail; 4.78 + struct ts_node *parent; 4.79 + 4.80 + struct ts_node *next; /* next sibling */ 4.81 +}; 4.82 + 4.83 +struct ts_node *ts_create_node(void); 4.84 +void ts_free_node(struct ts_node *n); 4.85 +void ts_free_tree(struct ts_node *tree); 4.86 + 4.87 +#ifdef __cplusplus 4.88 +} 4.89 +#endif 4.90 + 4.91 +#endif /* TREESTORE_H_ */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/treestorepp.h Fri Apr 11 08:56:46 2014 +0300 5.3 @@ -0,0 +1,44 @@ 5.4 +#ifndef TREESTOREPP_H_ 5.5 +#define TREESTOREPP_H_ 5.6 + 5.7 +#include "treestore.h" 5.8 + 5.9 +/// wraps a C ts_value in a convenient class 5.10 +class TSValue { 5.11 +private: 5.12 + ts_value *ctsv; 5.13 + 5.14 +public: 5.15 + TSValue(); 5.16 + ~TSValue(); 5.17 + 5.18 + TSValue(const TSValue &tsv); 5.19 + TSValue &operator =(const TSValue &tsv); 5.20 + 5.21 +#ifdef TS_USE_CPP11 5.22 + TSValue(const TSValue &&tsv); 5.23 + TSValue &operator =(const TSValue &&tsv); 5.24 +#endif 5.25 + 5.26 + bool set(const char *str); 5.27 + bool set_int(int inum); 5.28 + bool set_int(int count, ...); 5.29 + bool set_float(float fnum); 5.30 + bool set_float(int count, ...); 5.31 + bool set_array(int count, const TSValue &v0, ...); 5.32 + 5.33 + const char *get() const; 5.34 + 5.35 + int get_int() const; 5.36 + int *get_intv() const; 5.37 + 5.38 + float get_float() const; 5.39 + float *get_floatv() const; 5.40 + 5.41 + const TSValue *get_array() const; 5.42 + int get_array_size() const; 5.43 + 5.44 + int get_vec_size() const; //< equiv: get_array_size */ 5.45 +}; 5.46 + 5.47 +#endif // TREESTOREPP_H_
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/xmltree.c Fri Apr 11 08:56:46 2014 +0300 6.3 @@ -0,0 +1,448 @@ 6.4 +/* 6.5 +This file is part of the s-ray renderer <http://code.google.com/p/sray>. 6.6 +Copyright (C) 2009 John Tsiombikas <nuclear@member.fsf.org> 6.7 + 6.8 +This program is free software: you can redistribute it and/or modify 6.9 +it under the terms of the GNU General Public License as published by 6.10 +the Free Software Foundation, either version 3 of the License, or 6.11 +(at your option) any later version. 6.12 + 6.13 +This program is distributed in the hope that it will be useful, 6.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 6.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6.16 +GNU General Public License for more details. 6.17 + 6.18 +You should have received a copy of the GNU General Public License 6.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 6.20 +*/ 6.21 +/* TODO list 6.22 + * - fix cdata handling. make a nodes's cdata into a number of ordered children 6.23 + */ 6.24 +#include <stdio.h> 6.25 +#include <stdlib.h> 6.26 +#include <string.h> 6.27 +#include <ctype.h> 6.28 +#include <assert.h> 6.29 +#include <expat.h> 6.30 +#include "xmltree.h" 6.31 + 6.32 +#ifdef _MSC_VER 6.33 +typedef int ssize_t; 6.34 +#endif 6.35 + 6.36 +struct parse_data { 6.37 + XML_Parser parser; 6.38 + struct xml_node *cur_node; 6.39 + 6.40 + char *buf; 6.41 + int buf_size; 6.42 +}; 6.43 + 6.44 +static void start(void *udata, const char *name, const char **atts); 6.45 +static void end(void *udata, const char *name); 6.46 +static void cdata(void *udata, const char *text, int len); 6.47 +static void finish_cdata(struct parse_data *pdata); 6.48 +static void abort_parsing(XML_Parser p); 6.49 +static int write_rec(struct xml_node *x, FILE *fp, int lvl); 6.50 + 6.51 +#define IND_SPACES 4 6.52 +static void indent(FILE *fp, int lvl); 6.53 + 6.54 +struct xml_attr *xml_create_attr(const char *name, const char *val) 6.55 +{ 6.56 + struct xml_attr *attr; 6.57 + 6.58 + if(!(attr = malloc(sizeof *attr))) { 6.59 + return 0; 6.60 + } 6.61 + memset(attr, 0, sizeof *attr); 6.62 + 6.63 + if(name) { 6.64 + if(!(attr->name = malloc(strlen(name) + 1))) { 6.65 + free(attr); 6.66 + return 0; 6.67 + } 6.68 + strcpy(attr->name, name); 6.69 + } 6.70 + 6.71 + if(val) { 6.72 + if(!(attr->str = malloc(strlen(val) + 1))) { 6.73 + free(attr->name); 6.74 + free(attr); 6.75 + return 0; 6.76 + } 6.77 + strcpy(attr->str, val); 6.78 + 6.79 + if(isdigit(val[0]) || ((val[0] == '+' || val[0] == '-') && isdigit(val[1]))) { 6.80 + int i; 6.81 + attr->type = strchr(val, '.') ? ATYPE_FLT : ATYPE_INT; 6.82 + attr->ival = atoi(val); 6.83 + attr->fval = atof(val); 6.84 + 6.85 + attr->vval[0] = attr->vval[1] = attr->vval[2] = attr->vval[3] = 1.0; 6.86 + 6.87 + for(i=0; i<4; i++) { 6.88 + if(!*val) break; 6.89 + attr->vval[i] = atof(val); 6.90 + 6.91 + while(*val && !isspace(*val)) val++; 6.92 + while(*val && isspace(*val)) val++; 6.93 + } 6.94 + 6.95 + if(i > 1) { 6.96 + attr->type = ATYPE_VEC; 6.97 + } 6.98 + } 6.99 + } 6.100 + 6.101 + return attr; 6.102 +} 6.103 + 6.104 +void xml_free_attr(struct xml_attr *attr) 6.105 +{ 6.106 + free(attr->name); 6.107 + free(attr->str); 6.108 + free(attr); 6.109 +} 6.110 + 6.111 +void xml_free_attr_list(struct xml_attr *alist) 6.112 +{ 6.113 + while(alist) { 6.114 + struct xml_attr *tmp = alist; 6.115 + alist = alist->next; 6.116 + 6.117 + xml_free_attr(tmp); 6.118 + } 6.119 +} 6.120 + 6.121 +struct xml_attr *xml_get_attr(struct xml_node *node, const char *attr_name) 6.122 +{ 6.123 + struct xml_attr *attr; 6.124 + 6.125 + attr = node->attr; 6.126 + while(attr) { 6.127 + if(strcmp(attr->name, attr_name) == 0) { 6.128 + return attr; 6.129 + } 6.130 + attr = attr->next; 6.131 + } 6.132 + return 0; 6.133 +} 6.134 + 6.135 +struct xml_node *xml_create_tree(void) 6.136 +{ 6.137 + struct xml_node *x; 6.138 + 6.139 + if(!(x = malloc(sizeof *x))) { 6.140 + return 0; 6.141 + } 6.142 + memset(x, 0, sizeof *x); 6.143 + 6.144 + return x; 6.145 +} 6.146 + 6.147 +void xml_free_tree(struct xml_node *x) 6.148 +{ 6.149 + while(x->chld) { 6.150 + void *tmp = x->chld; 6.151 + 6.152 + x->chld = x->chld->next; 6.153 + xml_free_tree(tmp); 6.154 + } 6.155 + 6.156 + while(x->attr) { 6.157 + struct xml_attr *tmp = x->attr; 6.158 + x->attr = x->attr->next; 6.159 + 6.160 + free(tmp->name); 6.161 + free(tmp->str); 6.162 + free(tmp); 6.163 + } 6.164 + 6.165 + free(x->cdata); 6.166 + free(x->name); 6.167 + free(x); 6.168 +} 6.169 + 6.170 +struct xml_node *xml_read_tree(const char *fname) 6.171 +{ 6.172 + FILE *fp; 6.173 + struct xml_node *xml; 6.174 + 6.175 + if(!(fp = fopen(fname, "rb"))) { 6.176 + return 0; 6.177 + } 6.178 + xml = xml_read_tree_file(fp); 6.179 + fclose(fp); 6.180 + return xml; 6.181 +} 6.182 + 6.183 +struct xml_node *xml_read_tree_file(FILE *fp) 6.184 +{ 6.185 + struct parse_data pdata; 6.186 + struct xml_node node, *tree; 6.187 + XML_Parser p; 6.188 + ssize_t rdsz; 6.189 + void *buf; 6.190 + 6.191 + memset(&node, 0, sizeof node); 6.192 + 6.193 + if(!(p = XML_ParserCreate(0))) { 6.194 + return 0; 6.195 + } 6.196 + XML_SetElementHandler(p, start, end); 6.197 + XML_SetCharacterDataHandler(p, cdata); 6.198 + XML_SetUserData(p, &pdata); 6.199 + 6.200 + memset(&pdata, 0, sizeof pdata); 6.201 + pdata.parser = p; 6.202 + pdata.cur_node = &node; 6.203 + 6.204 + do { 6.205 + if(!(buf = XML_GetBuffer(p, 4096))) { 6.206 + break; 6.207 + } 6.208 + 6.209 + if((rdsz = fread(buf, 1, 4096, fp)) == -1) { 6.210 + break; 6.211 + } 6.212 + 6.213 + if(!XML_ParseBuffer(p, rdsz, rdsz < 4096)) { 6.214 + fprintf(stderr, "XML parsing error: %d: %s\n", (int)XML_GetCurrentLineNumber(p), 6.215 + XML_ErrorString(XML_GetErrorCode(p))); 6.216 + break; 6.217 + } 6.218 + } while(rdsz == 4096); 6.219 + 6.220 + tree = node.chld; 6.221 + if(tree) { 6.222 + assert(tree->next == 0); 6.223 + } 6.224 + 6.225 + if(pdata.cur_node != &node) { /* aborted */ 6.226 + xml_free_tree(tree); 6.227 + tree = 0; 6.228 + } 6.229 + 6.230 + if(pdata.buf) { 6.231 + free(pdata.buf); 6.232 + } 6.233 + 6.234 + XML_ParserFree(p); 6.235 + return tree; 6.236 +} 6.237 + 6.238 +static void start(void *udata, const char *name, const char **atts) 6.239 +{ 6.240 + struct xml_node *node = 0; 6.241 + struct parse_data *pdata = udata; 6.242 + 6.243 + finish_cdata(pdata); 6.244 + 6.245 + if(!(node = malloc(sizeof *node))) { 6.246 + goto err; 6.247 + } 6.248 + memset(node, 0, sizeof *node); 6.249 + 6.250 + if(!(node->name = malloc(strlen(name) + 1))) { 6.251 + goto err; 6.252 + } 6.253 + strcpy(node->name, name); 6.254 + 6.255 + while(*atts) { 6.256 + struct xml_attr *attr; 6.257 + 6.258 + if(!(attr = xml_create_attr(atts[0], atts[1]))) { 6.259 + goto err; 6.260 + } 6.261 + attr->next = node->attr; 6.262 + node->attr = attr; 6.263 + 6.264 + atts += 2; 6.265 + } 6.266 + 6.267 + xml_add_child(pdata->cur_node, node); 6.268 + pdata->cur_node = node; 6.269 + return; 6.270 + 6.271 +err: 6.272 + if(node) { 6.273 + free(node->name); 6.274 + xml_free_attr_list(node->attr); 6.275 + } 6.276 + free(node); 6.277 + abort_parsing(pdata->parser); 6.278 +} 6.279 + 6.280 +static void end(void *udata, const char *name) 6.281 +{ 6.282 + struct parse_data *pdata = udata; 6.283 + 6.284 + finish_cdata(pdata); 6.285 + 6.286 + pdata->cur_node = pdata->cur_node->up; 6.287 +} 6.288 + 6.289 +static void cdata(void *udata, const char *text, int len) 6.290 +{ 6.291 + char *tmp; 6.292 + struct parse_data *pdata = udata; 6.293 + 6.294 + if(!(tmp = realloc(pdata->buf, pdata->buf_size + len))) { 6.295 + abort_parsing(pdata->parser); 6.296 + return; 6.297 + } 6.298 + memcpy(tmp + pdata->buf_size, text, len); 6.299 + pdata->buf = tmp; 6.300 + pdata->buf_size += len; 6.301 +} 6.302 + 6.303 +static void finish_cdata(struct parse_data *pdata) 6.304 +{ 6.305 + char *tmp; 6.306 + 6.307 + if(!pdata->buf) { 6.308 + return; 6.309 + } 6.310 + 6.311 + if(!(tmp = realloc(pdata->buf, pdata->buf_size + 1))) { 6.312 + abort_parsing(pdata->parser); 6.313 + return; 6.314 + } 6.315 + tmp[pdata->buf_size] = 0; 6.316 + pdata->cur_node->cdata = tmp; 6.317 + 6.318 + pdata->buf = 0; 6.319 + pdata->buf_size = 0; 6.320 +} 6.321 + 6.322 +static void abort_parsing(XML_Parser p) 6.323 +{ 6.324 + perror("abort XML parsing"); 6.325 + 6.326 + XML_SetElementHandler(p, 0, 0); 6.327 + XML_SetCharacterDataHandler(p, 0); 6.328 + XML_StopParser(p, 0); 6.329 +} 6.330 + 6.331 +int xml_write_tree(struct xml_node *x, const char *fname) 6.332 +{ 6.333 + FILE *fp; 6.334 + int res; 6.335 + 6.336 + if(!(fp = fopen(fname, "wb"))) { 6.337 + return -1; 6.338 + } 6.339 + res = xml_write_tree_file(x, fp); 6.340 + fclose(fp); 6.341 + return res; 6.342 +} 6.343 + 6.344 +int xml_write_tree_file(struct xml_node *x, FILE *fp) 6.345 +{ 6.346 + return write_rec(x, fp, 0); 6.347 +} 6.348 + 6.349 +static int write_rec(struct xml_node *x, FILE *fp, int lvl) 6.350 +{ 6.351 + struct xml_node *c; 6.352 + struct xml_attr *attr; 6.353 + 6.354 + indent(fp, lvl); 6.355 + fputc('<', fp); 6.356 + fputs(x->name, fp); 6.357 + 6.358 + attr = x->attr; 6.359 + while(attr) { 6.360 + switch(attr->type) { 6.361 + case ATYPE_INT: 6.362 + fprintf(fp, " %s=\"%d\"", attr->name, attr->ival); 6.363 + break; 6.364 + 6.365 + case ATYPE_FLT: 6.366 + fprintf(fp, " %s=\"%.4f\"", attr->name, attr->fval); 6.367 + break; 6.368 + 6.369 + case ATYPE_VEC: 6.370 + fprintf(fp, " %s=\"%.4f %.4f %.4f %.4f\"", attr->name, attr->vval[0], 6.371 + attr->vval[1], attr->vval[2], attr->vval[3]); 6.372 + break; 6.373 + 6.374 + case ATYPE_STR: 6.375 + default: 6.376 + fprintf(fp, " %s=\"%s\"", attr->name, attr->str); 6.377 + break; 6.378 + } 6.379 + 6.380 + attr = attr->next; 6.381 + } 6.382 + 6.383 + if(!x->chld && !x->cdata) { 6.384 + fputc('/', fp); 6.385 + } 6.386 + fprintf(fp, ">\n"); 6.387 + 6.388 + if(x->cdata) { 6.389 + indent(fp, lvl + 1); 6.390 + fprintf(fp, "%s\n", x->cdata); 6.391 + } 6.392 + 6.393 + c = x->chld; 6.394 + while(c) { 6.395 + write_rec(c, fp, lvl + 1); 6.396 + c = c->next; 6.397 + } 6.398 + 6.399 + if(x->chld || x->cdata) { 6.400 + indent(fp, lvl); 6.401 + fprintf(fp, "</%s>\n", x->name); 6.402 + } 6.403 + return 0; 6.404 +} 6.405 + 6.406 +void xml_add_child(struct xml_node *x, struct xml_node *chld) 6.407 +{ 6.408 + chld->next = 0; 6.409 + 6.410 + if(x->chld) { 6.411 + x->chld_tail->next = chld; 6.412 + x->chld_tail = chld; 6.413 + } else { 6.414 + x->chld = x->chld_tail = chld; 6.415 + } 6.416 + 6.417 + chld->up = x; 6.418 + x->chld_count++; 6.419 +} 6.420 + 6.421 +void xml_remove_subtree(struct xml_node *sub) 6.422 +{ 6.423 + struct xml_node *x; 6.424 + 6.425 + if(sub->up) { 6.426 + x = sub->up->chld; 6.427 + if(x == sub) { 6.428 + sub->up->chld = sub->next; 6.429 + } else { 6.430 + while(x) { 6.431 + if(x->next == sub) { 6.432 + x->next = x->next->next; 6.433 + break; 6.434 + } 6.435 + x = x->next; 6.436 + } 6.437 + } 6.438 + } 6.439 + 6.440 + sub->up->chld_count--; 6.441 + sub->up = 0; 6.442 +} 6.443 + 6.444 +static void indent(FILE *fp, int lvl) 6.445 +{ 6.446 + int i, ind = lvl * IND_SPACES; 6.447 + 6.448 + for(i=0; i<ind; i++) { 6.449 + fputc(' ', fp); 6.450 + } 6.451 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/xmltree.h Fri Apr 11 08:56:46 2014 +0300 7.3 @@ -0,0 +1,63 @@ 7.4 +#ifndef COMMON_XMLTREE_H_ 7.5 +#define COMMON_XMLTREE_H_ 7.6 + 7.7 +#include <stdio.h> 7.8 + 7.9 +enum { 7.10 + ATYPE_STR, 7.11 + ATYPE_INT, 7.12 + ATYPE_FLT, 7.13 + ATYPE_VEC 7.14 +}; 7.15 + 7.16 +struct xml_attr { 7.17 + char *name; 7.18 + char *str; 7.19 + 7.20 + int type; 7.21 + int ival; 7.22 + float fval; 7.23 + float vval[4]; 7.24 + 7.25 + struct xml_attr *next; 7.26 +}; 7.27 + 7.28 +struct xml_node { 7.29 + char *name; 7.30 + char *cdata; 7.31 + struct xml_attr *attr; /* attribute list */ 7.32 + 7.33 + int chld_count; 7.34 + 7.35 + struct xml_node *up; /* parent pointer */ 7.36 + struct xml_node *chld, *chld_tail; /* children list */ 7.37 + struct xml_node *next; /* next sibling */ 7.38 +}; 7.39 + 7.40 +#ifdef __cplusplus 7.41 +extern "C" { 7.42 +#endif 7.43 + 7.44 +struct xml_attr *xml_create_attr(const char *name, const char *val); 7.45 +void xml_free_attr(struct xml_attr *attr); 7.46 +void xml_free_attr_list(struct xml_attr *alist); 7.47 + 7.48 +struct xml_attr *xml_get_attr(struct xml_node *node, const char *attr_name); 7.49 + 7.50 +struct xml_node *xml_create_tree(void); 7.51 +void xml_free_tree(struct xml_node *x); 7.52 + 7.53 +struct xml_node *xml_read_tree(const char *fname); 7.54 +struct xml_node *xml_read_tree_file(FILE *fp); 7.55 + 7.56 +int xml_write_tree(struct xml_node *x, const char *fname); 7.57 +int xml_write_tree_file(struct xml_node *x, FILE *fp); 7.58 + 7.59 +void xml_add_child(struct xml_node *x, struct xml_node *chld); 7.60 +void xml_remove_subtree(struct xml_node *sub); 7.61 + 7.62 +#ifdef __cplusplus 7.63 +} 7.64 +#endif 7.65 + 7.66 +#endif /* COMMON_XMLTREE_H_ */