Merge remote-tracking branch 'blackfin/for-linus'
[linux-2.6/next.git] / lib / kstrtox.c
blob5e066759f551ef61feb3acd5ab72c147e554dd98
1 /*
2 * Convert integer string representation to an integer.
3 * If an integer doesn't fit into specified type, -E is returned.
5 * Integer starts with optional sign.
6 * kstrtou*() functions do not accept sign "-".
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.
12 * If -E is returned, result is not touched.
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 #include <asm/uaccess.h>
22 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
24 unsigned long long acc;
25 int ok;
27 if (base == 0) {
28 if (s[0] == '0') {
29 if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
30 base = 16;
31 else
32 base = 8;
33 } else
34 base = 10;
36 if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
37 s += 2;
39 acc = 0;
40 ok = 0;
41 while (*s) {
42 unsigned int val;
44 if ('0' <= *s && *s <= '9')
45 val = *s - '0';
46 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
47 val = _tolower(*s) - 'a' + 10;
48 else if (*s == '\n' && *(s + 1) == '\0')
49 break;
50 else
51 return -EINVAL;
53 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;
60 s++;
62 if (!ok)
63 return -EINVAL;
64 *res = acc;
65 return 0;
68 int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
70 if (s[0] == '+')
71 s++;
72 return _kstrtoull(s, base, res);
74 EXPORT_SYMBOL(kstrtoull);
76 int kstrtoll(const char *s, unsigned int base, long long *res)
78 unsigned long long tmp;
79 int rv;
81 if (s[0] == '-') {
82 rv = _kstrtoull(s + 1, base, &tmp);
83 if (rv < 0)
84 return rv;
85 if ((long long)(-tmp) >= 0)
86 return -ERANGE;
87 *res = -tmp;
88 } else {
89 rv = kstrtoull(s, base, &tmp);
90 if (rv < 0)
91 return rv;
92 if ((long long)tmp < 0)
93 return -ERANGE;
94 *res = tmp;
96 return 0;
98 EXPORT_SYMBOL(kstrtoll);
100 /* Internal, do not use. */
101 int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
103 unsigned long long tmp;
104 int rv;
106 rv = kstrtoull(s, base, &tmp);
107 if (rv < 0)
108 return rv;
109 if (tmp != (unsigned long long)(unsigned long)tmp)
110 return -ERANGE;
111 *res = tmp;
112 return 0;
114 EXPORT_SYMBOL(_kstrtoul);
116 /* Internal, do not use. */
117 int _kstrtol(const char *s, unsigned int base, long *res)
119 long long tmp;
120 int rv;
122 rv = kstrtoll(s, base, &tmp);
123 if (rv < 0)
124 return rv;
125 if (tmp != (long long)(long)tmp)
126 return -ERANGE;
127 *res = tmp;
128 return 0;
130 EXPORT_SYMBOL(_kstrtol);
132 int kstrtouint(const char *s, unsigned int base, unsigned int *res)
134 unsigned long long tmp;
135 int rv;
137 rv = kstrtoull(s, base, &tmp);
138 if (rv < 0)
139 return rv;
140 if (tmp != (unsigned long long)(unsigned int)tmp)
141 return -ERANGE;
142 *res = tmp;
143 return 0;
145 EXPORT_SYMBOL(kstrtouint);
147 int kstrtoint(const char *s, unsigned int base, int *res)
149 long long tmp;
150 int rv;
152 rv = kstrtoll(s, base, &tmp);
153 if (rv < 0)
154 return rv;
155 if (tmp != (long long)(int)tmp)
156 return -ERANGE;
157 *res = tmp;
158 return 0;
160 EXPORT_SYMBOL(kstrtoint);
162 int kstrtou16(const char *s, unsigned int base, u16 *res)
164 unsigned long long tmp;
165 int rv;
167 rv = kstrtoull(s, base, &tmp);
168 if (rv < 0)
169 return rv;
170 if (tmp != (unsigned long long)(u16)tmp)
171 return -ERANGE;
172 *res = tmp;
173 return 0;
175 EXPORT_SYMBOL(kstrtou16);
177 int kstrtos16(const char *s, unsigned int base, s16 *res)
179 long long tmp;
180 int rv;
182 rv = kstrtoll(s, base, &tmp);
183 if (rv < 0)
184 return rv;
185 if (tmp != (long long)(s16)tmp)
186 return -ERANGE;
187 *res = tmp;
188 return 0;
190 EXPORT_SYMBOL(kstrtos16);
192 int kstrtou8(const char *s, unsigned int base, u8 *res)
194 unsigned long long tmp;
195 int rv;
197 rv = kstrtoull(s, base, &tmp);
198 if (rv < 0)
199 return rv;
200 if (tmp != (unsigned long long)(u8)tmp)
201 return -ERANGE;
202 *res = tmp;
203 return 0;
205 EXPORT_SYMBOL(kstrtou8);
207 int kstrtos8(const char *s, unsigned int base, s8 *res)
209 long long tmp;
210 int rv;
212 rv = kstrtoll(s, base, &tmp);
213 if (rv < 0)
214 return rv;
215 if (tmp != (long long)(s8)tmp)
216 return -ERANGE;
217 *res = tmp;
218 return 0;
220 EXPORT_SYMBOL(kstrtos8);
222 #define kstrto_from_user(f, g, type) \
223 int f(const char __user *s, size_t count, unsigned int base, type *res) \
225 /* sign, base 2 representation, newline, terminator */ \
226 char buf[1 + sizeof(type) * 8 + 1 + 1]; \
228 count = min(count, sizeof(buf) - 1); \
229 if (copy_from_user(buf, s, count)) \
230 return -EFAULT; \
231 buf[count] = '\0'; \
232 return g(buf, base, res); \
234 EXPORT_SYMBOL(f)
236 kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long);
237 kstrto_from_user(kstrtoll_from_user, kstrtoll, long long);
238 kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long);
239 kstrto_from_user(kstrtol_from_user, kstrtol, long);
240 kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int);
241 kstrto_from_user(kstrtoint_from_user, kstrtoint, int);
242 kstrto_from_user(kstrtou16_from_user, kstrtou16, u16);
243 kstrto_from_user(kstrtos16_from_user, kstrtos16, s16);
244 kstrto_from_user(kstrtou8_from_user, kstrtou8, u8);
245 kstrto_from_user(kstrtos8_from_user, kstrtos8, s8);