be2net: Refactor be_xmit_enqueue() routine
[cascardo/linux.git] / lib / hexdump.c
index 270773b..7ea0969 100644 (file)
@@ -97,63 +97,79 @@ EXPORT_SYMBOL(bin2hex);
  *
  * example output buffer:
  * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
+ *
+ * Return:
+ * The amount of bytes placed in the buffer without terminating NUL. If the
+ * output was truncated, then the return value is the number of bytes
+ * (excluding the terminating NUL) which would have been written to the final
+ * string if enough space had been available.
  */
-void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
-                       int groupsize, char *linebuf, size_t linebuflen,
-                       bool ascii)
+int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
+                      char *linebuf, size_t linebuflen, bool ascii)
 {
        const u8 *ptr = buf;
+       int ngroups;
        u8 ch;
        int j, lx = 0;
        int ascii_column;
+       int ret;
 
        if (rowsize != 16 && rowsize != 32)
                rowsize = 16;
 
-       if (!len)
-               goto nil;
        if (len > rowsize)              /* limit to one line at a time */
                len = rowsize;
+       if (!is_power_of_2(groupsize) || groupsize > 8)
+               groupsize = 1;
        if ((len % groupsize) != 0)     /* no mixed size output */
                groupsize = 1;
 
-       switch (groupsize) {
-       case 8: {
-               const u64 *ptr8 = buf;
-               int ngroups = len / groupsize;
+       ngroups = len / groupsize;
+       ascii_column = rowsize * 2 + rowsize / groupsize + 1;
 
-               for (j = 0; j < ngroups; j++)
-                       lx += scnprintf(linebuf + lx, linebuflen - lx,
-                                       "%s%16.16llx", j ? " " : "",
-                                       (unsigned long long)*(ptr8 + j));
-               ascii_column = 17 * ngroups + 2;
-               break;
-       }
+       if (!linebuflen)
+               goto overflow1;
 
-       case 4: {
-               const u32 *ptr4 = buf;
-               int ngroups = len / groupsize;
+       if (!len)
+               goto nil;
 
-               for (j = 0; j < ngroups; j++)
-                       lx += scnprintf(linebuf + lx, linebuflen - lx,
-                                       "%s%8.8x", j ? " " : "", *(ptr4 + j));
-               ascii_column = 9 * ngroups + 2;
-               break;
-       }
+       if (groupsize == 8) {
+               const u64 *ptr8 = buf;
 
-       case 2: {
-               const u16 *ptr2 = buf;
-               int ngroups = len / groupsize;
+               for (j = 0; j < ngroups; j++) {
+                       ret = snprintf(linebuf + lx, linebuflen - lx,
+                                      "%s%16.16llx", j ? " " : "",
+                                      (unsigned long long)*(ptr8 + j));
+                       if (ret >= linebuflen - lx)
+                               goto overflow1;
+                       lx += ret;
+               }
+       } else if (groupsize == 4) {
+               const u32 *ptr4 = buf;
 
-               for (j = 0; j < ngroups; j++)
-                       lx += scnprintf(linebuf + lx, linebuflen - lx,
-                                       "%s%4.4x", j ? " " : "", *(ptr2 + j));
-               ascii_column = 5 * ngroups + 2;
-               break;
-       }
+               for (j = 0; j < ngroups; j++) {
+                       ret = snprintf(linebuf + lx, linebuflen - lx,
+                                      "%s%8.8x", j ? " " : "",
+                                      *(ptr4 + j));
+                       if (ret >= linebuflen - lx)
+                               goto overflow1;
+                       lx += ret;
+               }
+       } else if (groupsize == 2) {
+               const u16 *ptr2 = buf;
 
-       default:
-               for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
+               for (j = 0; j < ngroups; j++) {
+                       ret = snprintf(linebuf + lx, linebuflen - lx,
+                                      "%s%4.4x", j ? " " : "",
+                                      *(ptr2 + j));
+                       if (ret >= linebuflen - lx)
+                               goto overflow1;
+                       lx += ret;
+               }
+       } else {
+               for (j = 0; j < len; j++) {
+                       if (linebuflen < lx + 3)
+                               goto overflow2;
                        ch = ptr[j];
                        linebuf[lx++] = hex_asc_hi(ch);
                        linebuf[lx++] = hex_asc_lo(ch);
@@ -161,21 +177,28 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
                }
                if (j)
                        lx--;
-
-               ascii_column = 3 * rowsize + 2;
-               break;
        }
        if (!ascii)
                goto nil;
 
-       while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
+       while (lx < ascii_column) {
+               if (linebuflen < lx + 2)
+                       goto overflow2;
                linebuf[lx++] = ' ';
-       for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) {
+       }
+       for (j = 0; j < len; j++) {
+               if (linebuflen < lx + 2)
+                       goto overflow2;
                ch = ptr[j];
                linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
        }
 nil:
+       linebuf[lx] = '\0';
+       return lx;
+overflow2:
        linebuf[lx++] = '\0';
+overflow1:
+       return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
 }
 EXPORT_SYMBOL(hex_dump_to_buffer);