aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2011-03-22 19:34:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-22 20:44:14 -0400
commit33ee3b2e2eb9b4b6c64dcf9ed66e2ac3124e748c (patch)
tree25d70c021189efa0bcbdf4e84b3ca97a6c147246 /lib
parent8a5700cd6754a3c88d2ea2f1d7a56f671987fc25 (diff)
kstrto*: converting strings to integers done (hopefully) right
1. simple_strto*() do not contain overflow checks and crufty, libc way to indicate failure. 2. strict_strto*() also do not have overflow checks but the name and comments pretend they do. 3. Both families have only "long long" and "long" variants, but users want strtou8() 4. Both "simple" and "strict" prefixes are wrong: Simple doesn't exactly say what's so simple, strict should not exist because conversion should be strict by default. The solution is to use "k" prefix and add convertors for more types. Enter kstrtoull() kstrtoll() kstrtoul() kstrtol() kstrtouint() kstrtoint() kstrtou64() kstrtos64() kstrtou32() kstrtos32() kstrtou16() kstrtos16() kstrtou8() kstrtos8() Include runtime testsuite (somewhat incomplete) as well. strict_strto*() become deprecated, stubbed to kstrto*() and eventually will be removed altogether. Use kstrto*() in code today! Note: on some archs _kstrtoul() and _kstrtol() are left in tree, even if they'll be unused at runtime. This is temporarily solution, because I don't want to hardcode list of archs where these functions aren't needed. Current solution with sizeof() and __alignof__ at least always works. 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/Kconfig.debug3
-rw-r--r--lib/Makefile2
-rw-r--r--lib/kstrtox.c227
-rw-r--r--lib/test-kstrtox.c739
-rw-r--r--lib/vsprintf.c141
5 files changed, 971 insertions, 141 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index bef5faab660f..df9234c5f9d1 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1250,3 +1250,6 @@ source "samples/Kconfig"
1250source "lib/Kconfig.kgdb" 1250source "lib/Kconfig.kgdb"
1251 1251
1252source "lib/Kconfig.kmemcheck" 1252source "lib/Kconfig.kmemcheck"
1253
1254config TEST_KSTRTOX
1255 tristate "Test kstrto*() family of functions at runtime"
diff --git a/lib/Makefile b/lib/Makefile
index ef7ed71a6ffd..8c9de027ebb1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -22,6 +22,8 @@ lib-y += kobject.o kref.o klist.o
22obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ 22obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
23 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ 23 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
24 string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o 24 string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o
25obj-y += kstrtox.o
26obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
25 27
26ifeq ($(CONFIG_DEBUG_KOBJECT),y) 28ifeq ($(CONFIG_DEBUG_KOBJECT),y)
27CFLAGS_kobject.o += -DDEBUG 29CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
new file mode 100644
index 000000000000..05672e819f8c
--- /dev/null
+++ b/lib/kstrtox.c
@@ -0,0 +1,227 @@
1/*
2 * Convert integer string representation to an integer.
3 * If an integer doesn't fit into specified type, -E is returned.
4 *
5 * Integer starts with optional sign.
6 * kstrtou*() functions do not accept sign "-".
7 *
8 * Radix 0 means autodetection: leading "0x" implies radix 16,
9 * leading "0" implies radix 8, otherwise radix is 10.
10 * Autodetection hints work after optional sign, but not before.
11 *
12 * If -E is returned, result is not touched.
13 */
14#include <linux/ctype.h>
15#include <linux/errno.h>
16#include <linux/kernel.h>
17#include <linux/math64.h>
18#include <linux/module.h>
19#include <linux/types.h>
20
21static inline char _tolower(const char c)
22{
23 return c | 0x20;
24}
25
26static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
27{
28 unsigned long long acc;
29 int ok;
30
31 if (base == 0) {
32 if (s[0] == '0') {
33 if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
34 base = 16;
35 else
36 base = 8;
37 } else
38 base = 10;
39 }
40 if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
41 s += 2;
42
43 acc = 0;
44 ok = 0;
45 while (*s) {
46 unsigned int val;
47
48 if ('0' <= *s && *s <= '9')
49 val = *s - '0';
50 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
51 val = _tolower(*s) - 'a' + 10;
52 else if (*s == '\n') {
53 if (*(s + 1) == '\0')
54 break;
55 else
56 return -EINVAL;
57 } else
58 return -EINVAL;
59
60 if (val >= base)
61 return -EINVAL;
62 if (acc > div_u64(ULLONG_MAX - val, base))
63 return -ERANGE;
64 acc = acc * base + val;
65 ok = 1;
66
67 s++;
68 }
69 if (!ok)
70 return -EINVAL;
71 *res = acc;
72 return 0;
73}
74
75int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
76{
77 if (s[0] == '+')
78 s++;
79 return _kstrtoull(s, base, res);
80}
81EXPORT_SYMBOL(kstrtoull);
82
83int kstrtoll(const char *s, unsigned int base, long long *res)
84{
85 unsigned long long tmp;
86 int rv;
87
88 if (s[0] == '-') {
89 rv = _kstrtoull(s + 1, base, &tmp);
90 if (rv < 0)
91 return rv;
92 if ((long long)(-tmp) >= 0)
93 return -ERANGE;
94 *res = -tmp;
95 } else {
96 rv = kstrtoull(s, base, &tmp);
97 if (rv < 0)
98 return rv;
99 if ((long long)tmp < 0)
100 return -ERANGE;
101 *res = tmp;
102 }
103 return 0;
104}
105EXPORT_SYMBOL(kstrtoll);
106
107/* Internal, do not use. */
108int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
109{
110 unsigned long long tmp;
111 int rv;
112
113 rv = kstrtoull(s, base, &tmp);
114 if (rv < 0)
115 return rv;
116 if (tmp != (unsigned long long)(unsigned long)tmp)
117 return -ERANGE;
118 *res = tmp;
119 return 0;
120}
121EXPORT_SYMBOL(_kstrtoul);
122
123/* Internal, do not use. */
124int _kstrtol(const char *s, unsigned int base, long *res)
125{
126 long long tmp;
127 int rv;
128
129 rv = kstrtoll(s, base, &tmp);
130 if (rv < 0)
131 return rv;
132 if (tmp != (long long)(long)tmp)
133 return -ERANGE;
134 *res = tmp;
135 return 0;
136}
137EXPORT_SYMBOL(_kstrtol);
138
139int kstrtouint(const char *s, unsigned int base, unsigned int *res)
140{
141 unsigned long long tmp;
142 int rv;
143
144 rv = kstrtoull(s, base, &tmp);
145 if (rv < 0)
146 return rv;
147 if (tmp != (unsigned long long)(unsigned int)tmp)
148 return -ERANGE;
149 *res = tmp;
150 return 0;
151}
152EXPORT_SYMBOL(kstrtouint);
153
154int kstrtoint(const char *s, unsigned int base, int *res)
155{
156 long long tmp;
157 int rv;
158
159 rv = kstrtoll(s, base, &tmp);
160 if (rv < 0)
161 return rv;
162 if (tmp != (long long)(int)tmp)
163 return -ERANGE;
164 *res = tmp;
165 return 0;
166}
167EXPORT_SYMBOL(kstrtoint);
168
169int kstrtou16(const char *s, unsigned int base, u16 *res)
170{
171 unsigned long long tmp;
172 int rv;
173
174 rv = kstrtoull(s, base, &tmp);
175 if (rv < 0)