diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-25 14:44:13 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-25 14:44:13 +0000 |
commit | ed836cdc30642ddbecc286b279d461ca44135cbb (patch) | |
tree | 70735d4bd1e34de43aa3f8092446caf460bd2540 | |
parent | 809a6e310443d0b5010c8b293cab0160608c1b02 (diff) | |
download | busybox-w32-ed836cdc30642ddbecc286b279d461ca44135cbb.tar.gz busybox-w32-ed836cdc30642ddbecc286b279d461ca44135cbb.tar.bz2 busybox-w32-ed836cdc30642ddbecc286b279d461ca44135cbb.zip |
regularize str -> num convertors
-rw-r--r-- | include/libbb.h | 35 | ||||
-rw-r--r-- | include/xatonum.h | 94 | ||||
-rw-r--r-- | libbb/Kbuild | 2 | ||||
-rw-r--r-- | libbb/xatol.c | 236 | ||||
-rw-r--r-- | libbb/xatonum.c | 91 | ||||
-rw-r--r-- | libbb/xatonum_template.c | 175 |
6 files changed, 362 insertions, 271 deletions
diff --git a/include/libbb.h b/include/libbb.h index 99a1928df..152fb7e01 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -315,40 +315,7 @@ struct suffix_mult { | |||
315 | const char *suffix; | 315 | const char *suffix; |
316 | unsigned mult; | 316 | unsigned mult; |
317 | }; | 317 | }; |
318 | unsigned long long xstrtoull(const char *numstr, int base); | 318 | #include "xatonum.h" |
319 | unsigned long long xatoull(const char *numstr); | ||
320 | unsigned long xstrtoul_range_sfx(const char *numstr, int base, | ||
321 | unsigned long lower, | ||
322 | unsigned long upper, | ||
323 | const struct suffix_mult *suffixes); | ||
324 | unsigned long xstrtoul_range(const char *numstr, int base, | ||
325 | unsigned long lower, | ||
326 | unsigned long upper); | ||
327 | unsigned long xstrtoul_sfx(const char *numstr, int base, | ||
328 | const struct suffix_mult *suffixes); | ||
329 | unsigned long xstrtoul(const char *numstr, int base); | ||
330 | unsigned long xatoul_range_sfx(const char *numstr, | ||
331 | unsigned long lower, | ||
332 | unsigned long upper, | ||
333 | const struct suffix_mult *suffixes); | ||
334 | unsigned long xatoul_sfx(const char *numstr, | ||
335 | const struct suffix_mult *suffixes); | ||
336 | unsigned long xatoul_range(const char *numstr, | ||
337 | unsigned long lower, | ||
338 | unsigned long upper); | ||
339 | unsigned long xatoul(const char *numstr); | ||
340 | long xstrtol_range_sfx(const char *numstr, int base, | ||
341 | long lower, | ||
342 | long upper, | ||
343 | const struct suffix_mult *suffixes); | ||
344 | long xstrtol_range(const char *numstr, int base, long lower, long upper); | ||
345 | long xatol_range_sfx(const char *numstr, | ||
346 | long lower, | ||
347 | long upper, | ||
348 | const struct suffix_mult *suffixes); | ||
349 | long xatol_range(const char *numstr, long lower, long upper); | ||
350 | long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes); | ||
351 | long xatol(const char *numstr); | ||
352 | /* Specialized: */ | 319 | /* Specialized: */ |
353 | unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper); | 320 | unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper); |
354 | unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes); | 321 | unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes); |
diff --git a/include/xatonum.h b/include/xatonum.h new file mode 100644 index 000000000..cdb5e7393 --- /dev/null +++ b/include/xatonum.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * ascii-to-numbers implementations for busybox | ||
4 | * | ||
5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | /* Provides extern declarations of functions */ | ||
11 | #define DECLARE_STR_CONV(type, T, UT) \ | ||
12 | \ | ||
13 | unsigned type xstrto##UT##_range_sfx(const char *str, int b, unsigned type l, unsigned type u, const struct suffix_mult *sfx); \ | ||
14 | unsigned type xstrto##UT##_range(const char *str, int b, unsigned type l, unsigned type u); \ | ||
15 | unsigned type xstrto##UT##_sfx(const char *str, int b, const struct suffix_mult *sfx); \ | ||
16 | unsigned type xstrto##UT(const char *str, int b); \ | ||
17 | unsigned type xato##UT##_range_sfx(const char *str, unsigned type l, unsigned type u, const struct suffix_mult *sfx); \ | ||
18 | unsigned type xato##UT##_range(const char *str, unsigned type l, unsigned type u); \ | ||
19 | unsigned type xato##UT##_sfx(const char *str, const struct suffix_mult *sfx); \ | ||
20 | unsigned type xato##UT(const char *str); \ | ||
21 | type xstrto##T##_range_sfx(const char *str, int b, type l, type u, const struct suffix_mult *sfx) ;\ | ||
22 | type xstrto##T##_range(const char *str, int b, type l, type u); \ | ||
23 | type xato##T##_range_sfx(const char *str, type l, type u, const struct suffix_mult *sfx); \ | ||
24 | type xato##T##_range(const char *str, type l, type u); \ | ||
25 | type xato##T##_sfx(const char *str, const struct suffix_mult *sfx); \ | ||
26 | type xato##T(const char *str); \ | ||
27 | |||
28 | /* Unsigned long long functions always exist */ | ||
29 | DECLARE_STR_CONV(long long, ll, ull) | ||
30 | |||
31 | |||
32 | /* Provides extern inline definitions of functions */ | ||
33 | /* (useful for mapping them to the type of the same width) */ | ||
34 | #define DEFINE_EQUIV_STR_CONV(narrow, N, W, UN, UW) \ | ||
35 | \ | ||
36 | extern inline \ | ||
37 | unsigned narrow xstrto##UN##_range_sfx(const char *str, int b, unsigned narrow l, unsigned narrow u, const struct suffix_mult *sfx) \ | ||
38 | { return xstrto##UW##_range_sfx(str, b, l, u, sfx); } \ | ||
39 | extern inline \ | ||
40 | unsigned narrow xstrto##UN##_range(const char *str, int b, unsigned narrow l, unsigned narrow u) \ | ||
41 | { return xstrto##UW##_range(str, b, l, u); } \ | ||
42 | extern inline \ | ||
43 | unsigned narrow xstrto##UN##_sfx(const char *str, int b, const struct suffix_mult *sfx) \ | ||
44 | { return xstrto##UW##_sfx(str, b, sfx); } \ | ||
45 | extern inline \ | ||
46 | unsigned narrow xstrto##UN(const char *str, int b) \ | ||
47 | { return xstrto##UW(str, b); } \ | ||
48 | extern inline \ | ||
49 | unsigned narrow xato##UN##_range_sfx(const char *str, unsigned narrow l, unsigned narrow u, const struct suffix_mult *sfx) \ | ||
50 | { return xato##UW##_range_sfx(str, l, u, sfx); } \ | ||
51 | extern inline \ | ||
52 | unsigned narrow xato##UN##_range(const char *str, unsigned narrow l, unsigned narrow u) \ | ||
53 | { return xato##UW##_range(str, l, u); } \ | ||
54 | extern inline \ | ||
55 | unsigned narrow xato##UN##_sfx(const char *str, const struct suffix_mult *sfx) \ | ||
56 | { return xato##UW##_sfx(str, sfx); } \ | ||
57 | extern inline \ | ||
58 | unsigned narrow xato##UN(const char *str) \ | ||
59 | { return xato##UW(str); } \ | ||
60 | extern inline \ | ||
61 | narrow xstrto##N##_range_sfx(const char *str, int b, narrow l, narrow u, const struct suffix_mult *sfx) \ | ||
62 | { return xstrto##W##_range_sfx(str, b, l, u, sfx); } \ | ||
63 | extern inline \ | ||
64 | narrow xstrto##N##_range(const char *str, int b, narrow l, narrow u) \ | ||
65 | { return xstrto##W##_range(str, b, l, u); } \ | ||
66 | extern inline \ | ||
67 | narrow xato##N##_range_sfx(const char *str, narrow l, narrow u, const struct suffix_mult *sfx) \ | ||
68 | { return xato##W##_range_sfx(str, l, u, sfx); } \ | ||
69 | extern inline \ | ||
70 | narrow xato##N##_range(const char *str, narrow l, narrow u) \ | ||
71 | { return xato##W##_range(str, l, u); } \ | ||
72 | extern inline \ | ||
73 | narrow xato##N##_sfx(const char *str, const struct suffix_mult *sfx) \ | ||
74 | { return xato##W##_sfx(str, sfx); } \ | ||
75 | extern inline \ | ||
76 | narrow xato##N(const char *str) \ | ||
77 | { return xato##W(str); } \ | ||
78 | |||
79 | /* If long == long long, then just map them one-to-one */ | ||
80 | #if ULONG_MAX == ULLONG_MAX | ||
81 | DEFINE_EQUIV_STR_CONV(long, l, ll, ul, ull) | ||
82 | #else | ||
83 | /* Else provide extern defs */ | ||
84 | DECLARE_STR_CONV(long, l, ul) | ||
85 | #endif | ||
86 | |||
87 | /* Same for int -> [long] long */ | ||
88 | #if UINT_MAX == ULLONG_MAX | ||
89 | DEFINE_EQUIV_STR_CONV(int, i, ll, u, ull) | ||
90 | #elif UINT_MAX == ULONG_MAX | ||
91 | DEFINE_EQUIV_STR_CONV(int, i, l, u, ul) | ||
92 | #else | ||
93 | DECLARE_STR_CONV(int, i, u) | ||
94 | #endif | ||
diff --git a/libbb/Kbuild b/libbb/Kbuild index fc4798bf3..1ddec9a8d 100644 --- a/libbb/Kbuild +++ b/libbb/Kbuild | |||
@@ -87,7 +87,7 @@ lib-y += vperror_msg.o | |||
87 | lib-y += warn_ignoring_args.o | 87 | lib-y += warn_ignoring_args.o |
88 | lib-y += wfopen.o | 88 | lib-y += wfopen.o |
89 | lib-y += wfopen_input.o | 89 | lib-y += wfopen_input.o |
90 | lib-y += xatol.o | 90 | lib-y += xatonum.o |
91 | lib-y += xconnect.o | 91 | lib-y += xconnect.o |
92 | lib-y += xfuncs.o | 92 | lib-y += xfuncs.o |
93 | lib-y += xgetcwd.o | 93 | lib-y += xgetcwd.o |
diff --git a/libbb/xatol.c b/libbb/xatol.c deleted file mode 100644 index cce8ad3eb..000000000 --- a/libbb/xatol.c +++ /dev/null | |||
@@ -1,236 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * ascii-to-numbers implementations for busybox | ||
4 | * | ||
5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | unsigned long long xstrtoull(const char *numstr, int base) | ||
13 | { | ||
14 | unsigned long long r; | ||
15 | int old_errno; | ||
16 | char *e; | ||
17 | if ((*numstr == '-') || (isspace)(*numstr)) | ||
18 | bb_error_msg_and_die("invalid number '%s'", numstr); | ||
19 | old_errno = errno; | ||
20 | errno = 0; | ||
21 | r = strtoull(numstr, &e, base); | ||
22 | if (errno || (numstr == e) || *e) | ||
23 | /* Error / no digits / illegal trailing chars */ | ||
24 | bb_error_msg_and_die("invalid number '%s'", numstr); | ||
25 | /* No error. So restore errno. */ | ||
26 | errno = old_errno; | ||
27 | return r; | ||
28 | } | ||
29 | |||
30 | unsigned long long xatoull(const char *numstr) | ||
31 | { | ||
32 | return xstrtoull(numstr, 10); | ||
33 | } | ||
34 | |||
35 | unsigned long xstrtoul_range_sfx(const char *numstr, int base, | ||
36 | unsigned long lower, | ||
37 | unsigned long upper, | ||
38 | const struct suffix_mult *suffixes) | ||
39 | { | ||
40 | unsigned long r; | ||
41 | int old_errno; | ||
42 | char *e; | ||
43 | |||
44 | /* Disallow '-' and any leading whitespace. Speed isn't critical here | ||
45 | * since we're parsing commandline args. So make sure we get the | ||
46 | * actual isspace function rather than a lnumstrer macro implementaion. */ | ||
47 | if ((*numstr == '-') || (isspace)(*numstr)) | ||
48 | goto inval; | ||
49 | |||
50 | /* Since this is a lib function, we're not allowed to reset errno to 0. | ||
51 | * Doing so could break an app that is deferring checking of errno. | ||
52 | * So, save the old value so that we can restore it if successful. */ | ||
53 | old_errno = errno; | ||
54 | errno = 0; | ||
55 | r = strtoul(numstr, &e, base); | ||
56 | /* Do the initial validity check. Note: The standards do not | ||
57 | * guarantee that errno is set if no digits were found. So we | ||
58 | * must test for this explicitly. */ | ||
59 | if (errno || (numstr == e)) | ||
60 | goto inval; /* error / no digits / illegal trailing chars */ | ||
61 | |||
62 | errno = old_errno; /* Ok. So restore errno. */ | ||
63 | |||
64 | /* Do optional suffix parsing. Allow 'empty' suffix tables. | ||
65 | * Note that we also allow nul suffixes with associated multipliers, | ||
66 | * to allow for scaling of the numstr by some default multiplier. */ | ||
67 | if (suffixes) { | ||
68 | while (suffixes->suffix) { | ||
69 | if (strcmp(suffixes->suffix, e) == 0) { | ||
70 | if (ULONG_MAX / suffixes->mult < r) | ||
71 | goto range; /* overflow! */ | ||
72 | ++e; | ||
73 | r *= suffixes->mult; | ||
74 | break; | ||
75 | } | ||
76 | ++suffixes; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* Note: trailing space is an error. | ||
81 | It would be easy enough to allow though if desired. */ | ||
82 | if (*e) | ||
83 | goto inval; | ||
84 | /* Finally, check for range limits. */ | ||
85 | if (r >= lower && r <= upper) | ||
86 | return r; | ||
87 | range: | ||
88 | bb_error_msg_and_die("number %s is not in %lu..%lu range", | ||
89 | numstr, lower, upper); | ||
90 | inval: | ||
91 | bb_error_msg_and_die("invalid number '%s'", numstr); | ||
92 | } | ||
93 | |||
94 | unsigned long xstrtoul_range(const char *numstr, int base, | ||
95 | unsigned long lower, | ||
96 | unsigned long upper) | ||
97 | { | ||
98 | return xstrtoul_range_sfx(numstr, base, lower, upper, NULL); | ||
99 | } | ||
100 | |||
101 | unsigned long xstrtoul_sfx(const char *numstr, int base, | ||
102 | const struct suffix_mult *suffixes) | ||
103 | { | ||
104 | return xstrtoul_range_sfx(numstr, base, 0, ULONG_MAX, suffixes); | ||
105 | } | ||
106 | |||
107 | unsigned long xstrtoul(const char *numstr, int base) | ||
108 | { | ||
109 | return xstrtoul_range_sfx(numstr, base, 0, ULONG_MAX, NULL); | ||
110 | } | ||
111 | |||
112 | unsigned long xatoul_range_sfx(const char *numstr, | ||
113 | unsigned long lower, | ||
114 | unsigned long upper, | ||
115 | const struct suffix_mult *suffixes) | ||
116 | { | ||
117 | return xstrtoul_range_sfx(numstr, 10, lower, upper, suffixes); | ||
118 | } | ||
119 | |||
120 | unsigned long xatoul_sfx(const char *numstr, | ||
121 | const struct suffix_mult *suffixes) | ||
122 | { | ||
123 | return xstrtoul_range_sfx(numstr, 10, 0, ULONG_MAX, suffixes); | ||
124 | } | ||
125 | |||
126 | unsigned long xatoul_range(const char *numstr, | ||
127 | unsigned long lower, | ||
128 | unsigned long upper) | ||
129 | { | ||
130 | return xstrtoul_range_sfx(numstr, 10, lower, upper, NULL); | ||
131 | } | ||
132 | |||
133 | unsigned long xatoul(const char *numstr) | ||
134 | { | ||
135 | return xatoul_sfx(numstr, NULL); | ||
136 | } | ||
137 | |||
138 | /* Signed ones */ | ||
139 | |||
140 | long xstrtol_range_sfx(const char *numstr, int base, | ||
141 | long lower, | ||
142 | long upper, | ||
143 | const struct suffix_mult *suffixes) | ||
144 | { | ||
145 | unsigned long u = LONG_MAX; | ||
146 | long r; | ||
147 | const char *p = numstr; | ||
148 | |||
149 | if ((p[0] == '-') && (p[1] != '+')) { | ||
150 | ++p; | ||
151 | ++u; /* two's complement */ | ||
152 | } | ||
153 | |||
154 | r = xstrtoul_range_sfx(p, base, 0, u, suffixes); | ||
155 | |||
156 | if (*numstr == '-') { | ||
157 | r = -r; | ||
158 | } | ||
159 | |||
160 | if (r < lower || r > upper) { | ||
161 | bb_error_msg_and_die("number %s is not in %ld..%ld range", | ||
162 | numstr, lower, upper); | ||
163 | } | ||
164 | |||
165 | return r; | ||
166 | } | ||
167 | |||
168 | long xstrtol_range(const char *numstr, int base, long lower, long upper) | ||
169 | { | ||
170 | return xstrtol_range_sfx(numstr, base, lower, upper, NULL); | ||
171 | } | ||
172 | |||
173 | long xatol_range_sfx(const char *numstr, | ||
174 | long lower, | ||
175 | long upper, | ||
176 | const struct suffix_mult *suffixes) | ||
177 | { | ||
178 | return xstrtol_range_sfx(numstr, 10, lower, upper, suffixes); | ||
179 | } | ||
180 | |||
181 | long xatol_range(const char *numstr, long lower, long upper) | ||
182 | { | ||
183 | return xstrtol_range_sfx(numstr, 10, lower, upper, NULL); | ||
184 | } | ||
185 | |||
186 | long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes) | ||
187 | { | ||
188 | return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, suffixes); | ||
189 | } | ||
190 | |||
191 | long xatol(const char *numstr) | ||
192 | { | ||
193 | return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, NULL); | ||
194 | } | ||
195 | |||
196 | /* Others */ | ||
197 | |||
198 | unsigned xatou_range(const char *numstr, unsigned lower, unsigned upper) | ||
199 | { | ||
200 | return xstrtoul_range_sfx(numstr, 10, lower, upper, NULL); | ||
201 | } | ||
202 | |||
203 | unsigned xatou_sfx(const char *numstr, const struct suffix_mult *suffixes) | ||
204 | { | ||
205 | return xstrtoul_range_sfx(numstr, 10, 0, UINT_MAX, suffixes); | ||
206 | } | ||
207 | |||
208 | unsigned xatou(const char *numstr) | ||
209 | { | ||
210 | return xatoul_range(numstr, 0, UINT_MAX); | ||
211 | } | ||
212 | |||
213 | int xatoi_range(const char *numstr, int lower, int upper) | ||
214 | { | ||
215 | return xatol_range(numstr, lower, upper); | ||
216 | } | ||
217 | |||
218 | int xatoi(const char *numstr) | ||
219 | { | ||
220 | return xatol_range(numstr, INT_MIN, INT_MAX); | ||
221 | } | ||
222 | |||
223 | int xatoi_u(const char *numstr) | ||
224 | { | ||
225 | return xatoul_range(numstr, 0, INT_MAX); | ||
226 | } | ||
227 | |||
228 | uint32_t xatou32(const char *numstr) | ||
229 | { | ||
230 | return xatoul_range(numstr, 0, 0xffffffff); | ||
231 | } | ||
232 | |||
233 | uint16_t xatou16(const char *numstr) | ||
234 | { | ||
235 | return xatoul_range(numstr, 0, 0xffff); | ||
236 | } | ||
diff --git a/libbb/xatonum.c b/libbb/xatonum.c new file mode 100644 index 000000000..910667c14 --- /dev/null +++ b/libbb/xatonum.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * ascii-to-numbers implementations for busybox | ||
4 | * | ||
5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | |||
10 | #include "libbb.h" | ||
11 | |||
12 | #define type long long | ||
13 | #define xstrtou(rest) xstrtoull##rest | ||
14 | #define xstrto(rest) xstrtoll##rest | ||
15 | #define xatou(rest) xatoull##rest | ||
16 | #define xato(rest) xatoll##rest | ||
17 | #define XSTR_UTYPE_MAX ULLONG_MAX | ||
18 | #define XSTR_TYPE_MAX LLONG_MAX | ||
19 | #define XSTR_TYPE_MIN LLONG_MIN | ||
20 | #define XSTR_STRTOU strtoull | ||
21 | #include "xatonum_template.c" | ||
22 | #undef type | ||
23 | #undef xstrtou | ||
24 | #undef xstrto | ||
25 | #undef xatou | ||
26 | #undef xato | ||
27 | #undef XSTR_UTYPE_MAX | ||
28 | #undef XSTR_TYPE_MAX | ||
29 | #undef XSTR_TYPE_MIN | ||
30 | #undef XSTR_STRTOU | ||
31 | |||
32 | #if ULONG_MAX != ULLONG_MAX | ||
33 | #define type long | ||
34 | #define xstrtou(rest) xstrtoul##rest | ||
35 | #define xstrto(rest) xstrtol##rest | ||
36 | #define xatou(rest) xatoul##rest | ||
37 | #define xato(rest) xatol##rest | ||
38 | #define XSTR_UTYPE_MAX ULONG_MAX | ||
39 | #define XSTR_TYPE_MAX LONG_MAX | ||
40 | #define XSTR_TYPE_MIN LONG_MIN | ||
41 | #define XSTR_STRTOU strtoul | ||
42 | #include "xatonum_template.c" | ||
43 | #undef type | ||
44 | #undef xstrtou | ||
45 | #undef xstrto | ||
46 | #undef xatou | ||
47 | #undef xato | ||
48 | #undef XSTR_UTYPE_MAX | ||
49 | #undef XSTR_TYPE_MAX | ||
50 | #undef XSTR_TYPE_MIN | ||
51 | #undef XSTR_STRTOU | ||
52 | #endif | ||
53 | |||
54 | #if UINT_MAX != ULONG_MAX | ||
55 | #define type int | ||
56 | #define xstrtou(rest) xstrtou##rest | ||
57 | #define xstrto(rest) xstrtoi##rest | ||
58 | #define xatou(rest) xatou##rest | ||
59 | #define xato(rest) xatoi##rest | ||
60 | #define XSTR_UTYPE_MAX UINT_MAX | ||
61 | #define XSTR_TYPE_MAX INT_MAX | ||
62 | #define XSTR_TYPE_MIN INT_MIN | ||
63 | #define XSTR_STRTOU strtoul | ||
64 | #include "xatonum_template.c" | ||
65 | #undef type | ||
66 | #undef xstrtou | ||
67 | #undef xstrto | ||
68 | #undef xatou | ||
69 | #undef xato | ||
70 | #undef XSTR_UTYPE_MAX | ||
71 | #undef XSTR_TYPE_MAX | ||
72 | #undef XSTR_TYPE_MIN | ||
73 | #undef XSTR_STRTOU | ||
74 | #endif | ||
75 | |||
76 | /* A few special cases */ | ||
77 | |||
78 | int xatoi_u(const char *numstr) | ||
79 | { | ||
80 | return xatoul_range(numstr, 0, INT_MAX); | ||
81 | } | ||
82 | |||
83 | uint32_t xatou32(const char *numstr) | ||
84 | { | ||
85 | return xatoul_range(numstr, 0, 0xffffffff); | ||
86 | } | ||
87 | |||
88 | uint16_t xatou16(const char *numstr) | ||
89 | { | ||
90 | return xatoul_range(numstr, 0, 0xffff); | ||
91 | } | ||
diff --git a/libbb/xatonum_template.c b/libbb/xatonum_template.c new file mode 100644 index 000000000..245586a5a --- /dev/null +++ b/libbb/xatonum_template.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | You need to define the following (example): | ||
3 | |||
4 | #define type long | ||
5 | #define xstrtou(rest) xstrtoul##rest | ||
6 | #define xstrto(rest) xstrtol##rest | ||
7 | #define xatou(rest) xatoul##rest | ||
8 | #define xato(rest) xatol##rest | ||
9 | #define XSTR_UTYPE_MAX ULONG_MAX | ||
10 | #define XSTR_TYPE_MAX LONG_MAX | ||
11 | #define XSTR_TYPE_MIN LONG_MIN | ||
12 | #define XSTR_STRTOU strtoul | ||
13 | */ | ||
14 | |||
15 | unsigned type xstrtou(_range_sfx)(const char *numstr, int base, | ||
16 | unsigned type lower, | ||
17 | unsigned type upper, | ||
18 | const struct suffix_mult *suffixes) | ||
19 | { | ||
20 | unsigned type r; | ||
21 | int old_errno; | ||
22 | char *e; | ||
23 | |||
24 | /* Disallow '-' and any leading whitespace. Speed isn't critical here | ||
25 | * since we're parsing commandline args. So make sure we get the | ||
26 | * actual isspace function rather than a lnumstrer macro implementaion. */ | ||
27 | if ((*numstr == '-') || (isspace)(*numstr)) | ||
28 | goto inval; | ||
29 | |||
30 | /* Since this is a lib function, we're not allowed to reset errno to 0. | ||
31 | * Doing so could break an app that is deferring checking of errno. | ||
32 | * So, save the old value so that we can restore it if successful. */ | ||
33 | old_errno = errno; | ||
34 | errno = 0; | ||
35 | r = XSTR_STRTOU(numstr, &e, base); | ||
36 | /* Do the initial validity check. Note: The standards do not | ||
37 | * guarantee that errno is set if no digits were found. So we | ||
38 | * must test for this explicitly. */ | ||
39 | if (errno || (numstr == e)) | ||
40 | goto inval; /* error / no digits / illegal trailing chars */ | ||
41 | |||
42 | errno = old_errno; /* Ok. So restore errno. */ | ||
43 | |||
44 | /* Do optional suffix parsing. Allow 'empty' suffix tables. | ||
45 | * Note that we also allow nul suffixes with associated multipliers, | ||
46 | * to allow for scaling of the numstr by some default multiplier. */ | ||
47 | if (suffixes) { | ||
48 | while (suffixes->suffix) { | ||
49 | if (strcmp(suffixes->suffix, e) == 0) { | ||
50 | if (XSTR_UTYPE_MAX / suffixes->mult < r) | ||
51 | goto range; /* overflow! */ | ||
52 | ++e; | ||
53 | r *= suffixes->mult; | ||
54 | break; | ||
55 | } | ||
56 | ++suffixes; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | /* Note: trailing space is an error. | ||
61 | It would be easy enough to allow though if desired. */ | ||
62 | if (*e) | ||
63 | goto inval; | ||
64 | /* Finally, check for range limits. */ | ||
65 | if (r >= lower && r <= upper) | ||
66 | return r; | ||
67 | range: | ||
68 | bb_error_msg_and_die("number %s is not in %llu..%llu range", | ||
69 | numstr, (unsigned long long)lower, | ||
70 | (unsigned long long)upper); | ||
71 | inval: | ||
72 | bb_error_msg_and_die("invalid number '%s'", numstr); | ||
73 | } | ||
74 | |||
75 | unsigned type xstrtou(_range)(const char *numstr, int base, | ||
76 | unsigned type lower, | ||
77 | unsigned type upper) | ||
78 | { | ||
79 | return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL); | ||
80 | } | ||
81 | |||
82 | unsigned type xstrtou(_sfx)(const char *numstr, int base, | ||
83 | const struct suffix_mult *suffixes) | ||
84 | { | ||
85 | return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes); | ||
86 | } | ||
87 | |||
88 | unsigned type xstrtou()(const char *numstr, int base) | ||
89 | { | ||
90 | return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL); | ||
91 | } | ||
92 | |||
93 | unsigned type xatou(_range_sfx)(const char *numstr, | ||
94 | unsigned type lower, | ||
95 | unsigned type upper, | ||
96 | const struct suffix_mult *suffixes) | ||
97 | { | ||
98 | return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes); | ||
99 | } | ||
100 | |||
101 | unsigned type xatou(_range)(const char *numstr, | ||
102 | unsigned type lower, | ||
103 | unsigned type upper) | ||
104 | { | ||
105 | return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL); | ||
106 | } | ||
107 | |||
108 | unsigned type xatou(_sfx)(const char *numstr, | ||
109 | const struct suffix_mult *suffixes) | ||
110 | { | ||
111 | return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes); | ||
112 | } | ||
113 | |||
114 | unsigned type xatou()(const char *numstr) | ||
115 | { | ||
116 | return xatou(_sfx)(numstr, NULL); | ||
117 | } | ||
118 | |||
119 | /* Signed ones */ | ||
120 | |||
121 | type xstrto(_range_sfx)(const char *numstr, int base, | ||
122 | type lower, | ||
123 | type upper, | ||
124 | const struct suffix_mult *suffixes) | ||
125 | { | ||
126 | unsigned type u = XSTR_TYPE_MAX; | ||
127 | type r; | ||
128 | const char *p = numstr; | ||
129 | |||
130 | if ((p[0] == '-') && (p[1] != '+')) { | ||
131 | ++p; | ||
132 | ++u; /* two's complement */ | ||
133 | } | ||
134 | |||
135 | r = xstrtou(_range_sfx)(p, base, 0, u, suffixes); | ||
136 | |||
137 | if (*numstr == '-') { | ||
138 | r = -r; | ||
139 | } | ||
140 | |||
141 | if (r < lower || r > upper) { | ||
142 | bb_error_msg_and_die("number %s is not in %lld..%lld range", | ||
143 | numstr, (long long)lower, (long long)upper); | ||
144 | } | ||
145 | |||
146 | return r; | ||
147 | } | ||
148 | |||
149 | type xstrto(_range)(const char *numstr, int base, type lower, type upper) | ||
150 | { | ||
151 | return xstrto(_range_sfx)(numstr, base, lower, upper, NULL); | ||
152 | } | ||
153 | |||
154 | type xato(_range_sfx)(const char *numstr, | ||
155 | type lower, | ||
156 | type upper, | ||
157 | const struct suffix_mult *suffixes) | ||
158 | { | ||
159 | return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes); | ||
160 | } | ||
161 | |||
162 | type xato(_range)(const char *numstr, type lower, type upper) | ||
163 | { | ||
164 | return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL); | ||
165 | } | ||
166 | |||
167 | type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes) | ||
168 | { | ||
169 | return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes); | ||
170 | } | ||
171 | |||
172 | type xato()(const char *numstr) | ||
173 | { | ||
174 | return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL); | ||
175 | } | ||