Blame src/ucm/ucm_cond.c

Packit 4a16fb
/*
Packit 4a16fb
 *  This library is free software; you can redistribute it and/or
Packit 4a16fb
 *  modify it under the terms of the GNU Lesser General Public
Packit 4a16fb
 *  License as published by the Free Software Foundation; either
Packit 4a16fb
 *  version 2 of the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *  This library is distributed in the hope that it will be useful,
Packit 4a16fb
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4a16fb
 *  Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *  You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *  License along with this library; if not, write to the Free Software
Packit 4a16fb
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 *
Packit 4a16fb
 *  Support for the verb/device/modifier core logic and API,
Packit 4a16fb
 *  command line tool and file parser was kindly sponsored by
Packit 4a16fb
 *  Texas Instruments Inc.
Packit 4a16fb
 *  Support for multiple active modifiers and devices,
Packit 4a16fb
 *  transition sequences, multiple client access and user defined use
Packit 4a16fb
 *  cases was kindly sponsored by Wolfson Microelectronics PLC.
Packit 4a16fb
 *
Packit 4a16fb
 *  Copyright (C) 2019 Red Hat Inc.
Packit 4a16fb
 *  Authors: Jaroslav Kysela <perex@perex.cz>
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
#include "ucm_local.h"
Packit 4a16fb
#include <regex.h>
Packit 4a16fb
Packit 4a16fb
static int get_string(snd_config_t *compound, const char *key, const char **str)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_t *node;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	err = snd_config_search(compound, key, &node);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	return snd_config_get_string(node, str);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int if_eval_string(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
Packit 4a16fb
{
Packit 4a16fb
	const char *string1 = NULL, *string2 = NULL;
Packit 4a16fb
	char *s1, *s2;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "String1", &string1);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("String error (If.Condition.String1)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "String2", &string2);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("String error (If.Condition.String2)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (string1 || string2) {
Packit 4a16fb
		if (string1 == NULL) {
Packit 4a16fb
			uc_error("If.Condition.String1 not defined");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		if (string2 == NULL) {
Packit 4a16fb
			uc_error("If.Condition.String2 not defined");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		err = uc_mgr_get_substituted_value(uc_mgr, &s2, string2);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			free(s1);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
		err = strcasecmp(s1, s2) == 0;
Packit 4a16fb
		free(s2);
Packit 4a16fb
		free(s1);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "Haystack", &string1);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("String error (If.Condition.Haystack)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "Needle", &string2);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("String error (If.Condition.Needle)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (string1 || string2) {
Packit 4a16fb
		if (string1 == NULL) {
Packit 4a16fb
			uc_error("If.Condition.Haystack not defined");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		if (string2 == NULL) {
Packit 4a16fb
			uc_error("If.Condition.Needle not defined");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
		err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		err = uc_mgr_get_substituted_value(uc_mgr, &s2, string2);
Packit 4a16fb
		if (err < 0) {
Packit 4a16fb
			free(s1);
Packit 4a16fb
			return err;
Packit 4a16fb
		}
Packit 4a16fb
		err = strstr(s1, s2) != NULL;
Packit 4a16fb
		free(s2);
Packit 4a16fb
		free(s1);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	uc_error("Unknown String condition arguments");
Packit 4a16fb
	return -EINVAL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int if_eval_regex_match(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
Packit 4a16fb
{
Packit 4a16fb
	const char *string, *regex_string;
Packit 4a16fb
	char *s;
Packit 4a16fb
	regex_t re;
Packit 4a16fb
	int options = REG_EXTENDED | REG_ICASE;
Packit 4a16fb
	regmatch_t match[1];
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "String", &string);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		uc_error("RegexMatch error (If.Condition.String)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "Regex", &regex_string);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		uc_error("RegexMatch error (If.Condition.Regex)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = uc_mgr_get_substituted_value(uc_mgr, &s, regex_string);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = regcomp(&re, s, options);
Packit 4a16fb
	free(s);
Packit 4a16fb
	if (err) {
Packit 4a16fb
		uc_error("Regex '%s' compilation failed (code %d)", err);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = uc_mgr_get_substituted_value(uc_mgr, &s, string);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		regfree(&re);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	err = regexec(&re, s, ARRAY_SIZE(match), match, 0);
Packit 4a16fb
	free(s);
Packit 4a16fb
	regfree(&re);
Packit 4a16fb
	return err == 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int if_eval_control_exists(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
Packit 4a16fb
{
Packit 4a16fb
	snd_ctl_t *ctl;
Packit 4a16fb
	const char *device = NULL, *ctldef, *enumval = NULL, *name;
Packit 4a16fb
	snd_ctl_elem_id_t *elem_id;
Packit 4a16fb
	snd_ctl_elem_info_t *elem_info;
Packit 4a16fb
	snd_ctl_elem_type_t type;
Packit 4a16fb
	char *s;
Packit 4a16fb
	int err, i, items;
Packit 4a16fb
Packit 4a16fb
	snd_ctl_elem_id_alloca(&elem_id);
Packit 4a16fb
	snd_ctl_elem_info_alloca(&elem_info);
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "Device", &device);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("ControlExists error (If.Condition.Device)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "Control", &ctldef);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		uc_error("ControlExists error (If.Condition.Control)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "ControlEnum", &enumval);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("ControlExists error (If.Condition.ControlEnum)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = uc_mgr_get_substituted_value(uc_mgr, &s, ctldef);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	err = snd_ctl_ascii_elem_id_parse(elem_id, s);
Packit 4a16fb
	free(s);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		uc_error("unable to parse element identificator (%s)", ctldef);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (device == NULL) {
Packit 4a16fb
		ctl = uc_mgr_get_ctl(uc_mgr);
Packit 4a16fb
		if (ctl == NULL) {
Packit 4a16fb
			uc_error("cannot determine control device");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
	} else {
Packit 4a16fb
		err = uc_mgr_get_substituted_value(uc_mgr, &s, device);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		err = uc_mgr_open_ctl(uc_mgr, &ctl, s);
Packit 4a16fb
		free(s);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	snd_ctl_elem_info_set_id(elem_info, elem_id);
Packit 4a16fb
	err = snd_ctl_elem_info(ctl, elem_info);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return 0;
Packit 4a16fb
Packit 4a16fb
	if (enumval) {
Packit 4a16fb
		type = snd_ctl_elem_info_get_type(elem_info);
Packit 4a16fb
		if (type != SND_CTL_ELEM_TYPE_ENUMERATED)
Packit 4a16fb
			return 0;
Packit 4a16fb
		err = uc_mgr_get_substituted_value(uc_mgr, &s, enumval);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		items = snd_ctl_elem_info_get_items(elem_info);
Packit 4a16fb
		for (i = 0; i < items; i++) {
Packit 4a16fb
			snd_ctl_elem_info_set_item(elem_info, i);
Packit 4a16fb
			err = snd_ctl_elem_info(ctl, elem_info);
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
				free(s);
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			name = snd_ctl_elem_info_get_item_name(elem_info);
Packit 4a16fb
			if (strcasecmp(name, s) == 0) {
Packit 4a16fb
				free(s);
Packit 4a16fb
				return 1;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
		free(s);
Packit 4a16fb
		return 0;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 1;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int if_eval(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
Packit 4a16fb
{
Packit 4a16fb
	const char *type;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (snd_config_get_type(eval) != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		uc_error("compound type expected for If.Condition");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = get_string(eval, "Type", &type);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		uc_error("type block error (If.Condition)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (strcmp(type, "ControlExists") == 0)
Packit 4a16fb
		return if_eval_control_exists(uc_mgr, eval);
Packit 4a16fb
Packit 4a16fb
	if (strcmp(type, "String") == 0)
Packit 4a16fb
		return if_eval_string(uc_mgr, eval);
Packit 4a16fb
Packit 4a16fb
	if (strcmp(type, "RegexMatch") == 0)
Packit 4a16fb
		return if_eval_regex_match(uc_mgr, eval);
Packit 4a16fb
Packit 4a16fb
	uc_error("unknown If.Condition.Type");
Packit 4a16fb
	return -EINVAL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int if_eval_one(snd_use_case_mgr_t *uc_mgr,
Packit 4a16fb
		       snd_config_t *cond,
Packit 4a16fb
		       snd_config_t **result,
Packit 4a16fb
		       snd_config_t **before,
Packit 4a16fb
		       snd_config_t **after)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_t *expr, *_true = NULL, *_false = NULL;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	*result = NULL;
Packit 4a16fb
Packit 4a16fb
	if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		uc_error("compound type expected for If.1");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (snd_config_search(cond, "Condition", &expr) < 0) {
Packit 4a16fb
		uc_error("condition block expected (If)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = snd_config_search(cond, "True", &_true);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("true block error (If)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = snd_config_search(cond, "False", &_false);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("false block error (If)");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = snd_config_search(cond, "Before", before);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("before block identifier error");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = snd_config_search(cond, "After", after);
Packit 4a16fb
	if (err < 0 && err != -ENOENT) {
Packit 4a16fb
		uc_error("before block identifier error");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	err = if_eval(uc_mgr, expr);
Packit 4a16fb
	if (err > 0) {
Packit 4a16fb
		*result = _true;
Packit 4a16fb
		return 0;
Packit 4a16fb
	} else if (err == 0) {
Packit 4a16fb
		*result = _false;
Packit 4a16fb
		return 0;
Packit 4a16fb
	} else {
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
#if 0
Packit 4a16fb
static void config_dump(snd_config_t *cfg)
Packit 4a16fb
{
Packit 4a16fb
	snd_output_t *out;
Packit 4a16fb
	snd_output_stdio_attach(&out, stderr, 0);
Packit 4a16fb
	snd_output_printf(out, "-----\n");
Packit 4a16fb
	snd_config_save(cfg, out);
Packit 4a16fb
	snd_output_close(out);
Packit 4a16fb
}
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
static int compound_merge(const char *id,
Packit 4a16fb
			  snd_config_t *dst, snd_config_t *src,
Packit 4a16fb
			  snd_config_t *before, snd_config_t *after)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n, *_before = NULL, *_after = NULL;
Packit 4a16fb
	const char *s;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		uc_error("compound type expected for If True/False block");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (before) {
Packit 4a16fb
		err = get_string(before, id, &s);
Packit 4a16fb
		if (err < 0 && err != -ENOENT)
Packit 4a16fb
			return err;
Packit 4a16fb
		if (err == 0) {
Packit 4a16fb
			err = snd_config_search(dst, s, &_before);
Packit 4a16fb
			if (err < 0 && err != -ENOENT)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (after) {
Packit 4a16fb
		err = get_string(after, id, &s);
Packit 4a16fb
		if (err < 0 && err != -ENOENT)
Packit 4a16fb
			return err;
Packit 4a16fb
		if (err == 0) {
Packit 4a16fb
			err = snd_config_search(dst, s, &_after);
Packit 4a16fb
			if (err < 0 && err != -ENOENT)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (_before && _after) {
Packit 4a16fb
		uc_error("defined both before and after identifiers in the If block");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, src) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		err = snd_config_remove(n);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		if (_before) {
Packit 4a16fb
			err = snd_config_add_before(_before, n);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			_before = NULL;
Packit 4a16fb
			_after = n;
Packit 4a16fb
		} else if (_after) {
Packit 4a16fb
			err = snd_config_add_after(_after, n);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			_after = n;
Packit 4a16fb
		} else {
Packit 4a16fb
			err = snd_config_add(dst, n);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * put back the result from all conditions to the parent
Packit 4a16fb
 */
Packit 4a16fb
int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
Packit 4a16fb
			      snd_config_t *parent,
Packit 4a16fb
			      snd_config_t *cond)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, i2, next, next2;
Packit 4a16fb
	snd_config_t *a, *n, *n2, *parent2, *before, *after;
Packit 4a16fb
	const char *id;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (uc_mgr->conf_format < 2) {
Packit 4a16fb
		uc_error("conditions are not supported for v1 syntax");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		uc_error("compound type expected for If");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cond) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		before = after = NULL;
Packit 4a16fb
		err = if_eval_one(uc_mgr, n, &a, &before, &after);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		if (a == NULL)
Packit 4a16fb
			continue;
Packit 4a16fb
		err = snd_config_search(a, "If", &n2;;
Packit 4a16fb
		if (err < 0 && err != -ENOENT) {
Packit 4a16fb
			uc_error("If block error (If)");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		} else if (err == 0) {
Packit 4a16fb
			err = uc_mgr_evaluate_condition(uc_mgr, a, n2);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			snd_config_delete(n2);
Packit 4a16fb
		}
Packit 4a16fb
		snd_config_for_each(i2, next2, a) {
Packit 4a16fb
			n2 = snd_config_iterator_entry(i2);
Packit 4a16fb
			err = snd_config_remove(n2);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			err = snd_config_get_id(n2, &id;;
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
__add:
Packit 4a16fb
				err = snd_config_add(parent, n2);
Packit 4a16fb
				if (err < 0)
Packit 4a16fb
					return err;
Packit 4a16fb
				continue;
Packit 4a16fb
			} else {
Packit 4a16fb
				err = snd_config_search(parent, id, &parent2);
Packit 4a16fb
				if (err == -ENOENT)
Packit 4a16fb
					goto __add;
Packit 4a16fb
				err = compound_merge(id, parent2, n2, before, after);
Packit 4a16fb
				if (err < 0)
Packit 4a16fb
					return err;
Packit 4a16fb
			}
Packit 4a16fb
			snd_config_delete(n2);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}