OSDN Git Service

stdlib.c, _strtod.c, stdlib.h: remove unused hidden functions
[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 #include <stdlib.h>
100 #include <string.h>
101 #include <ctype.h>
102 #include <errno.h>
103 #include <limits.h>
104 #include <float.h>
105 #include <bits/uClibc_fpmax.h>
106
107 #include <locale.h>
108
109 #ifdef __UCLIBC_HAS_WCHAR__
110 # include <wchar.h>
111 # include <wctype.h>
112 # include <bits/uClibc_uwchar.h>
113 #endif
114
115 #ifdef __UCLIBC_HAS_XLOCALE__
116 # include <xlocale.h>
117 #endif
118
119 /* Handle _STRTOD_HEXADECIMAL_FLOATS via uClibc config now. */
120 #undef _STRTOD_HEXADECIMAL_FLOATS
121 #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
122 # define _STRTOD_HEXADECIMAL_FLOATS 1
123 #endif
124
125 /**********************************************************************/
126
127 #undef _STRTOD_FPMAX
128
129 #if FPMAX_TYPE == 3
130
131 #define NEED_STRTOLD_WRAPPER
132 #define NEED_STRTOD_WRAPPER
133 #define NEED_STRTOF_WRAPPER
134
135 #elif FPMAX_TYPE == 2
136
137 #define NEED_STRTOD_WRAPPER
138 #define NEED_STRTOF_WRAPPER
139
140 #elif FPMAX_TYPE == 1
141
142 #define NEED_STRTOF_WRAPPER
143
144 #else
145
146 #error unknown FPMAX_TYPE!
147
148 #endif
149
150 extern void __fp_range_check(__fpmax_t y, __fpmax_t x) attribute_hidden;
151
152 /**********************************************************************/
153
154 #ifdef _STRTOD_RESTRICT_DIGITS
155 #define EXP_DENORM_ADJUST DECIMAL_DIG
156 #define MAX_ALLOWED_EXP (DECIMAL_DIG  + EXP_DENORM_ADJUST - FPMAX_MIN_10_EXP)
157
158 #if MAX_ALLOWED_EXP > INT_MAX
159 #error size assumption violated for MAX_ALLOWED_EXP
160 #endif
161 #else
162 /* We want some excess if we're not restricting mantissa digits. */
163 #define MAX_ALLOWED_EXP ((20 - FPMAX_MIN_10_EXP) * 2)
164 #endif
165
166
167 #if defined(_STRTOD_RESTRICT_DIGITS) || defined(_STRTOD_ENDPTR) || defined(_STRTOD_HEXADECIMAL_FLOATS)
168 #undef _STRTOD_NEED_NUM_DIGITS
169 #define _STRTOD_NEED_NUM_DIGITS 1
170 #endif
171
172 /**********************************************************************/
173 #if defined(L___strtofpmax) || defined(L___strtofpmax_l) || defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
174
175 #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
176
177 #define __strtofpmax    __wcstofpmax
178 #define __strtofpmax_l  __wcstofpmax_l
179
180 #define Wchar wchar_t
181 #ifdef __UCLIBC_DO_XLOCALE
182 #define ISSPACE(C) iswspace_l((C), locale_arg)
183 #else
184 #define ISSPACE(C) iswspace((C))
185 #endif
186
187 #else  /* defined(L___wcstofpmax) || defined(L___wcstofpmax_l) */
188
189 #define Wchar char
190 #ifdef __UCLIBC_DO_XLOCALE
191 #define ISSPACE(C) isspace_l((C), locale_arg)
192 #else
193 #define ISSPACE(C) isspace((C))
194 #endif
195
196 #endif /* defined(L___wcstofpmax) || defined(L___wcstofpmax_l) */
197
198
199 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
200
201 __fpmax_t attribute_hidden __strtofpmax(const Wchar *str, Wchar **endptr, int exponent_power)
202 {
203         return __strtofpmax_l(str, endptr, exponent_power, __UCLIBC_CURLOCALE);
204 }
205
206 #else  /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
207
208
209 __fpmax_t attribute_hidden __XL_NPP(__strtofpmax)(const Wchar *str, Wchar **endptr, int exponent_power
210                                                                  __LOCALE_PARAM )
211 {
212         __fpmax_t number;
213         __fpmax_t p_base = 10;                  /* Adjusted to 16 in the hex case. */
214         Wchar *pos0;
215 #ifdef _STRTOD_ENDPTR
216         Wchar *pos1;
217 #endif
218         Wchar *pos = (Wchar *) str;
219         int exponent_temp;
220         int negative; /* A flag for the number, a multiplier for the exponent. */
221 #ifdef _STRTOD_NEED_NUM_DIGITS
222         int num_digits;
223 #endif
224 #ifdef __UCLIBC_HAS_LOCALE__
225 #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
226         wchar_t decpt_wc = __LOCALE_PTR->decimal_point_wc;
227 #else
228         const char *decpt = __LOCALE_PTR->decimal_point;
229         int decpt_len = __LOCALE_PTR->decimal_point_len;
230 #endif
231 #endif
232
233 #ifdef _STRTOD_HEXADECIMAL_FLOATS
234         Wchar expchar = 'e';
235         Wchar *poshex = NULL;
236         __uint16_t is_mask = _ISdigit;
237 #define EXPCHAR         expchar
238 #define IS_X_DIGIT(C) __isctype((C), is_mask)
239 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
240 #define EXPCHAR         'e'
241 #define IS_X_DIGIT(C) isdigit((C))
242 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
243
244         while (ISSPACE(*pos)) {         /* Skip leading whitespace. */
245                 ++pos;
246         }
247
248         negative = 0;
249         switch(*pos) {                          /* Handle optional sign. */
250                 case '-': negative = 1; /* Fall through to increment position. */
251                 case '+': ++pos;
252         }
253
254 #ifdef _STRTOD_HEXADECIMAL_FLOATS
255         if ((*pos == '0') && (((pos[1])|0x20) == 'x')) {
256                 poshex = ++pos;                 /* Save position of 'x' in case no digits */
257                 ++pos;                                  /*   and advance past it.  */
258                 is_mask = _ISxdigit;    /* Used by IS_X_DIGIT. */
259                 expchar = 'p';                  /* Adjust exponent char. */
260                 p_base = 16;                    /* Adjust base multiplier. */
261         }
262 #endif
263
264         number = 0.;
265 #ifdef _STRTOD_NEED_NUM_DIGITS
266         num_digits = -1;
267 #endif
268 /*      exponent_power = 0; */
269         pos0 = NULL;
270
271  LOOP:
272         while (IS_X_DIGIT(*pos)) {      /* Process string of (hex) digits. */
273 #ifdef _STRTOD_RESTRICT_DIGITS
274                 if (num_digits < 0) {   /* First time through? */
275                         ++num_digits;           /* We've now seen a digit. */
276                 }
277                 if (num_digits || (*pos != '0')) { /* Had/have nonzero. */
278                         ++num_digits;
279                         if (num_digits <= DECIMAL_DIG) { /* Is digit significant? */
280 #ifdef _STRTOD_HEXADECIMAL_FLOATS
281                                 number = number * p_base
282                                         + (isdigit(*pos)
283                                            ? (*pos - '0')
284                                            : (((*pos)|0x20) - ('a' - 10)));
285 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
286                                 number = number * p_base + (*pos - '0');
287 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
288                         }
289                 }
290 #else  /* _STRTOD_RESTRICT_DIGITS */
291 #ifdef _STRTOD_NEED_NUM_DIGITS
292                 ++num_digits;
293 #endif
294 #ifdef _STRTOD_HEXADECIMAL_FLOATS
295                 number = number * p_base
296                         + (isdigit(*pos)
297                            ? (*pos - '0')
298                            : (((*pos)|0x20) - ('a' - 10)));
299 #else  /* _STRTOD_HEXADECIMAL_FLOATS */
300                 number = number * p_base + (*pos - '0');
301 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
302 #endif /* _STRTOD_RESTRICT_DIGITS */
303                 ++pos;
304         }
305
306 #ifdef __UCLIBC_HAS_LOCALE__
307 #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
308         if (!pos0 && (*pos == decpt_wc)) { /* First decimal point? */
309                 pos0 = ++pos;
310                 goto LOOP;
311         }
312 #else
313         if (!pos0 && !memcmp(pos, decpt, decpt_len)) { /* First decimal point? */
314                 pos0 = (pos += decpt_len);
315                 goto LOOP;
316         }
317 #endif
318 #else  /* __UCLIBC_HAS_LOCALE__ */
319         if ((*pos == '.') && !pos0) { /* First decimal point? */
320                 pos0 = ++pos;                   /* Save position of decimal point */
321                 goto LOOP;                              /*   and process rest of digits. */
322         }
323 #endif /* __UCLIBC_HAS_LOCALE__ */
324
325 #ifdef _STRTOD_NEED_NUM_DIGITS
326         if (num_digits<0) {                     /* Must have at least one digit. */
327 #ifdef _STRTOD_HEXADECIMAL_FLOATS
328                 if (poshex) {                   /* Back up to '0' in '0x' prefix. */
329                         pos = poshex;
330                         goto DONE;
331                 }
332 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
333
334 #ifdef _STRTOD_NAN_INF_STRINGS
335                 if (!pos0) {                    /* No decimal point, so check for inf/nan. */
336                         /* Note: nan is the first string so 'number = i/0.;' works. */
337                         static const char nan_inf_str[] = "\05nan\0\012infinity\0\05inf\0";
338                         int i = 0;
339
340                         do {
341                                 /* Unfortunately, we have no memcasecmp(). */
342                                 int j = 0;
343                                 /* | 0x20 is a cheap lowercasing (valid for ASCII letters and numbers only) */
344                                 while ((pos[j] | 0x20) == nan_inf_str[i+1+j]) {
345                                         ++j;
346                                         if (!nan_inf_str[i+1+j]) {
347                                                 number = i / 0.;
348                                                 if (negative) { /* Correct for sign. */
349                                                         number = -number;
350                                                 }
351                                                 pos += nan_inf_str[i] - 2;
352                                                 goto DONE;
353                                         }
354                                 }
355                                 i += nan_inf_str[i];
356                         } while (nan_inf_str[i]);
357                 }
358
359 #endif /* STRTOD_NAN_INF_STRINGS */
360 #ifdef _STRTOD_ENDPTR
361                 pos = (Wchar *) str;
362 #endif
363                 goto DONE;
364         }
365 #endif /* _STRTOD_NEED_NUM_DIGITS */
366
367 #ifdef _STRTOD_RESTRICT_DIGITS
368         if (num_digits > DECIMAL_DIG) { /* Adjust exponent for skipped digits. */
369                 exponent_power += num_digits - DECIMAL_DIG;
370         }
371 #endif
372
373         if (pos0) {
374                 exponent_power += pos0 - pos; /* Adjust exponent for decimal point. */
375         }
376
377 #ifdef _STRTOD_HEXADECIMAL_FLOATS
378         if (poshex) {
379                 exponent_power *= 4;    /* Above is 2**4, but below is 2. */
380                 p_base = 2;
381         }
382 #endif /* _STRTOD_HEXADECIMAL_FLOATS */
383
384         if (negative) {                         /* Correct for sign. */
385                 number = -number;
386         }
387
388         /* process an exponent string */
389         if (((*pos)|0x20) == EXPCHAR) {
390 #ifdef _STRTOD_ENDPTR
391                 pos1 = pos;
392 #endif
393                 negative = 1;
394                 switch(*++pos) {                /* Handle optional sign. */
395                         case '-': negative = -1; /* Fall through to increment pos. */
396                         case '+': ++pos;
397                 }
398
399                 pos0 = pos;
400                 exponent_temp = 0;
401                 while (isdigit(*pos)) { /* Process string of digits. */
402 #ifdef _STRTOD_RESTRICT_EXP
403                         if (exponent_temp < MAX_ALLOWED_EXP) { /* Avoid overflow. */
404                                 exponent_temp = exponent_temp * 10 + (*pos - '0');
405                         }
406 #else
407                         exponent_temp = exponent_temp * 10 + (*pos - '0');
408 #endif
409                         ++pos;
410                 }
411
412 #ifdef _STRTOD_ENDPTR
413                 if (pos == pos0) {      /* No digits? */
414                         pos = pos1;             /* Back up to {e|E}/{p|P}. */
415                 } /* else */
416 #endif
417
418                 exponent_power += negative * exponent_temp;
419         }
420
421 #ifdef _STRTOD_ZERO_CHECK
422         if (number == 0.) {
423                 goto DONE;
424         }
425 #endif
426
427         /* scale the result */
428 #ifdef _STRTOD_LOG_SCALING
429         exponent_temp = exponent_power;
430
431         if (exponent_temp < 0) {
432                 exponent_temp = -exponent_temp;
433         }
434
435         while (exponent_temp) {
436                 if (exponent_temp & 1) {
437                         if (exponent_power < 0) {
438                                 /* Warning... caluclating a factor for the exponent and
439                                  * then dividing could easily be faster.  But doing so
440                                  * might cause problems when dealing with denormals. */
441                                 number /= p_base;
442                         } else {
443                                 number *= p_base;
444                         }
445                 }
446                 exponent_temp >>= 1;
447                 p_base *= p_base;
448         }
449
450 #else  /* _STRTOD_LOG_SCALING */
451         while (exponent_power) {
452                 if (exponent_power < 0) {
453                         number /= p_base;
454                         exponent_power++;
455                 } else {
456                         number *= p_base;
457                         exponent_power--;
458                 }
459         }
460 #endif /* _STRTOD_LOG_SCALING */
461
462 #ifdef _STRTOD_ERRNO
463         if (__FPMAX_ZERO_OR_INF_CHECK(number)) {
464                 __set_errno(ERANGE);
465         }
466 #endif
467
468  DONE:
469 #ifdef _STRTOD_ENDPTR
470         if (endptr) {
471                 *endptr = pos;
472         }
473 #endif
474
475         return number;
476 }
477
478 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
479
480 #endif
481 /**********************************************************************/
482 #ifdef L___fp_range_check
483 #if defined(NEED_STRTOF_WRAPPER) || defined(NEED_STRTOD_WRAPPER)
484
485 void attribute_hidden __fp_range_check(__fpmax_t y, __fpmax_t x)
486 {
487         if (__FPMAX_ZERO_OR_INF_CHECK(y) /* y is 0 or +/- infinity */
488                 && (y != 0)     /* y is not 0 (could have x>0, y==0 if underflow) */
489                 && !__FPMAX_ZERO_OR_INF_CHECK(x) /* x is not 0 or +/- infinity */
490                 ) {
491                 __set_errno(ERANGE);    /* Then x is not in y's range. */
492         }
493 }
494
495 #endif
496 #endif
497 /**********************************************************************/
498 #if defined(L_strtof) || defined(L_strtof_l) || defined(L_wcstof) || defined(L_wcstof_l)
499 #if defined(NEED_STRTOF_WRAPPER)
500
501 #if defined(L_wcstof) || defined(L_wcstof_l)
502 #define strtof           wcstof
503 #define strtof_l         wcstof_l
504 #define __strtofpmax     __wcstofpmax
505 #define __strtofpmax_l   __wcstofpmax_l
506 #define Wchar wchar_t
507 #else
508 #define Wchar char
509 #endif
510
511
512 libc_hidden_proto(__XL_NPP(strtof))
513 float __XL_NPP(strtof)(const Wchar *str, Wchar **endptr   __LOCALE_PARAM )
514 {
515 #if FPMAX_TYPE == 1
516         return __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
517 #else
518         __fpmax_t x;
519         float y;
520
521         x = __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
522         y = (float) x;
523
524         __fp_range_check(y, x);
525
526         return y;
527 #endif
528 }
529 libc_hidden_def(__XL_NPP(strtof))
530
531 #endif
532 #endif
533 /**********************************************************************/
534 #if defined(L_strtod) || defined(L_strtod_l) || defined(L_wcstod) || defined(L_wcstod_l)
535 #if defined(NEED_STRTOD_WRAPPER)
536
537 #if defined(L_wcstod) || defined(L_wcstod_l)
538 #define strtod           wcstod
539 #define strtod_l         wcstod_l
540 #define __strtofpmax     __wcstofpmax
541 #define __strtofpmax_l   __wcstofpmax_l
542 #define Wchar wchar_t
543 #else
544 #define Wchar char
545 #endif
546
547 double __XL_NPP(strtod)(const Wchar *__restrict str,
548                                         Wchar **__restrict endptr   __LOCALE_PARAM )
549 {
550 #if FPMAX_TYPE == 2
551         return __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
552 #else
553         __fpmax_t x;
554         double y;
555
556         x = __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
557         y = (double) x;
558
559         __fp_range_check(y, x);
560
561         return y;
562 #endif
563 }
564 #ifdef L_strtod
565 libc_hidden_def(strtod)
566 #endif
567
568 #endif
569 #endif
570 /**********************************************************************/
571 #if defined(L_strtold) || defined(L_strtold_l) || defined(L_wcstold) || defined(L_wcstold_l)
572 #if defined(NEED_STRTOLD_WRAPPER)
573
574 #if defined(L_wcstold) || defined(L_wcstold_l)
575 #define strtold           wcstold
576 #define strtold_l         wcstold_l
577 #define __strtofpmax     __wcstofpmax
578 #define __strtofpmax_l   __wcstofpmax_l
579 #define Wchar wchar_t
580 #else
581 #define Wchar char
582 #endif
583
584 long double __XL_NPP(strtold) (const Wchar *str, Wchar **endptr   __LOCALE_PARAM )
585 {
586 #if FPMAX_TYPE == 3
587         return __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
588 #else
589         __fpmax_t x;
590         long double y;
591
592         x = __XL_NPP(__strtofpmax)(str, endptr, 0   __LOCALE_ARG );
593         y = (long double) x;
594
595         __fp_range_check(y, x);
596
597         return y;
598 #endif
599 }
600
601 #endif
602 #endif
603 /**********************************************************************/