mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-12-22 16:30:23 +00:00
Using Short Paths (ASCII-compatible) for Exe Dir and User Dir on Windows (#77)
Co-authored-by: Agent X <44549182+AgentXLP@users.noreply.github.com>
This commit is contained in:
parent
f348e03685
commit
227a4bbcf3
17 changed files with 191 additions and 228 deletions
2
Makefile
2
Makefile
|
@ -785,7 +785,7 @@ ifneq ($(SDL1_USED)$(SDL2_USED),00)
|
|||
endif
|
||||
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
BACKEND_LDFLAGS += `$(SDLCONFIG) --static-libs` -lsetupapi -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion
|
||||
BACKEND_LDFLAGS += `$(SDLCONFIG) --static-libs` -lsetupapi -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lshlwapi -lwinmm -lversion
|
||||
else
|
||||
BACKEND_LDFLAGS += `$(SDLCONFIG) --libs`
|
||||
endif
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "pc/ini.h"
|
||||
#include "pc/mods/mods.h"
|
||||
#include "pc/mods/mods_utils.h"
|
||||
#include "pc/os/os.h"
|
||||
#include "player_palette.h"
|
||||
|
||||
const struct PlayerPalette DEFAULT_MARIO_PALETTE =
|
||||
|
@ -64,14 +63,14 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
}
|
||||
|
||||
// open directory
|
||||
os_dirent* dir = NULL;
|
||||
struct dirent* dir = NULL;
|
||||
|
||||
OS_DIR* d = os_opendir(lpath);
|
||||
DIR* d = opendir(lpath);
|
||||
if (!d) { return; }
|
||||
|
||||
// iterate
|
||||
char path[SYS_MAX_PATH] = { 0 };
|
||||
while ((dir = os_readdir(d)) != NULL) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
// sanity check / fill path[]
|
||||
if (!directory_sanity_check(dir, lpath, path)) { continue; }
|
||||
snprintf(path, SYS_MAX_PATH, "%s", os_get_dir_name(dir));
|
||||
|
@ -113,7 +112,7 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
if (gPresetPaletteCount >= MAX_PRESET_PALETTES) { break; }
|
||||
}
|
||||
|
||||
os_closedir(d);
|
||||
closedir(d);
|
||||
|
||||
// this should mean we are in the exe path's palette dir
|
||||
if (appendPalettes) {
|
||||
|
@ -128,7 +127,7 @@ void player_palettes_read(const char* palettesPath, bool appendPalettes) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// copy remaining palettes
|
||||
for (int i = 0; i < gPresetPaletteCount; i++) {
|
||||
bool isCharacterPalette = false;
|
||||
|
|
|
@ -40,7 +40,7 @@ static CrashHandlerText sCrashHandlerText[128 + 256 + 4];
|
|||
#define PTR long long unsigned int)(uintptr_t
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define MEMNEW(typ, cnt) calloc(sizeof(typ), cnt)
|
||||
#define MEMNEW(typ, cnt) calloc(cnt, sizeof(typ))
|
||||
#define STRING(str, size, fmt, ...) char str[size]; snprintf(str, size, fmt, __VA_ARGS__);
|
||||
|
||||
#define BACK_TRACE_SIZE 15
|
||||
|
@ -457,15 +457,9 @@ static void crash_handler(const int signalNum, siginfo_t *info, UNUSED ucontext_
|
|||
|
||||
// Load symbols
|
||||
char filename[256] = { 0 };
|
||||
if (GetModuleFileName(NULL, filename, sizeof(filename))) {
|
||||
int index = strlen(filename);
|
||||
while (--index > 0) {
|
||||
if (filename[index] == '\\') {
|
||||
filename[index] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
strncat(filename, "\\coop.map", 255);
|
||||
const char *exe_path = sys_exe_path();
|
||||
if (NULL != exe_path) {
|
||||
snprintf(filename, 256, "%s/%s", exe_path, "coop.map");
|
||||
} else {
|
||||
snprintf(filename, 256, "%s", "coop.map");
|
||||
}
|
||||
|
|
|
@ -17,12 +17,9 @@ bool djui_language_init(char* lang) {
|
|||
}
|
||||
|
||||
// construct path
|
||||
char exePath[SYS_MAX_PATH] = "";
|
||||
path_get_folder((char*)path_to_executable(), exePath);
|
||||
|
||||
char path[SYS_MAX_PATH] = "";
|
||||
if (!lang || lang[0] == '\0') { lang = "English"; }
|
||||
snprintf(path, SYS_MAX_PATH, "%s/lang/%s.ini", exePath, lang);
|
||||
snprintf(path, SYS_MAX_PATH, "%s/lang/%s.ini", sys_exe_path(), lang);
|
||||
|
||||
// load
|
||||
sLang = ini_load(path);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "pc/debuglog.h"
|
||||
#include "pc/utils/misc.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/os/os.h"
|
||||
#include "pc/lua/smlua_hooks.h"
|
||||
#include "game/bettercamera.h"
|
||||
|
||||
|
@ -86,9 +85,9 @@ void djui_panel_language_create(struct DjuiBase* caller) {
|
|||
snprintf(lpath, SYS_MAX_PATH, "%s/lang", sys_exe_path());
|
||||
|
||||
// open directory
|
||||
os_dirent* dir = NULL;
|
||||
struct dirent* dir = NULL;
|
||||
|
||||
OS_DIR* d = os_opendir(lpath);
|
||||
DIR* d = opendir(lpath);
|
||||
if (!d) {
|
||||
LOG_ERROR("Could not open directory '%s'", lpath);
|
||||
|
||||
|
@ -111,10 +110,10 @@ void djui_panel_language_create(struct DjuiBase* caller) {
|
|||
|
||||
// iterate
|
||||
char path[SYS_MAX_PATH] = { 0 };
|
||||
while ((dir = os_readdir(d)) != NULL) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
// sanity check / fill path[]
|
||||
//if (!directory_sanity_check(dir, lpath, path)) { continue; }
|
||||
snprintf(path, SYS_MAX_PATH, "%s", os_get_dir_name(dir));
|
||||
snprintf(path, SYS_MAX_PATH, "%s", dir->d_name);
|
||||
|
||||
// strip the name before the .
|
||||
char* c = path;
|
||||
|
@ -130,7 +129,7 @@ void djui_panel_language_create(struct DjuiBase* caller) {
|
|||
if (!strcmp(path, "English")) { chkEnglish = checkbox; }
|
||||
}
|
||||
|
||||
os_closedir(d);
|
||||
closedir(d);
|
||||
|
||||
if (!foundMatch && chkEnglish) {
|
||||
chkEnglish->value = &sTrue;
|
||||
|
|
|
@ -51,6 +51,11 @@ bool fs_init(const char *writepath) {
|
|||
printf("FS: writepath set to `%s`\n", fs_writepath);
|
||||
#endif
|
||||
|
||||
// we shall not progress any further if the path is inaccessible
|
||||
if ('\0' == fs_writepath[0]) {
|
||||
sys_fatal("Could not access the User Preferences directory.");
|
||||
}
|
||||
|
||||
fs_mount(fs_writepath);
|
||||
|
||||
return true;
|
||||
|
@ -244,11 +249,13 @@ const char *fs_get_write_path(const char *vpath) {
|
|||
return path;
|
||||
}
|
||||
|
||||
const char *fs_convert_path(char *buf, const size_t bufsiz, const char *path) {
|
||||
const char *fs_convert_path(char *buf, const size_t bufsiz, const char *path) {
|
||||
if (NULL == path) { return ""; }
|
||||
|
||||
// ! means "executable directory"
|
||||
if (path[0] == '!') {
|
||||
if (snprintf(buf, bufsiz, "%s%s", sys_exe_path(), path + 1) < 0) {
|
||||
return NULL;
|
||||
if (snprintf(buf, bufsiz, "%s%s", sys_exe_path(), path + 1) < 0) {
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
strncpy(buf, path, bufsiz);
|
||||
|
@ -262,8 +269,33 @@ const char *fs_convert_path(char *buf, const size_t bufsiz, const char *path) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
bool fs_sys_filename_is_portable(char const *filename) {
|
||||
char c;
|
||||
while (0 != (c = *(filename++))) {
|
||||
|
||||
if (c < ' ' || c > '~') {
|
||||
// character outside of printable range
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
// characters unallowed in filenames
|
||||
case '/': case '\\': case '<': case '>':
|
||||
case ':': case '"': case '|': case '?': case '*':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* these operate on the real file system */
|
||||
|
||||
bool fs_sys_path_exists(const char *name) {
|
||||
struct stat st;
|
||||
return (stat(name, &st) == 0);
|
||||
}
|
||||
|
||||
bool fs_sys_file_exists(const char *name) {
|
||||
struct stat st;
|
||||
return (stat(name, &st) == 0 && S_ISREG(st.st_mode));
|
||||
|
@ -286,7 +318,7 @@ bool fs_sys_dir_is_empty(const char *name) {
|
|||
bool ret = true;
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
// skip "." and ".."
|
||||
if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0' ||
|
||||
if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0' ||
|
||||
(ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
@ -340,36 +372,17 @@ bool fs_sys_walk(const char *base, walk_fn_t walk, void *user, const bool recur)
|
|||
}
|
||||
|
||||
bool fs_sys_mkdir(const char *name) {
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
return _mkdir(name) == 0;
|
||||
#else
|
||||
#else
|
||||
return mkdir(name, 0777) == 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fs_sys_copy_file(const char *oldname, const char *newname) {
|
||||
uint8_t buf[2048];
|
||||
|
||||
FILE *fin = fopen(oldname, "rb");
|
||||
if (!fin) return false;
|
||||
|
||||
FILE *fout = fopen(newname, "wb");
|
||||
if (!fout) {
|
||||
fclose(fin);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
size_t rx;
|
||||
while ((rx = fread(buf, 1, sizeof(buf), fin)) > 0) {
|
||||
if (!fwrite(buf, rx, 1, fout)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fout);
|
||||
fclose(fin);
|
||||
|
||||
return ret;
|
||||
bool fs_sys_rmdir(const char *name) {
|
||||
#ifdef _WIN32
|
||||
return _rmdir(name) == 0;
|
||||
#else
|
||||
return rmdir(name) == 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -97,13 +97,16 @@ const char *fs_get_write_path(const char *vpath);
|
|||
// expands special chars in paths and changes backslashes to forward slashes
|
||||
const char *fs_convert_path(char *buf, const size_t bufsiz, const char *path);
|
||||
|
||||
bool fs_sys_filename_is_portable(char const *filename);
|
||||
|
||||
/* these operate on the real filesystem and are used by fs_packtype_dir */
|
||||
|
||||
bool fs_sys_walk(const char *base, walk_fn_t walk, void *user, const bool recur);
|
||||
bool fs_sys_path_exists(const char *name);
|
||||
bool fs_sys_file_exists(const char *name);
|
||||
bool fs_sys_dir_exists(const char *name);
|
||||
bool fs_sys_dir_is_empty(const char *name);
|
||||
bool fs_sys_mkdir(const char *name); // creates with 0777 by default
|
||||
bool fs_sys_copy_file(const char *oldname, const char *newname);
|
||||
bool fs_sys_rmdir(const char *name); // removes an empty directory
|
||||
|
||||
#endif // _SM64_FS_H_
|
||||
|
|
|
@ -454,18 +454,18 @@ bool mod_load(struct Mods* mods, char* basePath, char* modName) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool isDirectory = is_directory(fullPath);
|
||||
bool isDirectory = fs_sys_dir_exists(fullPath);
|
||||
|
||||
// make sure mod is valid
|
||||
if (str_ends_with(modName, ".lua")) {
|
||||
valid = true;
|
||||
} else if (is_directory(fullPath)) {
|
||||
} else if (fs_sys_dir_exists(fullPath)) {
|
||||
char tmpPath[SYS_MAX_PATH] = { 0 };
|
||||
if (!concat_path(tmpPath, fullPath, "main.lua")) {
|
||||
LOG_ERROR("Failed to concat path '%s' + '%s'", fullPath, "main.lua");
|
||||
return true;
|
||||
}
|
||||
valid = path_exists(tmpPath);
|
||||
valid = fs_sys_path_exists(tmpPath);
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
|
|
|
@ -115,7 +115,7 @@ C_FIELD const char* mod_storage_load(const char* key) {
|
|||
|
||||
char filename[SYS_MAX_PATH] = { 0 };
|
||||
mod_storage_get_filename(filename);
|
||||
if (!path_exists(filename)) { return NULL; }
|
||||
if (!fs_sys_path_exists(filename)) { return NULL; }
|
||||
|
||||
mINI::INIFile file(filename);
|
||||
mINI::INIStructure ini;
|
||||
|
@ -152,7 +152,7 @@ C_FIELD bool mod_storage_remove(const char* key) {
|
|||
|
||||
char filename[SYS_MAX_PATH] = { 0 };
|
||||
mod_storage_get_filename(filename);
|
||||
if (!path_exists(filename)) { return false; }
|
||||
if (!fs_sys_path_exists(filename)) { return false; }
|
||||
|
||||
mINI::INIFile file(filename);
|
||||
mINI::INIStructure ini;
|
||||
|
@ -172,7 +172,7 @@ C_FIELD bool mod_storage_clear(void) {
|
|||
|
||||
char filename[SYS_MAX_PATH] = { 0 };
|
||||
mod_storage_get_filename(filename);
|
||||
if (!path_exists(filename)) { return false; }
|
||||
if (!fs_sys_path_exists(filename)) { return false; }
|
||||
|
||||
mINI::INIFile file(filename);
|
||||
mINI::INIStructure ini;
|
||||
|
|
|
@ -218,7 +218,7 @@ static void mods_load(struct Mods* mods, char* modsBasePath, UNUSED bool isUserM
|
|||
normalize_path(modsBasePath);
|
||||
|
||||
// check for existence
|
||||
if (!is_directory(modsBasePath)) {
|
||||
if (!fs_sys_dir_exists(modsBasePath)) {
|
||||
LOG_ERROR("Could not find directory '%s'", modsBasePath);
|
||||
}
|
||||
|
||||
|
@ -275,10 +275,8 @@ void mods_refresh_local(void) {
|
|||
// load mods
|
||||
if (hasUserPath) { mods_load(&gLocalMods, userModPath, true); }
|
||||
|
||||
const char* exePath = path_to_executable();
|
||||
char defaultModsPath[SYS_MAX_PATH] = { 0 };
|
||||
path_get_folder((char*)exePath, defaultModsPath);
|
||||
strncat(defaultModsPath, MOD_DIRECTORY, SYS_MAX_PATH-1);
|
||||
snprintf(defaultModsPath, SYS_MAX_PATH, "%s/%s", sys_exe_path(), MOD_DIRECTORY);
|
||||
mods_load(&gLocalMods, defaultModsPath, false);
|
||||
|
||||
// sort
|
||||
|
|
|
@ -93,7 +93,7 @@ void mods_delete_folder(char* path) {
|
|||
if (!strcmp(dir->d_name, "..")) { continue; }
|
||||
if (!concat_path(fullPath, path, dir->d_name)) { continue; }
|
||||
|
||||
if (is_directory(fullPath)) {
|
||||
if (fs_sys_dir_exists(fullPath)) {
|
||||
mods_delete_folder(fullPath);
|
||||
} else if (fs_sys_file_exists(fullPath)) {
|
||||
if (unlink(fullPath) == -1) {
|
||||
|
@ -185,75 +185,6 @@ char* extract_lua_field(char* fieldName, char* buffer) {
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const char* path_to_executable(void) {
|
||||
static char exePath[SYS_MAX_PATH] = { 0 };
|
||||
if (exePath[0] != '\0') { return exePath; }
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HMODULE hModule = GetModuleHandle(NULL);
|
||||
if (hModule == NULL) {
|
||||
LOG_ERROR("unable to retrieve absolute windows path!");
|
||||
return NULL;
|
||||
}
|
||||
GetModuleFileName(hModule, exePath, SYS_MAX_PATH-1);
|
||||
#elif defined(OSX_BUILD)
|
||||
u32 bufsize = SYS_MAX_PATH-1;
|
||||
if (_NSGetExecutablePath(exePath, &bufsize) != 0) {
|
||||
LOG_ERROR("unable to retrieve absolute mac path!");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
char procPath[SYS_MAX_PATH] = { 0 };
|
||||
snprintf(procPath, SYS_MAX_PATH-1, "/proc/%d/exe", getpid());
|
||||
s32 rc = readlink(procPath, exePath, SYS_MAX_PATH-1);
|
||||
if (rc <= 0) {
|
||||
LOG_ERROR("unable to retrieve absolute linux path!");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return exePath;
|
||||
}
|
||||
|
||||
bool path_is_portable_filename(char* string) {
|
||||
char* s = string;
|
||||
while (*s != '\0') {
|
||||
char c = *s;
|
||||
|
||||
if (c < ' ' || c > '~') {
|
||||
// outside of printable range
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
// unallowed in filenames
|
||||
case '/':
|
||||
case '\\':
|
||||
case '<':
|
||||
case '>':
|
||||
case ':':
|
||||
case '"':
|
||||
case '|':
|
||||
case '?':
|
||||
case '*':
|
||||
return false;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool path_exists(char* path) {
|
||||
struct stat sb = { 0 };
|
||||
return (stat(path, &sb) == 0);
|
||||
}
|
||||
|
||||
bool is_directory(char* path) {
|
||||
struct stat sb = { 0 };
|
||||
return (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode));
|
||||
}
|
||||
|
||||
void normalize_path(char* path) {
|
||||
// replace slashes
|
||||
char* p = path;
|
||||
|
@ -298,7 +229,7 @@ void path_get_folder(char* path, char* outpath) {
|
|||
|
||||
bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath) {
|
||||
// skip non-portable filenames
|
||||
if (!path_is_portable_filename(dir->d_name)) { return false; }
|
||||
if (!fs_sys_filename_is_portable(dir->d_name)) { return false; }
|
||||
|
||||
// skip anything that contains \ or /
|
||||
if (strchr(dir->d_name, '/') != NULL) { return false; }
|
||||
|
@ -315,7 +246,7 @@ bool directory_sanity_check(struct dirent* dir, char* dirPath, char* outPath) {
|
|||
normalize_path(outPath);
|
||||
|
||||
// sanity check
|
||||
if (!path_exists(outPath)) {
|
||||
if (!fs_sys_path_exists(outPath)) {
|
||||
LOG_ERROR("Path doesn't exist: '%s'", outPath);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,6 @@ bool str_ends_with(const char* string, const char* suffix);
|
|||
|
||||
char* extract_lua_field(char* fieldName, char* buffer);
|
||||
|
||||
const char* path_to_executable(void);
|
||||
bool path_is_portable_filename(char* string);
|
||||
bool path_exists(char* path);
|
||||
bool is_directory(char* path);
|
||||
void normalize_path(char* path);
|
||||
bool concat_path(char* destination, char* path, char* fname);
|
||||
char* path_basename(char* path);
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
|
||||
#include "os_win.h"
|
||||
#else
|
||||
#include "os_other.h"
|
||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#define os_dirent struct dirent
|
||||
#define OS_DIR DIR
|
||||
#define os_opendir(_x) opendir(_x)
|
||||
#define os_readdir(_x) readdir(_x)
|
||||
#define os_closedir(_x) closedir(_x)
|
||||
#define os_get_dir_name(_x) _x->d_name
|
|
@ -1,20 +0,0 @@
|
|||
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stringapiset.h>
|
||||
#include "os_win.h"
|
||||
#include "pc/platform.h"
|
||||
|
||||
OS_DIR* os_opendir(const char* path) {
|
||||
wchar_t wpath[SYS_MAX_PATH] = { 0 };
|
||||
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, SYS_MAX_PATH);
|
||||
return _wopendir(wpath);
|
||||
}
|
||||
|
||||
const char* os_get_dir_name(os_dirent* dir) {
|
||||
static char path[SYS_MAX_PATH] = { 0 };
|
||||
snprintf(path, SYS_MAX_PATH, "%ls", dir->d_name);
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <wchar.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#define os_dirent struct _wdirent
|
||||
#define OS_DIR _WDIR
|
||||
|
||||
#define os_closedir(_x) _wclosedir(_x)
|
||||
#define os_readdir(_x) _wreaddir(_x)
|
||||
|
||||
OS_DIR* os_opendir(const char* path);
|
||||
const char* os_get_dir_name(os_dirent* dir);
|
|
@ -5,6 +5,12 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#endif
|
||||
|
||||
#include "cliopts.h"
|
||||
#include "fs/fs.h"
|
||||
#include "configfile.h"
|
||||
|
@ -76,57 +82,133 @@ void sys_fatal(const char *fmt, ...) {
|
|||
sys_fatal_impl(msg);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SDL2
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
static BOOL sys_windows_short_path(LPSTR destPath, SIZE_T destSize, LPWSTR wideLongPath)
|
||||
{
|
||||
WCHAR wideShortPath[SYS_MAX_PATH];
|
||||
|
||||
// Convert the Long Path in Wide Format to the alternate short form.
|
||||
// It will still point to already existing directory.
|
||||
if (0 == GetShortPathNameW(wideLongPath, wideShortPath, SYS_MAX_PATH)) { return FALSE; }
|
||||
|
||||
// Short Path can be safely represented by the US-ASCII Charset.
|
||||
return (WideCharToMultiByte(CP_ACP, 0, wideShortPath, (-1), destPath, destSize, NULL, NULL) > 0);
|
||||
}
|
||||
|
||||
const char *sys_user_path(void)
|
||||
{
|
||||
static char shortPath[SYS_MAX_PATH] = { 0 };
|
||||
if ('\0' != shortPath[0]) { return shortPath; }
|
||||
|
||||
WCHAR widePath[SYS_MAX_PATH];
|
||||
|
||||
// "%USERPROFILE%\AppData\Roaming"
|
||||
WCHAR *wcsAppDataPath = NULL;
|
||||
HRESULT res = SHGetKnownFolderPath(
|
||||
&(FOLDERID_RoamingAppData),
|
||||
(KF_FLAG_CREATE | KF_FLAG_DONT_UNEXPAND),
|
||||
NULL, &(wcsAppDataPath));
|
||||
|
||||
if (S_OK != res)
|
||||
{
|
||||
if (NULL != wcsAppDataPath) { CoTaskMemFree(wcsAppDataPath); }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LPCWSTR subdirs[] = { L"sm64ex-coop", L"sm64coopdx", NULL };
|
||||
|
||||
for (int i = 0; NULL != subdirs[i]; i++)
|
||||
{
|
||||
if (_snwprintf(widePath, SYS_MAX_PATH, L"%s\\%s", wcsAppDataPath, subdirs[i]) <= 0) { return NULL; }
|
||||
|
||||
// Directory already exists.
|
||||
if (FALSE != PathIsDirectoryW(widePath))
|
||||
{
|
||||
// Directory is not empty, so choose this name.
|
||||
if (FALSE == PathIsDirectoryEmptyW(widePath)) { break; }
|
||||
}
|
||||
|
||||
// 'widePath' will hold the last checked subdir name.
|
||||
}
|
||||
|
||||
// System resource can be safely released now.
|
||||
if (NULL != wcsAppDataPath) { CoTaskMemFree(wcsAppDataPath); }
|
||||
|
||||
// Always try to create the directory pointed to by User Path,
|
||||
// but ignore errors if the destination already exists.
|
||||
if (FALSE == CreateDirectoryW(widePath, NULL))
|
||||
{
|
||||
if (ERROR_ALREADY_EXISTS != GetLastError()) { return NULL; }
|
||||
}
|
||||
|
||||
return sys_windows_short_path(shortPath, SYS_MAX_PATH, widePath) ? shortPath : NULL;
|
||||
}
|
||||
|
||||
const char *sys_exe_path(void)
|
||||
{
|
||||
static char shortPath[SYS_MAX_PATH] = { 0 };
|
||||
if ('\0' != shortPath[0]) { return shortPath; }
|
||||
|
||||
WCHAR widePath[SYS_MAX_PATH];
|
||||
if (0 == GetModuleFileNameW(NULL, widePath, SYS_MAX_PATH)) { return NULL; }
|
||||
|
||||
WCHAR *lastBackslash = wcsrchr(widePath, L'\\');
|
||||
if (NULL != lastBackslash) { *lastBackslash = L'\0'; }
|
||||
else { return NULL; }
|
||||
|
||||
return sys_windows_short_path(shortPath, SYS_MAX_PATH, widePath) ? shortPath : NULL;
|
||||
}
|
||||
|
||||
static void sys_fatal_impl(const char *msg) {
|
||||
MessageBoxA(NULL, msg, "Fatal error", MB_ICONERROR);
|
||||
fprintf(stderr, "FATAL ERROR:\n%s\n", msg);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SDL2)
|
||||
|
||||
// we can just ask SDL for most of this shit if we have it
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
static const char *sys_old_user_path(void) {
|
||||
static char path[SYS_MAX_PATH] = { 0 };
|
||||
|
||||
// get the new pref path from SDL
|
||||
char *sdlPath = SDL_GetPrefPath("", "sm64ex-coop");
|
||||
if (sdlPath) {
|
||||
const unsigned int len = strlen(sdlPath);
|
||||
snprintf(path, sizeof(path), "%s", sdlPath);
|
||||
path[sizeof(path)-1] = 0;
|
||||
|
||||
SDL_free(sdlPath);
|
||||
|
||||
// strip the trailing separator
|
||||
if (path[len-1] == '/' || path[len-1] == '\\') { path[len-1] = 0; }
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const char *sys_user_path(void) {
|
||||
static char path[SYS_MAX_PATH] = { 0 };
|
||||
if ('\0' != path[0]) { return path; }
|
||||
|
||||
// get the new pref path from SDL
|
||||
char *sdlPath = SDL_GetPrefPath("", "sm64coopdx");
|
||||
if (sdlPath) {
|
||||
// redirect to the old user path if the current one is empty (likely just created from SDL_GetPrefPath)
|
||||
if (fs_sys_dir_is_empty(sdlPath)) {
|
||||
char const *subdirs[] = { "sm64ex-coop", "sm64coopdx", NULL };
|
||||
|
||||
char *sdlPath = NULL;
|
||||
for (int i = 0; NULL != subdirs[i]; i++)
|
||||
{
|
||||
if (sdlPath) {
|
||||
// Previous dir likely just created with SDL_GetPrefPath.
|
||||
fs_sys_rmdir(sdlPath);
|
||||
SDL_free(sdlPath);
|
||||
return sys_old_user_path();
|
||||
}
|
||||
|
||||
const unsigned int len = strlen(sdlPath);
|
||||
snprintf(path, sizeof(path), "%s", sdlPath);
|
||||
path[sizeof(path)-1] = 0;
|
||||
sdlPath = SDL_GetPrefPath("", subdirs[i]);
|
||||
|
||||
SDL_free(sdlPath);
|
||||
|
||||
// strip the trailing separator
|
||||
if (path[len-1] == '/' || path[len-1] == '\\') { path[len-1] = 0; }
|
||||
// Choose this directory if it already exists and is not empty.
|
||||
if (sdlPath && !fs_sys_dir_is_empty(sdlPath)) { break; }
|
||||
}
|
||||
|
||||
if (NULL == sdlPath) { return NULL; }
|
||||
|
||||
strncpy(path, sdlPath, SYS_MAX_PATH - 1);
|
||||
SDL_free(sdlPath);
|
||||
|
||||
// strip the trailing separator
|
||||
const unsigned int len = strlen(path);
|
||||
if (path[len-1] == '/' || path[len-1] == '\\') { path[len-1] = 0; }
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const char *sys_exe_path(void) {
|
||||
static char path[SYS_MAX_PATH] = { 0 };
|
||||
if ('\0' != path[0]) { return path; }
|
||||
|
||||
char *sdlPath = SDL_GetBasePath();
|
||||
if (sdlPath && sdlPath[0]) {
|
||||
// use the SDL path if it exists
|
||||
|
|
Loading…
Reference in a new issue