]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/strtonum-gen.h
Build: Added support for custom PKG_CONFIG_PATH in UCW::Configure::PkgConfig().
[libucw.git] / ucw / strtonum-gen.h
index c21a9880297343579d51b2126ab55821a2c14db2..621162d41582fabce8dcaf17d0ae02308ce5f760 100644 (file)
@@ -7,8 +7,10 @@
  *     of the GNU Lesser General Public License.
  */
 
-/* This is not a normall header file, it is generator of a function for converting strings to integers
- * of a certain type. This file should be used only by ucw/stronum.c .
+/*
+ * This is not a normal header file, it is a generator of a function for
+ * converting strings to integers of a certain type. This file should be used
+ * by ucw/stronum.c only.
  */
 
 #define STN_DECLARE(type, suffix) STN_DECLARE_CONVERTOR(type, suffix)
 #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 uint flags, const uint sign, const uint 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;
+  uint digits = 0;
+  int overflow = 0;
+  for (;; (*pp)++)
+    {
+      const uint c = (byte)**pp;
+
+      if (c == '_')
+        {
+          if (flags & STN_UNDERSCORE)
+            continue;
+          else
+            break;
+        }
+
+      const uint 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;
-  }
+  uint sign, base;
+  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;
 }