#pragma weak _wcstod = wcstod
#pragma weak _wstod = wstod
#include "lint.h"
#include <errno.h>
#include <stdio.h>
#include <values.h>
#include <floatingpoint.h>
#include <stddef.h>
#include <wctype.h>
#include "base_conversion.h"
#include <locale.h>
#include "libc.h"
#include "xpg6.h"
static void wstring_to_decimal(const wchar_t **, int, decimal_record *, int *);
double
wcstod(const wchar_t *cp, wchar_t **ptr)
{
double x;
decimal_mode mr;
decimal_record dr;
fp_exception_field_type fs;
int form;
wstring_to_decimal(&cp, __xpg6 & _C99SUSv3_recognize_hexfp, &dr, &form);
if (ptr != NULL)
*ptr = (wchar_t *)cp;
if (form == 0)
return (0.0);
#if defined(__i386) || defined(__amd64)
mr.rd = __xgetRD();
#elif defined(__sparc)
mr.rd = _QgetRD();
#else
#error Unknown architecture!
#endif
if (form < 0)
__hex_to_double(&dr, mr.rd, &x, &fs);
else
decimal_to_double(&x, &mr, &dr, &fs);
if (fs & ((1 << fp_overflow) | (1 << fp_underflow)))
errno = ERANGE;
return (x);
}
float
wcstof(const wchar_t *cp, wchar_t **ptr)
{
float x;
decimal_mode mr;
decimal_record dr;
fp_exception_field_type fs;
int form;
wstring_to_decimal(&cp, 1, &dr, &form);
if (ptr != NULL)
*ptr = (wchar_t *)cp;
if (form == 0)
return (0.0f);
#if defined(__i386) || defined(__amd64)
mr.rd = __xgetRD();
#elif defined(__sparc)
mr.rd = _QgetRD();
#else
#error Unknown architecture!
#endif
if (form < 0)
__hex_to_single(&dr, mr.rd, &x, &fs);
else
decimal_to_single(&x, &mr, &dr, &fs);
if (fs & ((1 << fp_overflow) | (1 << fp_underflow)))
errno = ERANGE;
return (x);
}
long double
wcstold(const wchar_t *cp, wchar_t **ptr)
{
long double x;
decimal_mode mr;
decimal_record dr;
fp_exception_field_type fs;
int form;
wstring_to_decimal(&cp, 1, &dr, &form);
if (ptr != NULL)
*ptr = (wchar_t *)cp;
if (form == 0)
return (0.0L);
#if defined(__i386) || defined(__amd64)
mr.rd = __xgetRD();
if (form < 0)
__hex_to_extended(&dr, mr.rd, (extended *)&x, &fs);
else
decimal_to_extended((extended *)&x, &mr, &dr, &fs);
#elif defined(__sparc)
mr.rd = _QgetRD();
if (form < 0)
__hex_to_quadruple(&dr, mr.rd, &x, &fs);
else
decimal_to_quadruple(&x, &mr, &dr, &fs);
#else
#error Unknown architecture!
#endif
if (fs & ((1 << fp_overflow) | (1 << fp_underflow)))
errno = ERANGE;
return (x);
}
double
wstod(const wchar_t *cp, wchar_t **ptr)
{
return (wcstod(cp, ptr));
}
static const char *infstring = "INFINITY";
static const char *nanstring = "NAN";
#define UCASE(c) (((L'a' <= c) && (c <= L'z'))? c - 32 : c)
#define NZDIGIT(c) ((L'1' <= c && c <= L'9') || (form < 0 && \
((L'a' <= c && c <= L'f') || (L'A' <= c && c <= L'F'))))
static void
wstring_to_decimal(const wchar_t **ppc, int c99, decimal_record *pd,
int *pform)
{
const wchar_t *cp = *ppc;
const wchar_t *good = cp - 1;
wchar_t current;
int sigfound;
int ids = 0;
int i, agree;
int nzbp = 0;
int nzap = 0;
char decpt;
int nfast, nfastlimit;
char *pfast;
int e, esign;
int expshift = 0;
int form;
decpt = *(localeconv()->decimal_point);
pd->fpclass = fp_signaling;
pd->sign = 0;
pd->exponent = 0;
pd->ds[0] = '\0';
pd->more = 0;
pd->ndigits = 0;
*pform = form = 0;
current = *cp;
while (iswspace((wint_t)current))
current = *++cp;
if (current == L'+') {
current = *++cp;
} else if (current == L'-') {
pd->sign = 1;
current = *++cp;
}
sigfound = -1;
if (L'1' <= current && current <= L'9') {
pd->fpclass = fp_normal;
form = 1;
good = cp;
sigfound = 1;
pd->ds[ids++] = (char)current;
current = *++cp;
} else {
switch (current) {
case L'0':
good = cp;
pd->fpclass = fp_zero;
if (c99) {
current = *++cp;
if (current == L'X' || current == L'x') {
form = -1;
expshift = 2;
current = *++cp;
if (NZDIGIT(current)) {
pd->fpclass = fp_normal;
good = cp;
sigfound = 1;
pd->ds[ids++] = (char)current;
current = *++cp;
break;
} else if (current == (wchar_t)decpt) {
current = *++cp;
goto afterpoint;
} else if (current != L'0') {
form = 1;
expshift = 0;
goto done;
}
} else {
form = 1;
}
} else {
form = 1;
}
while (current == L'0')
current = *++cp;
good = cp - 1;
sigfound = 0;
break;
case L'i':
case L'I':
current = *++cp;
agree = 1;
while (agree <= 7 &&
UCASE(current) == (wchar_t)infstring[agree]) {
current = *++cp;
agree++;
}
if (agree >= 3) {
pd->fpclass = fp_infinity;
form = 1;
good = (agree < 8)? cp + 2 - agree : cp - 1;
__inf_read = 1;
}
goto done;
case L'n':
case L'N':
current = *++cp;
agree = 1;
while (agree <= 2 &&
UCASE(current) == (wchar_t)nanstring[agree]) {
current = *++cp;
agree++;
}
if (agree == 3) {
pd->fpclass = fp_quiet;
form = 1;
good = cp - 1;
__nan_read = 1;
if (current == L'(') {
if (c99) {
do {
current = *++cp;
} while (iswalnum(current) ||
current == L'_');
} else {
do {
current = *++cp;
} while (current &&
current != L')');
}
if (current == L')')
good = cp;
}
}
goto done;
default:
if (current == (wchar_t)decpt) {
current = *++cp;
goto afterpoint;
}
goto done;
}
}
nextnumber:
if (NZDIGIT(current)) {
if (ids + nzbp + 2 < DECIMAL_STRING_LENGTH) {
for (i = 0; i < nzbp; i++)
pd->ds[ids++] = '0';
pd->ds[ids++] = (char)current;
} else {
pd->exponent += (nzbp + 1) << expshift;
pd->more = 1;
if (ids < DECIMAL_STRING_LENGTH) {
pd->ds[ids] = '\0';
pd->ndigits = ids;
ids = DECIMAL_STRING_LENGTH;
}
}
pd->fpclass = fp_normal;
sigfound = 1;
nzbp = 0;
current = *++cp;
nfastlimit = DECIMAL_STRING_LENGTH - 3 - ids;
for (nfast = 0, pfast = &(pd->ds[ids]);
nfast < nfastlimit && NZDIGIT(current);
nfast++) {
*pfast++ = (char)current;
current = *++cp;
}
ids += nfast;
if (current == L'0')
goto nextnumberzero;
good = cp - 1;
goto nextnumber;
} else {
switch (current) {
case L'0':
nextnumberzero:
while (current == L'0') {
nzbp++;
current = *++cp;
}
good = cp - 1;
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:
if (current == decpt) {
good = cp;
current = *++cp;
goto afterpoint;
}
goto done;
}
}
afterpoint:
if (NZDIGIT(current)) {
if (form == 0)
form = 1;
if (sigfound < 1) {
pd->fpclass = fp_normal;
sigfound = 1;
pd->ds[ids++] = (char)current;
pd->exponent = (-(nzap + 1)) << expshift;
} else {
if (ids + nzbp + nzap + 2 < DECIMAL_STRING_LENGTH) {
for (i = 0; i < nzbp + nzap; i++)
pd->ds[ids++] = '0';
pd->ds[ids++] = (char)current;
pd->exponent -= (nzap + 1) << expshift;
} else {
pd->exponent += nzbp << expshift;
pd->more = 1;
if (ids < DECIMAL_STRING_LENGTH) {
pd->ds[ids] = '\0';
pd->ndigits = ids;
ids = DECIMAL_STRING_LENGTH;
}
}
}
nzbp = 0;
nzap = 0;
current = *++cp;
nfastlimit = DECIMAL_STRING_LENGTH - 3 - ids;
for (nfast = 0, pfast = &(pd->ds[ids]);
nfast < nfastlimit && NZDIGIT(current);
nfast++) {
*pfast++ = (char)current;
current = *++cp;
}
ids += nfast;
pd->exponent -= nfast << expshift;
if (current == L'0')
goto zeroafterpoint;
good = cp - 1;
goto afterpoint;
} else {
switch (current) {
case L'0':
if (form == 0)
form = 1;
if (sigfound == -1) {
pd->fpclass = fp_zero;
sigfound = 0;
}
zeroafterpoint:
while (current == L'0') {
nzap++;
current = *++cp;
}
good = cp - 1;
goto afterpoint;
case L'E':
case L'e':
if (sigfound == -1 || form < 0)
goto done;
break;
case L'P':
case L'p':
if (sigfound == -1 || form > 0)
goto done;
break;
default:
goto done;
}
}
exponent:
e = 0;
esign = 0;
current = *++cp;
if (current == L'+') {
current = *++cp;
} else if (current == L'-') {
esign = 1;
current = *++cp;
}
while (L'0' <= current && current <= L'9') {
good = cp;
if (e <= 1000000)
e = 10 * e + current - L'0';
current = *++cp;
}
if (esign)
pd->exponent -= e;
else
pd->exponent += e;
done:
pd->exponent += nzbp << expshift;
if (ids < DECIMAL_STRING_LENGTH) {
pd->ds[ids] = '\0';
pd->ndigits = ids;
}
if (good >= *ppc) {
*ppc = good + 1;
} else {
pd->fpclass = fp_signaling;
pd->sign = 0;
form = 0;
}
*pform = form;
}