libtreestore
diff src/text.c @ 3:48d75df3ef04
picking this up again, converted to cmake, and started a text format reader/writer
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 10 Nov 2016 16:19:44 +0200 |
parents | |
children | bb873449cf59 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/text.c Thu Nov 10 16:19:44 2016 +0200 1.3 @@ -0,0 +1,235 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <ctype.h> 1.8 +#include "treestore.h" 1.9 + 1.10 +enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR }; 1.11 + 1.12 +static struct ts_node *read_node(FILE *fp); 1.13 +static int next_token(FILE *fp, char *buf, int bsz); 1.14 + 1.15 +static void print_attr(struct ts_attr *attr, FILE *fp, int level); 1.16 +static void print_value(struct ts_value *value, FILE *fp); 1.17 +static int tree_level(struct ts_node *n); 1.18 +static const char *indent(int x); 1.19 + 1.20 +struct ts_node *ts_text_load(FILE *fp) 1.21 +{ 1.22 + char token[256]; 1.23 + struct ts_node *node; 1.24 + 1.25 + if(next_token(fp, token, sizeof token) != TOK_ID || 1.26 + !(next_token(fp, token, sizeof token) == TOK_SYM && token[0] == '{')) { 1.27 + fprintf(stderr, "ts_text_load: invalid file format\n"); 1.28 + return 0; 1.29 + } 1.30 + if(!(node = read_node(fp))) { 1.31 + return 0; 1.32 + } 1.33 + if(!(node->name = strdup(token))) { 1.34 + perror("failed to allocate node name"); 1.35 + free(node); 1.36 + return 0; 1.37 + } 1.38 + return node; 1.39 +} 1.40 + 1.41 + 1.42 +#define EXPECT(type) \ 1.43 + if(next_token(fp, token, sizeof token) != (type)) goto err 1.44 +#define EXPECT_SYM(c) \ 1.45 + if(next_token(fp, token, sizeof token) != TOK_SYM || token[0] != (c)) goto err 1.46 + 1.47 +static struct ts_node *read_node(FILE *fp) 1.48 +{ 1.49 + char token[256]; 1.50 + struct ts_node *node; 1.51 + 1.52 + if(!(node = ts_alloc_node())) { 1.53 + perror("failed to allocate treestore node"); 1.54 + return 0; 1.55 + } 1.56 + 1.57 + while(next_token(fp, token, sizeof token) == TOK_ID) { 1.58 + char *id; 1.59 + 1.60 + if(!(id = strdup(token))) { 1.61 + goto err; 1.62 + } 1.63 + 1.64 + EXPECT(TOK_SYM); 1.65 + 1.66 + if(token[0] == '=') { 1.67 + /* attribute */ 1.68 + struct ts_attr *attr; 1.69 + int toktype; 1.70 + 1.71 + if(!(attr = ts_alloc_attr())) { 1.72 + goto err; 1.73 + } 1.74 + 1.75 + if((toktype = next_token(fp, token, sizeof token)) == -1) { 1.76 + ts_free_attr(attr); 1.77 + goto err; 1.78 + } 1.79 + attr->name = id; 1.80 + ts_set_value(&attr->val, token); 1.81 + 1.82 + ts_add_attr(node, attr); 1.83 + 1.84 + } else if(token[0] == '{') { 1.85 + /* child */ 1.86 + struct ts_node *child; 1.87 + 1.88 + if(!(child = read_node(fp))) { 1.89 + ts_free_node(node); 1.90 + return 0; 1.91 + } 1.92 + child->name = id; 1.93 + 1.94 + ts_add_child(node, child); 1.95 + 1.96 + } else { 1.97 + fprintf(stderr, "unexpected token: %s\n", token); 1.98 + goto err; 1.99 + } 1.100 + } 1.101 + 1.102 +err: 1.103 + fprintf(stderr, "treestore read_node failed\n"); 1.104 + ts_free_node(node); 1.105 + return 0; 1.106 +} 1.107 + 1.108 +static int next_token(FILE *fp, char *buf, int bsz) 1.109 +{ 1.110 + int c; 1.111 + char *ptr; 1.112 + 1.113 + // skip whitespace 1.114 + while((c = fgetc(fp)) != -1 && isspace(c)) { 1.115 + if(c == '#') { // skip to end of line 1.116 + while((c = fgetc(fp)) != -1 && c != '\n'); 1.117 + if(c == -1) return -1; 1.118 + } 1.119 + } 1.120 + if(c == -1) return -1; 1.121 + 1.122 + buf[0] = c; 1.123 + buf[1] = 0; 1.124 + 1.125 + if(isdigit(c)) { 1.126 + // token is a number 1.127 + ptr = buf + 1; 1.128 + while((c = fgetc(fp)) != -1 && isdigit(c)) { 1.129 + *ptr++ = c; 1.130 + } 1.131 + if(c != -1) ungetc(c, fp); 1.132 + *ptr = 0; 1.133 + return TOK_NUM; 1.134 + } 1.135 + if(isalpha(c)) { 1.136 + // token is an identifier 1.137 + ptr = buf + 1; 1.138 + while((c = fgetc(fp)) != -1 && isalnum(c)) { 1.139 + *ptr++ = c; 1.140 + } 1.141 + if(c != -1) ungetc(c, fp); 1.142 + *ptr = 0; 1.143 + return TOK_ID; 1.144 + } 1.145 + if(c == '"') { 1.146 + // token is a string constant 1.147 + ptr = buf; 1.148 + while((c = fgetc(fp)) != -1 && c != '"' && c != '\r' && c != '\n') { 1.149 + *ptr++ = c; 1.150 + } 1.151 + if(c != '"') { 1.152 + return -1; 1.153 + } 1.154 + *ptr = 0; 1.155 + return TOK_STR; 1.156 + } 1.157 + 1.158 + return TOK_SYM; 1.159 +} 1.160 + 1.161 +int ts_text_save(struct ts_node *tree, FILE *fp) 1.162 +{ 1.163 + struct ts_node *c; 1.164 + struct ts_attr *attr; 1.165 + int lvl = tree_level(tree); 1.166 + 1.167 + fprintf(fp, "%s%s {\n", indent(lvl), tree->name); 1.168 + 1.169 + attr = tree->attr_list; 1.170 + while(attr) { 1.171 + print_attr(attr, fp, lvl); 1.172 + attr = attr->next; 1.173 + } 1.174 + 1.175 + c = tree->child_list; 1.176 + while(c) { 1.177 + ts_text_save(c, fp); 1.178 + } 1.179 + 1.180 + fprintf(fp, "%s}\n", indent(lvl)); 1.181 +} 1.182 + 1.183 +static void print_attr(struct ts_attr *attr, FILE *fp, int level) 1.184 +{ 1.185 + fprintf(fp, "%s%s = ", indent(level + 1), attr->name); 1.186 + print_value(&attr->val, fp); 1.187 + fputc('\n', fp); 1.188 +} 1.189 + 1.190 +static void print_value(struct ts_value *value, FILE *fp) 1.191 +{ 1.192 + int i; 1.193 + 1.194 + switch(value->type) { 1.195 + case TS_NUMBER: 1.196 + fprintf(fp, "%g", value->fnum); 1.197 + break; 1.198 + 1.199 + case TS_VECTOR: 1.200 + fputc('[', fp); 1.201 + for(i=0; i<value->vec_size; i++) { 1.202 + if(i == 0) { 1.203 + fprintf(fp, "%g", value->vec[i]); 1.204 + } else { 1.205 + fprintf(fp, ", %g", value->vec[i]); 1.206 + } 1.207 + } 1.208 + fputc(']', fp); 1.209 + break; 1.210 + 1.211 + case TS_ARRAY: 1.212 + fputc('[', fp); 1.213 + for(i=0; i<value->array_size; i++) { 1.214 + if(i > 0) { 1.215 + fprintf(fp, ", "); 1.216 + } 1.217 + print_value(value->array + i, fp); 1.218 + } 1.219 + fputc(']', fp); 1.220 + break; 1.221 + 1.222 + default: 1.223 + fputs(value->str, fp); 1.224 + } 1.225 +} 1.226 + 1.227 +static int tree_level(struct ts_node *n) 1.228 +{ 1.229 + if(!n->parent) return 0; 1.230 + return tree_level(n->parent) + 1; 1.231 +} 1.232 + 1.233 +static const char *indent(int x) 1.234 +{ 1.235 + static const char *buf = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 1.236 + const char *end = buf + sizeof buf - 1; 1.237 + return x > sizeof buf - 1 ? buf : end - x; 1.238 +}