Merge branch 'slub/lockless' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
[pandora-kernel.git] / lib / kstrtox.c
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 #include <asm/uaccess.h>
21
22 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
23 {
24         unsigned long long acc;
25         int ok;
26
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;
35         }
36         if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
37                 s += 2;
38
39         acc = 0;
40         ok = 0;
41         while (*s) {
42                 unsigned int val;
43
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;
52
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;
59
60                 s++;
61         }
62         if (!ok)
63                 return -EINVAL;
64         *res = acc;
65         return 0;
66 }
67
68 int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
69 {
70         if (s[0] == '+')
71                 s++;
72         return _kstrtoull(s, base, res);
73 }
74 EXPORT_SYMBOL(kstrtoull);
75
76 int kstrtoll(const char *s, unsigned int base, long long *res)
77 {
78         unsigned long long tmp;
79         int rv;
80
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;
95         }
96         return 0;
97 }
98 EXPORT_SYMBOL(kstrtoll);
99
100 /* Internal, do not use. */
101 int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
102 {
103         unsigned long long tmp;
104         int rv;
105
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;
113 }
114 EXPORT_SYMBOL(_kstrtoul);
115
116 /* Internal, do not use. */
117 int _kstrtol(const char *s, unsigned int base, long *res)
118 {
119         long long tmp;
120         int rv;
121
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;
129 }
130 EXPORT_SYMBOL(_kstrtol);
131
132 int kstrtouint(const char *s, unsigned int base, unsigned int *res)
133 {
134         unsigned long long tmp;
135         int rv;
136
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;
144 }
145 EXPORT_SYMBOL(kstrtouint);
146
147 int kstrtoint(const char *s, unsigned int base, int *res)
148 {
149         long long tmp;
150         int rv;
151
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;
159 }
160 EXPORT_SYMBOL(kstrtoint);
161
162 int kstrtou16(const char *s, unsigned int base, u16 *res)
163 {
164         unsigned long long tmp;
165         int rv;
166
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;
174 }
175 EXPORT_SYMBOL(kstrtou16);
176
177 int kstrtos16(const char *s, unsigned int base, s16 *res)
178 {
179         long long tmp;
180         int rv;
181
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;
189 }
190 EXPORT_SYMBOL(kstrtos16);
191
192 int kstrtou8(const char *s, unsigned int base, u8 *res)
193 {
194         unsigned long long tmp;
195         int rv;
196
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;
204 }
205 EXPORT_SYMBOL(kstrtou8);
206
207 int kstrtos8(const char *s, unsigned int base, s8 *res)
208 {
209         long long tmp;
210         int rv;
211
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;
219 }
220 EXPORT_SYMBOL(kstrtos8);
221
222 #define kstrto_from_user(f, g, type)                                    \
223 int f(const char __user *s, size_t count, unsigned int base, type *res) \
224 {                                                                       \
225         /* sign, base 2 representation, newline, terminator */          \
226         char buf[1 + sizeof(type) * 8 + 1 + 1];                         \
227                                                                         \
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);                                       \
233 }                                                                       \
234 EXPORT_SYMBOL(f)
235
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);