lib/kstrtox: common code between kstrto*() and simple_strto*() functions
[pandora-kernel.git] / lib / kstrtox.c
index 5e06675..7a94c8f 100644 (file)
 #include <linux/module.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
+#include "kstrtox.h"
 
-static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
 {
-       unsigned long long acc;
-       int ok;
-
-       if (base == 0) {
+       if (*base == 0) {
                if (s[0] == '0') {
                        if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
-                               base = 16;
+                               *base = 16;
                        else
-                               base = 8;
+                               *base = 8;
                } else
-                       base = 10;
+                       *base = 10;
        }
-       if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
+       if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
                s += 2;
+       return s;
+}
 
-       acc = 0;
-       ok = 0;
+/*
+ * Convert non-negative integer string representation in explicitly given radix
+ * to an integer.
+ * Return number of characters consumed maybe or-ed with overflow bit.
+ * If overflow occurs, result integer (incorrect) is still returned.
+ *
+ * Don't you dare use this function.
+ */
+unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res)
+{
+       unsigned int rv;
+       int overflow;
+
+       *res = 0;
+       rv = 0;
+       overflow = 0;
        while (*s) {
                unsigned int val;
 
@@ -45,23 +59,40 @@ static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
                        val = *s - '0';
                else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
                        val = _tolower(*s) - 'a' + 10;
-               else if (*s == '\n' && *(s + 1) == '\0')
-                       break;
                else
-                       return -EINVAL;
+                       break;
 
                if (val >= base)
-                       return -EINVAL;
-               if (acc > div_u64(ULLONG_MAX - val, base))
-                       return -ERANGE;
-               acc = acc * base + val;
-               ok = 1;
-
+                       break;
+               if (*res > div_u64(ULLONG_MAX - val, base))
+                       overflow = 1;
+               *res = *res * base + val;
+               rv++;
                s++;
        }
-       if (!ok)
+       if (overflow)
+               rv |= KSTRTOX_OVERFLOW;
+       return rv;
+}
+
+static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+{
+       unsigned long long _res;
+       unsigned int rv;
+
+       s = _parse_integer_fixup_radix(s, &base);
+       rv = _parse_integer(s, base, &_res);
+       if (rv & KSTRTOX_OVERFLOW)
+               return -ERANGE;
+       rv &= ~KSTRTOX_OVERFLOW;
+       if (rv == 0)
+               return -EINVAL;
+       s += rv;
+       if (*s == '\n')
+               s++;
+       if (*s)
                return -EINVAL;
-       *res = acc;
+       *res = _res;
        return 0;
 }