From 683d7e88e46463497033eb4759ced45ee8b8cc49 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 14 Dec 2013 19:50:00 +0100 Subject: Allow some options taking filenames to refer to mpv config dir Add the mp_get_user_path() function, and make it expand special path prefixes. Use it for some things in mpv which take filenames (--input-config, --screenshot-template, opengl icc-profile suboption). This allows accessing files in the mpv config dir without hardcoding the config path by prefixing the path with ~~/. Details see manpage additions. --- DOCS/man/en/mpv.rst | 22 ++++++++++++++++++++++ mpvcore/input/input.c | 24 ++++++++++++++++-------- mpvcore/path.c | 22 ++++++++++++++++++++++ mpvcore/path.h | 5 +++++ mpvcore/player/screenshot.c | 5 ++++- video/out/gl_lcms.c | 5 ++++- 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/DOCS/man/en/mpv.rst b/DOCS/man/en/mpv.rst index 44a0c36f80..003a36ed53 100644 --- a/DOCS/man/en/mpv.rst +++ b/DOCS/man/en/mpv.rst @@ -285,6 +285,28 @@ It has the following format:: ``mpv --ao=pcm:file=%`expr length "$NAME"`%"$NAME" test.avi`` +Paths +----- + +Some care must be taken when passing arbitrary paths and filenames to mpv. For +example, paths starting with ``-`` will be interpreted as options. Likewise, +if a path contains the sequence ``://``, the string before that might be +interpreted as protocol prefix, even though ``://`` can be part of a legal +UNIX path. To avoid problems with arbitrary paths, you should be sure that +absolute paths passed to mpv start with ``/``, and relative paths with ``./``. + +The name ``-`` itself is interpreted as stdin, and will cause mpv to disable +console controls. (Which makes it suitable for playing data piped to stdin.) + +For paths passed to suboptions, the situation is further complicated by the +need to escape special characters. To work this around, the path can be +additionally wrapped in the ``%n%string_of_length_n`` syntax (see above). + +Some mpv options interpret paths starting with ``~``. Currently, the prefix +``~~/`` expands to the mpv configuration directory (usually ``~/.mpv/``). +``~/`` expands to the user's home directory. (The trailing ``/`` is always +required.) + Per-File Options ---------------- diff --git a/mpvcore/input/input.c b/mpvcore/input/input.c index f6553e7ba4..f9c7e0c173 100644 --- a/mpvcore/input/input.c +++ b/mpvcore/input/input.c @@ -2156,23 +2156,31 @@ static int parse_config(struct input_ctx *ictx, bool builtin, bstr data, static int parse_config_file(struct input_ctx *ictx, char *file, bool warn) { + int r = 0; + void *tmp = talloc_new(NULL); + stream_t *s = NULL; + + file = mp_get_user_path(tmp, file); if (!mp_path_exists(file)) { MP_MSG(ictx, warn ? MSGL_ERR : MSGL_V, "Input config file %s not found.\n", file); - return 0; + goto done; } - stream_t *s = stream_open(file, NULL); + s = stream_open(file, NULL); if (!s) { MP_ERR(ictx, "Can't open input config file %s.\n", file); - return 0; + goto done; } - bstr res = stream_read_complete(s, NULL, 1000000); - free_stream(s); + bstr data = stream_read_complete(s, tmp, 1000000); MP_VERBOSE(ictx, "Parsing input config file %s\n", file); - int n_binds = parse_config(ictx, false, res, file, NULL); - talloc_free(res.start); + int n_binds = parse_config(ictx, false, data, file, NULL); MP_VERBOSE(ictx, "Input config file %s parsed: %d binds\n", file, n_binds); - return 1; + r = 1; + +done: + free_stream(s); + talloc_free(tmp); + return r; } // If name is NULL, return "default". diff --git a/mpvcore/path.c b/mpvcore/path.c index df138489d6..9de11b24d1 100644 --- a/mpvcore/path.c +++ b/mpvcore/path.c @@ -97,6 +97,28 @@ char *mp_find_global_config_file(const char *filename) } } +char *mp_get_user_path(void *talloc_ctx, const char *path) +{ + if (!path) + return NULL; + bstr bpath = bstr0(path); + if (bstr_eatstart0(&bpath, "~")) { + // parse to "~" "/" + bstr prefix, rest; + if (bstr_split_tok(bpath, "/", &prefix, &rest)) { + const char *rest0 = rest.start; // ok in this case + char *res = NULL; + if (bstr_equals0(prefix, "~")) + res = talloc_steal(talloc_ctx, mp_find_user_config_file(rest0)); + if (bstr_equals0(prefix, "")) + res = mp_path_join(talloc_ctx, bstr0(getenv("HOME")), rest); + if (res) + return res; + } + } + return talloc_strdup(talloc_ctx, path); +} + char *mp_basename(const char *path) { char *s; diff --git a/mpvcore/path.h b/mpvcore/path.h index bae6956ec7..e0c61321d2 100644 --- a/mpvcore/path.h +++ b/mpvcore/path.h @@ -36,6 +36,11 @@ char *mp_find_global_config_file(const char *filename); // Search for the input filename in the user configuration location. char *mp_find_user_config_file(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 +// file from the user's home or mpv config directory. +char *mp_get_user_path(void *talloc_ctx, const char *path); + // Return pointer to filename part of path char *mp_basename(const char *path); diff --git a/mpvcore/player/screenshot.c b/mpvcore/player/screenshot.c index bf7a0ce9ee..d719495f9e 100644 --- a/mpvcore/player/screenshot.c +++ b/mpvcore/player/screenshot.c @@ -233,7 +233,10 @@ static char *create_fname(struct MPContext *mpctx, char *template, } res = talloc_strdup_append(res, template); - return talloc_asprintf_append(res, ".%s", file_ext); + res = talloc_asprintf_append(res, ".%s", file_ext); + char *fname = mp_get_user_path(NULL, res); + talloc_free(res); + return fname; error_exit: talloc_free(res); diff --git a/video/out/gl_lcms.c b/video/out/gl_lcms.c index 9999eca233..49a3a0346c 100644 --- a/video/out/gl_lcms.c +++ b/video/out/gl_lcms.c @@ -31,6 +31,7 @@ #include "mpvcore/bstr.h" #include "mpvcore/mp_msg.h" #include "mpvcore/m_option.h" +#include "mpvcore/path.h" #include "gl_video.h" #include "gl_lcms.h" @@ -90,11 +91,13 @@ static void lcms2_error_handler(cmsContext ctx, cmsUInt32Number code, static struct bstr load_file(void *talloc_ctx, const char *filename) { struct bstr res = {0}; - stream_t *s = stream_open(filename, NULL); + char *fname = mp_get_user_path(NULL, filename); + stream_t *s = stream_open(fname, NULL); if (s) { res = stream_read_complete(s, talloc_ctx, 1000000000); free_stream(s); } + talloc_free(fname); return res; } -- cgit v1.2.3