]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Fixed Parser::Tokenizer::int64, added more test cases
authorFrancesco Chemolli <kinkie@squid-cache.org>
Fri, 30 May 2014 09:42:45 +0000 (11:42 +0200)
committerFrancesco Chemolli <kinkie@squid-cache.org>
Fri, 30 May 2014 09:42:45 +0000 (11:42 +0200)
src/parser/Tokenizer.cc
src/parser/testTokenizer.cc

index 3c009c14b907f4657feed954d7e25baeabef47a3..453f36a24841e4af49a0c979ef7e8125b6408e4e 100644 (file)
@@ -56,25 +56,77 @@ Parser::Tokenizer::skip(const char tokenChar)
     return false;
 }
 
+/* reworked from compat/strtoll.c */
 bool
 Parser::Tokenizer::int64(int64_t & result, int base)
 {
     if (buf_.isEmpty())
         return false;
 
-    // API mismatch with strtoll: we don't eat leading space.
-    if (xisspace(buf_[0]))
-        return false;
+    //fixme: account for buf_.size()
+    bool neg = false;
+    const char *s = buf_.rawContent();
+    const char *end = buf_.rawContent() + buf_.length();
+
+    if (*s == '-') {
+        neg = true;
+        ++s;
+    } else if (*s == '+') {
+        ++s;
+    }
+    if (s >= end) return false;
+    if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) &&
+                    tolower(*(s+1)) == 'x') {
+        s += 2;
+        base = 16;
+    }
+    if (base == 0) {
+        if ( *s == '0') {
+            base = 8;
+            ++s;
+        } else {
+            base = 10;
+        }
+    }
+    if (s >= end) return false;
+
+    uint64_t cutoff;
 
-    char *eon;
-    errno = 0; // reset errno
+    cutoff = neg ? -static_cast<uint64_t>(INT64_MIN) : INT64_MAX;
+    int cutlim = cutoff % static_cast<int64_t>(base);
+    cutoff /= static_cast<uint64_t>(base);
 
-    int64_t rv = strtoll(buf_.rawContent(), &eon, base);
+    int any = 0, c;
+    int64_t acc = 0;
+    for (c = *s++; s <= end; c = *s++) {
+        if (xisdigit(c)) {
+            c -= '0';
+        } else if (xisalpha(c)) {
+            c -= xisupper(c) ? 'A' - 10 : 'a' - 10;
+        } else {
+            break;
+        }
+        if (c >= base)
+            break;
+        if (any < 0 || static_cast<uint64_t>(acc) > cutoff || (static_cast<uint64_t>(acc) == cutoff && c > cutlim))
+            any = -1;
+        else {
+            any = 1;
+            acc *= base;
+            acc += c;
+        }
+    }
 
-    if (errno != 0)
+    if (any == 0) // nothing was parsed
+        return false;
+    if (any < 0) {
+        acc = neg ? INT64_MIN : INT64_MAX;
+        errno = ERANGE;
         return false;
+    } else if (neg)
+        acc = -acc;
 
-    buf_.consume(eon - buf_.rawContent()); // consume the parsed chunk
-    result = rv;
+    result = acc;
+    buf_.consume(s - buf_.rawContent() -1);
     return true;
 }
index 1ea5200d75b9f76987cdaeabceeaa4cd0b313d3f..4e4dfa5ae63d541a59e60443f0ea5af7c508b40c 100644 (file)
@@ -203,4 +203,16 @@ testTokenizer::testTokenizerInt64()
         CPPUNIT_ASSERT(t.int64(rv));
         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
     }
+
+    // base-16, prefix
+    {
+        int64_t rv;
+        SBuf base("deadbeefrow");
+        const int64_t benchmark=0xdeadbeef;
+        Parser::Tokenizer t(base);
+        CPPUNIT_ASSERT(t.int64(rv,16));
+        CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+        CPPUNIT_ASSERT_EQUAL(SBuf("row"),t.buf());
+
+    }
 }