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