Messages in this thread | | | Date | Sun, 4 May 2008 20:35:17 +0400 | From | Cyrill Gorcunov <> | Subject | Re: [RFC PATCH] lib: add ascii hex helper functions |
| |
[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@gmail.com> | --- | 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@vger.kernel.org | More majordomo info at http://vger.kernel.org/majordomo-info.html | Please read the FAQ at http://www.tux.org/lkml/ | - Cyrill -
| |