msvcrt: Added sprintf_p_l implementation.
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index 6d7718c..0a4fa93 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -1119,7 +1119,7 @@
@ cdecl _splitpath_s(str ptr long ptr long ptr long ptr long) msvcrt._splitpath_s
@ stub _sprintf_l
@ stub _sprintf_p
-@ stub _sprintf_p_l
+@ varargs _sprintf_p_l(ptr long str ptr) msvcrt._sprintf_p_l
@ stub _sprintf_s_l
@ varargs _sscanf_l(str str ptr) msvcrt._sscanf_l
@ varargs _sscanf_s_l(str str ptr) msvcrt._sscanf_s_l
@@ -1174,7 +1174,7 @@
@ stub _swprintf_c
@ stub _swprintf_c_l
@ stub _swprintf_p
-@ stub _swprintf_p_l
+@ varargs _swprintf_p_l(ptr long wstr ptr) msvcrt._swprintf_p_l
@ stub _swprintf_s_l
@ varargs _swscanf_l(wstr wstr ptr) msvcrt._swscanf_l
@ varargs _swscanf_s_l(wstr wstr ptr) msvcrt._swscanf_s_l
@@ -1259,8 +1259,8 @@
@ cdecl _vsnwprintf_s(ptr long long wstr ptr) msvcrt._vsnwprintf_s
@ cdecl _vsnwprintf_s_l(ptr long long wstr ptr ptr) msvcrt._vsnwprintf_s_l
@ stub _vsprintf_l
-@ stub _vsprintf_p
-@ stub _vsprintf_p_l
+@ cdecl _vsprintf_p(ptr long str ptr) msvcrt._vsprintf_p
+@ cdecl _vsprintf_p_l(ptr long str ptr ptr) msvcrt._vsprintf_p_l
@ stub _vsprintf_s_l
@ cdecl _vswprintf(ptr long wstr ptr) msvcrt._vswprintf
@ cdecl _vswprintf_c(ptr long wstr ptr) msvcrt._vswprintf_c
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index fa2a271..d8a5ca3 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -973,7 +973,7 @@
@ cdecl _splitpath_s(str ptr long ptr long ptr long ptr long) msvcrt._splitpath_s
@ stub _sprintf_l
@ stub _sprintf_p
-@ stub _sprintf_p_l
+@ varargs _sprintf_p_l(ptr long str ptr) msvcrt._sprintf_p_l
@ stub _sprintf_s_l
@ varargs _sscanf_l(str str ptr) msvcrt._sscanf_l
@ varargs _sscanf_s_l(str str ptr) msvcrt._sscanf_s_l
@@ -1027,7 +1027,7 @@
@ stub _swprintf
@ stub _swprintf_c
@ stub _swprintf_p
-@ stub _swprintf_p_l
+@ varargs _swprintf_p_l(ptr long wstr ptr) msvcrt._swprintf_p_l
@ stub _swprintf_s_l
@ varargs _swscanf_l(wstr wstr ptr) msvcrt._swscanf_l
@ varargs _swscanf_s_l(wstr wstr ptr) msvcrt._swscanf_s_l
@@ -1112,8 +1112,8 @@
@ cdecl _vsnwprintf_s(ptr long long wstr ptr) msvcrt._vsnwprintf_s
@ cdecl _vsnwprintf_s_l(ptr long long wstr ptr ptr) msvcrt._vsnwprintf_s_l
@ stub _vsprintf_l
-@ stub _vsprintf_p
-@ stub _vsprintf_p_l
+@ cdecl _vsprintf_p(ptr long str ptr) msvcrt._vsprintf_p
+@ cdecl _vsprintf_p_l(ptr long str ptr ptr) msvcrt._vsprintf_p_l
@ stub _vsprintf_s_l
@ cdecl _vswprintf(ptr long wstr ptr) msvcrt._vswprintf
@ cdecl _vswprintf_c(ptr long wstr ptr) msvcrt._vswprintf_c
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index cbf4f74..56d8c2d 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -959,7 +959,7 @@
@ cdecl _splitpath_s(str ptr long ptr long ptr long ptr long) msvcrt._splitpath_s
@ stub _sprintf_l
@ stub _sprintf_p
-@ stub _sprintf_p_l
+@ varargs _sprintf_p_l(ptr long str ptr) msvcrt._sprintf_p_l
@ stub _sprintf_s_l
@ varargs _sscanf_l(str str ptr) msvcrt._sscanf_l
@ varargs _sscanf_s_l(str str ptr) msvcrt._sscanf_s_l
@@ -1014,7 +1014,7 @@
@ stub _swprintf_c
@ stub _swprintf_c_l
@ stub _swprintf_p
-@ stub _swprintf_p_l
+@ varargs _swprintf_p_l(ptr long wstr ptr) msvcrt._swprintf_p_l
@ stub _swprintf_s_l
@ varargs _swscanf_l(wstr wstr ptr) msvcrt._swscanf_l
@ varargs _swscanf_s_l(wstr wstr ptr) msvcrt._swscanf_s_l
@@ -1099,8 +1099,8 @@
@ cdecl _vsnwprintf_s(ptr long long wstr ptr) msvcrt._vsnwprintf_s
@ cdecl _vsnwprintf_s_l(ptr long long wstr ptr ptr) msvcrt._vsnwprintf_s_l
@ stub _vsprintf_l
-@ stub _vsprintf_p
-@ stub _vsprintf_p_l
+@ cdecl _vsprintf_p(ptr long str ptr) msvcrt._vsprintf_p
+@ cdecl _vsprintf_p_l(ptr long str ptr ptr) msvcrt._vsprintf_p_l
@ stub _vsprintf_s_l
@ cdecl _vswprintf(ptr long wstr ptr) msvcrt._vswprintf
@ cdecl _vswprintf_c(ptr long wstr ptr) msvcrt._vswprintf_c
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index 4fcdb14..852fe92 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -916,6 +916,7 @@
#define MSVCRT_CHECK_PMT(x) ((x) || (MSVCRT_INVALID_PMT(0),FALSE))
#endif
+#define MSVCRT__ARGMAX 100
typedef int (*puts_clbk_a)(void*, int, const char*);
typedef int (*puts_clbk_w)(void*, int, const MSVCRT_wchar_t*);
typedef union _printf_arg
@@ -931,6 +932,7 @@
int pf_printf_w(puts_clbk_w, void*, const MSVCRT_wchar_t*, MSVCRT__locale_t,
BOOL, BOOL, args_clbk, void*, __ms_va_list);
printf_arg arg_clbk_valist(void*, int, int, __ms_va_list*);
+printf_arg arg_clbk_positional(void*, int, int, __ms_va_list*);
#define MSVCRT__OVERFLOW 3
#define MSVCRT__UNDERFLOW 4
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index aaaca94..c1e7b75 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -901,7 +901,7 @@
@ cdecl _splitpath(str ptr ptr ptr ptr)
@ cdecl _splitpath_s(str ptr long ptr long ptr long ptr long)
# stub _sprintf_l
-# stub _sprintf_p_l
+@ varargs _sprintf_p_l(ptr long str ptr) MSVCRT_sprintf_p_l
# stub _sprintf_s_l
@ varargs _sscanf_l(str str ptr) MSVCRT__sscanf_l
@ varargs _sscanf_s_l(str str ptr) MSVCRT__sscanf_s_l
@@ -954,7 +954,7 @@
# stub _swprintf
# stub _swprintf_c
# stub _swprintf_c_l
-# stub _swprintf_p_l
+@ varargs _swprintf_p_l(ptr long wstr ptr) MSVCRT_swprintf_p_l
# stub _swprintf_s_l
@ varargs _swscanf_l(wstr wstr ptr) MSVCRT__swscanf_l
@ varargs _swscanf_s_l(wstr wstr ptr) MSVCRT__swscanf_s_l
@@ -1035,14 +1035,14 @@
@ cdecl _vsnwprintf_s(ptr long long wstr ptr) MSVCRT_vsnwprintf_s
@ cdecl _vsnwprintf_s_l(ptr long long wstr ptr ptr) MSVCRT_vsnwprintf_s_l
# stub _vsprintf_l
-# stub _vsprintf_p
-# stub _vsprintf_p_l
+@ cdecl _vsprintf_p(ptr long str ptr) MSVCRT_vsprintf_p
+@ cdecl _vsprintf_p_l(ptr long str ptr ptr) MSVCRT_vsprintf_p_l
# stub _vsprintf_s_l
@ cdecl _vswprintf(ptr long wstr ptr) MSVCRT_vsnwprintf
@ cdecl _vswprintf_c(ptr long wstr ptr) MSVCRT_vsnwprintf
@ cdecl _vswprintf_c_l(ptr long wstr ptr ptr) MSVCRT_vsnwprintf_l
@ cdecl _vswprintf_l(ptr long wstr ptr ptr) MSVCRT_vsnwprintf_l
-@ cdecl _vswprintf_p_l(ptr long wstr ptr ptr) MSVCRT_vsnwprintf_l
+@ cdecl _vswprintf_p_l(ptr long wstr ptr ptr) MSVCRT_vswprintf_p_l
@ cdecl _vswprintf_s_l(ptr long wstr ptr ptr) MSVCRT_vswprintf_s_l
# stub _vwprintf_l
# stub _vwprintf_p
diff --git a/dlls/msvcrt/printf.h b/dlls/msvcrt/printf.h
index 2db9b6c..104dd9c 100644
--- a/dlls/msvcrt/printf.h
+++ b/dlls/msvcrt/printf.h
@@ -553,6 +553,79 @@
return written;
}
+#ifndef PRINTF_WIDE
+enum types_clbk_flags {
+ TYPE_CLBK_VA_LIST = 1,
+ TYPE_CLBK_POSITIONAL = 2,
+ TYPE_CLBK_ERROR_POS = 4,
+ TYPE_CLBK_ERROR_TYPE = 8
+};
+
+/* This functions stores types of arguments. It uses args[0] internally */
+static printf_arg arg_clbk_type(void *ctx, int pos, int type, __ms_va_list *valist)
+{
+ static const printf_arg ret;
+ printf_arg *args = ctx;
+
+ if(pos == -1) {
+ args[0].get_int |= TYPE_CLBK_VA_LIST;
+ return ret;
+ } else
+ args[0].get_int |= TYPE_CLBK_POSITIONAL;
+
+ if(pos<1 || pos>MSVCRT__ARGMAX)
+ args[0].get_int |= TYPE_CLBK_ERROR_POS;
+ else if(args[pos].get_int && args[pos].get_int!=type)
+ args[0].get_int |= TYPE_CLBK_ERROR_TYPE;
+ else
+ args[pos].get_int = type;
+
+ return ret;
+}
+#endif
+
+static int FUNC_NAME(create_positional_ctx)(void *args_ctx, const APICHAR *format, __ms_va_list valist)
+{
+ struct FUNC_NAME(_str_ctx) puts_ctx = {INT_MAX, NULL};
+ printf_arg *args = args_ctx;
+ int i, j;
+
+ i = FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk_str), &puts_ctx, format, NULL, TRUE, FALSE,
+ arg_clbk_type, args_ctx, NULL);
+ if(i < 0)
+ return i;
+
+ if(args[0].get_int==0 || args[0].get_int==TYPE_CLBK_VA_LIST)
+ return 0;
+ if(args[0].get_int != TYPE_CLBK_POSITIONAL)
+ return -1;
+
+ for(i=MSVCRT__ARGMAX; i>0; i--)
+ if(args[i].get_int)
+ break;
+
+ for(j=1; j<=i; j++) {
+ switch(args[j].get_int) {
+ case VT_I8:
+ args[j].get_longlong = va_arg(valist, LONGLONG);
+ break;
+ case VT_INT:
+ args[j].get_int = va_arg(valist, int);
+ break;
+ case VT_R8:
+ args[j].get_double = va_arg(valist, double);
+ break;
+ case VT_PTR:
+ args[j].get_ptr = va_arg(valist, void*);
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ return j;
+}
+
#undef APICHAR
#undef CONVCHAR
#undef FUNC_NAME
diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c
index a121533..eb34ad8 100644
--- a/dlls/msvcrt/tests/printf.c
+++ b/dlls/msvcrt/tests/printf.c
@@ -44,6 +44,7 @@
static int (__cdecl *p__fcvt_s)(char *buffer, size_t length, double number,
int ndigits, int *decpt, int *sign);
static unsigned int (__cdecl *p__get_output_format)(void);
+static int (__cdecl *p__vsprintf_p)(char*, size_t, const char*, __ms_va_list);
static void init( void )
{
@@ -55,6 +56,7 @@
p__ecvt_s = (void *)GetProcAddress(hmod, "_ecvt_s");
p__fcvt_s = (void *)GetProcAddress(hmod, "_fcvt_s");
p__get_output_format = (void *)GetProcAddress(hmod, "_get_output_format");
+ p__vsprintf_p = (void*)GetProcAddress(hmod, "_vsprintf_p");
}
static void test_sprintf( void )
@@ -1050,6 +1052,47 @@
ok( !wcscmp(out1, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer));
}
+static int __cdecl _vsprintf_p_wrapper(char *str, size_t sizeOfBuffer,
+ const char *format, ...)
+{
+ int ret;
+ __ms_va_list valist;
+ __ms_va_start(valist, format);
+ ret = p__vsprintf_p(str, sizeOfBuffer, format, valist);
+ __ms_va_end(valist);
+ return ret;
+}
+
+static void test_vsprintf_p(void)
+{
+ char buf[1024];
+ int ret;
+
+ if(!p__vsprintf_p) {
+ win_skip("vsprintf_p not available\n");
+ return;
+ }
+
+ ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%s %d", "test", 1234);
+ ok(ret == 9, "ret = %d\n", ret);
+ ok(!memcmp(buf, "test 1234", 10), "buf = %s\n", buf);
+
+ ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%1$d", 1234, "additional param");
+ ok(ret == 4, "ret = %d\n", ret);
+ ok(!memcmp(buf, "1234", 5), "buf = %s\n", buf);
+
+ ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%2$s %1$d", 1234, "test");
+ ok(ret == 9, "ret = %d\n", ret);
+ ok(!memcmp(buf, "test 1234", 10), "buf = %s\n", buf);
+
+ ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%2$*3$s %2$.*1$s", 2, "test", 3);
+ ok(ret == 7, "ret = %d\n", ret);
+ ok(!memcmp(buf, "test te", 8), "buf = %s\n", buf);
+
+ /* Following test invokes invalid parameter handler */
+ /* ret = _vsprintf_p_wrapper(buf, sizeof(buf), "%d %1$d", 1234); */
+}
+
static void test__get_output_format(void)
{
unsigned int ret;
@@ -1078,5 +1121,6 @@
test_vscprintf();
test_vscwprintf();
test_vsnwprintf_s();
+ test_vsprintf_p();
test__get_output_format();
}
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index 053d6e7..c0cdde1 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -437,6 +437,15 @@
}
/*********************************************************************
+ * arg_clbk_positional (INTERNAL)
+ */
+printf_arg arg_clbk_positional(void *ctx, int pos, int type, __ms_va_list *valist)
+{
+ printf_arg *args = ctx;
+ return args[pos];
+}
+
+/*********************************************************************
* _vsnprintf (MSVCRT.@)
*/
int CDECL MSVCRT_vsnprintf( char *str, MSVCRT_size_t len,
@@ -790,6 +799,105 @@
}
/*********************************************************************
+ * _vsprintf_p_l (MSVCRT.@)
+ */
+int CDECL MSVCRT_vsprintf_p_l(char *buffer, MSVCRT_size_t length, const char *format,
+ MSVCRT__locale_t locale, __ms_va_list args)
+{
+ static const char nullbyte = '\0';
+ printf_arg args_ctx[MSVCRT__ARGMAX+1];
+ struct _str_ctx_a puts_ctx = {length, buffer};
+ int ret;
+
+ memset(args_ctx, 0, sizeof(args_ctx));
+
+ ret = create_positional_ctx_a(args_ctx, format, args);
+ if(ret < 0) {
+ MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
+ *MSVCRT__errno() = MSVCRT_EINVAL;
+ return ret;
+ } else if(ret == 0)
+ ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale, FALSE, TRUE,
+ arg_clbk_valist, NULL, args);
+ else
+ ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale, TRUE, TRUE,
+ arg_clbk_positional, args_ctx, NULL);
+
+ puts_clbk_str_a(&puts_ctx, 1, &nullbyte);
+ return ret;
+}
+
+/*********************************************************************
+ * _vsprintf_p (MSVCRT.@)
+ */
+int CDECL MSVCRT_vsprintf_p(char *buffer, MSVCRT_size_t length,
+ const char *format, __ms_va_list args)
+{
+ return MSVCRT_vsprintf_p_l(buffer, length, format, NULL, args);
+}
+
+/*********************************************************************
+ * _sprintf_p_l (MSVCRT.@)
+ */
+int CDECL MSVCRT_sprintf_p_l(char *buffer, MSVCRT_size_t length,
+ const char *format, MSVCRT__locale_t locale, ...)
+{
+ __ms_va_list valist;
+ int r;
+
+ __ms_va_start(valist, locale);
+ r = MSVCRT_vsprintf_p_l(buffer, length, format, locale, valist);
+ __ms_va_end(valist);
+
+ return r;
+}
+
+/*********************************************************************
+ * _vswprintf_p_l (MSVCRT.@)
+ */
+int CDECL MSVCRT_vswprintf_p_l(MSVCRT_wchar_t *buffer, MSVCRT_size_t length,
+ const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list args)
+{
+ static const MSVCRT_wchar_t nullbyte = '\0';
+ printf_arg args_ctx[MSVCRT__ARGMAX+1];
+ struct _str_ctx_w puts_ctx = {length, buffer};
+ int ret;
+
+ memset(args_ctx, 0, sizeof(args_ctx));
+
+ ret = create_positional_ctx_w(args_ctx, format, args);
+ if(ret < 0) {
+ MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
+ *MSVCRT__errno() = MSVCRT_EINVAL;
+ return ret;
+ } else if(ret == 0)
+ ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, TRUE, TRUE,
+ arg_clbk_valist, NULL, args);
+ else
+ ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, TRUE, TRUE,
+ arg_clbk_positional, args_ctx, NULL);
+
+ puts_clbk_str_w(&puts_ctx, 1, &nullbyte);
+ return ret;
+}
+
+/*********************************************************************
+ * _swprintf_p_l (MSVCRT.@)
+ */
+int CDECL MSVCRT_swprintf_p_l(MSVCRT_wchar_t *buffer, MSVCRT_size_t length,
+ const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, ...)
+{
+ __ms_va_list valist;
+ int r;
+
+ __ms_va_start(valist, locale);
+ r = MSVCRT_vswprintf_p_l(buffer, length, format, locale, valist);
+ __ms_va_end(valist);
+
+ return r;
+}
+
+/*********************************************************************
* wcscoll (MSVCRT.@)
*/
int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
diff --git a/include/msvcrt/crtdefs.h b/include/msvcrt/crtdefs.h
index 5232e80..9685a99 100644
--- a/include/msvcrt/crtdefs.h
+++ b/include/msvcrt/crtdefs.h
@@ -97,6 +97,8 @@
# endif
#endif
+#define _ARGMAX 100
+
#ifndef _MSVCRT_LONG_DEFINED
#define _MSVCRT_LONG_DEFINED
/* we need 32-bit longs even on 64-bit */