aboutsummaryrefslogtreecommitdiff
path: root/lib/kstrtox.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-31 17:46:07 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-31 17:46:07 -0700
commit094803e0aab3fe75bbf8202a8f4b5280eaade375 (patch)
tree278528ca9245a767fcfcfa97d977bd5714c082fd /lib/kstrtox.c
parent32087d4eeca14b82660dab288b1d659963b954bd (diff)
parentd8805e633e054c816c47cb6e727c81f156d9253d (diff)
Merge branch 'akpm' (Andrew's incoming)
Quoth Andrew: - Most of MM. Still waiting for the poweroc guys to get off their butts and review some threaded hugepages patches. - alpha - vfs bits - drivers/misc - a few core kerenl tweaks - printk() features - MAINTAINERS updates - backlight merge - leds merge - various lib/ updates - checkpatch updates * akpm: (127 commits) epoll: fix spurious lockdep warnings checkpatch: add a --strict check for utf-8 in commit logs kernel.h/checkpatch: mark strict_strto<foo> and simple_strto<foo> as obsolete llist-return-whether-list-is-empty-before-adding-in-llist_add-fix wireless: at76c50x: follow rename pack_hex_byte to hex_byte_pack fat: follow rename pack_hex_byte() to hex_byte_pack() security: follow rename pack_hex_byte() to hex_byte_pack() kgdb: follow rename pack_hex_byte() to hex_byte_pack() lib: rename pack_hex_byte() to hex_byte_pack() lib/string.c: fix strim() semantics for strings that have only blanks lib/idr.c: fix comment for ida_get_new_above() lib/percpu_counter.c: enclose hotplug only variables in hotplug ifdef lib/bitmap.c: quiet sparse noise about address space lib/spinlock_debug.c: print owner on spinlock lockup lib/kstrtox: common code between kstrto*() and simple_strto*() functions drivers/leds/leds-lp5521.c: check if reset is successful leds: turn the blink_timer off before starting to blink leds: save the delay values after a successful call to blink_set() drivers/leds/leds-gpio.c: use gpio_get_value_cansleep() when initializing drivers/leds/leds-lm3530.c: add __devexit_p where needed ...
Diffstat (limited to 'lib/kstrtox.c')
-rw-r--r--lib/kstrtox.c75
1 files changed, 53 insertions, 22 deletions
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index 5e066759f551..7a94c8f14e29 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -18,26 +18,40 @@
#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;
}