tablist.c (7049B)
1 /***** TODO ***** 2 3 Implement decoding from buffer (aka file) instead of stream. 4 Boilerplate should include capability of navigating the buffer 5 via next_token/prev_token commands, while keeping track of 6 current line and indentation level. 7 8 */ 9 10 #include <u.h> 11 #include <libc.h> 12 13 #include "../util/util.h" 14 #include "tablist.h" 15 16 Type TLnodeType = {.nbytes = sizeof(TLnode *), }; 17 18 TLnode * 19 allocTLnode(void) 20 { 21 TLnode *node = mallocz(sizeof(TLnode), 1); 22 node->children = allocslice(&TLnodeType, 0, 0); 23 return node; 24 } 25 26 void 27 freeTLnode(TLnode *node) 28 { 29 free(node->name); 30 free(node->value); 31 freeslice(node->children); 32 free(node); 33 } 34 35 int 36 TLnodeappend(TLnode *parent, TLnode *child) 37 { 38 sliceappendp(parent->children, 1, &child); 39 return 0; 40 } 41 42 static void 43 _printnode(TLnode *n) 44 { 45 print("NODE %p\n", n); 46 if (n->name != nil) print("NAME: %.*s\n", n->name->len, n->name->p); 47 if (n->value != nil) print("VALUE: %.*s\n", n->value->len, n->value->p); 48 print("CHILDREN: %d\n", n->children->len); 49 print("END\n"); 50 } 51 52 /***** DECODER *****/ 53 54 55 TLdecoder * 56 initTLdecoder(char *file) 57 { 58 TLdecoder *tlp; 59 tlp = mallocz(sizeof(TLdecoder), 1); 60 tlp->nodes = allocslice(&TLnodeType, 0, 1); 61 tlp->acc = allocslice(&CharType, 0, 256); 62 tlp->file = file; 63 return tlp; 64 } 65 66 int 67 TLdecode(TLdecoder *r, char *buf, usize count) 68 { 69 enum { 70 Start, Begin, Node, Name, FlushName, Value, FlushValue, Indent, 71 }; 72 usize i; 73 TLnode *new; 74 for (i = 0; i < count;) { 75 switch (r->state) { 76 case Start: 77 r->state = Begin; 78 79 case Begin: 80 r->indent = 0; 81 if (buf[i] == '\t') r->state = Indent; 82 else r->sp = 0, r->state = Node; 83 break; 84 85 case Node: 86 r->acc->len = 0; 87 if (buf[i] == '\\') r->state = Value, i++; 88 else r->state = Name; 89 break; 90 91 case Name: 92 if ((buf[i] != ' ') && (buf[i] != '\n')) { 93 r->acc = sliceappendp(r->acc, 1, buf+i), i++; 94 break; 95 } 96 r->state = FlushName; 97 98 case FlushName: 99 new = allocTLnode(); 100 new->name = slicecopy(r->acc); 101 102 if (r->indent == 0) { 103 r->sp = 0; 104 sliceappendp(r->nodes, 1, &new); 105 } else if (r->indent == -1) { 106 sliceappendp(r->stack[r->sp]->children, 1, &new); 107 } else if (r->indent <= r->sp) { 108 r->sp = r->indent; 109 sliceappendp(r->stack[r->sp - 1]->children, 1, &new); 110 } else if (r->indent == r->sp + 1) { 111 sliceappendp(r->stack[r->sp]->children, 1, &new); 112 r->sp = r->indent; 113 } else sysfatal("TLdecode/FlushName: indent is no good"); 114 115 r->stack[r->sp] = new; 116 117 if (buf[i] == ' ') r->state = Node, r->indent = -1, i++; 118 else r->state = Begin, i++; 119 break; 120 121 case Value: 122 if (buf[i] != '\n') { 123 r->acc = sliceappendp(r->acc, 1, buf+i), i++; 124 break; 125 } else r->state = FlushValue; 126 127 case FlushValue: 128 new = allocTLnode(); 129 new->value = slicecopy(r->acc); 130 131 if (r->indent == 0) { 132 r->sp = 0; 133 sliceappendp(r->nodes, 1, &new); 134 } else if (r->indent == -1) { 135 sliceappendp(r->stack[r->sp]->children, 1, &new); 136 } else if (r->indent <= r->sp) { 137 r->sp = r->indent; 138 sliceappendp(r->stack[r->sp - 1]->children, 1, &new); 139 } else if (r->indent == r->sp + 1) { 140 sliceappendp(r->stack[r->sp]->children, 1, &new); 141 r->sp = r->indent; 142 } else sysfatal("TLdecode/FlushName: indent is no good"); 143 144 r->stack[r->sp] = new; 145 146 r->state = Begin, i++; 147 break; 148 149 case Indent: 150 if (buf[i] == '\t') r->indent++, i++; 151 else r->state = Node; 152 break; 153 154 default: 155 sysfatal("TLdecode: unknown state %d", r->state); 156 } 157 } 158 return 0; 159 } 160 161 /******* ENCODER *******/ 162 163 typedef void * (TLencstate)(TLencoder *, char *); 164 TLencstate _encstart, _encnode, _encname, _encvalue, _encnext, 165 _encnl, _encsp, _encind, _encend; 166 167 168 #define ENCTOS(X) ( *(TLnode **)slicegetp(X->ns[X->sp], X->cs[X->sp]) ) 169 170 TLencoder * 171 initTLencoder(Slice *nodes) 172 { 173 TLencoder *w = mallocz(sizeof(TLencoder), 1); 174 w->ns[0] = nodes; 175 w->state = _encstart; 176 return w; 177 } 178 179 void * 180 _encstart(TLencoder *w, char *c) 181 { 182 if (w->ns[0]->len == 0) return _encend(w, c); 183 return _encnode(w, c); 184 } 185 186 void * 187 _encnode(TLencoder *w, char *c) 188 { 189 TLnode *n = ENCTOS(w); 190 assert(n != nil); 191 w->i = 0; 192 if (n->name != nil) return _encname(w, c); 193 if (n->value != nil) return _encvalue(w, c); 194 return _encend(w, c); 195 } 196 197 void * 198 _encname(TLencoder *w, char *c) 199 { 200 TLnode *n = ENCTOS(w); 201 if (w->i >= n->name->len) return _encnext(w, c); 202 char *s = slicegetp(n->name, w->i); 203 *c = *s; 204 w->i++; 205 return _encname; 206 } 207 208 void * 209 _encvalue(TLencoder *w, char *c) 210 { 211 if (w->i == 0) { 212 *c = '\\'; 213 w->i++; 214 return _encvalue; 215 } 216 TLnode *n = ENCTOS(w); 217 if (w->i >= n->value->len + 1) return _encnext(w, c); 218 char *s = slicegetp(n->value, w->i - 1); 219 *c = *s; 220 w->i++; 221 return _encvalue; 222 } 223 224 void * 225 _encnext(TLencoder *w, char *c) 226 { 227 TLnode *n = ENCTOS(w); 228 // TODO: delete? don't remember what this was for 229 // TLnode *fc = nil; 230 // if (n->children->len > 0) fc = *(TLnode **)slicegetp(n->children, 0); 231 232 if (n->children->len == 0) { 233 w->cs[w->sp]++; 234 return _encnl(w, c); 235 236 } else if ( (n->children->len > 1) || (n->value != nil) ) { 237 w->sp++; 238 w->ns[w->sp] = n->children; 239 w->cs[w->sp] = 0; 240 return _encnl(w, c); 241 242 } else { 243 w->sp++; 244 w->ns[w->sp] = n->children; 245 w->cs[w->sp] = 0; 246 return _encsp(w, c); 247 248 } 249 } 250 251 void * 252 _encnl(TLencoder *w, char *c) 253 { 254 *c = '\n'; 255 while (w->cs[w->sp] == w->ns[w->sp]->len) { 256 w->sp--; 257 if (w->sp < 0) return _encend; 258 w->cs[w->sp]++; 259 } 260 w->i = 0; 261 return _encind; 262 } 263 264 void * 265 _encsp(TLencoder *, char *c) 266 { 267 *c = ' '; 268 return _encnode; 269 } 270 271 void * 272 _encind(TLencoder *w, char *c) 273 { 274 if (w->i < w->sp) { 275 *c = '\t'; 276 w->i++; 277 return _encind; 278 } 279 return _encnode(w, c); 280 } 281 282 void * 283 _encend(TLencoder *, char *c) 284 { 285 *c = '\0'; 286 return nil; 287 } 288 289 int 290 TLencode(TLencoder *w, char *buf, usize count) 291 { 292 usize i; 293 for (i = 0; i < count; i++) { 294 if (w->state == nil) return i; 295 w->state = w->state(w, buf+i); 296 } 297 return i; 298 } 299 300 TLnode * 301 TLgetnode(Slice *list, char *name, char *value) 302 { 303 if (list == nil) sysfatal("TLgetnode: list is nil"); 304 if (list->arr->type != &TLnodeType) sysfatal("TLgetnode: list is not TLnodeType"); 305 if (list->len == 0) return nil; 306 int i; 307 for (i = 0; i < list->len; i++) { 308 TLnode **p = slicegetp(list, i); 309 TLnode *n = *p; 310 if (name != nil) { 311 if (strlen(name) != n->name->len) continue; 312 if (memcmp(name, n->name->p, n->name->len) == 0) 313 return n; 314 } else if (value != nil) { 315 if (strlen(value) != n->value->len) continue; 316 if (memcmp(value, n->value->p, n->value->len) == 0) 317 return n; 318 } else return nil; 319 } 320 return nil; 321 } 322 323 char * 324 TLval2str(TLnode *n) 325 { 326 usize len = 0; 327 int i; 328 for(i = 0; i < n->children->len; i++) { 329 TLnode **v = slicegetp(n->children, i); 330 TLnode *nn = *v; 331 if (nn->value == nil) continue; 332 len += nn->value->len + 1; 333 } 334 if (len == 0) len = 1; 335 char *buf = malloc(len); 336 char *p = buf; 337 for(i = 0; i < n->children->len; i++) { 338 TLnode **v = slicegetp(n->children, i); 339 TLnode *nn = *v; 340 if (nn->value == nil) continue; 341 memcpy(p, nn->value->p, nn->value->len); 342 p += nn->value->len; 343 *p = '\n'; 344 p++; 345 } 346 buf[len - 1] = '\0'; 347 // fprint(2, "TLval2str: %s\n", buf); 348 return buf; 349 }