From 9a66cc102074b33f1c01b27a725447cc7e82c1b3 Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Tue, 3 Dec 2024 20:08:39 -0500 Subject: [PATCH] add FR_CONF_OFFSET_REF() which allows you to reference another conf_parser_t, without requiring an intermediary CONF_SECTION --- src/lib/server/cf_parse.c | 48 +++++++++++++++++++++++++++++++++++++-- src/lib/server/cf_parse.h | 14 ++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/lib/server/cf_parse.c b/src/lib/server/cf_parse.c index 29a8647c1c161..1ead95765ea37 100644 --- a/src/lib/server/cf_parse.c +++ b/src/lib/server/cf_parse.c @@ -723,6 +723,9 @@ static int cf_section_parse_init(CONF_SECTION *cs, void *base, conf_parser_t con { CONF_PAIR *cp; + /* + * This rule refers to a named subsection + */ if ((rule->flags & CONF_FLAG_SUBSECTION)) { char const *name2 = NULL; CONF_SECTION *subcs; @@ -785,6 +788,14 @@ static int cf_section_parse_init(CONF_SECTION *cs, void *base, conf_parser_t con return 0; } + /* + * This rule refers to another conf_parse_t which is included in-line in + * this section. + */ + if ((rule->flags & CONF_FLAG_REF) != 0) { + return 0; + } + /* * Don't re-initialize data which was already parsed. */ @@ -971,7 +982,7 @@ static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, void *base, CONF_SECT return 0; } -static int cf_section_parse_rule(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, conf_parser_t *rule) +static int cf_section_parse_rule(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, conf_parser_t const *rule) { int ret; bool *is_set = NULL; @@ -999,7 +1010,40 @@ static int cf_section_parse_rule(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, */ if (rule->flags & CONF_FLAG_SUBSECTION) { return cf_subsection_parse(ctx, data, base, cs, rule); - } /* else it's a CONF_PAIR */ + } + + /* + * Ignore this rule if it's a reference, as the + * rules it points to have been pushed by the + * above function. + */ + if ((rule->flags & CONF_FLAG_REF) != 0) { + conf_parser_t const *rule_p; + uint8_t *sub_base = base; + + fr_assert(rule->subcs != NULL); + + sub_base += rule->offset; + + for (rule_p = rule->subcs; rule_p->name1; rule_p++) { + if (rule_p->flags & CONF_FLAG_DEPRECATED) continue; /* Skip deprecated */ + + ret = cf_section_parse_rule(ctx, sub_base, cs, rule_p); + if (ret < 0) return ret; + } + + /* + * Ensure we have a proper terminator, type so we catch + * missing terminators reliably + */ + fr_cond_assert(rule_p->type == conf_term.type); + + return 0; + } + + /* + * Else it's a CONF_PAIR + */ /* * Pair either needs an output destination or diff --git a/src/lib/server/cf_parse.h b/src/lib/server/cf_parse.h index f1dbdd9bebbe3..e175d50639f9d 100644 --- a/src/lib/server/cf_parse.h +++ b/src/lib/server/cf_parse.h @@ -300,6 +300,19 @@ _Generic(&(_ct), \ .offset = offsetof(_struct, _field), \ .subcs = _subcs +/** conf_parser_t which populates a sub-struct using a CONF_SECTION + * + * @param[in] _name of the CONF_SECTION to search for. + * @param[in] _struct containing the sub-struct to populate. + * @param[in] _field containing the sub-struct to populate. + * @param[in] _subcs conf_parser_t to include in-line in this section + */ +# define FR_CONF_OFFSET_REF(__struct, _field, _subcs) \ + .name1 = CF_IDENT_NONE, \ + .flags = CONF_FLAG_REF, \ + .offset = offsetof(_struct, _field), \ + .subcs = _subcs + /** conf_parser_t which parses a single CONF_PAIR producing a single global result * * @param[in] _name of the CONF_PAIR to search for. @@ -427,6 +440,7 @@ typedef enum CC_HINT(flag_enum) { CONF_FLAG_OK_MISSING = (1 << 22), //!< OK if it's missing CONF_FLAG_HIDDEN = (1 << 23), //!< Used by scripts to omit items from the ///< generated documentation. + CONF_FLAG_REF = (1 << 24), //!< reference another conf_parser_t inline in this one } conf_parser_flags_t; DIAG_ON(attributes)