Include fmt 11.0.2
[openal-soft.git] / common / win_main_utf8.h
blob81734242fc719846bd46234630fc1f0a6edaaa99
1 #ifndef WIN_MAIN_UTF8_H
2 #define WIN_MAIN_UTF8_H
4 /* For Windows systems this provides a way to get UTF-8 encoded argv strings,
5 * and also overrides fopen to accept UTF-8 filenames. Working with wmain
6 * directly complicates cross-platform compatibility, while normal main() in
7 * Windows uses the current codepage (which has limited availability of
8 * characters).
10 * For MinGW, you must link with -municode
12 #ifdef _WIN32
13 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
15 #include <shellapi.h>
16 #include <wchar.h>
18 #ifdef __cplusplus
19 #include <memory>
21 #define STATIC_CAST(...) static_cast<__VA_ARGS__>
22 #define REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__>
23 #define MAYBE_UNUSED [[maybe_unused]]
25 #else
27 #define STATIC_CAST(...) (__VA_ARGS__)
28 #define REINTERPRET_CAST(...) (__VA_ARGS__)
29 #ifdef __GNUC__
30 #define MAYBE_UNUSED __attribute__((__unused__))
31 #else
32 #define MAYBE_UNUSED
33 #endif
34 #endif
36 MAYBE_UNUSED static FILE *my_fopen(const char *fname, const char *mode)
38 wchar_t *wname=NULL, *wmode=NULL;
39 int namelen, modelen;
40 FILE *file = NULL;
41 errno_t err;
43 namelen = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
44 modelen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
46 if(namelen <= 0 || modelen <= 0)
48 fprintf(stderr, "Failed to convert UTF-8 fname \"%s\", mode \"%s\"\n", fname, mode);
49 return NULL;
52 #ifdef __cplusplus
53 auto strbuf = std::make_unique<wchar_t[]>(static_cast<size_t>(namelen) +
54 static_cast<size_t>(modelen));
55 wname = strbuf.get();
56 #else
57 wname = (wchar_t*)calloc(sizeof(wchar_t), (size_t)namelen + (size_t)modelen);
58 #endif
59 wmode = wname + namelen;
60 MultiByteToWideChar(CP_UTF8, 0, fname, -1, wname, namelen);
61 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen);
63 err = _wfopen_s(&file, wname, wmode);
64 if(err)
66 errno = err;
67 file = NULL;
70 #ifndef __cplusplus
71 free(wname);
72 #endif
73 return file;
75 #define fopen my_fopen
78 /* SDL overrides main and provides UTF-8 args for us. */
79 #if !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE)
80 int my_main(int, char**);
81 #define main my_main
83 #ifdef __cplusplus
84 extern "C"
85 #endif
86 int wmain(int argc, wchar_t **wargv)
88 char **argv;
89 size_t total;
90 int i;
92 total = sizeof(*argv) * STATIC_CAST(size_t)(argc);
93 for(i = 0;i < argc;i++)
94 total += STATIC_CAST(size_t)(WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL,
95 NULL));
97 #ifdef __cplusplus
98 auto argbuf = std::make_unique<char[]>(total);
99 argv = reinterpret_cast<char**>(argbuf.get());
100 #else
101 argv = (char**)calloc(1, total);
102 #endif
103 argv[0] = REINTERPRET_CAST(char*)(argv + argc);
104 for(i = 0;i < argc-1;i++)
106 int len = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL);
107 argv[i+1] = argv[i] + len;
109 WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL);
111 #ifdef __cplusplus
112 return main(argc, argv);
113 #else
114 i = main(argc, argv);
116 free(argv);
117 return i;
118 #endif
120 #endif /* !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) */
122 #endif /* _WIN32 */
124 #endif /* WIN_MAIN_UTF8_H */