From 57cbbde420ec8f50479f17c958ad3945f44b3081 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 1 Oct 2013 11:57:07 +0200 Subject: [PATCH 1/4] Create a default config file if it doesn't exist. --- file.h | 2 ++ file_path.c | 60 ++++++++++++++++++++++++++++++++++++++++++ frontend/frontend.c | 1 + settings.c | 63 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 122 insertions(+), 4 deletions(-) diff --git a/file.h b/file.h index 115b909f75..24e1cd9519 100644 --- a/file.h +++ b/file.h @@ -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); diff --git a/file_path.c b/file_path.c index b13921e34c..ea126a2674 100644 --- a/file_path.c +++ b/file_path.c @@ -19,6 +19,7 @@ #include "boolean.h" #include #include +#include #include "compat/strl.h" #include "compat/posix_string.h" @@ -44,6 +45,7 @@ #else #include #include +#include #include #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)) diff --git a/frontend/frontend.c b/frontend/frontend.c index 799a0eca6b..e3b39cc3eb 100644 --- a/frontend/frontend.c +++ b/frontend/frontend.c @@ -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) { diff --git a/settings.c b/settings.c index 75a5f3ebab..2215e66cf4 100644 --- a/settings.c +++ b/settings.c @@ -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,12 +436,45 @@ 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 ... + // Try to create a new config file. + if (!conf && (home || xdg)) + { + // 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; + } + } + } + + // Try this as a very last chance ... if (!conf) { #ifndef GLOBAL_CONFIG_DIR From 3ed932146888acac27ee171c2e9c7299463974ed Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 1 Oct 2013 12:08:20 +0200 Subject: [PATCH 2/4] Update man-page and --help. Remove an obsolete per-game config support. It doesn't work with the RGUI concept at all and is mostly just confusing. --- docs/retroarch.1 | 11 ++++++++--- retroarch.c | 15 ++------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/docs/retroarch.1 b/docs/retroarch.1 index 5de513d78d..30f4f0ffcb 100644 --- a/docs/retroarch.1 +++ b/docs/retroarch.1 @@ -74,14 +74,19 @@ 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 saving a default config also fails, it will try /etc/retroarch.cfg. If no configuration is found at all, default settings will be assumed. +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 diff --git a/retroarch.c b/retroarch.c index 5f2ee98b2a..5aea9cda6f 100644 --- a/retroarch.c +++ b/retroarch.c @@ -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[]) From 7f299274dfb479b12bbc4fd7f681b98b8121fe38 Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 1 Oct 2013 12:21:58 +0200 Subject: [PATCH 3/4] Don't try to load skeleton config. Breaks RGUI since it's usually read-only. --- docs/retroarch.1 | 3 ++- settings.c | 11 ----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/docs/retroarch.1 b/docs/retroarch.1 index 30f4f0ffcb..8c9aa59168 100644 --- a/docs/retroarch.1 +++ b/docs/retroarch.1 @@ -77,7 +77,8 @@ Should this not be defined, \fBretroarch\fR will look in platform specific paths /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. 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 saving a default config also fails, it will try /etc/retroarch.cfg. If no configuration is found at all, default settings will be assumed. +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. diff --git a/settings.c b/settings.c index 2215e66cf4..a5c5147a7d 100644 --- a/settings.c +++ b/settings.c @@ -474,17 +474,6 @@ static config_file_t *open_default_config_file(void) } } - // Try this as a very last chance ... - if (!conf) - { -#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); - } - if (conf) strlcpy(g_extern.config_path, conf_path, sizeof(g_extern.config_path)); #endif From 1a3d152ed2ed8e7e484e46be784c7bc302f07c4d Mon Sep 17 00:00:00 2001 From: Themaister Date: Tue, 1 Oct 2013 12:35:20 +0200 Subject: [PATCH 4/4] Add some more example command lines to man-pages. --- docs/retroarch-joyconfig.1 | 13 +++++++++++++ docs/retroarch.1 | 25 ++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/docs/retroarch-joyconfig.1 b/docs/retroarch-joyconfig.1 index 3b187024ab..886bb39cc4 100644 --- a/docs/retroarch-joyconfig.1 +++ b/docs/retroarch-joyconfig.1 @@ -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" diff --git a/docs/retroarch.1 b/docs/retroarch.1 index 8c9aa59168..c8717f6fbc 100644 --- a/docs/retroarch.1 +++ b/docs/retroarch.1 @@ -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