diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2011-10-31 20:12:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-31 20:30:56 -0400 |
commit | 1dff46d6987484eaa31f2fb1425216ba06418be3 (patch) | |
tree | 421e53d64a066b1f756156bb1d37154c0a5eab6a /lib/kstrtox.c | |
parent | b3c49c05b737887443c894c66635ae68dcdf0027 (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.c | 75 |
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 | ||
22 | static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) | 23 | const 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 | */ | ||
47 | unsigned 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 | |||
78 | static 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 | ||