stdclass: Add support for separate config/data dirs and system wide dirs
This adds support for separate config and data dirs. On Linux, these will be compliant XDG Basedir Specification, i.e. XDG_CONFIG_HOME and XDG_CONFIG_DIRS (or XDG_DATA_HOME and XDG_DATA_DIRS respectively). On all other platforms, there currently just set to the homedir path (so no previous behaviour has been changed). If reicast wants to read and write a data file, it just calls get_data_path("/samplefile.txt"). If it does not need to write to that file, it just uses get_data_path("/samplefile.txt", false). That way, we can also use system-wide dirs (like /usr/share/reicast on linux), that the user usually doesn't have write access to. The same applies for config file, where you use get_config_path(args) respectively.
This commit is contained in:
parent
c24a5faf5b
commit
b6d0cddcaa
|
@ -78,7 +78,7 @@ void cfgSaveStr(const wchar * Section, const wchar * Key, const wchar * String)
|
|||
|
||||
bool cfgOpen()
|
||||
{
|
||||
cfgPath=GetPath("/emu.cfg");
|
||||
cfgPath=get_config_path("/emu.cfg");
|
||||
FILE* cfgfile = fopen(cfgPath.c_str(),"r");
|
||||
|
||||
if(cfgfile != NULL) {
|
||||
|
|
|
@ -277,7 +277,7 @@ struct maple_sega_vmu: maple_base
|
|||
memset(lcd_data,0,sizeof(lcd_data));
|
||||
wchar tempy[512];
|
||||
sprintf(tempy,"/vmu_save_%s.bin",logical_port);
|
||||
string apath=GetPath(tempy);
|
||||
string apath=get_data_path(tempy);
|
||||
|
||||
file=fopen(apath.c_str(),"rb+");
|
||||
if (!file)
|
||||
|
|
|
@ -580,7 +580,7 @@ error:
|
|||
{
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
string path = GetPath("/dcnzorz_mem");
|
||||
string path = get_data_path("/dcnzorz_mem");
|
||||
fd = open(path.c_str(),O_CREAT|O_RDWR|O_TRUNC,S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
unlink(path.c_str());
|
||||
verify(ftruncate(fd,RAM_SIZE + VRAM_SIZE +ARAM_SIZE)==0);
|
||||
|
|
|
@ -607,7 +607,7 @@ void print_blocks()
|
|||
|
||||
if (print_stats)
|
||||
{
|
||||
f=fopen(GetPath("/blkmap.lst").c_str(),"w");
|
||||
f=fopen(get_data_path("/blkmap.lst").c_str(),"w");
|
||||
print_stats=0;
|
||||
|
||||
printf("Writing blocks to %p\n",f);
|
||||
|
|
|
@ -54,7 +54,7 @@ void emit_WriteCodeCache()
|
|||
{
|
||||
wchar path[512];
|
||||
sprintf(path,"/code_cache_%8p.bin",CodeCache);
|
||||
string pt2=GetPath(path);
|
||||
string pt2=get_data_path(path);
|
||||
printf("Writing code cache to %s\n",pt2.c_str());
|
||||
FILE*f=fopen(pt2.c_str(),"wb");
|
||||
if (f)
|
||||
|
|
|
@ -223,7 +223,7 @@ void mem_Term()
|
|||
sh4_area0_Term();
|
||||
|
||||
//write back Flash/SRAM
|
||||
SaveRomFiles(GetPath("/data/"));
|
||||
SaveRomFiles(get_data_path("/data/"));
|
||||
|
||||
//mem_b.Term(); // handled by vmem
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ void dc_run();
|
|||
}
|
||||
#endif
|
||||
|
||||
string get_config_dir()
|
||||
string find_user_config_dir()
|
||||
{
|
||||
#ifdef USES_HOMEDIR
|
||||
struct stat info;
|
||||
|
@ -259,14 +259,13 @@ string get_config_dir()
|
|||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
||||
*/
|
||||
home = (string)getenv("HOME") + "/.config/reicast";
|
||||
|
||||
}
|
||||
if(getenv("XDG_CONFIG_HOME") != NULL)
|
||||
{
|
||||
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
|
||||
home = (string)getenv("XDG_CONFIG_HOME") + "/reicast";
|
||||
}
|
||||
|
||||
|
||||
if(!home.empty())
|
||||
{
|
||||
if((stat(home.c_str(), &info) != 0) || !(info.st_mode & S_IFDIR))
|
||||
|
@ -277,11 +276,105 @@ string get_config_dir()
|
|||
return home;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Unable to detect config dir, use the current folder
|
||||
return ".";
|
||||
}
|
||||
|
||||
string find_user_data_dir()
|
||||
{
|
||||
#ifdef USES_HOMEDIR
|
||||
struct stat info;
|
||||
string data = "";
|
||||
if(getenv("HOME") != NULL)
|
||||
{
|
||||
// Support for the legacy config dir at "$HOME/.reicast"
|
||||
string legacy_data = (string)getenv("HOME") + "/.reicast";
|
||||
if((stat(legacy_data.c_str(), &info) == 0) && (info.st_mode & S_IFDIR))
|
||||
{
|
||||
// "$HOME/.reicast" already exists, let's use it!
|
||||
return legacy_data;
|
||||
}
|
||||
|
||||
/* If $XDG_DATA_HOME is not set, we're supposed to use "$HOME/.local/share" instead.
|
||||
* Consult the XDG Base Directory Specification for details:
|
||||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
||||
*/
|
||||
data = (string)getenv("HOME") + "/.local/share/reicast";
|
||||
}
|
||||
if(getenv("XDG_DATA_HOME") != NULL)
|
||||
{
|
||||
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.config
|
||||
data = (string)getenv("XDG_DATA_HOME") + "/reicast";
|
||||
}
|
||||
|
||||
if(!data.empty())
|
||||
{
|
||||
if((stat(data.c_str(), &info) != 0) || !(info.st_mode & S_IFDIR))
|
||||
{
|
||||
// If the directory doesn't exist yet, create it!
|
||||
mkdir(data.c_str(), 0755);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unable to detect config dir, use the current folder
|
||||
return ".";
|
||||
}
|
||||
|
||||
std::vector<string> find_system_config_dirs()
|
||||
{
|
||||
std::vector<string> dirs;
|
||||
if (getenv("XDG_DATA_DIRS") != NULL)
|
||||
{
|
||||
string s = (string)getenv("XDG_CONFIG_DIRS");
|
||||
|
||||
string::size_type pos = 0;
|
||||
string::size_type n = s.find(":", pos);
|
||||
while(n != std::string::npos)
|
||||
{
|
||||
dirs.push_back(s.substr(pos, n-pos) + "/reicast");
|
||||
pos = n + 1;
|
||||
n = s.find(":", pos);
|
||||
}
|
||||
// Separator not found
|
||||
dirs.push_back(s.substr(pos) + "/reicast");
|
||||
}
|
||||
else
|
||||
{
|
||||
dirs.push_back("/etc/xdg/reicast");
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
std::vector<string> find_system_data_dirs()
|
||||
{
|
||||
std::vector<string> dirs;
|
||||
if (getenv("XDG_DATA_DIRS") != NULL)
|
||||
{
|
||||
string s = (string)getenv("XDG_DATA_DIRS");
|
||||
|
||||
string::size_type pos = 0;
|
||||
string::size_type n = s.find(":", pos);
|
||||
while(n != std::string::npos)
|
||||
{
|
||||
dirs.push_back(s.substr(pos, n-pos) + "/reicast");
|
||||
pos = n + 1;
|
||||
n = s.find(":", pos);
|
||||
}
|
||||
// Separator not found
|
||||
dirs.push_back(s.substr(pos) + "/reicast");
|
||||
}
|
||||
else
|
||||
{
|
||||
dirs.push_back("/usr/local/share/reicast");
|
||||
dirs.push_back("/usr/share/reicast");
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, wchar* argv[])
|
||||
{
|
||||
#ifdef TARGET_PANDORA
|
||||
|
@ -289,9 +382,22 @@ int main(int argc, wchar* argv[])
|
|||
signal(SIGKILL, clean_exit);
|
||||
#endif
|
||||
|
||||
/* Set home dir */
|
||||
SetHomeDir(get_config_dir());
|
||||
printf("Home dir is: %s\n", GetPath("/").c_str());
|
||||
/* Set directories */
|
||||
set_user_config_dir(find_user_config_dir());
|
||||
set_user_data_dir(find_user_data_dir());
|
||||
std::vector<string> dirs;
|
||||
dirs = find_system_config_dirs();
|
||||
for(unsigned int i = 0; i < dirs.size(); i++)
|
||||
{
|
||||
add_system_data_dir(dirs[i]);
|
||||
}
|
||||
dirs = find_system_data_dirs();
|
||||
for(unsigned int i = 0; i < dirs.size(); i++)
|
||||
{
|
||||
add_system_data_dir(dirs[i]);
|
||||
}
|
||||
printf("Config dir is: %s\n", get_config_path("/").c_str());
|
||||
printf("Data dir is: %s\n", get_data_path("/").c_str());
|
||||
|
||||
common_linux_setup();
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ void* prof(void *ptr)
|
|||
|
||||
sprintf(line, "/%d.reprof", tick_count);
|
||||
|
||||
string logfile=GetPath(line);
|
||||
string logfile=get_data_path(line);
|
||||
|
||||
|
||||
printf("Profiler thread logging to -> %s\n", logfile.c_str());
|
||||
|
|
|
@ -48,7 +48,8 @@ void* emuthread(void* ) {
|
|||
char *Args[3];
|
||||
Args[0] = "dc";
|
||||
|
||||
SetHomeDir("/http");
|
||||
set_user_config_dir("/http");
|
||||
set_user_data_dir("/http");
|
||||
|
||||
dc_init(1,Args);
|
||||
dc_run();
|
||||
|
|
|
@ -165,9 +165,9 @@ int dc_init(int argc,wchar* argv[])
|
|||
#define DATA_PATH "/"
|
||||
#endif
|
||||
|
||||
if (settings.bios.UseReios || !LoadRomFiles(GetPath(DATA_PATH)))
|
||||
if (settings.bios.UseReios || !LoadRomFiles(get_data_path(DATA_PATH, false)))
|
||||
{
|
||||
if (!LoadHle(GetPath(DATA_PATH)))
|
||||
if (!LoadHle(get_data_path(DATA_PATH, false)))
|
||||
return -3;
|
||||
else
|
||||
printf("Did not load bios, using reios\n");
|
||||
|
@ -224,7 +224,7 @@ void dc_term()
|
|||
#ifndef _ANDROID
|
||||
SaveSettings();
|
||||
#endif
|
||||
SaveRomFiles(GetPath("/data/"));
|
||||
SaveRomFiles(get_data_path("/data/"));
|
||||
}
|
||||
|
||||
void LoadSettings()
|
||||
|
|
|
@ -930,9 +930,9 @@ bool gl_create_resources()
|
|||
#endif
|
||||
|
||||
int w, h;
|
||||
osd_tex=loadPNG(GetPath("/data/buttons.png"),w,h);
|
||||
osd_tex=loadPNG(get_data_path("/data/buttons.png", false),w,h);
|
||||
#ifdef TARGET_PANDORA
|
||||
osd_font=loadPNG(GetPath("/font2.png"),w,h);
|
||||
osd_font=loadPNG(get_data_path("/font2.png", false),w,h);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
|
|
@ -435,15 +435,19 @@ int main(int argc, wchar* argv[])
|
|||
{
|
||||
home += "/.reicast";
|
||||
mkdir(home.c_str(), 0755); // create the directory if missing
|
||||
SetHomeDir(home);
|
||||
set_user_config_dir(home);
|
||||
set_user_data_dir(home);
|
||||
}
|
||||
else
|
||||
SetHomeDir(".");
|
||||
set_user_config_dir(".");
|
||||
set_user_data_dir(".");
|
||||
#else
|
||||
SetHomeDir(".");
|
||||
set_user_config_dir(".");
|
||||
set_user_data_dir(".");
|
||||
#endif
|
||||
|
||||
printf("Home dir is: %s\n",GetPath("/").c_str());
|
||||
printf("Config dir is: %s\n", get_config_path("/").c_str());
|
||||
printf("Data dir is: %s\n", get_data_path("/").c_str());
|
||||
|
||||
common_linux_setup();
|
||||
|
||||
|
|
|
@ -1,22 +1,88 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "types.h"
|
||||
|
||||
string home_dir;
|
||||
string user_config_dir;
|
||||
string user_data_dir;
|
||||
std::vector<string> system_config_dirs;
|
||||
std::vector<string> system_data_dirs;
|
||||
|
||||
void SetHomeDir(const string& home)
|
||||
bool file_exists(const string& filename)
|
||||
{
|
||||
home_dir=home;
|
||||
struct stat info;
|
||||
return (stat (filename.c_str(), &info) == 0);
|
||||
}
|
||||
|
||||
//subpath format: /data/fsca-table.bit
|
||||
string GetPath(const string& subpath)
|
||||
void set_user_config_dir(const string& dir)
|
||||
{
|
||||
return (home_dir+subpath);
|
||||
user_config_dir = dir;
|
||||
}
|
||||
|
||||
void set_user_data_dir(const string& dir)
|
||||
{
|
||||
user_data_dir = dir;
|
||||
}
|
||||
|
||||
void add_system_config_dir(const string& dir)
|
||||
{
|
||||
system_config_dirs.push_back(dir);
|
||||
}
|
||||
|
||||
void add_system_data_dir(const string& dir)
|
||||
{
|
||||
system_data_dirs.push_back(dir);
|
||||
}
|
||||
|
||||
string get_config_path(const string& filename, bool user_writable)
|
||||
{
|
||||
if(user_writable)
|
||||
{
|
||||
/* Only stuff in the user_config_dir is supposed to be writable,
|
||||
* so we always return that.
|
||||
*/
|
||||
return (user_config_dir + filename);
|
||||
}
|
||||
|
||||
string filepath;
|
||||
for (unsigned int i = 0; i < system_config_dirs.size(); i++) {
|
||||
filepath = system_config_dirs[i] + filename;
|
||||
if (file_exists(filepath))
|
||||
{
|
||||
return filepath;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, so we return the user variant
|
||||
return (user_config_dir + filename);
|
||||
}
|
||||
|
||||
string get_data_path(const string& filename, bool user_writable)
|
||||
{
|
||||
if(user_writable)
|
||||
{
|
||||
/* Only stuff in the user_data_dir is supposed to be writable,
|
||||
* so we always return that.
|
||||
*/
|
||||
return (user_data_dir + filename);
|
||||
}
|
||||
|
||||
string filepath;
|
||||
for (unsigned int i = 0; i < system_data_dirs.size(); i++) {
|
||||
filepath = system_data_dirs[i] + filename;
|
||||
if (file_exists(filepath))
|
||||
{
|
||||
return filepath;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, so we return the user variant
|
||||
return (user_data_dir + filename);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -251,9 +251,14 @@ public :
|
|||
};
|
||||
|
||||
//Set the path !
|
||||
void SetHomeDir(const string& home);
|
||||
void set_user_config_dir(const string& dir);
|
||||
void set_user_data_dir(const string& dir);
|
||||
void add_system_config_dir(const string& dir);
|
||||
void add_system_data_dir(const string& dir);
|
||||
|
||||
//subpath format: /data/fsca-table.bit
|
||||
string GetPath(const string& subpath);
|
||||
string get_config_path(const string& filename, bool user_writable = true);
|
||||
string get_data_path(const string& filename, bool user_writable = true);
|
||||
|
||||
|
||||
class VArray2
|
||||
|
|
|
@ -79,7 +79,7 @@ enum demo_protocols {
|
|||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
||||
#define WEBUI_PATH GetPath("/webui")
|
||||
#define WEBUI_PATH get_data_path("/webui")
|
||||
|
||||
/*
|
||||
* We take a strict whitelist approach to stop ../ attacks
|
||||
|
|
|
@ -157,7 +157,8 @@ void SetupPath()
|
|||
GetModuleFileName(0,fname,512);
|
||||
string fn=string(fname);
|
||||
fn=fn.substr(0,fn.find_last_of('\\'));
|
||||
SetHomeDir(fn);
|
||||
set_user_config_dir(fn);
|
||||
set_user_data_dir(fn);
|
||||
}
|
||||
|
||||
int msgboxf(const wchar* text,unsigned int type,...)
|
||||
|
|
|
@ -253,8 +253,10 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_config(JNIEnv *env,jo
|
|||
{
|
||||
// Set home directory based on User config
|
||||
const char* D = dirName? env->GetStringUTFChars(dirName,0):0;
|
||||
SetHomeDir(D);
|
||||
printf("Home dir is: '%s'\n",GetPath("/").c_str());
|
||||
set_user_config_dir(D);
|
||||
set_user_data_dir(D);
|
||||
printf("Config dir is: %s\n", get_config_path("/").c_str());
|
||||
printf("Data dir is: %s\n", get_data_path("/").c_str());
|
||||
env->ReleaseStringUTFChars(dirName,D);
|
||||
}
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_init(JNIEnv *env,jobject obj,jstring fileName)
|
||||
|
|
|
@ -66,11 +66,13 @@ extern "C" int reicast_main(int argc, wchar* argv[])
|
|||
//ndcid=atoi(argv[1]);
|
||||
|
||||
string homedir = [ [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0] path] UTF8String];
|
||||
SetHomeDir(homedir);
|
||||
set_user_config_dir(homedir);
|
||||
set_user_data_dir(homedir);
|
||||
|
||||
freopen( (homedir + "/log.txt").c_str(), "wb", stdout);
|
||||
|
||||
printf("Home dir is: %s\n",GetPath("/").c_str());
|
||||
printf("Config dir is: %s\n", get_config_path("/").c_str());
|
||||
printf("Data dir is: %s\n", get_data_path("/").c_str());
|
||||
|
||||
common_linux_setup();
|
||||
|
||||
|
|
|
@ -95,10 +95,14 @@ void* emuthread(void*) {
|
|||
{
|
||||
home += "/.reicast";
|
||||
mkdir(home.c_str(), 0755); // create the directory if missing
|
||||
SetHomeDir(home);
|
||||
set_user_config_dir(home);
|
||||
set_user_data_dir(home);
|
||||
}
|
||||
else
|
||||
SetHomeDir(".");
|
||||
{
|
||||
set_user_config_dir(".");
|
||||
set_user_data_dir(".");
|
||||
}
|
||||
char* argv[] = { "reicast" };
|
||||
|
||||
dc_init(1,argv);
|
||||
|
|
Loading…
Reference in New Issue