From: Francesco Chemolli Date: Mon, 26 May 2014 13:04:01 +0000 (+0200) Subject: Implement Parser::Tokenizer::int64 and unit tests X-Git-Tag: SQUID_3_5_0_1~217^2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a56b469c6ecaeeca28b58de702eacc990433fcf3;p=thirdparty%2Fsquid.git Implement Parser::Tokenizer::int64 and unit tests --- diff --git a/src/parser/Tokenizer.cc b/src/parser/Tokenizer.cc index 469d0b62c6..5fef298508 100644 --- a/src/parser/Tokenizer.cc +++ b/src/parser/Tokenizer.cc @@ -60,36 +60,23 @@ Parser::Tokenizer::skip(const char tokenChar) bool Parser::Tokenizer::int64 (int64_t & result, int base) { - //register uint64_t acc; - register uint64_t cutoff; - bool neg = false; - static SBuf zerox("0x"), zero("0"); - if (buf_.isEmpty()) return false; - if (buf_[0] == '-') { - neg = true; - buf_.consume(1); - } - if (buf_[0] == '+') - buf_.consume(1); - if (base == 0) { - if (buf_.startsWith(zerox)) - base = 16; - else if (buf_.startsWith(zero)) - base = 8; - else - base = 10; - } - if (base != 8 && base != 10 && base != 16) + // API mismatch with strtoll: we don't eat leading space. + if (xisspace(buf_[0])) return false; - // TODO: finish - cutoff = neg ? -(uint64_t) INT64_MIN : INT64_MAX; + char *eon; + errno = 0; // reset errno - // dummy to keep compiler happy. Remove before continuing - if (neg) result = cutoff; + int64_t rv = strtoll(buf_.rawContent(), &eon, base); + + if (errno != 0) + return false; + + buf_.consume(eon - buf_.rawContent()); // consume the parsed chunk + result = rv; + return true; - return false; } diff --git a/src/parser/Tokenizer.h b/src/parser/Tokenizer.h index 0296a7221d..84db031342 100644 --- a/src/parser/Tokenizer.h +++ b/src/parser/Tokenizer.h @@ -21,6 +21,9 @@ class Tokenizer { public: explicit Tokenizer(const SBuf &inBuf) : buf_(inBuf) {} + // return a copy the current contents of the parse buffer + const SBuf buf() const { return buf_; } + /// whether the end of the buffer has been reached bool atEnd() const { return buf_.isEmpty(); } @@ -66,7 +69,7 @@ public: /** parse an unsigned int64_t at the beginning of the buffer * - * strtoull(3)-alike function: tries to parse unsigned 64-bit integer + * strtoll(3)-alike function: tries to parse unsigned 64-bit integer * at the beginning of the parse buffer, in the base specified by the user * or guesstimated; consumes the parsed characters. * @@ -76,9 +79,7 @@ public: * the base * \return true if the parsing was successful */ - bool uint64 (uint64_t & result, int base); - - bool int64 (int64_t &result, int base); + bool int64 (int64_t &result, int base = 0); private: SBuf buf_; ///< yet unparsed input diff --git a/src/parser/testTokenizer.cc b/src/parser/testTokenizer.cc index a329853632..5308c91de7 100644 --- a/src/parser/testTokenizer.cc +++ b/src/parser/testTokenizer.cc @@ -102,3 +102,80 @@ testTokenizer::testCharacterSet() { } + +void +testTokenizer::testTokenizerInt64() +{ + int64_t rv; + + // successful parse in base 10 + { + Parser::Tokenizer t(SBuf("1234")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv, 10)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // successful parse, autodetect base + { + Parser::Tokenizer t(SBuf("1234")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // successful parse, autodetect base + { + Parser::Tokenizer t(SBuf("01234")); + const int64_t benchmark = 01234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // successful parse, autodetect base + { + Parser::Tokenizer t(SBuf("0x12f4")); + const int64_t benchmark = 0x12f4; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // API mismatch: don't eat leading space + { + Parser::Tokenizer t(SBuf(" 1234")); + CPPUNIT_ASSERT(!t.int64(rv)); + } + + // API mismatch: don't eat multiple leading spaces + { + Parser::Tokenizer t(SBuf(" 1234")); + CPPUNIT_ASSERT(!t.int64(rv)); + } + + // trailing spaces + { + Parser::Tokenizer t(SBuf("1234 foo")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf(" foo"), t.buf()); + } + + // trailing nonspaces + { + Parser::Tokenizer t(SBuf("1234foo")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf("foo"), t.buf()); + } + + // trailing nonspaces + { + Parser::Tokenizer t(SBuf("0x1234foo")); + const int64_t benchmark = 0x1234f; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf("oo"), t.buf()); + } +} diff --git a/src/parser/testTokenizer.h b/src/parser/testTokenizer.h index 22ff87d9da..9089aa75cc 100644 --- a/src/parser/testTokenizer.h +++ b/src/parser/testTokenizer.h @@ -10,6 +10,7 @@ class testTokenizer : public CPPUNIT_NS::TestFixture CPPUNIT_TEST ( testTokenizerPrefix ); CPPUNIT_TEST ( testTokenizerSkip ); CPPUNIT_TEST ( testTokenizerToken ); + CPPUNIT_TEST ( testTokenizerInt64 ); CPPUNIT_TEST_SUITE_END(); protected: @@ -17,6 +18,7 @@ protected: void testTokenizerSkip(); void testTokenizerToken(); void testCharacterSet(); + void testTokenizerInt64(); }; #endif /* SQUID_TESTTOKENIZER_H_ */