blob: a235f3cc471c6d427fd4c2e713a701fa0b1e7e1b [file] [log] [blame]
Alexey Dobriyan33ee3b22011-03-22 16:34:40 -07001/*
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;
Alexey Dobriyan78be9592011-04-14 15:22:02 -070052 else if (*s == '\n' && *(s + 1) == '\0')
53 break;
54 else
Alexey Dobriyan33ee3b22011-03-22 16:34:40 -070055 return -EINVAL;
56
57 if (val >= base)
58 return -EINVAL;
59 if (acc > div_u64(ULLONG_MAX - val, base))
60 return -ERANGE;
61 acc = acc * base + val;
62 ok = 1;
63
64 s++;
65 }
66 if (!ok)
67 return -EINVAL;
68 *res = acc;
69 return 0;
70}
71
72int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
73{
74 if (s[0] == '+')
75 s++;
76 return _kstrtoull(s, base, res);
77}
78EXPORT_SYMBOL(kstrtoull);
79
80int kstrtoll(const char *s, unsigned int base, long long *res)
81{
82 unsigned long long tmp;
83 int rv;
84
85 if (s[0] == '-') {
86 rv = _kstrtoull(s + 1, base, &tmp);
87 if (rv < 0)
88 return rv;
89 if ((long long)(-tmp) >= 0)
90 return -ERANGE;
91 *res = -tmp;
92 } else {
93 rv = kstrtoull(s, base, &tmp);
94 if (rv < 0)
95 return rv;
96 if ((long long)tmp < 0)
97 return -ERANGE;
98 *res = tmp;
99 }
100 return 0;
101}
102EXPORT_SYMBOL(kstrtoll);
103
104/* Internal, do not use. */
105int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
106{
107 unsigned long long tmp;
108 int rv;
109
110 rv = kstrtoull(s, base, &tmp);
111 if (rv < 0)
112 return rv;
113 if (tmp != (unsigned long long)(unsigned long)tmp)
114 return -ERANGE;
115 *res = tmp;
116 return 0;
117}
118EXPORT_SYMBOL(_kstrtoul);
119
120/* Internal, do not use. */
121int _kstrtol(const char *s, unsigned int base, long *res)
122{
123 long long tmp;
124 int rv;
125
126 rv = kstrtoll(s, base, &tmp);
127 if (rv < 0)
128 return rv;
129 if (tmp != (long long)(long)tmp)
130 return -ERANGE;
131 *res = tmp;
132 return 0;
133}
134EXPORT_SYMBOL(_kstrtol);
135
136int kstrtouint(const char *s, unsigned int base, unsigned int *res)
137{
138 unsigned long long tmp;
139 int rv;
140
141 rv = kstrtoull(s, base, &tmp);
142 if (rv < 0)
143 return rv;
144 if (tmp != (unsigned long long)(unsigned int)tmp)
145 return -ERANGE;
146 *res = tmp;
147 return 0;
148}
149EXPORT_SYMBOL(kstrtouint);
150
151int kstrtoint(const char *s, unsigned int base, int *res)
152{
153 long long tmp;
154 int rv;
155
156 rv = kstrtoll(s, base, &tmp);
157 if (rv < 0)
158 return rv;
159 if (tmp != (long long)(int)tmp)
160 return -ERANGE;
161 *res = tmp;
162 return 0;
163}
164EXPORT_SYMBOL(kstrtoint);
165
166int kstrtou16(const char *s, unsigned int base, u16 *res)
167{
168 unsigned long long tmp;
169 int rv;
170
171 rv = kstrtoull(s, base, &tmp);
172 if (rv < 0)
173 return rv;
174 if (tmp != (unsigned long long)(u16)tmp)
175 return -ERANGE;
176 *res = tmp;
177 return 0;
178}
179EXPORT_SYMBOL(kstrtou16);
180
181int kstrtos16(const char *s, unsigned int base, s16 *res)
182{
183 long long tmp;
184 int rv;
185
186 rv = kstrtoll(s, base, &tmp);
187 if (rv < 0)
188 return rv;
189 if (tmp != (long long)(s16)tmp)
190 return -ERANGE;
191 *res = tmp;
192 return 0;
193}
194EXPORT_SYMBOL(kstrtos16);
195
196int kstrtou8(const char *s, unsigned int base, u8 *res)
197{
198 unsigned long long tmp;
199 int rv;
200
201 rv = kstrtoull(s, base, &tmp);
202 if (rv < 0)
203 return rv;
204 if (tmp != (unsigned long long)(u8)tmp)
205 return -ERANGE;
206 *res = tmp;
207 return 0;
208}
209EXPORT_SYMBOL(kstrtou8);
210
211int kstrtos8(const char *s, unsigned int base, s8 *res)
212{
213 long long tmp;
214 int rv;
215
216 rv = kstrtoll(s, base, &tmp);
217 if (rv < 0)
218 return rv;
219 if (tmp != (long long)(s8)tmp)
220 return -ERANGE;
221 *res = tmp;
222 return 0;
223}
224EXPORT_SYMBOL(kstrtos8);