]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/strtonum-gen.h
ff-varints: Fixed really silly bug in handling fastbufs.
[libucw.git] / ucw / strtonum-gen.h
index 079548ffe04e32dd8c941f5454b5d9df69896c59..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);
-
-  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;
 }