From: Paul Gofman pgofman@codeweavers.com
--- dlls/shlwapi/Makefile.in | 3 +- dlls/shlwapi/shlwapi_main.c | 124 ++++++- dlls/shlwapi/tests/string.c | 215 ++++++++++++ dlls/shlwapi/wsprintf.c | 629 ------------------------------------ dlls/user32/wsprintf.c | 4 - 5 files changed, 331 insertions(+), 644 deletions(-) delete mode 100644 dlls/shlwapi/wsprintf.c
diff --git a/dlls/shlwapi/Makefile.in b/dlls/shlwapi/Makefile.in index 2c94cfefce1..6bf580f42d5 100644 --- a/dlls/shlwapi/Makefile.in +++ b/dlls/shlwapi/Makefile.in @@ -18,5 +18,4 @@ SOURCES = \ stopwatch.c \ string.c \ thread.c \ - url.c \ - wsprintf.c + url.c diff --git a/dlls/shlwapi/shlwapi_main.c b/dlls/shlwapi/shlwapi_main.c index 7820bc56281..ea45bdf32d5 100644 --- a/dlls/shlwapi/shlwapi_main.c +++ b/dlls/shlwapi/shlwapi_main.c @@ -29,9 +29,109 @@ #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell); +WINE_DECLARE_DEBUG_CHANNEL(string);
HINSTANCE shlwapi_hInstance = 0;
+static int (CDECL *ntdll__vsnprintf)( char *str, size_t len, const char *format, va_list args ); +static int (CDECL *ntdll__vsnwprintf)( WCHAR *str, size_t len, const WCHAR *format, va_list args ); + + +/*********************************************************************** + * wvnsprintfA (SHLWAPI.@) + * + * Print formatted output to a string, up to a maximum number of chars. + * + * PARAMS + * buffer [O] Destination for output string + * maxlen [I] Maximum number of characters to write + * spec [I] Format string + * + * RETURNS + * Success: The number of characters written. + * Failure: -1. + */ +INT WINAPI wvnsprintfA( LPSTR buffer, INT maxlen, LPCSTR spec, va_list args ) +{ + INT ret; + + TRACE_(string)( "%p %u %s\n", buffer, maxlen, debugstr_a(spec) ); + + if (!maxlen) return -1; + if (maxlen < 0) + { + buffer[0] = 0; + return -1; + } + if ((ret = ntdll__vsnprintf( buffer, maxlen, spec, args )) == -1) + buffer[maxlen - 1] = 0; + return ret; +} + +/*********************************************************************** + * wvnsprintfW (SHLWAPI.@) + * + * See wvnsprintfA. + */ +INT WINAPI wvnsprintfW( LPWSTR buffer, INT maxlen, LPCWSTR spec, va_list args ) +{ + INT ret; + + TRACE_(string)( "%p %u %s\n", buffer, maxlen, debugstr_w(spec) ); + + if (!maxlen) return -1; + if (maxlen < 0) + { + buffer[0] = 0; + return -1; + } + if ((ret = ntdll__vsnwprintf( buffer, maxlen, spec, args )) == -1) + buffer[maxlen - 1] = 0; + return ret; +} + +/************************************************************************* + * wnsprintfA (SHLWAPI.@) + * + * Print formatted output to a string, up to a maximum number of chars. + * + * PARAMS + * lpOut [O] Destination for output string + * cchLimitIn [I] Maximum number of characters to write + * lpFmt [I] Format string + * + * RETURNS + * Success: The number of characters written. + * Failure: -1. + */ +int WINAPIV wnsprintfA(LPSTR lpOut, int cchLimitIn, LPCSTR lpFmt, ...) +{ + va_list valist; + INT res; + + va_start( valist, lpFmt ); + res = wvnsprintfA( lpOut, cchLimitIn, lpFmt, valist ); + va_end( valist ); + return res; +} + +/************************************************************************* + * wnsprintfW (SHLWAPI.@) + * + * See wnsprintfA. + */ +int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ...) +{ + va_list valist; + INT res; + + va_start( valist, lpFmt ); + res = wvnsprintfW( lpOut, cchLimitIn, lpFmt, valist ); + va_end( valist ); + return res; +} + + /************************************************************************* * SHLWAPI {SHLWAPI} * @@ -54,15 +154,21 @@ HINSTANCE shlwapi_hInstance = 0; */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) { - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - shlwapi_hInstance = hinstDLL; - break; - } - return TRUE; + TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + { + HANDLE hntdll = GetModuleHandleW(L"ntdll.dll"); + + ntdll__vsnprintf = (void *)GetProcAddress(hntdll, "_vsnprintf"); + ntdll__vsnwprintf = (void *)GetProcAddress(hntdll, "_vsnwprintf"); + DisableThreadLibraryCalls(hinstDLL); + shlwapi_hInstance = hinstDLL; + break; + } + } + return TRUE; }
/*********************************************************************** diff --git a/dlls/shlwapi/tests/string.c b/dlls/shlwapi/tests/string.c index 8379a523733..19430f27296 100644 --- a/dlls/shlwapi/tests/string.c +++ b/dlls/shlwapi/tests/string.c @@ -1173,6 +1173,29 @@ if (0) ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfA return %d, expected 9 or -1\n", ret); expect_eq(buf[9], 0, CHAR, "%x"); expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); + + memset(buf, 0xbf, sizeof(buf)); + ret = pwnsprintfA(buf + 1, -1, "%s", str1); + ok(ret == -1, "got %d.\n", ret); + expect_eq(buf[0], (CHAR)0xbf, CHAR, "%x"); + if (!broken(1)) + { + /* This is 0xbf before Win8. */ + expect_eq(buf[1], 0, CHAR, "%x"); + } + expect_eq(buf[2], (CHAR)0xbf, CHAR, "%x"); + + memset(buf, 0xbf, sizeof(buf)); + ret = pwnsprintfA(buf + 1, 0, "%s", str1); + ok(ret == -1, "got %d.\n", ret); + expect_eq(buf[0], (CHAR)0xbf, CHAR, "%x"); + expect_eq(buf[1], (CHAR)0xbf, CHAR, "%x"); + + memset(buf, 0xbf, sizeof(buf)); + ret = pwnsprintfA(buf, 1, ""); + ok(!ret, "got %d.\n", ret); + expect_eq(buf[0], 0, CHAR, "%x"); + expect_eq(buf[1], (CHAR)0xbf, CHAR, "%x"); } else win_skip("wnsprintfA() is not available\n"); @@ -1184,6 +1207,29 @@ if (0) ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfW return %d, expected 9 or -1\n", ret); expect_eq(wbuf[9], 0, WCHAR, "%x"); expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); + + memset(wbuf, 0xbf, sizeof(wbuf)); + ret = pwnsprintfW(wbuf + 1, -1, fmt, wstr1); + ok(ret == -1, "got %d.\n", ret); + expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x"); + if (!broken(1)) + { + /* This is 0xbfbf before Win8. */ + expect_eq(wbuf[1], 0, WCHAR, "%x"); + } + expect_eq(wbuf[2], (WCHAR)0xbfbf, WCHAR, "%x"); + + memset(wbuf, 0xbf, sizeof(wbuf)); + ret = pwnsprintfW(wbuf + 1, 0, fmt, wstr1); + ok(ret == -1, "got %d.\n", ret); + expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x"); + expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x"); + + memset(wbuf, 0xbf, sizeof(wbuf)); + ret = pwnsprintfW(wbuf, 1, L""); + ok(!ret, "got %d.\n", ret); + expect_eq(wbuf[0], 0, WCHAR, "%x"); + expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x"); } else win_skip("wnsprintfW() is not available\n"); @@ -1689,6 +1735,174 @@ static void test_StrCatChainW(void) ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]); }
+static void test_printf_format(void) +{ + const struct + { + const char *spec; + unsigned int arg_size; + ULONG64 arg; + const void *argw; + } + tests[] = + { + { "%qu", 0, 10 }, + { "%ll", 0, 10 }, + { "%lu", sizeof(ULONG), 65537 }, + { "%llu", sizeof(ULONG64), 10 }, + { "%lllllllu", sizeof(ULONG64), 10 }, + { "%#lx", sizeof(ULONG), 10 }, + { "%#llx", sizeof(ULONG64), 0x1000000000 }, + { "%#lllx", sizeof(ULONG64), 0x1000000000 }, + { "%hu", sizeof(ULONG), 65537 }, + { "%hlu", sizeof(ULONG), 65537 }, + { "%hllx", sizeof(ULONG64), 0x100000010 }, + { "%hlllx", sizeof(ULONG64), 0x100000010 }, + { "%llhx", sizeof(ULONG64), 0x100000010 }, + { "%lllhx", sizeof(ULONG64), 0x100000010 }, + { "%lhu", sizeof(ULONG), 65537 }, + { "%hhu", sizeof(ULONG), 65537 }, + { "%hwu", sizeof(ULONG), 65537 }, + { "%whu", sizeof(ULONG), 65537 }, + { "%##lhllwlx", sizeof(ULONG64), 0x1000000010 }, + { "%##lhlwlx", sizeof(ULONG), 0x1000000010 }, + { "%04lhlwllx", sizeof(ULONG64), 0x1000000010 }, + { "%s", sizeof(ULONG_PTR), (ULONG_PTR)"str", L"str" }, + { "%S", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%ls", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%lS", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%lls", sizeof(ULONG_PTR), (ULONG_PTR)"str", L"str" }, + { "%llS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%llls", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%lllS", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%lllls", sizeof(ULONG_PTR), (ULONG_PTR)"str", L"str" }, + { "%llllS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%hs", sizeof(ULONG_PTR), (ULONG_PTR)"str" }, + { "%hS", sizeof(ULONG_PTR), (ULONG_PTR)"str" }, + { "%ws", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%wS", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%hhs", sizeof(ULONG_PTR), (ULONG_PTR)"str" }, + { "%hhS", sizeof(ULONG_PTR), (ULONG_PTR)"str" }, + { "%wws", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%wwS", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%wwws", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%wwwS", sizeof(ULONG_PTR), (ULONG_PTR)L"str" }, + { "%hws", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%hwS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%whs", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%whS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%hwls", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%hwlls", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%hwlS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%hwllS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%lhws", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%llhws", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%lhwS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%llhwS", sizeof(ULONG_PTR), (ULONG_PTR)L"str", "str" }, + { "%c", sizeof(SHORT), 0x95c8 }, + { "%lc", sizeof(SHORT), 0x95c8 }, + { "%llc", sizeof(SHORT), 0x95c8 }, + { "%lllc", sizeof(SHORT), 0x95c8 }, + { "%llllc", sizeof(SHORT), 0x95c8 }, + { "%lllllc", sizeof(SHORT), 0x95c8 }, + { "%C", sizeof(SHORT), 0x95c8 }, + { "%lC", sizeof(SHORT), 0x95c8 }, + { "%llC", sizeof(SHORT), 0x95c8 }, + { "%lllC", sizeof(SHORT), 0x95c8 }, + { "%llllC", sizeof(SHORT), 0x95c8 }, + { "%lllllC", sizeof(SHORT), 0x95c8 }, + { "%hc", sizeof(BYTE), 0x95c8 }, + { "%hhc", sizeof(BYTE), 0x95c8 }, + { "%hhhc", sizeof(BYTE), 0x95c8 }, + { "%wc", sizeof(BYTE), 0x95c8 }, + { "%wC", sizeof(BYTE), 0x95c8 }, + { "%hwc", sizeof(BYTE), 0x95c8 }, + { "%whc", sizeof(BYTE), 0x95c8 }, + { "%hwC", sizeof(BYTE), 0x95c8 }, + { "%whC", sizeof(BYTE), 0x95c8 }, + { "%I64u", sizeof(ULONG64), 10 }, + { "%llI64u", sizeof(ULONG64), 10 }, + { "%I64llu", sizeof(ULONG64), 10 }, + { "%I64s", sizeof(ULONG_PTR), (ULONG_PTR)"str", L"str" }, + { "%q%u", sizeof(ULONG), 10 }, + { "%lhw%u", 0, 10 }, + { "%u% ", sizeof(ULONG), 10 }, + { "%u% %u", sizeof(ULONG), 10 }, + { "% ll u", 0, 10 }, + { "% llu", sizeof(ULONG64), 10 }, + { "%# llx", sizeof(ULONG64), 10 }, + { "% #llx", sizeof(ULONG64), 10 }, + }; + int (WINAPIV *ntdll__snprintf)(char *str, size_t len, const char *format, ...); + int (WINAPIV *ntdll__snwprintf)( WCHAR *str, size_t len, const WCHAR *format, ... ); + WCHAR ws[256], expectedw[256], specw[256]; + unsigned int i, j; + char expected[256], spec[256], s[256]; + int len_a, len_w = 0, expected_len_a, expected_len_w = 0; + HANDLE hntdll = GetModuleHandleW(L"ntdll.dll"); + + ntdll__snprintf = (void *)GetProcAddress(hntdll, "_snprintf"); + ok(!!ntdll__snprintf, "_snprintf not found.\n"); + ntdll__snwprintf = (void *)GetProcAddress(hntdll, "_snwprintf"); + ok(!!ntdll__snwprintf, "_snwprintf not found.\n"); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + strcpy(spec, tests[i].spec); + winetest_push_context("%s", spec); + strcat(spec,"|%s"); + *s = 0; + *ws = 0; + j = 0; + do + specw[j] = spec[j]; + while (specw[j++]); + if (tests[i].argw) + { + len_w = pwnsprintfW(ws, ARRAY_SIZE(ws), specw, tests[i].argw, L"end"); + expected_len_w = ntdll__snwprintf(expectedw, ARRAY_SIZE(expectedw), specw, tests[i].argw, L"end"); + } + switch (tests[i].arg_size) + { + case 0: + len_a = pwnsprintfA(s, ARRAY_SIZE(s), spec, "end"); + expected_len_a = ntdll__snprintf(expected, ARRAY_SIZE(expected), spec, "end"); + len_w = pwnsprintfW(ws, ARRAY_SIZE(ws), specw, L"end"); + expected_len_w = ntdll__snwprintf(expectedw, ARRAY_SIZE(expectedw), specw, L"end"); + break; + case 1: + case 2: + case 4: + len_a = pwnsprintfA(s, ARRAY_SIZE(s), spec, (ULONG)tests[i].arg, "end"); + expected_len_a = ntdll__snprintf(expected, ARRAY_SIZE(expected), spec, (ULONG)tests[i].arg, "end"); + if (!tests[i].argw) + { + len_w = pwnsprintfW(ws, ARRAY_SIZE(ws), specw, (ULONG)tests[i].arg, L"end"); + expected_len_w = ntdll__snwprintf(expectedw, ARRAY_SIZE(expectedw), specw, (ULONG)tests[i].arg, L"end"); + } + break; + case 8: + len_a = pwnsprintfA(s, ARRAY_SIZE(s), spec, (ULONG64)tests[i].arg, "end"); + expected_len_a = ntdll__snprintf(expected, ARRAY_SIZE(s), spec, (ULONG64)tests[i].arg, "end"); + if (!tests[i].argw) + { + len_w = pwnsprintfW(ws, ARRAY_SIZE(ws), specw, (ULONG64)tests[i].arg, L"end"); + expected_len_w = ntdll__snwprintf(expectedw, ARRAY_SIZE(expectedw), specw, (ULONG64)tests[i].arg, L"end"); + } + break; + default: + len_a = len_w = expected_len_a = expected_len_w = 0; + ok(0, "unknown length %u.\n", tests[i].arg_size); + break; + } + ok(len_a == expected_len_a, "got len %d, expected %d.\n", len_a, expected_len_a); + ok(!strcmp(s, expected), "got %s, expected %s.\n", debugstr_a(s), debugstr_a(expected)); + ok(len_w == expected_len_w, "got len %d, expected %d.\n", len_a, expected_len_a); + ok(!wcscmp(ws, expectedw), "got %s, expected %s.\n", debugstr_w(ws), debugstr_w(expectedw)); + winetest_pop_context(); + } +} + START_TEST(string) { HMODULE hShlwapi; @@ -1777,6 +1991,7 @@ START_TEST(string) test_StrStrNW(); test_StrStrNIW(); test_StrCatChainW(); + test_printf_format();
CoUninitialize(); } diff --git a/dlls/shlwapi/wsprintf.c b/dlls/shlwapi/wsprintf.c deleted file mode 100644 index fbd2a7e75bf..00000000000 --- a/dlls/shlwapi/wsprintf.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * wsprintf functions - * - * Copyright 1996 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * NOTE: - * This code is duplicated in user32. If you change something here make sure - * to change it in user32 too. - */ - -#include <stdarg.h> -#include <string.h> -#include <stdio.h> - -#include "windef.h" -#include "winbase.h" -#define NO_SHLWAPI_REG -#include "shlwapi.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(string); - - -#define WPRINTF_LEFTALIGN 0x0001 /* Align output on the left ('-' prefix) */ -#define WPRINTF_PREFIX_HEX 0x0002 /* Prefix hex with 0x ('#' prefix) */ -#define WPRINTF_ZEROPAD 0x0004 /* Pad with zeros ('0' prefix) */ -#define WPRINTF_LONG 0x0008 /* Long arg ('l' prefix) */ -#define WPRINTF_SHORT 0x0010 /* Short arg ('h' prefix) */ -#define WPRINTF_UPPER_HEX 0x0020 /* Upper-case hex ('X' specifier) */ -#define WPRINTF_WIDE 0x0040 /* Wide arg ('w' prefix) */ -#define WPRINTF_INTPTR 0x0080 /* Pointer-size arg ('I' prefix) */ -#define WPRINTF_I64 0x0100 /* 64-bit arg ('I64' prefix) */ - -typedef enum -{ - WPR_UNKNOWN, - WPR_CHAR, - WPR_WCHAR, - WPR_STRING, - WPR_WSTRING, - WPR_SIGNED, - WPR_UNSIGNED, - WPR_HEXA -} WPRINTF_TYPE; - -typedef struct -{ - UINT flags; - UINT width; - UINT precision; - WPRINTF_TYPE type; -} WPRINTF_FORMAT; - -typedef union { - WCHAR wchar_view; - CHAR char_view; - LPCSTR lpcstr_view; - LPCWSTR lpcwstr_view; - LONGLONG int_view; -} WPRINTF_DATA; - -static const CHAR null_stringA[] = "(null)"; -static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 }; - -/*********************************************************************** - * WPRINTF_ParseFormatA - * - * Parse a format specification. A format specification has the form: - * - * [-][#][0][width][.precision]type - * - * Return value is the length of the format specification in characters. - */ -static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res ) -{ - LPCSTR p = format; - - res->flags = 0; - res->width = 0; - res->precision = 0; - if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } - if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } - if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } - while ((*p >= '0') && (*p <= '9')) /* width field */ - { - res->width = res->width * 10 + *p - '0'; - p++; - } - if (*p == '.') /* precision field */ - { - p++; - while ((*p >= '0') && (*p <= '9')) - { - res->precision = res->precision * 10 + *p - '0'; - p++; - } - } - if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } - else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } - else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } - else if (*p == 'I') - { - if (p[1] == '6' && p[2] == '4') { res->flags |= WPRINTF_I64; p += 3; } - else if (p[1] == '3' && p[2] == '2') p += 3; - else { res->flags |= WPRINTF_INTPTR; p++; } - } - switch(*p) - { - case 'c': - res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; - break; - case 'C': - res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; - break; - case 'd': - case 'i': - res->type = WPR_SIGNED; - break; - case 's': - res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; - break; - case 'S': - res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; - break; - case 'u': - res->type = WPR_UNSIGNED; - break; - case 'p': - res->width = 2 * sizeof(void *); - res->flags |= WPRINTF_ZEROPAD | WPRINTF_INTPTR; - /* fall through */ - case 'X': - res->flags |= WPRINTF_UPPER_HEX; - /* fall through */ - case 'x': - res->type = WPR_HEXA; - break; - default: /* unknown format char */ - res->type = WPR_UNKNOWN; - p--; /* print format as normal char */ - break; - } - return (INT)(p - format) + 1; -} - - -/*********************************************************************** - * WPRINTF_ParseFormatW - * - * Parse a format specification. A format specification has the form: - * - * [-][#][0][width][.precision]type - * - * Return value is the length of the format specification in characters. - */ -static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res ) -{ - LPCWSTR p = format; - - res->flags = 0; - res->width = 0; - res->precision = 0; - if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } - if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } - if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } - while ((*p >= '0') && (*p <= '9')) /* width field */ - { - res->width = res->width * 10 + *p - '0'; - p++; - } - if (*p == '.') /* precision field */ - { - p++; - while ((*p >= '0') && (*p <= '9')) - { - res->precision = res->precision * 10 + *p - '0'; - p++; - } - } - if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } - else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } - else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } - else if (*p == 'I') - { - if (p[1] == '6' && p[2] == '4') { res->flags |= WPRINTF_I64; p += 3; } - else if (p[1] == '3' && p[2] == '2') p += 3; - else { res->flags |= WPRINTF_INTPTR; p++; } - } - switch(*p) - { - case 'c': - res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; - break; - case 'C': - res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; - break; - case 'd': - case 'i': - res->type = WPR_SIGNED; - break; - case 's': - res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; - break; - case 'S': - res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; - break; - case 'u': - res->type = WPR_UNSIGNED; - break; - case 'p': - res->width = 2 * sizeof(void *); - res->flags |= WPRINTF_ZEROPAD | WPRINTF_INTPTR; - /* fall through */ - case 'X': - res->flags |= WPRINTF_UPPER_HEX; - /* fall through */ - case 'x': - res->type = WPR_HEXA; - break; - default: - res->type = WPR_UNKNOWN; - p--; /* print format as normal char */ - break; - } - return (INT)(p - format) + 1; -} - - -/*********************************************************************** - * WPRINTF_GetLen - */ -static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg, - LPSTR number, UINT maxlen, BOOL dst_is_wide ) -{ - UINT len; - - if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD; - if (format->width > maxlen) format->width = maxlen; - switch(format->type) - { - case WPR_CHAR: - return (format->precision = 1); - case WPR_WCHAR: - if (dst_is_wide) len = 1; - else len = WideCharToMultiByte( CP_ACP, 0, &arg->wchar_view, 1, NULL, 0, NULL, NULL ); - return (format->precision = len); - case WPR_STRING: - if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA; - if (dst_is_wide) - { - LPCSTR p = arg->lpcstr_view; - for (len = 0; (!format->precision || len < format->precision) && *p; p++) - { - /* This isn't applicable for UTF-8 and UTF-7 */ - if (IsDBCSLeadByte( *p )) p++; - len++; - if (!*p) break; - } - } - else - { - for (len = 0; !format->precision || (len < format->precision); len++) - if (!*(arg->lpcstr_view + len)) break; - } - if (len > maxlen) len = maxlen; - return (format->precision = len); - case WPR_WSTRING: - if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW; - if (dst_is_wide) - { - for (len = 0; !format->precision || (len < format->precision); len++) - if (!*(arg->lpcwstr_view + len)) break; - } - else - { - LPCWSTR p = arg->lpcwstr_view; - for (len = 0; (!format->precision || len < format->precision) && *p; p++) - len += WideCharToMultiByte( CP_ACP, 0, p, 1, NULL, 0, NULL, NULL ); - if (format->precision && len > format->precision) len = format->precision; - } - if (len > maxlen) len = maxlen; - return (format->precision = len); - case WPR_SIGNED: - case WPR_UNSIGNED: - case WPR_HEXA: - { - const char *digits = (format->flags & WPRINTF_UPPER_HEX) ? "0123456789ABCDEF" : "0123456789abcdef"; - ULONGLONG num = arg->int_view; - int base = format->type == WPR_HEXA ? 16 : 10; - char buffer[20], *p = buffer, *dst = number; - - if (format->type == WPR_SIGNED && arg->int_view < 0) - { - *dst++ = '-'; - num = -arg->int_view; - } - if (format->flags & WPRINTF_INTPTR) num = (UINT_PTR)num; - else if (!(format->flags & WPRINTF_I64)) num = (UINT)num; - - do - { - *p++ = digits[num % base]; - num /= base; - } while (num); - while (p > buffer) *dst++ = *(--p); - *dst = 0; - len = dst - number; - break; - } - default: - return 0; - } - if (len > maxlen) len = maxlen; - if (format->precision < len) format->precision = len; - if (format->precision > maxlen) format->precision = maxlen; - if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision)) - format->precision = format->width; - if (format->flags & WPRINTF_PREFIX_HEX) len += 2; - return len; -} - - -/*********************************************************************** - * wvnsprintfA (SHLWAPI.@) - * - * Print formatted output to a string, up to a maximum number of chars. - * - * PARAMS - * buffer [O] Destination for output string - * maxlen [I] Maximum number of characters to write - * spec [I] Format string - * - * RETURNS - * Success: The number of characters written. - * Failure: -1. - */ -INT WINAPI wvnsprintfA( LPSTR buffer, INT maxlen, LPCSTR spec, va_list args ) -{ - WPRINTF_FORMAT format; - LPSTR p = buffer; - UINT i, len, sign; - CHAR number[21]; /* 64bit number can be 18446744073709551616 which is 20 chars. and a \0 */ - WPRINTF_DATA argData; - - TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec)); - - while (*spec && (maxlen > 1)) - { - if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } - spec++; - if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } - spec += WPRINTF_ParseFormatA( spec, &format ); - - switch(format.type) - { - case WPR_WCHAR: - argData.wchar_view = (WCHAR)va_arg( args, int ); - break; - case WPR_CHAR: - argData.char_view = (CHAR)va_arg( args, int ); - break; - case WPR_STRING: - argData.lpcstr_view = va_arg( args, LPCSTR ); - break; - case WPR_WSTRING: - argData.lpcwstr_view = va_arg( args, LPCWSTR ); - break; - case WPR_HEXA: - case WPR_SIGNED: - case WPR_UNSIGNED: - if (format.flags & WPRINTF_INTPTR) argData.int_view = va_arg(args, INT_PTR); - else if (format.flags & WPRINTF_I64) argData.int_view = va_arg(args, LONGLONG); - else argData.int_view = va_arg(args, INT); - break; - default: - argData.wchar_view = 0; - break; - } - - len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1, FALSE ); - sign = 0; - if (!(format.flags & WPRINTF_LEFTALIGN)) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - switch(format.type) - { - case WPR_WCHAR: - { - CHAR mb[5]; - if (WideCharToMultiByte( CP_ACP, 0, &argData.wchar_view, 1, mb, sizeof(mb), NULL, NULL )) - { - memcpy( p, mb, len ); - p += len; - } - } - break; - case WPR_CHAR: - *p++ = argData.char_view; - break; - case WPR_STRING: - memcpy( p, argData.lpcstr_view, len ); - p += len; - break; - case WPR_WSTRING: - { - LPCWSTR ptr = argData.lpcwstr_view; - for (i = 0; i < len; ptr++) - { - CHAR mb[5]; /* 5 is MB_LEN_MAX */ - int ret = WideCharToMultiByte( CP_ACP, 0, ptr, 1, mb, sizeof(mb), NULL, NULL ); - i += ret; - if (i > len) ret = len - (p - buffer); - memcpy( p, mb, ret ); - p += ret; - } - } - break; - case WPR_HEXA: - if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) - { - *p++ = '0'; - *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; - maxlen -= 2; - len -= 2; - } - /* fall through */ - case WPR_SIGNED: - /* Transfer the sign now, just in case it will be zero-padded*/ - if (number[0] == '-') - { - *p++ = '-'; - sign = 1; - } - /* fall through */ - case WPR_UNSIGNED: - for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; - memcpy( p, number + sign, len - sign ); - p += len - sign; - break; - case WPR_UNKNOWN: - continue; - } - if (format.flags & WPRINTF_LEFTALIGN) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - maxlen -= len; - } - *p = 0; - TRACE("%s\n",debugstr_a(buffer)); - return (maxlen > 1) ? (INT)(p - buffer) : -1; -} - - -/*********************************************************************** - * wvnsprintfW (SHLWAPI.@) - * - * See wvnsprintfA. - */ -INT WINAPI wvnsprintfW( LPWSTR buffer, INT maxlen, LPCWSTR spec, va_list args ) -{ - WPRINTF_FORMAT format; - LPWSTR p = buffer; - UINT i, len, sign; - CHAR number[21]; /* 64bit number can be 18446744073709551616 which is 20 chars. and a \0 */ - WPRINTF_DATA argData; - - TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec)); - - while (*spec && (maxlen > 1)) - { - if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } - spec++; - if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } - spec += WPRINTF_ParseFormatW( spec, &format ); - - switch(format.type) - { - case WPR_WCHAR: - argData.wchar_view = (WCHAR)va_arg( args, int ); - break; - case WPR_CHAR: - argData.char_view = (CHAR)va_arg( args, int ); - break; - case WPR_STRING: - argData.lpcstr_view = va_arg( args, LPCSTR ); - break; - case WPR_WSTRING: - argData.lpcwstr_view = va_arg( args, LPCWSTR ); - break; - case WPR_HEXA: - case WPR_SIGNED: - case WPR_UNSIGNED: - if (format.flags & WPRINTF_INTPTR) argData.int_view = va_arg(args, INT_PTR); - else if (format.flags & WPRINTF_I64) argData.int_view = va_arg(args, LONGLONG); - else argData.int_view = va_arg(args, INT); - break; - default: - argData.wchar_view = 0; - break; - } - - len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1, TRUE ); - sign = 0; - if (!(format.flags & WPRINTF_LEFTALIGN)) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - switch(format.type) - { - case WPR_WCHAR: - *p++ = argData.wchar_view; - break; - case WPR_CHAR: - { - WCHAR wc; - if (!IsDBCSLeadByte( (BYTE)argData.char_view ) - && MultiByteToWideChar( CP_ACP, 0, &argData.char_view, 1, &wc, 1 ) > 0) - *p++ = wc; - else - *p++ = 0; - break; - } - case WPR_STRING: - { - LPCSTR ptr = argData.lpcstr_view; - for (i = 0; i < len; i++) - { - WCHAR buf[2]; /* for LeadByte + NUL case, we need 2 WCHARs. */ - int ret, mb_len = IsDBCSLeadByte( *ptr ) ? 2 : 1; - ret = MultiByteToWideChar( CP_ACP, 0, ptr, mb_len, buf, ARRAY_SIZE( buf )); - *p++ = buf[ret - 1]; - ptr += mb_len; - } - } - break; - case WPR_WSTRING: - if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) ); - p += len; - break; - case WPR_HEXA: - if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) - { - *p++ = '0'; - *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; - maxlen -= 2; - len -= 2; - } - /* fall through */ - case WPR_SIGNED: - /* Transfer the sign now, just in case it will be zero-padded*/ - if (number[0] == '-') - { - *p++ = '-'; - sign = 1; - } - /* fall through */ - case WPR_UNSIGNED: - for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; - for (i = sign; i < len; i++) *p++ = (BYTE)number[i]; - break; - case WPR_UNKNOWN: - continue; - } - if (format.flags & WPRINTF_LEFTALIGN) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - maxlen -= len; - } - *p = 0; - TRACE("%s\n",debugstr_w(buffer)); - return (maxlen > 1) ? (INT)(p - buffer) : -1; -} - - -/************************************************************************* - * wnsprintfA (SHLWAPI.@) - * - * Print formatted output to a string, up to a maximum number of chars. - * - * PARAMS - * lpOut [O] Destination for output string - * cchLimitIn [I] Maximum number of characters to write - * lpFmt [I] Format string - * - * RETURNS - * Success: The number of characters written. - * Failure: -1. - */ -int WINAPIV wnsprintfA(LPSTR lpOut, int cchLimitIn, LPCSTR lpFmt, ...) -{ - va_list valist; - INT res; - - va_start( valist, lpFmt ); - res = wvnsprintfA( lpOut, cchLimitIn, lpFmt, valist ); - va_end( valist ); - return res; -} - - -/************************************************************************* - * wnsprintfW (SHLWAPI.@) - * - * See wnsprintfA. - */ -int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ...) -{ - va_list valist; - INT res; - - va_start( valist, lpFmt ); - res = wvnsprintfW( lpOut, cchLimitIn, lpFmt, valist ); - va_end( valist ); - return res; -} diff --git a/dlls/user32/wsprintf.c b/dlls/user32/wsprintf.c index 1b396f0269c..cbf74226418 100644 --- a/dlls/user32/wsprintf.c +++ b/dlls/user32/wsprintf.c @@ -16,10 +16,6 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * NOTE: - * This code is duplicated in shlwapi. If you change something here make sure - * to change it in shlwapi too. */
#include <stdarg.h>