]> mj.ucw.cz Git - libucw.git/commitdiff
Minor fixes to strtonum.
authorDaniel Fiala <daniel.fiala@netcentrum.cz>
Mon, 2 Aug 2010 17:54:13 +0000 (19:54 +0200)
committerDaniel Fiala <daniel.fiala@netcentrum.cz>
Mon, 2 Aug 2010 17:54:13 +0000 (19:54 +0200)
  * Removed nested function from strtonum-gen.h .
  * Error messages are not saved in separate static variables.
  * Octal numbers can be detected by prefix '0[0-7]...' (this feature is enabled by STN_OCT0).
  * One-command blocks are not enclosed by { ... } .
  * STN_ZCHAR renamed to STN_WHOLE.

ucw/strtonum-gen.h
ucw/strtonum-test.c
ucw/strtonum-test.t
ucw/strtonum.c
ucw/strtonum.h

index f339dcbc7af0c5dafd226ef8f88862965a7ded75..6b1a6f8f3688b53d63e4ea22de02afda107bb088 100644 (file)
 #define STN_MAX ((STN_TYPE)(-1))
 static const STN_TYPE S(tops)[STN_DBASES_MASK+1] = { [2] = STN_MAX/2, [8] = STN_MAX/8, [10] = STN_MAX/10, [16] = STN_MAX/16 };
 
+static const char *S(parse_string)(const char **pp, const uns flags, const uns sign, const uns base, STN_TYPE *num)
+{
+  const STN_TYPE max = STN_MAX;
+  const STN_TYPE top = S(tops)[base];
+  if (!top)
+    return "Unknown base";
+
+  const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max;
+
+  STN_TYPE val = 0;
+  uns digits = 0;
+  int overflow = 0;
+  for (;; (*pp)++)
+    {
+      const uns c = (byte)**pp;
+
+      if (c == '_')
+        {
+          if (flags & STN_UNDERSCORE)
+            continue;
+          else
+            break;
+        }
+
+      const uns d = get_digit(c);
+      if (d >= base)
+        break;
+
+      digits++;
+
+      if (overflow)
+        continue;
+
+      STN_TYPE v = val;
+      if ( (overflow = (v > top || (v *= base) > sign_max - d)) )
+        continue;
+      val = v + d;
+    }
+
+  if (!overflow)
+    {
+      if (!digits)
+        return "Number contains no digits";
+
+      if (sign)
+        val = -val;
+    }
+  else
+    {
+      if (flags & STN_TRUNC)
+        val = sign_max;
+      else
+        return "Numeric overflow";
+    }
+
+  if ((flags & STN_WHOLE) && **pp)
+    return "Invalid character";
+
+  if (num)
+    *num = val;
+
+  return NULL;
+}
+
 STN_DECLARE(STN_TYPE, STN_SUFFIX)
 {
-  const char *p = str;
   const char *err = NULL;
 
   uns sign, base;
-  err = str_to_num_init(&p, flags, &sign, &base);
-
-  auto const char *parse_string(void);
-  const char *parse_string(void)
-  {
-    const STN_TYPE max = STN_MAX;
-    const STN_TYPE top = S(tops)[base];
-    if (!top)
-      {
-        return err_unknown_base;
-      }
-
-    const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max;
-
-    STN_TYPE val = 0;
-    uns digits = 0;
-    int overflow = 0;
-    for (;; p++)
-      {
-        const uns c = (byte)*p;
-
-        if (c == '_')
-          {
-            if (flags & STN_UNDERSCORE)
-              continue;
-            else
-              break;
-          }
-
-        const uns d = get_digit(c);
-        if (d >= base)
-          break;
-        digits++;
-        if (overflow)
-          continue;
-
-        STN_TYPE v = val;
-        if ( (overflow = (v > top || (v *= base) > sign_max - d)) )
-          continue;
-        val = v + d;
-      }
-
-    if (!overflow)
-      {
-        if (!digits)
-          {
-            return err_no_digits;
-          }
-
-        if (sign)
-          {
-            val = -val;
-          }
-      }
-    else
-      {
-        if (flags & STN_TRUNC)
-          val = sign_max;
-        else
-          {
-            return err_numeric_overflow;
-          }
-      }
-
-    if ((flags & STN_ZCHAR) && *p)
-      {
-        return err_invalid_character;
-      }
-
-    if (num)
-      *num = val;
-
-    return NULL;
-  }
+  err = str_to_num_init(&str, flags, &sign, &base);
 
   if (!err)
-    err = parse_string();
+    err = S(parse_string)(&str, flags, sign, base, num);
 
   if (next)
-    *next = p;
+    *next = str;
 
   return err;
 }
index fd15714db9109ee86212c307f9f896b9b18c4439..6fa6f23a22b9421025533e548b971c9db8967157 100644 (file)
@@ -39,6 +39,9 @@ static uns str_to_flags(const char *str)
            case 'o':
              flags |= STN_OCT;
              break;
+           case 'O':
+             flags |= STN_OCT0;
+             break;
            case 'B':
              flags |= STN_BIN;
              break;
@@ -61,8 +64,8 @@ static uns str_to_flags(const char *str)
            case 's':
              flags |= STN_SIGNED;
              break;
-           case 'Z':
-             flags |= STN_ZCHAR;
+           case 'W':
+             flags |= STN_WHOLE;
              break;
          }
      }
index f8747b5196155b78afd66bfafc95d8e6161003c4..5fc427fac4b004d5c3fdf6a98f523d321d50758f 100644 (file)
@@ -7,203 +7,211 @@ Run:        ../obj/ucw/strtonum-test '0o+-_' '0o100_000xc' | grep '^i'
 Out:   i32768
 
 # 2
+Run:   ../obj/ucw/strtonum-test '0O+-_' '0100_000xc' | grep '^i'
+Out:   i32768
+
+# 3
+Run:   ../obj/ucw/strtonum-test '0O+-_' '00000000778' | grep '^i'
+Out:   i63
+
+# 4
 Run:   ../obj/ucw/strtonum-test '0XoB+-_' '4_294_967_295xcyv' | grep '^i'
 Out:   i4294967295
 
-# 3
+# 5
 Run:   ../obj/ucw/strtonum-test '0XoB+-_' '4_294_967_296xc' | grep '^e'
 Out:   e[Numeric overflow]
 
-# 4
+# 6
 Run:   ../obj/ucw/strtonum-test '0XoBt+-_' '4_294_967_296xc' | grep '^h'
 Out:   hffffffff
 
-# 5
+# 7
 Run:   ../obj/ucw/strtonum-test '0XoBt+-_' '4_294_967_296xc' | grep '^b'
 Out:   b13:0x78
 
-# 6
+# 8
 Run:   ../obj/ucw/strtonum-test '0XoBt+-_' '0x__4_' | grep '^i'
 Out:   i4
 
-# 7
+# 9
 Run:   ../obj/ucw/strtonum-test '0XoBt+-_' '0x__4_' | grep '^b'
 Out:   b6:0x0
 
-# 8
+# 10
 Run:   ../obj/ucw/strtonum-test '0XoBt+-_' '0xXW' | grep '^e'
 Out:   e[Number contains no digits]
 
-# 9
+# 11
 Run:   ../obj/ucw/strtonum-test '0XoBt+-_' '0xXW' | grep '^b'
 Out:   b2:0x58
 
-# 10
+# 12
 Run:   ../obj/ucw/strtonum-test '0oBt+-_' '0xXW' | grep '^i'
 Out:   i0
 
-# 11
+# 13
 Run:   ../obj/ucw/strtonum-test '0oBt+-_' '0xXW' | grep '^b'
 Out:   b1:0x78
 
-# 12
-Run:   ../obj/ucw/strtonum-test '0oBt+-_Z' '0xXW' | grep '^e'
+# 14
+Run:   ../obj/ucw/strtonum-test '0oBt+-_W' '0xXW' | grep '^e'
 Out:   e[Invalid character]
 
-# 13
-Run:   ../obj/ucw/strtonum-test '0oBt+-_Z' '0xXW' | grep '^b'
+# 15
+Run:   ../obj/ucw/strtonum-test '0oBt+-_W' '0xXW' | grep '^b'
 Out:   b1:0x78
 
-# 14
+# 16
 Run:   ../obj/ucw/strtonum-test '0Bs+-_' '2_147_483_647xxx' | grep '^i'
 Out:   i2147483647
 
-# 15
+# 17
 Run:   ../obj/ucw/strtonum-test '0Bs+-_' '2_147_483_647xxx' | grep '^i'
 Out:   i2147483647
 
-# 16
+# 18
 Run:   ../obj/ucw/strtonum-test '0Bs+-_' '2_147_483_648xxx' | grep '^e'
 Out:   e[Numeric overflow]
 
-# 17
+# 19
 Run:   ../obj/ucw/strtonum-test '0Bs+-_' '-2_147_483_648xxx' | grep '^i'
 Out:   i-2147483648
 
-# 18
+# 20
 Run:   ../obj/ucw/strtonum-test '0Bs+-_' '-2_147_483_649xxx' | grep '^e'
 Out:   e[Numeric overflow]
 
-# 19
+# 21
 Run:   ../obj/ucw/strtonum-test '0Bts+-_' '2_147_483_648xxx' | grep '^i'
 Out:   i2147483647
 
-# 20
+# 22
 Run:   ../obj/ucw/strtonum-test '0Bts+-_' '-2_147_483_649xxx' | grep '^i'
 Out:   i-2147483648
 
-# 21
+# 23
 Run:   ../obj/ucw/strtonum-test '0Bts+-_' '-2_147_483_649xxx' | grep '^i'
 Out:   i-2147483648
 
-# 22
+# 24
 Run:   ../obj/ucw/strtonum-test '0X+-' '0xABCDEFxxx' | grep '^h'
 Out:   habcdef
 
-# 23
+# 25
 Run:   ../obj/ucw/strtonum-test '0X+-_' '0x00_AB_CD_EFxxx' | grep '^h'
 Out:   habcdef
 
-# 24
+# 26
 Run:   ../obj/ucw/strtonum-test '0Xs+-_' '-0x00AB_CDEFxxx' | grep '^h'
 Out:   hff543211
 
-# 25
+# 27
 Run:   ../obj/ucw/strtonum-test '0XBs+-_' '-0x00AB_CDEFxxx' | grep '^h'
 Out:   hff543211
 
-# 26
+# 28
 Run:   ../obj/ucw/strtonum-test '0B+-_' '0B1111_0000_1000_0101_1010xxx' | grep '^h'
 Out:   hf085a
 
-# 27
+# 29
 Run:   ../obj/ucw/strtonum-test '0+-_' '0B1111_0000_1000_0101_1010xxx' | grep '^b'
 Out:   b1:0x42
 
-# 28
+# 30
 Run:   ../obj/ucw/strtonum-test '0o+-_' '0o70105xxx' | grep '^i'
 Out:   i28741
 
-# 29
+# 31
 Run:   ../obj/ucw/strtonum-test '0os+-_' '-0o70105xxx' | grep '^i'
 Out:   i-28741
 
-# 30
+# 32
 Run:   ../obj/ucw/strtonum-test '0os+-_' '-0o___________xxx' | grep '^e'
 Out:   e[Number contains no digits]
 
-# 31
+# 33
 Run:   ../obj/ucw/strtonum-test '2+-_' '10578ABCG' | grep '^i'
 Out:   i2
 
-# 32
+# 34
 Run:   ../obj/ucw/strtonum-test '2s+-_' '-10578ABCG' | grep '^i'
 Out:   i-2
 
-# 33
+# 35
 Run:   ../obj/ucw/strtonum-test '8+-_' '10578ABCG' | grep '^i'
 Out:   i559
 
-# 34
+# 36
 Run:   ../obj/ucw/strtonum-test '8s+-_' '-10578ABCG' | grep '^i'
 Out:   i-559
 
-# 35
+# 37
 Run:   ../obj/ucw/strtonum-test '0+-_' '10578ABCG' | grep '^i'
 Out:   i10578
 
-# 36
+# 38
 Run:   ../obj/ucw/strtonum-test '0s+-_' '-10578ABCG' | grep '^i'
 Out:   i-10578
 
-# 37
+# 39
 Run:   ../obj/ucw/strtonum-test 'h+-_' '10578ABCG' | grep '^i'
 Out:   i274172604
 
-# 38
+# 40
 Run:   ../obj/ucw/strtonum-test 'hs+-_' '-10578ABCG' | grep '^i'
 Out:   i-274172604
 
 ## Testing str_to_uintmax(.) (It is supoposed that uintmax_t is 8 bytes integer)
-# 39
+# 41
 Run:   ../obj/ucw/strtonum-test 'h+-_' 'FFFF_FFFF_ffff_ffFF' | grep '^H'
 Out:   Hffffffffffffffff
 
-# 40
+# 42
 Run:   ../obj/ucw/strtonum-test 'h+-_' 'FFFF_FFFF_ffff_ffFF' | grep '^I'
 Out:   I18446744073709551615
 
-#41
+# 43
 Run:   ../obj/ucw/strtonum-test '0t+-_' '1844674407370000009551616' | grep '^I'
 Out:   I18446744073709551615
 
-#42
+# 44
 Run:   ../obj/ucw/strtonum-test '0+-_' '18446744073709551616' | grep '^E'
 Out:   E[Numeric overflow]
 
-# 43
+# 45
 Run:   ../obj/ucw/strtonum-test '0+-_' '18446744073709551614' | grep '^H'
 Out:   Hfffffffffffffffe
 
-# 44
+# 46
 Run:   ../obj/ucw/strtonum-test '0s+-_' '9223372036854775807L' | grep '^I'
 Out:   I9223372036854775807
 
-# 45
+# 47
 Run:   ../obj/ucw/strtonum-test '0s+-_' '9223372036854775806L' | grep '^I'
 Out:   I9223372036854775806
 
-# 46
+# 48
 Run:   ../obj/ucw/strtonum-test '0st+-_' '92233720368547758000000L' | grep '^I'
 Out:   I9223372036854775807
 
-# 47
+# 49
 Run:   ../obj/ucw/strtonum-test '0s+-_' '9223372036854775808L' | grep '^E'
 Out:   E[Numeric overflow]
 
-# 48
+# 50
 Run:   ../obj/ucw/strtonum-test '0s+-_' '-9223372036854775808L' | grep '^I'
 Out:   I-9223372036854775808
 
-# 49
+# 51
 Run:   ../obj/ucw/strtonum-test '0s+-_' '-9223372036854775807L' | grep '^I'
 Out:   I-9223372036854775807
 
-# 50
+# 52
 Run:   ../obj/ucw/strtonum-test '0st+-_' '-9223372036854775800000L' | grep '^I'
 Out:   I-9223372036854775808
 
-# 51
+# 53
 Run:   ../obj/ucw/strtonum-test '0s+-_' '-9223372036854775809L' | grep '^E'
 Out:   E[Numeric overflow]
 
index 43656fca424702478f9ae4dacd1f22d99e899a3f..1d6cd1cd29ae6476df62b3719a4943b8f0bcab9c 100644 (file)
 #include "ucw/chartype.h"
 #include "ucw/strtonum.h"
 
-static const char err_numeric_overflow[] = "Numeric overflow";
-static const char err_no_digits[] = "Number contains no digits";
-static const char err_invalid_character[] = "Invalid character";
-static const char err_unknown_base[] = "Unknown base";
-
-static uns detect_base(const char *p, const uns flags)
+static uns detect_base(const char **pp, const uns flags)
 {
-  if ((flags & STN_BASES) && *p == '0')
+  if ((flags & STN_BASES0) && **pp == '0')
     {
-      switch (p[1] & 0xDF)
+      switch ( (*pp)[1] )
         {
+          case 'x':
           case 'X':
             if (flags & STN_HEX)
               {
+                *pp += 2;
                 return 16;
               }
             break;
 
+          case 'b':
           case 'B':
             if (flags & STN_BIN)
               {
+                *pp += 2;
                 return 2;
               }
             break;
 
+          case 'o':
           case 'O':
             if (flags & STN_OCT)
               {
+                *pp += 2;
+                return 8;
+              }
+            break;
+
+          case '0'...'7':
+            if (flags & STN_OCT0)
+              {
+                (*pp)++;
                 return 8;
               }
             break;
@@ -69,16 +78,7 @@ static const char *str_to_num_init(const char **pp, const uns flags, uns *sign,
         p++;
     }
 
-  const uns prefix_base = detect_base(p, flags);
-  if (prefix_base)
-    {
-      p += 2;
-      *base = prefix_base;
-    }
-  else
-    {
-      *base = flags & STN_DBASES_MASK;
-    }
+  *base = detect_base(&p, flags) ? : flags & STN_DBASES_MASK;
 
   *pp = p;
   return err;
@@ -87,9 +87,7 @@ static const char *str_to_num_init(const char **pp, const uns flags, uns *sign,
 static inline uns get_digit(const uns c)
 {
   if (c <= '9')
-    {
-      return c - '0';
-    }
+    return c - '0';
   else
     {
       const int a = c & 0xDF;
index 597790bc4e8bbf7bf972bce36e2af09cfde90688..fd7e87b196a9e10c059963e2959953700ae34412 100644 (file)
@@ -19,13 +19,15 @@ enum str_to_num_flags {
   STN_HEX = 0x400,         // Support hexadecimal numbers (0x...)
   STN_BIN = 0x800,         // Support binary numbers (0b...)
   STN_OCT = 0x1000,        // Support octal numbers (0o...)
-  STN_UNDERSCORE = 0x2000, // Number can contain underscore characters to increase readability (eg. 1_000_000)
-  STN_ZCHAR = 0x4000,      // Number can be terminated only by \0 character
+  STN_OCT0 = 0x2000,       // Support octal numbers (0[0-7]...)
+  STN_UNDERSCORE = 0x4000, // Number can contain underscore characters to increase readability (eg. 1_000_000)
+  STN_WHOLE = 0x8000,      // Number can be terminated only by \0 character
 };
 
 #define STN_DBASES_MASK    0x1F
 #define STN_SIGNS          (STN_MINUS | STN_PLUS)
 #define STN_BASES          (STN_DEC | STN_HEX | STN_BIN | STN_OCT)
+#define STN_BASES0         (STN_BASES | STN_OCT0)
 #define STN_FLAGS          (STN_MINUS | STN_PLUS | STN_BASES)
 #define STN_UFLAGS         (STN_FLAGS | STN_UNDERSCORE)
 #define STN_SFLAGS         (STN_FLAGS | STN_SIGNED)