]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add helper API calls to manipulate maps and lists
authorColin Vidal <colin@isc.org>
Thu, 16 Oct 2025 12:54:24 +0000 (14:54 +0200)
committerEvan Hunt <each@isc.org>
Wed, 29 Oct 2025 20:55:04 +0000 (13:55 -0700)
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.

lib/isccfg/include/isccfg/cfg.h
lib/isccfg/parser.c

index adc3a95eb1209f91e55d12c3b11a3282dda4ef1f..ec3076f3ce490464c4a55de1607e0833bd4e4d2b 100644 (file)
@@ -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);
 /*%<
index aad26d4ddf0cbeb7b771ea17341fba1907a5b475..646471e52b7de8165307a38f2ee1022ed2b032f5 100644 (file)
@@ -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,