init
[csRadar.git] / vdf.h
1 #define vdf_foreach( NODE, STR, AS ) \
2 int __vdf_it_##__LINE__ = 0; \
3 vdf_node * AS;\
4 while( (AS = vdf_next( NODE, STR, &__vdf_it_##__LINE__ )) )
5
6 #define kv_foreach( NODE, STR, AS ) \
7 int __kv_it_##__LINE__ = 0; \
8 const char * AS;\
9 while( (AS = kv_iter( NODE, STR, &__kv_it_##__LINE__ )) )
10
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <ctype.h>
15
16 // TYPES
17 // ==================================================================================================================
18
19 typedef struct vdf_kv vdf_kv;
20 typedef struct vdf_node vdf_node;
21 typedef struct vdf_ctx vdf_ctx;
22
23 // API
24 // ==================================================================================================================
25
26 // Open / close
27 vdf_node *vdf_open_file( const char *fn );
28 void vdf_free_r( vdf_node *p );
29
30 // Nodes
31 // -----
32
33 // Starting from *it, get next child with matching name from node.
34 vdf_node *vdf_next( vdf_node *node, const char *name, int *it );
35
36 // Create new empty node attached to parent. name can be NULL
37 vdf_node *vdf_create_node( vdf_node *parent, const char *name );
38
39 // Save / printing
40 // ---------------
41
42 void vdf_out( vdf_node *h, int lvl, int declare, FILE *file );
43 void vdf_save( vdf_node *node, const char *fn );
44 void vdf_print( vdf_node *node );
45
46 // Keyvalue pairs
47 // --------------
48
49 // Get value string pointer from node's dictionary
50 const char *kv_get( vdf_node *node, const char *key, const char *value_defalt );
51
52 // Iterate each keyvalue starting from *it until key is matched
53 char *kv_iter( vdf_node *node, const char *key, int *it );
54
55 // Get keyvalue from node as int / float
56 int kv_get_int( vdf_node *node, const char *key, const int default_value );
57 float kv_get_float( vdf_node *node, const char *key, float default_value );
58
59 // Parse values into sepecifc type
60 void kv_int_array( vdf_node *node, const char *key, u32 count, int *arr );
61 void kv_float_array( vdf_node *node, const char *key, u32 count, float *arr );
62 void kv_double_array( vdf_node *node, const char *key, u32 count, double *arr );
63
64 // INTERNAL API
65 // ==================================================================================================================
66
67 // Add keyvalue pair to node
68 void vdf_kv_append( vdf_node *p, const char *k, const char *v );
69
70 // (low level api for arrays)
71 void kv_parse_array( const char *source, u32 esize, u32 count, void(*interp_func)(const char *src, void *dest), void *arr );
72 void vdf_str_to_float( const char *src, void *dest );
73 void vdf_str_to_int( const char *src, void *dest );
74
75 // Parsing context
76 // ---------------
77 void vdf_newln( vdf_ctx *ctx );
78 void vdf_endl( vdf_ctx *ctx );
79 int vdf_line_control( vdf_ctx *ctx );
80 void vdf_wait_endl( vdf_ctx *ctx );
81 void vdf_parse_string( vdf_ctx *ctx );
82 int vdf_parse_structure( vdf_ctx *ctx );
83 void vdf_parse_begin_token( vdf_ctx *ctx, char *ptr );
84 void vdf_parse_feedbuffer( vdf_ctx *ctx, char *buf );
85
86 // Formatting
87 void vdf_out_indent( const int n, FILE *file );
88
89 // IMPLEMENTATION
90 // ==================================================================================================================
91
92 struct vdf_kv
93 {
94 char *key;
95 char *value;
96 };
97
98 struct vdf_node
99 {
100 char *name;
101
102 vdf_node *parent;
103
104 vdf_node **nodes;
105 vdf_kv *pairs;
106 };
107
108 vdf_node *vdf_next( vdf_node *node, const char *name, int *it )
109 {
110 if( !node )
111 return NULL;
112
113 for( int i = it? *it: 0; i < csr_sb_count( node->nodes ); i ++ )
114 {
115 if( !strcmp( name, node->nodes[i]->name ))
116 {
117 if( it ) *it = i+1;
118 return node->nodes[i];
119 }
120 }
121
122 return NULL;
123 }
124
125 const char *kv_get( vdf_node *node, const char *key, const char *value_defalt )
126 {
127 if( node )
128 {
129 for( int i = 0; i < csr_sb_count( node->pairs ); i ++ )
130 {
131 if( !strcmp( node->pairs[ i ].key, key ) )
132 {
133 return node->pairs[ i ].value;
134 }
135 }
136 }
137
138 return value_defalt;
139 }
140
141 char *kv_iter( vdf_node *node, const char *key, int *it )
142 {
143 char *val;
144
145 if( node )
146 {
147 while( *it < csr_sb_count( node->pairs ) )
148 {
149 if( !strcmp( node->pairs[ *it ].key, key ) )
150 {
151 val = node->pairs[ *it ].value;
152 *it = *it + 1;
153 return val;
154 }
155
156 *it = *it + 1;
157 }
158 }
159
160 return NULL;
161 }
162
163 void vdf_str_to_int( const char *src, void *dest )
164 {
165 *((int *)dest) = atoi( src );
166 }
167
168 void vdf_str_to_float( const char *src, void *dest )
169 {
170 *((float *)dest) = atof( src );
171 }
172
173 void vdf_str_to_double( const char *src, void *dest )
174 {
175 *((double *)dest) = atof( src );
176 }
177
178 void kv_parse_array( const char *source, u32 esize, u32 count, void(*interp_func)(const char *src, void *dest), void *arr )
179 {
180 if( !source )
181 return;
182
183 char value_buf[ 64 ];
184 int token = 0;
185
186 u32 i = 0;
187 u32 k = 0;
188
189 char const *c = source;
190
191 while( *c )
192 {
193 if( *c == ' ' || *c == '\t' || *c == '[' || *c == ']' || *c == '(' || *c == ')' )
194 {
195 if( token )
196 {
197 value_buf[ k ] = 0x00;
198 token = 0;
199
200 interp_func( value_buf, ((u8 *)arr) + i*esize );
201 i ++;
202
203 if( i >= count )
204 {
205 break;
206 }
207 }
208 }
209 else
210 {
211 if( !token )
212 {
213 token = 1;
214 k = 0;
215 }
216
217 if( token )
218 {
219 if( k < sizeof( value_buf ) - 1 )
220 {
221 value_buf[ k ++ ] = *c;
222 }
223 }
224 }
225
226 c ++;
227 }
228
229 // Add remaining case if we hit null
230 if( token && (i < count) )
231 {
232 value_buf[ k ] = 0x00;
233 interp_func( value_buf, ((u8 *)arr) + i*esize );
234 }
235 }
236
237 void kv_int_array( vdf_node *node, const char *key, u32 count, int *arr )
238 {
239 kv_parse_array( kv_get( node, key, NULL ), sizeof(int), count, vdf_str_to_int, arr );
240 }
241
242 void kv_float_array( vdf_node *node, const char *key, u32 count, float *arr )
243 {
244 kv_parse_array( kv_get( node, key, NULL ), sizeof(float), count, vdf_str_to_float, arr );
245 }
246
247 void kv_double_array( vdf_node *node, const char *key, u32 count, double *arr )
248 {
249 kv_parse_array( kv_get( node, key, NULL ), sizeof(double), count, vdf_str_to_double, arr );
250 }
251
252 int kv_get_int( vdf_node *node, const char *key, const int default_value )
253 {
254 const char *v = kv_get( node, key, NULL );
255 return v? atoi(v): default_value;
256 }
257
258 float kv_get_float( vdf_node *node, const char *key, float default_value )
259 {
260 const char *v = kv_get( node, key, NULL );
261 return v? atof( v ): default_value;
262 }
263
264 vdf_node *vdf_create_node( vdf_node *parent, const char *name )
265 {
266 vdf_node *node = calloc( 1, sizeof( vdf_node ) );
267
268 if( name )
269 {
270 node->name = csr_malloc( strlen( name )+1 );
271 strcpy( node->name, name );
272 }
273
274 if( parent )
275 {
276 node->parent = parent;
277
278 parent->nodes = csr_sb_reserve( parent->nodes, 1, sizeof(vdf_node *) );
279
280 vdf_node **child = (vdf_node **)csr_sb_use( parent->nodes );
281 *child = node;
282 }
283
284 return node;
285 }
286
287 void vdf_kv_append( vdf_node *p, const char *k, const char *v )
288 {
289 p->pairs = csr_sb_reserve( p->pairs, 1, sizeof(vdf_kv) );
290 vdf_kv *kv = (vdf_kv *)csr_sb_use( p->pairs );
291
292 u32 sv = strlen(v)+1;
293 u32 sk = strlen(k)+1;
294
295 kv->key = csr_malloc( sv+sk );
296 kv->value = kv->key+sk;
297
298 memcpy( kv->key, k, sk );
299 memcpy( kv->value, v, sv );
300 }
301
302 void vdf_free_r( vdf_node *p )
303 {
304 for( int i = 0; i < csr_sb_count( p->pairs ); i ++ )
305 {
306 free( p->pairs[ i ].key );
307 }
308
309 for( int i = 0; i < csr_sb_count( p->nodes ); i ++ )
310 {
311 vdf_free_r( p->nodes[ i ] );
312 }
313
314 csr_sb_free( p->pairs );
315 csr_sb_free( p->nodes );
316 free( p->name );
317 free( p );
318 }
319
320 // PARSING
321 // ==================================================================================================================
322
323 struct vdf_ctx
324 {
325 char name[2048];
326
327 vdf_node *root;
328
329 u32 lines;
330 u32 errors;
331
332 // State
333 struct
334 {
335 int wait;
336 int expect_decl;
337
338 char *tokens[2];
339 int i;
340
341 char *ptr_read;
342
343 vdf_node *pnode;
344 }
345 st;
346 };
347
348 void vdf_newln( vdf_ctx *ctx )
349 {
350 ctx->lines ++;
351
352 ctx->st.tokens[0] = NULL;
353 ctx->st.tokens[1] = NULL;
354 ctx->st.i = 0;
355 }
356
357 void vdf_endl( vdf_ctx *ctx )
358 {
359 // Final out-tokens
360 if( ctx->st.tokens[0] )
361 {
362 // Keypair
363 if( ctx->st.tokens[1] )
364 {
365 vdf_kv_append( ctx->st.pnode, ctx->st.tokens[0], ctx->st.tokens[1] );
366 }
367 else
368 {
369 // Decl
370 strcpy( ctx->name, ctx->st.tokens[0] );
371 ctx->st.expect_decl = 1;
372 }
373 }
374
375 vdf_newln( ctx );
376 }
377
378 int vdf_line_control( vdf_ctx *ctx )
379 {
380 if( *ctx->st.ptr_read == '\r' )
381 {
382 *ctx->st.ptr_read = 0x00;
383 return 1;
384 }
385 if( *ctx->st.ptr_read == '\n' )
386 {
387 *ctx->st.ptr_read = 0x00;
388 vdf_endl( ctx );
389 return 2;
390 }
391
392 return 0;
393 }
394
395 void vdf_wait_endl( vdf_ctx *ctx )
396 {
397 while( (*ctx->st.ptr_read) && (*ctx->st.ptr_read != '\n') )
398 {
399 if( vdf_line_control( ctx ) == 2 )
400 {
401 return;
402 }
403
404 ctx->st.ptr_read ++;
405 }
406 }
407
408 void vdf_parse_string( vdf_ctx *ctx )
409 {
410 while( *ctx->st.ptr_read )
411 {
412 if( *ctx->st.ptr_read == '"' )
413 {
414 *ctx->st.ptr_read = 0x00;
415 return;
416 }
417
418 if( vdf_line_control( ctx ) )
419 {
420 fprintf( stderr, "Unexpected end of line character (Line: %u)\n", ctx->lines );
421 return;
422 }
423
424 ctx->st.ptr_read ++;
425 }
426 }
427
428 int vdf_parse_structure( vdf_ctx *ctx )
429 {
430 if( *ctx->st.ptr_read == '{' )
431 {
432 if( ctx->st.tokens[0] || !ctx->st.expect_decl )
433 {
434 fprintf( stderr, "Unexpected token '{' (Line: %u)\n", ctx->lines );
435 ctx->errors ++;
436 }
437
438 ctx->st.expect_decl = 0;
439 ctx->st.pnode = vdf_create_node( ctx->st.pnode, ctx->name );
440
441 vdf_wait_endl( ctx );
442 return 1;
443 }
444
445 // Closing block, jump read head back to parent
446 if( *ctx->st.ptr_read == '}' )
447 {
448 if( !ctx->st.pnode->parent )
449 {
450 fprintf( stderr, "Unexpected token '}' (Line: %u)\n", ctx->lines );
451 ctx->errors ++;
452 }
453 else
454 {
455 ctx->st.pnode = ctx->st.pnode->parent;
456 }
457
458 vdf_wait_endl( ctx );
459 return 1;
460 }
461
462 return 0;
463 }
464
465 void vdf_parse_begin_token( vdf_ctx *ctx, char *ptr )
466 {
467 ctx->st.tokens[ ctx->st.i ] = ptr;
468
469 if( ctx->st.expect_decl )
470 {
471 fprintf( stderr, "Unexpected token '%s' (Line: %u)\n", ctx->name, ctx->lines );
472 ctx->errors ++;
473 }
474 }
475
476 void vdf_parse_feedbuffer( vdf_ctx *ctx, char *buf )
477 {
478 ctx->st.ptr_read = buf;
479
480 while( *ctx->st.ptr_read )
481 {
482 if( !vdf_line_control( ctx ) )
483 {
484 if( (*ctx->st.ptr_read == '/') && (ctx->st.ptr_read[1] == '/') )
485 {
486 *ctx->st.ptr_read = 0x00;
487 ctx->st.ptr_read += 2;
488
489 vdf_endl( ctx );
490 vdf_wait_endl( ctx );
491 }
492 else
493 {
494 if( !vdf_parse_structure( ctx ) )
495 {
496 if( *ctx->st.ptr_read == ' ' || *ctx->st.ptr_read == '\t' )
497 {
498 *ctx->st.ptr_read = 0x00;
499
500 if( ctx->st.tokens[ ctx->st.i ] )
501 {
502 ctx->st.i ++;
503
504 if( ctx->st.i == 2 )
505 {
506 vdf_wait_endl( ctx );
507 }
508 }
509 }
510 // Start new entry
511 else if( !ctx->st.tokens[ ctx->st.i ] )
512 {
513 if( *ctx->st.ptr_read == '"' )
514 {
515 *ctx->st.ptr_read = 0x00;
516 ctx->st.ptr_read ++;
517
518 vdf_parse_begin_token( ctx, ctx->st.ptr_read );
519 vdf_parse_string( ctx );
520 }
521 else
522 {
523 if( !( *ctx->st.ptr_read == '/' && *(ctx->st.ptr_read + 1) == *ctx->st.ptr_read ) )
524 {
525 vdf_parse_begin_token( ctx, ctx->st.ptr_read );
526 }
527 }
528 }
529 }
530 }
531 }
532
533 ctx->st.ptr_read ++;
534 }
535 }
536
537 vdf_node *vdf_open_file( const char *fn )
538 {
539 char *text_src = csr_textasset_read( fn );
540
541 if( !text_src )
542 {
543 fprintf( stderr, "vdf open failed\n" );
544 return NULL;
545 }
546
547 vdf_ctx ctx = {0};
548 ctx.root = ctx.st.pnode = vdf_create_node( NULL, NULL );
549
550 vdf_newln( &ctx );
551 vdf_parse_feedbuffer( &ctx, text_src );
552
553 free( text_src );
554 return ctx.root;
555 }
556
557 // OUTPUT
558 // ==================================================================================================================
559
560 void vdf_out_indent( const int n, FILE *file )
561 {
562 for( int x = 0; x < n; x ++ )
563 fprintf( file, "\t" );
564 }
565
566 void vdf_out( vdf_node *h, int lvl, int declare, FILE *file )
567 {
568 if( declare )
569 {
570 vdf_out_indent( lvl, file ); fprintf( file, "\"%s\"\n", h->name );
571 vdf_out_indent( lvl, file ); fprintf( file, "{\n" );
572 }
573
574 for( int i = 0; i < csr_sb_count( h->pairs ); i ++ )
575 {
576 vdf_out_indent( lvl+1, file ); fprintf( file, "\"%s\" \"%s\"\n", h->pairs[i].key, h->pairs[i].value );
577 }
578
579 for( int i = 0; i < csr_sb_count( h->nodes ); i ++ )
580 {
581 vdf_out( h->nodes[i], lvl + 1, 1, file );
582 }
583
584 if( declare )
585 {
586 vdf_out_indent( lvl, file ); fprintf( file, "}\n" );
587 }
588 }
589
590 void vdf_save( vdf_node *node, const char *fn )
591 {
592 FILE* file = fopen( fn, "w" );
593
594 vdf_out( node, -1, 0, file );
595
596 fclose( file );
597 }
598
599 void vdf_print( vdf_node *node )
600 {
601 vdf_out( node, -1, 0, stdout );
602 }