summaryrefslogtreecommitdiffstats
path: root/m_option.c
diff options
context:
space:
mode:
Diffstat (limited to 'm_option.c')
-rw-r--r--m_option.c137
1 files changed, 135 insertions, 2 deletions
diff --git a/m_option.c b/m_option.c
index 015b8f8e20..14a1a0a3d7 100644
--- a/m_option.c
+++ b/m_option.c
@@ -26,15 +26,18 @@
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
+#include <limits.h>
#include <inttypes.h>
#include <unistd.h>
#include <assert.h>
+#include <libavutil/common.h>
+#include <libavutil/avstring.h>
+
#include "talloc.h"
#include "m_option.h"
#include "mp_msg.h"
#include "stream/url.h"
-#include "libavutil/avstring.h"
char *m_option_strerror(int code)
{
@@ -128,6 +131,15 @@ static char *print_flag(const m_option_t *opt, const void *val)
return talloc_strdup(NULL, "yes");
}
+static void add_flag(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ if (fabs(add) < 0.5)
+ return;
+ bool state = VAL(val) != opt->min;
+ state = wrap ? !state : add > 0;
+ VAL(val) = state ? opt->max : opt->min;
+}
+
const m_option_type_t m_option_type_flag = {
// need yes or no in config files
.name = "Flag",
@@ -136,10 +148,13 @@ const m_option_type_t m_option_type_flag = {
.parse = parse_flag,
.print = print_flag,
.copy = copy_opt,
+ .add = add_flag,
};
// Integer
+#undef VAL
+
static int parse_longlong(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
@@ -202,7 +217,35 @@ static char *print_int(const m_option_t *opt, const void *val)
{
if (opt->type->size == sizeof(int64_t))
return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val);
- return talloc_asprintf(NULL, "%d", VAL(val));
+ return talloc_asprintf(NULL, "%d", *(const int *)val);
+}
+
+static void add_int64(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ int64_t v = *(int64_t *)val;
+
+ v = v + add;
+
+ bool is64 = opt->type->size == sizeof(int64_t);
+ 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;
+
+ if (v < min)
+ v = wrap ? max : min;
+ if (v > max)
+ v = wrap ? min : max;
+
+ *(int64_t *)val = v;
+}
+
+static void add_int(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ int64_t tmp = *(int *)val;
+ add_int64(opt, &tmp, add, wrap);
+ *(int *)val = tmp;
}
const m_option_type_t m_option_type_int = {
@@ -211,6 +254,7 @@ const m_option_type_t m_option_type_int = {
.parse = parse_int,
.print = print_int,
.copy = copy_opt,
+ .add = add_int,
};
const m_option_type_t m_option_type_int64 = {
@@ -219,6 +263,7 @@ const m_option_type_t m_option_type_int64 = {
.parse = parse_int64,
.print = print_int,
.copy = copy_opt,
+ .add = add_int64,
};
static int parse_intpair(const struct m_option *opt, struct bstr name,
@@ -311,12 +356,74 @@ static char *print_choice(const m_option_t *opt, const void *val)
abort();
}
+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++) {
+ *min = FFMIN(*min, alt->value);
+ *max = FFMAX(*max, alt->value);
+ }
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ *min = FFMIN(*min, opt->min);
+ *max = FFMAX(*max, opt->max);
+ }
+}
+
+static void check_choice(int dir, int val, bool *found, int *best, int choice)
+{
+ if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) ||
+ (dir == +1 && (!(*found) || choice < (*best)) && choice > val))
+ {
+ *found = true;
+ *best = choice;
+ }
+}
+
+static void add_choice(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ assert(opt->type == &m_option_type_choice);
+ int dir = add > 0 ? +1 : -1;
+ bool found = false;
+ int ival = *(int *)val;
+ int best = 0; // init. value unused
+
+ if (fabs(add) < 0.5)
+ return;
+
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ int newval = ival + add;
+ if (ival >= opt->min && ival <= opt->max &&
+ newval >= opt->min && newval <= opt->max)
+ {
+ found = true;
+ best = newval;
+ } else {
+ check_choice(dir, ival, &found, &best, opt->min);
+ check_choice(dir, ival, &found, &best, opt->max);
+ }
+ }
+
+ for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++)
+ check_choice(dir, ival, &found, &best, alt->value);
+
+ if (!found) {
+ int min, max;
+ choice_get_min_max(opt, &min, &max);
+ best = (dir == -1) ^ wrap ? min : max;
+ }
+
+ *(int *)val = best;
+}
+
const struct m_option_type m_option_type_choice = {
.name = "String", // same as arbitrary strings in option list for now
.size = sizeof(int),
.parse = parse_choice,
.print = print_choice,
.copy = copy_opt,
+ .add = add_choice,
};
// Float
@@ -386,6 +493,23 @@ static char *print_double(const m_option_t *opt, const void *val)
return talloc_asprintf(NULL, "%f", VAL(val));
}
+static void add_double(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ double v = VAL(val);
+
+ v = v + add;
+
+ double min = (opt->flags & M_OPT_MIN) ? opt->min : -INFINITY;
+ double max = (opt->flags & M_OPT_MAX) ? opt->max : +INFINITY;
+
+ if (v < min)
+ v = wrap ? max : min;
+ if (v > max)
+ v = wrap ? min : max;
+
+ VAL(val) = v;
+}
+
const m_option_type_t m_option_type_double = {
// double precision float or ratio (numerator[:/]denominator)
.name = "Double",
@@ -414,6 +538,13 @@ static char *print_float(const m_option_t *opt, const void *val)
return talloc_asprintf(NULL, "%f", VAL(val));
}
+static void add_float(const m_option_t *opt, void *val, double add, bool wrap)
+{
+ double tmp = VAL(val);
+ add_double(opt, &tmp, add, wrap);
+ VAL(val) = tmp;
+}
+
const m_option_type_t m_option_type_float = {
// floating point number or ratio (numerator[:/]denominator)
.name = "Float",
@@ -421,6 +552,7 @@ const m_option_type_t m_option_type_float = {
.parse = parse_float,
.print = print_float,
.copy = copy_opt,
+ .add = add_float,
};
///////////// String
@@ -1009,6 +1141,7 @@ const m_option_type_t m_option_type_time = {
.parse = parse_time,
.print = print_double,
.copy = copy_opt,
+ .add = add_double,
};