aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hexdump.c
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2015-02-12 18:02:29 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-12 21:54:15 -0500
commit114fc1afb2de7dec40da137dc2a55cd38fc220f2 (patch)
tree414c7731a5a4743cbdba6583a1b79f3723ec190d /lib/hexdump.c
parent5d909c8d54b114eddb7c50506f03bf7309a9192e (diff)
hexdump: make it return number of bytes placed in buffer
This patch makes hexdump return the number of bytes placed in the buffer excluding trailing NUL. In the case of overflow it returns the desired amount of bytes to produce the entire dump. Thus, it mimics snprintf(). This will be useful for users that would like to repeat with a bigger buffer. [akpm@linux-foundation.org: fix printk warning] Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/hexdump.c')
-rw-r--r--lib/hexdump.c73
1 files changed, 55 insertions, 18 deletions
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 4af53f73c7cc..7ea09699855d 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -97,22 +97,26 @@ EXPORT_SYMBOL(bin2hex);
97 * 97 *
98 * example output buffer: 98 * example output buffer:
99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO 99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
100 *
101 * Return:
102 * The amount of bytes placed in the buffer without terminating NUL. If the
103 * output was truncated, then the return value is the number of bytes
104 * (excluding the terminating NUL) which would have been written to the final
105 * string if enough space had been available.
100 */ 106 */
101void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, 107int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
102 int groupsize, char *linebuf, size_t linebuflen, 108 char *linebuf, size_t linebuflen, bool ascii)
103 bool ascii)
104{ 109{
105 const u8 *ptr = buf; 110 const u8 *ptr = buf;
106 int ngroups; 111 int ngroups;
107 u8 ch; 112 u8 ch;
108 int j, lx = 0; 113 int j, lx = 0;
109 int ascii_column; 114 int ascii_column;
115 int ret;
110 116
111 if (rowsize != 16 && rowsize != 32) 117 if (rowsize != 16 && rowsize != 32)
112 rowsize = 16; 118 rowsize = 16;
113 119
114 if (!len)
115 goto nil;
116 if (len > rowsize) /* limit to one line at a time */ 120 if (len > rowsize) /* limit to one line at a time */
117 len = rowsize; 121 len = rowsize;
118 if (!is_power_of_2(groupsize) || groupsize > 8) 122 if (!is_power_of_2(groupsize) || groupsize > 8)
@@ -122,27 +126,50 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
122 126
123 ngroups = len / groupsize; 127 ngroups = len / groupsize;
124 ascii_column = rowsize * 2 + rowsize / groupsize + 1; 128 ascii_column = rowsize * 2 + rowsize / groupsize + 1;
129
130 if (!linebuflen)
131 goto overflow1;
132
133 if (!len)
134 goto nil;
135
125 if (groupsize == 8) { 136 if (groupsize == 8) {
126 const u64 *ptr8 = buf; 137 const u64 *ptr8 = buf;
127 138
128 for (j = 0; j < ngroups; j++) 139 for (j = 0; j < ngroups; j++) {
129 lx += scnprintf(linebuf + lx, linebuflen - lx, 140 ret = snprintf(linebuf + lx, linebuflen - lx,
130 "%s%16.16llx", j ? " " : "", 141 "%s%16.16llx", j ? " " : "",
131 (unsigned long long)*(ptr8 + j)); 142 (unsigned long long)*(ptr8 + j));
143 if (ret >= linebuflen - lx)
144 goto overflow1;
145 lx += ret;
146 }
132 } else if (groupsize == 4) { 147 } else if (groupsize == 4) {
133 const u32 *ptr4 = buf; 148 const u32 *ptr4 = buf;
134 149
135 for (j = 0; j < ngroups; j++) 150 for (j = 0; j < ngroups; j++) {
136 lx += scnprintf(linebuf + lx, linebuflen - lx, 151 ret = snprintf(linebuf + lx, linebuflen - lx,
137 "%s%8.8x", j ? " " : "", *(ptr4 + j)); 152 "%s%8.8x", j ? " " : "",
153 *(ptr4 + j));
154 if (ret >= linebuflen - lx)
155 goto overflow1;
156 lx += ret;
157 }
138 } else if (groupsize == 2) { 158 } else if (groupsize == 2) {
139 const u16 *ptr2 = buf; 159 const u16 *ptr2 = buf;
140 160
141 for (j = 0; j < ngroups; j++) 161 for (j = 0; j < ngroups; j++) {
142 lx += scnprintf(linebuf + lx, linebuflen - lx, 162 ret = snprintf(linebuf + lx, linebuflen - lx,
143 "%s%4.4x", j ? " " : "", *(ptr2 + j)); 163 "%s%4.4x", j ? " " : "",
164 *(ptr2 + j));
165 if (ret >= linebuflen - lx)
166 goto overflow1;
167 lx += ret;
168 }
144 } else { 169 } else {
145 for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { 170 for (j = 0; j < len; j++) {
171 if (linebuflen < lx + 3)
172 goto overflow2;
146 ch = ptr[j]; 173 ch = ptr[j];
147 linebuf[lx++] = hex_asc_hi(ch); 174 linebuf[lx++] = hex_asc_hi(ch);
148 linebuf[lx++] = hex_asc_lo(ch); 175 linebuf[lx++] = hex_asc_lo(ch);
@@ -154,14 +181,24 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
154 if (!ascii) 181 if (!ascii)
155 goto nil; 182 goto nil;
156 183
157 while (lx < (linebuflen - 1) && lx < ascii_column) 184 while (lx < ascii_column) {
185 if (linebuflen < lx + 2)
186 goto overflow2;
158 linebuf[lx++] = ' '; 187 linebuf[lx++] = ' ';
159 for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) { 188 }
189 for (j = 0; j < len; j++) {
190 if (linebuflen < lx + 2)
191 goto overflow2;
160 ch = ptr[j]; 192 ch = ptr[j];
161 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; 193 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
162 } 194 }
163nil: 195nil:
196 linebuf[lx] = '\0';
197 return lx;
198overflow2:
164 linebuf[lx++] = '\0'; 199 linebuf[lx++] = '\0';
200overflow1:
201 return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
165} 202}
166EXPORT_SYMBOL(hex_dump_to_buffer); 203EXPORT_SYMBOL(hex_dump_to_buffer);
167 204