diff --git a/dlls/msvcrt/main.c b/dlls/msvcrt/main.c index 272ba71f4c9..4ae52c70a57 100644 --- a/dlls/msvcrt/main.c +++ b/dlls/msvcrt/main.c @@ -123,15 +123,3 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) } return TRUE; } - -/********************************************************************* - * $I10_OUTPUT (MSVCRT.@) - * Function not really understood but needed to make the DLL work - */ -void CDECL MSVCRT_I10_OUTPUT(void) -{ - /* FIXME: This is probably data, not a function */ - /* no it is a function. I10 is an Int of 10 bytes */ - /* also known as 80 bit floating point (long double */ - /* for some compilers, not MSVC) */ -} diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index c7d66545b8c..1bf3f6db263 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -1,6 +1,6 @@ # msvcrt.dll - MS VC++ Run Time Library -@ cdecl $I10_OUTPUT() MSVCRT_I10_OUTPUT +@ cdecl -norelay $I10_OUTPUT(double long long long ptr) MSVCRT_I10_OUTPUT @ cdecl -i386 -norelay ??0__non_rtti_object@@QAE@ABV0@@Z(ptr) __thiscall_MSVCRT___non_rtti_object_copy_ctor @ cdecl -i386 -norelay ??0__non_rtti_object@@QAE@PBD@Z(ptr) __thiscall_MSVCRT___non_rtti_object_ctor @ cdecl -i386 -norelay ??0bad_cast@@AAE@PBQBD@Z(ptr) __thiscall_MSVCRT_bad_cast_ctor diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index 21dc29f166b..8c993992223 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -26,6 +26,7 @@ #include "wine/port.h" #include +#include #include #include #include @@ -669,3 +670,98 @@ int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str, memcpy(str, pos, buffer-pos+65); return 0; } + +#define I10_OUTPUT_MAX_PREC 21 +/* Internal structure used by $I10_OUTPUT */ +struct _I10_OUTPUT_DATA { + short pos; + char sign; + BYTE len; + char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */ +}; + +/********************************************************************* + * $I10_OUTPUT (MSVCRT.@) + * ld - long double to be printed to data + * prec - precision of part, we're interested in + * flag - 0 for first prec digits, 1 for fractional part + * data - data to be populated + * + * return value + * 0 if given double is NaN or INF + * 1 otherwise + * + * FIXME + * Native sets last byte of data->str to '0' or '9', I don't know what + * it means. Current implementation sets it always to '0'. + */ +int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld, int prec, int flag, struct _I10_OUTPUT_DATA *data) +{ + static const char inf_str[] = "1#INF"; + static const char nan_str[] = "1#QNAN"; + + double d = ld.x; + char format[8]; + char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */ + char *p; + + TRACE("(%lf %d %x %p)\n", d, prec, flag, data); + + if(d<0) { + data->sign = '-'; + d = -d; + } else + data->sign = ' '; + + if(isinf(d)) { + data->pos = 1; + data->len = 5; + memcpy(data->str, inf_str, sizeof(inf_str)); + + return 0; + } + + if(isnan(d)) { + data->pos = 1; + data->len = 6; + memcpy(data->str, nan_str, sizeof(nan_str)); + + return 0; + } + + if(flag&1) { + int exp = 1+floor(log10(d)); + + prec += exp; + if(exp < 0) + prec--; + } + prec--; + + if(prec+1 > I10_OUTPUT_MAX_PREC) + prec = I10_OUTPUT_MAX_PREC-1; + else if(prec < 0) { + d = 0.0; + prec = 0; + } + + sprintf(format, "%%.%dle", prec); + sprintf(buf, format, d); + + buf[1] = buf[0]; + data->pos = atoi(buf+prec+3); + if(buf[1] != '0') + data->pos++; + + for(p = buf+prec+1; p>buf+1 && *p=='0'; p--); + data->len = p-buf; + + memcpy(data->str, buf+1, data->len); + data->str[data->len] = '\0'; + + if(buf[1]!='0' && prec-data->len+1>0) + memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1); + + return 1; +} +#undef I10_OUTPUT_MAX_PREC diff --git a/dlls/msvcrt/tests/misc.c b/dlls/msvcrt/tests/misc.c index d8b1b88b91a..68f47f8b309 100644 --- a/dlls/msvcrt/tests/misc.c +++ b/dlls/msvcrt/tests/misc.c @@ -24,6 +24,7 @@ static int (__cdecl *prand_s)(unsigned int *); static int (__cdecl *memcpy_s)(void *, MSVCRT_size_t, void*, MSVCRT_size_t); +static int (__cdecl *pI10_OUTPUT)(long double, int, int, void*); static void init(void) { @@ -31,6 +32,7 @@ static void init(void) prand_s = (void *)GetProcAddress(hmod, "rand_s"); memcpy_s = (void*)GetProcAddress(hmod, "memcpy_s"); + pI10_OUTPUT = (void*)GetProcAddress(hmod, "$I10_OUTPUT"); } static void test_rand_s(void) @@ -104,10 +106,97 @@ static void test_memcpy_s(void) ok(dest[0] == '\0', "dest[0] != \'\\0\'\n"); } +typedef struct _I10_OUTPUT_data { + short pos; + char sign; + BYTE len; + char str[100]; +} I10_OUTPUT_data; + +typedef struct _I10_OUTPUT_test { + long double d; + int size; + int flags; + + I10_OUTPUT_data out; + int ret; + const char *remain; +} I10_OUTPUT_test; + +static const I10_OUTPUT_test I10_OUTPUT_tests[] = { + /* arg3 = 0 */ + { 0.0, 10, 0, {0, ' ', 1, "0"}, 1, "" }, + { 1.0, 10, 0, {1, ' ', 1, "1"}, 1, "000000009" }, + { -1.0, 10, 0, {1, '-', 1, "1"}, 1, "000000009" }, + { 1.23, 10, 0, {1, ' ', 3, "123"}, 1, "0000009" }, + { 1e13, 10, 0, {14, ' ', 1, "1"}, 1, "000000009" }, + { 1e30, 30, 0, {31, ' ', 21, "100000000000000001988"}, 1, "" }, + { 1e-13, 10, 0, {-12, ' ', 1, "1"}, 1, "000000000" }, + { 0.25, 10, 0, {0, ' ', 2, "25"}, 1, "00000000" }, + { 1.0000001, 10, 0, {1, ' ', 8, "10000001"}, 1, "00" }, + /* arg3 = 1 */ + { 0.0, 10, 1, {0, ' ', 1, "0"}, 1, "" }, + { 1.0, 10, 1, {1, ' ', 1, "1"}, 1, "0000000009" }, + { -1.0, 10, 1, {1, '-', 1, "1"}, 1, "0000000009" }, + { 1.23, 10, 1, {1, ' ', 3, "123"}, 1, "00000009" }, + { 1e13, 10, 1, {14, ' ', 1, "1"}, 1, "00000000000000000009" }, + { 1e30, 30, 1, {31, ' ', 21, "100000000000000001988"}, 1, "" }, + { 1e-13, 10, 1, {0, ' ', 1, "0"}, 1, "" }, + { 1e-7, 10, 1, {-6, ' ', 1, "1"}, 1, "09" }, + { 0.25, 10, 1, {0, ' ', 2, "25"}, 1, "00000000" }, + { 1.0000001, 10, 1, {1, ' ', 8, "10000001"}, 1, "000" }, + /* too small buffer */ + { 0.0, 0, 0, {0, ' ', 1, "0"}, 1, "" }, + { 0.0, 0, 1, {0, ' ', 1, "0"}, 1, "" }, + { 123.0, 2, 0, {3, ' ', 2, "12"}, 1, "" }, + { 123.0, 0, 0, {0, ' ', 1, "0"}, 1, "" }, + { 123.0, 2, 1, {3, ' ', 3, "123"}, 1, "09" }, + { 0.99, 1, 0, {1, ' ', 1, "1"}, 1, "" }, + { 1264567.0, 2, 0, {7, ' ', 2, "13"}, 1, "" }, + { 1264567.0, 2, 1, {7, ' ', 7, "1264567"}, 1, "00" }, + { 1234567891.0, 2, 1, {10, ' ', 10, "1234567891"}, 1, "09" } +}; + +static void test_I10_OUTPUT(void) +{ + I10_OUTPUT_data out; + int i, j, ret; + + if(!pI10_OUTPUT) { + win_skip("I10_OUTPUT not available\n"); + return; + } + + for(i=0; i