[RFC PATCH] lib: add ascii hex helper functions
From: Harvey Harrison
Date: Sat May 03 2008 - 15:27:17 EST
Everyone rolls their own version around the tree, centralize
in lib/hexdump.c. Move the only existing users of hex_asc over
to the hi/lo helpers.
Add helpers for reading binary values from a stream of hex chars.
Most existing users want to know how many chars were read as well.
This implementation chooses to return the number of chars read
and takes a pointer to the value being read.
As an alternative, a char **buf could be passed and the value could
be returned and the pointer updated by reference.
Fixed size helpers for u8, u16, u32 and u64 have been added with
another helper that takes an argument specifying the max number of
chars to read (capped to the size that will fit in an unsigned long)
Signed-off-by: Harvey Harrison <harvey.harrison@xxxxxxxxx>
---
Andrew, I've thought a little more about this, It's possible we could
get away without the u8/u16 helpers, but it does make the api nicely
complete, and they are pretty small. Most users really want to read
a long or an int, but many can be move to the u32/u64 versions to
tighten up implicit assumptions being made about the length being
read.
I'll wait for coment before fixing the previous series of patches to
use these.
drivers/pnp/support.c | 8 ++--
include/linux/kernel.h | 6 ++-
lib/hexdump.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 146 insertions(+), 7 deletions(-)
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 3eba85e..95b076c 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -45,10 +45,10 @@ void pnp_eisa_id_to_string(u32 id, char *str)
str[0] = 'A' + ((id >> 26) & 0x3f) - 1;
str[1] = 'A' + ((id >> 21) & 0x1f) - 1;
str[2] = 'A' + ((id >> 16) & 0x1f) - 1;
- str[3] = hex_asc((id >> 12) & 0xf);
- str[4] = hex_asc((id >> 8) & 0xf);
- str[5] = hex_asc((id >> 4) & 0xf);
- str[6] = hex_asc((id >> 0) & 0xf);
+ str[3] = hex_asc_hi(id >> 8);
+ str[4] = hex_asc_lo(id >> 8);
+ str[5] = hex_asc_hi(id);
+ str[6] = hex_asc_lo(id);
str[7] = '\0';
}
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 4d46e29..20cae9a 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -276,7 +276,11 @@ extern void print_hex_dump(const char *level, const char *prefix_str,
const void *buf, size_t len, bool ascii);
extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
const void *buf, size_t len);
-#define hex_asc(x) "0123456789abcdef"[x]
+
+extern const char hex_asc[];
+extern int hex_to_int(char c);
+#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
+#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
#define pr_emerg(fmt, arg...) \
printk(KERN_EMERG fmt, ##arg)
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 3435465..c5cfee0 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -12,6 +12,141 @@
#include <linux/kernel.h>
#include <linux/module.h>
+const char hex_asc[] = "0123456789abcdef";
+
+/**
+ * hex_char_to_int - convert a single hex ASCII char to an integer value
+ * @ch: char to convert, not case sensitive [a-f][A-F][0-9]
+ *
+ * Returns -1 if the char is not a valid hexadecimal character
+ */
+int hex_char_to_int(char ch)
+{
+ /*
+ * Make ch lower-case, works only for digits and letters
+ */
+ ch |= 0x20;
+ if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ return -1;
+}
+EXPORT_SYMBOL(hex_char_to_int);
+
+/**
+ * hex_to_val - read a unsigned long from an ascii hex buffer
+ * @buf: buffer containing text
+ * @val: result read form the buffer
+ * @maxchars: maximum number of ascii chars to read
+ *
+ * The number of valid hex chars read is returned. In the event that the
+ * first character read is not a valid hex char @val will be zeroed.
+ * The number of chars read is capped at sizeof(unsigned long) * 2.
+ */
+int hex_to_val(const char *buf, unsigned long *val, unsigned int maxchars)
+{
+ int numread;
+ int tmp;
+ unsigned long res = 0;
+
+ if (maxchars > sizeof(unsigned long) * 2)
+ maxchars = sizeof(unsigned long) * 2;
+
+ for (numread = 0; numread < maxchars; numread++) {
+ tmp = hex_char_to_int(*buf++);
+ if (tmp < 0)
+ break;
+ else
+ res = (res << 4) | (tmp & 0x0f);
+ }
+ *val = res;
+
+ return numread;
+}
+EXPORT_SYMBOL(hex_to_val);
+
+/**
+ * hex_to_u8 - read a u8 from an ascii hex buffer
+ * @buf: buffer containing text
+ * @val: result read form the buffer
+ *
+ * The number of valid hex chars read is returned. In the event that the
+ * first character read is not a valid hex char @val will be zeroed.
+ */
+int hex_to_u8(const char *buf, u8 *val)
+{
+ unsigned long temp;
+ int numread = hex_to_val(buf, &temp, 2);
+
+ *val = (u8)temp;
+ return numread;
+}
+EXPORT_SYMBOL(hex_to_u8);
+
+/**
+ * hex_to_u16 - read a u16 from an ascii hex buffer
+ * @buf: buffer containing text
+ * @val: result read form the buffer
+ *
+ * The number of valid hex chars read is returned. In the event that the
+ * first character read is not a valid hex char @val will be zeroed.
+ */
+int hex_to_u16(const char *buf, u16 *val)
+{
+ unsigned long temp;
+ int numread = hex_to_val(buf, &temp, 4);
+
+ *val = (u16)temp;
+ return numread;
+}
+EXPORT_SYMBOL(hex_to_u16);
+
+/**
+ * hex_to_u32 - read a u32 from an ascii hex buffer
+ * @buf: buffer containing text
+ * @val: result read form the buffer
+ *
+ * The number of valid hex chars read is returned. In the event that the
+ * first character read is not a valid hex char @val will be zeroed.
+ */
+int hex_to_u32(const char *buf, u32 *val)
+{
+ unsigned long temp;
+ int numread = hex_to_val(buf, &temp, 8);
+
+ *val = (u32)temp;
+ return numread;
+}
+EXPORT_SYMBOL(hex_to_u32);
+
+/**
+ * hex_to_u64 - read a u32 from an ascii hex buffer
+ * @buf: buffer containing text
+ * @val: result read form the buffer
+ *
+ * The number of valid hex chars read is returned. In the event that the
+ * first character read is not a valid hex char @val will be zeroed.
+ */
+int hex_to_u64(const char *buf, u64 *val)
+{
+ int numread;
+ int tmp;
+ u64 res = 0;
+
+ for (numread = 0; numread < 16; numread++) {
+ tmp = hex_char_to_int(*buf++);
+ if (tmp < 0)
+ break;
+ else
+ res = (res << 4) | (tmp & 0x0f);
+ }
+ *val = res;
+
+ return numread;
+}
+EXPORT_SYMBOL(hex_to_u64);
+
/**
* hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
* @buf: data blob to dump
@@ -93,8 +228,8 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
j++) {
ch = ptr[j];
- linebuf[lx++] = hex_asc(ch >> 4);
- linebuf[lx++] = hex_asc(ch & 0x0f);
+ linebuf[lx++] = hex_asc_hi(ch);
+ linebuf[lx++] = hex_asc_lo(ch);
linebuf[lx++] = ' ';
}
ascii_column = 3 * rowsize + 2;
--
1.5.5.1.350.gbbbf
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/