At present print_buffer() outputs a hex dump but it is not possible to
place this dump in a string. Refactor it into a top-level function which
does the printing and a utility function that dumps a line into a string.
This makes the code more generally useful.

Signed-off-by: Simon Glass <s...@chromium.org>
---

 include/display_options.h |  25 +++++++++
 lib/display_options.c     | 115 +++++++++++++++++++++++---------------
 test/print_ut.c           |  30 +++++++++-
 3 files changed, 123 insertions(+), 47 deletions(-)

diff --git a/include/display_options.h b/include/display_options.h
index 049688e39e8..43810cbe22f 100644
--- a/include/display_options.h
+++ b/include/display_options.h
@@ -47,6 +47,31 @@ void print_freq(uint64_t freq, const char *suffix);
 int print_buffer(ulong addr, const void *data, uint width, uint count,
                 uint linelen);
 
+/*
+ * Maximum length of an output line is when width == 1
+ *     9 for address,
+ *     a space, two hex digits and an ASCII character for each byte
+ *     2 spaces between the hex and ASCII
+ *     \0 terminator
+ */
+#define HEXDUMP_MAX_BUF_LENGTH(bytes)  (9 + (bytes) * 4 + 3)
+
+/**
+ * hexdump_line() - Print out a single line of a hex dump
+ *
+ * @addr:      Starting address to display at start of line
+ * @data:      pointer to data buffer
+ * @width:     data value width.  May be 1, 2, or 4.
+ * @count:     number of values to display
+ * @linelen:   Number of values to print per line; specify 0 for default length
+ * @out:       Output buffer to hold the dump
+ * @size:      Size of output buffer in bytes
+ * @return number of bytes processed, if OK, -ENOSPC if buffer too small
+ *
+ */
+int hexdump_line(ulong addr, const void *data, uint width, uint count,
+                uint linelen, char *out, int size);
+
 /**
  * display_options() - display the version string / build tag
  *
diff --git a/lib/display_options.c b/lib/display_options.c
index 7752baba2bd..c08a87e3162 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -131,10 +131,11 @@ void print_size(uint64_t size, const char *s)
        printf (" %ciB%s", c, s);
 }
 
-#define MAX_LINE_LENGTH_BYTES (64)
-#define DEFAULT_LINE_LENGTH_BYTES (16)
-int print_buffer(ulong addr, const void *data, uint width, uint count,
-                uint linelen)
+#define MAX_LINE_LENGTH_BYTES          64
+#define DEFAULT_LINE_LENGTH_BYTES      16
+
+int hexdump_line(ulong addr, const void *data, uint width, uint count,
+                uint linelen, char *out, int size)
 {
        /* linebuf as a union causes proper alignment */
        union linebuf {
@@ -143,62 +144,86 @@ int print_buffer(ulong addr, const void *data, uint 
width, uint count,
                uint16_t us[MAX_LINE_LENGTH_BYTES/sizeof(uint16_t) + 1];
                uint8_t  uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1];
        } lb;
+       uint thislinelen;
        int i;
        ulong x;
 
+       if (linelen * width > MAX_LINE_LENGTH_BYTES)
+               linelen = MAX_LINE_LENGTH_BYTES / width;
+       if (linelen < 1)
+               linelen = DEFAULT_LINE_LENGTH_BYTES / width;
+
+       /*
+        * Check the size here so that we don't need to use snprintf(). This
+        * helps to reduce code size
+        */
+       if (size < HEXDUMP_MAX_BUF_LENGTH(linelen * width))
+               return -ENOSPC;
+
+       thislinelen = linelen;
+       out += sprintf(out, "%08lx:", addr);
+
+       /* check for overflow condition */
+       if (count < thislinelen)
+               thislinelen = count;
+
+       /* Copy from memory into linebuf and print hex values */
+       for (i = 0; i < thislinelen; i++) {
+               if (width == 4)
+                       x = lb.ui[i] = *(volatile uint32_t *)data;
+               else if (MEM_SUPPORT_64BIT_DATA && width == 8)
+                       x = lb.uq[i] = *(volatile ulong *)data;
+               else if (width == 2)
+                       x = lb.us[i] = *(volatile uint16_t *)data;
+               else
+                       x = lb.uc[i] = *(volatile uint8_t *)data;
+               if (CONFIG_IS_ENABLED(USE_TINY_PRINTF))
+                       out += sprintf(out, " %x", (uint)x);
+               else
+                       out += sprintf(out, " %0*lx", width * 2, x);
+               data += width;
+       }
+
+       /* fill line with whitespace for nice ASCII print */
+       for (i = 0; i < (linelen - thislinelen) * (width * 2 + 1); i++)
+               *out++ = ' ';
+
+       /* Print data in ASCII characters */
+       for (i = 0; i < thislinelen * width; i++) {
+               if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80)
+                       lb.uc[i] = '.';
+       }
+       lb.uc[i] = '\0';
+       out += sprintf(out, "  %s", lb.uc);
+
+       return thislinelen;
+}
+
+int print_buffer(ulong addr, const void *data, uint width, uint count,
+                uint linelen)
+{
        if (linelen*width > MAX_LINE_LENGTH_BYTES)
                linelen = MAX_LINE_LENGTH_BYTES / width;
        if (linelen < 1)
                linelen = DEFAULT_LINE_LENGTH_BYTES / width;
 
        while (count) {
-               uint thislinelen = linelen;
-               printf("%08lx:", addr);
-
-               /* check for overflow condition */
-               if (count < thislinelen)
-                       thislinelen = count;
-
-               /* Copy from memory into linebuf and print hex values */
-               for (i = 0; i < thislinelen; i++) {
-                       if (width == 4)
-                               x = lb.ui[i] = *(volatile uint32_t *)data;
-                       else if (MEM_SUPPORT_64BIT_DATA && width == 8)
-                               x = lb.uq[i] = *(volatile ulong *)data;
-                       else if (width == 2)
-                               x = lb.us[i] = *(volatile uint16_t *)data;
-                       else
-                               x = lb.uc[i] = *(volatile uint8_t *)data;
-                       if (CONFIG_IS_ENABLED(USE_TINY_PRINTF))
-                               printf(" %x", (uint)x);
-                       else
-                               printf(" %0*lx", width * 2, x);
-                       data += width;
-               }
+               uint thislinelen;
+               char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)];
 
-               while (thislinelen < linelen) {
-                       /* fill line with whitespace for nice ASCII print */
-                       for (i=0; i<width*2+1; i++)
-                               puts(" ");
-                       linelen--;
-               }
-
-               /* Print data in ASCII characters */
-               for (i = 0; i < thislinelen * width; i++) {
-                       if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80)
-                               lb.uc[i] = '.';
-               }
-               lb.uc[i] = '\0';
-               printf("  %s\n", lb.uc);
+               thislinelen = hexdump_line(addr, data, width, count, linelen,
+                                          buf, sizeof(buf));
+               assert(thislinelen >= 0);
+               puts(buf);
+               putc('\n');
 
                /* update references */
+               data += thislinelen * width;
                addr += thislinelen * width;
                count -= thislinelen;
 
-#ifndef CONFIG_SPL_BUILD
-               if (ctrlc())
-                       return -1;
-#endif
+               if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
+                       return -EINTR;
        }
 
        return 0;
diff --git a/test/print_ut.c b/test/print_ut.c
index 3a3cdf323e1..079d3f7cb08 100644
--- a/test/print_ut.c
+++ b/test/print_ut.c
@@ -229,7 +229,33 @@ static int print_display_buffer(struct unit_test_state 
*uts)
 }
 PRINT_TEST(print_display_buffer, UT_TESTF_CONSOLE_REC);
 
-static int print_hex_dump(struct unit_test_state *uts)
+static int print_hexdump_line(struct unit_test_state *uts)
+{
+       char *linebuf;
+       u8 *buf;
+       int i;
+
+       buf = map_sysmem(0, BUF_SIZE);
+       memset(buf, '\0', BUF_SIZE);
+       for (i = 0; i < 0x11; i++)
+               buf[i] = i * 0x11;
+
+       /* Check buffer size calculations */
+       linebuf = map_sysmem(0x400, BUF_SIZE);
+       memset(linebuf, '\xff', BUF_SIZE);
+       ut_asserteq(-ENOSPC, hexdump_line(0, buf, 1, 0x10, 0, linebuf, 75));
+       ut_asserteq(-1, linebuf[0]);
+       ut_asserteq(0x10, hexdump_line(0, buf, 1, 0x10, 0, linebuf, 76));
+       ut_asserteq(0, linebuf[75]);
+       ut_asserteq(-1, linebuf[76]);
+
+       unmap_sysmem(buf);
+
+       return 0;
+}
+PRINT_TEST(print_hexdump_line, UT_TESTF_CONSOLE_REC);
+
+static int print_hexdump(struct unit_test_state *uts)
 {
        u8 *buf;
        int i;
@@ -302,7 +328,7 @@ static int print_hex_dump(struct unit_test_state *uts)
 
        return 0;
 }
-PRINT_TEST(print_hex_dump, UT_TESTF_CONSOLE_REC);
+PRINT_TEST(print_hexdump, UT_TESTF_CONSOLE_REC);
 
 int do_ut_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-- 
2.31.0.rc2.261.g7f71774620-goog

Reply via email to