From 0c1dd8a8f54a152755faef3d323ce6fdc7d63f73 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 6 Aug 2012 17:42:53 +0200 Subject: m_config: support flatten and merge flags for suboptions M_OPT_PREFIXED allows adding top-level options with the suboption mechanism. The point of this is that, even though these options are top-level options, they don't need to be added directly to a top- level option array (such as mplayer_opts[]). Instead, the suboption can be defined in a separate source file. Only a suboption declaration is needed to add these options. M_OPT_MERGE is similar to M_OPT_PREFIXED, but doesn't add the name of the suboptions entry as prefix. Given you have a suboption declaration "prefix" and the suboption "subopt", you can pass them as follows on the command line: normal: --prefix=subopt=value M_OPT_PREFIXED: --prefix-subopt=value M_OPT_MERGE: --subopt=value --- m_config.c | 46 ++++++++++++++++++++++++++++++++-------------- m_config.h | 2 ++ m_option.h | 8 ++++++++ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/m_config.c b/m_config.c index 2f989eb6f8..ab410646e1 100644 --- a/m_config.c +++ b/m_config.c @@ -162,8 +162,8 @@ static void optstruct_set(const struct m_config *config, } static void m_config_add_option(struct m_config *config, - const struct m_option *arg, - const char *prefix); + struct m_config_option *parent, + const struct m_option *arg); static int config_destroy(void *p) { @@ -215,7 +215,7 @@ struct m_config *m_config_new(void *optstruct, *p = (struct m_option){ "include", NULL, CONF_TYPE_STRING, 0, }; - m_config_add_option(config, p, NULL); + m_config_add_option(config, NULL, p); config->includefunc = includefunc; } @@ -263,15 +263,17 @@ void m_config_leave_file_local(struct m_config *config) } } -static void add_options(struct m_config *config, const struct m_option *defs, - const char *prefix) +static void add_options(struct m_config *config, + struct m_config_option *parent, + const struct m_option *defs) { for (int i = 0; defs[i].name; i++) - m_config_add_option(config, defs + i, prefix); + m_config_add_option(config, parent, defs + i); } static void m_config_add_option(struct m_config *config, - const struct m_option *arg, const char *prefix) + struct m_config_option *parent, + const struct m_option *arg) { struct m_config_option *co; @@ -282,15 +284,27 @@ static void m_config_add_option(struct m_config *config, co = talloc_zero(config, struct m_config_option); co->opt = arg; + if (parent) { + // Merge case: pretend it has no parent (note that we still must follow + // the "real" parent for accessing struct fields) + if (parent->opt->flags & M_OPT_MERGE) + co->parent = parent->parent; + else + co->parent = parent; + } + // Fill in the full name - if (prefix && *prefix) - co->name = talloc_asprintf(co, "%s:%s", prefix, arg->name); - else + if (co->parent) { + const char *sep = (co->parent->opt->flags & M_OPT_PREFIXED) ? "-" : ":"; + co->name = talloc_asprintf(co, "%s%s%s", co->parent->name, sep, + arg->name); + } else co->name = (char *)arg->name; // Option with children -> add them if (arg->type->flags & M_OPT_TYPE_HAS_CHILD) { - add_options(config, arg->p, co->name); + const struct m_option *sub = arg->p; + add_options(config, co, sub); } else { struct m_config_option *i; // Check if there is already an option pointing to this address @@ -328,8 +342,12 @@ static void m_config_add_option(struct m_config *config, } } } - co->next = config->opts; - config->opts = co; + + // pretend that merge options don't exist (only their children matter) + if (!(arg->flags & M_OPT_MERGE)) { + co->next = config->opts; + config->opts = co; + } } int m_config_register_options(struct m_config *config, @@ -338,7 +356,7 @@ int m_config_register_options(struct m_config *config, assert(config != NULL); assert(args != NULL); - add_options(config, args, NULL); + add_options(config, NULL, args); return 1; } diff --git a/m_config.h b/m_config.h index 10f0cb67ed..beeab80a53 100644 --- a/m_config.h +++ b/m_config.h @@ -42,6 +42,8 @@ struct m_config_option { void *global_backup; // See \ref ConfigOptionFlags. unsigned int flags; + // If this is a suboption, the option that contains this option. + struct m_config_option *parent; }; // Profiles allow to predefine some sets of options that can then diff --git a/m_option.h b/m_option.h index 4ab7e9c1d2..e0321d1de1 100644 --- a/m_option.h +++ b/m_option.h @@ -290,6 +290,14 @@ struct m_option { // For m_option_type_choice, the first listed choice will be used. #define M_OPT_IMPLICIT_DEFAULT (1 << 7) +// For options with children, add all children as top-level arguments +// (e.g. "--parent=child=value" becomes "--parent-child=value") +#define M_OPT_PREFIXED (1 << 8) + +// Similar to M_OPT_PREFIXED, but drop the prefix. +// (e.g. "--parent=child=value" becomes "--child=value") +#define M_OPT_MERGE (1 << 9) + // These are kept for compatibility with older code. #define CONF_MIN M_OPT_MIN #define CONF_MAX M_OPT_MAX -- cgit v1.2.3