mount: if FILE* is NULL, it's not wise to use it.
[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_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 }