author | Olivier Brunel
<jjk@jjacky.com> 2023-04-30 06:59:01 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2023-05-20 18:06:38 UTC |
parent | f577313573a612833bff5bb1d2ee50fbd80bf3bb |
src/doc/buffer.h/buffer_puthex.3.md | +4 | -1 |
src/doc/hex.0.md | +34 | -0 |
src/doc/hex.h/hexall_fmt.3.md | +97 | -0 |
src/liblimb/buffer.h/buffer_puthex.c | +10 | -15 |
src/liblimb/buffer.h/buffer_putmsg.c | +1 | -1 |
src/liblimb/hex.h/hex_fmt.c | +13 | -0 |
src/liblimb/hex.h/hexall_fmt.c | +56 | -0 |
src/liblimb/include/limb/buffer.h | +2 | -1 |
src/liblimb/include/limb/hex.h | +28 | -0 |
src/mkrabintables/hexall_fmt.o | +1 | -0 |
diff --git a/src/doc/buffer.h/buffer_puthex.3.md b/src/doc/buffer.h/buffer_puthex.3.md index 7b39ff7..9192bde 100644 --- a/src/doc/buffer.h/buffer_puthex.3.md +++ b/src/doc/buffer.h/buffer_puthex.3.md @@ -10,7 +10,7 @@ buffer\_puthex - write byte array content as hexadecimal dump into buffer #include <limb/buffer.h> ```pre hl -ssize_t buffer_puthex(buffer *<em>buf</em>, const void *<em>data</em>, size_t <em>dlen</em>) +ssize_t buffer_puthex(buffer *<em>buf</em>, const void *<em>data</em>, size_t <em>dlen</em>, int <em>options</em>) ``` # DESCRIPTION @@ -19,6 +19,9 @@ The `buffer_puthex`() function will write the content of byte array pointed to by `data` of length `dlen` into the buffer `buf` as an hexadecimal dump, i.e. every byte's value will be written out in 2-character hexadecimal form. +Additionally, it is possible to specify some flags in `options` to affect the +output, adding spaces and/or newlines. Refer to [hexall_fmt](3) for more. + # RETURN VALUE The `buffer_puthex`() function returns the number of bytes written into `buf` diff --git a/src/doc/hex.0.md b/src/doc/hex.0.md new file mode 100644 index 0000000..30a46b7 --- /dev/null +++ b/src/doc/hex.0.md @@ -0,0 +1,34 @@ +% limb manual +% hex.h(0) + +# NAME + +hex.h - hexadecimal dumping of data + + +# SYNOPSIS + + #include <limb/hex.h> + + +# DESCRIPTION + +The header defines functions to needed to print/dump data in hexadecimal. + +## Constants + +The following constants are defined : + +: *HEX_SP*, *HEX_1BLOCK_SP*, *HEX_2BLOCK_SP*, *HEX_3BLOCK_SP*, *HEX_4BLOCK_SP*, +: *HEX_LF*, *HEX_1BLOCK_LF*, *HEX_2BLOCK_LF*, *HEX_3BLOCK_LF*, *HEX_4BLOCK_LF* +:: Options that can be passed to the functions below. + +## Functions + +The following functions are defined : + +: [hexall_fmt](3) +:: To print given text/data in hexadecimal. + +: [hex_fmt](3) +:: Similar to [hexall_fmt](3) but don't handle partial processing. diff --git a/src/doc/hex.h/hexall_fmt.3.md b/src/doc/hex.h/hexall_fmt.3.md new file mode 100644 index 0000000..95cf603 --- /dev/null +++ b/src/doc/hex.h/hexall_fmt.3.md @@ -0,0 +1,97 @@ +% limb manual +% hexall_fmt(3) + +# NAME + +hexall\_fmt, hex\_fmt - printf given text/data in hexadecimal + +# SYNOPSIS + + #include <limb/hex.h> + +```pre hl +int hexall_fmt(char *<em>dst</em>, size_t <em>dlen</em>, const char *<em>sce</em>, size_t <em>slen</em>, int <em>options</em>, size_t *<em>w</em>, size_t *<em>r</em>) +ssize_t hex_fmt(char *<em>dst</em>, size_t <em>dlen</em>, const char *<em>sce</em>, size_t <em>slen</em>, int <em>options</em>) +``` + +# DESCRIPTION + +The `hexall_fmt`() function will write the content of `sce` of length `slen` +bytes, starting at offset pointed by `r` (usually 0), into the memory area +pointed by `dst` starting at position `w` (usually 0) and never going past +`dlen`, in hexadecimal form (each byte represented as 2 bytes in base16). + +The values pointed to by `r` and `w` are updated accordingly to reflect the +positions of the last read in `sce` and write in `dst`, respectively. +Specifically, if a byte couldn't be written out for lack of space in `dst`, the +value pointed to by `r` would remain on the last successfully processed byte, +and no "partial write" would have occurred in `dst`. + +If `dst` is *NULL* then nothing is written, the data in `sce` is still processed +and both `r` and `w` (/both/ mandatory) updated accordingly. + +It is possible to define some options affecting the output written in `dst` via +the `options` argument, whose value is constructed as a bitwise-inclusive OR of +the following : + +: *HEX_SP* +:: Add a space after each value (i.e. after the 2 bytes representing one byte in +: `sce`). + +: *HEX_LF* +:: Add a newline (`\n`) at the end. + +: *HEX_1BLOCK_SP*, *HEX_2BLOCK_SP*, *HEX_3BLOCK_SP*, *HEX_4BLOCK_SP* +:: Add a space after every one, two, three or four (respectively) blocks of +:: value have been written out. + +: *HEX_1BLOCK_LF*, *HEX_2BLOCK_LF*, *HEX_3BLOCK_LF*, *HEX_4BLOCK_LF* +:: Add a newline (`\n`) after every one, two, three or four (respectively) +:: blocks of value have been written out. + +When combining those, only one extra character can be written out at any given +position, except for the spaces added via *HEX_SP*. +Meaning that after e.g. 16 values have been written out, either one newline +/or/ one space will be added. For example, using `HEX_1BLOCK_SP | HEX_2BLOCK_SP +| HEX_2BLOCK_LF` would only result in a newline being added : +- Both *HEX_1BLOCK_SP* and *HEX_2BLOCK_SP* match the position, so only one + space would be added, but +- When both spaces and newlines are a match, newlines take priority. + +As indicated, spaces added due to *HEX_SP* are not affected, so 2 spaces could +be added after 8 values if using e.g. `HEX_SP | HEX_1BLOCK_SP` + +Similarly two consecutive newlines will never be added, so using e.g. `HEX_LF | +HEX_4BLOCK_LF` on a 32 bytes block of data (`slen` = 32) would only lead to +a single newline added. + +The `hex_fmt`() function is similar, only without the `r` and `w` arguments, and +different return values. + +# RETURN VALUE + +The `hexall_fmt`() function returns 1 on success. Otherwise it returns 0 and +sets `errno` to indicate the error. + +In either case, values pointed to by `r` and `w` will have been updated to +reflect the positions of the last read in `sce` and write in `dst`, +respectively. + +The `esc_fmt`() returns the number of bytes written into `dst` on success. +Otherwise it returns -1 and set `errno` to indicate the error. + +# ERRORS + +The `escall_fmt`() and `esc_fmt`() functions may fail if : + +: *ENOBUFS* +:: Not enough space in `dst`. + +The `escall_fmt`() function may also fail if : + +: *EINVAL* +:: Either `r` or `w` was too high (more than `slen` or `dlen`, respectively). + +# SEE ALSO + +[buffer_puthex](3) diff --git a/src/liblimb/buffer.h/buffer_puthex.c b/src/liblimb/buffer.h/buffer_puthex.c index 5e2266d..c74d620 100644 --- a/src/liblimb/buffer.h/buffer_puthex.c +++ b/src/liblimb/buffer.h/buffer_puthex.c @@ -1,27 +1,22 @@ /* This file is part of limb https://lila.oss/limb * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ /* SPDX-License-Identifier: GPL-2.0-only */ -#include <skalibs/fmtscan.h> #include <limb/buffer.h> +#include <limb/hex.h> ssize_t -buffer_puthex(buffer *b, const void *data_, size_t dlen) +buffer_puthex(buffer *b, const void *data, size_t dlen, int options) { - const unsigned char *data = data_; - ssize_t w = 0; - char buf[2]; + size_t written = 0, r = 0; - for (size_t i = 0; i < dlen; ++i) { - ssize_t l; - - buf[0] = fmtscan_asc(data[i] >> 4); - buf[1] = fmtscan_asc(data[i] & 0xf); - - l = buffer_put(b, buf, 2); - if (l < 0) + while (r < dlen) { + char buf[64]; + size_t w = 0; + hexall_fmt(buf, sizeof(buf), data, dlen, options, &w, &r); + if (buffer_put(b, buf, w) < 0) return -1; - w += l; + written += w; } - return w; + return written; } diff --git a/src/liblimb/buffer.h/buffer_putmsg.c b/src/liblimb/buffer.h/buffer_putmsg.c index 4e1130b..972c4c6 100644 --- a/src/liblimb/buffer.h/buffer_putmsg.c +++ b/src/liblimb/buffer.h/buffer_putmsg.c @@ -34,7 +34,7 @@ buffer_putmsg(buffer *b, const char * const *as, unsigned int n) buf[u64_fmt(buf, u)] = 0; buffer_puts(b, buf_); } else if (as[i] == PUTMSG_HEX_NEXT && i + 2 < n) { - buffer_puthex(b, as[i + 1], (uintptr_t) as[i + 2]); + buffer_puthex(b, as[i + 1], (uintptr_t) as[i + 2], 0); i += 2; } else if (as[i] == PUTMSG_LEN_NEXT && i + 2 < n) { if (puts == buffer_puts) diff --git a/src/liblimb/hex.h/hex_fmt.c b/src/liblimb/hex.h/hex_fmt.c new file mode 100644 index 0000000..4584815 --- /dev/null +++ b/src/liblimb/hex.h/hex_fmt.c @@ -0,0 +1,13 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <limb/hex.h> + +ssize_t +hex_fmt(char *dst, size_t dlen, const char *sce, size_t slen, int options) +{ + size_t w = 0, r = 0; + if (!hexall_fmt(dst, dlen, sce, slen, options, &w, &r)) + return -1; + return w; +} diff --git a/src/liblimb/hex.h/hexall_fmt.c b/src/liblimb/hex.h/hexall_fmt.c new file mode 100644 index 0000000..b877361 --- /dev/null +++ b/src/liblimb/hex.h/hexall_fmt.c @@ -0,0 +1,56 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <errno.h> +#include <skalibs/fmtscan.h> +#include <limb/hex.h> + +int +hexall_fmt(char *dst, size_t dlen, const char *sce_, size_t slen, int options, size_t *w, size_t *r) +{ + if (*r > slen || *w > dlen) return (errno = EINVAL, 0); + + while (*r < slen && *w + 1 < dlen) { + const unsigned char *sce = (const unsigned char *) sce_; + int l = 2; + + /* actual hex converting */ + dst[*w ] = fmtscan_asc(sce[*r] >> 4); + dst[*w + 1] = fmtscan_asc(sce[*r] & 0xf); + + /* do we add a trailing LF? */ + if (*r + 1 == slen && (options & HEX_LF)) { + if (*w + l >= dlen) goto err; + dst[*w + l++] = '\n'; + } + + /* do we add LF/space every so often? */ + if (l == 2 && options & HEX_BLOCKS) { + unsigned n; + /* first see for a LF, the option's value being every nth byte */ + n = options & HEX_BLOCKS_LF; + if (n && !((*r + 1) % n)) { + if (*w + l >= dlen) goto err; + dst[*w + l++] = '\n'; + } else { + /* no LF, check for spaces then, shifting down to get the same + * option's value == every nth byte */ + n = (options & HEX_BLOCKS_SP) >> 3; + n = (options & HEX_SP) + (n && !((*r + 1) % n)); + for ( ; n; --n) { + if (*w + l >= dlen) goto err; + dst[*w + l++] = ' '; + } + } + } + + *r += 1; + *w += l; + } + if (*r < slen) goto err; + + return 1; +err: + errno = ENOBUFS; + return 0; +} diff --git a/src/liblimb/include/limb/buffer.h b/src/liblimb/include/limb/buffer.h index d854c46..d44da5c 100644 --- a/src/liblimb/include/limb/buffer.h +++ b/src/liblimb/include/limb/buffer.h @@ -5,6 +5,7 @@ #define LIMB_BUFFER_H #include <skalibs/buffer.h> +#include <limb/hex.h> /* HEX_* */ /* special values usable as strings for buffer_putmsg() */ #define PUTMSG_SYS ((void *) 1) /* add strerror(errno) */ @@ -34,7 +35,7 @@ extern void buffer_putmsg(buffer *b, const char * const *as, unsigned int n); extern size_t buffer_putescall(buffer *b, const char *s, size_t len, size_t *pos); extern ssize_t buffer_putesc(buffer *b, const char *s, size_t len); extern ssize_t buffer_putescs(buffer *b, const char *s); -extern ssize_t buffer_puthex(buffer *b, const void *data, size_t dlen); +extern ssize_t buffer_puthex(buffer *b, const void *data, size_t dlen, int options); typedef ssize_t (*base_fmt_fn) (char *dst, const char *data, size_t dlen, int pad); extern ssize_t buffer_putbase(buffer *b, const char *data, size_t dlen, base_fmt_fn basefmt, size_t bin, size_t bout, int pad); diff --git a/src/liblimb/include/limb/hex.h b/src/liblimb/include/limb/hex.h new file mode 100644 index 0000000..3e01796 --- /dev/null +++ b/src/liblimb/include/limb/hex.h @@ -0,0 +1,28 @@ +/* This file is part of limb https://lila.oss/limb + * Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LIMB_HEX_H +#define LIMB_HEX_H + +#include <sys/types.h> + +enum { + HEX_SP = 1 << 0, + HEX_LF = 1 << 1, + HEX_1BLOCK_LF = 1 << 3, + HEX_2BLOCK_LF = 1 << 4, + HEX_3BLOCK_LF = HEX_1BLOCK_LF | HEX_2BLOCK_LF, + HEX_4BLOCK_LF = 1 << 5, + HEX_BLOCKS_LF = HEX_3BLOCK_LF | HEX_4BLOCK_LF, + HEX_1BLOCK_SP = 1 << 6, + HEX_2BLOCK_SP = 1 << 7, + HEX_3BLOCK_SP = HEX_1BLOCK_SP | HEX_2BLOCK_SP, + HEX_4BLOCK_SP = 1 << 8, + HEX_BLOCKS_SP = HEX_3BLOCK_SP | HEX_4BLOCK_SP, + HEX_BLOCKS = HEX_BLOCKS_LF | HEX_BLOCKS_SP, +}; + +extern int hexall_fmt(char *dst, size_t dlen, const char *sce, size_t slen, int options, size_t *w, size_t *r); +extern ssize_t hex_fmt(char *dst, size_t dlen, const char *sce, size_t slen, int options); + +#endif /* LIMB_HEX_H */ diff --git a/src/mkrabintables/hexall_fmt.o b/src/mkrabintables/hexall_fmt.o new file mode 120000 index 0000000..3e7c609 --- /dev/null +++ b/src/mkrabintables/hexall_fmt.o @@ -0,0 +1 @@ +liblimb/hex.h/hexall_fmt.o \ No newline at end of file