| #include <stdio.h> |
| #include <string.h> |
| #include <wchar.h> |
| #include <winternl.h> |
| |
| /* mingw-w64 headers */ |
| #include "libtest.h" |
| |
| #define ARRAY_COUNT(a) (sizeof(a)/sizeof(a[0])) |
| #define DEF_STRING(str) { sizeof(str)-sizeof(str[0]), sizeof(str)-sizeof(str[0]), str } |
| |
| #define PRINT_NARROW_BUF(buf) \ |
| for (i = 0; i < ARRAY_COUNT(buf); i++) { \ |
| if ((buf)[i] == '\n' || ((buf)[i] >= 0x20 && (buf)[i] <= 0x7E && (buf)[i] != '\\')) \ |
| fputc((buf)[i], stderr); \ |
| else \ |
| fprintf(stderr, "\\x%02X", (unsigned int)(unsigned char)(buf)[i]); \ |
| } |
| |
| #define PRINT_WIDE_BUF(buf) \ |
| for (i = 0; i < ARRAY_COUNT(buf); i++) { \ |
| if ((buf)[i] == L'\n' || ((buf)[i] >= 0x20 && (buf)[i] <= 0x7E && (buf)[i] != L'\\')) \ |
| fputc((char)(buf)[i], stderr); \ |
| else \ |
| fprintf(stderr, "\\x%04X", (unsigned int)(wint_t)(buf)[i]); \ |
| } \ |
| |
| int main() { |
| ANSI_STRING anull = {}; |
| UNICODE_STRING wnull = {}; |
| ANSI_STRING as0 = DEF_STRING("TEST\x00XYZA"); |
| ANSI_STRING as1 = DEF_STRING("TEST"); |
| UNICODE_STRING ws0 = DEF_STRING(L"TEST\x0000XYZA"); |
| UNICODE_STRING ws1 = DEF_STRING(L"TEST"); |
| char abuf[70]; |
| char abuf2[45]; |
| wchar_t wbuf[55]; |
| wchar_t wbuf2[50]; |
| wchar_t wbuf3[23]; |
| wchar_t wbuf4[4]; |
| int ret; |
| size_t i; |
| |
| (void)ws1; /* avoid "warning: unused variable" on some builds */ |
| (void)wbuf3; /* avoid "warning: unused variable" on some builds */ |
| (void)wbuf4; /* avoid "warning: unused variable" on some builds */ |
| |
| mingw_test_init (); |
| |
| /* |
| * These tests do not work with msvcrt20.dll, msvcrt40.dll and msvcr40d.dll |
| * which do not support %Z format. All older and new CRT libraries support it. |
| * |
| * UCRT does not accept nul characters in ANSI_STRING for wide printf functions |
| * and treats them as errors (signaled by negative return value and stopping |
| * formatting). They are accepted in narrow printf functions. Nul characters |
| * in UNICODE_STRING are accepted by both narrow and wide printf functions. |
| */ |
| |
| #if __MSVCRT_VERSION__ >= 0x200 && __MSVCRT_VERSION__ <= 0x400 |
| return 77; |
| #endif |
| |
| memset(abuf, 0xff, sizeof(abuf)); |
| #if __USE_MINGW_ANSI_STDIO == 1 || defined(_UCRT) |
| ret = snprintf(abuf, ARRAY_COUNT(abuf), "%Z\n%hZ\n%lZ\n%wZ\n%hZ\n%hZ\n%wZ\n%wZ\n", &ws0, &as0, &ws0, &ws0, &anull, NULL, &wnull, NULL); |
| #else |
| ret = snprintf(abuf, ARRAY_COUNT(abuf), "%Z\n%hZ\n%lZ\n%wZ\n%hZ\n%hZ\n%wZ\n%wZ\n", &as0, &as0, &as0, &ws0, &anull, NULL, &wnull, NULL); |
| #endif |
| if (ret != ARRAY_COUNT(abuf)-2 || memcmp(abuf, "TEST\x00XYZA\nTEST\x00XYZA\nTEST\x00XYZA\nTEST\x00XYZA\n(null)\n(null)\n(null)\n(null)\n\x00\xFF", ARRAY_COUNT(abuf)) != 0) { |
| fprintf(stderr, "ret: expected=%d got=%d\n", ARRAY_COUNT(abuf)-2, ret); |
| fprintf(stderr, "abuf:\n"); |
| PRINT_NARROW_BUF(abuf); |
| fprintf(stderr, "\n"); |
| return 1; |
| } |
| printf("OK abuf\n"); |
| |
| memset(abuf2, 0xff, sizeof(abuf2)); |
| ret = snprintf(abuf2, ARRAY_COUNT(abuf2), "%hZ\n%wZ\n%hZ\n%hZ\n%wZ\n%wZ\n", &as1, &ws0, &anull, NULL, &wnull, NULL); |
| if (ret != ARRAY_COUNT(abuf2)-2 || memcmp(abuf2, "TEST\nTEST\x00XYZA\n(null)\n(null)\n(null)\n(null)\n\x00\xFF", ARRAY_COUNT(abuf2)) != 0) { |
| fprintf(stderr, "ret: expected=%d got=%d\n", ARRAY_COUNT(abuf2)-2, ret); |
| fprintf(stderr, "abuf2:\n"); |
| PRINT_NARROW_BUF(abuf2); |
| fprintf(stderr, "\n"); |
| return 1; |
| } |
| printf("OK abuf2\n"); |
| |
| memset(wbuf, 0xff, sizeof(wbuf)); |
| #if __USE_MINGW_ANSI_STDIO == 1 || defined(_UCRT) |
| ret = swprintf(wbuf, ARRAY_COUNT(wbuf), L"%Z\n%hZ\n%lZ\n%wZ\n%hZ\n%hZ\n%wZ\n%wZ\n", &as1, &as1, &ws1, &ws0, &anull, NULL, &wnull, NULL); |
| #else |
| ret = swprintf(wbuf, ARRAY_COUNT(wbuf), L"%Z\n%hZ\n%lZ\n%wZ\n%hZ\n%hZ\n%wZ\n%wZ\n", &as1, &as1, &as1, &ws0, &anull, NULL, &wnull, NULL); |
| #endif |
| if (ret != ARRAY_COUNT(wbuf)-2 || wmemcmp(wbuf, L"TEST\nTEST\nTEST\nTEST\x00XYZA\n(null)\n(null)\n(null)\n(null)\n\x0000\xFFFF", ARRAY_COUNT(wbuf)) != 0) { |
| fprintf(stderr, "ret: expected=%d got=%d\n", ARRAY_COUNT(wbuf)-2, ret); |
| fprintf(stderr, "wbuf:\n"); |
| PRINT_WIDE_BUF(wbuf); |
| fprintf(stderr, "\n"); |
| return 1; |
| } |
| printf("OK wbuf\n"); |
| |
| memset(wbuf2, 0xff, sizeof(wbuf2)); |
| ret = swprintf(wbuf2, ARRAY_COUNT(wbuf2), L"%Z\n%hZ\n%wZ\n%hZ\n%hZ\n%wZ\n%wZ\n", &as1, &as1, &ws0, &anull, NULL, &wnull, NULL); |
| if (ret != ARRAY_COUNT(wbuf2)-2 || wmemcmp(wbuf2, L"TEST\nTEST\nTEST\x00XYZA\n(null)\n(null)\n(null)\n(null)\n\x0000\xFFFF", ARRAY_COUNT(wbuf2)) != 0) { |
| fprintf(stderr, "ret: expected=%d got=%d\n", ARRAY_COUNT(wbuf2)-2, ret); |
| fprintf(stderr, "wbuf2:\n"); |
| PRINT_WIDE_BUF(wbuf2); |
| fprintf(stderr, "\n"); |
| return 1; |
| } |
| printf("OK wbuf2\n"); |
| |
| /* msvcr80+ and UCRT stop processing the format string at the first nul byte in ANSI_STRING buffer and returns -1 */ |
| #if __USE_MINGW_ANSI_STDIO == 1 || __MSVCRT_VERSION__ >= 0x800 || defined(_UCRT) |
| memset(wbuf3, 0xff, sizeof(wbuf3)); |
| ret = swprintf(wbuf3, ARRAY_COUNT(wbuf3), L"prefix%hZsuffix", &as0); |
| if (ret != -1 || wmemcmp(wbuf3, L"prefixTEST\x0000\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF\xFFFF", ARRAY_COUNT(wbuf3)-1) != 0 || |
| #if __USE_MINGW_ANSI_STDIO == 1 || defined(_UCRT) |
| wbuf3[ARRAY_COUNT(wbuf3)-1] != L'\xFFFF' /* UCRT does not touch the last char in buffer */ |
| #else /* __MSVCRT_VERSION__ >= 0x800 && __MSVCRT_VERSION__ <= 0xC00 */ |
| wbuf3[ARRAY_COUNT(wbuf3)-1] != L'\x0000' /* msvcr80-msvcr120 clears the last char in buffer */ |
| #endif |
| ) { |
| fprintf(stderr, "ret: expected=%d got=%d\n", -1, ret); |
| fprintf(stderr, "wbuf3:\n"); |
| PRINT_WIDE_BUF(wbuf3); |
| fprintf(stderr, "\n"); |
| return 1; |
| } |
| printf("OK wbuf3\n"); |
| |
| memset(wbuf4, 0xff, sizeof(wbuf4)); |
| ret = swprintf(wbuf4, ARRAY_COUNT(wbuf4), L"%hZ", &as0); |
| if (ret != -1 || wmemcmp(wbuf4, L"TES\x0000", ARRAY_COUNT(wbuf4)) != 0) { |
| fprintf(stderr, "ret: expected=%d got=%d\n", -1, ret); |
| fprintf(stderr, "wbuf4:\n"); |
| PRINT_WIDE_BUF(wbuf4); |
| fprintf(stderr, "\n"); |
| return 1; |
| } |
| printf("OK wbuf4\n"); |
| #endif |
| |
| return 0; |
| } |