aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kstrtox.c
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2011-10-31 20:12:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-31 20:30:56 -0400
commit1dff46d6987484eaa31f2fb1425216ba06418be3 (patch)
tree421e53d64a066b1f756156bb1d37154c0a5eab6a /lib/kstrtox.c
parentb3c49c05b737887443c894c66635ae68dcdf0027 (diff)
lib/kstrtox: common code between kstrto*() and simple_strto*() functions
Currently termination logic (\0 or \n\0) is hardcoded in _kstrtoull(), avoid that for code reuse between kstrto*() and simple_strtoull(). Essentially, make them different only in termination logic. simple_strtoull() (and scanf(), BTW) ignores integer overflow, that's a bug we currently don't have guts to fix, making KSTRTOX_OVERFLOW hack necessary. Almost forgot: patch shrinks code size by about ~80 bytes on x86_64. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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 @@
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/types.h> 19#include <linux/types.h>
20#include <asm/uaccess.h> 20#include <asm/uaccess.h>
21#include "kstrtox.h"
21 22
22static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) 23const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
23{ 24{
24 unsigned long long acc; 25 if (*base == 0) {
25 int ok;
26
27 if (base == 0) {
28 if (s[0] == '0') { 26 if (s[0] == '0') {
29 if (_tolower(s[1]) == 'x' && isxdigit(s[2])) 27 if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
30 base = 16; 28 *base = 16;
31 else 29 else
32 base = 8; 30 *base = 8;
33 } else 31 } else
34 base = 10; 32 *base = 10;
35 } 33 }
36 if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') 34 if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
37 s += 2; 35 s += 2;
36 return s;
37}
38 38
39 acc = 0; 39/*
40 ok = 0; 40 * Convert non-negative integer string representation in explicitly given radix
41 * to an integer.
42 * Return number of characters consumed maybe or-ed with overflow bit.
43 * If overflow occurs, result integer (incorrect) is still returned.
44 *
45 * Don't you dare use this function.
46 */
47unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res)
48{
49 unsigned int rv;
50 int overflow;
51
52 *res = 0;
53 rv = 0;
54 overflow = 0;
41 while (*s) { 55 while (*s) {
42 unsigned int val; 56 unsigned int val;
43 57
@@ -45,23 +59,40 @@ static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
45 val = *s - '0'; 59 val = *s - '0';
46 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f') 60 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
47 val = _tolower(*s) - 'a' + 10; 61 val = _tolower(*s) - 'a' + 10;
48 else if (*s == '\n' && *(s + 1) == '\0')
49 break;
50 else 62 else
51 return -EINVAL; 63 break;
52 64
53 if (val >= base) 65 if (val >= base)
54 return -EINVAL; 66 break;
55 if (acc > div_u64(ULLONG_MAX - val, base)) 67 if (*res > div_u64(ULLONG_MAX - val, base))
56 return -ERANGE; 68 overflow = 1;
57 acc = acc * base + val; 69 *res = *res * base + val;
58 ok = 1; 70 rv++;
59
60 s++; 71 s++;
61 } 72 }
62 if (!ok) 73 if (overflow)
74 rv |= KSTRTOX_OVERFLOW;
75 return rv;
76}
77
78static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
79{
80 unsigned long long _res;
81 unsigned int rv;
82
83 s = _parse_integer_fixup_radix(s, &base);
84 rv = _parse_integer(s, base, &_res);
85 if (rv & KSTRTOX_OVERFLOW)
86 return -ERANGE;
87 rv &= ~KSTRTOX_OVERFLOW;
88 if (rv == 0)
89 return -EINVAL;
90 s += rv;
91 if (*s == '\n')
92 s++;
93 if (*s)
63 return -EINVAL; 94 return -EINVAL;
64 *res = acc; 95 *res = _res;
65 return 0; 96 return 0;
66} 97}
67 98