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 | |
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')
-rw-r--r-- | lib/kstrtox.c | 75 | ||||
-rw-r--r-- | lib/kstrtox.h | 8 | ||||
-rw-r--r-- | lib/vsprintf.c | 33 |
3 files changed, 68 insertions, 48 deletions
diff --git a/lib/kstrtox.c b/lib/kstrtox.c index 5e066759f55..7a94c8f14e2 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 | ||
diff --git a/lib/kstrtox.h b/lib/kstrtox.h new file mode 100644 index 00000000000..f13eeeaf441 --- /dev/null +++ b/lib/kstrtox.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _LIB_KSTRTOX_H | ||
2 | #define _LIB_KSTRTOX_H | ||
3 | |||
4 | #define KSTRTOX_OVERFLOW (1U << 31) | ||
5 | const char *_parse_integer_fixup_radix(const char *s, unsigned int *base); | ||
6 | unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res); | ||
7 | |||
8 | #endif | ||
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d7222a9c826..c1a3927326e 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -31,17 +31,7 @@ | |||
31 | #include <asm/div64.h> | 31 | #include <asm/div64.h> |
32 | #include <asm/sections.h> /* for dereference_function_descriptor() */ | 32 | #include <asm/sections.h> /* for dereference_function_descriptor() */ |
33 | 33 | ||
34 | static unsigned int simple_guess_base(const char *cp) | 34 | #include "kstrtox.h" |
35 | { | ||
36 | if (cp[0] == '0') { | ||
37 | if (_tolower(cp[1]) == 'x' && isxdigit(cp[2])) | ||
38 | return 16; | ||
39 | else | ||
40 | return 8; | ||
41 | } else { | ||
42 | return 10; | ||
43 | } | ||
44 | } | ||
45 | 35 | ||
46 | /** | 36 | /** |
47 | * simple_strtoull - convert a string to an unsigned long long | 37 | * simple_strtoull - convert a string to an unsigned long long |
@@ -51,23 +41,14 @@ static unsigned int simple_guess_base(const char *cp) | |||
51 | */ | 41 | */ |
52 | unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) | 42 | unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) |
53 | { | 43 | { |
54 | unsigned long long result = 0; | 44 | unsigned long long result; |
45 | unsigned int rv; | ||
55 | 46 | ||
56 | if (!base) | 47 | cp = _parse_integer_fixup_radix(cp, &base); |
57 | base = simple_guess_base(cp); | 48 | rv = _parse_integer(cp, base, &result); |
49 | /* FIXME */ | ||
50 | cp += (rv & ~KSTRTOX_OVERFLOW); | ||
58 | 51 | ||
59 | if (base == 16 && cp[0] == '0' && _tolower(cp[1]) == 'x') | ||
60 | cp += 2; | ||
61 | |||
62 | while (isxdigit(*cp)) { | ||
63 | unsigned int value; | ||
64 | |||
65 | value = isdigit(*cp) ? *cp - '0' : _tolower(*cp) - 'a' + 10; | ||
66 | if (value >= base) | ||
67 | break; | ||
68 | result = result * base + value; | ||
69 | cp++; | ||
70 | } | ||
71 | if (endp) | 52 | if (endp) |
72 | *endp = (char *)cp; | 53 | *endp = (char *)cp; |
73 | 54 | ||