lib: add %*pHX + %*pHS hexdump in printfrr

(I'll get to `zlog_hexdump()` in a separate pass.)

Signed-off-by: David Lamparter <equinox@diac24.net>
This commit is contained in:
David Lamparter 2021-02-19 00:08:11 +01:00
parent bb12115e0b
commit a4cb97a6c1
5 changed files with 111 additions and 1 deletions

View File

@ -91,6 +91,8 @@ Extensions
+-----------+--------------------------+----------------------------------------------+
| ``%pFX`` | ``struct bgp_dest *`` | ``fe80::1234/64`` (available in BGP only) |
+-----------+--------------------------+----------------------------------------------+
| ``%.*pHX``| ``int len, void *ptr`` | ``12 34 56 78`` (hexdump) |
+-----------+--------------------------+----------------------------------------------+
Printf features like field lengths can be used normally with these extensions,
e.g. ``%-15pI4`` works correctly.

View File

@ -227,7 +227,11 @@ void printfrr_ext_reg(const struct printfrr_ext *);
} \
/* end */
/* fbuf helper functions */
/* fbuf helper functions - note all 3 of these return the length that would
* be written regardless of how much space was available in the buffer, as
* needed for implementing printfrr extensions. (They also accept NULL buf
* for that.)
*/
static inline ssize_t bputs(struct fbuf *buf, const char *str)
{
@ -251,6 +255,17 @@ static inline ssize_t bputch(struct fbuf *buf, char ch)
return 1;
}
static inline ssize_t bputhex(struct fbuf *buf, uint8_t val)
{
static const char hexch[] = "0123456789abcdef";
if (buf && buf->pos < buf->buf + buf->len)
*buf->pos++ = hexch[(val >> 4) & 0xf];
if (buf && buf->pos < buf->buf + buf->len)
*buf->pos++ = hexch[val & 0xf];
return 2;
}
/* %pVA extension, equivalent to Linux kernel %pV */
struct va_format {
@ -261,6 +276,13 @@ struct va_format {
#ifdef _FRR_ATTRIBUTE_PRINTFRR
#pragma FRR printfrr_ext "%pFB" (struct fbuf *)
#pragma FRR printfrr_ext "%pVA" (struct va_format *)
#pragma FRR printfrr_ext "%pHX" (signed char *)
#pragma FRR printfrr_ext "%pHX" (unsigned char *)
#pragma FRR printfrr_ext "%pHX" (void *)
#pragma FRR printfrr_ext "%pHS" (signed char *)
#pragma FRR printfrr_ext "%pHS" (unsigned char *)
#pragma FRR printfrr_ext "%pHS" (void *)
#endif
/* when using non-ISO-C compatible extension specifiers... */

75
lib/strformat.c Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "printfrr.h"
printfrr_ext_autoreg_p("HX", printfrr_hexdump)
static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
ssize_t ret = 0;
ssize_t input_len = printfrr_ext_len(ea);
char sep = ' ';
const uint8_t *pos, *end;
if (ea->fmt[0] == 'c') {
ea->fmt++;
sep = ':';
} else if (ea->fmt[0] == 'n') {
ea->fmt++;
sep = '\0';
}
if (input_len < 0)
return 0;
for (pos = ptr, end = pos + input_len; pos < end; pos++) {
if (sep && pos != ptr)
ret += bputch(buf, sep);
ret += bputhex(buf, *pos);
}
return ret;
}
/* string analog for hexdumps / the "this." in ("74 68 69 73 0a |this.|") */
printfrr_ext_autoreg_p("HS", printfrr_hexdstr)
static ssize_t printfrr_hexdstr(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
ssize_t ret = 0;
ssize_t input_len = printfrr_ext_len(ea);
const uint8_t *pos, *end;
if (input_len < 0)
return 0;
for (pos = ptr, end = pos + input_len; pos < end; pos++) {
if (*pos >= 0x20 && *pos < 0x7f)
ret += bputch(buf, *pos);
else
ret += bputch(buf, '.');
}
return ret;
}

View File

@ -90,6 +90,7 @@ lib_libfrr_la_SOURCES = \
lib/spf_backoff.c \
lib/srcdest_table.c \
lib/stream.c \
lib/strformat.c \
lib/strlcat.c \
lib/strlcpy.c \
lib/systemd.c \

View File

@ -216,5 +216,15 @@ int main(int argc, char **argv)
sg.src.s_addr = INADDR_ANY;
printchk("(*,224.1.2.3)", "%pSG4", &sg);
uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 };
printchk("12 34 00 ca fe 00 aa 55", "%.8pHX", randhex);
printchk("12 34 00 ca fe 00 aa 55", "%.*pHX",
(int)sizeof(randhex), randhex);
printchk("12 34 00 ca", "%.4pHX", randhex);
printchk("12:34:00:ca:fe:00:aa:55", "%.8pHXc", randhex);
printchk("123400cafe00aa55", "%.8pHXn", randhex);
return !!errors;
}