OSDN Git Service

Kill a warning. Change __wcstofpmax to __wcstofpmax_l where appropiate
[uclinux-h8/uClibc.git] / libc / stdlib / strtod.c
1 /*
2  * Copyright (C) 2000-2005     Manuel Novoa III
3  *
4  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
5  */
6
7 /* Notes:
8  *
9  * The primary objective of this implementation was minimal size and
10  * portablility, while providing robustness and resonable accuracy.
11  *
12  * This implementation depends on IEEE floating point behavior and expects
13  * to be able to generate +/- infinity as a result.
14  *
15  * There are a number of compile-time options below.
16  */
17
18 /* July 27, 2003
19  *
20  * General cleanup and some minor size optimizations.
21  * Change implementation to support __strtofpmax() rather than strtod().
22  *   Now all the strto{floating pt}() funcs are implemented in terms of
23  *   of the internal __strtofpmax() function.
24  * Support "nan", "inf", and "infinity" strings (case-insensitive).
25  * Support hexadecimal floating point notation.
26  * Support wchar variants.
27  * Support xlocale variants.
28  *
29  * TODO:
30  *
31  * Consider accumulating blocks of digits in longs to save floating pt mults.
32  *   This would likely be much better on anything that only supported floats
33  *   where DECIMAL_DIG == 9.  Actually, if floats have FLT_MAX_10_EXP == 38,
34  *   we could calculate almost all the exponent multipliers (p_base) in
35  *   long arithmetic as well.
36  */
37
38 /**********************************************************************/
39 /*                                                      OPTIONS                                                                   */
40 /**********************************************************************/
41
42 /* Defined if we want to recognize "nan", "inf", and "infinity". (C99) */
43 #define _STRTOD_NAN_INF_STRINGS  1
44
45 /* Defined if we want support hexadecimal floating point notation. (C99) */
46 /* Note!  Now controlled by uClibc configuration.  See below. */
47 #define _STRTOD_HEXADECIMAL_FLOATS 1
48
49 /* Defined if we want to scale with a O(log2(exp)) multiplications.
50  * This is generally a good thing to do unless you are really tight
51  * on space and do not expect to convert values of large magnitude. */
52
53 #define _STRTOD_LOG_SCALING       1
54
55 /* WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!!
56  *
57  * Clearing any of the options below this point is not advised (or tested).
58  *
59  * WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!!   WARNING!!! */
60
61 /* Defined if we want strtod to set errno appropriately. */
62 /* NOTE: Implies all options below. */
63 #define _STRTOD_ERRNO                   1
64
65 /* Defined if we want support for the endptr arg. */
66 /* Implied by _STRTOD_ERRNO. */
67 #define _STRTOD_ENDPTR             1
68
69 /* Defined if we want to prevent overflow in accumulating the exponent. */
70 /* Implied by _STRTOD_ERRNO. */
71 #define _STRTOD_RESTRICT_EXP     1
72
73 /* Defined if we want to process mantissa digits more intelligently. */
74 /* Implied by _STRTOD_ERRNO. */
75 #define _STRTOD_RESTRICT_DIGITS  1
76
77 /* Defined if we want to skip scaling 0 for the exponent. */
78 /* Implied by _STRTOD_ERRNO. */
79 #define _STRTOD_ZERO_CHECK         1
80
81 /**********************************************************************/
82 /* Don't change anything that follows.                                                                     */
83 /**********************************************************************/
84
85 #ifdef _STRTOD_ERRNO
86 #undef _STRTOD_ENDPTR
87 #undef _STRTOD_RESTRICT_EXP
88 #undef _STRTOD_RESTRICT_DIGITS
89 #undef _STRTOD_ZERO_CHECK
90 #define _STRTOD_ENDPTR             1
91 #define _STRTOD_RESTRICT_EXP     1
92 #define _STRTOD_RESTRICT_DIGITS  1
93 #define _STRTOD_ZERO_CHECK         1
94 #endif
95
96 /**********************************************************************/
97
98 #define _ISOC99_SOURCE 1
99 #define _GNU_SOURCE
100 #include <stdlib.h>
101 #include <string.h>
102 #include <ctype.h>
103 #include <errno.h>
104 #include <limits.h>
105 #include <float.h>
106 #include <bits/uClibc_fpmax.h>
107
108 #include <locale.h>
109
110 #ifdef __UCLIBC_HAS_WCHAR__
111
112 #include <wchar.h>
113 #include <wctype.h>
114 #include <bits/uClibc_uwchar.h>
115
116 #endif
117
118 #ifdef __UCLIBC_HAS_XLOCALE__
119 #include <xlocale.h>
120 #endif /* __UCLIBC_HAS_XLOCALE__ */
121
122
123
124 /* Handle _STRTOD_HEXADECIMAL_FLOATS via uClibc config now. */
125 #undef _STRTOD_HEXADECIMAL_FLOATS
126 #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
127 #define _STRTOD_HEXADECIMAL_FLOATS 1
128 #endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
129
130 /**********************************************************************/
131
132 #undef _STRTOD_FPMAX
133
134 #if FPMAX_TYPE == 3
135
136 #define NEED_STRTOLD_WRAPPER
137 #define NEED_STRTOD_WRAPPER
138 #define NEED_STRTOF_WRAPPER
139
140 #elif FPMAX_TYPE == 2
141
142 #define NEED_STRTOD_WRAPPER
143 #define NEED_STRTOF_WRAPPER
144
145 #elif FPMAX_TYPE == 1
146
147 #define NEED_STRTOF_WRAPPER
148
149 #else
150
151 #error unknown FPMAX_TYPE!
152
153 #endif
154
155 extern void __fp_range_check(__fpmax_t y, __fpmax_t x);
156
157 /**********************************************************************/
158
159 #ifdef _STRTOD_RESTRICT_DIGITS
160 #define EXP_DENORM_ADJUST DECIMAL_DIG
161 #define MAX_ALLOWED_EXP (DECIMAL_DIG  + EXP_DENORM_ADJUST - FPMAX_MIN_10_EXP)
162
163 #if MAX_ALLOWED_EXP > INT_MAX
164 #error size assumption violated for MAX_ALLOWED_EXP
165 #endif
166 #else
167 /* We want some excess if we're not restricting mantissa digits. */
168 #define MAX_ALLOWED_EXP ((20 - FPMAX_MIN_10_EXP) * 2)
169 #endif
170
171
172 #if defined(_STRTOD_RESTRICT_DIGITS) || defined(_STRTOD_ENDPTR) || defined(_STRTOD_HEXADECIMAL_FLOATS)
173 #undef _STRTOD_NEED_NUM_DIGITS
174 #define _STRTOD_NEED_NUM_DIGITS 1
175 #endif
176
177 /**********************************************************************/
178 #if defined(L___strtofpmax) || defined(L___strtofpmax_l) || defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
179
180 #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
181
182 #define __strtofpmax    __wcstofpmax
183 #define __strtofpmax_l  __wcstofpmax_l
184
185 #define Wchar wchar_t
186 #ifdef __UCLIBC_DO_XLOCALE
187 #define ISSPACE(C) iswspace_l((C), locale_arg)
188 #else
189 #define ISSPACE(C) iswspace((C))
190 #endif
191
192 #else  /* defined(L___wcstofpmax) || defined(L___wcstofpmax_l) */
193
194 #define Wchar char
195 #ifdef __UCLIBC_DO_XLOCALE
196 #define ISSPACE(C) isspace_l((C), locale_arg)
197 #else
198 #define ISSPACE(C) isspace((C))
199 #endif
200
201 #endif /* defined(L___wcstofpmax) || defined(L___wcstofpmax_l) */
202
203
204 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
205
206 __fpmax_t __strtofpmax(const Wchar *str, Wchar **endptr, int exponent_power)
207 {
208         return __strtofpmax_l(str, endptr, exponent_power, __UCLIBC_CURLOCALE);
209 }
210
211 #else  /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
212
213 __fpmax_t __XL_NPP(__strtofpmax)(const Wchar *str, Wchar **endptr, int exponent_power
214                                                                  __LOCALE_PARAM )
215 {
216         __fpmax_t number;
217         __fpmax_t p_base = 10;                  /* Adjusted to 16 in the hex case. */
218         Wchar *pos0;
219 #ifdef _STRTOD_ENDPTR
220         Wchar *pos1;
221 #endif
222         Wchar *pos = (Wchar *) str;
223         int exponent_temp;
224         int negative; /* A flag for the number, a multiplier for the exponent. */
225 #ifdef _STRTOD_NEED_NUM_DIGITS
226         int num_digits;
227 #endif
228 #ifdef __UCLIBC_HAS_LOCALE__
229 #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
230         wchar_t decpt_wc = __LOCALE_PTR->decimal_point;
231 #else
232         const char *decpt = __LOCALE_PTR->decimal_point;
233         int decpt_len = __LOCALE_PTR->decimal_point_len;
234 #endif
235 #endif
236
237 #ifdef _STRTOD_HEXADECIMAL_FLOATS
238         Wchar expchar = 'e';
239         Wchar *poshex = NULL;
240         __uint16_t is_mask = _ISdigit;
241 #define EXPCHAR         expchar
242 #define IS_X_DIGIT(C) __isctype((C), is_mask)
243 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
244 #define EXPCHAR         'e'
245 #define IS_X_DIGIT(C) isdigit((C))
246 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
247
248         while (ISSPACE(*pos)) {         /* Skip leading whitespace. */
249                 ++pos;
250         }
251
252         negative = 0;
253         switch(*pos) {                          /* Handle optional sign. */
254                 case '-': negative = 1; /* Fall through to increment position. */
255                 case '+': ++pos;
256         }
257
258 #ifdef _STRTOD_HEXADECIMAL_FLOATS
259         if ((*pos == '0') && (((pos[1])|0x20) == 'x')) {
260                 poshex = ++pos;                 /* Save position of 'x' in case no digits */
261                 ++pos;                                  /*   and advance past it.  */
262                 is_mask = _ISxdigit;    /* Used by IS_X_DIGIT. */
263                 expchar = 'p';                  /* Adjust exponent char. */
264                 p_base = 16;                    /* Adjust base multiplier. */
265         }
266 #endif
267
268         number = 0.;
269 #ifdef _STRTOD_NEED_NUM_DIGITS
270         num_digits = -1;
271 #endif
272 /*      exponent_power = 0; */
273         pos0 = NULL;
274
275  LOOP:
276         while (IS_X_DIGIT(*pos)) {      /* Process string of (hex) digits. */
277 #ifdef _STRTOD_RESTRICT_DIGITS
278                 if (num_digits < 0) {   /* First time through? */
279                         ++num_digits;           /* We've now seen a digit. */
280                 }
281                 if (num_digits || (*pos != '0')) { /* Had/have nonzero. */
282                         ++num_digits;
283                         if (num_digits <= DECIMAL_DIG) { /* Is digit significant? */
284 #ifdef _STRTOD_HEXADECIMAL_FLOATS
285                                 number = number * p_base
286                                         + (isdigit(*pos)
287                                            ? (*pos - '0')
288                                            : (((*pos)|0x20) - ('a' - 10)));
289 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
290                                 number = number * p_base + (*pos - '0');
291 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
292                         }
293                 }
294 #else  /* _STRTOD_RESTRICT_DIGITS */
295 #ifdef _STRTOD_NEED_NUM_DIGITS
296                 ++num_digits;
297 #endif
298 #ifdef _STRTOD_HEXADECIMAL_FLOATS
299                 number = number * p_base
300                         + (isdigit(*pos)
301                            ? (*pos - '0')
302                            : (((*pos)|0x20) - ('a' - 10)));
303 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
304                 number = number * p_base + (*pos - '0');
305 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
306 #endif /* _STRTOD_RESTRICT_DIGITS */
307                 ++pos;
308         }
309
310 #ifdef __UCLIBC_HAS_LOCALE__
311 #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
312         if (!pos0 && (*pos == decpt_wc)) { /* First decimal point? */
313                 pos0 = ++pos;
314                 goto LOOP;
315         }
316 #else
317         if (!pos0 && !memcmp(pos, decpt, decpt_len)) { /* First decimal point? */
318                 pos0 = (pos += decpt_len);
319                 goto LOOP;
320         }
321 #endif
322 #else  /* __UCLIBC_HAS_LOCALE__ */
323         if ((*pos == '.') && !pos0) { /* First decimal point? */
324                 pos0 = ++pos;                   /* Save position of decimal point */
325                 goto LOOP;                              /*   and process rest of digits. */
326         }
327 #endif /* __UCLIBC_HAS_LOCALE__ */
328
329 #ifdef _STRTOD_NEED_NUM_DIGITS
330         if (num_digits<0) {                     /* Must have at least one digit. */
331 #ifdef _STRTOD_HEXADECIMAL_FLOATS
332                 if (poshex) {                   /* Back up to '0' in '0x' prefix. */
333                         pos = poshex;
334                         goto DONE;
335                 }
336 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
337
338 #ifdef _STRTOD_NAN_INF_STRINGS
339                 if (!pos0) {                    /* No decimal point, so check for inf/nan. */
340                         /* Note: nan is the first string so 'number = i/0.;' works. */
341                         static const char nan_inf_str[] = "\05nan\0\012infinity\0\05inf\0";
342                         int i = 0;
343
344 #ifdef __UCLIBC_HAS_LOCALE__
345                         /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/
346 #undef _tolower
347 #define _tolower(C)     ((C)|0x20)
348 #endif /* __UCLIBC_HAS_LOCALE__ */
349
350                         do {
351                                 /* Unfortunately, we have no memcasecmp(). */
352                                 int j = 0;
353                                 while (_tolower(pos[j]) == nan_inf_str[i+1+j]) {
354                                         ++j;
355                                         if (!nan_inf_str[i+1+j]) {
356                                                 number = i / 0.;
357                                                 if (negative) { /* Correct for sign. */
358                                                         number = -number;
359                                                 }
360                                                 pos += nan_inf_str[i] - 2;
361                                                 goto DONE;
362                                         }
363                                 }
364                                 i += nan_inf_str[i];
365                         } while (nan_inf_str[i]);
366                 }
367
368 #endif /* STRTOD_NAN_INF_STRINGS */
369 #ifdef _STRTOD_ENDPTR
370                 pos = (Wchar *) str;
371 #endif
372                 goto DONE;
373         }
374 #endif /* _STRTOD_NEED_NUM_DIGITS */
375
376 #ifdef _STRTOD_RESTRICT_DIGITS
377         if (num_digits > DECIMAL_DIG) { /* Adjust exponent for skipped digits. */
378                 exponent_power += num_digits - DECIMAL_DIG;
379         }
380 #endif
381
382         if (pos0) {
383                 exponent_power += pos0 - pos; /* Adjust exponent for decimal point. */
384         }
385
386 #ifdef _STRTOD_HEXADECIMAL_FLOATS
387         if (poshex) {
388                 exponent_power *= 4;    /* Above is 2**4, but below is 2. */
389                 p_base = 2;
390         }
391 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
392
393         if (negative) {                         /* Correct for sign. */
394                 number = -number;
395         }
396
397         /* process an exponent string */
398         if (((*pos)|0x20) == EXPCHAR) {
399 #ifdef _STRTOD_ENDPTR
400                 pos1 = pos;
401 #endif
402                 negative = 1;
403                 switch(*++pos) {                /* Handle optional sign. */
404                         case '-': negative = -1; /* Fall through to increment pos. */
405                         case '+': ++pos;
406                 }
407
408                 pos0 = pos;
409                 exponent_temp = 0;
410                 while (isdigit(*pos)) { /* Process string of digits. */
411 #ifdef _STRTOD_RESTRICT_EXP
412                         if (exponent_temp < MAX_ALLOWED_EXP) { /* Avoid overflow. */
413                                 exponent_temp = exponent_temp * 10 + (*pos - '0');
414                         }
415 #else
416                         exponent_temp = exponent_temp * 10 + (*pos - '0');
417 #endif
418                         ++pos;
419                 }
420
421 #ifdef _STRTOD_ENDPTR
422                 if (pos == pos0) {      /* No digits? */
423                         pos = pos1;             /* Back up to {e|E}/{p|P}. */
424                 } /* else */
425 #endif
426
427                 exponent_power += negative * exponent_temp;
428         }
429
430 #ifdef _STRTOD_ZERO_CHECK
431         if (number == 0.) {
432                 goto DONE;
433         }
434 #endif
435
436         /* scale the result */
437 #ifdef _STRTOD_LOG_SCALING
438         exponent_temp = exponent_power;
439
440         if (exponent_temp < 0) {
441                 exponent_temp = -exponent_temp;
442         }
443
444         while (exponent_temp) {
445                 if (exponent_temp & 1) {
446                         if (exponent_power < 0) {
447                                 /* Warning... caluclating a factor for the exponent and
448                                  * then dividing could easily be faster.  But doing so
449                                  * might cause problems when dealing with denormals. */
450                                 number /= p_base;
451                         } else {
452                                 number *= p_base;
453                         }
454                 }
455                 exponent_temp >>= 1;
456                 p_base *= p_base;
457         }
458
459 #else  /* _STRTOD_LOG_SCALING */
460         while (exponent_power) {
461                 if (exponent_power < 0) {
462                         number /= p_base;
463                         exponent_power++;
464                 } else {
465                         number *= p_base;
466                         exponent_power--;
467                 }
468         }
469 #endif /* _STRTOD_LOG_SCALING */
470
471 #ifdef _STRTOD_ERRNO
472         if (__FPMAX_ZERO_OR_INF_CHECK(number)) {
473                 __set_errno(ERANGE);
474         }
475 #endif
476
477  DONE:
478 #ifdef _STRTOD_ENDPTR
479         if (endptr) {
480                 *endptr = pos;
481         }
482 #endif
483
484         return number;
485 }
486
487 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
488
489 #endif
490 /**********************************************************************/
491 #ifdef L___fp_range_check
492 #if defined(NEED_STRTOF_WRAPPER) || defined(NEED_STRTOD_WRAPPER)
493
494 extern void __fp_range_check(__fpmax_t y, __fpmax_t x)
495 {
496         if (__FPMAX_ZERO_OR_INF_CHECK(y) /* y is 0 or +/- infinity */
497                 && (y != 0)     /* y is not 0 (could have x>0, y==0 if underflow) */
498                 && !__FPMAX_ZERO_OR_INF_CHECK(x) /* x is not 0 or +/- infinity */
499                 ) {
500                 __set_errno(ERANGE);    /* Then x is not in y's range. */
501         }
502 }
503
504 #endif
505 #endif
506 /**********************************************************************/
507 #if defined(L_strtof) || defined(L_strtof_l) || defined(L_wcstof) || defined(L_wcstof_l)
508 #if defined(NEED_STRTOF_WRAPPER)
509
510 #if defined(L_wcstof) || defined(L_wcstof_l)
511 #define strtof           wcstof
512 #define strtof_l         wcstof_l
513 #define __strtof         __wcstof
514 #define __strtof_l       __wcstof_l
515 #define __strtofpmax     __wcstofpmax
516 #define __strtofpmax_l   __wcstofpmax_l
517 #define Wchar wchar_t
518 #else
519 #define Wchar char
520 #endif
521
522
523 float __XL(strtof)(const Wchar *str, Wchar **endptr   __LOCALE_PARAM )
524 {
525 #if FPMAX_TYPE == 1
526         return __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
527 #else
528         __fpmax_t x;
529         float y;
530
531         x = __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
532         y = (float) x;
533
534         __fp_range_check(y, x);
535
536         return y;
537 #endif
538 }
539
540 __XL_ALIAS(strtof)
541
542 #endif
543 #endif
544 /**********************************************************************/
545 #if defined(L_strtod) || defined(L_strtod_l) || defined(L_wcstod) || defined(L_wcstod_l)
546 #if defined(NEED_STRTOD_WRAPPER)
547
548 #if defined(L_wcstod) || defined(L_wcstod_l)
549 #define strtod           wcstod
550 #define strtod_l         wcstod_l
551 #define __strtod         __wcstod
552 #define __strtod_l       __wcstod_l
553 #define __strtofpmax     __wcstofpmax
554 #define __strtofpmax_l   __wcstofpmax_l
555 #define Wchar wchar_t
556 #else
557 #define Wchar char
558 #endif
559
560 double __XL(strtod)(const Wchar *__restrict str,
561                                         Wchar **__restrict endptr   __LOCALE_PARAM )
562 {
563 #if FPMAX_TYPE == 2
564         return __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
565 #else
566         __fpmax_t x;
567         double y;
568
569         x = __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
570         y = (double) x;
571
572         __fp_range_check(y, x);
573
574         return y;
575 #endif
576 }
577
578 __XL_ALIAS(strtod)
579
580 #endif
581 #endif
582 /**********************************************************************/
583 #if defined(L_strtold) || defined(L_strtold_l) || defined(L_wcstold) || defined(L_wcstold_l)
584 #if defined(NEED_STRTOLD_WRAPPER)
585
586 #if defined(L_wcstold) || defined(L_wcstold_l)
587 #define strtold           wcstold
588 #define strtold_l         wcstold_l
589 #define __strtold         __wcstold
590 #define __strtold_l       __wcstold_l
591 #define __strtofpmax     __wcstofpmax
592 #define __strtofpmax_l   __wcstofpmax_l
593 #define Wchar wchar_t
594 #else
595 #define Wchar char
596 #endif
597
598 long double __XL(strtold)(const Wchar *str, Wchar **endptr   __LOCALE_PARAM )
599 {
600 #if FPMAX_TYPE == 3
601         return __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
602 #else
603         __fpmax_t x;
604         long double y;
605
606         x = __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
607         y = (long double) x;
608
609         __fp_range_check(y, x);
610
611         return y;
612 #endif
613 }
614
615 __XL_ALIAS(strtold)
616
617 #endif
618 #endif
619 /**********************************************************************/