mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-15 05:34:46 +00:00
msvcrt: Don't use strtold in __STRINGTOLD_L.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b22ffa5891
commit
a22adf1893
|
@ -28,6 +28,7 @@ static const int p10s[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
|
|||
#define LIMB_MAX 1000000000 /* 10^9 */
|
||||
|
||||
#define BNUM_PREC64 128 /* data size needed to store 64-bit double */
|
||||
#define BNUM_PREC80 2048 /* data size needed to store 80-bit double */
|
||||
|
||||
/* bnum represents real number with fixed decimal point */
|
||||
struct bnum {
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#define MSVCRT_FLT_MIN_10_EXP (-37)
|
||||
#define MSVCRT_DBL_MAX_10_EXP 308
|
||||
#define MSVCRT_DBL_MIN_10_EXP (-307)
|
||||
#define DBL80_MAX_10_EXP 4932
|
||||
#define DBL80_MIN_10_EXP -4951
|
||||
#define MSVCRT_DBL_DIG 15
|
||||
#ifdef _WIN64
|
||||
#define MSVCRT_SIZE_MAX MSVCRT_UI64_MAX
|
||||
|
@ -1230,7 +1232,7 @@ struct fpnum {
|
|||
enum fpmod mod;
|
||||
};
|
||||
struct fpnum fpnum_parse(MSVCRT_wchar_t (*)(void*), void (*)(void*),
|
||||
void*, MSVCRT_pthreadlocinfo) DECLSPEC_HIDDEN;
|
||||
void*, MSVCRT_pthreadlocinfo, BOOL) DECLSPEC_HIDDEN;
|
||||
int fpnum_double(struct fpnum*, double*) DECLSPEC_HIDDEN;
|
||||
/* Maybe one day we'll enable the invalid parameter handlers with the full set of information (msvcrXXd)
|
||||
* #define MSVCRT_INVALID_PMT(x) MSVCRT_call_invalid_parameter_handler(x, __FUNCTION__, __FILE__, __LINE__, 0)
|
||||
|
|
|
@ -405,7 +405,7 @@ _FUNCTION_ {
|
|||
#endif
|
||||
|
||||
fp = fpnum_parse(_STRTOD_NAME_(strtod_scanf_get),
|
||||
_STRTOD_NAME_(strtod_scanf_unget), &ctx, locinfo);
|
||||
_STRTOD_NAME_(strtod_scanf_unget), &ctx, locinfo, FALSE);
|
||||
fpnum_double(&fp, &cur);
|
||||
if(!rd && ctx.err) {
|
||||
_UNLOCK_FILE_(file);
|
||||
|
|
|
@ -468,6 +468,132 @@ int fpnum_double(struct fpnum *fp, double *d)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define LDBL_EXP_BITS 15
|
||||
#define LDBL_MANT_BITS 64
|
||||
int fpnum_ldouble(struct fpnum *fp, MSVCRT__LDOUBLE *d)
|
||||
{
|
||||
if (fp->mod == FP_VAL_INFINITY)
|
||||
{
|
||||
d->x80[0] = 0;
|
||||
d->x80[1] = 0x80000000;
|
||||
d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fp->mod == FP_VAL_NAN)
|
||||
{
|
||||
d->x80[0] = ~0;
|
||||
d->x80[1] = ~0;
|
||||
d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE("%c %s *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
|
||||
wine_dbgstr_longlong(fp->m), fp->exp, fp->mod);
|
||||
if (!fp->m)
|
||||
{
|
||||
d->x80[0] = 0;
|
||||
d->x80[1] = 0;
|
||||
d->x80[2] = 0;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make sure that we don't overflow modifying exponent */
|
||||
if (fp->exp > 1<<LDBL_EXP_BITS)
|
||||
{
|
||||
d->x80[0] = 0;
|
||||
d->x80[1] = 0x80000000;
|
||||
d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return MSVCRT_ERANGE;
|
||||
}
|
||||
if (fp->exp < -(1<<LDBL_EXP_BITS))
|
||||
{
|
||||
d->x80[0] = 0;
|
||||
d->x80[1] = 0;
|
||||
d->x80[2] = 0;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return MSVCRT_ERANGE;
|
||||
}
|
||||
fp->exp += LDBL_MANT_BITS - 1;
|
||||
|
||||
/* normalize mantissa */
|
||||
while(fp->m < (ULONGLONG)1 << (LDBL_MANT_BITS-1))
|
||||
{
|
||||
fp->m <<= 1;
|
||||
fp->exp--;
|
||||
}
|
||||
fp->exp += (1 << (LDBL_EXP_BITS-1)) - 1;
|
||||
|
||||
/* handle subnormals */
|
||||
if (fp->exp <= 0)
|
||||
{
|
||||
if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
|
||||
else if (fp->m & 1) fp->mod = FP_ROUND_UP;
|
||||
else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
|
||||
fp->m >>= 1;
|
||||
}
|
||||
while(fp->m && fp->exp<0)
|
||||
{
|
||||
if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
|
||||
else if (fp->m & 1) fp->mod = FP_ROUND_UP;
|
||||
else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
|
||||
fp->m >>= 1;
|
||||
fp->exp++;
|
||||
}
|
||||
|
||||
/* round mantissa */
|
||||
if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
|
||||
{
|
||||
if (fp->m == MSVCRT_UI64_MAX)
|
||||
{
|
||||
fp->m = (ULONGLONG)1 << (LDBL_MANT_BITS - 1);
|
||||
fp->exp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fp->m++;
|
||||
|
||||
/* handle subnormal that falls into regular range due to rounding */
|
||||
if ((fp->m ^ (fp->m - 1)) & ((ULONGLONG)1 << (LDBL_MANT_BITS - 1))) fp->exp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp->exp >= (1<<LDBL_EXP_BITS)-1)
|
||||
{
|
||||
d->x80[0] = 0;
|
||||
d->x80[1] = 0x80000000;
|
||||
d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return MSVCRT_ERANGE;
|
||||
}
|
||||
if (!fp->m || fp->exp < 0)
|
||||
{
|
||||
d->x80[0] = 0;
|
||||
d->x80[1] = 0;
|
||||
d->x80[2] = 0;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return MSVCRT_ERANGE;
|
||||
}
|
||||
|
||||
d->x80[0] = fp->m;
|
||||
d->x80[1] = fp->m >> 32;
|
||||
d->x80[2] = fp->exp;
|
||||
if (fp->sign == -1)
|
||||
d->x80[2] |= 1 << LDBL_EXP_BITS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if _MSVCR_VER >= 140
|
||||
|
||||
static inline int hex2int(char c)
|
||||
|
@ -612,8 +738,8 @@ static inline BOOL bnum_to_mant(struct bnum *b, ULONGLONG *m)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
|
||||
void *ctx, MSVCRT_pthreadlocinfo locinfo)
|
||||
static struct fpnum fpnum_parse_bnum(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
|
||||
void *ctx, MSVCRT_pthreadlocinfo locinfo, BOOL ldouble, struct bnum *b)
|
||||
{
|
||||
#if _MSVCR_VER >= 140
|
||||
MSVCRT_wchar_t _infinity[] = { 'i', 'n', 'f', 'i', 'n', 'i', 't', 'y', 0 };
|
||||
|
@ -622,9 +748,7 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
|
|||
int matched=0;
|
||||
#endif
|
||||
BOOL found_digit = FALSE, found_dp = FALSE, found_sign = FALSE;
|
||||
BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC64])];
|
||||
int e2 = 0, dp=0, sign=1, off, limb_digits = 0, i;
|
||||
struct bnum *b = (struct bnum*)bnum_data;
|
||||
enum fpmod round = FP_ROUND_ZERO;
|
||||
MSVCRT_wchar_t nch;
|
||||
ULONGLONG m;
|
||||
|
@ -684,7 +808,6 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
|
|||
|
||||
b->b = 0;
|
||||
b->e = 1;
|
||||
b->size = BNUM_PREC64;
|
||||
b->data[0] = 0;
|
||||
while(nch>='0' && nch<='9') {
|
||||
found_digit = TRUE;
|
||||
|
@ -806,11 +929,11 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
|
|||
if(off < 0) off += LIMB_DIGITS;
|
||||
if(off) bnum_mult(b, p10s[off]);
|
||||
|
||||
if(dp-1 > MSVCRT_DBL_MAX_10_EXP)
|
||||
if(dp-1 > (ldouble ? DBL80_MAX_10_EXP : MSVCRT_DBL_MAX_10_EXP))
|
||||
return fpnum(sign, INT_MAX, 1, FP_ROUND_ZERO);
|
||||
/* Count part of exponent stored in denormalized mantissa. */
|
||||
/* Increase exponent range to handle subnormals. */
|
||||
if(dp-1 < MSVCRT_DBL_MIN_10_EXP-MSVCRT_DBL_DIG-18)
|
||||
if(dp-1 < (ldouble ? DBL80_MIN_10_EXP : MSVCRT_DBL_MIN_10_EXP-MSVCRT_DBL_DIG-18))
|
||||
return fpnum(sign, INT_MIN, 1, FP_ROUND_ZERO);
|
||||
|
||||
while(dp > 3*LIMB_DIGITS) {
|
||||
|
@ -847,6 +970,24 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
|
|||
return fpnum(sign, e2, m, round);
|
||||
}
|
||||
|
||||
struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
|
||||
void *ctx, MSVCRT_pthreadlocinfo locinfo, BOOL ldouble)
|
||||
{
|
||||
if(!ldouble) {
|
||||
BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC64])];
|
||||
struct bnum *b = (struct bnum*)bnum_data;
|
||||
|
||||
b->size = BNUM_PREC64;
|
||||
return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
|
||||
} else {
|
||||
BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC80])];
|
||||
struct bnum *b = (struct bnum*)bnum_data;
|
||||
|
||||
b->size = BNUM_PREC80;
|
||||
return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
|
||||
}
|
||||
}
|
||||
|
||||
static MSVCRT_wchar_t strtod_str_get(void *ctx)
|
||||
{
|
||||
const char **p = ctx;
|
||||
|
@ -888,7 +1029,7 @@ static inline double strtod_helper(const char *str, char **end, MSVCRT__locale_t
|
|||
p++;
|
||||
beg = p;
|
||||
|
||||
fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo);
|
||||
fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, FALSE);
|
||||
if (end) *end = (p == beg ? (char*)str : (char*)p);
|
||||
|
||||
err = fpnum_double(&fp, &ret);
|
||||
|
@ -1300,15 +1441,30 @@ MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t l
|
|||
int CDECL __STRINGTOLD_L( MSVCRT__LDOUBLE *value, char **endptr,
|
||||
const char *str, int flags, MSVCRT__locale_t locale )
|
||||
{
|
||||
#ifdef HAVE_STRTOLD
|
||||
long double ld;
|
||||
FIXME("%p %p %s %x %p partial stub\n", value, endptr, str, flags, locale );
|
||||
ld = strtold(str,0);
|
||||
memcpy(value, &ld, 10);
|
||||
#else
|
||||
FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
|
||||
#endif
|
||||
return 0;
|
||||
MSVCRT_pthreadlocinfo locinfo;
|
||||
const char *beg, *p;
|
||||
int err, ret = 0;
|
||||
struct fpnum fp;
|
||||
|
||||
if (flags) FIXME("flags not supported: %x\n", flags);
|
||||
|
||||
if (!locale)
|
||||
locinfo = get_locinfo();
|
||||
else
|
||||
locinfo = locale->locinfo;
|
||||
|
||||
p = str;
|
||||
while (MSVCRT__isspace_l((unsigned char)*p, locale))
|
||||
p++;
|
||||
beg = p;
|
||||
|
||||
fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, TRUE);
|
||||
if (endptr) *endptr = (p == beg ? (char*)str : (char*)p);
|
||||
if (p == beg) ret = 4;
|
||||
|
||||
err = fpnum_ldouble(&fp, value);
|
||||
if (err) ret = (value->x80[2] & 0x7fff ? 2 : 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -529,7 +529,7 @@ double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
|
|||
p++;
|
||||
beg = p;
|
||||
|
||||
fp = fpnum_parse(strtod_wstr_get, strtod_wstr_unget, &p, locinfo);
|
||||
fp = fpnum_parse(strtod_wstr_get, strtod_wstr_unget, &p, locinfo, FALSE);
|
||||
if (end) *end = (p == beg ? (MSVCRT_wchar_t*)str : (MSVCRT_wchar_t*)p);
|
||||
|
||||
err = fpnum_double(&fp, &ret);
|
||||
|
|
Loading…
Reference in a new issue