@@ -38,11 +38,14 @@ size_t xvsnprintf(char *buf, size_t len, const char *fmt, va_list *ap);
3838size_t xsnprintf (char * , size_t , const char * fmt , ...);
3939
4040// Pre-defined %M/%m formatting functions
41- size_t fmt_ip4 (void (* out )(char , void * ), void * arg , va_list * ap );
42- size_t fmt_ip6 (void (* out )(char , void * ), void * arg , va_list * ap );
43- size_t fmt_mac (void (* out )(char , void * ), void * arg , va_list * ap );
44- size_t fmt_b64 (void (* out )(char , void * ), void * arg , va_list * ap );
45- size_t fmt_esc (void (* out )(char , void * ), void * arg , va_list * ap );
41+ size_t fmt_ip4 (void (* fn )(char , void * ), void * arg , va_list * ap );
42+ size_t fmt_ip6 (void (* fn )(char , void * ), void * arg , va_list * ap );
43+ size_t fmt_mac (void (* fn )(char , void * ), void * arg , va_list * ap );
44+ size_t fmt_b64 (void (* fn )(char , void * ), void * arg , va_list * ap );
45+ size_t fmt_esc (void (* fn )(char , void * ), void * arg , va_list * ap );
46+
47+ // Utility functions
48+ void xhexdump (void (* fn )(char , void * ), void * arg , const void * buf , size_t len );
4649
4750// JSON parsing API
4851int json_get (const char * buf , int len , const char * path , int * size );
@@ -83,26 +86,28 @@ size_t xsnprintf(char *buf, size_t len, const char *fmt, ...) {
8386 return n ;
8487}
8588
86- size_t fmt_ip4 (void (* out )(char , void * ), void * arg , va_list * ap ) {
89+ size_t fmt_ip4 (void (* fn )(char , void * ), void * arg , va_list * ap ) {
8790 uint8_t * p = va_arg (* ap , uint8_t * );
88- return xprintf (out , arg , "%d.%d.%d.%d" , p [0 ], p [1 ], p [2 ], p [3 ]);
91+ return xprintf (fn , arg , "%d.%d.%d.%d" , p [0 ], p [1 ], p [2 ], p [3 ]);
8992}
9093
9194#define U16 (p ) ((((uint16_t) (p)[0]) << 8) | (p)[1])
92- size_t fmt_ip6 (void (* out )(char , void * ), void * arg , va_list * ap ) {
95+ size_t fmt_ip6 (void (* fn )(char , void * ), void * arg , va_list * ap ) {
9396 uint8_t * p = va_arg (* ap , uint8_t * );
94- return xprintf (out , arg , "[%x:%x:%x:%x:%x:%x:%x:%x]" , U16 (& p [0 ]), U16 (& p [2 ]),
97+ return xprintf (fn , arg , "[%x:%x:%x:%x:%x:%x:%x:%x]" , U16 (& p [0 ]), U16 (& p [2 ]),
9598 U16 (& p [4 ]), U16 (& p [6 ]), U16 (& p [8 ]), U16 (& p [10 ]), U16 (& p [12 ]),
9699 U16 (& p [14 ]));
97100}
98101
99- size_t fmt_mac (void (* out )(char , void * ), void * arg , va_list * ap ) {
102+ size_t fmt_mac (void (* fn )(char , void * ), void * arg , va_list * ap ) {
100103 uint8_t * p = va_arg (* ap , uint8_t * );
101- return xprintf (out , arg , "%02x:%02x:%02x:%02x:%02x:%02x" , p [0 ], p [1 ], p [2 ],
104+ return xprintf (fn , arg , "%02x:%02x:%02x:%02x:%02x:%02x" , p [0 ], p [1 ], p [2 ],
102105 p [3 ], p [4 ], p [5 ]);
103106}
104107
105- static int xisdigit (int c ) { return c >= '0' && c <= '9' ; }
108+ static int xisdigit (int c ) {
109+ return c >= '0' && c <= '9' ;
110+ }
106111
107112static size_t xstrlen (const char * s ) {
108113 size_t n = 0 ;
@@ -282,24 +287,24 @@ static char xesc(int c, int esc) {
282287 return 0 ;
283288}
284289
285- size_t fmt_esc (void (* out )(char , void * ), void * param , va_list * ap ) {
290+ size_t fmt_esc (void (* fn )(char , void * ), void * param , va_list * ap ) {
286291 unsigned len = va_arg (* ap , unsigned );
287292 const char * s = va_arg (* ap , const char * );
288293 size_t i , n = 0 ;
289294 if (len == 0 ) len = s == NULL ? 0 : (unsigned ) xstrlen (s );
290295 for (i = 0 ; i < len && s [i ] != '\0' ; i ++ ) {
291296 char c = xesc (s [i ], 1 );
292297 if (c ) {
293- out ('\\' , param ), out (c , param ), n += 2 ;
298+ fn ('\\' , param ), fn (c , param ), n += 2 ;
294299 } else {
295- out (s [i ], param );
300+ fn (s [i ], param );
296301 n ++ ;
297302 }
298303 }
299304 return n ;
300305}
301306
302- size_t fmt_b64 (void (* out )(char , void * ), void * param , va_list * ap ) {
307+ size_t fmt_b64 (void (* fn )(char , void * ), void * param , va_list * ap ) {
303308 unsigned len = va_arg (* ap , unsigned );
304309 uint8_t * buf = va_arg (* ap , uint8_t * );
305310 size_t i , n = 0 ;
@@ -311,21 +316,21 @@ size_t fmt_b64(void (*out)(char, void *), void *param, va_list *ap) {
311316 char tmp [4 ] = {t [c1 >> 2 ], t [(c1 & 3 ) << 4 | (c2 >> 4 )], '=' , '=' };
312317 if (i + 1 < len ) tmp [2 ] = t [(c2 & 15 ) << 2 | (c3 >> 6 )];
313318 if (i + 2 < len ) tmp [3 ] = t [c3 & 63 ];
314- n += scpy (out , param , tmp , sizeof (tmp ));
319+ n += scpy (fn , param , tmp , sizeof (tmp ));
315320 }
316321 return n ;
317322}
318323
319- size_t xprintf (void (* out )(char , void * ), void * ptr , const char * fmt , ...) {
324+ size_t xprintf (void (* fn )(char , void * ), void * ptr , const char * fmt , ...) {
320325 size_t len = 0 ;
321326 va_list ap ;
322327 va_start (ap , fmt );
323- len = xvprintf (out , ptr , fmt , & ap );
328+ len = xvprintf (fn , ptr , fmt , & ap );
324329 va_end (ap );
325330 return len ;
326331}
327332
328- size_t xvprintf (xout_t out , void * param , const char * fmt , va_list * ap ) {
333+ size_t xvprintf (xout_t fn , void * param , const char * fmt , va_list * ap ) {
329334 size_t i = 0 , n = 0 ;
330335 while (fmt [i ] != '\0' ) {
331336 if (fmt [i ] == '%' ) {
@@ -375,41 +380,41 @@ size_t xvprintf(xout_t out, void *param, const char *fmt, va_list *ap) {
375380 }
376381 for (j = 0 ; j < xl && w > 0 ; j ++ ) w -- ;
377382 for (j = 0 ; pad == ' ' && !minus && k < w && j + k < w ; j ++ )
378- n += scpy (out , param , & pad , 1 );
379- n += scpy (out , param , (char * ) "0x" , xl );
383+ n += scpy (fn , param , & pad , 1 );
384+ n += scpy (fn , param , (char * ) "0x" , xl );
380385 for (j = 0 ; pad == '0' && k < w && j + k < w ; j ++ )
381- n += scpy (out , param , & pad , 1 );
382- n += scpy (out , param , tmp , k );
386+ n += scpy (fn , param , & pad , 1 );
387+ n += scpy (fn , param , tmp , k );
383388 for (j = 0 ; pad == ' ' && minus && k < w && j + k < w ; j ++ )
384- n += scpy (out , param , & pad , 1 );
389+ n += scpy (fn , param , & pad , 1 );
385390 } else if (c == 'm' || c == 'M' ) {
386391 xfmt_t f = va_arg (* ap , xfmt_t );
387- if (c == 'm' ) out ('"' , param );
388- n += f (out , param , ap );
389- if (c == 'm' ) n += 2 , out ('"' , param );
392+ if (c == 'm' ) fn ('"' , param );
393+ n += f (fn , param , ap );
394+ if (c == 'm' ) n += 2 , fn ('"' , param );
390395 } else if (c == 'c' ) {
391396 int ch = va_arg (* ap , int );
392- out ((char ) ch , param );
397+ fn ((char ) ch , param );
393398 n ++ ;
394399 } else if (c == 's' ) {
395400 char * p = va_arg (* ap , char * );
396401 if (pr == ~0U ) pr = p == NULL ? 0 : strlen (p );
397402 for (j = 0 ; !minus && pr < w && j + pr < w ; j ++ )
398- n += scpy (out , param , & pad , 1 );
399- n += scpy (out , param , p , pr );
403+ n += scpy (fn , param , & pad , 1 );
404+ n += scpy (fn , param , p , pr );
400405 for (j = 0 ; minus && pr < w && j + pr < w ; j ++ )
401- n += scpy (out , param , & pad , 1 );
406+ n += scpy (fn , param , & pad , 1 );
402407 } else if (c == '%' ) {
403- out ('%' , param );
408+ fn ('%' , param );
404409 n ++ ;
405410 } else {
406- out ('%' , param );
407- out (c , param );
411+ fn ('%' , param );
412+ fn (c , param );
408413 n += 2 ;
409414 }
410415 i ++ ;
411416 } else {
412- out (fmt [i ], param ), n ++ , i ++ ;
417+ fn (fmt [i ], param ), n ++ , i ++ ;
413418 }
414419 }
415420 return n ;
@@ -644,6 +649,43 @@ long json_get_long(const char *buf, int len, const char *path, long dflt) {
644649 return dflt ;
645650}
646651
652+ static char xnibble (char c ) {
653+ return c < 10 ? c + '0' : c + 'W' ;
654+ }
655+
656+ void xhexdump (void (* fn )(char , void * ), void * a , const void * buf , size_t len ) {
657+ const uint8_t * p = (const uint8_t * ) buf ;
658+ char ascii [16 ];
659+ size_t i , j , n = 0 ;
660+ for (i = 0 ; i < len ; i ++ ) {
661+ if ((i & 15 ) == 0 ) {
662+ // Print buffered ascii chars
663+ if (i > 0 ) {
664+ fn (' ' , a ), fn (' ' , a );
665+ for (j = 0 ; j < sizeof (ascii ); j ++ ) fn (ascii [j ], a );
666+ fn ('\n' , a ), n = 0 ;
667+ }
668+ // Print hex address, then \t
669+ fn (xnibble ((i >> 12 ) & 15 ), a ), fn (xnibble ((i >> 8 ) & 15 ), a );
670+ fn (xnibble ((i >> 4 ) & 15 ), a ), fn ('0' , a );
671+ fn (' ' , a ), fn (' ' , a ), fn (' ' , a );
672+ }
673+ fn (xnibble (p [i ] >> 4 ), a ), fn (xnibble (p [i ] & 15 ), a );
674+ fn (' ' , a ); // Space after hex number
675+ if (p [i ] >= ' ' && p [i ] <= '~' ) {
676+ ascii [n ++ ] = (char ) p [i ]; // Printable
677+ } else {
678+ ascii [n ++ ] = '.' ; // Non-printable
679+ }
680+ }
681+ if (n > 0 ) {
682+ while (n < 16 ) fn (' ' , a ), fn (' ' , a ), fn (' ' , a ), ascii [n ++ ] = ' ' ;
683+ fn (' ' , a ), fn (' ' , a );
684+ for (j = 0 ; j < sizeof (ascii ); j ++ ) fn (ascii [j ], a );
685+ }
686+ fn ('\n' , a );
687+ }
688+
647689#endif // STR_API_ONLY
648690
649691#ifdef __cplusplus
0 commit comments