aboutsummaryrefslogtreecommitdiff
path: root/libbb/xatol.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/xatol.c')
-rw-r--r--libbb/xatol.c210
1 files changed, 210 insertions, 0 deletions
diff --git a/libbb/xatol.c b/libbb/xatol.c
new file mode 100644
index 000000000..82250a7bb
--- /dev/null
+++ b/libbb/xatol.c
@@ -0,0 +1,210 @@
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
12unsigned long long xatoull(const char *numstr)
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, 10);
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
30unsigned long xstrtoul_range_sfx(const char *numstr, int base,
31 unsigned long lower,
32 unsigned long upper,
33 const struct suffix_mult *suffixes)
34{
35 unsigned long r;
36 int old_errno;
37 char *e;
38
39 /* Disallow '-' and any leading whitespace. Speed isn't critical here
40 * since we're parsing commandline args. So make sure we get the
41 * actual isspace function rather than a lnumstrer macro implementaion. */
42 if ((*numstr == '-') || (isspace)(*numstr))
43 goto inval;
44
45 /* Since this is a lib function, we're not allowed to reset errno to 0.
46 * Doing so could break an app that is deferring checking of errno.
47 * So, save the old value so that we can restore it if successful. */
48 old_errno = errno;
49 errno = 0;
50 r = strtoul(numstr, &e, base);
51 /* Do the initial validity check. Note: The standards do not
52 * guarantee that errno is set if no digits were found. So we
53 * must test for this explicitly. */
54 if (errno || (numstr == e))
55 goto inval; /* error / no digits / illegal trailing chars */
56
57 errno = old_errno; /* Ok. So restore errno. */
58
59 /* Do optional suffix parsing. Allow 'empty' suffix tables.
60 * Note that we also allow nul suffixes with associated multipliers,
61 * to allow for scaling of the numstr by some default multiplier. */
62 if (suffixes) {
63 while (suffixes->suffix) {
64 if (strcmp(suffixes->suffix, e) == 0) {
65 if (ULONG_MAX / suffixes->mult < r)
66 goto range; /* overflow! */
67 ++e;
68 r *= suffixes->mult;
69 break;
70 }
71 ++suffixes;
72 }
73 }
74
75 /* Note: trailing space is an error.
76 It would be easy enough to allow though if desired. */
77 if (*e)
78 goto inval;
79 /* Finally, check for range limits. */
80 if (r >= lower && r <= upper)
81 return r;
82 range:
83 bb_error_msg_and_die("number %s is not in %lu..%lu range",
84 numstr, lower, upper);
85 inval:
86 bb_error_msg_and_die("invalid number '%s'", numstr);
87}
88
89unsigned long xstrtoul_range(const char *numstr, int base,
90 unsigned long lower,
91 unsigned long upper)
92{
93 return xstrtoul_range_sfx(numstr, base, lower, upper, NULL);
94}
95
96unsigned long xstrtoul(const char *numstr, int base)
97{
98 return xstrtoul_range_sfx(numstr, base, 0, ULONG_MAX, NULL);
99}
100
101unsigned long xatoul_range_sfx(const char *numstr,
102 unsigned long lower,
103 unsigned long upper,
104 const struct suffix_mult *suffixes)
105{
106 return xstrtoul_range_sfx(numstr, 10, lower, upper, suffixes);
107}
108
109unsigned long xatoul_sfx(const char *numstr,
110 const struct suffix_mult *suffixes)
111{
112 return xstrtoul_range_sfx(numstr, 10, 0, ULONG_MAX, suffixes);
113}
114
115unsigned long xatoul_range(const char *numstr,
116 unsigned long lower,
117 unsigned long upper)
118{
119 return xstrtol_range_sfx(numstr, 10, lower, upper, NULL);
120}
121
122unsigned long xatoul(const char *numstr)
123{
124 return xatoul_sfx(numstr, NULL);
125}
126
127/* Signed ones */
128
129long xstrtol_range_sfx(const char *numstr, int base,
130 long lower,
131 long upper,
132 const struct suffix_mult *suffixes)
133{
134 unsigned long u = LONG_MAX;
135 long r;
136 const char *p = numstr;
137
138 if ((p[0] == '-') && (p[1] != '+')) {
139 ++p;
140 ++u; /* two's complement */
141 }
142
143 r = xstrtoul_range_sfx(p, base, 0, u, suffixes);
144
145 if (*numstr == '-') {
146 r = -r;
147 }
148
149 if (r < lower || r > upper) {
150 bb_error_msg_and_die("number %s is not in %ld..%ld range",
151 numstr, lower, upper);
152 }
153
154 return r;
155}
156
157long xstrtol_range(const char *numstr, int base, long lower, long upper)
158{
159 return xstrtol_range_sfx(numstr, base, lower, upper, NULL);
160}
161
162long xatol_range_sfx(const char *numstr,
163 long lower,
164 long upper,
165 const struct suffix_mult *suffixes)
166{
167 return xstrtol_range_sfx(numstr, 10, lower, upper, suffixes);
168}
169
170long xatol_range(const char *numstr, long lower, long upper)
171{
172 return xstrtol_range_sfx(numstr, 10, lower, upper, NULL);
173}
174
175long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes)
176{
177 return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, suffixes);
178}
179
180long xatol(const char *numstr)
181{
182 return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, NULL);
183}
184
185/* Others */
186
187unsigned xatou(const char *numstr)
188{
189 return xatoul_range(numstr, 0, UINT_MAX);
190}
191
192int xatoi(const char *numstr)
193{
194 return xatol_range(numstr, INT_MIN, INT_MAX);
195}
196
197int xatoi_u(const char *numstr)
198{
199 return xatoul_range(numstr, 0, INT_MAX);
200}
201
202uint32_t xatou32(const char *numstr)
203{
204 return xatoul_range(numstr, 0, 0xffffffff);
205}
206
207uint16_t xatou16(const char *numstr)
208{
209 return xatoul_range(numstr, 0, 0xffff);
210}