libtreestore

view 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 source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "treestore.h"
7 enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR };
9 static struct ts_node *read_node(FILE *fp);
10 static int next_token(FILE *fp, char *buf, int bsz);
12 static void print_attr(struct ts_attr *attr, FILE *fp, int level);
13 static void print_value(struct ts_value *value, FILE *fp);
14 static int tree_level(struct ts_node *n);
15 static const char *indent(int x);
17 struct ts_node *ts_text_load(FILE *fp)
18 {
19 char token[256];
20 struct ts_node *node;
22 if(next_token(fp, token, sizeof token) != TOK_ID ||
23 !(next_token(fp, token, sizeof token) == TOK_SYM && token[0] == '{')) {
24 fprintf(stderr, "ts_text_load: invalid file format\n");
25 return 0;
26 }
27 if(!(node = read_node(fp))) {
28 return 0;
29 }
30 if(!(node->name = strdup(token))) {
31 perror("failed to allocate node name");
32 free(node);
33 return 0;
34 }
35 return node;
36 }
39 #define EXPECT(type) \
40 if(next_token(fp, token, sizeof token) != (type)) goto err
41 #define EXPECT_SYM(c) \
42 if(next_token(fp, token, sizeof token) != TOK_SYM || token[0] != (c)) goto err
44 static struct ts_node *read_node(FILE *fp)
45 {
46 char token[256];
47 struct ts_node *node;
49 if(!(node = ts_alloc_node())) {
50 perror("failed to allocate treestore node");
51 return 0;
52 }
54 while(next_token(fp, token, sizeof token) == TOK_ID) {
55 char *id;
57 if(!(id = strdup(token))) {
58 goto err;
59 }
61 EXPECT(TOK_SYM);
63 if(token[0] == '=') {
64 /* attribute */
65 struct ts_attr *attr;
66 int toktype;
68 if(!(attr = ts_alloc_attr())) {
69 goto err;
70 }
72 if((toktype = next_token(fp, token, sizeof token)) == -1) {
73 ts_free_attr(attr);
74 goto err;
75 }
76 attr->name = id;
77 ts_set_value(&attr->val, token);
79 ts_add_attr(node, attr);
81 } else if(token[0] == '{') {
82 /* child */
83 struct ts_node *child;
85 if(!(child = read_node(fp))) {
86 ts_free_node(node);
87 return 0;
88 }
89 child->name = id;
91 ts_add_child(node, child);
93 } else {
94 fprintf(stderr, "unexpected token: %s\n", token);
95 goto err;
96 }
97 }
99 err:
100 fprintf(stderr, "treestore read_node failed\n");
101 ts_free_node(node);
102 return 0;
103 }
105 static int next_token(FILE *fp, char *buf, int bsz)
106 {
107 int c;
108 char *ptr;
110 // skip whitespace
111 while((c = fgetc(fp)) != -1 && isspace(c)) {
112 if(c == '#') { // skip to end of line
113 while((c = fgetc(fp)) != -1 && c != '\n');
114 if(c == -1) return -1;
115 }
116 }
117 if(c == -1) return -1;
119 buf[0] = c;
120 buf[1] = 0;
122 if(isdigit(c)) {
123 // token is a number
124 ptr = buf + 1;
125 while((c = fgetc(fp)) != -1 && isdigit(c)) {
126 *ptr++ = c;
127 }
128 if(c != -1) ungetc(c, fp);
129 *ptr = 0;
130 return TOK_NUM;
131 }
132 if(isalpha(c)) {
133 // token is an identifier
134 ptr = buf + 1;
135 while((c = fgetc(fp)) != -1 && isalnum(c)) {
136 *ptr++ = c;
137 }
138 if(c != -1) ungetc(c, fp);
139 *ptr = 0;
140 return TOK_ID;
141 }
142 if(c == '"') {
143 // token is a string constant
144 ptr = buf;
145 while((c = fgetc(fp)) != -1 && c != '"' && c != '\r' && c != '\n') {
146 *ptr++ = c;
147 }
148 if(c != '"') {
149 return -1;
150 }
151 *ptr = 0;
152 return TOK_STR;
153 }
155 return TOK_SYM;
156 }
158 int ts_text_save(struct ts_node *tree, FILE *fp)
159 {
160 struct ts_node *c;
161 struct ts_attr *attr;
162 int lvl = tree_level(tree);
164 fprintf(fp, "%s%s {\n", indent(lvl), tree->name);
166 attr = tree->attr_list;
167 while(attr) {
168 print_attr(attr, fp, lvl);
169 attr = attr->next;
170 }
172 c = tree->child_list;
173 while(c) {
174 ts_text_save(c, fp);
175 }
177 fprintf(fp, "%s}\n", indent(lvl));
178 }
180 static void print_attr(struct ts_attr *attr, FILE *fp, int level)
181 {
182 fprintf(fp, "%s%s = ", indent(level + 1), attr->name);
183 print_value(&attr->val, fp);
184 fputc('\n', fp);
185 }
187 static void print_value(struct ts_value *value, FILE *fp)
188 {
189 int i;
191 switch(value->type) {
192 case TS_NUMBER:
193 fprintf(fp, "%g", value->fnum);
194 break;
196 case TS_VECTOR:
197 fputc('[', fp);
198 for(i=0; i<value->vec_size; i++) {
199 if(i == 0) {
200 fprintf(fp, "%g", value->vec[i]);
201 } else {
202 fprintf(fp, ", %g", value->vec[i]);
203 }
204 }
205 fputc(']', fp);
206 break;
208 case TS_ARRAY:
209 fputc('[', fp);
210 for(i=0; i<value->array_size; i++) {
211 if(i > 0) {
212 fprintf(fp, ", ");
213 }
214 print_value(value->array + i, fp);
215 }
216 fputc(']', fp);
217 break;
219 default:
220 fputs(value->str, fp);
221 }
222 }
224 static int tree_level(struct ts_node *n)
225 {
226 if(!n->parent) return 0;
227 return tree_level(n->parent) + 1;
228 }
230 static const char *indent(int x)
231 {
232 static const char *buf = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
233 const char *end = buf + sizeof buf - 1;
234 return x > sizeof buf - 1 ? buf : end - x;
235 }