compat: backport system_nrt_wq
[~emulex/for-vlad/old/compat.git] / compat / 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/kernel.h>
15 /* 
16  * kstrto* was included in kernel 2.6.38.4 and causes conflicts with the
17  * version included in compat-wireless. We use strict_strtol to check if
18  * kstrto* is already available.
19  */
20 #ifndef strict_strtol
21
22 #include <linux/ctype.h>
23 #include <linux/errno.h>
24 #include <linux/kernel.h>
25 #include <linux/math64.h>
26 #include <linux/module.h>
27 #include <linux/types.h>
28
29 static inline char _tolower(const char c)
30 {
31         return c | 0x20;
32 }
33
34 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
35 {
36         unsigned long long acc;
37         int ok;
38
39         if (base == 0) {
40                 if (s[0] == '0') {
41                         if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
42                                 base = 16;
43                         else
44                                 base = 8;
45                 } else
46                         base = 10;
47         }
48         if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
49                 s += 2;
50
51         acc = 0;
52         ok = 0;
53         while (*s) {
54                 unsigned int val;
55
56                 if ('0' <= *s && *s <= '9')
57                         val = *s - '0';
58                 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
59                         val = _tolower(*s) - 'a' + 10;
60                 else if (*s == '\n') {
61                         if (*(s + 1) == '\0')
62                                 break;
63                         else
64                                 return -EINVAL;
65                 } else
66                         return -EINVAL;
67
68                 if (val >= base)
69                         return -EINVAL;
70                 if (acc > div_u64(ULLONG_MAX - val, base))
71                         return -ERANGE;
72                 acc = acc * base + val;
73                 ok = 1;
74
75                 s++;
76         }
77         if (!ok)
78                 return -EINVAL;
79         *res = acc;
80         return 0;
81 }
82
83 int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
84 {
85         if (s[0] == '+')
86                 s++;
87         return _kstrtoull(s, base, res);
88 }
89 EXPORT_SYMBOL(kstrtoull);
90
91 int kstrtoll(const char *s, unsigned int base, long long *res)
92 {
93         unsigned long long tmp;
94         int rv;
95
96         if (s[0] == '-') {
97                 rv = _kstrtoull(s + 1, base, &tmp);
98                 if (rv < 0)
99                         return rv;
100                 if ((long long)(-tmp) >= 0)
101                         return -ERANGE;
102                 *res = -tmp;
103         } else {
104                 rv = kstrtoull(s, base, &tmp);
105                 if (rv < 0)
106                         return rv;
107                 if ((long long)tmp < 0)
108                         return -ERANGE;
109                 *res = tmp;
110         }
111         return 0;
112 }
113 EXPORT_SYMBOL(kstrtoll);
114
115 /* Internal, do not use. */
116 int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
117 {
118         unsigned long long tmp;
119         int rv;
120
121         rv = kstrtoull(s, base, &tmp);
122         if (rv < 0)
123                 return rv;
124         if (tmp != (unsigned long long)(unsigned long)tmp)
125                 return -ERANGE;
126         *res = tmp;
127         return 0;
128 }
129 EXPORT_SYMBOL(_kstrtoul);
130
131 /* Internal, do not use. */
132 int _kstrtol(const char *s, unsigned int base, long *res)
133 {
134         long long tmp;
135         int rv;
136
137         rv = kstrtoll(s, base, &tmp);
138         if (rv < 0)
139                 return rv;
140         if (tmp != (long long)(long)tmp)
141                 return -ERANGE;
142         *res = tmp;
143         return 0;
144 }
145 EXPORT_SYMBOL(_kstrtol);
146
147 int kstrtouint(const char *s, unsigned int base, unsigned int *res)
148 {
149         unsigned long long tmp;
150         int rv;
151
152         rv = kstrtoull(s, base, &tmp);
153         if (rv < 0)
154                 return rv;
155         if (tmp != (unsigned long long)(unsigned int)tmp)
156                 return -ERANGE;
157         *res = tmp;
158         return 0;
159 }
160 EXPORT_SYMBOL(kstrtouint);
161
162 int kstrtoint(const char *s, unsigned int base, int *res)
163 {
164         long long tmp;
165         int rv;
166
167         rv = kstrtoll(s, base, &tmp);
168         if (rv < 0)
169                 return rv;
170         if (tmp != (long long)(int)tmp)
171                 return -ERANGE;
172         *res = tmp;
173         return 0;
174 }
175 EXPORT_SYMBOL(kstrtoint);
176
177 int kstrtou16(const char *s, unsigned int base, u16 *res)
178 {
179         unsigned long long tmp;
180         int rv;
181
182         rv = kstrtoull(s, base, &tmp);
183         if (rv < 0)
184                 return rv;
185         if (tmp != (unsigned long long)(u16)tmp)
186                 return -ERANGE;
187         *res = tmp;
188         return 0;
189 }
190 EXPORT_SYMBOL(kstrtou16);
191
192 int kstrtos16(const char *s, unsigned int base, s16 *res)
193 {
194         long long tmp;
195         int rv;
196
197         rv = kstrtoll(s, base, &tmp);
198         if (rv < 0)
199                 return rv;
200         if (tmp != (long long)(s16)tmp)
201                 return -ERANGE;
202         *res = tmp;
203         return 0;
204 }
205 EXPORT_SYMBOL(kstrtos16);
206
207 int kstrtou8(const char *s, unsigned int base, u8 *res)
208 {
209         unsigned long long tmp;
210         int rv;
211
212         rv = kstrtoull(s, base, &tmp);
213         if (rv < 0)
214                 return rv;
215         if (tmp != (unsigned long long)(u8)tmp)
216                 return -ERANGE;
217         *res = tmp;
218         return 0;
219 }
220 EXPORT_SYMBOL(kstrtou8);
221
222 int kstrtos8(const char *s, unsigned int base, s8 *res)
223 {
224         long long tmp;
225         int rv;
226
227         rv = kstrtoll(s, base, &tmp);
228         if (rv < 0)
229                 return rv;
230         if (tmp != (long long)(s8)tmp)
231                 return -ERANGE;
232         *res = tmp;
233         return 0;
234 }
235 EXPORT_SYMBOL(kstrtos8);
236 #endif /* #ifndef strict_strtol */