[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [tor/master] Make tor_sscanf handle %x



Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Mon, 11 Oct 2010 10:50:47 -0400
Subject: Make tor_sscanf handle %x
Commit: 8f76f31761f051d5b6a3280462db6adf95b19233

---
 src/common/util.c    |   22 +++++++++++++---------
 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 b5a3ade..fd6956c 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 68a0ca2..5701f12 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);
-- 
1.7.1