diff options
Diffstat (limited to 'options/m_option.c')
-rw-r--r-- | options/m_option.c | 717 |
1 files changed, 374 insertions, 343 deletions
diff --git a/options/m_option.c b/options/m_option.c index c55ca06bc8..3d9ae26669 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> +#include <limits.h> #include <math.h> #include <stdio.h> #include <stdarg.h> @@ -42,7 +43,7 @@ #include "misc/json.h" #include "misc/node.h" #include "m_option.h" -#include "m_config.h" +#include "m_config_frontend.h" #if HAVE_DOS_PATHS #define OPTION_PATH_SEPARATOR ';' @@ -52,6 +53,39 @@ const char m_option_path_separator = OPTION_PATH_SEPARATOR; +// For integer types: since min/max are floats and may not be able to represent +// the real min/max, and since opt.min/.max may use +/-INFINITY, some care has +// to be taken. (Also tricky rounding.) +#define OPT_INT_MIN(opt, T, Tm) ((opt)->min < (opt)->max \ + ? ((opt)->min <= (double)(Tm) ? (Tm) : (T)((opt)->min)) : (Tm)) +#define OPT_INT_MAX(opt, T, Tm) ((opt)->min < (opt)->max \ + ? ((opt)->max >= (double)(Tm) ? (Tm) : (T)((opt)->max)) : (Tm)) + +int m_option_parse(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param, void *dst) +{ + int r = M_OPT_INVALID; + if (bstr_equals0(param, "help") && opt->help) { + r = opt->help(log, opt, name); + if (r < 0) + return r; + } + + r = opt->type->parse(log, opt, name, param, dst); + if (r < 0) + return r; + + if (opt->validate) { + r = opt->validate(log, opt, name, dst); + if (r < 0) { + if (opt->type->free) + opt->type->free(dst); + return r; + } + } + return 1; +} + char *m_option_strerror(int code) { switch (code) { @@ -77,7 +111,7 @@ int m_option_required_params(const m_option_t *opt) if (opt->flags & M_OPT_OPTIONAL_PARAM) return 0; if (opt->type == &m_option_type_choice) { - struct m_opt_choice_alternatives *alt; + const struct m_opt_choice_alternatives *alt; for (alt = opt->priv; alt->name; alt++) { if (strcmp(alt->name, "yes") == 0) return 0; @@ -109,11 +143,11 @@ static void copy_opt(const m_option_t *opt, void *dst, const void *src) memcpy(dst, src, opt->type->size); } -// Flag +// Bool -#define VAL(x) (*(int *)(x)) +#define VAL(x) (*(bool *)(x)) -static int parse_flag(struct mp_log *log, const m_option_t *opt, +static int parse_bool(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { if (bstr_equals0(param, "yes") || !param.len) { @@ -140,12 +174,12 @@ static int parse_flag(struct mp_log *log, const m_option_t *opt, return is_help ? M_OPT_EXIT : M_OPT_INVALID; } -static char *print_flag(const m_option_t *opt, const void *val) +static char *print_bool(const m_option_t *opt, const void *val) { return talloc_strdup(NULL, VAL(val) ? "yes" : "no"); } -static void add_flag(const m_option_t *opt, void *val, double add, bool wrap) +static void add_bool(const m_option_t *opt, void *val, double add, bool wrap) { if (fabs(add) < 0.5) return; @@ -154,7 +188,7 @@ static void add_flag(const m_option_t *opt, void *val, double add, bool wrap) VAL(val) = state ? 1 : 0; } -static int flag_set(const m_option_t *opt, void *dst, struct mpv_node *src) +static int bool_set(const m_option_t *opt, void *dst, struct mpv_node *src) { if (src->format != MPV_FORMAT_FLAG) return M_OPT_UNKNOWN; @@ -162,7 +196,7 @@ static int flag_set(const m_option_t *opt, void *dst, struct mpv_node *src) return 1; } -static int flag_get(const m_option_t *opt, void *ta_parent, +static int bool_get(const m_option_t *opt, void *ta_parent, struct mpv_node *dst, void *src) { dst->format = MPV_FORMAT_FLAG; @@ -170,11 +204,73 @@ static int flag_get(const m_option_t *opt, void *ta_parent, return 1; } +static bool bool_equal(const m_option_t *opt, void *a, void *b) +{ + return VAL(a) == VAL(b); +} + +const m_option_type_t m_option_type_bool = { + .name = "Flag", // same as m_option_type_flag; transparent to user + .size = sizeof(bool), + .flags = M_OPT_TYPE_OPTIONAL_PARAM | M_OPT_TYPE_CHOICE, + .parse = parse_bool, + .print = print_bool, + .copy = copy_opt, + .add = add_bool, + .set = bool_set, + .get = bool_get, + .equal = bool_equal, +}; + +#undef VAL + +// Flag + +#define VAL(x) (*(int *)(x)) + +static int parse_flag(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param, void *dst) +{ + bool bdst = false; + int r = parse_bool(log, opt, name, param, &bdst); + if (dst) + VAL(dst) = bdst; + return r; +} + +static char *print_flag(const m_option_t *opt, const void *val) +{ + return print_bool(opt, &(bool){VAL(val)}); +} + +static void add_flag(const m_option_t *opt, void *val, double add, bool wrap) +{ + bool bval = VAL(val); + add_bool(opt, &bval, add, wrap); + VAL(val) = bval; +} + +static int flag_set(const m_option_t *opt, void *dst, struct mpv_node *src) +{ + bool bdst = false; + int r = bool_set(opt, &bdst, src); + if (r >= 0) + VAL(dst) = bdst; + return r; +} + +static int flag_get(const m_option_t *opt, void *ta_parent, + struct mpv_node *dst, void *src) +{ + return bool_get(opt, ta_parent, dst, &(bool){VAL(src)}); +} + static bool flag_equal(const m_option_t *opt, void *a, void *b) { return VAL(a) == VAL(b); } +// Only exists for libmpv interopability and should not be used anywhere. const m_option_type_t m_option_type_flag = { // need yes or no in config files .name = "Flag", @@ -193,16 +289,19 @@ const m_option_type_t m_option_type_flag = { #undef VAL -static int clamp_longlong(const m_option_t *opt, void *val) +static int clamp_longlong(const m_option_t *opt, long long i_min, long long i_max, + void *val) { long long v = *(long long *)val; int r = 0; - if ((opt->flags & M_OPT_MAX) && (v > opt->max)) { - v = opt->max; + long long min = OPT_INT_MIN(opt, long long, i_min); + long long max = OPT_INT_MAX(opt, long long, i_max); + if (v > max) { + v = max; r = M_OPT_OUT_OF_RANGE; } - if ((opt->flags & M_OPT_MIN) && (v < opt->min)) { - v = opt->min; + if (v < min) { + v = min; r = M_OPT_OUT_OF_RANGE; } *(long long *)val = v; @@ -210,6 +309,7 @@ static int clamp_longlong(const m_option_t *opt, void *val) } static int parse_longlong(struct mp_log *log, const m_option_t *opt, + long long i_min, long long i_max, struct bstr name, struct bstr param, void *dst) { if (param.len == 0) @@ -225,15 +325,17 @@ static int parse_longlong(struct mp_log *log, const m_option_t *opt, return M_OPT_INVALID; } - if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) { - mp_err(log, "The %.*s option must be >= %d: %.*s\n", - BSTR_P(name), (int) opt->min, BSTR_P(param)); + long long min = OPT_INT_MIN(opt, long long, i_min); + if (tmp_int < min) { + mp_err(log, "The %.*s option must be >= %lld: %.*s\n", + BSTR_P(name), min, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } - if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) { - mp_err(log, "The %.*s option must be <= %d: %.*s\n", - BSTR_P(name), (int) opt->max, BSTR_P(param)); + long long max = OPT_INT_MAX(opt, long long, i_max); + if (tmp_int > max) { + mp_err(log, "The %.*s option must be <= %lld: %.*s\n", + BSTR_P(name), max, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } @@ -246,7 +348,7 @@ static int parse_longlong(struct mp_log *log, const m_option_t *opt, static int clamp_int64(const m_option_t *opt, void *val) { long long tmp = *(int64_t *)val; - int r = clamp_longlong(opt, &tmp); + int r = clamp_longlong(opt, INT64_MIN, INT64_MAX, &tmp); *(int64_t *)val = tmp; return r; } @@ -255,7 +357,7 @@ static int parse_int(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { long long tmp; - int r = parse_longlong(log, opt, name, param, &tmp); + int r = parse_longlong(log, opt, INT_MIN, INT_MAX, name, param, &tmp); if (r >= 0 && dst) *(int *)dst = tmp; return r; @@ -265,7 +367,7 @@ static int parse_int64(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { long long tmp; - int r = parse_longlong(log, opt, name, param, &tmp); + int r = parse_longlong(log, opt, INT64_MIN, INT64_MAX, name, param, &tmp); if (r >= 0 && dst) *(int64_t *)dst = tmp; return r; @@ -290,8 +392,8 @@ static void add_int64(const m_option_t *opt, void *val, double add, bool wrap) int64_t nmin = is64 ? INT64_MIN : INT_MIN; int64_t nmax = is64 ? INT64_MAX : INT_MAX; - int64_t min = (opt->flags & M_OPT_MIN) ? opt->min : nmin; - int64_t max = (opt->flags & M_OPT_MAX) ? opt->max : nmax; + int64_t min = OPT_INT_MIN(opt, int64_t, nmin); + int64_t max = OPT_INT_MAX(opt, int64_t, nmax); if (v < min) v = wrap ? max : min; @@ -314,7 +416,7 @@ static void multiply_int64(const m_option_t *opt, void *val, double f) int64_t iv = v; if (v < INT64_MIN) iv = INT64_MIN; - if (v > INT64_MAX) + if (v >= (double)INT64_MAX) iv = INT64_MAX; *(int64_t *)val = iv; clamp_int64(opt, val); @@ -332,9 +434,9 @@ static int int64_set(const m_option_t *opt, void *dst, struct mpv_node *src) if (src->format != MPV_FORMAT_INT64) return M_OPT_UNKNOWN; int64_t val = src->u.int64; - if ((opt->flags & M_OPT_MIN) && val < opt->min) + if (val < OPT_INT_MIN(opt, int64_t, INT64_MIN)) return M_OPT_OUT_OF_RANGE; - if ((opt->flags & M_OPT_MAX) && val > opt->max) + if (val > OPT_INT_MAX(opt, int64_t, INT64_MAX)) return M_OPT_OUT_OF_RANGE; *(int64_t *)dst = val; return 1; @@ -380,6 +482,7 @@ static bool int64_equal(const m_option_t *opt, void *a, void *b) const m_option_type_t m_option_type_int = { .name = "Integer", + .flags = M_OPT_TYPE_USES_RANGE, .size = sizeof(int), .parse = parse_int, .print = print_int, @@ -393,6 +496,7 @@ const m_option_type_t m_option_type_int = { const m_option_type_t m_option_type_int64 = { .name = "Integer64", + .flags = M_OPT_TYPE_USES_RANGE, .size = sizeof(int64_t), .parse = parse_int64, .print = print_int, @@ -447,15 +551,17 @@ static int parse_byte_size(struct mp_log *log, const m_option_t *opt, tmp_int *= unit; - if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) { - mp_err(log, "The %.*s option must be >= %d: %.*s\n", - BSTR_P(name), (int) opt->min, BSTR_P(param)); + int64_t min = OPT_INT_MIN(opt, int64_t, INT64_MIN); + if (tmp_int < min) { + mp_err(log, "The %.*s option must be >= %"PRId64": %.*s\n", + BSTR_P(name), min, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } - if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) { - mp_err(log, "The %.*s option must be <= %d: %.*s\n", - BSTR_P(name), (int) opt->max, BSTR_P(param)); + int64_t max = OPT_INT_MAX(opt, int64_t, INT64_MAX); + if (tmp_int > max) { + mp_err(log, "The %.*s option must be <= %"PRId64": %.*s\n", + BSTR_P(name), max, BSTR_P(param)); return M_OPT_OUT_OF_RANGE; } @@ -490,6 +596,7 @@ static char *pretty_print_byte_size(const m_option_t *opt, const void *val) const m_option_type_t m_option_type_byte_size = { .name = "ByteSize", + .flags = M_OPT_TYPE_USES_RANGE, .size = sizeof(int64_t), .parse = parse_byte_size, .print = print_int, @@ -502,59 +609,6 @@ const m_option_type_t m_option_type_byte_size = { .equal = int64_equal, }; -static int parse_intpair(struct mp_log *log, const struct m_option *opt, - struct bstr name, struct bstr param, void *dst) -{ - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - struct bstr s = param; - int end = -1; - int start = bstrtoll(s, &s, 10); - if (s.len == param.len) - goto bad; - if (s.len > 0) { - if (!bstr_startswith0(s, "-")) - goto bad; - s = bstr_cut(s, 1); - } - if (s.len > 0) - end = bstrtoll(s, &s, 10); - if (s.len > 0) - goto bad; - - if (dst) { - int *p = dst; - p[0] = start; - p[1] = end; - } - - return 1; - -bad: - mp_err(log, "Invalid integer range " - "specification for option %.*s: %.*s\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; -} - -static char *print_intpair(const m_option_t *opt, const void *val) -{ - const int *p = val; - char *res = talloc_asprintf(NULL, "%d", p[0]); - if (p[1] != -1) - res = talloc_asprintf_append(res, "-%d", p[1]); - return res; -} - -const struct m_option_type m_option_type_intpair = { - .name = "Int[-Int]", - .size = sizeof(int[2]), - .parse = parse_intpair, - .print = print_intpair, - .copy = copy_opt, -}; - const char *m_opt_choice_str(const struct m_opt_choice_alternatives *choices, int value) { @@ -567,17 +621,17 @@ const char *m_opt_choice_str(const struct m_opt_choice_alternatives *choices, static void print_choice_values(struct mp_log *log, const struct m_option *opt) { - struct m_opt_choice_alternatives *alt = opt->priv; + const struct m_opt_choice_alternatives *alt = opt->priv; for ( ; alt->name; alt++) mp_info(log, " %s\n", alt->name[0] ? alt->name : "(passing nothing)"); - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) + if (opt->min < opt->max) mp_info(log, " %g-%g (integer range)\n", opt->min, opt->max); } static int parse_choice(struct mp_log *log, const struct m_option *opt, struct bstr name, struct bstr param, void *dst) { - struct m_opt_choice_alternatives *alt = opt->priv; + const struct m_opt_choice_alternatives *alt = opt->priv; for ( ; alt->name; alt++) { if (!bstrcmp0(param, alt->name)) break; @@ -597,9 +651,11 @@ static int parse_choice(struct mp_log *log, const struct m_option *opt, } if (param.len == 0) return M_OPT_MISSING_PARAM; - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + if (opt->min < opt->max) { long long val; - if (parse_longlong(mp_null_log, opt, name, param, &val) == 1) { + if (parse_longlong(mp_null_log, opt, INT_MIN, INT_MAX, name, param, + &val) == 1) + { if (dst) *(int *)dst = val; return 1; @@ -622,11 +678,11 @@ static void choice_get_min_max(const struct m_option *opt, int *min, int *max) assert(opt->type == &m_option_type_choice); *min = INT_MAX; *max = INT_MIN; - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) { + for (const struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) { *min = MPMIN(*min, alt->value); *max = MPMAX(*max, alt->value); } - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + if (opt->min < opt->max) { *min = MPMIN(*min, opt->min); *max = MPMAX(*max, opt->max); } @@ -653,7 +709,7 @@ static void add_choice(const m_option_t *opt, void *val, double add, bool wrap) if (fabs(add) < 0.5) return; - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + if (opt->min < opt->max) { int newval = ival + add; if (ival >= opt->min && ival <= opt->max && newval >= opt->min && newval <= opt->max) @@ -666,7 +722,7 @@ static void add_choice(const m_option_t *opt, void *val, double add, bool wrap) } } - for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) + for (const struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) check_choice(dir, ival, &found, &best, alt->value); if (!found) { @@ -699,29 +755,30 @@ static int choice_set(const m_option_t *opt, void *dst, struct mpv_node *src) return r; } -static struct m_opt_choice_alternatives *get_choice(const m_option_t *opt, - const void *val, int *out_val) +static const struct m_opt_choice_alternatives *get_choice(const m_option_t *opt, + const void *val, + int *out_val) { int v = *(int *)val; - struct m_opt_choice_alternatives *alt; + const struct m_opt_choice_alternatives *alt; for (alt = opt->priv; alt->name; alt++) { if (alt->value == v) return alt; } - if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + if (opt->min < opt->max) { if (v >= opt->min && v <= opt->max) { *out_val = v; return NULL; } } - abort(); + MP_ASSERT_UNREACHABLE(); } static int choice_get(const m_option_t *opt, void *ta_parent, struct mpv_node *dst, void *src) { int ival = 0; - struct m_opt_choice_alternatives *alt = get_choice(opt, src, &ival); + const struct m_opt_choice_alternatives *alt = get_choice(opt, src, &ival); // If a choice string looks like a number, return it as number if (alt) { char *end = NULL; @@ -753,7 +810,7 @@ static int choice_get(const m_option_t *opt, void *ta_parent, static char *print_choice(const m_option_t *opt, const void *val) { int ival = 0; - struct m_opt_choice_alternatives *alt = get_choice(opt, val, &ival); + const struct m_opt_choice_alternatives *alt = get_choice(opt, val, &ival); return alt ? talloc_strdup(NULL, alt->name) : talloc_asprintf(NULL, "%d", ival); } @@ -761,7 +818,7 @@ static char *print_choice(const m_option_t *opt, const void *val) const struct m_option_type m_option_type_choice = { .name = "Choice", .size = sizeof(int), - .flags = M_OPT_TYPE_CHOICE, + .flags = M_OPT_TYPE_CHOICE | M_OPT_TYPE_USES_RANGE, .parse = parse_choice, .print = print_choice, .copy = copy_opt, @@ -773,7 +830,7 @@ const struct m_option_type m_option_type_choice = { static int apply_flag(const struct m_option *opt, int *val, bstr flag) { - struct m_opt_choice_alternatives *alt; + const struct m_opt_choice_alternatives *alt; for (alt = opt->priv; alt->name; alt++) { if (bstr_equals0(flag, alt->name)) { if (*val & alt->value) @@ -787,8 +844,8 @@ static int apply_flag(const struct m_option *opt, int *val, bstr flag) static const char *find_next_flag(const struct m_option *opt, int *val) { - struct m_opt_choice_alternatives *best = NULL; - struct m_opt_choice_alternatives *alt; + const struct m_opt_choice_alternatives *best = NULL; + const struct m_opt_choice_alternatives *alt; for (alt = opt->priv; alt->name; alt++) { if (alt->value && (alt->value & (*val)) == alt->value) { if (!best || av_popcount64(alt->value) > av_popcount64(best->value)) @@ -815,7 +872,7 @@ static int parse_flags(struct mp_log *log, const struct m_option *opt, mp_fatal(log, "Invalid flag for option %.*s: %.*s\n", BSTR_P(name), BSTR_P(flag)); mp_info(log, "Valid flags are:\n"); - struct m_opt_choice_alternatives *alt; + const struct m_opt_choice_alternatives *alt; for (alt = opt->priv; alt->name; alt++) mp_info(log, " %s\n", alt->name); mp_info(log, "Flags can usually be combined with '+'.\n"); @@ -903,13 +960,15 @@ static int clamp_double(const m_option_t *opt, void *val) { double v = VAL(val); int r = 0; - if ((opt->flags & M_OPT_MAX) && (v > opt->max)) { - v = opt->max; - r = M_OPT_OUT_OF_RANGE; - } - if ((opt->flags & M_OPT_MIN) && (v < opt->min)) { - v = opt->min; - r = M_OPT_OUT_OF_RANGE; + if (opt->min < opt->max) { + if (v > opt->max) { + v = opt->max; + r = M_OPT_OUT_OF_RANGE; + } + if (v < opt->min) { + v = opt->min; + r = M_OPT_OUT_OF_RANGE; + } } // (setting max/min to INFINITY/-INFINITY is allowed) if (!isfinite(v) && v != opt->max && v != opt->min) { @@ -964,12 +1023,12 @@ static char *print_double(const m_option_t *opt, const void *val) return talloc_asprintf(NULL, "%f", f); } -static char *print_double_f3(const m_option_t *opt, const void *val) +static char *pretty_print_double(const m_option_t *opt, const void *val) { double f = VAL(val); if (isnan(f)) return print_double(opt, val); - return talloc_asprintf(NULL, "%.3f", f); + return mp_format_double(NULL, f, 4, false, false, !(opt->flags & M_OPT_FIXED_LEN_PRINT)); } static void add_double(const m_option_t *opt, void *val, double add, bool wrap) @@ -978,8 +1037,8 @@ static void add_double(const m_option_t *opt, void *val, double add, bool wrap) v = v + add; - double min = (opt->flags & M_OPT_MIN) ? opt->min : -INFINITY; - double max = (opt->flags & M_OPT_MAX) ? opt->max : +INFINITY; + double min = opt->min < opt->max ? opt->min : -INFINITY; + double max = opt->min < opt->max ? opt->max : +INFINITY; if (v < min) v = wrap ? max : min; @@ -1037,10 +1096,37 @@ static bool double_equal(const m_option_t *opt, void *a, void *b) const m_option_type_t m_option_type_double = { // double precision float or ratio (numerator[:/]denominator) .name = "Double", + .flags = M_OPT_TYPE_USES_RANGE, .size = sizeof(double), .parse = parse_double, .print = print_double, - .pretty_print = print_double_f3, + .pretty_print = pretty_print_double, + .copy = copy_opt, + .add = add_double, + .multiply = multiply_double, + .set = double_set, + .get = double_get, + .equal = double_equal, +}; + +static int parse_double_aspect(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param, void *dst) +{ + if (bstr_equals0(param, "no")) { + if (dst) + VAL(dst) = 0.0; + return 1; + } + return parse_double(log, opt, name, param, dst); +} + +const m_option_type_t m_option_type_aspect = { + .name = "Aspect", + .size = sizeof(double), + .flags = M_OPT_TYPE_CHOICE | M_OPT_TYPE_USES_RANGE, + .parse = parse_double_aspect, + .print = print_double, + .pretty_print = pretty_print_double, .copy = copy_opt, .add = add_double, .multiply = multiply_double, @@ -1068,10 +1154,10 @@ static char *print_float(const m_option_t *opt, const void *val) return print_double(opt, &tmp); } -static char *print_float_f3(const m_option_t *opt, const void *val) +static char *pretty_print_float(const m_option_t *opt, const void *val) { double tmp = VAL(val); - return print_double_f3(opt, &tmp); + return pretty_print_double(opt, &tmp); } static void add_float(const m_option_t *opt, void *val, double add, bool wrap) @@ -1112,36 +1198,11 @@ static bool float_equal(const m_option_t *opt, void *a, void *b) const m_option_type_t m_option_type_float = { // floating point number or ratio (numerator[:/]denominator) .name = "Float", + .flags = M_OPT_TYPE_USES_RANGE, .size = sizeof(float), .parse = parse_float, .print = print_float, - .pretty_print = print_float_f3, - .copy = copy_opt, - .add = add_float, - .multiply = multiply_float, - .set = float_set, - .get = float_get, - .equal = float_equal, -}; - -static int parse_float_aspect(struct mp_log *log, const m_option_t *opt, - struct bstr name, struct bstr param, void *dst) -{ - if (bstr_equals0(param, "no")) { - if (dst) - VAL(dst) = 0.0f; - return 1; - } - return parse_float(log, opt, name, param, dst); -} - -const m_option_type_t m_option_type_aspect = { - .name = "Aspect", - .size = sizeof(float), - .flags = M_OPT_TYPE_CHOICE, - .parse = parse_float_aspect, - .print = print_float, - .pretty_print = print_float_f3, + .pretty_print = pretty_print_float, .copy = copy_opt, .add = add_float, .multiply = multiply_float, @@ -1155,39 +1216,9 @@ const m_option_type_t m_option_type_aspect = { #undef VAL #define VAL(x) (*(char **)(x)) -static int clamp_str(const m_option_t *opt, void *val) -{ - char *v = VAL(val); - int len = v ? strlen(v) : 0; - if ((opt->flags & M_OPT_MIN) && (len < opt->min)) - return M_OPT_OUT_OF_RANGE; - if ((opt->flags & M_OPT_MAX) && (len > opt->max)) - return M_OPT_OUT_OF_RANGE; - return 0; -} - static int parse_str(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { - m_opt_string_validate_fn validate = opt->priv; - if (validate) { - int r = validate(log, opt, name, param); - if (r < 0) - return r; - } - - if ((opt->flags & M_OPT_MIN) && (param.len < opt->min)) { - mp_err(log, "Parameter must be >= %d chars: %.*s\n", - (int) opt->min, BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - - if ((opt->flags & M_OPT_MAX) && (param.len > opt->max)) { - mp_err(log, "Parameter must be <= %d chars: %.*s\n", - (int) opt->max, BSTR_P(param)); - return M_OPT_OUT_OF_RANGE; - } - if (dst) { talloc_free(VAL(dst)); VAL(dst) = bstrdup0(NULL, param); @@ -1214,7 +1245,7 @@ static int str_set(const m_option_t *opt, void *dst, struct mpv_node *src) if (src->format != MPV_FORMAT_STRING) return M_OPT_UNKNOWN; char *s = src->u.string; - int r = s ? clamp_str(opt, &s) : M_OPT_INVALID; + int r = s ? 0 : M_OPT_INVALID; if (r >= 0) copy_str(opt, dst, &s); return r; @@ -1261,11 +1292,10 @@ const m_option_type_t m_option_type_string = { #define OP_NONE 0 #define OP_ADD 1 #define OP_PRE 2 -#define OP_DEL 3 -#define OP_CLR 4 -#define OP_TOGGLE 5 -#define OP_APPEND 6 -#define OP_REMOVE 7 +#define OP_CLR 3 +#define OP_TOGGLE 4 +#define OP_APPEND 5 +#define OP_REMOVE 6 static void free_str_list(void *dst) { @@ -1307,55 +1337,6 @@ static int str_list_add(char **add, int n, void *dst, int pre) return 1; } -static int str_list_del(struct mp_log *log, char **del, int n, void *dst) -{ - char **lst, *ep; - int i, ln, s; - long idx; - - lst = VAL(dst); - - for (ln = 0; lst && lst[ln]; ln++) - /**/; - s = ln; - - for (i = 0; del[i] != NULL; i++) { - idx = strtol(del[i], &ep, 0); - if (*ep) { - mp_err(log, "Invalid index: %s\n", del[i]); - talloc_free(del[i]); - continue; - } - talloc_free(del[i]); - if (idx < 0 || idx >= ln) { - mp_err(log, "Index %ld is out of range.\n", idx); - continue; - } else if (!lst[idx]) - continue; - talloc_free(lst[idx]); - lst[idx] = NULL; - s--; - } - talloc_free(del); - - if (s == 0) { - talloc_free(lst); - VAL(dst) = NULL; - return 1; - } - - // Don't bother shrinking the list allocation - for (i = 0, n = 0; i < ln; i++) { - if (!lst[i]) - continue; - lst[n] = lst[i]; - n++; - } - lst[s] = NULL; - - return 1; -} - static struct bstr get_nextsep(struct bstr *ptr, char sep, bool modify) { struct bstr str = *ptr; @@ -1402,11 +1383,6 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt, multi = false; } else if (bstr_endswith0(name, "-pre")) { op = OP_PRE; - } else if (bstr_endswith0(name, "-del")) { - op = OP_DEL; - mp_warn(log, "Option %.*s: -del is deprecated! " - "Use -remove (removes by content instead of by index).\n", - BSTR_P(name)); } else if (bstr_endswith0(name, "-clr")) { op = OP_CLR; } else if (bstr_endswith0(name, "-set")) { @@ -1420,14 +1396,20 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt, if (op == OP_TOGGLE || op == OP_REMOVE) { if (dst) { char **list = VAL(dst); - int index = find_list_bstr(list, param); - if (index >= 0) { - char *old = list[index]; - for (int n = index; list[n]; n++) - list[n] = list[n + 1]; - talloc_free(old); + bool found = false; + int index = 0; + do { + index = find_list_bstr(list, param); + if (index >= 0) { + found = true; + char *old = list[index]; + for (int n = index; list[n]; n++) + list[n] = list[n + 1]; + talloc_free(old); + } + } while (index >= 0); + if (found) return 1; - } } if (op == OP_REMOVE) return 1; // ignore if not found @@ -1458,9 +1440,6 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt, } if (n == 0 && op != OP_NONE) return M_OPT_INVALID; - if (((opt->flags & M_OPT_MIN) && (n < opt->min)) || - ((opt->flags & M_OPT_MAX) && (n > opt->max))) - return M_OPT_OUT_OF_RANGE; if (!dst) return 1; @@ -1491,8 +1470,6 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt, return str_list_add(res, n, dst, 0); case OP_PRE: return str_list_add(res, n, dst, 1); - case OP_DEL: - return str_list_del(log, res, n, dst); } if (VAL(dst)) @@ -1535,6 +1512,7 @@ static char *print_str_list(const m_option_t *opt, const void *src) { char **lst = NULL; char *ret = NULL; + const char sep = opt->priv ? *(char *)opt->priv : OPTION_LIST_SEPARATOR; if (!(src && VAL(src))) return talloc_strdup(NULL, ""); @@ -1542,7 +1520,7 @@ static char *print_str_list(const m_option_t *opt, const void *src) for (int i = 0; lst[i]; i++) { if (ret) - ret = talloc_strdup_append_buffer(ret, ","); + ret = talloc_strndup_append_buffer(ret, &sep, 1); ret = talloc_strdup_append_buffer(ret, lst[i]); } return ret; @@ -1622,7 +1600,6 @@ const m_option_type_t m_option_type_string_list = { {"add"}, {"append"}, {"clr", M_OPT_TYPE_OPTIONAL_PARAM}, - {"del"}, {"pre"}, {"set"}, {"toggle"}, @@ -1702,7 +1679,7 @@ static int parse_keyvalue_list(struct mp_log *log, const m_option_t *opt, val = param; param.len = 0; } else { - r = read_subparam(log, name, ",:", ¶m, &val); + r = read_subparam(log, name, ",", ¶m, &val); if (r < 0) break; } @@ -1728,7 +1705,7 @@ static int parse_keyvalue_list(struct mp_log *log, const m_option_t *opt, } if (param.len) { - mp_err(log, "Unparseable garbage at end of option value: '%.*s'\n", + mp_err(log, "Unparsable garbage at end of option value: '%.*s'\n", BSTR_P(param)); r = M_OPT_INVALID; } @@ -1838,7 +1815,7 @@ static int parse_msglevels(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { if (bstr_equals0(param, "help")) { - mp_info(log, "Syntax:\n\n --msglevel=module1=level,module2=level,...\n\n" + mp_info(log, "Syntax:\n\n --msg-level=module1=level,module2=level,...\n\n" "'module' is output prefix as shown with -v, or a prefix\n" "of it. level is one of:\n\n" " fatal error warn info status v debug trace\n\n" @@ -1920,7 +1897,7 @@ const m_option_type_t m_option_type_dummy_flag = { // Read s sub-option name, or a positional sub-opt value. // termset is a string containing the set of chars that terminate an option. -// Return 0 on succes, M_OPT_ error code otherwise. +// Return 0 on success, M_OPT_ error code otherwise. // optname is for error reporting. static int read_subparam(struct mp_log *log, bstr optname, char *termset, bstr *str, bstr *out_subparam) @@ -2137,7 +2114,7 @@ static bool parse_geometry_str(struct m_geometry *gm, bstr s) if (s.len == 0) return true; // Approximate grammar: - // [[W][xH]][{+-}X{+-}Y] | [X:Y] + // [[W][xH]][{+-}X{+-}Y][/WS] | [X:Y] // (meaning: [optional] {one character of} one|alternative) // Every number can be followed by '%' int num; @@ -2173,6 +2150,14 @@ static bool parse_geometry_str(struct m_geometry *gm, bstr s) READ_SIGN(y_sign); READ_NUM(y, y_per); } + if (bstr_eatstart0(&s, "/")) { + bstr rest; + long long v = bstrtoll(s, &rest, 10); + if (s.len == rest.len || v < 1 || v > INT_MAX) + goto error; + s = rest; + gm->ws = v; + } } else { gm->xy_valid = true; READ_NUM(x, x_per); @@ -2209,6 +2194,8 @@ static char *print_geometry(const m_option_t *opt, const void *val) res = talloc_asprintf_append(res, gm->y_sign ? "-" : "+"); APPEND_PER(y, y_per); } + if (gm->ws > 0) + res = talloc_asprintf_append(res, "/%d", gm->ws); } return res; } @@ -2236,7 +2223,7 @@ void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh, *widw = *widh * asp; } // Center window after resize. If valid x:y values are passed to - // geometry, then those values will be overriden. + // geometry, then those values will be overridden. *xpos += prew / 2 - *widw / 2; *ypos += preh / 2 - *widh / 2; } @@ -2293,7 +2280,8 @@ static bool geometry_equal(const m_option_t *opt, void *a, void *b) ga->xy_valid == gb->xy_valid && ga->wh_valid == gb->wh_valid && ga->w_per == gb->w_per && ga->h_per == gb->h_per && ga->x_per == gb->x_per && ga->y_per == gb->y_per && - ga->x_sign == gb->x_sign && ga->y_sign == gb->y_sign; + ga->x_sign == gb->x_sign && ga->y_sign == gb->y_sign && + ga->ws == gb->ws; } con |