Browse Source

2008-03-09 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	* 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.
Tatsuhiro Tsujikawa 17 years ago
parent
commit
68b84574ae
7 changed files with 115 additions and 39 deletions
  1. 14 0
      ChangeLog
  2. 7 6
      src/PStringNumLoop.h
  3. 7 6
      src/ParameterizedStringParser.cc
  4. 31 3
      src/Util.cc
  5. 14 5
      src/Util.h
  6. 9 9
      test/ParameterizedStringParserTest.cc
  7. 33 10
      test/UtilTest.cc

+ 14 - 0
ChangeLog

@@ -1,3 +1,17 @@
+2008-03-09  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	* 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  <tujikawa at rednoah dot com>
 
 	Rewritten the functions for binding port.

+ 7 - 6
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;
   }

+ 7 - 6
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);

+ 31 - 3
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;
 }

+ 14 - 5
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);
 

+ 9 - 9
test/ParameterizedStringParserTest.cc

@@ -126,9 +126,9 @@ void ParameterizedStringParserTest::testParse_loop()
 
   SharedHandle<PStringNumLoop> 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<PStringNumLoop> 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<PStringNumLoop> 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<PStringSegment> segment2 = loop1->getNext();
   CPPUNIT_ASSERT(!segment2.isNull());

+ 33 - 10
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");