1b71e9ca8707f28523914b44ab3113544a8bcd70
[oweals/busybox.git] / libbb / xatol.c
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(const char *numstr, int base)
102 {
103         return xstrtoul_range_sfx(numstr, base, 0, ULONG_MAX, NULL);
104 }
105
106 unsigned long xatoul_range_sfx(const char *numstr,
107                 unsigned long lower,
108                 unsigned long upper,
109                 const struct suffix_mult *suffixes)
110 {
111         return xstrtoul_range_sfx(numstr, 10, lower, upper, suffixes);
112 }
113
114 unsigned long xatoul_sfx(const char *numstr,
115                 const struct suffix_mult *suffixes)
116 {
117         return xstrtoul_range_sfx(numstr, 10, 0, ULONG_MAX, suffixes);
118 }
119
120 unsigned long xatoul_range(const char *numstr,
121                 unsigned long lower,
122                 unsigned long upper)
123 {
124         return xstrtol_range_sfx(numstr, 10, lower, upper, NULL);
125 }
126
127 unsigned long xatoul(const char *numstr)
128 {
129         return xatoul_sfx(numstr, NULL);
130 }
131
132 /* Signed ones */
133
134 long xstrtol_range_sfx(const char *numstr, int base,
135                 long lower,
136                 long upper,
137                 const struct suffix_mult *suffixes)
138 {
139         unsigned long u = LONG_MAX;
140         long r;
141         const char *p = numstr;
142
143         if ((p[0] == '-') && (p[1] != '+')) {
144                 ++p;
145                 ++u;    /* two's complement */
146         }
147
148         r = xstrtoul_range_sfx(p, base, 0, u, suffixes);
149
150         if (*numstr == '-') {
151                 r = -r;
152         }
153
154         if (r < lower || r > upper) {
155                 bb_error_msg_and_die("number %s is not in %ld..%ld range",
156                                 numstr, lower, upper);
157         }
158
159         return r;
160 }
161
162 long xstrtol_range(const char *numstr, int base, long lower, long upper)
163 {
164         return xstrtol_range_sfx(numstr, base, lower, upper, NULL);
165 }
166
167 long xatol_range_sfx(const char *numstr,
168                 long lower,
169                 long upper,
170                 const struct suffix_mult *suffixes)
171 {
172         return xstrtol_range_sfx(numstr, 10, lower, upper, suffixes);
173 }
174
175 long xatol_range(const char *numstr, long lower, long upper)
176 {
177         return xstrtol_range_sfx(numstr, 10, lower, upper, NULL);
178 }
179
180 long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes)
181 {
182         return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, suffixes);
183 }
184
185 long xatol(const char *numstr)
186 {
187         return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, NULL);
188 }
189
190 /* Others */
191
192 unsigned xatou(const char *numstr)
193 {
194         return xatoul_range(numstr, 0, UINT_MAX);
195 }
196
197 int xatoi_range(const char *numstr, int lower, int upper)
198 {
199         return xatol_range(numstr, lower, upper);
200 }
201
202 int xatoi(const char *numstr)
203 {
204         return xatol_range(numstr, INT_MIN, INT_MAX);
205 }
206
207 int xatoi_u(const char *numstr)
208 {
209         return xatoul_range(numstr, 0, INT_MAX);
210 }
211
212 uint32_t xatou32(const char *numstr)
213 {
214         return xatoul_range(numstr, 0, 0xffffffff);
215 }
216
217 uint16_t xatou16(const char *numstr)
218 {
219         return xatoul_range(numstr, 0, 0xffff);
220 }