Initial public busybox upstream commit
[busybox4maemo] / libbb / xatonum_template.c
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. Make sure we get the
25          * actual isspace function rather than a macro implementaion. */
26         if (*numstr == '-' || *numstr == '+' || (isspace)(*numstr))
27                 goto inval;
28
29         /* Since this is a lib function, we're not allowed to reset errno to 0.
30          * Doing so could break an app that is deferring checking of errno.
31          * So, save the old value so that we can restore it if successful. */
32         old_errno = errno;
33         errno = 0;
34         r = XSTR_STRTOU(numstr, &e, base);
35         /* Do the initial validity check.  Note: The standards do not
36          * guarantee that errno is set if no digits were found.  So we
37          * must test for this explicitly. */
38         if (errno || numstr == e)
39                 goto inval; /* error / no digits / illegal trailing chars */
40
41         errno = old_errno;      /* Ok.  So restore errno. */
42
43         /* Do optional suffix parsing.  Allow 'empty' suffix tables.
44          * Note that we also allow nul suffixes with associated multipliers,
45          * to allow for scaling of the numstr by some default multiplier. */
46         if (suffixes) {
47                 while (suffixes->mult) {
48                         if (strcmp(suffixes->suffix, e) == 0) {
49                                 if (XSTR_UTYPE_MAX / suffixes->mult < r)
50                                         goto range; /* overflow! */
51                                 r *= suffixes->mult;
52                                 goto chk_range;
53                         }
54                         ++suffixes;
55                 }
56         }
57
58         /* Note: trailing space is an error.
59            It would be easy enough to allow though if desired. */
60         if (*e)
61                 goto inval;
62  chk_range:
63         /* Finally, check for range limits. */
64         if (r >= lower && r <= upper)
65                 return r;
66  range:
67         bb_error_msg_and_die("number %s is not in %llu..%llu range",
68                 numstr, (unsigned long long)lower,
69                 (unsigned long long)upper);
70  inval:
71         bb_error_msg_and_die("invalid number '%s'", numstr);
72 }
73
74 unsigned type xstrtou(_range)(const char *numstr, int base,
75                 unsigned type lower,
76                 unsigned type upper)
77 {
78         return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL);
79 }
80
81 unsigned type xstrtou(_sfx)(const char *numstr, int base,
82                 const struct suffix_mult *suffixes)
83 {
84         return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes);
85 }
86
87 unsigned type xstrtou()(const char *numstr, int base)
88 {
89         return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
90 }
91
92 unsigned type xatou(_range_sfx)(const char *numstr,
93                 unsigned type lower,
94                 unsigned type upper,
95                 const struct suffix_mult *suffixes)
96 {
97         return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes);
98 }
99
100 unsigned type xatou(_range)(const char *numstr,
101                 unsigned type lower,
102                 unsigned type upper)
103 {
104         return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL);
105 }
106
107 unsigned type xatou(_sfx)(const char *numstr,
108                 const struct suffix_mult *suffixes)
109 {
110         return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes);
111 }
112
113 unsigned type xatou()(const char *numstr)
114 {
115         return xatou(_sfx)(numstr, NULL);
116 }
117
118 /* Signed ones */
119
120 type xstrto(_range_sfx)(const char *numstr, int base,
121                 type lower,
122                 type upper,
123                 const struct suffix_mult *suffixes)
124 {
125         unsigned type u = XSTR_TYPE_MAX;
126         type r;
127         const char *p = numstr;
128
129         /* NB: if you'll decide to disallow '+':
130          * at least renice applet needs to allow it */
131         if (p[0] == '+' || p[0] == '-') {
132                 ++p;
133                 if (p[0] == '-')
134                         ++u; /* = <type>_MIN (01111... + 1 == 10000...) */
135         }
136
137         r = xstrtou(_range_sfx)(p, base, 0, u, suffixes);
138
139         if (*numstr == '-') {
140                 r = -r;
141         }
142
143         if (r < lower || r > upper) {
144                 bb_error_msg_and_die("number %s is not in %lld..%lld range",
145                                 numstr, (long long)lower, (long long)upper);
146         }
147
148         return r;
149 }
150
151 type xstrto(_range)(const char *numstr, int base, type lower, type upper)
152 {
153         return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
154 }
155
156 type xato(_range_sfx)(const char *numstr,
157                 type lower,
158                 type upper,
159                 const struct suffix_mult *suffixes)
160 {
161         return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes);
162 }
163
164 type xato(_range)(const char *numstr, type lower, type upper)
165 {
166         return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL);
167 }
168
169 type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
170 {
171         return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes);
172 }
173
174 type xato()(const char *numstr)
175 {
176         return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
177 }
178
179 #undef type
180 #undef xstrtou
181 #undef xstrto
182 #undef xatou
183 #undef xato
184 #undef XSTR_UTYPE_MAX
185 #undef XSTR_TYPE_MAX
186 #undef XSTR_TYPE_MIN
187 #undef XSTR_STRTOU