Make tor_sscanf handle %x

This commit is contained in:
Nick Mathewson 2010-10-11 10:50:47 -04:00
parent 45ce1f678f
commit 8f76f31761
2 changed files with 25 additions and 9 deletions

View File

@ -2498,18 +2498,21 @@ digit_to_num(char d)
* success, store the result in <b>out</b>, advance bufp to the next
* character, and return 0. On failure, return -1. */
static int
scan_unsigned(const char **bufp, unsigned *out, int width)
scan_unsigned(const char **bufp, unsigned *out, int width, int base)
{
unsigned result = 0;
int scanned_so_far = 0;
const int hex = base==16;
tor_assert(base == 10 || base == 16);
if (!bufp || !*bufp || !out)
return -1;
if (width<0)
width=MAX_SCANF_WIDTH;
while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
int digit = digit_to_num(*(*bufp)++);
unsigned new_result = result * 10 + digit;
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
&& scanned_so_far < width) {
int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
unsigned new_result = result * base + digit;
if (new_result > UINT32_MAX || new_result < result)
return -1; /* over/underflow. */
result = new_result;
@ -2571,11 +2574,12 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
if (!width) /* No zero-width things. */
return -1;
}
if (*pattern == 'u') {
if (*pattern == 'u' || *pattern == 'x') {
unsigned *u = va_arg(ap, unsigned *);
const int base = (*pattern == 'u') ? 10 : 16;
if (!*buf)
return n_matched;
if (scan_unsigned(&buf, u, width)<0)
if (scan_unsigned(&buf, u, width, base)<0)
return n_matched;
++pattern;
++n_matched;
@ -2612,9 +2616,9 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b>
* and store the results in the corresponding argument fields. Differs from
* sscanf in that it: Only handles %u and %Ns. Does not handle arbitrarily
* long widths. %u does not consume any space. Is locale-independent.
* Returns -1 on malformed patterns.
* sscanf in that it: Only handles %u and %x and %Ns. Does not handle
* arbitrarily long widths. %u and %x do not consume any space. Is
* locale-independent. Returns -1 on malformed patterns.
*
* (As with other locale-independent functions, we need this to parse data that
* is in ASCII without worrying that the C library's locale-handling will make

View File

@ -833,6 +833,18 @@ test_util_sscanf(void)
test_eq(u2, 3u);
test_eq(u3, 99u);
/* %x should work. */
r = tor_sscanf("1234 02aBcdEf", "%x %x", &u1, &u2);
test_eq(r, 2);
test_eq(u1, 0x1234);
test_eq(u2, 0x2ABCDEF);
/* Width works on %x */
r = tor_sscanf("f00dcafe444", "%4x%4x%u", &u1, &u2, &u3);
test_eq(r, 3);
test_eq(u1, 0xf00d);
test_eq(u2, 0xcafe);
test_eq(u3, 444);
r = tor_sscanf("99% fresh", "%3u%% fresh", &u1); /* percents are scannable.*/
test_eq(r, 1);
test_eq(u1, 99);