/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*/
#include "lint.h"
#include <errno.h>
#include <stdio.h>
#include <values.h>
#include <floatingpoint.h>
#include <stddef.h>
#include <wctype.h>
#include <locale.h>
#include "libc.h"
#include "xpg6.h"
double
{
double x;
int form;
if (form == 0)
return (0.0); /* Shameful kluge for SVID's sake. */
#else
#endif
if (form < 0)
else
return (x);
}
float
{
float x;
int form;
if (form == 0)
return (0.0f);
#else
#endif
if (form < 0)
else
return (x);
}
long double
{
long double x;
int form;
if (form == 0)
return (0.0L);
if (form < 0)
else
if (form < 0)
else
#else
#endif
return (x);
}
double
{
}
/*
* The following macro is applied to wchar_t arguments solely for the
* purpose of comparing the result with one of the characters in the
* strings above.
*/
/*
* The following macro yields an expression that is true whenever
* the argument is a valid nonzero digit for the form being parsed.
*/
((L'a' <= c && c <= L'f') || (L'A' <= c && c <= L'F'))))
/*
* wstring_to_decimal is modelled on string_to_decimal, the majority
* of which can be found in the common file char_to_decimal.h. The
* significant differences are:
*
* 1. This code recognizes only C99 (hex fp strings and restricted
* characters in parentheses following "nan") vs. C90 modes, no
* Fortran conventions.
*
* 2. *pform is an int rather than an enum decimal_string_form. On
* return, *pform == 0 if no valid token was found, *pform < 0
* if a C99 hex fp string was found, and *pform > 0 if a decimal
* string was found.
*/
static void
int *pform)
{
int sigfound;
int ids = 0;
int i, agree;
char decpt;
char *pfast;
int e, esign;
int expshift = 0;
int form;
/*
* This routine assumes that the radix point is a single
* ASCII character, so that following this assignment, the
* condition (current == decpt) will correctly detect it.
*/
/* input is invalid until we find something */
/* skip white space */
/* look for optional leading sign */
if (current == L'+') {
} else if (current == L'-') {
}
/*
* Admissible first non-white-space, non-sign characters are
* 0-9, i, I, n, N, or the radix point.
*/
form = 1;
} else {
switch (current) {
case L'0':
/*
* Accept the leading zero and set pd->fpclass
* accordingly, but don't set sigfound until we
* determine that this isn't a "fake" hex string
* (i.e., 0x.p...).
*/
if (c99) {
/* look for a hex fp string */
/* assume hex fp form */
form = -1;
expshift = 2;
/*
* Only a digit or radix point can
* follow "0x".
*/
sigfound = 1;
break;
goto afterpoint;
} else if (current != L'0') {
/* not hex fp after all */
form = 1;
expshift = 0;
goto done;
}
} else {
form = 1;
}
} else {
form = 1;
}
/* skip all leading zeros */
while (current == L'0')
sigfound = 0; /* 0 = only zeros found so far */
break;
case L'i':
case L'I':
/* look for inf or infinity */
agree = 1;
while (agree <= 7 &&
agree++;
}
if (agree >= 3) {
/* found valid infinity */
form = 1;
__inf_read = 1;
}
goto done;
case L'n':
case L'N':
/* look for nan or nan(string) */
agree = 1;
while (agree <= 2 &&
agree++;
}
if (agree == 3) {
/* found valid NaN */
form = 1;
__nan_read = 1;
if (current == L'(') {
/* accept parenthesized string */
if (c99) {
do {
current == L'_');
} else {
do {
} while (current &&
current != L')');
}
if (current == L')')
}
}
goto done;
default:
/*
* Don't accept the radix point just yet;
* we need to see at least one digit.
*/
goto afterpoint;
}
goto done;
}
}
/*
* Admissible characters after the first digit are a valid
* digit, an exponent delimiter (E or e for decimal form,
* P or p for hex form), or the radix point. (Note that we
* can't get here unless we've already found a digit.)
*/
/*
* Found another nonzero digit. If there's enough room
* in pd->ds, store any intervening zeros we've found so far
* and then store this digit. Otherwise, stop storing
* digits in pd->ds and set pd->more.
*/
for (i = 0; i < nzbp; i++)
} else {
if (ids < DECIMAL_STRING_LENGTH) {
/* don't store any more digits */
}
}
sigfound = 1;
nzbp = 0;
/*
* Use an optimized loop to grab a consecutive sequence
* of nonzero digits quickly.
*/
nfast++) {
}
if (current == L'0')
goto nextnumberzero; /* common case */
/* advance good to the last accepted digit */
goto nextnumber;
} else {
switch (current) {
case L'0':
/*
* Count zeros before the radix point. Later we
* will either put these zeros into pd->ds or add
* nzbp to pd->exponent to account for them.
*/
while (current == L'0') {
nzbp++;
}
goto nextnumber;
case L'E':
case L'e':
if (form < 0)
goto done;
goto exponent;
case L'P':
case L'p':
if (form > 0)
goto done;
goto exponent;
default:
/* accept the radix point */
goto afterpoint;
}
goto done;
}
}
/*
* Admissible characters after the radix point are a valid digit
* or an exponent delimiter. (Note that it is possible to get
* here even though we haven't found any digits yet.)
*/
if (form == 0)
form = 1;
if (sigfound < 1) {
/* no significant digits found until now */
sigfound = 1;
} else {
/* significant digits have been found */
} else {
if (ids < DECIMAL_STRING_LENGTH) {
/* don't store any more digits */
}
}
}
nzbp = 0;
nzap = 0;
/*
* Use an optimized loop to grab a consecutive sequence
* of nonzero digits quickly.
*/
nfast++) {
}
if (current == L'0')
goto zeroafterpoint;
/* advance good to the last accepted digit */
goto afterpoint;
} else {
switch (current) {
case L'0':
if (form == 0)
form = 1;
if (sigfound == -1) {
sigfound = 0;
}
/*
* Count zeros after the radix point. If we find
* any more nonzero digits later, we will put these
* zeros into pd->ds and decrease pd->exponent by
* nzap.
*/
while (current == L'0') {
nzap++;
}
goto afterpoint;
case L'E':
case L'e':
/* don't accept exponent without preceding digits */
goto done;
break;
case L'P':
case L'p':
/* don't accept exponent without preceding digits */
goto done;
break;
default:
goto done;
}
}
e = 0;
esign = 0;
/* look for optional exponent sign */
if (current == L'+') {
} else if (current == L'-') {
esign = 1;
}
/*
* Accumulate explicit exponent. Note that if we don't find at
* least one digit, good won't be updated and e will remain 0.
* Also, we keep e from getting too large so we don't overflow
* the range of int (but notice that the threshold is large
* enough that any larger e would cause the result to underflow
* or overflow anyway).
*/
if (e <= 1000000)
}
if (esign)
else
done:
/*
* If we found any zeros before the radix point that were not
* accounted for earlier, adjust the exponent. (This is only
* relevant when pd->fpclass == fp_normal, but it's harmless
* in all other cases.)
*/
/* terminate pd->ds if we haven't already */
if (ids < DECIMAL_STRING_LENGTH) {
}
/*
* If we accepted any characters, advance *ppc to point to the
* first character we didn't accept; otherwise, pass back a
* signaling nan.
*/
} else {
form = 0;
}
}