1 /* Copyright (c) 2002,2004,2005 Joerg Wunsch
2 Copyright (c) 2008 Dmitry Xmelkov
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the
14 distribution.
15
16 * Neither the name of the copyright holders nor the names of
17 contributors may be used to endorse or promote products derived
18 from this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "scanf_private.h"
34 #include "../../libm/common/math_config.h"
35
36 static const char pstr_nfinity[] = "nfinity";
37 static const char pstr_an[] = "an";
38
39 #if defined(STRTOD) || defined(STRTOF) || defined(STRTOLD)
40 # define CHECK_WIDTH() 1
41 # define CHECK_RANGE(flt) do { \
42 if (CHECK_LONG()) { \
43 if ((double) flt == 0.0 || (double) flt == (double) INFINITY) \
44 errno = ERANGE; \
45 } else if (CHECK_LONG_LONG()) { \
46 if (flt == (FLOAT) 0.0 || flt == (FLOAT) INFINITY) \
47 errno = ERANGE; \
48 } else { \
49 if ((float) flt == 0.0f || (float) flt == (float) INFINITY) \
50 errno = ERANGE; \
51 } \
52 } while (0);
53 # ifdef STRTOD
54 # define CHECK_LONG() 1
55 # define CHECK_LONG_LONG() 0
56 # define FLOAT_MIN __DBL_MIN__
57 # define FLOAT_MANT_DIG __DBL_MANT_DIG__
58 # define FLOAT_MAX_EXP __DBL_MAX_EXP__
59 # define FLOAT_MIN_EXP __DBL_MIN_EXP__
60 # define ASFLOAT(x) _asdouble(x)
61 # define TOFLOAT(x) ((double) (x))
62 # elif defined(STRTOLD)
63 # define CHECK_LONG() 0
64 # define CHECK_LONG_LONG() 1
65 # define FLOAT_MIN __LDBL_MIN__
66 # define FLOAT_MANT_DIG __LDBL_MANT_DIG__
67 # define FLOAT_MAX_EXP __LDBL_MAX_EXP__
68 # define FLOAT_MIN_EXP __LDBL_MIN_EXP__
69 # define ASFLOAT(x) aslongdouble(x)
70 # define TOFLOAT(x) _u128_to_ld(x)
71 typedef long double FLOAT;
72 typedef _u128 UINTFLOAT;
73 #define UINTFLOAT_128
74 # else
75 # define CHECK_LONG() 0
76 # define CHECK_LONG_LONG() 0
77 # define PICOLIBC_FLOAT_PRINTF_SCANF
78 # define FLOAT_MIN __FLT_MIN__
79 # define FLOAT_MANT_DIG __FLT_MANT_DIG__
80 # define FLOAT_MAX_EXP __FLT_MAX_EXP__
81 # define FLOAT_MIN_EXP __FLT_MIN_EXP__
82 # define ASFLOAT(x) _asfloat(x)
83 # define TOFLOAT(x) ((float) (x))
84 # endif
85
86 #define FLT_STREAM const char
87
scanf_getc(const char * s,int * lenp)88 static inline int scanf_getc(const char *s, int *lenp)
89 {
90 int l = *lenp;
91 int c = s[l];
92 *lenp = l + 1;
93 return c;
94 }
95
scanf_ungetc(int c,const char * s,int * lenp)96 static inline void scanf_ungetc(int c, const char *s, int *lenp)
97 {
98 (void) c;
99 (void) s;
100 *lenp = *lenp - 1;
101 }
102
103 #undef EOF
104 #define EOF -1
105
106 #else
107 # define CHECK_WIDTH() (--width != 0)
108 # define CHECK_RANGE(flt)
109 # ifdef PICOLIBC_FLOAT_PRINTF_SCANF
110 # define CHECK_LONG() 0
111 # define CHECK_LONG_LONG() 0
112 # define FLOAT_MANT_DIG __FLT_MANT_DIG__
113 # define FLOAT_MAX_EXP __FLT_MAX_EXP__
114 # define FLOAT_MIN_EXP __FLT_MIN_EXP__
115 # define ASFLOAT(x) _asfloat(x)
116 # define TOFLOAT(x) ((float) (x))
117 # else
118 # if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
119 # define CHECK_LONG() (flags & (FL_LONG|FL_LONGLONG))
120 # define CHECK_LONG_LONG() 0
121 # else
122 # define CHECK_LONG() (flags & FL_LONG)
123 # if defined(_WANT_IO_LONG_DOUBLE)
124 # define CHECK_LONG_LONG() (flags & FL_LONGLONG)
125 # define FLOAT_MANT_DIG __LDBL_MANT_DIG__
126 # define FLOAT_MAX_EXP __LDBL_MAX_EXP__
127 # define FLOAT_MIN_EXP __LDBL_MIN_EXP__
128 # define UINTFLOAT_128
129
130 typedef long double FLOAT;
131 typedef _u128 UINTFLOAT;
132
133 # define ASFLOAT(x) aslongdouble(x)
134 # define TOFLOAT(x) _u128_to_ld(x)
135 # else
136 # define CHECK_LONG_LONG() 0
137 # endif
138 # endif
139 # if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__ || !defined(_WANT_IO_LONG_DOUBLE)
140 # define FLOAT_MANT_DIG __DBL_MANT_DIG__
141 # define FLOAT_MAX_EXP __DBL_MAX_EXP__
142 # define FLOAT_MIN_EXP __DBL_MIN_EXP__
143 # define ASFLOAT(x) _asdouble(x)
144 # define TOFLOAT(x) ((double) (x))
145 # endif
146 # endif
147 #endif
148
149 #ifdef UINTFLOAT_128
150 #define U32_TO_UF(x) to_u128(x)
151 #define U64_TO_UF(x) to_u128(x)
152 #define U128_TO_UF(x) (x)
153 #define UF_TO_U32(x) from_u128(x)
154 #define UF_TO_U64(x) from_u128(x)
155 #define UF_TO_U128(x) (x)
156 #define UF_IS_ZERO(x) _u128_is_zero(x)
157 #define UF_TIMES_BASE(a,b) _u128_times_base(a,b)
158 #define UF_PLUS_DIGIT(a,b) _u128_plus_64(a,b)
159 #define UF_RSHIFT(a,b) _u128_rshift(a,b)
160 #define UF_LSHIFT(a,b) _u128_lshift(a,b)
161 #define UF_LSHIFT_64(a,b) _u128_lshift_64(a,b)
162 #define UF_LT(a,b) _u128_lt(a,b)
163 #define UF_GE(a,b) _u128_ge(a,b)
164 #define UF_OR_64(a,b) _u128_or_64(a,b)
165 #define UF_AND_64(a,b) _u128_and_64(a,b)
166 #define UF_AND(a,b) _u128_and(a,b)
167 #define UF_NOT(a) _u128_not(a)
168 #define UF_OR(a,b) _u128_or(a,b)
169 #else
170 #define U32_TO_UF(x) (x)
171 #define U64_TO_UF(x) (x)
172 #define U128_TO_UF(x) from_u128(x)
173 #define UF_TO_U32(x) (x)
174 #define UF_TO_U64(x) (x)
175 #define UF_TO_U128(x) to_u128(x)
176 #define UF_IS_ZERO(x) ((x) == 0)
177 #define UF_TIMES_BASE(a,b) ((a) * (b))
178 #define UF_PLUS_DIGIT(a,b) ((a) + (b))
179 #define UF_RSHIFT(a,b) ((a) >> (b))
180 #define UF_LSHIFT(a,b) ((a) << (b))
181 #define UF_LSHIFT_64(a,b) ((UINTFLOAT) (a) << (b))
182 #define UF_LT(a,b) ((a) < (b))
183 #define UF_GE(a,b) ((a) >= (b))
184 #define UF_OR_64(a,b) ((a) | (b))
185 #define UF_AND_64(a,b) ((a) & (b))
186 #define UF_AND(a,b) ((a) & (b))
187 #define UF_NOT(a) (~(a))
188 #define UF_OR(a,b) ((a) | (b))
189 #endif
190
191 #ifndef UINTFLOAT_128
192 #include "dtoa_engine.h"
193 #endif
194
195 static unsigned char
conv_flt(FLT_STREAM * stream,int * lenp,width_t width,void * addr,uint16_t flags)196 conv_flt (FLT_STREAM *stream, int *lenp, width_t width, void *addr, uint16_t flags)
197 {
198 UINTFLOAT uint;
199 unsigned int overflow = 0;
200 int uintdigits = 0;
201 FLOAT flt;
202 int i;
203 const char *p;
204 int exp;
205
206 i = scanf_getc (stream, lenp); /* after scanf_ungetc() */
207
208 switch ((unsigned char)i) {
209 case '-':
210 flags |= FL_MINUS;
211 FALLTHROUGH;
212 case '+':
213 if (!CHECK_WIDTH() || (i = scanf_getc (stream, lenp)) < 0)
214 return 0;
215 }
216
217 switch (TOLOWER (i)) {
218 case 'n':
219 p = pstr_an;
220 flt = (FLOAT) NAN;
221 goto operate_pstr;
222
223 case 'i':
224 p = pstr_nfinity;
225 flt = (FLOAT) INFINITY;
226 operate_pstr:
227 {
228 unsigned char c;
229
230 while ((c = *p++) != 0) {
231 if (CHECK_WIDTH()) {
232 if ((i = scanf_getc (stream, lenp)) >= 0) {
233 if ((unsigned char)TOLOWER(i) == c)
234 continue;
235 scanf_ungetc (i, stream, lenp);
236 }
237 if (p == pstr_nfinity + 3)
238 break;
239 return 0;
240 }
241 }
242 }
243 break;
244
245 default:
246 exp = 0;
247 uint = U32_TO_UF(0);
248 #define uintdigitsmax_10_float 8
249 #define uintdigitsmax_10_double 16
250 #define uintdigitsmax_10_long_double 32
251 #define uintdigitsmax_16_float 7
252 #define uintdigitsmax_16_double 15
253 #define uintdigitsmax_16_long_double 30
254
255 #ifdef _WANT_IO_C99_FORMATS
256 int base = 10;
257 #else
258 #define base 10
259 #endif
260
261 #define uintdigitsmax \
262 ((base) == 10 ? \
263 (CHECK_LONG() ? \
264 uintdigitsmax_10_double : \
265 (CHECK_LONG_LONG() ? uintdigitsmax_10_long_double : \
266 uintdigitsmax_10_float)) : \
267 (CHECK_LONG() ? \
268 uintdigitsmax_16_double : \
269 (CHECK_LONG_LONG() ? uintdigitsmax_16_long_double : \
270 uintdigitsmax_16_float)))
271
272 do {
273
274 unsigned char c;
275
276 #ifdef _WANT_IO_C99_FORMATS
277 if ((flags & FL_FHEX) && (c = TOLOWER(i) - 'a') <= 5)
278 c += 10;
279 else
280 #endif
281 c = i - '0';
282
283 if (c < base) {
284 flags |= FL_ANY;
285 if (flags & FL_OVFL) {
286 overflow |= (c != 0);
287 if (!(flags & FL_DOT))
288 exp += 1;
289 } else {
290 if (flags & FL_DOT)
291 exp -= 1;
292 uint = UF_PLUS_DIGIT(UF_TIMES_BASE(uint, base), c);
293 if (!UF_IS_ZERO(uint)) {
294 uintdigits++;
295 if (uintdigits > uintdigitsmax)
296 flags |= FL_OVFL;
297 }
298 }
299
300 } else if (c == (('.'-'0') & 0xff) && !(flags & FL_DOT)) {
301 flags |= FL_DOT;
302 #ifdef _WANT_IO_C99_FORMATS
303 } else if (TOLOWER(i) == 'x' && (flags & FL_ANY) && UF_IS_ZERO(uint)) {
304 flags |= FL_FHEX;
305 base = 16;
306 #endif
307 } else {
308 break;
309 }
310 } while (CHECK_WIDTH() && (i = scanf_getc (stream, lenp)) >= 0);
311
312 if (!(flags & FL_ANY))
313 return 0;
314
315 #ifdef _WANT_IO_C99_FORMATS
316 int exp_match = (flags & FL_FHEX) ? 'p' : 'e';
317 #else
318 #define exp_match 'e'
319 #endif
320 if (TOLOWER(i) == exp_match)
321 {
322 int esign, edig;
323 int expacc;
324
325 if (!CHECK_WIDTH())
326 goto no_exp;
327
328 esign = scanf_getc (stream, lenp);
329
330 switch ((unsigned char)esign) {
331 case '-':
332 flags |= FL_MEXP;
333 FALLTHROUGH;
334 case '+':
335 if (!CHECK_WIDTH()) {
336 scanf_ungetc(esign, stream, lenp);
337 goto no_exp;
338 }
339 edig = scanf_getc (stream, lenp); /* test EOF will below */
340 break;
341 default:
342 edig = esign;
343 esign = EOF;
344 break;
345 }
346
347 if (!ISDIGIT (edig))
348 {
349 scanf_ungetc(edig, stream, lenp);
350 if (esign != EOF)
351 scanf_ungetc(esign, stream, lenp);
352 goto no_exp;
353 }
354
355 i = edig;
356 expacc = 0;
357 #define MAX_POSSIBLE_EXP (FLOAT_MAX_EXP + FLOAT_MANT_DIG * 4)
358 do {
359 if (expacc < MAX_POSSIBLE_EXP)
360 expacc = expacc * 10 + (i - '0');
361 } while (CHECK_WIDTH() && ISDIGIT (i = scanf_getc(stream, lenp)));
362 if (flags & FL_MEXP)
363 expacc = -expacc;
364 #ifdef _WANT_IO_C99_FORMATS
365 if (flags & FL_FHEX)
366 exp *= 4;
367 #endif
368 exp += expacc;
369 }
370
371 no_exp:
372 if (width)
373 scanf_ungetc (i, stream, lenp);
374
375 if (UF_IS_ZERO(uint)) {
376 flt = (FLOAT) 0;
377 break;
378 }
379
380 #ifdef _WANT_IO_C99_FORMATS
381 if (flags & FL_FHEX)
382 {
383 int sig_bits;
384 int min_exp;
385
386 if (CHECK_LONG()) {
387 sig_bits = __DBL_MANT_DIG__;
388 min_exp = __DBL_MIN_EXP__ - 1;
389 } else if (CHECK_LONG_LONG()) {
390 sig_bits = __LDBL_MANT_DIG__;
391 min_exp = __LDBL_MIN_EXP__ - 1;
392 } else {
393 sig_bits = __FLT_MANT_DIG__;
394 min_exp = __FLT_MIN_EXP__ - 1;
395 }
396
397 /* We're using two guard bits, one for the
398 * 'half' value and the second to indicate whether
399 * there is any non-zero value beyond that
400 */
401 exp += (sig_bits + 2 - 1);
402
403 /* Make significand larger than 1.0 */
404 while (UF_LT(uint, UF_LSHIFT_64(1, (sig_bits + 2 - 1)))) {
405 uint = UF_LSHIFT(uint, 1);
406 exp--;
407 }
408
409 /* Now shift right until the exponent is in range and the
410 * value is less than 2.0. Capture any value > 0.5 in the
411 * LSB of uint. This may generate a denorm.
412 */
413 while (UF_GE(uint, UF_LSHIFT_64(1, (sig_bits + 2))) || exp < min_exp) {
414 /* squash extra bits into the second guard bit */
415 uint = UF_OR_64(UF_RSHIFT(uint, 1), UF_AND_64(uint, 1));
416 exp++;
417 }
418
419 /* Mix in the overflow bit computed while scanning the
420 * string
421 */
422 uint = UF_OR_64(uint, overflow);
423
424 /* Round even */
425 if (UF_AND_64(uint, 3) == 3 || UF_AND_64(uint, 6) == 6) {
426 uint = UF_PLUS_DIGIT(uint, 4);
427 if (UF_GE(uint, UF_LSHIFT_64(1, FLOAT_MANT_DIG + 2))) {
428 uint = UF_RSHIFT(uint, 1);
429 exp++;
430 }
431 }
432
433 /* remove guard bits */
434 uint = UF_RSHIFT(uint, 2);
435
436 /* align from target to FLOAT */
437 uint = UF_LSHIFT(uint, FLOAT_MANT_DIG - sig_bits);
438
439 if (min_exp != (FLOAT_MIN_EXP - 1)) {
440
441 /* Convert from target denorm to FLOAT value */
442 while (UF_LT(uint, UF_LSHIFT_64(1, (FLOAT_MANT_DIG - 1))) && exp > FLOAT_MIN_EXP) {
443 uint = UF_LSHIFT(uint, 1);
444 exp--;
445 }
446 }
447
448 if (exp >= FLOAT_MAX_EXP) {
449 flt = (FLOAT) INFINITY;
450 } else {
451 #if !defined(UINTFLOAT_128) || __LDBL_IS_IEC_60559__ != 0
452 if (UF_LT(uint, UF_LSHIFT_64(1, (FLOAT_MANT_DIG-1)))) {
453 exp = 0;
454 } else {
455 exp += (FLOAT_MAX_EXP - 1);
456 #if defined(UINTFLOAT_128) && (defined(__x86_64__) || defined(__i386__))
457 /*
458 * Intel 80-bit format is weird -- there's an
459 * integer bit so denorms can have the 'real'
460 * exponent value. That means we don't mask off
461 * the integer bit
462 */
463 #define EXP_SHIFT FLOAT_MANT_DIG
464 #else
465 uint = UF_AND(uint, UF_NOT(UF_LSHIFT_64(1, (FLOAT_MANT_DIG-1))));
466 #define EXP_SHIFT (FLOAT_MANT_DIG-1)
467 #endif
468 }
469 uint = UF_OR(uint, UF_LSHIFT_64(exp, EXP_SHIFT));
470 flt = ASFLOAT(uint);
471 #else /* !defined(UINTFLOAT_128) || __LDBL_IS_IEC_60559__ != 0 */
472 flt = scalbnl(TOFLOAT(uint), exp - (FLOAT_MANT_DIG-1));
473 #endif
474 }
475 }
476 else
477 #endif
478 {
479 if (CHECK_LONG())
480 {
481 if (uintdigits + exp <= -324) {
482 // Number is less than 1e-324, which should be rounded down to 0; return +/-0.0.
483 flt = (FLOAT) 0.0;
484 } else if (uintdigits + exp >= 310) {
485 // Number is larger than 1e+309, which should be rounded to +/-Infinity.
486 flt = (FLOAT) INFINITY;
487 } else {
488 flt = (FLOAT) __atod_engine(UF_TO_U64(uint), exp);
489 }
490 }
491 else if (CHECK_LONG_LONG())
492 {
493 flt = (FLOAT) __atold_engine(UF_TO_U128(uint), exp);
494 }
495 else
496 {
497 if (uintdigits + exp <= -46) {
498 // Number is less than 1e-46, which should be rounded down to 0; return 0.0.
499 flt = (FLOAT) 0.0f;
500 } else if (uintdigits + exp >= 40) {
501 // Number is larger than 1e+39, which should be rounded to +/-Infinity.
502 flt = (FLOAT) INFINITY;
503 } else {
504 flt = (FLOAT) __atof_engine(UF_TO_U32(uint), exp);
505 }
506 }
507 }
508 CHECK_RANGE(flt)
509 break;
510 } /* switch */
511
512 if (flags & FL_MINUS)
513 flt = -flt;
514 if (addr) {
515 if (CHECK_LONG())
516 *((double *) addr) = (double) flt;
517 else if (CHECK_LONG_LONG())
518 *((long double *) addr) = (long double) flt;
519 else
520 *((float *) addr) = (float) flt;
521 }
522 return 1;
523 }
524
525 #undef base
526