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