move config-file seeking code to its own thing.
look also into the same directory as melonDS. make it the preferred place for storing melonDS.ini. rewrite WinMain() wrapper.
This commit is contained in:
parent
9a0bf912d9
commit
40f3f91368
|
@ -23,6 +23,7 @@ SET(SOURCES
|
|||
src/GPU2D.cpp
|
||||
src/GPU3D.cpp
|
||||
src/GPU3D_Soft.cpp
|
||||
src/melon_fopen.cpp
|
||||
src/NDS.cpp
|
||||
src/NDSCart.cpp
|
||||
src/RTC.cpp
|
||||
|
|
|
@ -234,6 +234,7 @@
|
|||
<Unit filename="src/libui_sdl/libui/windows/winpublic.cpp" />
|
||||
<Unit filename="src/libui_sdl/libui/windows/winutil.cpp" />
|
||||
<Unit filename="src/libui_sdl/main.cpp" />
|
||||
<Unit filename="src/melon_fopen.cpp" />
|
||||
<Unit filename="src/melon_fopen.h" />
|
||||
<Unit filename="src/pcap/bluetooth.h" />
|
||||
<Unit filename="src/pcap/bpf.h" />
|
||||
|
|
106
src/Config.cpp
106
src/Config.cpp
|
@ -20,21 +20,17 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "Config.h"
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK
|
||||
#include <windows.h>
|
||||
//#include <knownfolders.h> // FUCK THAT SHIT
|
||||
extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}};
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <glib.h>
|
||||
#endif
|
||||
#include "melon_fopen.h"
|
||||
|
||||
|
||||
bool LocalFileExists(const char* name);
|
||||
extern char* EmuDirectory;
|
||||
|
||||
namespace Config
|
||||
{
|
||||
|
||||
const char* kConfigFile = "melonDS.ini";
|
||||
|
||||
int KeyMapping[12];
|
||||
int JoyMapping[12];
|
||||
|
||||
|
@ -114,72 +110,6 @@ ConfigEntry ConfigFile[] =
|
|||
{"", -1, NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
FILE* GetConfigFile(const char* fileName, const char* permissions)
|
||||
{
|
||||
// Locations are application directory, and XDG_CONFIG_HOME/melonds or AppData/MelonDS on windows
|
||||
|
||||
FILE* f;
|
||||
|
||||
// First check application directory
|
||||
f = fopen(fileName, permissions);
|
||||
if (f) return f;
|
||||
#ifdef _WIN32
|
||||
// Now check AppData
|
||||
PWSTR appDataPath = NULL;
|
||||
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appDataPath);
|
||||
if (!appDataPath)
|
||||
return NULL;
|
||||
|
||||
const WCHAR* appdir = L"\\melonDS\\";
|
||||
|
||||
int fnlen = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, NULL, 0);
|
||||
if (fnlen < 1) return NULL;
|
||||
WCHAR* wfileName = new WCHAR[fnlen];
|
||||
int res = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, wfileName, fnlen);
|
||||
if (res != fnlen) { delete[] wfileName; return NULL; } // checkme?
|
||||
|
||||
int pos = wcslen(appDataPath);
|
||||
void* ptr = CoTaskMemRealloc(appDataPath, (pos+wcslen(appdir)+fnlen+1)*sizeof(WCHAR));
|
||||
if (!ptr) { delete[] wfileName; return NULL; } // oh well
|
||||
appDataPath = (PWSTR)ptr;
|
||||
|
||||
wcscpy(&appDataPath[pos], appdir); pos += wcslen(appdir);
|
||||
wcscpy(&appDataPath[pos], wfileName);
|
||||
|
||||
// this will be more than enough
|
||||
WCHAR fatperm[4];
|
||||
fatperm[0] = permissions[0];
|
||||
fatperm[1] = permissions[1];
|
||||
fatperm[2] = permissions[2];
|
||||
fatperm[3] = 0;
|
||||
|
||||
f = _wfopen(appDataPath, fatperm);
|
||||
CoTaskMemFree(appDataPath);
|
||||
delete[] wfileName;
|
||||
if (f) return f;
|
||||
#else
|
||||
// Now check XDG_CONFIG_HOME
|
||||
// TODO: check for memory leak there
|
||||
std::string path = std::string(g_get_user_config_dir()) + "/melonds/" + fileName;
|
||||
f = fopen(path.c_str(), permissions);
|
||||
if (f) return f;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
bool HasConfigFile(const char* fileName)
|
||||
{
|
||||
FILE* f = GetConfigFile(fileName, "rb");
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Load()
|
||||
{
|
||||
|
@ -196,7 +126,7 @@ void Load()
|
|||
entry++;
|
||||
}
|
||||
|
||||
FILE* f = Config::GetConfigFile("melonDS.ini", "r");
|
||||
FILE* f = melon_fopen_local(kConfigFile, "r");
|
||||
if (!f) return;
|
||||
|
||||
char linebuf[1024];
|
||||
|
@ -232,8 +162,26 @@ void Load()
|
|||
|
||||
void Save()
|
||||
{
|
||||
FILE* f = Config::GetConfigFile("melonDS.ini", "w");
|
||||
if (!f) return;
|
||||
FILE* f;
|
||||
if (LocalFileExists(kConfigFile))
|
||||
{
|
||||
f = melon_fopen_local(kConfigFile, "w");
|
||||
if (!f) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int dirlen = strlen(EmuDirectory);
|
||||
int filelen = strlen(kConfigFile);
|
||||
char* path = new char[dirlen + 1 + filelen + 1];
|
||||
strncpy(&path[0], EmuDirectory, dirlen);
|
||||
path[dirlen] = '/';
|
||||
strncpy(&path[dirlen+1], kConfigFile, filelen);
|
||||
path[dirlen+1+filelen] = '\0';
|
||||
|
||||
f = melon_fopen(path, "w");
|
||||
delete[] path;
|
||||
if (!f) return;
|
||||
}
|
||||
|
||||
ConfigEntry* entry = &ConfigFile[0];
|
||||
for (;;)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "RTC.h"
|
||||
#include "Wifi.h"
|
||||
#include "Platform.h"
|
||||
#include "melon_fopen.h"
|
||||
|
||||
|
||||
namespace NDS
|
||||
|
@ -386,7 +387,7 @@ void Reset()
|
|||
dbg_CyclesTimer7 = 0;
|
||||
#endif // DEBUG_CHECK_DESYNC
|
||||
|
||||
f = Config::GetConfigFile("bios9.bin", "rb");
|
||||
f = melon_fopen_local("bios9.bin", "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf("ARM9 BIOS not found\n");
|
||||
|
@ -403,7 +404,7 @@ void Reset()
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
f = Config::GetConfigFile("bios7.bin", "rb");
|
||||
f = melon_fopen_local("bios7.bin", "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf("ARM7 BIOS not found\n");
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "Config.h"
|
||||
#include "NDS.h"
|
||||
#include "SPI.h"
|
||||
#include "melon_fopen.h"
|
||||
|
||||
|
||||
namespace SPI_Firmware
|
||||
|
@ -89,7 +90,7 @@ void Reset()
|
|||
if (Firmware) delete[] Firmware;
|
||||
Firmware = NULL;
|
||||
|
||||
FILE* f = Config::GetConfigFile("firmware.bin", "rb");
|
||||
FILE* f = melon_fopen_local("firmware.bin", "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf("firmware.bin not found\n");
|
||||
|
@ -129,7 +130,7 @@ void Reset()
|
|||
|
||||
// take a backup
|
||||
char* firmbkp = "firmware.bin.bak";
|
||||
f = Config::GetConfigFile(firmbkp, "rb");
|
||||
f = melon_fopen_local(firmbkp, "rb");
|
||||
if (f) fclose(f);
|
||||
else
|
||||
{
|
||||
|
@ -324,7 +325,7 @@ void Write(u8 val, u32 hold)
|
|||
|
||||
if (!hold && (CurCmd == 0x02 || CurCmd == 0x0A))
|
||||
{
|
||||
FILE* f = Config::GetConfigFile("firmware.bin", "r+b");
|
||||
FILE* f = melon_fopen_local("firmware.bin", "r+b");
|
||||
if (f)
|
||||
{
|
||||
u32 cutoff = 0x7FA00 & FirmwareMask;
|
||||
|
|
|
@ -52,6 +52,9 @@ const int kScreenLayout[3] = {0, 1, 2};
|
|||
const int kScreenSizing[4] = {0, 1, 2, 3};
|
||||
|
||||
|
||||
char* EmuDirectory;
|
||||
|
||||
|
||||
uiWindow* MainWindow;
|
||||
uiArea* MainDrawArea;
|
||||
|
||||
|
@ -116,7 +119,7 @@ void GetSavestateName(int slot, char* filename, int len);
|
|||
|
||||
|
||||
|
||||
bool FileExists(char* name)
|
||||
bool FileExists(const char* name)
|
||||
{
|
||||
FILE* f = melon_fopen(name, "rb");
|
||||
if (!f) return false;
|
||||
|
@ -124,6 +127,14 @@ bool FileExists(char* name)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LocalFileExists(const char* name)
|
||||
{
|
||||
FILE* f = melon_fopen_local(name, "rb");
|
||||
if (!f) return false;
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void UpdateWindowTitle(void* data)
|
||||
{
|
||||
|
@ -1308,6 +1319,19 @@ int main(int argc, char** argv)
|
|||
printf("melonDS " MELONDS_VERSION "\n");
|
||||
printf(MELONDS_URL "\n");
|
||||
|
||||
{
|
||||
int len = strlen(argv[0]);
|
||||
while (len > 0)
|
||||
{
|
||||
if (argv[0][len] == '/') break;
|
||||
if (argv[0][len] == '\\') break;
|
||||
len--;
|
||||
}
|
||||
EmuDirectory = new char[len];
|
||||
strncpy(EmuDirectory, argv[0], len);
|
||||
EmuDirectory[len] = '\0';
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||
|
||||
|
@ -1335,7 +1359,7 @@ int main(int argc, char** argv)
|
|||
|
||||
Config::Load();
|
||||
|
||||
if (!Config::HasConfigFile("bios7.bin") || !Config::HasConfigFile("bios9.bin") || !Config::HasConfigFile("firmware.bin"))
|
||||
if (!LocalFileExists("bios7.bin") || !LocalFileExists("bios9.bin") || !LocalFileExists("firmware.bin"))
|
||||
{
|
||||
uiMsgBoxError(
|
||||
NULL,
|
||||
|
@ -1618,6 +1642,7 @@ int main(int argc, char** argv)
|
|||
|
||||
uiUninit();
|
||||
SDL_Quit();
|
||||
delete[] EmuDirectory;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1627,41 +1652,26 @@ int main(int argc, char** argv)
|
|||
|
||||
int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdshow)
|
||||
{
|
||||
char cmdargs[16][256];
|
||||
int arg = 1;
|
||||
int j = 0;
|
||||
bool inquote = false;
|
||||
int len = strlen(cmdline);
|
||||
for (int i = 0; i < len; i++)
|
||||
int argc = 0;
|
||||
wchar_t** argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
char* nullarg = "";
|
||||
|
||||
char** argv = new char*[argc];
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
char c = cmdline[i];
|
||||
if (c == '\0') break;
|
||||
if (c == '"') inquote = !inquote;
|
||||
if (!inquote && c==' ')
|
||||
{
|
||||
if (j > 255) j = 255;
|
||||
if (arg < 16) cmdargs[arg][j] = '\0';
|
||||
arg++;
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arg < 16 && j < 255) cmdargs[arg][j] = c;
|
||||
j++;
|
||||
}
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, NULL, 0, NULL, NULL);
|
||||
if (len < 1) return NULL;
|
||||
argv[i] = new char[len];
|
||||
int res = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, argv[i], len, NULL, NULL);
|
||||
if (res != len) { delete[] argv[i]; argv[i] = nullarg; }
|
||||
}
|
||||
if (j > 255) j = 255;
|
||||
if (arg < 16) cmdargs[arg][j] = '\0';
|
||||
if (len > 0) arg++;
|
||||
|
||||
// FIXME!!
|
||||
strncpy(cmdargs[0], "melonDS.exe", 256);
|
||||
int ret = main(argc, argv);
|
||||
|
||||
char* cmdargptr[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
cmdargptr[i] = &cmdargs[i][0];
|
||||
for (int i = 0; i < argc; i++) if (argv[i] != nullarg) delete[] argv[i];
|
||||
delete[] argv;
|
||||
|
||||
return main(arg, cmdargptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
Copyright 2016-2019 StapleButter
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK
|
||||
#include <windows.h>
|
||||
//#include <knownfolders.h> // FUCK THAT SHIT
|
||||
extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}};
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
extern char* EmuDirectory;
|
||||
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
|
||||
|
||||
FILE* melon_fopen(const char* path, const char* mode)
|
||||
{
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
|
||||
if (len < 1) return NULL;
|
||||
WCHAR* fatass = new WCHAR[len];
|
||||
int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, fatass, len);
|
||||
if (res != len) { delete[] fatass; return NULL; } // checkme?
|
||||
|
||||
// this will be more than enough
|
||||
WCHAR fatmode[4];
|
||||
fatmode[0] = mode[0];
|
||||
fatmode[1] = mode[1];
|
||||
fatmode[2] = mode[2];
|
||||
fatmode[3] = 0;
|
||||
|
||||
FILE* ret = _wfopen(fatass, fatmode);
|
||||
delete[] fatass;
|
||||
return ret;
|
||||
}
|
||||
|
||||
FILE* melon_fopen_local(const char* fileName, const char* permissions)
|
||||
{
|
||||
// Locations are application directory, and AppData/melonDS on windows
|
||||
|
||||
FILE* f;
|
||||
|
||||
// First check current working directory
|
||||
f = fopen(fileName, permissions);
|
||||
if (f) return f;
|
||||
|
||||
// then emu directory
|
||||
{
|
||||
int dirlen = strlen(EmuDirectory);
|
||||
if (dirlen)
|
||||
{
|
||||
int filelen = strlen(fileName);
|
||||
int len = dirlen + 1 + filelen + 1;
|
||||
char* tmp = new char[len];
|
||||
strncpy(&tmp[0], EmuDirectory, dirlen);
|
||||
tmp[dirlen] = '\\';
|
||||
strncpy(&tmp[dirlen+1], fileName, filelen);
|
||||
tmp[dirlen+1+filelen] = '\0';
|
||||
|
||||
f = melon_fopen(tmp, permissions);
|
||||
delete[] tmp;
|
||||
if (f) return f;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check AppData
|
||||
PWSTR appDataPath = NULL;
|
||||
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appDataPath);
|
||||
if (!appDataPath)
|
||||
return NULL;
|
||||
|
||||
// this will be more than enough
|
||||
WCHAR fatperm[4];
|
||||
fatperm[0] = permissions[0];
|
||||
fatperm[1] = permissions[1];
|
||||
fatperm[2] = permissions[2];
|
||||
fatperm[3] = 0;
|
||||
|
||||
int fnlen = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, NULL, 0);
|
||||
if (fnlen < 1) return NULL;
|
||||
WCHAR* wfileName = new WCHAR[fnlen];
|
||||
int res = MultiByteToWideChar(CP_UTF8, 0, fileName, -1, wfileName, fnlen);
|
||||
if (res != fnlen) { delete[] wfileName; return NULL; } // checkme?
|
||||
|
||||
const WCHAR* appdir = L"\\melonDS\\";
|
||||
|
||||
int pos = wcslen(appDataPath);
|
||||
void* ptr = CoTaskMemRealloc(appDataPath, (pos+wcslen(appdir)+fnlen+1)*sizeof(WCHAR));
|
||||
if (!ptr) { delete[] wfileName; return NULL; } // oh well
|
||||
appDataPath = (PWSTR)ptr;
|
||||
|
||||
wcscpy(&appDataPath[pos], appdir); pos += wcslen(appdir);
|
||||
wcscpy(&appDataPath[pos], wfileName);
|
||||
|
||||
f = _wfopen(appDataPath, fatperm);
|
||||
CoTaskMemFree(appDataPath);
|
||||
delete[] wfileName;
|
||||
if (f) return f;
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
||||
FILE* melon_fopen(const char* filename, const char* perm) { return fopen(filename, perm); }
|
||||
|
||||
FILE* GetConfigFile(const char* fileName, const char* permissions)
|
||||
{
|
||||
// Locations are application directory, and XDG_CONFIG_HOME/melonds
|
||||
|
||||
FILE* f;
|
||||
|
||||
// First check current working directory
|
||||
f = fopen(fileName, permissions);
|
||||
if (f) return f;
|
||||
|
||||
// then emu directory
|
||||
{
|
||||
int dirlen = strlen(EmuDirectory);
|
||||
if (dirlen)
|
||||
{
|
||||
int filelen = strlen(fileName);
|
||||
int len = dirlen + 1 + filelen + 1;
|
||||
char* tmp = new char[len];
|
||||
strncpy(&tmp[0], EmuDirectory, dirlen);
|
||||
tmp[dirlen] = '\\';
|
||||
strncpy(&tmp[dirlen+1], fileName, filelen);
|
||||
tmp[dirlen+1+filelen] = '\0';
|
||||
|
||||
f = fopen(tmp, permissions);
|
||||
delete[] tmp;
|
||||
if (f) return f;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check XDG_CONFIG_HOME
|
||||
// TODO: check for memory leak there
|
||||
std::string path = std::string(g_get_user_config_dir()) + "/melonds/" + fileName;
|
||||
f = fopen(path.c_str(), permissions);
|
||||
if (f) return f;
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -19,34 +19,9 @@
|
|||
#ifndef MELON_FOPEN_H
|
||||
#define MELON_FOPEN_H
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
#include <windows.h>
|
||||
FILE* melon_fopen(const char* filename, const char* perm);
|
||||
FILE* melon_fopen_local(const char* filename, const char* perm);
|
||||
|
||||
static FILE* melon_fopen(const char* path, const char* mode)
|
||||
{
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
|
||||
if (len < 1) return NULL;
|
||||
WCHAR* fatass = new WCHAR[len];
|
||||
int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, fatass, len);
|
||||
if (res != len) { delete[] fatass; return NULL; } // checkme?
|
||||
|
||||
// this will be more than enough
|
||||
WCHAR fatmode[4];
|
||||
fatmode[0] = mode[0];
|
||||
fatmode[1] = mode[1];
|
||||
fatmode[2] = mode[2];
|
||||
fatmode[3] = 0;
|
||||
|
||||
FILE* ret = _wfopen(fatass, fatmode);
|
||||
delete[] fatass;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define melon_fopen fopen
|
||||
|
||||
#endif
|
||||
|
||||
#endif // MELON_FOPEN_H
|
||||
|
|
Loading…
Reference in New Issue