Here's an alternative based on character arithmetic:
int hexdigits(char *str, int ndigits)
{
int i;
int n = 0;
for (i=0; i<ndigits; ++i) {
int d = *str++ - '0';
if (d > 9 || d < 0)
d += '0' - 'A' + 10;
if (d > 15 || d < 0)
d += 'A' - 'a';
if (d > 15 || d < 0)
return -1;
n <<= 4;
n |= d;
}
return n;
}
It should handle digits in both cases, and work for both ASCII and EBCDIC. Using it for more than 7 digits invites integer overflow, and may make the use of -1 as an error value indistinguishable from a valid conversion.
Just call it with the offset added to the base string: e.g. w = hexdigits(buf+3, 4);
for the suggested offset of 3 chars into a string stored in buf
.
Edit: Here's a version with fewer conditions that is guaranteed to work for ASCII. I'm reasonably certain it will work for EBCDIC as well, but don't have any text of that flavor laying around to prove it.
Also, I fixed a stupid oversight and made the accumulator an int
instead of unsigned short
. It wouldn't affect the 4-digit case, but it made it overflow at only 16-bit numbers instead of the full capacity of an int
.
int hexdigits2(char *str, int ndigits)
{
int i;
int n = 0;
for (i=0; i<ndigits; ++i) {
unsigned char d = *str++ - '0';
if (d > 9)
d += '0' - 'A' + 10;
if (d > 15)
d += 'A' - 'a';
if (d > 15)
return -1;
n <<= 4;
n |= d;
}
return n;
}
Usage is the same as the earlier version, but the generated code could be a bit smaller.