mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-20 08:38:01 +00:00
msvcrt: Change strtod_l implementation.
This commit is contained in:
parent
815840e972
commit
f76eef7401
|
@ -23,8 +23,11 @@
|
||||||
|
|
||||||
#define _ISOC99_SOURCE
|
#define _ISOC99_SOURCE
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "wine/port.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "msvcrt.h"
|
#include "msvcrt.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
@ -141,13 +144,10 @@ double CDECL MSVCRT_atof( const char *str )
|
||||||
*/
|
*/
|
||||||
double CDECL MSVCRT_strtod_l( const char *str, char **end, MSVCRT__locale_t locale)
|
double CDECL MSVCRT_strtod_l( const char *str, char **end, MSVCRT__locale_t locale)
|
||||||
{
|
{
|
||||||
const char *p, *dec_point=NULL, *exp=NULL;
|
unsigned __int64 d=0, hlp;
|
||||||
char *copy;
|
int exp=0, sign=1;
|
||||||
|
const char *p;
|
||||||
double ret;
|
double ret;
|
||||||
int err = errno;
|
|
||||||
|
|
||||||
if(!locale)
|
|
||||||
locale = get_locale();
|
|
||||||
|
|
||||||
if(!str) {
|
if(!str) {
|
||||||
MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
|
MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
|
||||||
|
@ -155,45 +155,93 @@ double CDECL MSVCRT_strtod_l( const char *str, char **end, MSVCRT__locale_t loca
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!locale)
|
||||||
|
locale = get_locale();
|
||||||
|
|
||||||
/* FIXME: use *_l functions */
|
/* FIXME: use *_l functions */
|
||||||
p = str;
|
p = str;
|
||||||
while(isspace(*p))
|
while(isspace(*p))
|
||||||
p++;
|
p++;
|
||||||
if(*p=='+' || *p=='-')
|
|
||||||
|
if(*p == '-') {
|
||||||
|
sign = -1;
|
||||||
p++;
|
p++;
|
||||||
while(isdigit(*p))
|
} else if(*p == '+')
|
||||||
p++;
|
p++;
|
||||||
if(*p == *locale->locinfo->lconv->decimal_point) {
|
|
||||||
if(*p!='.')
|
while(isdigit(*p)) {
|
||||||
dec_point = p;
|
hlp = d*10+*(p++)-'0';
|
||||||
|
if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
|
||||||
|
exp++;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
d = hlp;
|
||||||
|
}
|
||||||
|
while(isdigit(*p)) {
|
||||||
|
exp++;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(*p == *locale->locinfo->lconv->decimal_point)
|
||||||
|
p++;
|
||||||
|
|
||||||
|
while(isdigit(*p)) {
|
||||||
|
hlp = d*10+*(p++)-'0';
|
||||||
|
if(d>MSVCRT_UI64_MAX/10 || hlp<d)
|
||||||
|
break;
|
||||||
|
|
||||||
|
d = hlp;
|
||||||
|
exp--;
|
||||||
|
}
|
||||||
while(isdigit(*p))
|
while(isdigit(*p))
|
||||||
p++;
|
p++;
|
||||||
if(*p=='d' || *p=='D')
|
|
||||||
exp = p;
|
|
||||||
|
|
||||||
/* FIXME: don't copy input string */
|
if(p == str) {
|
||||||
if((dec_point || exp) && (copy=_strdup(str))) {
|
|
||||||
if(dec_point)
|
|
||||||
copy[dec_point-str] = '.';
|
|
||||||
|
|
||||||
if(exp)
|
|
||||||
copy[exp-str] = 'e';
|
|
||||||
|
|
||||||
ret = strtod(copy, end);
|
|
||||||
if(end)
|
if(end)
|
||||||
*end = (char*)str+(*end-copy);
|
*end = (char*)str;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
MSVCRT_free(copy);
|
if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
|
||||||
} else
|
int e=0, s=1;
|
||||||
ret = strtod(str, end);
|
|
||||||
|
|
||||||
if(err != errno)
|
p++;
|
||||||
*MSVCRT__errno() = errno;
|
if(*p == '-') {
|
||||||
|
s = -1;
|
||||||
|
p++;
|
||||||
|
} else if(*p == '+')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
if(isdigit(*p)) {
|
||||||
|
while(isdigit(*p)) {
|
||||||
|
if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
|
||||||
|
e = INT_MAX;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
e *= s;
|
||||||
|
|
||||||
|
if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
|
||||||
|
else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
|
||||||
|
else exp += e;
|
||||||
|
} else {
|
||||||
|
if(*p=='-' || *p=='+')
|
||||||
|
p--;
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(exp>0)
|
||||||
|
ret = (double)sign*d*pow(10, exp);
|
||||||
|
else
|
||||||
|
ret = (double)sign*d/pow(10, -exp);
|
||||||
|
|
||||||
|
if((d && ret==0.0) || isinf(ret))
|
||||||
|
*MSVCRT__errno() = MSVCRT_ERANGE;
|
||||||
|
|
||||||
|
if(end)
|
||||||
|
*end = (char*)p;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
|
|
|
@ -1081,7 +1081,7 @@ static void test__strtoi64(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline BOOL almost_equal(double d1, double d2) {
|
static inline BOOL almost_equal(double d1, double d2) {
|
||||||
if(d1-d2>-1e-16 && d1-d2<1e-16)
|
if(d1-d2>-1e-30 && d1-d2<1e-30)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1093,6 +1093,7 @@ static void test__strtod(void)
|
||||||
const char double3[] = "INF";
|
const char double3[] = "INF";
|
||||||
const char double4[] = ".21e12";
|
const char double4[] = ".21e12";
|
||||||
const char double5[] = "214353e-3";
|
const char double5[] = "214353e-3";
|
||||||
|
const char overflow[] = "1d9999999999999999999";
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
double d;
|
double d;
|
||||||
|
@ -1106,8 +1107,8 @@ static void test__strtod(void)
|
||||||
ok(end == double2+7, "incorrect end (%d)\n", end-double2);
|
ok(end == double2+7, "incorrect end (%d)\n", end-double2);
|
||||||
|
|
||||||
d = strtod(double3, &end);
|
d = strtod(double3, &end);
|
||||||
todo_wine ok(almost_equal(d, 0), "d = %lf\n", d);
|
ok(almost_equal(d, 0), "d = %lf\n", d);
|
||||||
todo_wine ok(end == double3, "incorrect end (%d)\n", end-double3);
|
ok(end == double3, "incorrect end (%d)\n", end-double3);
|
||||||
|
|
||||||
d = strtod(double4, &end);
|
d = strtod(double4, &end);
|
||||||
ok(almost_equal(d, 210000000000.0), "d = %lf\n", d);
|
ok(almost_equal(d, 210000000000.0), "d = %lf\n", d);
|
||||||
|
@ -1127,12 +1128,37 @@ static void test__strtod(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
d = strtod("12.1", NULL);
|
d = strtod("12.1", NULL);
|
||||||
todo_wine ok(almost_equal(d, 12.0), "d = %lf\n", d);
|
ok(almost_equal(d, 12.0), "d = %lf\n", d);
|
||||||
|
|
||||||
d = strtod("12,1", NULL);
|
d = strtod("12,1", NULL);
|
||||||
ok(almost_equal(d, 12.1), "d = %lf\n", d);
|
ok(almost_equal(d, 12.1), "d = %lf\n", d);
|
||||||
|
|
||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
|
|
||||||
|
/* Precision tests */
|
||||||
|
d = strtod("0.1", NULL);
|
||||||
|
ok(almost_equal(d, 0.1), "d = %lf\n", d);
|
||||||
|
d = strtod("-0.1", NULL);
|
||||||
|
ok(almost_equal(d, -0.1), "d = %lf\n", d);
|
||||||
|
d = strtod("0.1281832188491894198128921", NULL);
|
||||||
|
ok(almost_equal(d, 0.1281832188491894198128921), "d = %lf\n", d);
|
||||||
|
d = strtod("0.82181281288121", NULL);
|
||||||
|
ok(almost_equal(d, 0.82181281288121), "d = %lf\n", d);
|
||||||
|
d = strtod("21921922352523587651128218821", NULL);
|
||||||
|
ok(almost_equal(d, 21921922352523587651128218821.0), "d = %lf\n", d);
|
||||||
|
d = strtod("0.1d238", NULL);
|
||||||
|
ok(almost_equal(d, 0.1e238L), "d = %lf\n", d);
|
||||||
|
d = strtod("0.1D-4736", NULL);
|
||||||
|
ok(almost_equal(d, 0.1e-4736L), "d = %lf\n", d);
|
||||||
|
|
||||||
|
errno = 0xdeadbeef;
|
||||||
|
d = strtod(overflow, &end);
|
||||||
|
ok(errno == ERANGE, "errno = %x\n", errno);
|
||||||
|
ok(end == overflow+21, "incorrect end (%d)\n", end-overflow);
|
||||||
|
|
||||||
|
errno = 0xdeadbeef;
|
||||||
|
strtod("-1d309", NULL);
|
||||||
|
ok(errno == ERANGE, "errno = %x\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
START_TEST(string)
|
START_TEST(string)
|
||||||
|
|
Loading…
Reference in a new issue