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