summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-12-18 06:00:37 +0100
committerwm4 <wm4@nowhere>2019-12-18 06:03:39 +0100
commit8bdedf9062074f03b13820487fccc892105eb472 (patch)
tree8a5efd7ebd78994d4085865fe2663949988eadcb
parentd3e3bd43074ddd8f4c8829a7454b9f855454f462 (diff)
downloadmpv-8bdedf9062074f03b13820487fccc892105eb472.tar.bz2
mpv-8bdedf9062074f03b13820487fccc892105eb472.tar.xz
options: make keys in key/value lists unique
I don't even know anymore whether this was intended or not. Certain use cases for the "-o" options might require this. These options are for passing general FFmpeg options. These are translated to av_opt_set() calls, which may or may not accumulate the option values on multiple calls with the same option name (how should I know?). Anyway, it seems crazy to allow non-unique keys, so make them unique. The ad-hoc nature of the option code makes this wonderfully complicated (when I wrote that this code is cursed, I meant it). In combination with lazy testing, it probably means there are lots of bugs here.
-rw-r--r--DOCS/man/mpv.rst3
-rw-r--r--options/m_option.c27
2 files changed, 30 insertions, 0 deletions
diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst
index eaced80082..9ff62ae4f0 100644
--- a/DOCS/man/mpv.rst
+++ b/DOCS/man/mpv.rst
@@ -520,6 +520,9 @@ Suffix Meaning
-add Append 1 or more items (same syntax as -set)
============= ===============================================
+Keys are unique within the list. If an already present key is set, the existing
+key is removed before the new value is appended.
+
Filter options
~~~~~~~~~~~~~~
diff --git a/options/m_option.c b/options/m_option.c
index 1ff3d26d22..2ebe79cff3 100644
--- a/options/m_option.c
+++ b/options/m_option.c
@@ -1621,6 +1621,28 @@ const m_option_type_t m_option_type_string_list = {
static int read_subparam(struct mp_log *log, bstr optname, char *termset,
bstr *str, bstr *out_subparam);
+static int keyvalue_list_find_key(char **lst, bstr str)
+{
+ for (int n = 0; lst && lst[n] && lst[n + 1]; n += 2) {
+ if (bstr_equals0(str, lst[n]))
+ return n / 2;
+ }
+ return -1;
+}
+
+static void keyvalue_list_del_key(char **lst, int index)
+{
+ int count = 0;
+ for (int n = 0; lst && lst[n]; n++)
+ count++;
+ assert(index * 2 + 1 < count);
+ count += 1; // terminating item
+ talloc_free(lst[index * 2 + 0]);
+ talloc_free(lst[index * 2 + 1]);
+ MP_TARRAY_REMOVE_AT(lst, count, index * 2 + 1);
+ MP_TARRAY_REMOVE_AT(lst, count, index * 2 + 0);
+}
+
static int parse_keyvalue_list(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param, void *dst)
{
@@ -1664,6 +1686,11 @@ static int parse_keyvalue_list(struct mp_log *log, const m_option_t *opt,
break;
}
if (dst) {
+ int index = keyvalue_list_find_key(lst, key);
+ if (index >= 0) {
+ keyvalue_list_del_key(lst, index);
+ num -= 2;
+ }
MP_TARRAY_APPEND(NULL, lst, num, bstrto0(NULL, key));
MP_TARRAY_APPEND(NULL, lst, num, bstrto0(NULL, val));
}