Merge pull request #320 from libretro/createconfig

Create default config
This commit is contained in:
Squarepusher 2013-10-01 07:46:53 -07:00
commit 1d60ea18c2
7 changed files with 164 additions and 30 deletions

View File

@ -16,8 +16,21 @@ retroarch-joyconfig \- Tool to configure joypad bindings for \fBretroarch\fR.
It reads in necessary joypad bindings for a certain player and joypad.
.SH "EXAMPLE COMMANDLINES"
.TP
\fBConfigure joypad for player 1, using first joypad. Configuration is dumped to a file.\fR
retroarch-joyconfig -p 1 -j 0 -o inputconfig.cfg
.TP
\fBConfigure joypad for player 1, using first joypad. Update retroarch.cfg directly.\fR
retroarch-joyconfig -p 1 -j 0 -i retroarch.cfg -o retroarch.cfg
.TP
\fBConfigure joypad for player 1, using first joypad. Configuration is dumped to stdout.\fR
retroarch-joyconfig -p 1 -j 0
.TP
\fBCreate an autoconfig file using first joypad.\fR
retroarch-joyconfig -j 0 -a ~/.config/retroarch/autoconfig/pad.cfg
.SH "GENERAL OPTIONS"

View File

@ -4,7 +4,7 @@
.SH NAME
retroarch \- A simple frontend for the libretro API.
retroarch \- The reference frontend for the libretro API.
.SH SYNOPSIS
@ -12,13 +12,32 @@ retroarch \- A simple frontend for the libretro API.
.SH "DESCRIPTION"
\fBretroarch\fR is an emulator frontend for the libretro API.
libretro provides emulation of a game system, and can be implemented by any frontend.
\fBretroarch\fR is the reference frontend for the libretro API.
libretro is an abstraction of a game system, and can be implemented by any frontend.
The libretro API is designed for games and emulators.
\fBretroarch\fR focuses on exposing needed functionality for the game system through the use of command line and configuration files.
It also features a simple built-in UI called RGUI.
.SH "EXAMPLE COMMANDLINE"
.TP
\fBLoad a ROM, using a specific libretro core and config file.\fR
retroarch --config ~/.config/retroarch/retroarch.cfg --libretro /path/to/libretro/core.so /path/to/rom.rom --verbose
.TP
\fBNo command line options will start RetroArch in RGUI mode.\fR
retroarch
.TP
\fBStart RetroArch in RGUI, with verbose logging.\fR
retroarch --menu --verbose
.SH "RGUI"
RGUI is the built-in GUI system for RetroArch. It is aimed at being controlled with a gamepad only.
.SH "DEFAULT CONTROLS"
By default, only keyboard input is accepted.
.SH "GENERAL OPTIONS"
.TP
@ -74,14 +93,20 @@ Always starts RetroArch in fullscreen. Disregards settings in configuration file
Sets the configuration file path. \fBretroarch\fR will use this path to load the configuration file.
Should this not be defined, \fBretroarch\fR will look in platform specific paths to attempt finding the config file.
/etc/retroarch.cfg (when installed), or retroarch.cfg in the source tarball serves as a skeleton configuration file.
If PATH is a directory, RetroArch will treat this as the config file directory, where the state file name will be inferred from the rom name (*.cfg).
If a config cannot be found when using directory path, the default config path will be used instead.
/etc/retroarch.cfg should serve as a skeleton config only, and not used as a config file.
.IP
Unix-like systems will look in $XDG_CONFIG_HOME/retroarch/retroarch.cfg first. If $XDG_CONFIG_HOME is not defined, it is assumed to be $HOME/.config as per specification. Then it will try $HOME/.retroarch.cfg. Last, it will try /etc/retroarch.cfg. If no configuration is found, default settings will be assumed. A configuration file does not need to define every possible option, only those that should be overridden.
Unix-like systems will look in $XDG_CONFIG_HOME/retroarch/retroarch.cfg first. If $XDG_CONFIG_HOME is not defined, it is assumed to be $HOME/.config as per specification. Then it will try $HOME/.retroarch.cfg. If both paths fail, RetroArch will try to create a new, default config file in $XDG_CONFIG_HOME/retroarch/retroarch.cfg (or the $HOME/.config default for $XDG_CONFIG_HOME). If no configuration is found at all, default settings will be assumed.
RetroArch will not attempt to load the skeleton config /etc/retroarch.cfg.
A configuration file does not need to define every possible option, only those which should be overridden.
If config_save_on_exit = true is set in the config file, RetroArch will overwrite the config file on exit. Settings can be changed from within RGUI.
If RetroArch overwrites a config file, formatting, comments, etc will be lost.
If RetroArch creates a default config file, it will have config_save_on_exit set automatically.
.IP
Windows will look in retroarch.cfg in same folder where retroarch.exe resides.
A default config file will also be created in the same manner as Unix.
.TP
\fB--appendconfig PATH\fR

2
file.h
View File

@ -74,6 +74,8 @@ bool path_is_directory(const char *path);
bool path_file_exists(const char *path);
const char *path_get_extension(const char *path);
bool path_mkdir(const char *dir);
// Removes all text after and including the last '.'
char *path_remove_extension(char *path);

View File

@ -19,6 +19,7 @@
#include "boolean.h"
#include <string.h>
#include <time.h>
#include <errno.h>
#include "compat/strl.h"
#include "compat/posix_string.h"
@ -44,6 +45,7 @@
#else
#include <io.h>
#include <fcntl.h>
#include <direct.h>
#include <windows.h>
#endif
#else
@ -564,6 +566,64 @@ void path_resolve_realpath(char *buf, size_t size)
#endif
}
static bool path_mkdir_norecurse(const char *dir)
{
#if (defined(_WIN32) && !defined(_XBOX)) || !defined(RARCH_CONSOLE)
#ifdef _WIN32
int ret = _mkdir(dir);
#else
int ret = mkdir(dir, 0750);
#endif
if (ret < 0 && errno == EEXIST && path_is_directory(dir)) // Don't treat this as an error.
ret = 0;
if (ret < 0)
RARCH_ERR("mkdir(%s) error: %s.\n", dir, strerror(errno));
return ret == 0;
#else
(void)dir;
return false;
#endif
}
bool path_mkdir(const char *dir)
{
const char *target = NULL;
char *basedir = strdup(dir); // Use heap. Real chance of stack overflow if we recurse too hard.
bool ret = true;
if (!basedir)
return false;
path_parent_dir(basedir);
if (!*basedir || !strcmp(basedir, dir))
{
ret = false;
goto end;
}
if (path_is_directory(basedir))
{
target = dir;
ret = path_mkdir_norecurse(dir);
}
else
{
target = basedir;
ret = path_mkdir(basedir);
if (ret)
{
target = dir;
ret = path_mkdir_norecurse(dir);
}
}
end:
if (target && !ret)
RARCH_ERR("Failed to create directory: \"%s\".\n", target);
free(basedir);
return ret;
}
void fill_pathname_resolve_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size)
{
if (path_is_absolute(in_path))

View File

@ -67,6 +67,7 @@ static bool libretro_install_core(const char *path_prefix,
void rarch_make_dir(const char *x, const char *name)
{
// FIXME: This should use path_mkdir() in file_path.c.
RARCH_LOG("Checking directory name %s [%s]\n", name, x);
if (strlen(x) > 0)
{

View File

@ -600,9 +600,9 @@ static int16_t input_state(unsigned port, unsigned device, unsigned index, unsig
}
#ifdef _WIN32
#define RARCH_DEFAULT_CONF_PATH_STR "\n\t\tDefaults to retroarch.cfg in same directory as retroarch.exe."
#define RARCH_DEFAULT_CONF_PATH_STR "\n\t\tDefaults to retroarch.cfg in same directory as retroarch.exe.\n\t\tIf a default config is not found, RetroArch will attempt to create one."
#else
#define RARCH_DEFAULT_CONF_PATH_STR "\n\t\tBy default looks for config in $XDG_CONFIG_HOME/retroarch/retroarch.cfg,\n\t\t$HOME/.config/retroarch/retroarch.cfg,\n\t\tand $HOME/.retroarch.cfg."
#define RARCH_DEFAULT_CONF_PATH_STR "\n\t\tBy default looks for config in $XDG_CONFIG_HOME/retroarch/retroarch.cfg,\n\t\t$HOME/.config/retroarch/retroarch.cfg,\n\t\tand $HOME/.retroarch.cfg.\n\t\tIf a default config is not found, RetroArch will attempt to create one."
#endif
#include "config.features.h"
@ -772,17 +772,6 @@ static void set_paths(const char *path)
// do not overwrite it as this was initialized before in a menu or otherwise.
if (!*g_settings.system_directory)
fill_pathname_basedir(g_settings.system_directory, path, sizeof(g_settings.system_directory));
if (*g_extern.config_path && path_is_directory(g_extern.config_path))
{
fill_pathname_dir(g_extern.config_path, g_extern.basename, ".cfg", sizeof(g_extern.config_path));
RARCH_LOG("Redirecting config file to \"%s\".\n", g_extern.config_path);
if (!path_file_exists(g_extern.config_path))
{
*g_extern.config_path = '\0';
RARCH_LOG("Did not find config file. Using system default.\n");
}
}
}
static void parse_input(int argc, char *argv[])

View File

@ -392,6 +392,28 @@ static config_file_t *open_default_config_file(void)
}
}
// Try to create a new config file.
if (!conf)
{
conf = config_file_new(NULL);
bool saved = false;
if (conf) // Since this is a clean config file, we can safely use config_save_on_exit.
{
fill_pathname_resolve_relative(conf_path, app_path, "retroarch.cfg", sizeof(conf_path));
config_set_bool(conf, "config_save_on_exit", true);
saved = config_file_write(conf, conf_path);
}
if (saved)
RARCH_WARN("Created new config file in: \"%s\".\n", conf_path); // WARN here to make sure user has a good chance of seeing it.
else
{
RARCH_ERR("Failed to create new config file in: \"%s\".\n", conf_path);
config_file_free(conf);
conf = NULL;
}
}
if (conf)
strlcpy(g_extern.config_path, conf_path, sizeof(g_extern.config_path));
#elif !defined(__CELLOS_LV2__) && !defined(_XBOX)
@ -401,9 +423,9 @@ static config_file_t *open_default_config_file(void)
// XDG_CONFIG_HOME falls back to $HOME/.config.
if (xdg)
snprintf(conf_path, sizeof(conf_path), "%s/retroarch/retroarch.cfg", xdg);
fill_pathname_join(conf_path, xdg, "retroarch/retroarch.cfg", sizeof(conf_path));
else if (home)
snprintf(conf_path, sizeof(conf_path), "%s/.config/retroarch/retroarch.cfg", home);
fill_pathname_join(conf_path, home, ".config/retroarch/retroarch.cfg", sizeof(conf_path));
if (xdg || home)
{
@ -414,20 +436,42 @@ static config_file_t *open_default_config_file(void)
// Fallback to $HOME/.retroarch.cfg.
if (!conf && home)
{
snprintf(conf_path, sizeof(conf_path), "%s/.retroarch.cfg", home);
fill_pathname_join(conf_path, home, ".retroarch.cfg", sizeof(conf_path));
RARCH_LOG("Looking for config in: \"%s\".\n", conf_path);
conf = config_file_new(conf_path);
}
// Try this as a last chance ...
if (!conf)
// Try to create a new config file.
if (!conf && (home || xdg))
{
#ifndef GLOBAL_CONFIG_DIR
#define GLOBAL_CONFIG_DIR "/etc"
#endif
fill_pathname_join(conf_path, GLOBAL_CONFIG_DIR, "retroarch.cfg", sizeof(conf_path));
RARCH_LOG("Looking for config in: \"%s\".\n", conf_path);
conf = config_file_new(conf_path);
// XDG_CONFIG_HOME falls back to $HOME/.config.
if (xdg)
fill_pathname_join(conf_path, xdg, "retroarch/retroarch.cfg", sizeof(conf_path));
else if (home)
fill_pathname_join(conf_path, home, ".config/retroarch/retroarch.cfg", sizeof(conf_path));
char basedir[PATH_MAX];
fill_pathname_basedir(basedir, conf_path, sizeof(basedir));
if (path_mkdir(basedir))
{
conf = config_file_new(NULL);
bool saved = false;
if (conf)
{
config_set_bool(conf, "config_save_on_exit", true); // Since this is a clean config file, we can safely use config_save_on_exit.
saved = config_file_write(conf, conf_path);
}
if (saved)
RARCH_WARN("Created new config file in: \"%s\".\n", conf_path); // WARN here to make sure user has a good chance of seeing it.
else
{
RARCH_ERR("Failed to create new config file in: \"%s\".\n", conf_path);
config_file_free(conf);
conf = NULL;
}
}
}
if (conf)