OSDN Git Service

conf: implement snd_config_add_before() and snd_config_add_after()
authorJaroslav Kysela <perex@perex.cz>
Thu, 14 Nov 2019 15:56:05 +0000 (16:56 +0100)
committerJaroslav Kysela <perex@perex.cz>
Thu, 14 Nov 2019 15:56:05 +0000 (16:56 +0100)
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
include/conf.h
include/list.h
src/conf.c

index d44c0a2..456b272 100644 (file)
@@ -114,7 +114,9 @@ int snd_config_expand(snd_config_t *config, snd_config_t *root,
 int snd_config_evaluate(snd_config_t *config, snd_config_t *root,
                        snd_config_t *private_data, snd_config_t **result);
 
-int snd_config_add(snd_config_t *config, snd_config_t *leaf);
+int snd_config_add(snd_config_t *config, snd_config_t *child);
+int snd_config_add_before(snd_config_t *before, snd_config_t *child);
+int snd_config_add_after(snd_config_t *after, snd_config_t *child);
 int snd_config_remove(snd_config_t *config);
 int snd_config_delete(snd_config_t *config);
 int snd_config_delete_compound_members(const snd_config_t *config);
index 947c1f8..7f0cfc0 100644 (file)
@@ -86,6 +86,21 @@ static inline void list_add_tail(struct list_head *p, struct list_head *list)
        list->prev = p;
 }
 
+/* list_insert - insert a new list entry between two known consecutive entries
+ * @p: the new entry to be inserted between prev and next
+ * @prev: the left-side entry
+ * @next: the right-side entry
+ */
+static inline void list_insert(struct list_head *p,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+       next->prev = p;
+       p->next = next;
+       p->prev = prev;
+       prev->next = p;
+}
+
 /* list_del - delete the given list entry */
 static inline void list_del(struct list_head *p)
 {
index 558114a..ffdbdd1 100644 (file)
@@ -1979,6 +1979,88 @@ int snd_config_add(snd_config_t *parent, snd_config_t *child)
 }
 
 /**
+ * \brief Adds a child after another child configuration node.
+ * \param after Handle to the start configuration node.
+ * \param child Handle to the configuration node to be added.
+ * \return Zero if successful, otherwise a negative error code.
+ *
+ * This function makes the node \a child a child of the parent of
+ * the node \a after.
+ *
+ * The parent node then owns the child node, i.e., the child node gets
+ * deleted together with its parent.
+ *
+ * \a child must have an id.
+ *
+ * \par Errors:
+ * <dl>
+ * <dt>-EINVAL<dd>\a child does not have an id.
+ * <dt>-EINVAL<dd>\a child already has a parent.
+ * <dt>-EEXIST<dd>\a parent already contains a child node with the same
+ *                id as \a child.
+ * </dl>
+ */
+int snd_config_add_after(snd_config_t *after, snd_config_t *child)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *parent;
+       assert(after && child);
+       parent = after->parent;
+       assert(parent);
+       if (!child->id || child->parent)
+               return -EINVAL;
+       snd_config_for_each(i, next, parent) {
+               snd_config_t *n = snd_config_iterator_entry(i);
+               if (strcmp(child->id, n->id) == 0)
+                       return -EEXIST;
+       }
+       child->parent = parent;
+       list_insert(&child->list, &after->list, after->list.next);
+       return 0;
+}
+
+/**
+ * \brief Adds a child before another child configuration node.
+ * \param before Handle to the start configuration node.
+ * \param child Handle to the configuration node to be added.
+ * \return Zero if successful, otherwise a negative error code.
+ *
+ * This function makes the node \a child a child of the parent of
+ * the node \a before.
+ *
+ * The parent node then owns the child node, i.e., the child node gets
+ * deleted together with its parent.
+ *
+ * \a child must have an id.
+ *
+ * \par Errors:
+ * <dl>
+ * <dt>-EINVAL<dd>\a child does not have an id.
+ * <dt>-EINVAL<dd>\a child already has a parent.
+ * <dt>-EEXIST<dd>\a parent already contains a child node with the same
+ *                id as \a child.
+ * </dl>
+ */
+int snd_config_add_before(snd_config_t *before, snd_config_t *child)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *parent;
+       assert(before && child);
+       parent = before->parent;
+       assert(parent);
+       if (!child->id || child->parent)
+               return -EINVAL;
+       snd_config_for_each(i, next, parent) {
+               snd_config_t *n = snd_config_iterator_entry(i);
+               if (strcmp(child->id, n->id) == 0)
+                       return -EEXIST;
+       }
+       child->parent = parent;
+       list_insert(&child->list, before->list.prev, &before->list);
+       return 0;
+}
+
+/**
  * \brief Removes a configuration node from its tree.
  * \param config Handle to the configuration node to be removed.
  * \return Zero if successful, otherwise a negative error code.