1 : /* Copyright (c) 2007 James Antill -- See LICENSE file for terms. */
2 :
3 : #ifndef USTR_PARSE_H
4 : #error " You should have already included ustr-parse.h, or just include ustr.h."
5 : #endif
6 :
7 : #if ! USTR_CONF_HAVE_STDINT_H
8 : # define USTR__UMAX unsigned long
9 : #else
10 : # define USTR__UMAX uintmax_t
11 : #endif
12 :
13 : /* basically uses: [ ]*[-+](0b|0B|0o|0O|0x|0X|0)[0-9a-z_]+ */
14 : USTR_CONF_e_PROTO
15 : int ustr__parse_num_beg(const char **ptr, size_t *len,
16 : unsigned int flags, int *tst_neg, int *tst_0,
17 : unsigned int *ern)
18 : USTR__COMPILE_ATTR_WARN_UNUSED_RET() USTR__COMPILE_ATTR_NONNULL_A();
19 : USTR_CONF_i_PROTO
20 : int ustr__parse_num_beg(const char **ptr, size_t *len,
21 : unsigned int flags, int *tst_neg, int *tst_0,
22 : unsigned int *ern)
23 264 : {
24 264 : unsigned int base = flags & USTR__MASK_PARSE_NUM_BASE;
25 264 : int auto_base = USTR_FALSE;
26 :
27 264 : if (!base)
28 196 : auto_base = USTR_TRUE;
29 68 : else if (base > 36)
30 4 : base = 36;
31 64 : else if (base == 1)
32 8 : ++base;
33 :
34 264 : if (flags & USTR_FLAG_PARSE_NUM_SPACE)
35 : {
36 190 : while (*len && (**ptr == ' '))
37 : {
38 88 : ++*ptr;
39 88 : --*len;
40 : }
41 :
42 68 : if (!*len)
43 : {
44 4 : *ern = USTR_TYPE_PARSE_NUM_ERR_ONLY_S;
45 4 : return (0);
46 : }
47 : }
48 :
49 260 : if (!(flags & USTR_FLAG_PARSE_NUM_NO_BEG_PM))
50 : {
51 252 : switch (**ptr)
52 : {
53 : case '-':
54 52 : *tst_neg = USTR_TRUE;
55 : case '+':
56 84 : ++*ptr;
57 84 : --*len;
58 : }
59 252 : if (!*len)
60 : {
61 8 : *ern = USTR_TYPE_PARSE_NUM_ERR_ONLY_SPM;
62 8 : return (0);
63 : }
64 : }
65 :
66 252 : if (**ptr != '0')
67 : {
68 96 : if (base)
69 48 : return (base);
70 48 : return (10);
71 : }
72 :
73 156 : ++*ptr;
74 156 : --*len;
75 :
76 156 : if (!*len)
77 : {
78 24 : *tst_0 = USTR_TRUE;
79 24 : return (10);
80 : }
81 164 : else if ((auto_base || (base == 2)) && ((**ptr == 'b') || (**ptr == 'B')))
82 32 : base = 2;
83 128 : else if ((auto_base || (base == 8)) && ((**ptr == 'o') || (**ptr == 'O')))
84 28 : base = 8;
85 120 : else if ((auto_base || (base == 16)) && ((**ptr == 'x') || (**ptr == 'X')))
86 48 : base = 16;
87 24 : else if ((flags & USTR_FLAG_PARSE_NUM_NO_BEG_ZERO) &&
88 : (!auto_base || (**ptr == '0')))
89 : {
90 4 : *ern = USTR_TYPE_PARSE_NUM_ERR_BEG_ZERO;
91 4 : return (0);
92 : }
93 : else
94 : {
95 20 : *tst_0 = USTR_TRUE;
96 20 : if (base)
97 4 : return (base);
98 16 : return (8);
99 : }
100 :
101 108 : ++*ptr;
102 108 : --*len;
103 :
104 108 : if (!*len)
105 : {
106 12 : *ern = USTR_TYPE_PARSE_NUM_ERR_ONLY_SPMX;
107 12 : return (0);
108 : }
109 :
110 96 : if ((flags & USTR_FLAG_PARSE_NUM_NO_BEG_ZERO) && (**ptr == '0') && (*len > 1))
111 : {
112 4 : *ern = USTR_TYPE_PARSE_NUM_ERR_BEG_ZERO;
113 4 : return (0);
114 : }
115 :
116 92 : return (base);
117 : }
118 : #if USTR_CONF_HAVE_STDINT_H
119 : USTR_CONF_I_PROTO
120 : #else
121 : USTR_CONF_e_PROTO
122 : USTR__UMAX ustr_parse_uintmaxx(const struct Ustr *, size_t, unsigned int,
123 : USTR__UMAX, USTR__UMAX, char,
124 : size_t *, unsigned int *)
125 : USTR__COMPILE_ATTR_WARN_UNUSED_RET() USTR__COMPILE_ATTR_NONNULL_L((1));
126 : USTR_CONF_i_PROTO
127 : #endif
128 : USTR__UMAX ustr_parse_uintmaxx(const struct Ustr *s1, size_t off,
129 : unsigned int flags,
130 : USTR__UMAX num_min, USTR__UMAX num_max,
131 : const char *sep,
132 : size_t *ret_len, unsigned int *ern)
133 264 : {
134 : static const char local_let_low[] = "abcdefghijklmnopqrstuvwxyz";
135 : static const char local_let_high[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
136 : unsigned int dummy_ern;
137 264 : unsigned int num_base = 0;
138 264 : int tst_neg = USTR_FALSE;
139 264 : int tst_0 = USTR_FALSE;
140 264 : int done_once = USTR_FALSE;
141 264 : char num_end = '9';
142 264 : const char *ptr = ustr_cstr(s1);
143 264 : size_t len = ustr_len(s1);
144 : size_t orig_len;
145 264 : USTR__UMAX ret = 0;
146 264 : size_t slen = strlen(sep);
147 :
148 132 : USTR_ASSERT(ustr_assert_valid(s1));
149 132 : USTR_ASSERT(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE) || !num_min);
150 :
151 264 : if (!ern) ern = &dummy_ern;
152 264 : *ern = USTR_TYPE_PARSE_NUM_ERR_NONE;
153 :
154 264 : USTR_ASSERT_RET(off <= len, 0);
155 264 : ptr += off;
156 264 : len -= off;
157 :
158 264 : orig_len = len;
159 :
160 264 : if (!(num_base = ustr__parse_num_beg(&ptr,&len, flags, &tst_neg,&tst_0, ern)))
161 32 : return (0);
162 :
163 232 : if (tst_neg && (flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE))
164 : {
165 4 : *ern = USTR_TYPE_PARSE_NUM_ERR_NEGATIVE;
166 4 : return (0);
167 : }
168 :
169 228 : if (num_base < 10)
170 72 : num_end = '0' + num_base - 1;
171 :
172 228 : if (tst_neg)
173 44 : num_max = num_min;
174 :
175 228 : done_once = tst_0;
176 1412 : while (len)
177 : {
178 1004 : const char *end = 0;
179 1004 : unsigned int add_num = 0;
180 1004 : USTR__UMAX old_ret = ret;
181 :
182 1004 : if (done_once && (flags & USTR_FLAG_PARSE_NUM_SEP) &&
183 : (*ptr == *sep) && (len >= slen) && !memcmp(ptr, sep, slen))
184 : {
185 84 : ptr += slen;
186 84 : len -= slen;
187 84 : continue;
188 : }
189 : else
190 : {
191 1524 : if ((*ptr >= '0') && (*ptr <= num_end))
192 604 : add_num = (*ptr - '0');
193 316 : else if (num_base <= 10)
194 24 : break;
195 292 : else if ((end = memchr(local_let_low, *ptr, num_base - 10)))
196 104 : add_num = 10 + (end - local_let_low);
197 188 : else if ((end = memchr(local_let_high, *ptr, num_base - 10)))
198 176 : add_num = 10 + (end - local_let_high);
199 : else
200 12 : break;
201 : }
202 :
203 884 : ret = (ret * num_base) + add_num;
204 884 : if ((flags & USTR_FLAG_PARSE_NUM_OVERFLOW) &&
205 : (((ret - add_num) / num_base) != old_ret))
206 : {
207 12 : *ern = USTR_TYPE_PARSE_NUM_ERR_OVERFLOW;
208 12 : ret = 0;
209 12 : break;
210 : }
211 :
212 872 : ++ptr;
213 872 : --len;
214 872 : done_once = USTR_TRUE;
215 : }
216 :
217 228 : if (!done_once)
218 : {
219 24 : *ern = USTR_TYPE_PARSE_NUM_ERR_OOB;
220 24 : return (0);
221 : }
222 :
223 204 : if (!*ern && (flags & USTR_FLAG_PARSE_NUM_EXACT) && len)
224 4 : *ern = USTR_TYPE_PARSE_NUM_ERR_OOB;
225 :
226 204 : if (ret > num_max)
227 : {
228 28 : ret = num_max;
229 28 : if (flags & USTR_FLAG_PARSE_NUM_OVERFLOW)
230 : {
231 16 : if (!*ern)
232 16 : *ern = USTR_TYPE_PARSE_NUM_ERR_OVERFLOW;
233 16 : ret = 0;
234 : }
235 : }
236 :
237 204 : if (ret_len)
238 28 : *ret_len = orig_len - len;
239 :
240 204 : if (tst_neg)
241 40 : return (-ret);
242 :
243 164 : return (ret);
244 : }
245 :
246 : #if USTR_CONF_HAVE_STDINT_H
247 : USTR_CONF_I_PROTO
248 : uintmax_t ustr_parse_uintmax(const struct Ustr *s1, size_t off,
249 : unsigned int flags, size_t *len, unsigned int *ern)
250 40 : {
251 20 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
252 40 : flags |= USTR_FLAG_PARSE_NUM_NO_NEGATIVE;
253 40 : return (ustr_parse_uintmaxx(s1, off, flags, 0, UINTMAX_MAX, "_", len, ern));
254 : }
255 : USTR_CONF_I_PROTO
256 : intmax_t ustr_parse_intmax(const struct Ustr *s1, size_t off,
257 : unsigned int flags, size_t *len, unsigned int *ern)
258 16 : {
259 16 : uintmax_t num_min = INTMAX_MIN;
260 8 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
261 16 : return (ustr_parse_uintmaxx(s1,off, flags, -num_min,INTMAX_MAX, "_",len,ern));
262 : }
263 : #endif
264 :
265 : USTR_CONF_I_PROTO
266 : unsigned long ustr_parse_ulongx(const struct Ustr *s1, size_t off,
267 : unsigned int flags,
268 : unsigned long num_min, unsigned long num_max,
269 : const char *sep, size_t *len, unsigned int *ern)
270 40 : { return (ustr_parse_uintmaxx(s1,off, flags, num_min,num_max, sep, len, ern)); }
271 :
272 : USTR_CONF_I_PROTO
273 : unsigned long ustr_parse_ulong(const struct Ustr *s1, size_t off,
274 : unsigned int flags,
275 : size_t *len, unsigned int *ern)
276 12 : {
277 6 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
278 12 : flags |= USTR_FLAG_PARSE_NUM_NO_NEGATIVE;
279 12 : return (ustr_parse_uintmaxx(s1, off, flags, 0, ULONG_MAX, "_", len, ern));
280 : }
281 : USTR_CONF_I_PROTO
282 : long ustr_parse_long(const struct Ustr *s1, size_t off, unsigned int flags,
283 : size_t *len, unsigned int *ern)
284 8 : {
285 8 : unsigned long num_min = LONG_MIN;
286 4 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
287 8 : return (ustr_parse_uintmaxx(s1,off, flags, -num_min, LONG_MAX, "_", len,ern));
288 : }
289 :
290 : USTR_CONF_I_PROTO
291 : unsigned int ustr_parse_uint(const struct Ustr *s1, size_t off,
292 : unsigned int flags, size_t *len, unsigned int *ern)
293 44 : {
294 22 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
295 44 : flags |= USTR_FLAG_PARSE_NUM_NO_NEGATIVE;
296 44 : return (ustr_parse_uintmaxx(s1, off, flags, 0, UINT_MAX, "_", len, ern));
297 : }
298 : USTR_CONF_I_PROTO
299 : int ustr_parse_int(const struct Ustr *s1, size_t off, unsigned int flags,
300 : size_t *len, unsigned int *ern)
301 40 : {
302 40 : unsigned int num_min = INT_MIN;
303 20 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
304 40 : return (ustr_parse_uintmaxx(s1,off, flags, -num_min, INT_MAX, "_", len, ern));
305 : }
306 :
307 : USTR_CONF_I_PROTO
308 : unsigned short ustr_parse_ushort(const struct Ustr *s1, size_t off,
309 : unsigned int flags,
310 : size_t *len, unsigned int *ern)
311 12 : {
312 6 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
313 12 : flags |= USTR_FLAG_PARSE_NUM_NO_NEGATIVE;
314 12 : return (ustr_parse_uintmaxx(s1, off, flags, 0, USHRT_MAX, "_", len, ern));
315 : }
316 : USTR_CONF_I_PROTO
317 : short ustr_parse_short(const struct Ustr *s1, size_t off, unsigned int flags,
318 : size_t *len, unsigned int *ern)
319 20 : {
320 20 : unsigned short num_min = SHRT_MIN;
321 10 : ustr_assert(!(flags & USTR_FLAG_PARSE_NUM_NO_NEGATIVE));
322 20 : return (ustr_parse_uintmaxx(s1,off, flags, -num_min, SHRT_MAX, "_", len,ern));
323 : }
324 :
325 : /* void *ustr_parse_num(const struct Ustr *s1, unsigned int flags,
326 : unsigned int *ern,
327 : void *(*func)(unsigned int, int,unsigned int *, void *),
328 : void *data)
329 :
330 : if (is_neg) add_num = -add_num;
331 :
332 : if (!(ret = func(num_base, add_num, err, ret)) && !*err)
333 : return (NULL);
334 : */
335 :
|