libtreestore

annotate 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
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 }