b5fb4a482bf991ef4624b65ab93b89be33da51a6
[vg.git] / vg_msg.h
1 #ifndef VG_MSG_H
2 #define VG_MSG_H
3 #include "vg_stdint.h"
4 #include "vg_platform.h"
5
6 /*
7 * Example data:
8 * kvstr "someinfo"
9 * kvint 200
10 * frame "person"{
11 * name "jeff"
12 * country "england"
13 * }
14 * frame "building"{
15 * capacity 1000
16 * }
17 * frame "person"{
18 * country "wales"
19 * name "micheal"
20 * }
21 *
22 * Creating the data in code:
23 * -----------------------------------------------------------------------------
24 * u8 data_buf[512];
25 * vg_msg data;
26 * vg_msg_init( &data, data_buf, 512 );
27 *
28 * vg_msg_wkvstr( &data, "kvstr", "someinfo" );
29 * vg_msg_wkvu32( &data, "kvint", 200 );
30 *
31 * vg_msg_frame( &data, "person" );
32 * vg_msg_wkvstr( &data, "name", "jeff" );
33 * vg_msg_wkvstr( &data, "country", "england" );
34 * vg_msg_end_frame( &data );
35 *
36 * vg_msg_frame( &data, "building" );
37 * vg_msg_wkvu32( &data, "capacity", 1000 );
38 * vg_msg_end_frame( &data );
39 *
40 * vg_msg_frame( &data, "person" );
41 * vg_msg_wkvstr( &data, "country", "wales" );
42 * vg_msg_wkvstr( &data, "name", "micheal" );
43 * vg_msg_end_frame( &data );
44 *
45 * Saving the data out
46 * -----------------------------------------------------------------------------
47 *
48 * if( data.error == k_vg_msg_error_OK ){
49 * // write data_buf, for length data.cur
50 * }
51 *
52 * Load the data
53 * -----------------------------------------------------------------------------
54 *
55 * u8 data_buf[512];
56 * u32 data_len;
57 *
58 * // read data_buf and data_len
59 *
60 * vg_msg data;
61 * vg_msg_init( &data, data_buf, data_len );
62 *
63 *
64 * Reading data
65 * -----------------------------------------------------------------------------
66 *
67 * if( vg_msg_seekframe( &msg, "rows" ) ){
68 * while( vg_msg_seekframe( &msg, NULL ) ){
69 * vg_warn( "%s\n", vg_msg_readkvstr( &msg, "yedo" ) );
70 * vg_msg_skip_frame( &msg );
71 * }
72 * }
73 *
74 * Reading back the stream linearly
75 * -----------------------------------------------------------------------------
76 *
77 * vg_msg_cmd cmd;
78 * while( vg_msg_next( &data, &cmd ) ){
79 * if( cmd.code == k_vg_msg_frame ) printf( "{" );
80 * else if( cmd.code == k_vg_msg_endframe ) printf( "}" );
81 * esle if( cmd.code == k_vg_msg_kvstring )
82 * printf( "string: %s\n", cmd.value._buf );
83 * }
84 */
85
86 enum vg_msg_code{
87 /* low types */
88 k_vg_msg_end = 0,
89 k_vg_msg_frame = 1,
90 k_vg_msg_endframe = 2,
91 k_vg_msg_kv = 10,
92 k_vg_msg_kvstring = 11,
93 k_vg_msg_kvbin = 12,
94
95 /* variable sized types */
96 k_vg_msg_float = 0x40,
97 k_vg_msg_unsigned = 0x80,
98 k_vg_msg_signed = 0xC0,
99
100 /* masks */
101 k_vg_msg_array_count_bits = 0x3C,
102 k_vg_msg_type_size_bits = 0x03,
103 k_vg_msg_type_base_bits = 0xC0,
104 k_vg_msg_type_bits = k_vg_msg_type_base_bits|k_vg_msg_type_size_bits,
105
106 /* sizes */
107 k_vg_msg_8b = 0x00,
108 k_vg_msg_16b = 0x01,
109 k_vg_msg_32b = 0x02,
110 k_vg_msg_64b = 0x03,
111
112 /* common types */
113 k_vg_msg_u8 = k_vg_msg_unsigned|k_vg_msg_8b,
114 k_vg_msg_u16 = k_vg_msg_unsigned|k_vg_msg_16b,
115 k_vg_msg_u32 = k_vg_msg_unsigned|k_vg_msg_32b,
116 k_vg_msg_u64 = k_vg_msg_unsigned|k_vg_msg_64b,
117 k_vg_msg_i8 = k_vg_msg_signed |k_vg_msg_8b,
118 k_vg_msg_i16 = k_vg_msg_signed |k_vg_msg_16b,
119 k_vg_msg_i32 = k_vg_msg_signed |k_vg_msg_32b,
120 k_vg_msg_i64 = k_vg_msg_signed |k_vg_msg_64b,
121 k_vg_msg_f32 = k_vg_msg_float |k_vg_msg_32b,
122 k_vg_msg_f64 = k_vg_msg_float |k_vg_msg_64b,
123
124 k_vg_msg_v2f = k_vg_msg_float |k_vg_msg_32b | (1<<2),
125 k_vg_msg_v3f = k_vg_msg_float |k_vg_msg_32b | (2<<2),
126 k_vg_msg_v4f = k_vg_msg_float |k_vg_msg_32b | (3<<2)
127 };
128
129 typedef struct vg_msg vg_msg;
130 typedef struct vg_msg_cmd vg_msg_cmd;
131 typedef struct vg_msg_cursor vg_msg_cursor;
132 struct vg_msg{
133 u32 max;
134 u8 *buf;
135
136 /* reading */
137 struct vg_msg_cursor {
138 u32 co, depth;
139 }
140 cur;
141
142 enum vg_msg_error{
143 k_vg_msg_error_OK,
144 k_vg_msg_error_unbalanced,
145 k_vg_msg_error_overflow,
146 k_vg_msg_error_unhandled_cmd
147 }
148 error;
149 };
150
151 struct vg_msg_cmd{
152 u8 code;
153
154 const char *key;
155 u32 key_djb2;
156
157 const void *value;
158 u32 value_djb2;
159
160 u32 len; /* set if binary type */
161 };
162
163 /* write a buffer from msg, rang checked. */
164 static void vg_msg_wbuf( vg_msg *msg, u8 *buf, u32 len ){
165 if( msg->error != k_vg_msg_error_OK ) return;
166 if( msg->cur.co+len > msg->max ){
167 msg->error = k_vg_msg_error_overflow;
168 return;
169 }
170
171 for( u32 i=0; i<len; i++ ){
172 msg->buf[ msg->cur.co ++ ] = buf[i];
173 }
174 }
175
176 /* read a buffer from msg, rang checked. */
177 static void vg_msg_rbuf( vg_msg *msg, u8 *buf, u32 len ){
178 if( msg->error != k_vg_msg_error_OK ) return;
179 if( msg->cur.co+len > msg->max ){
180 msg->error = k_vg_msg_error_overflow;
181 return;
182 }
183
184 for( u32 i=0; i<len; i++ ){
185 buf[i] = msg->buf[ msg->cur.co ++ ];
186 }
187 }
188
189 /* write null terminated string to stream */
190 static void vg_msg_wstr( vg_msg *msg, const char *str ){
191 if( msg->error != k_vg_msg_error_OK ) return;
192 for( u32 i=0;; i++ ){
193 vg_msg_wbuf( msg, (u8[]){ str[i] }, 1 );
194 if( !str[i] ) break;
195 }
196 }
197
198 /* read null terminated string, range check and generate hash (djb2) */
199 static const char *vg_msg_rstr( vg_msg *msg, u32 *djb2 ){
200 if( msg->error != k_vg_msg_error_OK ) return 0;
201
202 u32 hash = 5381, c;
203 const char *str = (void *)(&msg->buf[ msg->cur.co ]);
204
205 while( (c = msg->buf[ msg->cur.co ++ ]) ){
206 if( msg->cur.co >= msg->max ){
207 msg->error = k_vg_msg_error_overflow;
208 return 0;
209 }
210 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
211 }
212
213 *djb2 = hash;
214 return str;
215 }
216
217 /* begin a new frame in message stream */
218 static void vg_msg_frame( vg_msg *msg, const char *name ){
219 if( msg->error != k_vg_msg_error_OK ) return;
220
221 msg->cur.depth ++;
222 vg_msg_wbuf( msg, (u8[]){ k_vg_msg_frame }, 1 );
223 vg_msg_wstr( msg, name );
224 }
225
226 /* end frame in message stream */
227 static void vg_msg_end_frame( vg_msg *msg ){
228 if( msg->error != k_vg_msg_error_OK ) return;
229 if( !msg->cur.depth ){
230 msg->error = k_vg_msg_error_unbalanced;
231 return;
232 }
233 msg->cur.depth --;
234 vg_msg_wbuf( msg, (u8[]){ k_vg_msg_endframe }, 1 );
235 }
236
237 /* write a KV string to stream */
238 static void vg_msg_wkvstr( vg_msg *msg, const char *key, const char *value ){
239 vg_msg_wbuf( msg, (u8[]){ k_vg_msg_kvstring }, 1 );
240 vg_msg_wstr( msg, key );
241 vg_msg_wstr( msg, value );
242 }
243
244 /* write a binary block to stream */
245 static void vg_msg_wkvbin( vg_msg *msg, const char *key, u8 *bin, u32 len ){
246 vg_msg_wbuf( msg, (u8[]){ k_vg_msg_kvbin }, 1 );
247 vg_msg_wstr( msg, key );
248 vg_msg_wbuf( msg, (u8 *)(&len), 4 );
249 vg_msg_wbuf( msg, bin, len );
250 }
251
252 static u32 vg_msg_cmd_array_count( u8 code ){
253 return ((code & k_vg_msg_array_count_bits)>>2) + 1;
254 }
255
256 static u32 vg_msg_cmd_type_size( u8 code ){
257 return 0x1 << (code & k_vg_msg_type_size_bits);
258 }
259
260 /* get the byte count of a sized code */
261 static u32 vg_msg_cmd_bytecount( u8 code ){
262 return vg_msg_cmd_array_count( code ) * vg_msg_cmd_type_size( code );
263 }
264
265 static u8 vg_msg_count_bits( u32 count ){
266 assert( (count <= 16) && count );
267 return ((count-1)<<2);
268 }
269
270 /* write a sized type */
271 static void vg_msg_wkvnum( vg_msg *msg, const char *key,
272 u8 type, u8 count, void *data ){
273 u8 code = type | vg_msg_count_bits(count);
274
275 vg_msg_wbuf( msg, &code, 1 );
276 vg_msg_wstr( msg, key );
277 vg_msg_wbuf( msg, data, vg_msg_cmd_bytecount(code) );
278 }
279
280 #define _WRITE_KV_INTG_HELPER( TYPE ) \
281 static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \
282 vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, &v ); \
283 }
284
285 #define _WRITE_KV_VEC_HELPER( TYPE ) \
286 static void vg_msg_wkv##TYPE( vg_msg *msg, const char *key, TYPE v ){ \
287 vg_msg_wkvnum( msg, key, k_vg_msg_##TYPE, 1, v ); \
288 }
289
290 _WRITE_KV_INTG_HELPER( u8 )
291 _WRITE_KV_INTG_HELPER( u16 )
292 _WRITE_KV_INTG_HELPER( u32 )
293 _WRITE_KV_INTG_HELPER( u64 )
294 _WRITE_KV_INTG_HELPER( i8 )
295 _WRITE_KV_INTG_HELPER( i16 )
296 _WRITE_KV_INTG_HELPER( i32 )
297 _WRITE_KV_INTG_HELPER( i64 )
298 _WRITE_KV_INTG_HELPER( f32 )
299 _WRITE_KV_INTG_HELPER( f64 )
300 _WRITE_KV_VEC_HELPER( v2f )
301 _WRITE_KV_VEC_HELPER( v3f )
302 _WRITE_KV_VEC_HELPER( v4f )
303
304 static void vg_msg_init( vg_msg *msg, u8 *buffer, u32 len ){
305 msg->buf = buffer;
306 msg->cur.co = 0;
307 msg->cur.depth = 0;
308 msg->error = k_vg_msg_error_OK;
309 msg->max = len;
310 }
311
312 /*
313 * The stream reading interface
314 * -----------------------------------------------------------------------------
315 */
316
317 /* move the cursor through the next message. it will always read in the value or
318 * create an error if it runs of the end of the stream. every possible command
319 * must be handled in this function */
320 static int vg_msg_next( vg_msg *msg, vg_msg_cmd *cmd ){
321 vg_msg_rbuf( msg, &cmd->code, 1 );
322 if( msg->error != k_vg_msg_error_OK ) return 0;
323
324 #ifdef VG_MSG_V1_SUPPORT
325 /* |sized| |count-1| |shift|
326 * 0 1 0 0 0 1 0 0 0x44 (1 byte, float[2]. So, never used anyway)
327 * converts to
328 * 1 0 0 0 0 0 1 0 0x82
329 */
330 if( cmd->code == 0x44 ) cmd->code = 0x82;
331 #endif
332 cmd->key_djb2 = 0;
333 if( msg->error != k_vg_msg_error_OK ) return 0;
334
335 if( cmd->code == k_vg_msg_frame ){
336 cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
337 msg->cur.depth ++;
338 }
339 else if( cmd->code == k_vg_msg_endframe ){
340 if( !msg->cur.depth ){
341 msg->error = k_vg_msg_error_unbalanced;
342 return 0;
343 }
344 msg->cur.depth --;
345 }
346 else if( cmd->code >= k_vg_msg_kv ){
347 cmd->key = vg_msg_rstr( msg, &cmd->key_djb2 );
348 cmd->value_djb2 = 0;
349
350 if( cmd->code & k_vg_msg_type_base_bits ){
351 u32 bytes = vg_msg_cmd_bytecount( cmd->code );
352 cmd->value = &msg->buf[ msg->cur.co ];
353 msg->cur.co += bytes;
354 }
355 else if( cmd->code == k_vg_msg_kvstring ){
356 cmd->value = vg_msg_rstr( msg, &cmd->value_djb2 );
357 }
358 else if( cmd->code == k_vg_msg_kvbin ){
359 vg_msg_rbuf( msg, (u8 *)(&cmd->len), 4 );
360 if( msg->error != k_vg_msg_error_OK )
361 return 0;
362 cmd->value = &msg->buf[ msg->cur.co ];
363 msg->cur.co += cmd->len;
364 }
365 else
366 msg->error = k_vg_msg_error_unhandled_cmd;
367
368 if( msg->cur.co > msg->max )
369 msg->error = k_vg_msg_error_overflow;
370 }
371 else
372 msg->error = k_vg_msg_error_unhandled_cmd;
373
374 if( msg->error != k_vg_msg_error_OK )
375 return 0;
376 else
377 return 1;
378 }
379
380 /* move through the frame(and subframes) until we fall out of it */
381 static int vg_msg_skip_frame( vg_msg *msg ){
382 vg_msg_cmd cmd;
383
384 u32 start_depth = msg->cur.depth;
385 while( vg_msg_next( msg, &cmd ) )
386 if( msg->cur.depth < start_depth )
387 return 1;
388 return 0;
389 }
390
391 /*
392 * A more friendly but slower interface
393 * -----------------------------------------------------------------------------
394 */
395
396 /* moves to a frame,
397 * returns 0 if drops out of scope or ends.
398 */
399 static int vg_msg_seekframe( vg_msg *msg, const char *name ){
400 vg_msg_cursor orig = msg->cur;
401 vg_msg_cmd cmd;
402 while( vg_msg_next( msg, &cmd ) ){
403 if( msg->cur.depth < orig.depth ){
404 msg->cur = orig;
405 return 0;
406 }
407 if( msg->cur.depth != orig.depth+1 )
408 continue;
409 if( cmd.code == k_vg_msg_frame )
410 if( !name || VG_STRDJB2_EQ( name, cmd.key, cmd.key_djb2 ) )
411 return 1;
412 }
413
414 msg->cur = orig;
415 return 0;
416 }
417
418 /*
419 * Convert any type integral type to u64
420 */
421 static u64 vg_msg_cast_to_u64( const void *src, u8 src_base, u8 src_size ){
422 if( src_base == k_vg_msg_float ){
423 if( src_size == 4 ) return (u64)(*((f32*)src));
424 else if( src_size == 8 ) return (u64)(*((f64*)src));
425 else return 0;
426 }
427 else {
428 u64 a = 0;
429 memcpy( &a, src, src_size );
430 return a;
431 }
432 }
433
434 /*
435 * Convert any integral type to i64
436 */
437 static i64 vg_msg_cast_to_i64( const void *src, u8 src_base, u8 src_size ){
438 if( src_base == k_vg_msg_float ){
439 if( src_size == 4 ) return (i64)(*((f32*)src));
440 else if( src_size == 8 ) return (i64)(*((f64*)src));
441 else return 0;
442 }
443 else {
444 u64 a = 0;
445 memcpy( &a, src, src_size );
446
447 if( (src_base == k_vg_msg_signed) && (src_size != 8) ){
448 /* extend sign bit */
449 u64 sign_bit = 0x1llu << ((src_size*8)-1);
450 if( a & sign_bit )
451 a |= (0xffffffffffffffffllu << (64-__builtin_clzll( a )));
452 }
453
454 return *((i64*)&a);
455 }
456 }
457
458 /*
459 * Convert any integral type to f64
460 */
461 static f64 vg_msg_cast_to_f64( const void *src, u8 src_base, u8 src_size ){
462 if( src_base == k_vg_msg_float ){
463 if( src_size == 4 ) return (f64)(*((f32*)src));
464 else if( src_size == 8 ) return *((f64*)src);
465 else return 0.0;
466 }
467 else
468 return (f64)vg_msg_cast_to_i64( src, src_base, src_size );
469 }
470
471 /*
472 * Convert any full integral type code to another
473 * Passing in non-integral codes is undefined
474 */
475 static void vg_msg_cast( const void *src, u8 src_code, void *dst, u8 dst_code ){
476 if( src_code == dst_code ){
477 memcpy( dst, src, vg_msg_cmd_bytecount( src_code ) );
478 }
479 else {
480 u32 src_n = vg_msg_cmd_array_count( src_code ),
481 dst_n = vg_msg_cmd_array_count( dst_code ),
482 src_s = vg_msg_cmd_type_size( src_code ),
483 dst_s = vg_msg_cmd_type_size( dst_code ),
484 src_b = src_code & k_vg_msg_type_base_bits,
485 dst_b = dst_code & k_vg_msg_type_base_bits;
486
487 memset( dst, 0, dst_s * dst_n );
488
489 for( u32 i=0; i<VG_MIN(src_n,dst_n); i ++ ){
490 const void *ptr_s = src + i*src_s;
491 void *ptr_d = dst + i*dst_s;
492
493 if( dst_b == k_vg_msg_unsigned ){
494 u64 a = vg_msg_cast_to_u64( ptr_s, src_b, src_s );
495 if ( dst_s == 1 ) *((u8 *)ptr_d) = (u8 )a;
496 else if( dst_s == 2 ) *((u16*)ptr_d) = (u16)a;
497 else if( dst_s == 4 ) *((u32*)ptr_d) = (u32)a;
498 else if( dst_s == 8 ) *((u64*)ptr_d) = a;
499 }
500 else if( dst_b == k_vg_msg_signed ){
501 i64 a = vg_msg_cast_to_i64( ptr_s, src_b, src_s );
502 if ( dst_s == 1 ) *((i8 *)ptr_d) = (i8 )a;
503 else if( dst_s == 2 ) *((i16*)ptr_d) = (i16)a;
504 else if( dst_s == 4 ) *((i32*)ptr_d) = (i32)a;
505 else if( dst_s == 8 ) *((i64*)ptr_d) = a;
506 }
507 else {
508 f64 a = vg_msg_cast_to_f64( ptr_s, src_b, src_s );
509 if ( dst_s == 4 ) *((f32*)ptr_d) = (f32)a;
510 else if( dst_s == 8 ) *((f64*)ptr_d) = a;
511 }
512 }
513 }
514 }
515
516 /*
517 * search in current level from cursor, to find kv cmd
518 * returns 0 if not found
519 * Cursor does not move
520 * If found, the kv command is written to cmd
521 */
522 static int vg_msg_getkvcmd( vg_msg *msg, const char *key, vg_msg_cmd *cmd ){
523 vg_msg_cursor orig = msg->cur;
524 while( vg_msg_next( msg, cmd ) ){
525 if( msg->cur.depth < orig.depth ){
526 msg->cur = orig;
527 return 0;
528 }
529 if( msg->cur.depth > orig.depth )
530 continue;
531 if( cmd->code > k_vg_msg_kv ){
532 if( VG_STRDJB2_EQ( key, cmd->key, cmd->key_djb2 ) ){
533 msg->cur = orig;
534 return 1;
535 }
536 }
537 }
538 msg->error = k_vg_msg_error_OK;
539 msg->cur = orig;
540 return 0;
541 }
542
543 /*
544 * Read a integral KV out to dst, and perform conversion if needed
545 * dst is always defined, if its not found its set to 0
546 */
547 static int vg_msg_getkvintg( vg_msg *msg, const char *key, u8 type, void *dst ){
548 vg_msg_cmd cmd;
549 if( vg_msg_getkvcmd( msg, key, &cmd ) ){
550 vg_msg_cast( cmd.value, cmd.code, dst, type );
551 return 1;
552 }
553 else {
554 memset( dst, 0, vg_msg_cmd_bytecount(type) );
555 return 0;
556 }
557 }
558
559 /* helper for reading string kvs. returns NULL if not found */
560 static const char *vg_msg_getkvstr( vg_msg *msg, const char *key ){
561 vg_msg_cmd cmd;
562 if( vg_msg_getkvcmd( msg, key, &cmd ) )
563 return cmd.value;
564 else
565 return NULL;
566 }
567
568 #define _GET_KV_INTG_HELPER( TYPE ) \
569 static TYPE vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
570 TYPE default_value ){ \
571 vg_msg_cmd cmd; \
572 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
573 TYPE v; \
574 vg_msg_cast( cmd.value, cmd.code, &v, k_vg_msg_##TYPE ); \
575 return v; \
576 } \
577 else \
578 return default_value; \
579 }
580
581 #define _GET_KV_VEC_HELPER( TYPE ) \
582 static int vg_msg_getkv##TYPE( vg_msg *msg, const char *key, \
583 TYPE v, \
584 TYPE default_value ){ \
585 vg_msg_cmd cmd; \
586 if( vg_msg_getkvcmd( msg, key, &cmd ) ){ \
587 vg_msg_cast( cmd.value, cmd.code, v, k_vg_msg_##TYPE ); \
588 return 1; \
589 } \
590 else \
591 if ( default_value ) \
592 vg_msg_cast( default_value, k_vg_msg_##TYPE, v, k_vg_msg_##TYPE ); \
593 return 0; \
594 }
595
596 _GET_KV_INTG_HELPER( u8 )
597 _GET_KV_INTG_HELPER( u16 )
598 _GET_KV_INTG_HELPER( u32 )
599 _GET_KV_INTG_HELPER( u64 )
600 _GET_KV_INTG_HELPER( i8 )
601 _GET_KV_INTG_HELPER( i16 )
602 _GET_KV_INTG_HELPER( i32 )
603 _GET_KV_INTG_HELPER( i64 )
604 _GET_KV_INTG_HELPER( f32 )
605 _GET_KV_INTG_HELPER( f64 )
606 _GET_KV_VEC_HELPER( v2f )
607 _GET_KV_VEC_HELPER( v3f )
608 _GET_KV_VEC_HELPER( v4f )
609
610 /* debug the thing */
611 static void vg_msg_print( vg_msg *msg, u32 len ){
612 if( msg->error != k_vg_msg_error_OK ){
613 printf( "Message contains errors\n" );
614 return;
615 }
616
617 vg_msg b;
618 vg_msg_init( &b, msg->buf, len );
619
620 vg_msg_cmd cmd;
621 while( vg_msg_next( &b, &cmd ) ){
622 if( cmd.code == k_vg_msg_frame ){
623 for( u32 i=0; i<b.cur.depth-1; i++ ) printf( " " );
624 printf( "'%s'{\n", cmd.key );
625 }
626 else {
627 for( u32 i=0; i<b.cur.depth; i++ ) printf( " " );
628
629 if( cmd.code == k_vg_msg_endframe )
630 printf( "}\n" );
631 else if( cmd.code == k_vg_msg_kvstring )
632 printf( "'%s': '%s'\n", cmd.key, (char *)cmd.value );
633 else if( cmd.code == k_vg_msg_kvbin )
634 printf( "'%s': <binary data> (%u bytes)\n", cmd.key, cmd.len );
635 else {
636 u32 base = cmd.code & k_vg_msg_type_base_bits,
637 count = vg_msg_cmd_array_count( cmd.code ),
638 size = vg_msg_cmd_type_size( cmd.code );
639
640 printf( "'%s': ", cmd.key );
641
642 if( count > 1 ) printf( "{ " );
643
644 for( u32 i=0; i<count; i++ ){
645 const void *p = cmd.value + size*i;
646
647 if( base == k_vg_msg_unsigned ){
648 printf(
649 #ifdef _WIN32
650 "%llu"
651 #else
652 "%lu"
653 #endif
654 , vg_msg_cast_to_u64( p, base, size ) );
655 }
656 else if( base == k_vg_msg_signed ){
657 printf(
658 #ifdef _WIN32
659 "%lld"
660 #else
661 "%ld"
662 #endif
663 , vg_msg_cast_to_i64( p, base, size ) );
664 }
665 else
666 printf( "%f", vg_msg_cast_to_f64( p, base, size ));
667
668 if( i+1<count ) printf(", ");
669 }
670
671 if( count > 1 ) printf( " }" );
672 printf( "\n" );
673 }
674 }
675 }
676 }
677
678 #endif /* VG_MSG_H */