libtreestore
changeset 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 |
files | CMakeLists.txt include/treestore.h src/text.c src/treestore.c |
diffstat | 4 files changed, 251 insertions(+), 58 deletions(-) [+] |
line diff
1.1 --- a/CMakeLists.txt Thu Nov 10 16:19:44 2016 +0200 1.2 +++ b/CMakeLists.txt Sun Nov 13 19:46:01 2016 +0200 1.3 @@ -23,6 +23,9 @@ 1.4 target_include_directories(treestore PUBLIC include) 1.5 target_include_directories(treestore-static PUBLIC include) 1.6 1.7 +target_link_libraries(treestore -lexpat) 1.8 +target_link_libraries(treestore-static -lexpat) 1.9 + 1.10 install(TARGETS treestore 1.11 RUNTIME DESTINATION bin 1.12 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
2.1 --- a/include/treestore.h Thu Nov 10 16:19:44 2016 +0200 2.2 +++ b/include/treestore.h Sun Nov 13 19:46:01 2016 +0200 2.3 @@ -4,18 +4,21 @@ 2.4 #include <stdarg.h> 2.5 2.6 #ifdef __cplusplus 2.7 +#define TS_DEFVAL(x) =(x) 2.8 extern "C" { 2.9 +#else 2.10 +#define TS_DEFVAL(x) 2.11 #endif 2.12 2.13 -enum ts_value_type { TS_UNKNOWN, TS_NUMBER, TS_VECTOR, TS_ARRAY }; 2.14 +enum ts_value_type { TS_STRING, TS_NUMBER, TS_VECTOR, TS_ARRAY }; 2.15 2.16 /** treestore node attribute value */ 2.17 struct ts_value { 2.18 enum ts_value_type type; 2.19 2.20 - char *str; /**< all values have a string representation */ 2.21 - int inum; /**< numeric values TS_NUMBER will have this set */ 2.22 - float fnum; /**< numeric values TS_NUMBER will have this set */ 2.23 + char *str; /**< string values will have this set */ 2.24 + int inum; /**< numeric values will have this set */ 2.25 + float fnum; /**< numeric values will have this set */ 2.26 2.27 /** vector values (arrays containing ONLY numbers) will have this set */ 2.28 float *vec; /**< elements of the vector */ 2.29 @@ -46,7 +49,7 @@ 2.30 /** set a ts_value from a list of floats */ 2.31 int ts_set_valuefv(struct ts_value *tsv, int count, ...); 2.32 int ts_set_valuefv_va(struct ts_value *tsv, int count, va_list ap); 2.33 -int ts_set_valuef(struct ts_value *tsv, int fnum); /**< equiv: ts_set_valuefv(val, 1, fnum) */ 2.34 +int ts_set_valuef(struct ts_value *tsv, float fnum); /**< equiv: ts_set_valuefv(val, 1, fnum) */ 2.35 2.36 /** set a ts_value from a list of ts_value pointers. they are deep-copied as per ts_copy_value */ 2.37 int ts_set_valuev(struct ts_value *tsv, int count, ...); 2.38 @@ -100,6 +103,18 @@ 2.39 void ts_add_attr(struct ts_node *node, struct ts_attr *attr); 2.40 struct ts_attr *ts_get_attr(struct ts_node *node, const char *name); 2.41 2.42 +const char *ts_get_attr_str(struct ts_node *node, const char *aname, 2.43 + const char *def_val TS_DEFVAL(0)); 2.44 +float ts_get_attr_num(struct ts_node *node, const char *aname, 2.45 + float def_val TS_DEFVAL(0.0f)); 2.46 +int ts_get_attr_int(struct ts_node *node, const char *aname, 2.47 + int def_val TS_DEFVAL(0.0f)); 2.48 +float *ts_get_attr_vec(struct ts_node *node, const char *aname, 2.49 + float *def_val TS_DEFVAL(0)); 2.50 +struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, 2.51 + struct ts_value *def_val TS_DEFVAL(0)); 2.52 + 2.53 + 2.54 void ts_add_child(struct ts_node *node, struct ts_node *child); 2.55 int ts_remove_child(struct ts_node *node, struct ts_node *child); 2.56 struct ts_node *ts_get_child(struct ts_node *node, const char *name); 2.57 @@ -107,6 +122,7 @@ 2.58 struct ts_node *ts_load(const char *fname); 2.59 int ts_save(struct ts_node *tree, const char *fname); 2.60 2.61 + 2.62 #ifdef __cplusplus 2.63 } 2.64 #endif
3.1 --- a/src/text.c Thu Nov 10 16:19:44 2016 +0200 3.2 +++ b/src/text.c Sun Nov 13 19:46:01 2016 +0200 3.3 @@ -4,46 +4,69 @@ 3.4 #include <ctype.h> 3.5 #include "treestore.h" 3.6 3.7 +#define MAX_TOKEN_SIZE 512 3.8 +struct parser { 3.9 + FILE *fp; 3.10 + int nline; 3.11 + char token[MAX_TOKEN_SIZE]; 3.12 +}; 3.13 + 3.14 enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR }; 3.15 3.16 -static struct ts_node *read_node(FILE *fp); 3.17 -static int next_token(FILE *fp, char *buf, int bsz); 3.18 +static struct ts_node *read_node(struct parser *pstate); 3.19 +static int read_array(struct parser *pstate, struct ts_value *tsv, char endsym); 3.20 +static int next_token(struct parser *pstate); 3.21 3.22 static void print_attr(struct ts_attr *attr, FILE *fp, int level); 3.23 static void print_value(struct ts_value *value, FILE *fp); 3.24 static int tree_level(struct ts_node *n); 3.25 static const char *indent(int x); 3.26 +static const char *toktypestr(int type); 3.27 + 3.28 +#define EXPECT(type) \ 3.29 + do { \ 3.30 + if(next_token(pst) != (type)) { \ 3.31 + fprintf(stderr, "expected %s token\n", toktypestr(type)); \ 3.32 + goto err; \ 3.33 + } \ 3.34 + } while(0) 3.35 + 3.36 +#define EXPECT_SYM(c) \ 3.37 + do { \ 3.38 + if(next_token(pst) != TOK_SYM || pst->token[0] != (c)) { \ 3.39 + fprintf(stderr, "expected symbol: %c\n", c); \ 3.40 + goto err; \ 3.41 + } \ 3.42 + } while(0) 3.43 + 3.44 3.45 struct ts_node *ts_text_load(FILE *fp) 3.46 { 3.47 - char token[256]; 3.48 - struct ts_node *node; 3.49 + char *root_name; 3.50 + struct parser pstate, *pst = &pstate; 3.51 + struct ts_node *node = 0; 3.52 3.53 - if(next_token(fp, token, sizeof token) != TOK_ID || 3.54 - !(next_token(fp, token, sizeof token) == TOK_SYM && token[0] == '{')) { 3.55 - fprintf(stderr, "ts_text_load: invalid file format\n"); 3.56 + pstate.fp = fp; 3.57 + pstate.nline = 0; 3.58 + 3.59 + EXPECT(TOK_ID); 3.60 + if(!(root_name = strdup(pst->token))) { 3.61 + perror("failed to allocate root node name"); 3.62 return 0; 3.63 } 3.64 - if(!(node = read_node(fp))) { 3.65 + EXPECT_SYM('{'); 3.66 + if(!(node = read_node(pst))) { 3.67 return 0; 3.68 } 3.69 - if(!(node->name = strdup(token))) { 3.70 - perror("failed to allocate node name"); 3.71 - free(node); 3.72 - return 0; 3.73 - } 3.74 + node->name = root_name; 3.75 + 3.76 +err: 3.77 return node; 3.78 } 3.79 3.80 - 3.81 -#define EXPECT(type) \ 3.82 - if(next_token(fp, token, sizeof token) != (type)) goto err 3.83 -#define EXPECT_SYM(c) \ 3.84 - if(next_token(fp, token, sizeof token) != TOK_SYM || token[0] != (c)) goto err 3.85 - 3.86 -static struct ts_node *read_node(FILE *fp) 3.87 +static struct ts_node *read_node(struct parser *pst) 3.88 { 3.89 - char token[256]; 3.90 + int type; 3.91 struct ts_node *node; 3.92 3.93 if(!(node = ts_alloc_node())) { 3.94 @@ -51,107 +74,143 @@ 3.95 return 0; 3.96 } 3.97 3.98 - while(next_token(fp, token, sizeof token) == TOK_ID) { 3.99 + while((type = next_token(pst)) == TOK_ID) { 3.100 char *id; 3.101 3.102 - if(!(id = strdup(token))) { 3.103 + if(!(id = strdup(pst->token))) { 3.104 goto err; 3.105 } 3.106 3.107 EXPECT(TOK_SYM); 3.108 3.109 - if(token[0] == '=') { 3.110 + if(pst->token[0] == '=') { 3.111 /* attribute */ 3.112 struct ts_attr *attr; 3.113 - int toktype; 3.114 + int type; 3.115 3.116 if(!(attr = ts_alloc_attr())) { 3.117 goto err; 3.118 } 3.119 3.120 - if((toktype = next_token(fp, token, sizeof token)) == -1) { 3.121 + if((type = next_token(pst)) == -1) { 3.122 ts_free_attr(attr); 3.123 + fprintf(stderr, "read_node: unexpected EOF\n"); 3.124 goto err; 3.125 } 3.126 + 3.127 + switch(type) { 3.128 + case TOK_NUM: 3.129 + ts_set_valuef(&attr->val, atof(pst->token)); 3.130 + break; 3.131 + 3.132 + case TOK_SYM: 3.133 + if(pst->token[0] == '[' || pst->token[0] == '{') { 3.134 + char endsym = pst->token[0] + 2; /* end symbol is dist 2 from either '[' or '{' */ 3.135 + if(read_array(pst, &attr->val, endsym) == -1) { 3.136 + goto err; 3.137 + } 3.138 + } else { 3.139 + fprintf(stderr, "read_node: unexpected rhs symbol: %c\n", pst->token[0]); 3.140 + } 3.141 + break; 3.142 + 3.143 + case TOK_ID: 3.144 + case TOK_STR: 3.145 + default: 3.146 + ts_set_value(&attr->val, pst->token); 3.147 + } 3.148 + 3.149 attr->name = id; 3.150 - ts_set_value(&attr->val, token); 3.151 - 3.152 ts_add_attr(node, attr); 3.153 3.154 - } else if(token[0] == '{') { 3.155 + } else if(pst->token[0] == '{') { 3.156 /* child */ 3.157 struct ts_node *child; 3.158 3.159 - if(!(child = read_node(fp))) { 3.160 + if(!(child = read_node(pst))) { 3.161 ts_free_node(node); 3.162 return 0; 3.163 } 3.164 + 3.165 child->name = id; 3.166 - 3.167 ts_add_child(node, child); 3.168 3.169 } else { 3.170 - fprintf(stderr, "unexpected token: %s\n", token); 3.171 + fprintf(stderr, "unexpected token: %s\n", pst->token); 3.172 goto err; 3.173 } 3.174 } 3.175 3.176 + if(type != TOK_SYM || pst->token[0] != '}') { 3.177 + fprintf(stderr, "expected closing brace\n"); 3.178 + goto err; 3.179 + } 3.180 + return node; 3.181 + 3.182 err: 3.183 fprintf(stderr, "treestore read_node failed\n"); 3.184 ts_free_node(node); 3.185 return 0; 3.186 } 3.187 3.188 -static int next_token(FILE *fp, char *buf, int bsz) 3.189 +static int read_array(struct parser *pst, struct ts_value *tsv, char endsym) 3.190 +{ 3.191 + // TODO implement 3.192 + return -1; 3.193 +} 3.194 + 3.195 +static int next_token(struct parser *pst) 3.196 { 3.197 int c; 3.198 - char *ptr; 3.199 + char *ptr, *bend = pst->token + MAX_TOKEN_SIZE - 1; /* leave space for the terminator */ 3.200 3.201 // skip whitespace 3.202 - while((c = fgetc(fp)) != -1 && isspace(c)) { 3.203 + while((c = fgetc(pst->fp)) != -1) { 3.204 if(c == '#') { // skip to end of line 3.205 - while((c = fgetc(fp)) != -1 && c != '\n'); 3.206 + while((c = fgetc(pst->fp)) != -1 && c != '\n'); 3.207 if(c == -1) return -1; 3.208 } 3.209 + if(!isspace(c)) break; 3.210 + if(c == '\n') ++pst->nline; 3.211 } 3.212 if(c == -1) return -1; 3.213 3.214 - buf[0] = c; 3.215 - buf[1] = 0; 3.216 + pst->token[0] = c; 3.217 + pst->token[1] = 0; 3.218 3.219 if(isdigit(c)) { 3.220 // token is a number 3.221 - ptr = buf + 1; 3.222 - while((c = fgetc(fp)) != -1 && isdigit(c)) { 3.223 - *ptr++ = c; 3.224 + ptr = pst->token + 1; 3.225 + while((c = fgetc(pst->fp)) != -1 && isdigit(c)) { 3.226 + if(ptr < bend) *ptr++ = c; 3.227 } 3.228 - if(c != -1) ungetc(c, fp); 3.229 + if(c != -1) ungetc(c, pst->fp); 3.230 *ptr = 0; 3.231 return TOK_NUM; 3.232 } 3.233 if(isalpha(c)) { 3.234 // token is an identifier 3.235 - ptr = buf + 1; 3.236 - while((c = fgetc(fp)) != -1 && isalnum(c)) { 3.237 - *ptr++ = c; 3.238 + ptr = pst->token + 1; 3.239 + while((c = fgetc(pst->fp)) != -1 && isalnum(c)) { 3.240 + if(ptr < bend) *ptr++ = c; 3.241 } 3.242 - if(c != -1) ungetc(c, fp); 3.243 + if(c != -1) ungetc(c, pst->fp); 3.244 *ptr = 0; 3.245 return TOK_ID; 3.246 } 3.247 if(c == '"') { 3.248 // token is a string constant 3.249 - ptr = buf; 3.250 - while((c = fgetc(fp)) != -1 && c != '"' && c != '\r' && c != '\n') { 3.251 - *ptr++ = c; 3.252 + ptr = pst->token; 3.253 + while((c = fgetc(pst->fp)) != -1 && c != '"' && c != '\r' && c != '\n') { 3.254 + if(ptr < bend) *ptr++ = c; 3.255 } 3.256 + if(c == '\n') ++pst->nline; 3.257 if(c != '"') { 3.258 return -1; 3.259 } 3.260 *ptr = 0; 3.261 return TOK_STR; 3.262 } 3.263 - 3.264 return TOK_SYM; 3.265 } 3.266 3.267 @@ -172,6 +231,7 @@ 3.268 c = tree->child_list; 3.269 while(c) { 3.270 ts_text_save(c, fp); 3.271 + c = c->next; 3.272 } 3.273 3.274 fprintf(fp, "%s}\n", indent(lvl)); 3.275 @@ -217,7 +277,7 @@ 3.276 break; 3.277 3.278 default: 3.279 - fputs(value->str, fp); 3.280 + fprintf(fp, "\"%s\"", value->str); 3.281 } 3.282 } 3.283 3.284 @@ -229,7 +289,22 @@ 3.285 3.286 static const char *indent(int x) 3.287 { 3.288 - static const char *buf = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 3.289 + static const char buf[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 3.290 const char *end = buf + sizeof buf - 1; 3.291 return x > sizeof buf - 1 ? buf : end - x; 3.292 } 3.293 + 3.294 +static const char *toktypestr(int type) 3.295 +{ 3.296 + switch(type) { 3.297 + case TOK_ID: 3.298 + return "identifier"; 3.299 + case TOK_NUM: 3.300 + return "number"; 3.301 + case TOK_STR: 3.302 + return "string"; 3.303 + case TOK_SYM: 3.304 + return "symbol"; 3.305 + } 3.306 + return "unknown"; 3.307 +}
4.1 --- a/src/treestore.c Thu Nov 10 16:19:44 2016 +0200 4.2 +++ b/src/treestore.c Sun Nov 13 19:46:01 2016 +0200 4.3 @@ -93,9 +93,15 @@ 4.4 return -1; 4.5 } 4.6 4.7 +struct val_list_node { 4.8 + struct ts_value val; 4.9 + struct val_list_node *next; 4.10 +}; 4.11 4.12 int ts_set_value(struct ts_value *tsv, const char *str) 4.13 { 4.14 + char *endp; 4.15 + 4.16 if(tsv->str) { 4.17 ts_destroy_value(tsv); 4.18 if(ts_init_value(tsv) == -1) { 4.19 @@ -103,10 +109,58 @@ 4.20 } 4.21 } 4.22 4.23 + tsv->type = TS_STRING; 4.24 if(!(tsv->str = malloc(strlen(str) + 1))) { 4.25 return -1; 4.26 } 4.27 strcpy(tsv->str, str); 4.28 + 4.29 + /* try to parse the string and see if it fits any of the value types */ 4.30 + if(*str == '[' || *str == '{') { 4.31 + /* try to parse as a vector */ 4.32 + struct val_list_node *list = 0, *tail = 0, *node; 4.33 + int nelem = 0; 4.34 + char endsym = *str++ + 2; /* ']' is '[' + 2 and '}' is '{' + 2 */ 4.35 + 4.36 + while(*str && *str != endsym) { 4.37 + float val = strtod(str, &endp); 4.38 + if(endp == str || !(node = malloc(sizeof *node))) { 4.39 + break; 4.40 + } 4.41 + ts_init_value(&node->val); 4.42 + ts_set_valuef(&node->val, val); 4.43 + node->next = 0; 4.44 + 4.45 + if(list) { 4.46 + tail->next = node; 4.47 + tail = node; 4.48 + } else { 4.49 + list = tail = node; 4.50 + } 4.51 + ++nelem; 4.52 + str = endp; 4.53 + } 4.54 + 4.55 + if(nelem && (tsv->array = malloc(nelem * sizeof *tsv->array)) && 4.56 + (tsv->vec = malloc(nelem * sizeof *tsv->vec))) { 4.57 + int idx = 0; 4.58 + while(list) { 4.59 + node = list; 4.60 + list = list->next; 4.61 + 4.62 + tsv->array[idx] = node->val; 4.63 + tsv->vec[idx] = node->val.fnum; 4.64 + ++idx; 4.65 + free(node); 4.66 + } 4.67 + tsv->type = TS_VECTOR; 4.68 + } 4.69 + 4.70 + } else if((tsv->fnum = strtod(str, &endp)), endp != str) { 4.71 + /* it's a number I guess... */ 4.72 + tsv->type = TS_NUMBER; 4.73 + } 4.74 + 4.75 return 0; 4.76 } 4.77 4.78 @@ -226,7 +280,7 @@ 4.79 return 0; 4.80 } 4.81 4.82 -int ts_set_valuef(struct ts_value *tsv, int fnum) 4.83 +int ts_set_valuef(struct ts_value *tsv, float fnum) 4.84 { 4.85 return ts_set_valuefv(tsv, 1, fnum); 4.86 } 4.87 @@ -387,6 +441,51 @@ 4.88 return 0; 4.89 } 4.90 4.91 +const char *ts_get_attr_str(struct ts_node *node, const char *aname, const char *def_val) 4.92 +{ 4.93 + struct ts_attr *attr = ts_get_attr(node, aname); 4.94 + if(!attr || !attr->val.str) { 4.95 + return def_val; 4.96 + } 4.97 + return attr->val.str; 4.98 +} 4.99 + 4.100 +float ts_get_attr_num(struct ts_node *node, const char *aname, float def_val) 4.101 +{ 4.102 + struct ts_attr *attr = ts_get_attr(node, aname); 4.103 + if(!attr || attr->val.type != TS_NUMBER) { 4.104 + return def_val; 4.105 + } 4.106 + return attr->val.fnum; 4.107 +} 4.108 + 4.109 +int ts_get_attr_int(struct ts_node *node, const char *aname, int def_val) 4.110 +{ 4.111 + struct ts_attr *attr = ts_get_attr(node, aname); 4.112 + if(!attr || attr->val.type != TS_NUMBER) { 4.113 + return def_val; 4.114 + } 4.115 + return attr->val.inum; 4.116 +} 4.117 + 4.118 +float *ts_get_attr_vec(struct ts_node *node, const char *aname, float *def_val) 4.119 +{ 4.120 + struct ts_attr *attr = ts_get_attr(node, aname); 4.121 + if(!attr || !attr->val.vec) { 4.122 + return def_val; 4.123 + } 4.124 + return attr->val.vec; 4.125 +} 4.126 + 4.127 +struct ts_value *ts_get_attr_array(struct ts_node *node, const char *aname, struct ts_value *def_val) 4.128 +{ 4.129 + struct ts_attr *attr = ts_get_attr(node, aname); 4.130 + if(!attr || !attr->val.array) { 4.131 + return def_val; 4.132 + } 4.133 + return attr->val.array; 4.134 +} 4.135 + 4.136 void ts_add_child(struct ts_node *node, struct ts_node *child) 4.137 { 4.138 if(child->parent) {