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
10 * For MinGW, you must link with -municode
13 #define WIN32_LEAN_AND_MEAN
21 #define STATIC_CAST(...) static_cast<__VA_ARGS__>
22 #define REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__>
23 #define MAYBE_UNUSED [[maybe_unused]]
27 #define STATIC_CAST(...) (__VA_ARGS__)
28 #define REINTERPRET_CAST(...) (__VA_ARGS__)
30 #define MAYBE_UNUSED __attribute__((__unused__))
36 MAYBE_UNUSED
static FILE *my_fopen(const char *fname
, const char *mode
)
38 wchar_t *wname
=NULL
, *wmode
=NULL
;
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
);
53 auto strbuf
= std::make_unique
<wchar_t[]>(static_cast<size_t>(namelen
) +
54 static_cast<size_t>(modelen
));
57 wname
= (wchar_t*)calloc(sizeof(wchar_t), (size_t)namelen
+ (size_t)modelen
);
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
);
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**);
86 int wmain(int argc
, wchar_t **wargv
)
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
,
98 auto argbuf
= std::make_unique
<char[]>(total
);
99 argv
= reinterpret_cast<char**>(argbuf
.get());
101 argv
= (char**)calloc(1, total
);
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
);
112 return main(argc
, argv
);
114 i
= main(argc
, argv
);
120 #endif /* !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) */
124 #endif /* WIN_MAIN_UTF8_H */