summaryrefslogtreecommitdiffstats
path: root/options/m_option.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-03-13 16:49:39 +0100
committerwm4 <wm4@nowhere>2020-03-13 17:34:46 +0100
commit8d965a1bfb3782343a03cff44977f11bb920f0b1 (patch)
tree2d115c24510ab36cc9ac7af8dea2b710537561c9 /options/m_option.c
parent5d5a7e19537a036fe16ce04555e6ce9449c47494 (diff)
downloadmpv-8d965a1bfb3782343a03cff44977f11bb920f0b1.tar.bz2
mpv-8d965a1bfb3782343a03cff44977f11bb920f0b1.tar.xz
options: change how option range min/max is handled
Before this commit, option declarations used M_OPT_MIN/M_OPT_MAX (and some other identifiers based on these) to signal whether an option had min/max values. Remove these flags, and make it use a range implicitly on the condition if min<max is true. This requires care in all cases when only M_OPT_MIN or M_OPT_MAX were set (instead of both). Generally, the commit replaces all these instances with using DBL_MAX/DBL_MIN for the "unset" part of the range. This also happens to fix some cases where you could pass over-large values to integer options, which were silently truncated, but now cause an error. This commit has some higher potential for regressions.
Diffstat (limited to 'options/m_option.c')
-rw-r--r--options/m_option.c111
1 files changed, 70 insertions, 41 deletions
diff --git a/options/m_option.c b/options/m_option.c
index 4bfecec44d..c31fececdf 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>
@@ -52,6 +53,14 @@
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 <= (Tm) ? (Tm) : (T)((opt)->min)) : (Tm))
+#define OPT_INT_MAX(opt, T, Tm) \
+ ((opt)->min < (opt)->max ? ((opt)->max >= (Tm) ? (Tm) : (T)((opt)->max)) : (Tm))
+
char *m_option_strerror(int code)
{
switch (code) {
@@ -193,16 +202,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 +222,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 +238,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 +261,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 +270,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 +280,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 +305,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;
@@ -332,9 +347,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 +395,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 +409,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 +464,20 @@ 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));
+ double x = INT64_MAX;
+ printf("max: %ld, %f %f %ld %ld %d %d\n", max, x, opt->max, (int64_t)opt->max, (int64_t)x, x > INT64_MAX, x == INT64_MAX);
+ abort();
return M_OPT_OUT_OF_RANGE;
}
@@ -490,6 +512,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,
@@ -517,7 +540,7 @@ static void print_choice_values(struct mp_log *log, const struct m_option *opt)
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);
}
@@ -544,9 +567,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;
@@ -573,7 +598,7 @@ static void choice_get_min_max(const struct m_option *opt, int *min, int *max)
*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);
}
@@ -600,7 +625,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)
@@ -655,7 +680,7 @@ static struct m_opt_choice_alternatives *get_choice(const m_option_t *opt,
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;
@@ -708,7 +733,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,
@@ -850,13 +875,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) {
@@ -925,8 +952,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;
@@ -984,6 +1011,7 @@ 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,
@@ -1059,6 +1087,7 @@ 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,
@@ -1085,7 +1114,7 @@ static int parse_float_aspect(struct mp_log *log, const m_option_t *opt,
const m_option_type_t m_option_type_aspect = {
.name = "Aspect",
.size = sizeof(float),
- .flags = M_OPT_TYPE_CHOICE,
+ .flags = M_OPT_TYPE_CHOICE | M_OPT_TYPE_USES_RANGE,
.parse = parse_float_aspect,
.print = print_float,
.pretty_print = print_float_f3,