Commit 1dff46d6987484eaa31f2fb1425216ba06418be3
Committed by
Linus Torvalds
1 parent
b3c49c05b7
Exists in
master
and in
38 other branches
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>
Showing 3 changed files with 68 additions and 48 deletions Side-by-side Diff
lib/kstrtox.c
... | ... | @@ -18,26 +18,40 @@ |
18 | 18 | #include <linux/module.h> |
19 | 19 | #include <linux/types.h> |
20 | 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 | - int ok; | |
26 | - | |
27 | - if (base == 0) { | |
25 | + if (*base == 0) { | |
28 | 26 | if (s[0] == '0') { |
29 | 27 | if (_tolower(s[1]) == 'x' && isxdigit(s[2])) |
30 | - base = 16; | |
28 | + *base = 16; | |
31 | 29 | else |
32 | - base = 8; | |
30 | + *base = 8; | |
33 | 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 | 35 | s += 2; |
36 | + return s; | |
37 | +} | |
38 | 38 | |
39 | - acc = 0; | |
40 | - ok = 0; | |
39 | +/* | |
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 | 55 | while (*s) { |
42 | 56 | unsigned int val; |
43 | 57 | |
44 | 58 | |
45 | 59 | |
46 | 60 | |
47 | 61 | |
... | ... | @@ -45,23 +59,40 @@ |
45 | 59 | val = *s - '0'; |
46 | 60 | else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f') |
47 | 61 | val = _tolower(*s) - 'a' + 10; |
48 | - else if (*s == '\n' && *(s + 1) == '\0') | |
49 | - break; | |
50 | 62 | else |
51 | - return -EINVAL; | |
63 | + break; | |
52 | 64 | |
53 | 65 | if (val >= base) |
54 | - return -EINVAL; | |
55 | - if (acc > div_u64(ULLONG_MAX - val, base)) | |
56 | - return -ERANGE; | |
57 | - acc = acc * base + val; | |
58 | - ok = 1; | |
59 | - | |
66 | + break; | |
67 | + if (*res > div_u64(ULLONG_MAX - val, base)) | |
68 | + overflow = 1; | |
69 | + *res = *res * base + val; | |
70 | + rv++; | |
60 | 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) | |
63 | 89 | return -EINVAL; |
64 | - *res = acc; | |
90 | + s += rv; | |
91 | + if (*s == '\n') | |
92 | + s++; | |
93 | + if (*s) | |
94 | + return -EINVAL; | |
95 | + *res = _res; | |
65 | 96 | return 0; |
66 | 97 | } |
67 | 98 |
lib/kstrtox.h
lib/vsprintf.c
... | ... | @@ -31,17 +31,7 @@ |
31 | 31 | #include <asm/div64.h> |
32 | 32 | #include <asm/sections.h> /* for dereference_function_descriptor() */ |
33 | 33 | |
34 | -static unsigned int simple_guess_base(const char *cp) | |
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 | -} | |
34 | +#include "kstrtox.h" | |
45 | 35 | |
46 | 36 | /** |
47 | 37 | * simple_strtoull - convert a string to an unsigned long long |
48 | 38 | |
49 | 39 | |
... | ... | @@ -51,23 +41,14 @@ |
51 | 41 | */ |
52 | 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) | |
57 | - base = simple_guess_base(cp); | |
47 | + cp = _parse_integer_fixup_radix(cp, &base); | |
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 | 52 | if (endp) |
72 | 53 | *endp = (char *)cp; |
73 | 54 |