rewrite the emulator to use UTF-8 internally
This commit is contained in:
286
src/win/win.c
286
src/win/win.c
@@ -31,6 +31,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <direct.h>
|
||||
#include <wchar.h>
|
||||
#include <io.h>
|
||||
#define HAVE_STDARG_H
|
||||
@@ -66,6 +67,7 @@ HINSTANCE hinstance; /* application instance */
|
||||
HANDLE ghMutex;
|
||||
LCID lang_id; /* current language ID used */
|
||||
DWORD dwSubLangID;
|
||||
int acp_utf8; /* Windows supports UTF-8 codepage */
|
||||
|
||||
|
||||
/* Local data. */
|
||||
@@ -81,7 +83,7 @@ static rc_str_t *lpRCstr2048,
|
||||
*lpRCstr6144,
|
||||
*lpRCstr7168;
|
||||
static int vid_api_inited = 0;
|
||||
static wchar_t *argbuf;
|
||||
static char *argbuf;
|
||||
static int first_use = 1;
|
||||
static LARGE_INTEGER StartingTime;
|
||||
static LARGE_INTEGER Frequency;
|
||||
@@ -181,6 +183,36 @@ LoadCommonStrings(void)
|
||||
}
|
||||
|
||||
|
||||
size_t mbstoc16s(uint16_t dst[], const char src[], int len)
|
||||
{
|
||||
if (src == NULL) return 0;
|
||||
if (len < 0) return 0;
|
||||
|
||||
size_t ret = MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst == NULL ? 0 : len);
|
||||
|
||||
if (!ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
size_t c16stombs(char dst[], const uint16_t src[], int len)
|
||||
{
|
||||
if (src == NULL) return 0;
|
||||
if (len < 0) return 0;
|
||||
|
||||
size_t ret = WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst == NULL ? 0 : len, NULL, NULL);
|
||||
|
||||
if (!ret) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Set (or re-set) the language for the application. */
|
||||
void
|
||||
set_language(int id)
|
||||
@@ -302,21 +334,25 @@ CloseConsole(void)
|
||||
|
||||
/* Process the commandline, and create standard argc/argv array. */
|
||||
static int
|
||||
ProcessCommandLine(wchar_t ***argw)
|
||||
ProcessCommandLine(char ***argv)
|
||||
{
|
||||
WCHAR *cmdline;
|
||||
wchar_t **args;
|
||||
char **args;
|
||||
int argc_max;
|
||||
int i, q, argc;
|
||||
|
||||
cmdline = GetCommandLine();
|
||||
i = wcslen(cmdline) + 1;
|
||||
argbuf = (wchar_t *)malloc(sizeof(wchar_t)*i);
|
||||
wcscpy(argbuf, cmdline);
|
||||
if (acp_utf8) {
|
||||
i = strlen(GetCommandLineA()) + 1;
|
||||
argbuf = (char *)malloc(i);
|
||||
strcpy(argbuf, GetCommandLineA());
|
||||
} else {
|
||||
i = c16stombs(NULL, GetCommandLineW(), 0) + 1;
|
||||
argbuf = (char *)malloc(i);
|
||||
c16stombs(argbuf, GetCommandLineW(), i);
|
||||
}
|
||||
|
||||
argc = 0;
|
||||
argc_max = 64;
|
||||
args = (wchar_t **)malloc(sizeof(wchar_t *) * argc_max);
|
||||
args = (char **)malloc(sizeof(char *) * argc_max);
|
||||
if (args == NULL) {
|
||||
free(argbuf);
|
||||
return(0);
|
||||
@@ -325,11 +361,11 @@ ProcessCommandLine(wchar_t ***argw)
|
||||
/* parse commandline into argc/argv format */
|
||||
i = 0;
|
||||
while (argbuf[i]) {
|
||||
while (argbuf[i] == L' ')
|
||||
while (argbuf[i] == ' ')
|
||||
i++;
|
||||
|
||||
if (argbuf[i]) {
|
||||
if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) {
|
||||
if ((argbuf[i] == '\'') || (argbuf[i] == '"')) {
|
||||
q = argbuf[i++];
|
||||
if (!argbuf[i])
|
||||
break;
|
||||
@@ -340,7 +376,7 @@ ProcessCommandLine(wchar_t ***argw)
|
||||
|
||||
if (argc >= argc_max) {
|
||||
argc_max += 64;
|
||||
args = realloc(args, sizeof(wchar_t *)*argc_max);
|
||||
args = realloc(args, sizeof(char *)*argc_max);
|
||||
if (args == NULL) {
|
||||
free(argbuf);
|
||||
return(0);
|
||||
@@ -348,7 +384,7 @@ ProcessCommandLine(wchar_t ***argw)
|
||||
}
|
||||
|
||||
while ((argbuf[i]) && ((q)
|
||||
? (argbuf[i]!=q) : (argbuf[i]!=L' '))) i++;
|
||||
? (argbuf[i]!=q) : (argbuf[i]!=' '))) i++;
|
||||
|
||||
if (argbuf[i]) {
|
||||
argbuf[i] = 0;
|
||||
@@ -358,7 +394,7 @@ ProcessCommandLine(wchar_t ***argw)
|
||||
}
|
||||
|
||||
args[argc] = NULL;
|
||||
*argw = args;
|
||||
*argv = args;
|
||||
|
||||
return(argc);
|
||||
}
|
||||
@@ -368,12 +404,18 @@ ProcessCommandLine(wchar_t ***argw)
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow)
|
||||
{
|
||||
wchar_t **argw = NULL;
|
||||
char **argv = NULL;
|
||||
int argc, i;
|
||||
wchar_t * AppID = L"86Box.86Box\0";
|
||||
|
||||
SetCurrentProcessExplicitAppUserModelID(AppID);
|
||||
|
||||
/* Check if Windows supports UTF-8 */
|
||||
if (GetACP() == CP_UTF8)
|
||||
acp_utf8 = 1;
|
||||
else
|
||||
acp_utf8 = 0;
|
||||
|
||||
/* Set this to the default value (windowed mode). */
|
||||
video_fullscreen = 0;
|
||||
|
||||
@@ -387,10 +429,10 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow)
|
||||
set_language(0x0409);
|
||||
|
||||
/* Process the command line for options. */
|
||||
argc = ProcessCommandLine(&argw);
|
||||
argc = ProcessCommandLine(&argv);
|
||||
|
||||
/* Pre-initialize the system, this loads the config file. */
|
||||
if (! pc_init(argc, argw)) {
|
||||
if (! pc_init(argc, argv)) {
|
||||
/* Detach from console. */
|
||||
if (force_debug)
|
||||
CreateConsole(0);
|
||||
@@ -399,7 +441,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow)
|
||||
PostMessage((HWND) (uintptr_t) source_hwnd, WM_HAS_SHUTDOWN, (WPARAM) 0, (LPARAM) hwndMain);
|
||||
|
||||
free(argbuf);
|
||||
free(argw);
|
||||
free(argv);
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -417,7 +459,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow)
|
||||
i = ui_init(nCmdShow);
|
||||
|
||||
free(argbuf);
|
||||
free(argw);
|
||||
free(argv);
|
||||
return(i);
|
||||
}
|
||||
|
||||
@@ -507,87 +549,152 @@ do_stop(void)
|
||||
|
||||
|
||||
void
|
||||
plat_get_exe_name(wchar_t *s, int size)
|
||||
plat_get_exe_name(char *s, int size)
|
||||
{
|
||||
GetModuleFileName(hinstance, s, size);
|
||||
wchar_t *temp;
|
||||
|
||||
if (acp_utf8)
|
||||
GetModuleFileNameA(hinstance, s, size);
|
||||
else {
|
||||
temp = malloc(size * sizeof(wchar_t));
|
||||
GetModuleFileNameW(hinstance, temp, size);
|
||||
c16stombs(s, temp, size);
|
||||
free(temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix)
|
||||
plat_tempfile(char *bufp, char *prefix, char *suffix)
|
||||
{
|
||||
SYSTEMTIME SystemTime;
|
||||
char temp[1024];
|
||||
|
||||
if (prefix != NULL)
|
||||
sprintf(temp, "%ls-", prefix);
|
||||
sprintf(bufp, "%s-", prefix);
|
||||
else
|
||||
strcpy(temp, "");
|
||||
strcpy(bufp, "");
|
||||
|
||||
GetSystemTime(&SystemTime);
|
||||
sprintf(&temp[strlen(temp)], "%d%02d%02d-%02d%02d%02d-%03d%ls",
|
||||
sprintf(&bufp[strlen(bufp)], "%d%02d%02d-%02d%02d%02d-%03d%s",
|
||||
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay,
|
||||
SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond,
|
||||
SystemTime.wMilliseconds,
|
||||
suffix);
|
||||
mbstowcs(bufp, temp, strlen(temp)+1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
plat_getcwd(wchar_t *bufp, int max)
|
||||
plat_getcwd(char *bufp, int max)
|
||||
{
|
||||
(void)_wgetcwd(bufp, max);
|
||||
wchar_t *temp;
|
||||
|
||||
if (acp_utf8)
|
||||
(void)_getcwd(bufp, max);
|
||||
else {
|
||||
temp = malloc(max * sizeof(wchar_t));
|
||||
(void)_wgetcwd(temp, max);
|
||||
c16stombs(bufp, temp, max);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
plat_chdir(wchar_t *path)
|
||||
plat_chdir(char *path)
|
||||
{
|
||||
return(_wchdir(path));
|
||||
wchar_t *temp;
|
||||
int len, ret;
|
||||
|
||||
if (acp_utf8)
|
||||
return(_chdir(path));
|
||||
else {
|
||||
len = mbstoc16s(NULL, path, 0) + 1;
|
||||
temp = malloc(len * sizeof(wchar_t));
|
||||
mbstoc16s(temp, path, len);
|
||||
|
||||
ret = _wchdir(temp);
|
||||
|
||||
free(temp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FILE *
|
||||
plat_fopen(wchar_t *path, wchar_t *mode)
|
||||
plat_fopen(const char *path, const char *mode)
|
||||
{
|
||||
return(_wfopen(path, mode));
|
||||
wchar_t *pathw, *modew;
|
||||
int len;
|
||||
FILE *fp;
|
||||
|
||||
if (acp_utf8)
|
||||
return fopen(path, mode);
|
||||
else {
|
||||
len = mbstoc16s(NULL, path, 0) + 1;
|
||||
pathw = malloc(sizeof(wchar_t) * len);
|
||||
mbstoc16s(pathw, path, len);
|
||||
|
||||
len = mbstoc16s(NULL, mode, 0) + 1;
|
||||
modew = malloc(sizeof(wchar_t) * len);
|
||||
mbstoc16s(modew, mode, len);
|
||||
|
||||
fp = _wfopen(pathw, modew);
|
||||
|
||||
free(pathw);
|
||||
free(modew);
|
||||
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Open a file, using Unicode pathname, with 64bit pointers. */
|
||||
FILE *
|
||||
plat_fopen64(const wchar_t *path, const wchar_t *mode)
|
||||
plat_fopen64(const char *path, const char *mode)
|
||||
{
|
||||
return(_wfopen(path, mode));
|
||||
return plat_fopen(path, mode);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
plat_remove(wchar_t *path)
|
||||
plat_remove(char *path)
|
||||
{
|
||||
_wremove(path);
|
||||
wchar_t *temp;
|
||||
int len;
|
||||
|
||||
if (acp_utf8)
|
||||
remove(path);
|
||||
else {
|
||||
len = mbstoc16s(NULL, path, 0) + 1;
|
||||
temp = malloc(len * sizeof(wchar_t));
|
||||
mbstoc16s(temp, path, len);
|
||||
|
||||
_wremove(temp);
|
||||
|
||||
free(temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Make sure a path ends with a trailing (back)slash. */
|
||||
void
|
||||
plat_path_slash(wchar_t *path)
|
||||
plat_path_slash(char *path)
|
||||
{
|
||||
if ((path[wcslen(path)-1] != L'\\') &&
|
||||
(path[wcslen(path)-1] != L'/')) {
|
||||
wcscat(path, L"\\");
|
||||
if ((path[strlen(path)-1] != '\\') &&
|
||||
(path[strlen(path)-1] != '/')) {
|
||||
strcat(path, "\\");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check if the given path is absolute or not. */
|
||||
int
|
||||
plat_path_abs(wchar_t *path)
|
||||
plat_path_abs(char *path)
|
||||
{
|
||||
if ((path[1] == L':') || (path[0] == L'\\') || (path[0] == L'/'))
|
||||
if ((path[1] == ':') || (path[0] == '\\') || (path[0] == '/'))
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
@@ -595,33 +702,33 @@ plat_path_abs(wchar_t *path)
|
||||
|
||||
|
||||
/* Return the last element of a pathname. */
|
||||
wchar_t *
|
||||
plat_get_basename(const wchar_t *path)
|
||||
char *
|
||||
plat_get_basename(const char *path)
|
||||
{
|
||||
int c = (int)wcslen(path);
|
||||
int c = (int)strlen(path);
|
||||
|
||||
while (c > 0) {
|
||||
if (path[c] == L'/' || path[c] == L'\\')
|
||||
return((wchar_t *)&path[c]);
|
||||
if (path[c] == '/' || path[c] == '\\')
|
||||
return((char *)&path[c]);
|
||||
c--;
|
||||
}
|
||||
|
||||
return((wchar_t *)path);
|
||||
return((char *)path);
|
||||
}
|
||||
|
||||
|
||||
/* Return the 'directory' element of a pathname. */
|
||||
void
|
||||
plat_get_dirname(wchar_t *dest, const wchar_t *path)
|
||||
plat_get_dirname(char *dest, const char *path)
|
||||
{
|
||||
int c = (int)wcslen(path);
|
||||
wchar_t *ptr;
|
||||
int c = (int)strlen(path);
|
||||
char *ptr;
|
||||
|
||||
ptr = (wchar_t *)path;
|
||||
ptr = (char *)path;
|
||||
|
||||
while (c > 0) {
|
||||
if (path[c] == L'/' || path[c] == L'\\') {
|
||||
ptr = (wchar_t *)&path[c];
|
||||
if (path[c] == '/' || path[c] == '\\') {
|
||||
ptr = (char *)&path[c];
|
||||
break;
|
||||
}
|
||||
c--;
|
||||
@@ -630,17 +737,17 @@ plat_get_dirname(wchar_t *dest, const wchar_t *path)
|
||||
/* Copy to destination. */
|
||||
while (path < ptr)
|
||||
*dest++ = *path++;
|
||||
*dest = L'\0';
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
|
||||
wchar_t *
|
||||
plat_get_filename(wchar_t *s)
|
||||
char *
|
||||
plat_get_filename(char *s)
|
||||
{
|
||||
int c = wcslen(s) - 1;
|
||||
int c = strlen(s) - 1;
|
||||
|
||||
while (c > 0) {
|
||||
if (s[c] == L'/' || s[c] == L'\\')
|
||||
if (s[c] == '/' || s[c] == '\\')
|
||||
return(&s[c+1]);
|
||||
c--;
|
||||
}
|
||||
@@ -649,47 +756,61 @@ plat_get_filename(wchar_t *s)
|
||||
}
|
||||
|
||||
|
||||
wchar_t *
|
||||
plat_get_extension(wchar_t *s)
|
||||
char *
|
||||
plat_get_extension(char *s)
|
||||
{
|
||||
int c = wcslen(s) - 1;
|
||||
int c = strlen(s) - 1;
|
||||
|
||||
if (c <= 0)
|
||||
return(s);
|
||||
|
||||
while (c && s[c] != L'.')
|
||||
while (c && s[c] != '.')
|
||||
c--;
|
||||
|
||||
if (!c)
|
||||
return(&s[wcslen(s)]);
|
||||
return(&s[strlen(s)]);
|
||||
|
||||
return(&s[c+1]);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2)
|
||||
plat_append_filename(char *dest, char *s1, char *s2)
|
||||
{
|
||||
wcscat(dest, s1);
|
||||
strcpy(dest, s1);
|
||||
plat_path_slash(dest);
|
||||
wcscat(dest, s2);
|
||||
strcat(dest, s2);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
plat_put_backslash(wchar_t *s)
|
||||
plat_put_backslash(char *s)
|
||||
{
|
||||
int c = wcslen(s) - 1;
|
||||
int c = strlen(s) - 1;
|
||||
|
||||
if (s[c] != L'/' && s[c] != L'\\')
|
||||
s[c] = L'/';
|
||||
if (s[c] != '/' && s[c] != '\\')
|
||||
s[c] = '/';
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
plat_dir_check(wchar_t *path)
|
||||
plat_dir_check(char *path)
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributes(path);
|
||||
DWORD dwAttrib;
|
||||
int len;
|
||||
wchar_t *temp;
|
||||
|
||||
if (acp_utf8)
|
||||
dwAttrib = GetFileAttributesA(path);
|
||||
else {
|
||||
len = mbstoc16s(NULL, path, 0) + 1;
|
||||
temp = malloc(len * sizeof(wchar_t));
|
||||
mbstoc16s(temp, path, len);
|
||||
|
||||
dwAttrib = GetFileAttributesW(temp);
|
||||
|
||||
free(temp);
|
||||
}
|
||||
|
||||
return(((dwAttrib != INVALID_FILE_ATTRIBUTES &&
|
||||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) ? 1 : 0);
|
||||
@@ -697,9 +818,24 @@ plat_dir_check(wchar_t *path)
|
||||
|
||||
|
||||
int
|
||||
plat_dir_create(wchar_t *path)
|
||||
plat_dir_create(char *path)
|
||||
{
|
||||
return((int)SHCreateDirectory(hwndMain, path));
|
||||
int ret, len;
|
||||
wchar_t *temp;
|
||||
|
||||
if (acp_utf8)
|
||||
return (int)SHCreateDirectoryExA(NULL, path, NULL);
|
||||
else {
|
||||
len = mbstoc16s(NULL, path, 0) + 1;
|
||||
temp = malloc(len * sizeof(wchar_t));
|
||||
mbstoc16s(temp, path, len);
|
||||
|
||||
ret = (int)SHCreateDirectoryExW(NULL, temp, NULL);
|
||||
|
||||
free(temp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user