diff options
Diffstat (limited to 'common/win_main_utf8.h')
-rw-r--r-- | common/win_main_utf8.h | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/common/win_main_utf8.h b/common/win_main_utf8.h new file mode 100644 index 00000000..faddc257 --- /dev/null +++ b/common/win_main_utf8.h @@ -0,0 +1,97 @@ +#ifndef WIN_MAIN_UTF8_H +#define WIN_MAIN_UTF8_H + +/* For Windows systems this provides a way to get UTF-8 encoded argv strings, + * and also overrides fopen to accept UTF-8 filenames. Working with wmain + * directly complicates cross-platform compatibility, while normal main() in + * Windows uses the current codepage (which has limited availability of + * characters). + * + * For MinGW, you must link with -municode + */ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <shellapi.h> + +static FILE *my_fopen(const char *fname, const char *mode) +{ + WCHAR *wname=NULL, *wmode=NULL; + int namelen, modelen; + FILE *file = NULL; + errno_t err; + + namelen = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0); + modelen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + + if(namelen <= 0 || modelen <= 0) + { + fprintf(stderr, "Failed to convert UTF-8 fname \"%s\", mode \"%s\"\n", fname, mode); + return NULL; + } + + wname = calloc(sizeof(WCHAR), namelen+modelen); + wmode = wname + namelen; + MultiByteToWideChar(CP_UTF8, 0, fname, -1, wname, namelen); + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen); + + err = _wfopen_s(&file, wname, wmode); + if(err) + { + errno = err; + file = NULL; + } + + free(wname); + + return file; +} +#define fopen my_fopen + + +static char **arglist; +static void cleanup_arglist(void) +{ + free(arglist); +} + +static void GetUnicodeArgs(int *argc, char ***argv) +{ + size_t total; + wchar_t **args; + int nargs, i; + + args = CommandLineToArgvW(GetCommandLineW(), &nargs); + if(!args) + { + fprintf(stderr, "Failed to get command line args: %ld\n", GetLastError()); + exit(EXIT_FAILURE); + } + + total = sizeof(**argv) * nargs; + for(i = 0;i < nargs;i++) + total += WideCharToMultiByte(CP_UTF8, 0, args[i], -1, NULL, 0, NULL, NULL); + + atexit(cleanup_arglist); + arglist = *argv = calloc(1, total); + (*argv)[0] = (char*)(*argv + nargs); + for(i = 0;i < nargs-1;i++) + { + int len = WideCharToMultiByte(CP_UTF8, 0, args[i], -1, (*argv)[i], 65535, NULL, NULL); + (*argv)[i+1] = (*argv)[i] + len; + } + WideCharToMultiByte(CP_UTF8, 0, args[i], -1, (*argv)[i], 65535, NULL, NULL); + *argc = nargs; + + LocalFree(args); +} +#define GET_UNICODE_ARGS(argc, argv) GetUnicodeArgs(argc, argv) + +#else + +/* Do nothing. */ +#define GET_UNICODE_ARGS(argc, argv) + +#endif + +#endif /* WIN_MAIN_UTF8_H */ |