diff options
author | Nick Mathewson <nickm@torproject.org> | 2010-10-11 10:50:47 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2010-10-11 10:50:47 -0400 |
commit | 8f76f31761f051d5b6a3280462db6adf95b19233 (patch) | |
tree | b9a4daadf14df6db79a5ecb978a3bedd20e3730a | |
parent | 45ce1f678fa3de4634d29415d850eb2723440bca (diff) | |
download | tor-8f76f31761f051d5b6a3280462db6adf95b19233.tar.gz tor-8f76f31761f051d5b6a3280462db6adf95b19233.zip |
Make tor_sscanf handle %x
-rw-r--r-- | src/common/util.c | 22 | ||||
-rw-r--r-- | src/test/test_util.c | 12 |
2 files changed, 25 insertions, 9 deletions
diff --git a/src/common/util.c b/src/common/util.c index b5a3ade2bd..fd6956c3a4 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -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 diff --git a/src/test/test_util.c b/src/test/test_util.c index 68a0ca2984..5701f12857 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -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); |