From: Colin Vidal Date: Thu, 16 Oct 2025 12:54:24 +0000 (+0200) Subject: add helper API calls to manipulate maps and lists X-Git-Tag: v9.21.15~22^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=473bbeb54b8212f1b83c3811aa76625efa447296;p=thirdparty%2Fbind9.git add helper API calls to manipulate maps and lists cfg_map_addclone() is a variant of cfg_map_add which internally clones an object and adds it to a map. It ensures that the object is an implicit list if the map clause has the CFG_CLAUSEFLAG_MULTI set cfg_list_addclone() clones a list (internally cloning each individual element) and appends or preprends it to an existing target list. Both of these will be needed to merge the default configuration with the user configuration. --- diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index adc3a95eb12..ec3076f3ce4 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -136,6 +136,32 @@ cfg_parser_currentfile(cfg_parser_t *pctx); * existent. */ +isc_result_t +cfg_map_addclone(cfg_obj_t *map, const cfg_obj_t *obj, + const cfg_clausedef_t *clause); +/*%< + * Add a clone of 'obj' to the specified clause in mapbody 'mapobj'. + * If the clause is tagged with CFG_CLAUSEFLAG_MULTI, the function expects + * that 'obj' is a list and will clone each element and sequentially add them + * (preserving the order), instead of adding a list as single element of + * map[clausename]. + * + * Require: + * \li 'obj' is a valid cfg_obj_t. + * \li 'mapobj' is a valid cfg_obj_t of type map. + * \li 'clause' is a valid clause definition. + */ + +void +cfg_list_addclone(cfg_obj_t *dst, const cfg_obj_t *src, bool prepend); +/*%< + * Clone each `src` element and add them into the existing list `dst`. If + * `prepend` is set, the `src` elements will be added at the beginning of + * `src`, and the order of `src` is preserved. + * + * Both `dst` and `src` must be valid pointers to cfg objects of type list. + */ + void cfg_obj_clone(const cfg_obj_t *source, cfg_obj_t **target); /*%< diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index aad26d4ddf0..646471e52b7 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -3992,35 +3992,32 @@ cfg_print_grammar(const cfg_type_t *type, unsigned int flags, cfg_doc_obj(&pctx, type); } -isc_result_t -cfg_map_add(cfg_obj_t *mapobj, cfg_obj_t *obj, const char *clausename) { - isc_result_t result = ISC_R_SUCCESS; - const cfg_map_t *map = NULL; - isc_symvalue_t symval; +static const cfg_clausedef_t * +map_lookup_clause(const cfg_obj_t *mapobj, const char *clausename) { + const cfg_map_t *map = &mapobj->value.map; const cfg_clausedef_t *const *clauseset = NULL; const cfg_clausedef_t *clause = NULL; - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); - REQUIRE(obj != NULL); - REQUIRE(clausename != NULL); - - map = &mapobj->value.map; - - clause = NULL; for (clauseset = map->clausesets; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; clause++) { if (strcasecmp(clause->name, clausename) == 0) { - goto breakout; + return clause; } } } -breakout: - if (clause == NULL || clause->name == NULL) { - return ISC_R_FAILURE; - } + return NULL; +} - result = isc_symtab_lookup(map->symtab, clausename, SYMTAB_DUMMY_TYPE, +static isc_result_t +map_define(cfg_obj_t *mapobj, cfg_obj_t *obj, const cfg_clausedef_t *clause) { + isc_result_t result; + const cfg_map_t *map; + isc_symvalue_t symval; + + map = &mapobj->value.map; + + result = isc_symtab_lookup(map->symtab, clause->name, SYMTAB_DUMMY_TYPE, &symval); if (result == ISC_R_NOTFOUND) { if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { @@ -4059,6 +4056,89 @@ breakout: return result; } +isc_result_t +cfg_map_add(cfg_obj_t *mapobj, cfg_obj_t *obj, const char *clausename) { + const cfg_clausedef_t *clause; + + REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + REQUIRE(obj != NULL); + REQUIRE(clausename != NULL); + + clause = map_lookup_clause(mapobj, clausename); + if (clause == NULL || clause->name == NULL) { + return ISC_R_FAILURE; + } + + return map_define(mapobj, obj, clause); +} + +isc_result_t +cfg_map_addclone(cfg_obj_t *map, const cfg_obj_t *obj, + const cfg_clausedef_t *clause) { + isc_result_t result = ISC_R_SUCCESS; + cfg_obj_t *clone = NULL; + + REQUIRE(map != NULL && map->type->rep == &cfg_rep_map); + REQUIRE(obj != NULL); + REQUIRE(clause != NULL && clause->name != NULL); + + /* + * Repeatable clauses aren't explicitly defined as cfg_list types, + * but a list is created internally if the clause has + * CFG_CLAUSEFLAG_MULTI set. + */ + if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { + const cfg_listelt_t *elt = NULL; + + REQUIRE(cfg_obj_islist(obj)); + + elt = cfg_list_first(obj); + while (elt != NULL && result == ISC_R_SUCCESS) { + cfg_obj_clone(elt->obj, &clone); + result = map_define(map, clone, clause); + elt = cfg_list_next(elt); + + /* + * map_define internally attach each added node + * in the implicit list + */ + cfg_obj_detach(&clone); + } + } else { + cfg_obj_clone(obj, &clone); + result = map_define(map, clone, clause); + } + + return result; +} + +void +cfg_list_addclone(cfg_obj_t *dst, const cfg_obj_t *src, bool prepend) { + const cfg_listelt_t *srcelt = NULL; + cfg_list_t list = ISC_LIST_INITIALIZER; + + REQUIRE(cfg_obj_islist(dst)); + REQUIRE(cfg_obj_islist(src)); + + srcelt = cfg_list_first(src); + while (srcelt != NULL) { + cfg_listelt_t *dstelt = isc_mem_get(dst->mctx, sizeof(*dstelt)); + + *dstelt = (cfg_listelt_t){ .link = ISC_LINK_INITIALIZER }; + cfg_obj_clone(srcelt->obj, &dstelt->obj); + + if (prepend) { + ISC_LIST_APPEND(list, dstelt, link); + } else { + ISC_LIST_APPEND(dst->value.list, dstelt, link); + } + srcelt = cfg_list_next(srcelt); + } + if (prepend) { + ISC_LIST_PREPENDLIST(dst->value.list, list, link); + } +} + isc_result_t cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list, cfg_aclconfctx_t *aclctx, pluginlist_cb_t *callback,