diff options
Diffstat (limited to 'm_property.c')
-rw-r--r-- | m_property.c | 488 |
1 files changed, 205 insertions, 283 deletions
diff --git a/m_property.c b/m_property.c index ac68d86163..c8cf4e3dcf 100644 --- a/m_property.c +++ b/m_property.c @@ -25,7 +25,9 @@ #include <stdio.h> #include <string.h> #include <inttypes.h> -#include <unistd.h> +#include <assert.h> + +#include <libavutil/common.h> #include "talloc.h" #include "m_option.h" @@ -33,173 +35,254 @@ #include "mp_msg.h" #include "mpcommon.h" +const struct m_option_type m_option_type_dummy = { + .name = "Unknown", +}; + +struct legacy_prop { + const char *old, *new; +}; +static const struct legacy_prop legacy_props[] = { + {"switch_video", "video"}, + {"switch_audio", "audio"}, + {"switch_program", "program"}, + {"framedropping", "framedrop"}, + {"osdlevel", "osd-level"}, + {0} +}; + +static bool translate_legacy_property(const char *name, char *buffer, + size_t buffer_size) +{ + if (strlen(name) + 1 > buffer_size) + return false; + + const char *old_name = name; + + for (int n = 0; legacy_props[n].new; n++) { + if (strcmp(name, legacy_props[n].old) == 0) { + name = legacy_props[n].new; + break; + } + } + + snprintf(buffer, buffer_size, "%s", name); + + // Old names used "_" instead of "-" + for (int n = 0; buffer[n]; n++) { + if (buffer[n] == '_') + buffer[n] = '-'; + } + + if (strcmp(old_name, buffer) != 0) { + mp_msg(MSGT_CPLAYER, MSGL_V, "Warning: property '%s' is deprecated, " + "replaced with '%s'. Fix your input.conf!\n", old_name, buffer); + } + + return true; +} + static int do_action(const m_option_t *prop_list, const char *name, int action, void *arg, void *ctx) { const char *sep; const m_option_t *prop; - m_property_action_t ka; - int r; if ((sep = strchr(name, '/')) && sep[1]) { int len = sep - name; char base[len + 1]; memcpy(base, name, len); base[len] = 0; prop = m_option_list_find(prop_list, base); - ka.key = sep + 1; - ka.action = action; - ka.arg = arg; + struct m_property_action_arg ka = { + .key = sep + 1, + .action = action, + .arg = arg, + }; action = M_PROPERTY_KEY_ACTION; arg = &ka; } else prop = m_option_list_find(prop_list, name); if (!prop) return M_PROPERTY_UNKNOWN; - r = ((m_property_ctrl_f)prop->p)(prop, action, arg, ctx); - if (action == M_PROPERTY_GET_TYPE && r < 0) { - if (!arg) - return M_PROPERTY_ERROR; - *(const m_option_t **)arg = prop; + int (*control)(const m_option_t*, int, void*, void*) = prop->p; + int r = control(prop, action, arg, ctx); + if (action == M_PROPERTY_GET_TYPE && r < 0 && + prop->type != &m_option_type_dummy) + { + *(struct m_option *)arg = *prop; return M_PROPERTY_OK; } return r; } -int m_property_do(const m_option_t *prop_list, const char *name, +int m_property_do(const m_option_t *prop_list, const char *in_name, int action, void *arg, void *ctx) { - const m_option_t *opt; union m_option_value val = {0}; int r; + char name[64]; + if (!translate_legacy_property(in_name, name, sizeof(name))) + return M_PROPERTY_UNKNOWN; + + struct m_option opt = {0}; + r = do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx); + if (r <= 0) + return r; + assert(opt.type); + switch (action) { - case M_PROPERTY_PRINT: + case M_PROPERTY_PRINT: { if ((r = do_action(prop_list, name, M_PROPERTY_PRINT, arg, ctx)) >= 0) return r; - // fallback on the default print for this type - case M_PROPERTY_TO_STRING: - if ((r = do_action(prop_list, name, M_PROPERTY_TO_STRING, arg, ctx)) != - M_PROPERTY_NOT_IMPLEMENTED) - return r; - // fallback on the options API. Get the type, value and print. - if ((r = - do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0) + // Fallback to m_option + if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0) return r; + char *str = m_option_pretty_print(&opt, &val); + m_option_free(&opt, &val); + *(char **)arg = str; + return str != NULL; + } + case M_PROPERTY_GET_STRING: { if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0) return r; - if (!arg) - return M_PROPERTY_ERROR; - char *str = m_option_print(opt, &val); + char *str = m_option_print(&opt, &val); + m_option_free(&opt, &val); *(char **)arg = str; return str != NULL; - case M_PROPERTY_PARSE: - // try the property own parsing func - if ((r = do_action(prop_list, name, M_PROPERTY_PARSE, arg, ctx)) != + } + case M_PROPERTY_SET_STRING: { + // (reject 0 return value: success, but empty string with flag) + if (m_option_parse(&opt, bstr0(name), bstr0(arg), &val) <= 0) + return M_PROPERTY_ERROR; + r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx); + m_option_free(&opt, &val); + return r; + } + case M_PROPERTY_SWITCH: { + struct m_property_switch_arg *sarg = arg; + if ((r = do_action(prop_list, name, M_PROPERTY_SWITCH, arg, ctx)) != M_PROPERTY_NOT_IMPLEMENTED) return r; - // fallback on the options API, get the type and parse. - if ((r = - do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0) - return r; - if (!arg) - return M_PROPERTY_ERROR; - if ((r = m_option_parse(opt, bstr0(opt->name), bstr0(arg), &val)) <= 0) + // Fallback to m_option + if (!opt.type->add) + return M_PROPERTY_NOT_IMPLEMENTED; + if ((r = do_action(prop_list, name, M_PROPERTY_GET, &val, ctx)) <= 0) return r; + opt.type->add(&opt, &val, sarg->inc, sarg->wrap); r = do_action(prop_list, name, M_PROPERTY_SET, &val, ctx); - m_option_free(opt, &val); + m_option_free(&opt, &val); return r; } - return do_action(prop_list, name, action, arg, ctx); + case M_PROPERTY_SET: { + if (!opt.type->clamp) { + mp_msg(MSGT_CPLAYER, MSGL_WARN, "Property '%s' without clamp().\n", + name); + } else { + m_option_copy(&opt, &val, arg); + r = opt.type->clamp(&opt, arg); + m_option_free(&opt, &val); + if (r != 0) { + mp_msg(MSGT_CPLAYER, MSGL_ERR, + "Property '%s': invalid value.\n", name); + return M_PROPERTY_ERROR; + } + } + return do_action(prop_list, name, M_PROPERTY_SET, arg, ctx); + } + default: + return do_action(prop_list, name, action, arg, ctx); + } } -char *m_properties_expand_string(const m_option_t *prop_list, char *str, +static int m_property_do_bstr(const m_option_t *prop_list, bstr name, + int action, void *arg, void *ctx) +{ + char name0[64]; + if (name.len >= sizeof(name0)) + return M_PROPERTY_UNKNOWN; + snprintf(name0, sizeof(name0), "%.*s", BSTR_P(name)); + return m_property_do(prop_list, name0, action, arg, ctx); +} + +static void append_str(char **s, int *len, bstr append) +{ + MP_TARRAY_GROW(NULL, *s, *len + append.len); + memcpy(*s + *len, append.start, append.len); + *len = *len + append.len; +} + +char *m_properties_expand_string(const m_option_t *prop_list, char *str0, void *ctx) { - int l, fr = 0, pos = 0, size = strlen(str) + 512; - char *p = NULL, *e, *ret = malloc(size), num_val; - int skip = 0, lvl = 0, skip_lvl = 0; - - while (str[0]) { - if (str[0] == '\\') { - int sl = 1; - switch (str[1]) { - case 'e': - p = "\x1b", l = 1; break; - case 'n': - p = "\n", l = 1; break; - case 'r': - p = "\r", l = 1; break; - case 't': - p = "\t", l = 1; break; - case 'x': - if (str[2]) { - char num[3] = { str[2], str[3], 0 }; - char *end = num; - num_val = strtol(num, &end, 16); - sl = end - num + 1; - l = 1; - p = &num_val; - } else - l = 0; - break; - default: - p = str + 1, l = 1; - } - str += 1 + sl; - } else if (lvl > 0 && str[0] == ')') { - if (skip && lvl <= skip_lvl) - skip = 0; - lvl--, str++, l = 0; - } else if (str[0] == '$' && str[1] == '{' - && (e = strchr(str + 2, '}'))) { - str += 2; - int method = M_PROPERTY_PRINT; - if (str[0] == '=') { - str += 1; - method = M_PROPERTY_TO_STRING; - } - int pl = e - str; - char pname[pl + 1]; - memcpy(pname, str, pl); - pname[pl] = 0; - if (m_property_do(prop_list, pname, method, &p, ctx) >= 0 && p) - l = strlen(p), fr = 1; - else - l = 0; - str = e + 1; - } else if (str[0] == '?' && str[1] == '(' - && (e = strchr(str + 2, ':'))) { - lvl++; + char *ret = NULL; + int ret_len = 0; + bool skip = false; + int level = 0, skip_level = 0; + bstr str = bstr0(str0); + + while (str.len) { + if (level > 0 && bstr_eatstart0(&str, "}")) { + if (skip && level <= skip_level) + skip = false; + level--; + } else if (bstr_startswith0(str, "${") && bstr_find0(str, "}") >= 0) { + str = bstr_cut(str, 2); + level++; + + // Assume ":" and "}" can't be part of the property name + // => if ":" comes before "}", it must be for the fallback + int term_pos = bstrcspn(str, ":}"); + bstr name = bstr_splice(str, 0, term_pos < 0 ? str.len : term_pos); + str = bstr_cut(str, term_pos); + bool have_fallback = bstr_eatstart0(&str, ":"); + if (!skip) { - int is_not = str[2] == '!'; - int pl = e - str - (is_not ? 3 : 2); - char pname[pl + 1]; - memcpy(pname, str + (is_not ? 3 : 2), pl); - pname[pl] = 0; - if (m_property_do(prop_list, pname, M_PROPERTY_GET, NULL, ctx) < 0) { - if (!is_not) - skip = 1, skip_lvl = lvl; - } else if (is_not) - skip = 1, skip_lvl = lvl; + bool cond_yes = bstr_eatstart0(&name, "?"); + bool cond_no = !cond_yes && bstr_eatstart0(&name, "!"); + bool raw = bstr_eatstart0(&name, "="); + int method = (raw || cond_yes || cond_no) + ? M_PROPERTY_GET_STRING : M_PROPERTY_PRINT; + + char *s = NULL; + int r = m_property_do_bstr(prop_list, name, method, &s, ctx); + if (cond_yes || cond_no) { + skip = (!!s != cond_yes); + } else { + skip = !!s; + char *append = s; + if (!s && !have_fallback && !raw) { + append = r == M_PROPERTY_UNAVAILABLE + ? "(unavailable)" : "(error)"; + } + append_str(&ret, &ret_len, bstr0(append)); + } + talloc_free(s); + if (skip) + skip_level = level; } - str = e + 1, l = 0; - } else - p = str, l = 1, str++; + } else if (level == 0 && bstr_eatstart0(&str, "$>")) { + append_str(&ret, &ret_len, str); + break; + } else { + char c; - if (skip || l <= 0) - continue; + // Other combinations, e.g. "$x", are added verbatim + if (bstr_eatstart0(&str, "$$")) { + c = '$'; + } else if (bstr_eatstart0(&str, "$}")) { + c = '}'; + } else { + c = str.start[0]; + str = bstr_cut(str, 1); + } - if (pos + l + 1 > size) { - size = pos + l + 512; - ret = realloc(ret, size); + if (!skip) + MP_TARRAY_APPEND(NULL, ret, ret_len, c); } - memcpy(ret + pos, p, l); - pos += l; - if (fr) - talloc_free(p), fr = 0; } - ret[pos] = 0; + MP_TARRAY_APPEND(NULL, ret, ret_len, '\0'); return ret; } @@ -231,193 +314,32 @@ void m_properties_print_help_list(const m_option_t *list) mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d properties\n", count); } -// Some generic property implementations - int m_property_int_ro(const m_option_t *prop, int action, void *arg, int var) { - switch (action) { - case M_PROPERTY_GET: - if (!arg) - return 0; + if (action == M_PROPERTY_GET) { *(int *)arg = var; - return 1; + return M_PROPERTY_OK; } return M_PROPERTY_NOT_IMPLEMENTED; } -int m_property_int_range(const m_option_t *prop, int action, - void *arg, int *var) -{ - switch (action) { - case M_PROPERTY_SET: - if (!arg) - return 0; - M_PROPERTY_CLAMP(prop, *(int *)arg); - *var = *(int *)arg; - return 1; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var += (arg ? *(int *)arg : 1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - M_PROPERTY_CLAMP(prop, *var); - return 1; - } - return m_property_int_ro(prop, action, arg, *var); -} - -int m_property_choice(const m_option_t *prop, int action, - void *arg, int *var) -{ - switch (action) { - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max; - *var %= (int)prop->max + 1; - return 1; - } - return m_property_int_range(prop, action, arg, var); -} - -int m_property_flag_ro(const m_option_t *prop, int action, - void *arg, int var) -{ - switch (action) { - case M_PROPERTY_PRINT: - if (!arg) - return 0; - *(char **)arg = talloc_strdup(NULL, (var > prop->min) ? - mp_gtext("enabled") : mp_gtext("disabled")); - return 1; - } - return m_property_int_ro(prop, action, arg, var); -} - -int m_property_flag(const m_option_t *prop, int action, - void *arg, int *var) -{ - switch (action) { - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var = *var == prop->min ? prop->max : prop->min; - return 1; - case M_PROPERTY_PRINT: - return m_property_flag_ro(prop, action, arg, *var); - } - return m_property_int_range(prop, action, arg, var); -} - int m_property_float_ro(const m_option_t *prop, int action, void *arg, float var) { - switch (action) { - case M_PROPERTY_GET: - if (!arg) - return 0; + if (action == M_PROPERTY_GET) { *(float *)arg = var; - return 1; - case M_PROPERTY_PRINT: - if (!arg) - return 0; - *(char **)arg = talloc_asprintf(NULL, "%.2f", var); - return 1; + return M_PROPERTY_OK; } return M_PROPERTY_NOT_IMPLEMENTED; } -int m_property_float_range(const m_option_t *prop, int action, - void *arg, float *var) -{ - switch (action) { - case M_PROPERTY_SET: - if (!arg) - return 0; - M_PROPERTY_CLAMP(prop, *(float *)arg); - *var = *(float *)arg; - return 1; - case M_PROPERTY_STEP_UP: - case M_PROPERTY_STEP_DOWN: - *var += (arg ? *(float *)arg : 0.1) * - (action == M_PROPERTY_STEP_DOWN ? -1 : 1); - M_PROPERTY_CLAMP(prop, *var); - return 1; - } - return m_property_float_ro(prop, action, arg, *var); -} - -int m_property_delay(const m_option_t *prop, int action, - void *arg, float *var) -{ - switch (action) { - case M_PROPERTY_PRINT: - if (!arg) - return 0; - *(char **)arg = talloc_asprintf(NULL, "%d ms", ROUND((*var) * 1000)); - return 1; - default: - return m_property_float_range(prop, action, arg, var); - } -} - int m_property_double_ro(const m_option_t *prop, int action, void *arg, double var) { - switch (action) { - case M_PROPERTY_GET: - if (!arg) - return 0; + if (action == M_PROPERTY_GET) { *(double *)arg = var; - return 1; - case M_PROPERTY_PRINT: - if (!arg) - return 0; - *(char **)arg = talloc_asprintf(NULL, "%.2f", var); - return 1; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -int m_property_time_ro(const m_option_t *prop, int action, - void *arg, double var) -{ - switch (action) { - case M_PROPERTY_PRINT: - if (!arg) - return M_PROPERTY_ERROR; - else { - *(char **)arg = mp_format_time(var, false); - return M_PROPERTY_OK; - } - } - return m_property_double_ro(prop, action, arg, var); -} - -int m_property_string_ro(const m_option_t *prop, int action, void *arg, - char *str) -{ - switch (action) { - case M_PROPERTY_GET: - if (!arg) - return 0; - *(char **)arg = str; - return 1; - case M_PROPERTY_PRINT: - if (!arg) - return 0; - *(char **)arg = talloc_strdup(NULL, str); - return 1; - } - return M_PROPERTY_NOT_IMPLEMENTED; -} - -int m_property_bitrate(const m_option_t *prop, int action, void *arg, int rate) -{ - switch (action) { - case M_PROPERTY_PRINT: - if (!arg) - return M_PROPERTY_ERROR; - *(char **)arg = talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000); return M_PROPERTY_OK; } - return m_property_int_ro(prop, action, arg, rate); + return M_PROPERTY_NOT_IMPLEMENTED; } |