From cb250d490c14872f03bb0320179e48d05fe2539d Mon Sep 17 00:00:00 2001 From: Kenneth Zhou Date: Wed, 18 Jun 2014 19:55:40 -0400 Subject: Basic xdg directory implementation Search $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS for config files. This also negates the need to have separate user and global variants of mp_find_config_file() Closes #864, #109. Signed-off-by: wm4 --- options/path.c | 202 +++++++++++++++++++++++++++++++++++++-------------------- options/path.h | 12 ++-- 2 files changed, 136 insertions(+), 78 deletions(-) (limited to 'options') diff --git a/options/path.c b/options/path.c index 53ce3a5282..decaba4c78 100644 --- a/options/path.c +++ b/options/path.c @@ -43,100 +43,139 @@ #include "osdep/io.h" #include "osdep/path.h" -typedef char *(*lookup_fun)(void *tctx, struct mpv_global *global, const char *); -static const lookup_fun config_lookup_functions[] = { - mp_find_user_config_file, +#define STRNULL(s) ((s) ? (s) : "(NULL)") + + + +static void mp_add_xdg_config_dirs(void *talloc_ctx, struct mpv_global *global, + char **dirs, int i) +{ + const char *home = getenv("HOME"); + const char *tmp = NULL; + + tmp = getenv("XDG_CONFIG_HOME"); + if (tmp && *tmp) + dirs[i++] = talloc_asprintf(talloc_ctx, "%s/mpv", tmp); + else if (home && *home) + dirs[i++] = talloc_asprintf(talloc_ctx, "%s/.config/mpv", home); + + // Maintain compatibility with old ~/.mpv + if (home && *home) + dirs[i++] = talloc_asprintf(talloc_ctx, "%s/.mpv", home); + #if HAVE_COCOA - mp_get_macosx_bundled_path, + dirs[i++] = mp_get_macosx_bundle_dir(talloc_ctx); #endif - mp_find_global_config_file, - NULL -}; -#define STRNULL(s) ((s) ? (s) : "(NULL)") + tmp = getenv("XDG_CONFIG_DIRS"); + if (tmp && *tmp) { + char *xdgdirs = talloc_strdup(talloc_ctx, tmp); + while (xdgdirs) { + char *dir = xdgdirs; -char *mp_find_config_file(void *talloc_ctx, struct mpv_global *global, - const char *filename) -{ - struct MPOpts *opts = global->opts; + xdgdirs = strchr(xdgdirs, ':'); + if (xdgdirs) + *xdgdirs++ = 0; - char *res = NULL; - if (opts->load_config) { - if (opts->force_configdir && opts->force_configdir[0]) { - // Always force the local config dir. - res = mp_find_user_config_file(talloc_ctx, global, filename); - } else { - for (int i = 0; config_lookup_functions[i] != NULL; i++) { - res = config_lookup_functions[i](talloc_ctx, global, filename); - if (!res) - continue; - - if (mp_path_exists(res)) - break; - - talloc_free(res); - res = NULL; + if (!dir[0]) + continue; + + dirs[i++] = talloc_asprintf(talloc_ctx, "%s%s", dir, "/mpv"); + + if (i + 1 >= MAX_CONFIG_PATHS) { + MP_WARN(global, "Too many config files, not reading any more\n"); + break; } } } - MP_VERBOSE(global, "any config path: '%s' -> '%s'\n", STRNULL(filename), - STRNULL(res)); - return res; + else { + dirs[i++] = MPLAYER_CONFDIR; + } } -char *mp_find_user_config_file(void *talloc_ctx, struct mpv_global *global, - const char *filename) +// Return NULL-terminated array of config directories, from highest to lowest +// priority +static char **mp_config_dirs(void *talloc_ctx, struct mpv_global *global) +{ + char **ret = talloc_zero_array(talloc_ctx, char*, MAX_CONFIG_PATHS); + + if (global->opts->force_configdir && global->opts->force_configdir[0]) { + ret[0] = talloc_strdup(talloc_ctx, global->opts->force_configdir); + return ret; + } + + const char *tmp = NULL; + int i = 0; + + tmp = getenv("MPV_HOME"); + if (tmp && *tmp) + ret[i++] = talloc_strdup(talloc_ctx, tmp); + +#if defined(_WIN32) && !defined(__CYGWIN__) + mp_add_win_config_dirs(talloc_ctx, global, ret, i); +#else + mp_add_xdg_config_dirs(talloc_ctx, global, ret, i); +#endif + + MP_VERBOSE(global, "search dirs:"); + for (char **c = ret; *c; c++) + MP_VERBOSE(global, " %s", *c); + MP_VERBOSE(global, "\n"); + + return ret; +} + + + +char *mp_find_config_file(void *talloc_ctx, struct mpv_global *global, + const char *filename) { struct MPOpts *opts = global->opts; + void *tmp = talloc_new(NULL); char *res = NULL; if (opts->load_config) { - if (opts->force_configdir && opts->force_configdir[0]) { - res = mp_path_join(talloc_ctx, bstr0(opts->force_configdir), - bstr0(filename)); - } else { - char *homedir = getenv("MPV_HOME"); - char *configdir = NULL; - - if (!homedir) { -#ifdef _WIN32 - res = talloc_steal(talloc_ctx, mp_get_win_config_path(filename)); -#endif - homedir = getenv("HOME"); - configdir = ".mpv"; - } + for (char **dir = mp_config_dirs(tmp, global); *dir; dir++) { + char *config_file = talloc_asprintf(tmp, "%s/%s", *dir, filename); - if (!res && homedir) { - char *temp = mp_path_join(NULL, bstr0(homedir), bstr0(configdir)); - res = mp_path_join(talloc_ctx, bstr0(temp), bstr0(filename)); - talloc_free(temp); + if (mp_path_exists(config_file)) { + res = talloc_strdup(talloc_ctx, config_file); + break; } } } - MP_VERBOSE(global, "user config path: '%s' -> '%s'\n", STRNULL(filename), + talloc_free(tmp); + + MP_VERBOSE(global, "config path: '%s' -> '%s'\n", STRNULL(filename), STRNULL(res)); return res; } - -char *mp_find_global_config_file(void *talloc_ctx, struct mpv_global *global, - const char *filename) +char **mp_find_all_config_files(void *talloc_ctx, struct mpv_global *global, + const char *filename) { struct MPOpts *opts = global->opts; - char *res = NULL; - if (opts->load_config && !(opts->force_configdir && opts->force_configdir[0])) - { - if (filename) { - res = mp_path_join(talloc_ctx, bstr0(MPLAYER_CONFDIR), bstr0(filename)); - } else { - res = talloc_strdup(talloc_ctx, MPLAYER_CONFDIR); + char **front = talloc_zero_array(talloc_ctx, char*, MAX_CONFIG_PATHS); + char **ret = front + (MAX_CONFIG_PATHS - 1); + + if (opts->load_config) { + for (char **dir = mp_config_dirs(talloc_ctx, global); *dir; dir++) { + char *config_file = talloc_asprintf(talloc_ctx, "%s/%s", *dir, filename); + + if (!mp_path_exists(config_file)) + continue; + + *(--ret) = config_file; } } - MP_VERBOSE(global, "global config path: '%s' -> '%s'\n", STRNULL(filename), - STRNULL(res)); - return res; + MP_VERBOSE(global, "config file: '%s'\n", STRNULL(filename)); + + for (char** c = ret; *c; c++) + MP_VERBOSE(global, " -> '%s'\n", *c); + + return ret; } char *mp_get_user_path(void *talloc_ctx, struct mpv_global *global, @@ -152,7 +191,7 @@ char *mp_get_user_path(void *talloc_ctx, struct mpv_global *global, if (bstr_split_tok(bpath, "/", &prefix, &rest)) { const char *rest0 = rest.start; // ok in this case if (bstr_equals0(prefix, "~")) { - res = mp_find_user_config_file(talloc_ctx, global, rest0); + res = mp_find_config_file(talloc_ctx, global, rest0); } else if (bstr_equals0(prefix, "")) { res = mp_path_join(talloc_ctx, bstr0(getenv("HOME")), rest); } @@ -281,14 +320,35 @@ bstr mp_split_proto(bstr path, bstr *out_url) return r; } +void mp_mkdirp(const char *dir) +{ + void *tmp = talloc_new(NULL); + char *path = talloc_strdup(tmp, dir); + char *cdir = path + 1; + + while (cdir) { + cdir = strchr(cdir, '/'); + if (cdir) + *cdir = 0; + + mkdir(path, 0700); + + if (cdir) + *cdir++ = '/'; + } + + talloc_free(tmp); +} + void mp_mk_config_dir(struct mpv_global *global, char *subdir) { void *tmp = talloc_new(NULL); - char *confdir = mp_find_user_config_file(tmp, global, ""); - if (confdir) { - if (subdir) - confdir = mp_path_join(tmp, bstr0(confdir), bstr0(subdir)); - mkdir(confdir, 0777); + char *dir = mp_config_dirs(tmp, global)[0]; + + if (dir) { + dir = talloc_asprintf(tmp, "%s/%s", dir, subdir); + mp_mkdirp(dir); } + talloc_free(tmp); } diff --git a/options/path.h b/options/path.h index 0d23dcbe9b..30ca34d205 100644 --- a/options/path.h +++ b/options/path.h @@ -32,13 +32,10 @@ struct mpv_global; char *mp_find_config_file(void *talloc_ctx, struct mpv_global *global, const char *filename); -// Search for the input filename in the global configuration location. -char *mp_find_global_config_file(void *talloc_ctx, struct mpv_global *global, - const char *filename); - -// Search for the input filename in the user configuration location. -char *mp_find_user_config_file(void *talloc_ctx, struct mpv_global *global, - const char *filename); +// Find all instances of the given config file. Paths are returned in order +// from lowest to highest priority. +char **mp_find_all_config_files(void *talloc_ctx, struct mpv_global *global, + const char *filename); // Normally returns a talloc_strdup'ed copy of the path, except for special // paths starting with '~'. Used to allow the user explicitly reference a @@ -77,6 +74,7 @@ bool mp_is_url(bstr path); bstr mp_split_proto(bstr path, bstr *out_url); +void mp_mkdirp(const char *dir); void mp_mk_config_dir(struct mpv_global *global, char *subdir); #endif /* MPLAYER_PATH_H */ -- cgit v1.2.3