Welcome to little lamb

Code » limb » commit 5ac9c43

Add hex.h & related functions, use it for buffer_puthex..

author Olivier Brunel
2023-04-30 06:59:01 UTC
committer Olivier Brunel
2023-05-20 18:06:38 UTC
parent f577313573a612833bff5bb1d2ee50fbd80bf3bb

Add hex.h & related functions, use it for buffer_puthex..

..thus having options for easy "dumping"

Specifically HEX_SP will add spaces between each byte, while
HEX_xBLOCK_SP (where x is 1, 2, 3 or 4) will put a space after each
1/2/3 or 4 blocks of 8 bytes; and HEX_xBLOCK_LF is similar but adding
a LF instead of a space.
Lastly, HEX_LF allows to add a trailing newline.

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