4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
33 * This file is based on /usr/src/lib/libc/port/gen/strtod.c and
34 * /usr/src/lib/libc/sparc/fp/string_decim.c
37 #pragma weak _wcstod = wcstod
38 #pragma weak _wstod = wstod
44 #include <floatingpoint.h>
47 #include "base_conversion.h" /* from usr/src/lib/libc/inc */
52 static void wstring_to_decimal(const wchar_t **, int, decimal_record
*, int *);
55 wcstod(const wchar_t *cp
, wchar_t **ptr
)
60 fp_exception_field_type fs
;
63 wstring_to_decimal(&cp
, __xpg6
& _C99SUSv3_recognize_hexfp
, &dr
, &form
);
67 return (0.0); /* Shameful kluge for SVID's sake. */
68 #if defined(__i386) || defined(__amd64)
70 #elif defined(__sparc)
73 #error Unknown architecture!
76 __hex_to_double(&dr
, mr
.rd
, &x
, &fs
);
78 decimal_to_double(&x
, &mr
, &dr
, &fs
);
79 if (fs
& ((1 << fp_overflow
) | (1 << fp_underflow
)))
85 wcstof(const wchar_t *cp
, wchar_t **ptr
)
90 fp_exception_field_type fs
;
93 wstring_to_decimal(&cp
, 1, &dr
, &form
);
98 #if defined(__i386) || defined(__amd64)
100 #elif defined(__sparc)
103 #error Unknown architecture!
106 __hex_to_single(&dr
, mr
.rd
, &x
, &fs
);
108 decimal_to_single(&x
, &mr
, &dr
, &fs
);
109 if (fs
& ((1 << fp_overflow
) | (1 << fp_underflow
)))
115 wcstold(const wchar_t *cp
, wchar_t **ptr
)
120 fp_exception_field_type fs
;
123 wstring_to_decimal(&cp
, 1, &dr
, &form
);
125 *ptr
= (wchar_t *)cp
;
128 #if defined(__i386) || defined(__amd64)
131 __hex_to_extended(&dr
, mr
.rd
, (extended
*)&x
, &fs
);
133 decimal_to_extended((extended
*)&x
, &mr
, &dr
, &fs
);
134 #elif defined(__sparc)
137 __hex_to_quadruple(&dr
, mr
.rd
, &x
, &fs
);
139 decimal_to_quadruple(&x
, &mr
, &dr
, &fs
);
141 #error Unknown architecture!
143 if (fs
& ((1 << fp_overflow
) | (1 << fp_underflow
)))
149 wstod(const wchar_t *cp
, wchar_t **ptr
)
151 return (wcstod(cp
, ptr
));
154 static const char *infstring
= "INFINITY";
155 static const char *nanstring
= "NAN";
158 * The following macro is applied to wchar_t arguments solely for the
159 * purpose of comparing the result with one of the characters in the
162 #define UCASE(c) (((L'a' <= c) && (c <= L'z'))? c - 32 : c)
165 * The following macro yields an expression that is true whenever
166 * the argument is a valid nonzero digit for the form being parsed.
168 #define NZDIGIT(c) ((L'1' <= c && c <= L'9') || (form < 0 && \
169 ((L'a' <= c && c <= L'f') || (L'A' <= c && c <= L'F'))))
172 * wstring_to_decimal is modelled on string_to_decimal, the majority
173 * of which can be found in the common file char_to_decimal.h. The
174 * significant differences are:
176 * 1. This code recognizes only C99 (hex fp strings and restricted
177 * characters in parentheses following "nan") vs. C90 modes, no
178 * Fortran conventions.
180 * 2. *pform is an int rather than an enum decimal_string_form. On
181 * return, *pform == 0 if no valid token was found, *pform < 0
182 * if a C99 hex fp string was found, and *pform > 0 if a decimal
186 wstring_to_decimal(const wchar_t **ppc
, int c99
, decimal_record
*pd
,
189 const wchar_t *cp
= *ppc
; /* last character seen */
190 const wchar_t *good
= cp
- 1; /* last character accepted */
191 wchar_t current
; /* always equal to *cp */
195 int nzbp
= 0; /* number of zeros before point */
196 int nzap
= 0; /* number of zeros after point */
198 int nfast
, nfastlimit
;
205 * This routine assumes that the radix point is a single
206 * ASCII character, so that following this assignment, the
207 * condition (current == decpt) will correctly detect it.
209 decpt
= *(localeconv()->decimal_point
);
211 /* input is invalid until we find something */
212 pd
->fpclass
= fp_signaling
;
220 /* skip white space */
222 while (iswspace((wint_t)current
))
225 /* look for optional leading sign */
226 if (current
== L
'+') {
228 } else if (current
== L
'-') {
233 sigfound
= -1; /* -1 = no digits found yet */
236 * Admissible first non-white-space, non-sign characters are
237 * 0-9, i, I, n, N, or the radix point.
239 if (L
'1' <= current
&& current
<= L
'9') {
240 pd
->fpclass
= fp_normal
;
243 sigfound
= 1; /* 1 = significant digits found */
244 pd
->ds
[ids
++] = (char)current
;
250 * Accept the leading zero and set pd->fpclass
251 * accordingly, but don't set sigfound until we
252 * determine that this isn't a "fake" hex string
256 pd
->fpclass
= fp_zero
;
258 /* look for a hex fp string */
260 if (current
== L
'X' || current
== L
'x') {
261 /* assume hex fp form */
266 * Only a digit or radix point can
269 if (NZDIGIT(current
)) {
270 pd
->fpclass
= fp_normal
;
273 pd
->ds
[ids
++] = (char)current
;
276 } else if (current
== (wchar_t)decpt
) {
279 } else if (current
!= L
'0') {
280 /* not hex fp after all */
292 /* skip all leading zeros */
293 while (current
== L
'0')
296 sigfound
= 0; /* 0 = only zeros found so far */
301 /* look for inf or infinity */
305 UCASE(current
) == (wchar_t)infstring
[agree
]) {
310 /* found valid infinity */
311 pd
->fpclass
= fp_infinity
;
313 good
= (agree
< 8)? cp
+ 2 - agree
: cp
- 1;
320 /* look for nan or nan(string) */
324 UCASE(current
) == (wchar_t)nanstring
[agree
]) {
329 /* found valid NaN */
330 pd
->fpclass
= fp_quiet
;
334 if (current
== L
'(') {
335 /* accept parenthesized string */
339 } while (iswalnum(current
) ||
354 if (current
== (wchar_t)decpt
) {
356 * Don't accept the radix point just yet;
357 * we need to see at least one digit.
368 * Admissible characters after the first digit are a valid
369 * digit, an exponent delimiter (E or e for decimal form,
370 * P or p for hex form), or the radix point. (Note that we
371 * can't get here unless we've already found a digit.)
373 if (NZDIGIT(current
)) {
375 * Found another nonzero digit. If there's enough room
376 * in pd->ds, store any intervening zeros we've found so far
377 * and then store this digit. Otherwise, stop storing
378 * digits in pd->ds and set pd->more.
380 if (ids
+ nzbp
+ 2 < DECIMAL_STRING_LENGTH
) {
381 for (i
= 0; i
< nzbp
; i
++)
383 pd
->ds
[ids
++] = (char)current
;
385 pd
->exponent
+= (nzbp
+ 1) << expshift
;
387 if (ids
< DECIMAL_STRING_LENGTH
) {
390 /* don't store any more digits */
391 ids
= DECIMAL_STRING_LENGTH
;
394 pd
->fpclass
= fp_normal
;
400 * Use an optimized loop to grab a consecutive sequence
401 * of nonzero digits quickly.
403 nfastlimit
= DECIMAL_STRING_LENGTH
- 3 - ids
;
404 for (nfast
= 0, pfast
= &(pd
->ds
[ids
]);
405 nfast
< nfastlimit
&& NZDIGIT(current
);
407 *pfast
++ = (char)current
;
412 goto nextnumberzero
; /* common case */
413 /* advance good to the last accepted digit */
421 * Count zeros before the radix point. Later we
422 * will either put these zeros into pd->ds or add
423 * nzbp to pd->exponent to account for them.
425 while (current
== L
'0') {
445 if (current
== decpt
) {
446 /* accept the radix point */
457 * Admissible characters after the radix point are a valid digit
458 * or an exponent delimiter. (Note that it is possible to get
459 * here even though we haven't found any digits yet.)
461 if (NZDIGIT(current
)) {
465 /* no significant digits found until now */
466 pd
->fpclass
= fp_normal
;
468 pd
->ds
[ids
++] = (char)current
;
469 pd
->exponent
= (-(nzap
+ 1)) << expshift
;
471 /* significant digits have been found */
472 if (ids
+ nzbp
+ nzap
+ 2 < DECIMAL_STRING_LENGTH
) {
473 for (i
= 0; i
< nzbp
+ nzap
; i
++)
475 pd
->ds
[ids
++] = (char)current
;
476 pd
->exponent
-= (nzap
+ 1) << expshift
;
478 pd
->exponent
+= nzbp
<< expshift
;
480 if (ids
< DECIMAL_STRING_LENGTH
) {
483 /* don't store any more digits */
484 ids
= DECIMAL_STRING_LENGTH
;
493 * Use an optimized loop to grab a consecutive sequence
494 * of nonzero digits quickly.
496 nfastlimit
= DECIMAL_STRING_LENGTH
- 3 - ids
;
497 for (nfast
= 0, pfast
= &(pd
->ds
[ids
]);
498 nfast
< nfastlimit
&& NZDIGIT(current
);
500 *pfast
++ = (char)current
;
504 pd
->exponent
-= nfast
<< expshift
;
507 /* advance good to the last accepted digit */
515 if (sigfound
== -1) {
516 pd
->fpclass
= fp_zero
;
521 * Count zeros after the radix point. If we find
522 * any more nonzero digits later, we will put these
523 * zeros into pd->ds and decrease pd->exponent by
526 while (current
== L
'0') {
535 /* don't accept exponent without preceding digits */
536 if (sigfound
== -1 || form
< 0)
542 /* don't accept exponent without preceding digits */
543 if (sigfound
== -1 || form
> 0)
556 /* look for optional exponent sign */
558 if (current
== L
'+') {
560 } else if (current
== L
'-') {
566 * Accumulate explicit exponent. Note that if we don't find at
567 * least one digit, good won't be updated and e will remain 0.
568 * Also, we keep e from getting too large so we don't overflow
569 * the range of int (but notice that the threshold is large
570 * enough that any larger e would cause the result to underflow
571 * or overflow anyway).
573 while (L
'0' <= current
&& current
<= L
'9') {
576 e
= 10 * e
+ current
- L
'0';
586 * If we found any zeros before the radix point that were not
587 * accounted for earlier, adjust the exponent. (This is only
588 * relevant when pd->fpclass == fp_normal, but it's harmless
589 * in all other cases.)
591 pd
->exponent
+= nzbp
<< expshift
;
593 /* terminate pd->ds if we haven't already */
594 if (ids
< DECIMAL_STRING_LENGTH
) {
600 * If we accepted any characters, advance *ppc to point to the
601 * first character we didn't accept; otherwise, pass back a
607 pd
->fpclass
= fp_signaling
;