Alexandre Julliard : kernel32: Reimplement the formatting of inserts in FormatMessageW.
Alexandre Julliard
julliard at winehq.org
Fri Oct 30 11:04:28 CDT 2009
Module: wine
Branch: master
Commit: b381958f7879e90a0e501982acd192acc11b8411
URL: http://source.winehq.org/git/wine.git/?a=commit;h=b381958f7879e90a0e501982acd192acc11b8411
Author: Alexandre Julliard <julliard at winehq.org>
Date: Thu Oct 29 17:36:45 2009 +0100
kernel32: Reimplement the formatting of inserts in FormatMessageW.
---
dlls/kernel32/format_msg.c | 186 ++++++++++++++++++++++++++++++--------------
1 files changed, 127 insertions(+), 59 deletions(-)
diff --git a/dlls/kernel32/format_msg.c b/dlls/kernel32/format_msg.c
index dd10efa..18b4f96 100644
--- a/dlls/kernel32/format_msg.c
+++ b/dlls/kernel32/format_msg.c
@@ -256,6 +256,126 @@ static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, __ms_va_li
}
+/**********************************************************************
+ * format_insertW (internal)
+ */
+static LPCWSTR format_insertW( int insert, LPCWSTR format, DWORD flags, __ms_va_list *args, LPWSTR *result)
+{
+ static const WCHAR fmt_lu[] = {'%','l','u',0};
+ WCHAR *wstring = NULL, *p, fmt[256];
+ ULONG_PTR arg;
+ int size;
+
+ if (*format != '!') /* simple string */
+ {
+ WCHAR *str = (WCHAR *)get_arg( insert, flags, args );
+ *result = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) );
+ strcpyW( *result, str );
+ return format;
+ }
+
+ format++;
+ p = fmt;
+ *p++ = '%';
+
+ while (*format == '0' ||
+ *format == '+' ||
+ *format == '-' ||
+ *format == ' ' ||
+ *format == '*' ||
+ *format == '#')
+ {
+ if (*format == '*')
+ {
+ p += sprintfW( p, fmt_lu, get_arg( insert, flags, args ));
+ insert++;
+ format++;
+ }
+ else *p++ = *format++;
+ }
+ while (isdigitW(*format)) *p++ = *format++;
+
+ if (*format == '.')
+ {
+ *p++ = *format++;
+ if (*format == '*')
+ {
+ p += sprintfW( p, fmt_lu, get_arg( insert, flags, args ));
+ insert++;
+ format++;
+ }
+ else
+ while (isdigitW(*format)) *p++ = *format++;
+ }
+
+ arg = get_arg( insert, flags, args );
+
+ /* check for ascii string format */
+ if ((format[0] == 'h' && format[1] == 's') ||
+ (format[0] == 'h' && format[1] == 'S') ||
+ (format[0] == 'S'))
+ {
+ DWORD len = MultiByteToWideChar( CP_ACP, 0, (char *)arg, -1, /*FIXME*/ NULL, 0 );
+ wstring = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ MultiByteToWideChar( CP_ACP, 0, (char *)arg, -1, wstring, len );
+ arg = (ULONG_PTR)wstring;
+ *p++ = 's';
+ }
+ /* check for ascii character format */
+ else if ((format[0] == 'h' && format[1] == 'c') ||
+ (format[0] == 'h' && format[1] == 'C') ||
+ (format[0] == 'C'))
+ {
+ char ch = arg;
+ wstring = HeapAlloc( GetProcessHeap(), 0, 2 );
+ MultiByteToWideChar( CP_ACP, 0, &ch, 1, wstring, 1 );
+ wstring[1] = 0;
+ arg = (ULONG_PTR)wstring;
+ *p++ = 's';
+ }
+ /* check for wide string format */
+ else if ((format[0] == 'l' && format[1] == 's') ||
+ (format[0] == 'l' && format[1] == 'S') ||
+ (format[0] == 'w' && format[1] == 's'))
+ {
+ *p++ = 's';
+ }
+ /* check for wide character format */
+ else if ((format[0] == 'l' && format[1] == 'c') ||
+ (format[0] == 'l' && format[1] == 'C') ||
+ (format[0] == 'w' && format[1] == 'c'))
+ {
+ *p++ = 'c';
+ }
+ /* FIXME: handle I64 etc. */
+ else while (*format && *format != '!') *p++ = *format++;
+
+ *p = 0;
+ size = 256;
+ for (;;)
+ {
+ WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
+ int needed = snprintfW( ret, size, fmt, arg );
+ if (needed == -1 || needed >= size)
+ {
+ HeapFree( GetProcessHeap(), 0, ret );
+ size = max( needed + 1, size * 2 );
+ }
+ else
+ {
+ *result = ret;
+ break;
+ }
+ }
+
+ while (*format && *format != '!') format++;
+ if (*format == '!') format++;
+
+ HeapFree( GetProcessHeap(), 0, wstring );
+ return format;
+}
+
+
/***********************************************************************
* FormatMessageA (KERNEL32.@)
* FIXME: missing wrap,
@@ -439,18 +559,17 @@ DWORD WINAPI FormatMessageW(
DWORD dwLanguageId,
LPWSTR lpBuffer,
DWORD nSize,
- __ms_va_list* _args )
+ __ms_va_list* args )
{
- LPDWORD args=(LPDWORD)_args;
#if defined(__i386__) || defined(__sparc__)
/* This implementation is completely dependent on the format of the va_list on x86 CPUs */
LPWSTR target,t;
DWORD talloced;
- LPWSTR from,f;
+ LPWSTR from;
+ LPCWSTR f;
DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
BOOL eos = FALSE;
WCHAR ch;
- static const WCHAR fmt_wc[] = {'%','w','c',0};
TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
@@ -508,10 +627,8 @@ DWORD WINAPI FormatMessageW(
while (*f && !eos) {
if (*f=='%') {
int insertnr;
- WCHAR *fmtstr,*sprintfbuf,*x;
- DWORD *argliststart;
+ WCHAR *str,*x;
- fmtstr = NULL;
f++;
if (!*f) {
ADD_TO_T('%');
@@ -534,58 +651,9 @@ DWORD WINAPI FormatMessageW(
f++;
break;
}
- if (*f=='!') {
- f++;
- if (NULL!=(x=strchrW(f,'!'))) {
- *x='\0';
- fmtstr=HeapAlloc( GetProcessHeap(), 0,(strlenW(f)+2)*sizeof(WCHAR));
- sprintfW(fmtstr,PCNTFMTWSTR,f);
- f=x+1;
- } else {
- fmtstr=HeapAlloc(GetProcessHeap(),0,(strlenW(f)+2)*sizeof(WCHAR));
- sprintfW(fmtstr,PCNTFMTWSTR,f);
- f+=strlenW(f); /*at \0*/
- }
- } else {
- if(!args) break;
- fmtstr = HeapAlloc( GetProcessHeap(),0,3*sizeof(WCHAR));
- strcpyW( fmtstr, FMTWSTR );
- }
- if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
- argliststart=args+insertnr-1;
- else
- argliststart=(*(DWORD**)args)+insertnr-1;
-
- if (fmtstr[strlenW(fmtstr)-1]=='s' && argliststart[0]) {
- DWORD xarr[3];
- WCHAR *fmt_end = fmtstr + strlenW(fmtstr) - 1;
-
- /* remap %ws to %ls */
- if (fmt_end > fmtstr && (fmt_end[-1] == 'w')) fmt_end[-1] = 'l';
- xarr[0]=*(argliststart+0);
- /* possible invalid pointers */
- xarr[1]=*(argliststart+1);
- xarr[2]=*(argliststart+2);
- sprintfbuf = HeapAlloc(GetProcessHeap(), 0, 1000);
- /* CMF - This makes a BIG assumption about va_list */
- vsnprintfW(sprintfbuf, 1000, fmtstr, (va_list) xarr);
- }
- else if (strcmpW(fmtstr, fmt_wc) == 0) {
- sprintfbuf = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * 2);
- sprintfbuf[0] = *(WCHAR *)argliststart;
- sprintfbuf[1] = 0;
- } else {
- sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
-
- /* CMF - This makes a BIG assumption about va_list */
- vsprintfW(sprintfbuf, fmtstr, (va_list) argliststart);
- }
- x=sprintfbuf;
- while (*x) {
- ADD_TO_T(*x++);
- }
- HeapFree(GetProcessHeap(),0,sprintfbuf);
- HeapFree(GetProcessHeap(),0,fmtstr);
+ f = format_insertW( insertnr, f, dwFlags, args, &str );
+ for (x = str; *x; x++) ADD_TO_T(*x);
+ HeapFree( GetProcessHeap(), 0, str );
break;
case 'n':
ADD_TO_T('\r');
More information about the wine-cvs
mailing list