<commit_before>/*
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  Support for the verb/device/modifier core logic and API,
 *  command line tool and file parser was kindly sponsored by
 *  Texas Instruments Inc.
 *  Support for multiple active modifiers and devices,
 *  transition sequences, multiple client access and user defined use
 *  cases was kindly sponsored by Wolfson Microelectronics PLC.
 *
 *  Copyright (C) 2008-2010 SlimLogic Ltd
 *  Copyright (C) 2010 Wolfson Microelectronics PLC
 *  Copyright (C) 2010 Texas Instruments Inc.
 *  Copyright (C) 2010 Red Hat Inc.
 *  Authors: <NAME> <<EMAIL>>
 *	         <NAME> <<EMAIL>>
 *	         <NAME> <<EMAIL>>
 *               <NAME> <<EMAIL>>
 */

#include "ucm_local.h"
#include <stdarg.h>
#include <pthread.h>

/*
 * misc
 */

static int get_value1(const char **value, struct list_head *value_list,
                      const char *identifier);
static int get_value3(const char **value,
		      const char *identifier,
		      struct list_head *value_list1,
		      struct list_head *value_list2,
		      struct list_head *value_list3);

static int check_identifier(const char *identifier, const char *prefix)
{
	int len;

	if (strcmp(identifier, prefix) == 0)
		return 1;
	len = strlen(prefix);
	if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
		return 1;
	return 0;
}

static int list_count(struct list_head *list)
{
        struct list_head *pos;
        int count = 0;
        
        list_for_each(pos, list) {
                count += 1;
        }
        return count;
}

static int alloc_str_list(struct list_head *list, int mult, char **result[])
{
        char **res;
        int cnt;
        
        cnt = list_count(list) * mult;
        if (cnt == 0)
                return cnt;
        res = calloc(mult, cnt * sizeof(char *));
        if (res == NULL)
                return -ENOMEM;
        *result = res;
        return cnt;
}

/**
 * \brief Create an identifier
 * \param fmt Format (sprintf like)
 * \param ... Optional arguments for sprintf like format
 * \return Allocated string identifier or NULL on error
 */
char *snd_use_case_identifier(const char *fmt, ...)
{
	char *str, *res;
	int size = strlen(fmt) + 512;
	va_list args;

	str = malloc(size);
	if (str == NULL)
		return NULL;
	va_start(args, fmt);
	vsnprintf(str, size, fmt, args);
	va_end(args);
	str[size-1] = '\0';
	res = realloc(str, strlen(str) + 1);
	if (res)
		return res;
	return str;
}

/**
 * \brief Free a string list
 * \param list The string list to free
 * \param items Count of strings
 * \return Zero if success, otherwise a negative error code
 */
int snd_use_case_free_list(const char *list[], int items)
{
        int i;
	if (list == NULL)
		return 0;
        for (i = 0; i < items; i++)
		free((void *)list[i]);
        free(list);
	return 0;
}

static int open_ctl(snd_use_case_mgr_t *uc_mgr,
		    snd_ctl_t **ctl,
		    const char *ctl_dev)
{
	int err;

	/* FIXME: add a list of ctl devices to uc_mgr structure and
           cache accesses for multiple opened ctl devices */
	if (uc_mgr->ctl_dev != NULL && strcmp(ctl_dev, uc_mgr->ctl_dev) == 0) {
		*ctl = uc_mgr->ctl;
		return 0;
	}
	if (uc_mgr->ctl_dev) {
		free(uc_mgr->ctl_dev);
		uc_mgr->ctl_dev = NULL;
		snd_ctl_close(uc_mgr->ctl);
	
	}
	err = snd_ctl_open(ctl, ctl_dev, 0);
	if (err < 0)
		return err;
	uc_mgr->ctl_dev = strdup(ctl_dev);
	if (uc_mgr->ctl_dev == NULL) {
		snd_ctl_close(*ctl);
		return -ENOMEM;
	}
	uc_mgr->ctl = *ctl;
	return 0;
}

static int execute_cset(snd_ctl_t *ctl, char *cset)
{
	char *pos;
	int err;
	snd_ctl_elem_id_t *id;
	snd_ctl_elem_value_t *value;
	snd_ctl_elem_info_t *info;

	snd_ctl_elem_id_malloc(&id);
	snd_ctl_elem_value_malloc(&value);
	snd_ctl_elem_info_malloc(&info);

	pos = strchr(cset, ' ');
	if (pos == NULL) {
		uc_error("undefined value for cset >%s<", cset);
		return -EINVAL;
	}
	*pos = '\0';
	err = snd_ctl_ascii_elem_id_parse(id, cset);
	if (err < 0)
		goto __fail;
	snd_ctl_elem_value_set_id(value, id);
	snd_ctl_elem_info_set_id(info, id);
	err = snd_ctl_elem_read(ctl, value);<commit_msg>ucm: fix handling of cset with spaces in the control name<commit_after>/*
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  Support for the verb/device/modifier core logic and API,
 *  command line tool and file parser was kindly sponsored by
 *  Texas Instruments Inc.
 *  Support for multiple active modifiers and devices,
 *  transition sequences, multiple client access and user defined use
 *  cases was kindly sponsored by Wolfson Microelectronics PLC.
 *
 *  Copyright (C) 2008-2010 SlimLogic Ltd
 *  Copyright (C) 2010 Wolfson Microelectronics PLC
 *  Copyright (C) 2010 Texas Instruments Inc.
 *  Copyright (C) 2010 Red Hat Inc.
 *  Authors: <NAME> <<EMAIL>>
 *	         <NAME> <<EMAIL>>
 *	         <NAME> <<EMAIL>>
 *               <NAME> <<EMAIL>>
 */

#include "ucm_local.h"
#include <stdarg.h>
#include <pthread.h>

/*
 * misc
 */

static int get_value1(const char **value, struct list_head *value_list,
                      const char *identifier);
static int get_value3(const char **value,
		      const char *identifier,
		      struct list_head *value_list1,
		      struct list_head *value_list2,
		      struct list_head *value_list3);

static int check_identifier(const char *identifier, const char *prefix)
{
	int len;

	if (strcmp(identifier, prefix) == 0)
		return 1;
	len = strlen(prefix);
	if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
		return 1;
	return 0;
}

static int list_count(struct list_head *list)
{
        struct list_head *pos;
        int count = 0;
        
        list_for_each(pos, list) {
                count += 1;
        }
        return count;
}

static int alloc_str_list(struct list_head *list, int mult, char **result[])
{
        char **res;
        int cnt;
        
        cnt = list_count(list) * mult;
        if (cnt == 0)
                return cnt;
        res = calloc(mult, cnt * sizeof(char *));
        if (res == NULL)
                return -ENOMEM;
        *result = res;
        return cnt;
}

/**
 * \brief Create an identifier
 * \param fmt Format (sprintf like)
 * \param ... Optional arguments for sprintf like format
 * \return Allocated string identifier or NULL on error
 */
char *snd_use_case_identifier(const char *fmt, ...)
{
	char *str, *res;
	int size = strlen(fmt) + 512;
	va_list args;

	str = malloc(size);
	if (str == NULL)
		return NULL;
	va_start(args, fmt);
	vsnprintf(str, size, fmt, args);
	va_end(args);
	str[size-1] = '\0';
	res = realloc(str, strlen(str) + 1);
	if (res)
		return res;
	return str;
}

/**
 * \brief Free a string list
 * \param list The string list to free
 * \param items Count of strings
 * \return Zero if success, otherwise a negative error code
 */
int snd_use_case_free_list(const char *list[], int items)
{
        int i;
	if (list == NULL)
		return 0;
        for (i = 0; i < items; i++)
		free((void *)list[i]);
        free(list);
	return 0;
}

static int open_ctl(snd_use_case_mgr_t *uc_mgr,
		    snd_ctl_t **ctl,
		    const char *ctl_dev)
{
	int err;

	/* FIXME: add a list of ctl devices to uc_mgr structure and
           cache accesses for multiple opened ctl devices */
	if (uc_mgr->ctl_dev != NULL && strcmp(ctl_dev, uc_mgr->ctl_dev) == 0) {
		*ctl = uc_mgr->ctl;
		return 0;
	}
	if (uc_mgr->ctl_dev) {
		free(uc_mgr->ctl_dev);
		uc_mgr->ctl_dev = NULL;
		snd_ctl_close(uc_mgr->ctl);
	
	}
	err = snd_ctl_open(ctl, ctl_dev, 0);
	if (err < 0)
		return err;
	uc_mgr->ctl_dev = strdup(ctl_dev);
	if (uc_mgr->ctl_dev == NULL) {
		snd_ctl_close(*ctl);
		return -ENOMEM;
	}
	uc_mgr->ctl = *ctl;
	return 0;
}

static int execute_cset(snd_ctl_t *ctl, char *cset)
{
	char *pos;
	int err;
	snd_ctl_elem_id_t *id;
	snd_ctl_elem_value_t *value;
	snd_ctl_elem_info_t *info;

	snd_ctl_elem_id_malloc(&id);
	snd_ctl_elem_value_malloc(&value);
	snd_ctl_elem_info_malloc(&info);

	pos = strrchr(cset, ' ');
	if (pos == NULL) {
		uc_error("undefined value for cset >%s<", cset);
		return -EINVAL;
	}
	*pos = '\0';
	err = snd_ctl_ascii_elem_id_parse(id, cset);
	if (err < 0)
		goto __fail;
	snd_ctl_elem_value_set_id(value, id);
	snd_ctl_elem_info_set_id(info, id);
	err = snd_ctl_elem_read(ctl, value);
{'fraction_non_alphanumeric': 0.11302901112613081, 'fraction_numerical': 0.013309763959654778, 'mean_word_length': 3.0633713561470217, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '454533', 'n_tokens_mistral': 3457, 'n_tokens_neox': 3290, 'n_words': 1079}