]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ucm: add Prepend and Append block handling for If conditions (syntax 8+)
authorJaroslav Kysela <perex@perex.cz>
Mon, 17 Nov 2025 17:00:59 +0000 (18:00 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 17 Nov 2025 17:01:14 +0000 (18:01 +0100)
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/ucm/ucm_cond.c
src/ucm/ucm_confdoc.h

index b86d8f045e149e9732f9c96db8be40585cb83b4f..b909c6b2bd396620105636d0bedeb70265c7a8fa 100644 (file)
@@ -373,21 +373,50 @@ static int if_eval_one(snd_use_case_mgr_t *uc_mgr,
                       snd_config_t *cond,
                       snd_config_t **result,
                       snd_config_t **before,
-                      snd_config_t **after)
+                      snd_config_t **after,
+                      snd_config_t **prepend,
+                      snd_config_t **append)
 {
        snd_config_t *expr, *_true = NULL, *_false = NULL;
-       int err;
+       int err, has_condition;
 
        *result = NULL;
+       *prepend = NULL;
+       *append = NULL;
 
        if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) {
                snd_error(UCM, "compound type expected for If.1");
                return -EINVAL;
        }
 
-       if (snd_config_search(cond, "Condition", &expr) < 0) {
-               snd_error(UCM, "condition block expected (If)");
-               return -EINVAL;
+       /* For syntax v8+, Condition is optional if Prepend or Append is present */
+       has_condition = snd_config_search(cond, "Condition", &expr) >= 0;
+
+       if (uc_mgr->conf_format >= 8) {
+               /* Check for Prepend block */
+               err = snd_config_search(cond, "Prepend", prepend);
+               if (err < 0 && err != -ENOENT) {
+                       snd_error(UCM, "prepend block error (If)");
+                       return -EINVAL;
+               }
+
+               /* Check for Append block */
+               err = snd_config_search(cond, "Append", append);
+               if (err < 0 && err != -ENOENT) {
+                       snd_error(UCM, "append block error (If)");
+                       return -EINVAL;
+               }
+
+               /* If Prepend or Append is present, Condition can be omitted */
+               if (!has_condition && (*prepend == NULL && *append == NULL)) {
+                       snd_error(UCM, "condition block expected (If)");
+                       return -EINVAL;
+               }
+       } else {
+               if (!has_condition) {
+                       snd_error(UCM, "condition block expected (If)");
+                       return -EINVAL;
+               }
        }
 
        err = snd_config_search(cond, "True", &_true);
@@ -414,16 +443,22 @@ static int if_eval_one(snd_use_case_mgr_t *uc_mgr,
                return -EINVAL;
        }
 
-       err = if_eval(uc_mgr, expr);
-       if (err > 0) {
-               *result = _true;
-               return 0;
-       } else if (err == 0) {
-               *result = _false;
-               return 0;
-       } else {
-               return err;
+       /* Evaluate condition if present */
+       if (has_condition) {
+               err = if_eval(uc_mgr, expr);
+               if (err > 0) {
+                       *result = _true;
+                       return 0;
+               } else if (err == 0) {
+                       *result = _false;
+                       return 0;
+               } else {
+                       return err;
+               }
        }
+
+       /* If no condition (v8+ with Prepend/Append only), no result block */
+       return 0;
 }
 
 #if 0
@@ -445,7 +480,7 @@ int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
                              snd_config_t *cond)
 {
        snd_config_iterator_t i, next;
-       snd_config_t *a, *n, *before, *after;
+       snd_config_t *a, *n, *before, *after, *prepend, *append;
        int err;
 
        if (uc_mgr->conf_format < 2) {
@@ -460,19 +495,43 @@ int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
 
        snd_config_for_each(i, next, cond) {
                n = snd_config_iterator_entry(i);
-               before = after = NULL;
-               err = if_eval_one(uc_mgr, n, &a, &before, &after);
-               if (err < 0)
-                       return err;
-               if (a == NULL)
-                       continue;
-               err = uc_mgr_evaluate_inplace(uc_mgr, a);
-               if (err < 0)
-                       return err;
-               err = uc_mgr_config_tree_merge(uc_mgr, parent, a, before, after);
+               before = after = prepend = append = NULL;
+               err = if_eval_one(uc_mgr, n, &a, &before, &after, &prepend, &append);
                if (err < 0)
                        return err;
-               snd_config_delete(a);
+
+               /* For v8+: Handle Prepend block - prepend to parent before result */
+               if (prepend != NULL) {
+                       err = uc_mgr_evaluate_inplace(uc_mgr, prepend);
+                       if (err < 0)
+                               return err;
+                       err = uc_mgr_config_tree_merge(uc_mgr, parent, prepend, before, after);
+                       if (err < 0)
+                               return err;
+                       snd_config_delete(prepend);
+               }
+
+               /* Merge the condition result (True or False block) */
+               if (a != NULL) {
+                       err = uc_mgr_evaluate_inplace(uc_mgr, a);
+                       if (err < 0)
+                               return err;
+                       err = uc_mgr_config_tree_merge(uc_mgr, parent, a, before, after);
+                       if (err < 0)
+                               return err;
+                       snd_config_delete(a);
+               }
+
+               /* For v8+: Handle Append block - append to parent after result */
+               if (append != NULL) {
+                       err = uc_mgr_evaluate_inplace(uc_mgr, append);
+                       if (err < 0)
+                               return err;
+                       err = uc_mgr_config_tree_merge(uc_mgr, parent, append, before, after);
+                       if (err < 0)
+                               return err;
+                       snd_config_delete(append);
+               }
        }
        return 0;
 }
index e6c0a09128a52e549a3e2f858876ab7846f47053..924f640d9543b232a29b7338542b555a519f2415 100644 (file)
@@ -550,6 +550,14 @@ must define a *Condition* block and *True* or *False* blocks or both. The *True*
 blocks will be merged to the parent tree (where the *If* block is defined) when
 the *Condition* is evaluated.
 
+Starting with *Syntax* version *8*, *If* blocks can also include *Prepend* and *Append*
+configuration blocks. These blocks are always merged to the parent tree, independent of the
+condition evaluation result:
+- *Prepend* block is merged before the condition result (*True* or *False* block)
+- *Append* block is merged after the condition result (*True* or *False* block)
+- Both *Prepend* and *Append* can be specified simultaneously
+- When *Prepend* or *Append* is present, the *Condition* directive can be omitted
+
 Example:
 
 ~~~{.html}
@@ -566,6 +574,38 @@ If.uniqueid {
 }
 ~~~
 
+Example with Prepend and Append (*Syntax* version *8*+):
+
+~~~{.html}
+If.setup {
+  Prepend {
+    Define.before "prepended"
+  }
+  Condition {
+    Type AlwaysTrue
+  }
+  True {
+    Define.middle "conditional"
+  }
+  Append {
+    Define.after "appended"
+  }
+}
+~~~
+
+Example with Prepend/Append only (no Condition, *Syntax* version *8*+):
+
+~~~{.html}
+If.common {
+  Prepend {
+    Define.x "always executed"
+  }
+  Append {
+    Define.y "also always executed"
+  }
+}
+~~~
+
 #### True (Type AlwaysTrue)
 
 Execute only *True* block. It may be used to change the evaluation order as