msvcrt: Implement ecvt_s.
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index 9f2a147..82606e2 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -583,7 +583,7 @@
@ cdecl _dup2(long long) msvcrt._dup2
@ cdecl _dupenv_s(ptr ptr str) msvcrt._dupenv_s
@ cdecl _ecvt(double long ptr ptr) msvcrt._ecvt
-@ stub _ecvt_s
+@ cdecl _ecvt_s(str long double long ptr ptr) msvcrt._ecvt_s
@ cdecl _encoded_null() msvcr90._encoded_null
@ cdecl _endthread() msvcrt._endthread
@ cdecl _endthreadex(long) msvcrt._endthreadex
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index 1512347..e54eea6 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -423,7 +423,7 @@
@ cdecl _dup2(long long) msvcrt._dup2
@ cdecl _dupenv_s(ptr ptr str) msvcrt._dupenv_s
@ cdecl _ecvt(double long ptr ptr) msvcrt._ecvt
-@ stub _ecvt_s
+@ cdecl _ecvt_s(str long double long ptr ptr) msvcrt._ecvt_s
@ cdecl _encode_pointer(ptr) msvcr90._encode_pointer
@ cdecl _encoded_null() msvcr90._encoded_null
@ cdecl _endthread() msvcrt._endthread
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index feaf80e..5baee98 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -415,7 +415,7 @@
@ cdecl _dup2(long long) msvcrt._dup2
@ cdecl _dupenv_s(ptr ptr str) msvcrt._dupenv_s
@ cdecl _ecvt(double long ptr ptr) msvcrt._ecvt
-@ stub _ecvt_s
+@ cdecl _ecvt_s(str long double long ptr ptr) msvcrt._ecvt_s
@ cdecl _encode_pointer(ptr) MSVCR90_encode_pointer
@ cdecl _encoded_null()
@ cdecl _endthread() msvcrt._endthread
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index 6fb0549..d2110cb 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -1104,6 +1104,72 @@
return data->efcvt_buffer;
}
+/*********************************************************************
+ * _ecvt_s (MSVCRT.@)
+ */
+int CDECL _ecvt_s( char *buffer, MSVCRT_size_t length, double number, int ndigits, int *decpt, int *sign )
+{
+ int prec, len;
+ char *result;
+ const char infret[] = "1#INF";
+
+ if(!MSVCRT_CHECK_PMT(buffer != NULL) || !MSVCRT_CHECK_PMT(decpt != NULL) || !MSVCRT_CHECK_PMT(sign != NULL))
+ {
+ *MSVCRT__errno() = MSVCRT_EINVAL;
+ return MSVCRT_EINVAL;
+ }
+ if(!MSVCRT_CHECK_PMT(length > 2) || !MSVCRT_CHECK_PMT(ndigits < (int)length - 1))
+ {
+ *MSVCRT__errno() = MSVCRT_ERANGE;
+ return MSVCRT_ERANGE;
+ }
+
+ /* special case - inf */
+ if(number == HUGE_VAL || number == -HUGE_VAL)
+ {
+ memset(buffer, '0', ndigits);
+ memcpy(buffer, infret, min(ndigits, sizeof(infret) - 1 ) );
+ buffer[ndigits] = '\0';
+ (*decpt) = 1;
+ if(number == -HUGE_VAL)
+ (*sign) = 1;
+ else
+ (*sign) = 0;
+ return 0;
+ }
+ result = (char*)MSVCRT_malloc(max(ndigits + 7, 7));
+
+ if( number < 0) {
+ *sign = TRUE;
+ number = -number;
+ } else
+ *sign = FALSE;
+ /* handle cases with zero ndigits or less */
+ prec = ndigits;
+ if( prec < 1) prec = 2;
+ len = snprintf(result, 80, "%.*le", prec - 1, number);
+ /* take the decimal "point away */
+ if( prec != 1)
+ memmove( result + 1, result + 2, len - 1 );
+ /* take the exponential "e" out */
+ result[ prec] = '\0';
+ /* read the exponent */
+ sscanf( result + prec + 1, "%d", decpt);
+ (*decpt)++;
+ /* adjust for some border cases */
+ if( result[0] == '0')/* value is zero */
+ *decpt = 0;
+ /* handle cases with zero ndigits or less */
+ if( ndigits < 1){
+ if( result[ 0] >= '5')
+ (*decpt)++;
+ result[ 0] = '\0';
+ }
+ memcpy( buffer, result, max(ndigits + 1, 1) );
+ MSVCRT_free( result );
+ return 0;
+}
+
/***********************************************************************
* _fcvt (MSVCRT.@)
*/
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index 9fe5f64..ba8c9ea 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -378,7 +378,7 @@
@ cdecl _dup (long) MSVCRT__dup
@ cdecl _dup2 (long long) MSVCRT__dup2
@ cdecl _ecvt(double long ptr ptr)
-# stub _ecvt_s
+@ cdecl _ecvt_s(str long double long ptr ptr)
@ cdecl _endthread ()
@ cdecl _endthreadex(long)
@ extern _environ MSVCRT__environ