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_ */