From 68b84574ae5f3a46b0157799783cf51b1a8f4676 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Mar 2008 15:03:47 +0000 Subject: [PATCH] 2008-03-09 Tatsuhiro Tsujikawa * src/Util.{h, cc} (parseUInt): New function. (alphaToNum): Now returns unsigned int and 0 when overflow detected. The actual range is uint32_t. * test/UtilTest.cc * src/ParameterizedStringParser.cc: Use Util::parseUInt() for loop variables. * test/ParameterizedStringParserTest.cc * src/PStringNumLoop.h: Make _startValue and _endValue unsigned int. --- ChangeLog | 14 +++++++++ src/PStringNumLoop.h | 13 ++++---- src/ParameterizedStringParser.cc | 13 ++++---- src/Util.cc | 34 +++++++++++++++++++-- src/Util.h | 19 ++++++++---- test/ParameterizedStringParserTest.cc | 18 +++++------ test/UtilTest.cc | 43 ++++++++++++++++++++------- 7 files changed, 115 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index a481ca04..b685aaa4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-03-09 Tatsuhiro Tsujikawa + + * src/Util.{h, cc} + (parseUInt): New function. + (alphaToNum): Now returns unsigned int and 0 when overflow detected. + The actual range is uint32_t. + * test/UtilTest.cc + + * src/ParameterizedStringParser.cc: + Use Util::parseUInt() for loop variables. + * test/ParameterizedStringParserTest.cc + + * src/PStringNumLoop.h: Make _startValue and _endValue unsigned int. + 2008-03-09 Tatsuhiro Tsujikawa Rewritten the functions for binding port. diff --git a/src/PStringNumLoop.h b/src/PStringNumLoop.h index 3aa29254..b12ad3ee 100644 --- a/src/PStringNumLoop.h +++ b/src/PStringNumLoop.h @@ -45,9 +45,9 @@ class PStringNumLoop : public PStringDatum { private: - int _startValue; + unsigned int _startValue; - int _endValue; + unsigned int _endValue; unsigned int _step; @@ -56,7 +56,8 @@ private: PStringDatumHandle _next; public: - PStringNumLoop(int startValue, int endValue, unsigned int step, + PStringNumLoop(unsigned int startValue, unsigned int endValue, + unsigned int step, const NumberDecoratorHandle& nd, const PStringDatumHandle& next = 0): _startValue(startValue), @@ -69,7 +70,7 @@ public: virtual void accept(PStringVisitor* visitor) { - for(int i = _startValue; i <= _endValue; i += _step) { + for(unsigned int i = _startValue; i <= _endValue; i += _step) { PStringSegment(_numberDecorator->decorate(i), _next).accept(visitor); } } @@ -79,12 +80,12 @@ public: return _next; } - int getStartValue() const + unsigned int getStartValue() const { return _startValue; } - int getEndValue() const + unsigned int getEndValue() const { return _endValue; } diff --git a/src/ParameterizedStringParser.cc b/src/ParameterizedStringParser.cc index 6d46ef66..d203383e 100644 --- a/src/ParameterizedStringParser.cc +++ b/src/ParameterizedStringParser.cc @@ -113,10 +113,11 @@ PStringDatumHandle ParameterizedStringParser::createLoop(const std::string& src, std::string::size_type colonIndex = loopStr.find(":"); if(colonIndex != std::string::npos) { std::string stepStr = loopStr.substr(colonIndex+1); + int sstep; if(Util::isNumber(stepStr)) { - step = Util::parseInt(stepStr); + step = Util::parseUInt(stepStr); } else { - throw new FatalException("A step count must be a number."); + throw new FatalException("A step count must be a positive number."); } loopStr.erase(colonIndex); } @@ -125,12 +126,12 @@ PStringDatumHandle ParameterizedStringParser::createLoop(const std::string& src, throw new FatalException("Loop range missing."); } NumberDecoratorHandle nd = 0; - int start; - int end; + unsigned int start; + unsigned int end; if(Util::isNumber(range.first) && Util::isNumber(range.second)) { nd = new FixedWidthNumberDecorator(range.first.size()); - start = Util::parseInt(range.first); - end = Util::parseInt(range.second); + start = Util::parseUInt(range.first); + end = Util::parseUInt(range.second); } else if(Util::isLowercase(range.first) && Util::isLowercase(range.second)) { nd = new AlphaNumberDecorator(range.first.size()); start = Util::alphaToNum(range.first); diff --git a/src/Util.cc b/src/Util.cc index e00844a9..c2d18416 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -417,6 +417,31 @@ int32_t Util::parseInt(const std::string& s, int32_t base) return v; } +uint32_t Util::parseUInt(const std::string& s, int base) +{ + std::string trimed = Util::trim(s); + if(trimed.empty()) { + throw new DlAbortEx(MSG_STRING_INTEGER_CONVERSION_FAILURE, + "empty string"); + } + // We don't allow negative number. + if(trimed[0] == '-') { + throw new DlAbortEx(MSG_STRING_INTEGER_CONVERSION_FAILURE, + trimed.c_str()); + } + char* stop; + errno = 0; + unsigned long int v = strtoul(trimed.c_str(), &stop, base); + if(*stop != '\0') { + throw new DlAbortEx(MSG_STRING_INTEGER_CONVERSION_FAILURE, + trimed.c_str()); + } else if((v == ULONG_MAX) && errno == ERANGE || v > UINT32_MAX) { + throw new DlAbortEx(MSG_STRING_INTEGER_CONVERSION_FAILURE, + trimed.c_str()); + } + return v; +} + int64_t Util::parseLLInt(const std::string& s, int32_t base) { std::string trimed = Util::trim(s); @@ -730,7 +755,7 @@ bool Util::isUppercase(const std::string& what) return true; } -int Util::alphaToNum(const std::string& alphabets) +unsigned int Util::alphaToNum(const std::string& alphabets) { if(alphabets.empty()) { return 0; @@ -741,10 +766,13 @@ int Util::alphaToNum(const std::string& alphabets) } else { base = 'A'; } - int num = 0; + uint64_t num = 0; for(size_t i = 0; i < alphabets.size(); ++i) { - int v = alphabets[i]-base; + unsigned int v = alphabets[i]-base; num = num*26+v; + if(num > UINT32_MAX) { + return 0; + } } return num; } diff --git a/src/Util.h b/src/Util.h index 3cec6dcf..971cde61 100644 --- a/src/Util.h +++ b/src/Util.h @@ -167,6 +167,8 @@ public: static int32_t parseInt(const std::string& s, int32_t base = 10); + static unsigned int parseUInt(const std::string& s, int base = 10); + static int64_t parseLLInt(const std::string& s, int32_t base = 10); static IntSequence parseIntRange(const std::string& src); @@ -205,14 +207,21 @@ public: static void sleep(long seconds); static void usleep(long microseconds); - + static bool isNumber(const std::string& what); - + static bool isLowercase(const std::string& what); - + static bool isUppercase(const std::string& what); - - static int alphaToNum(const std::string& alphabets); + + /** + * Converts alphabets to unsigned int, assuming alphabets as a base 26 + * integer and 'a' or 'A' is 0. + * This function assumes alphabets includes only a-z. + * Upper case are allowed but all letters must be upper case. + * If overflow occurs, returns 0. + */ + static unsigned int alphaToNum(const std::string& alphabets); static void mkdirs(const std::string& dirpath); diff --git a/test/ParameterizedStringParserTest.cc b/test/ParameterizedStringParserTest.cc index 99f20131..f89e350f 100644 --- a/test/ParameterizedStringParserTest.cc +++ b/test/ParameterizedStringParserTest.cc @@ -126,9 +126,9 @@ void ParameterizedStringParserTest::testParse_loop() SharedHandle loop1 = ls; CPPUNIT_ASSERT(!loop1.isNull()); - CPPUNIT_ASSERT_EQUAL(1, loop1->getStartValue()); - CPPUNIT_ASSERT_EQUAL(10, loop1->getEndValue()); - CPPUNIT_ASSERT_EQUAL((unsigned int)2, loop1->getStep()); + CPPUNIT_ASSERT_EQUAL(1U, loop1->getStartValue()); + CPPUNIT_ASSERT_EQUAL(10U, loop1->getEndValue()); + CPPUNIT_ASSERT_EQUAL(2U, loop1->getStep()); } void ParameterizedStringParserTest::testParse_loop_empty() @@ -189,9 +189,9 @@ void ParameterizedStringParserTest::testParse_alphaLoop() SharedHandle loop1 = ls; CPPUNIT_ASSERT(!loop1.isNull()); - CPPUNIT_ASSERT_EQUAL(0, loop1->getStartValue()); - CPPUNIT_ASSERT_EQUAL(25, loop1->getEndValue()); - CPPUNIT_ASSERT_EQUAL((unsigned int)2, loop1->getStep()); + CPPUNIT_ASSERT_EQUAL(0U, loop1->getStartValue()); + CPPUNIT_ASSERT_EQUAL(25U, loop1->getEndValue()); + CPPUNIT_ASSERT_EQUAL(2U, loop1->getStep()); } void ParameterizedStringParserTest::testParse_loop_mixedChar() @@ -230,9 +230,9 @@ void ParameterizedStringParserTest::testParse_segment_loop() SharedHandle loop1 = segment1->getNext(); CPPUNIT_ASSERT(!loop1.isNull()); - CPPUNIT_ASSERT_EQUAL(1, loop1->getStartValue()); - CPPUNIT_ASSERT_EQUAL(3, loop1->getEndValue()); - CPPUNIT_ASSERT_EQUAL((unsigned int)1, loop1->getStep()); + CPPUNIT_ASSERT_EQUAL(1U, loop1->getStartValue()); + CPPUNIT_ASSERT_EQUAL(3U, loop1->getEndValue()); + CPPUNIT_ASSERT_EQUAL(1U, loop1->getStep()); SharedHandle segment2 = loop1->getNext(); CPPUNIT_ASSERT(!segment2.isNull()); diff --git a/test/UtilTest.cc b/test/UtilTest.cc index 355217dd..5b38b58c 100644 --- a/test/UtilTest.cc +++ b/test/UtilTest.cc @@ -39,6 +39,7 @@ class UtilTest:public CppUnit::TestFixture { CPPUNIT_TEST(testParseIntRange); CPPUNIT_TEST(testParseIntRange_invalidRange); CPPUNIT_TEST(testParseInt); + CPPUNIT_TEST(testParseUInt); CPPUNIT_TEST(testParseLLInt); CPPUNIT_TEST(testToString_binaryStream); CPPUNIT_TEST(testItos); @@ -75,6 +76,7 @@ public: void testParseIntRange(); void testParseIntRange_invalidRange(); void testParseInt(); + void testParseUInt(); void testParseLLInt(); void testToString_binaryStream(); void testItos(); @@ -412,12 +414,14 @@ void UtilTest::testIsUppercase() void UtilTest::testAlphaToNum() { - CPPUNIT_ASSERT_EQUAL(0, Util::alphaToNum("a")); - CPPUNIT_ASSERT_EQUAL(0, Util::alphaToNum("aa")); - CPPUNIT_ASSERT_EQUAL(1, Util::alphaToNum("b")); - CPPUNIT_ASSERT_EQUAL(675, Util::alphaToNum("zz")); // 25*26+25 - CPPUNIT_ASSERT_EQUAL(675, Util::alphaToNum("ZZ")); // 25*26+25 - CPPUNIT_ASSERT_EQUAL(0, Util::alphaToNum("")); + CPPUNIT_ASSERT_EQUAL(0U, Util::alphaToNum("a")); + CPPUNIT_ASSERT_EQUAL(0U, Util::alphaToNum("aa")); + CPPUNIT_ASSERT_EQUAL(1U, Util::alphaToNum("b")); + CPPUNIT_ASSERT_EQUAL(675U, Util::alphaToNum("zz")); // 25*26+25 + CPPUNIT_ASSERT_EQUAL(675U, Util::alphaToNum("ZZ")); // 25*26+25 + CPPUNIT_ASSERT_EQUAL(0U, Util::alphaToNum("")); + CPPUNIT_ASSERT_EQUAL(4294967295U, Util::alphaToNum("NXMRLXV")); + CPPUNIT_ASSERT_EQUAL(0U, Util::alphaToNum("NXMRLXW")); // uint32_t overflow } void UtilTest::testMkdirs() @@ -522,8 +526,8 @@ void UtilTest::testParseIntRange_invalidRange() void UtilTest::testParseInt() { - CPPUNIT_ASSERT_EQUAL((int32_t)-1, Util::parseInt(" -1 ")); - CPPUNIT_ASSERT_EQUAL((int32_t)2147483647, Util::parseInt("2147483647")); + CPPUNIT_ASSERT_EQUAL(-1, Util::parseInt(" -1 ")); + CPPUNIT_ASSERT_EQUAL(2147483647, Util::parseInt("2147483647")); try { Util::parseInt("2147483648"); CPPUNIT_FAIL("exception must be thrown."); @@ -554,10 +558,29 @@ void UtilTest::testParseInt() } } +void UtilTest::testParseUInt() +{ + CPPUNIT_ASSERT_EQUAL(4294967295U, Util::parseUInt(" 4294967295 ")); + try { + Util::parseUInt("-1"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + std::cerr << *e; + delete e; + } + try { + Util::parseUInt("4294967296"); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + std::cerr << *e; + delete e; + } +} + void UtilTest::testParseLLInt() { - CPPUNIT_ASSERT_EQUAL((int64_t)-1, Util::parseLLInt(" -1 ")); - CPPUNIT_ASSERT_EQUAL((int64_t)9223372036854775807LL, + CPPUNIT_ASSERT_EQUAL(-1LL, Util::parseLLInt(" -1 ")); + CPPUNIT_ASSERT_EQUAL(9223372036854775807LL, Util::parseLLInt("9223372036854775807")); try { Util::parseLLInt("9223372036854775808");