Re: [RFC PATCH] lib: add ascii hex helper functions
From: Cyrill Gorcunov
Date: Sun May 04 2008 - 12:36:24 EST
[Harvey Harrison - Sat, May 03, 2008 at 12:27:27PM -0700]
| 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;
hi Harvey, maybe we should use tolower() from ctype.h here?
| + 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/
|
- Cyrill -
--
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/