Blame src/topology/save.c

Packit Service f36a15
/*
Packit Service f36a15
  Copyright(c) 2019 Red Hat Inc.
Packit Service f36a15
  All rights reserved.
Packit Service f36a15
Packit Service f36a15
  This library is free software; you can redistribute it and/or modify
Packit Service f36a15
  it under the terms of the GNU Lesser General Public License as
Packit Service f36a15
  published by the Free Software Foundation; either version 2.1 of
Packit Service f36a15
  the License, or (at your option) any later version.
Packit Service f36a15
Packit Service f36a15
  This program is distributed in the hope that it will be useful,
Packit Service f36a15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f36a15
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f36a15
  GNU Lesser General Public License for more details.
Packit Service f36a15
Packit Service f36a15
  Authors: Jaroslav Kysela <perex@perex.cz>
Packit Service f36a15
*/
Packit Service f36a15
Packit Service f36a15
#include "list.h"
Packit Service f36a15
#include "tplg_local.h"
Packit Service f36a15
Packit Service f36a15
#define SAVE_ALLOC_SHIFT	(13)	/* 8192 bytes */
Packit Service f36a15
Packit Service f36a15
int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...)
Packit Service f36a15
{
Packit Service f36a15
	va_list va;
Packit Service f36a15
	char buf[1024], *s;
Packit Service f36a15
	size_t n, l, t, pl;
Packit Service f36a15
Packit Service f36a15
	if (pfx == NULL)
Packit Service f36a15
		pfx = "";
Packit Service f36a15
Packit Service f36a15
	va_start(va, fmt);
Packit Service f36a15
	n = vsnprintf(buf, sizeof(buf), fmt, va);
Packit Service f36a15
	va_end(va);
Packit Service f36a15
Packit Service f36a15
	if (n >= sizeof(buf))
Packit Service f36a15
		return -EOVERFLOW;
Packit Service f36a15
Packit Service f36a15
	pl = strlen(pfx);
Packit Service f36a15
	l = *dst ? strlen(*dst) : 0;
Packit Service f36a15
	t = l + pl + n + 1;
Packit Service f36a15
	/* allocate chunks */
Packit Service f36a15
	if (*dst == NULL ||
Packit Service f36a15
	    (l >> SAVE_ALLOC_SHIFT) != (t >> SAVE_ALLOC_SHIFT)) {
Packit Service f36a15
		s = realloc(*dst, ((t >> SAVE_ALLOC_SHIFT) + 1) <<
Packit Service f36a15
							SAVE_ALLOC_SHIFT);
Packit Service f36a15
		if (s == NULL) {
Packit Service f36a15
			free(*dst);
Packit Service f36a15
			*dst = NULL;
Packit Service f36a15
			return -ENOMEM;
Packit Service f36a15
		}
Packit Service f36a15
	} else {
Packit Service f36a15
		s = *dst;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	if (pl > 0)
Packit Service f36a15
		strcpy(s + l, pfx);
Packit Service f36a15
	strcpy(s + l + pl, buf);
Packit Service f36a15
	*dst = s;
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value)
Packit Service f36a15
{
Packit Service f36a15
	if ((value % 1000) != 0) {
Packit Service f36a15
		if (value > 0xfffffff0)
Packit Service f36a15
			return snprintf(dst, dst_size, "%d", (int)value);
Packit Service f36a15
		if (value >= 0xffff0000)
Packit Service f36a15
			return snprintf(dst, dst_size, "0x%x", value);
Packit Service f36a15
	}
Packit Service f36a15
	return snprintf(dst, dst_size, "%u", value);
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_pprint_integer(snd_config_t *n, char **ret)
Packit Service f36a15
{
Packit Service f36a15
	long lval;
Packit Service f36a15
	int err, type;
Packit Service f36a15
	char buf[16];
Packit Service f36a15
Packit Service f36a15
	type = snd_config_get_type(n);
Packit Service f36a15
	if (type == SND_CONFIG_TYPE_INTEGER) {
Packit Service f36a15
		err = snd_config_get_integer(n, &lval);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		if (lval < INT_MIN || lval > UINT_MAX)
Packit Service f36a15
			return snd_config_get_ascii(n, ret);
Packit Service f36a15
	} else if (type == SND_CONFIG_TYPE_INTEGER64) {
Packit Service f36a15
		long long llval;
Packit Service f36a15
		err = snd_config_get_integer64(n, &llval);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		if (llval < INT_MIN || llval > UINT_MAX)
Packit Service f36a15
			return snd_config_get_ascii(n, ret);
Packit Service f36a15
		lval = llval;
Packit Service f36a15
	}
Packit Service f36a15
	err = tplg_nice_value_format(buf, sizeof(buf), (unsigned int)lval);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
	*ret = strdup(buf);
Packit Service f36a15
	if (*ret == NULL)
Packit Service f36a15
		return -ENOMEM;
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int _compar(const void *a, const void *b)
Packit Service f36a15
{
Packit Service f36a15
	const snd_config_t *c1 = *(snd_config_t **)a;
Packit Service f36a15
	const snd_config_t *c2 = *(snd_config_t **)b;
Packit Service f36a15
	const char *id1, *id2;
Packit Service f36a15
	if (snd_config_get_id(c1, &id1)) return 0;
Packit Service f36a15
	if (snd_config_get_id(c2, &id2)) return 0;
Packit Service f36a15
	return strcmp(id1, id2);
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static snd_config_t *sort_config(const char *id, snd_config_t *src)
Packit Service f36a15
{
Packit Service f36a15
	snd_config_t *dst, **a;
Packit Service f36a15
	snd_config_iterator_t i, next;
Packit Service f36a15
	int index, array, count;
Packit Service f36a15
Packit Service f36a15
	if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) {
Packit Service f36a15
Packit Service f36a15
		if (snd_config_copy(&dst, src) >= 0)
Packit Service f36a15
			return dst;
Packit Service f36a15
		return NULL;
Packit Service f36a15
	}
Packit Service f36a15
	count = 0;
Packit Service f36a15
	snd_config_for_each(i, next, src)
Packit Service f36a15
		count++;
Packit Service f36a15
	a = malloc(sizeof(dst) * count);
Packit Service f36a15
	if (a == NULL)
Packit Service f36a15
		return NULL;
Packit Service f36a15
	array = snd_config_is_array(src);
Packit Service f36a15
	if (array <= 0) {
Packit Service f36a15
		index = 0;
Packit Service f36a15
		snd_config_for_each(i, next, src) {
Packit Service f36a15
			snd_config_t *s = snd_config_iterator_entry(i);
Packit Service f36a15
			a[index++] = s;
Packit Service f36a15
		}
Packit Service f36a15
		qsort(a, count, sizeof(a[0]), _compar);
Packit Service f36a15
	}
Packit Service f36a15
	if (snd_config_make_compound(&dst, id, count == 1)) {
Packit Service f36a15
		free(a);
Packit Service f36a15
		return NULL;
Packit Service f36a15
	}
Packit Service f36a15
	for (index = 0; index < count; index++) {
Packit Service f36a15
		snd_config_t *s = a[index];
Packit Service f36a15
		const char *id2;
Packit Service f36a15
		if (snd_config_get_id(s, &id2)) {
Packit Service f36a15
			snd_config_delete(dst);
Packit Service f36a15
			free(a);
Packit Service f36a15
			return NULL;
Packit Service f36a15
		}
Packit Service f36a15
		s = sort_config(id2, s);
Packit Service f36a15
		if (s == NULL || snd_config_add(dst, s)) {
Packit Service f36a15
			if (s)
Packit Service f36a15
				snd_config_delete(s);
Packit Service f36a15
			snd_config_delete(dst);
Packit Service f36a15
			free(a);
Packit Service f36a15
			return NULL;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
	free(a);
Packit Service f36a15
	return dst;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_check_quoted(const unsigned char *p)
Packit Service f36a15
{
Packit Service f36a15
	for ( ; *p != '\0'; p++) {
Packit Service f36a15
		switch (*p) {
Packit Service f36a15
		case ' ':
Packit Service f36a15
		case '=':
Packit Service f36a15
		case ';':
Packit Service f36a15
		case ',':
Packit Service f36a15
		case '.':
Packit Service f36a15
		case '{':
Packit Service f36a15
		case '}':
Packit Service f36a15
		case '\'':
Packit Service f36a15
		case '"':
Packit Service f36a15
			return 1;
Packit Service f36a15
		default:
Packit Service f36a15
			if (*p <= 31 || *p >= 127)
Packit Service f36a15
				return 1;
Packit Service f36a15
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_save_quoted(char **dst, const char *str)
Packit Service f36a15
{
Packit Service f36a15
	static const char nibble[16] = "0123456789abcdef";
Packit Service f36a15
	unsigned char *p, *d, *t;
Packit Service f36a15
	int c;
Packit Service f36a15
Packit Service f36a15
	d = t = alloca(strlen(str) * 5 + 1 + 1);
Packit Service f36a15
	for (p = (unsigned char *)str; *p != '\0'; p++) {
Packit Service f36a15
		c = *p;
Packit Service f36a15
		switch (c) {
Packit Service f36a15
		case '\n':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = 'n';
Packit Service f36a15
			break;
Packit Service f36a15
		case '\t':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = 't';
Packit Service f36a15
			break;
Packit Service f36a15
		case '\v':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = 'v';
Packit Service f36a15
			break;
Packit Service f36a15
		case '\b':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = 'b';
Packit Service f36a15
			break;
Packit Service f36a15
		case '\r':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = 'r';
Packit Service f36a15
			break;
Packit Service f36a15
		case '\f':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = 'f';
Packit Service f36a15
			break;
Packit Service f36a15
		case '\'':
Packit Service f36a15
			*t++ = '\\';
Packit Service f36a15
			*t++ = c;
Packit Service f36a15
			break;
Packit Service f36a15
		default:
Packit Service f36a15
			if (c >= 32 && c <= 126) {
Packit Service f36a15
				*t++ = c;
Packit Service f36a15
			} else {
Packit Service f36a15
				*t++ = '\\';
Packit Service f36a15
				*t++ = 'x';
Packit Service f36a15
				*t++ = nibble[(c >> 4) & 0x0f];
Packit Service f36a15
				*t++ = nibble[(c >> 0) & 0x0f];
Packit Service f36a15
			}
Packit Service f36a15
			break;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
	*t = '\0';
Packit Service f36a15
	return tplg_save_printf(dst, NULL, "'%s'", d);
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_save_string(char **dst, const char *str, int id)
Packit Service f36a15
{
Packit Service f36a15
	const unsigned char *p = (const unsigned char *)str;
Packit Service f36a15
Packit Service f36a15
	if (!p || !*p)
Packit Service f36a15
		return tplg_save_printf(dst, NULL, "''");
Packit Service f36a15
Packit Service f36a15
	if (!id && ((*p >= '0' && *p <= '9') || *p == '-'))
Packit Service f36a15
		return tplg_save_quoted(dst, str);
Packit Service f36a15
Packit Service f36a15
	if (tplg_check_quoted(p))
Packit Service f36a15
		return tplg_save_quoted(dst, str);
Packit Service f36a15
Packit Service f36a15
	return tplg_save_printf(dst, NULL, "%s", str);
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int save_config(char **dst, int level, const char *delim, snd_config_t *src)
Packit Service f36a15
{
Packit Service f36a15
	snd_config_iterator_t i, next;
Packit Service f36a15
	snd_config_t *s;
Packit Service f36a15
	const char *id;
Packit Service f36a15
	char *pfx;
Packit Service f36a15
	unsigned int count;
Packit Service f36a15
	int type, err, quoted, array;
Packit Service f36a15
Packit Service f36a15
	if (delim == NULL)
Packit Service f36a15
		delim = "";
Packit Service f36a15
Packit Service f36a15
	type = snd_config_get_type(src);
Packit Service f36a15
	if (type != SND_CONFIG_TYPE_COMPOUND) {
Packit Service f36a15
		char *val;
Packit Service f36a15
		if (type == SND_CONFIG_TYPE_INTEGER ||
Packit Service f36a15
		    type == SND_CONFIG_TYPE_INTEGER64) {
Packit Service f36a15
			err = tplg_pprint_integer(src, &val;;
Packit Service f36a15
		} else {
Packit Service f36a15
			err = snd_config_get_ascii(src, &val;;
Packit Service f36a15
		}
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		if (type == SND_CONFIG_TYPE_STRING) {
Packit Service f36a15
			/* hexa array pretty print */
Packit Service f36a15
			id = strchr(val, '\n');
Packit Service f36a15
			if (id) {
Packit Service f36a15
				err = tplg_save_printf(dst, NULL, "\n");
Packit Service f36a15
				if (err < 0)
Packit Service f36a15
					goto retval;
Packit Service f36a15
				for (id++; *id == '\t'; id++) {
Packit Service f36a15
					err = tplg_save_printf(dst, NULL, "\t");
Packit Service f36a15
					if (err < 0)
Packit Service f36a15
						goto retval;
Packit Service f36a15
				}
Packit Service f36a15
				delim = "";
Packit Service f36a15
			}
Packit Service f36a15
			err = tplg_save_printf(dst, NULL, "%s'%s'\n", delim, val);
Packit Service f36a15
		} else {
Packit Service f36a15
			err = tplg_save_printf(dst, NULL, "%s%s\n", delim, val);
Packit Service f36a15
		}
Packit Service f36a15
retval:
Packit Service f36a15
		free(val);
Packit Service f36a15
		return err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	count = 0;
Packit Service f36a15
	quoted = 0;
Packit Service f36a15
	array = snd_config_is_array(src);
Packit Service f36a15
	s = NULL;
Packit Service f36a15
	snd_config_for_each(i, next, src) {
Packit Service f36a15
		s = snd_config_iterator_entry(i);
Packit Service f36a15
		err = snd_config_get_id(s, &id;;
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		if (!quoted && tplg_check_quoted((unsigned char *)id))
Packit Service f36a15
			quoted = 1;
Packit Service f36a15
		count++;
Packit Service f36a15
	}
Packit Service f36a15
	if (count == 0)
Packit Service f36a15
		return 0;
Packit Service f36a15
Packit Service f36a15
	if (count == 1) {
Packit Service f36a15
		err = snd_config_get_id(s, &id;;
Packit Service f36a15
		if (err >= 0 && level > 0)
Packit Service f36a15
			err = tplg_save_printf(dst, NULL, ".");
Packit Service f36a15
		if (err >= 0)
Packit Service f36a15
			err = tplg_save_string(dst, id, 1);
Packit Service f36a15
		if (err >= 0)
Packit Service f36a15
			err = save_config(dst, level, " ", s);
Packit Service f36a15
		return err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	pfx = alloca(level + 1);
Packit Service f36a15
	memset(pfx, '\t', level);
Packit Service f36a15
	pfx[level] = '\0';
Packit Service f36a15
Packit Service f36a15
	if (level > 0) {
Packit Service f36a15
		err = tplg_save_printf(dst, NULL, "%s%s\n", delim,
Packit Service f36a15
				       array > 0 ? "[" : "{");
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	snd_config_for_each(i, next, src) {
Packit Service f36a15
		s = snd_config_iterator_entry(i);
Packit Service f36a15
		const char *id;
Packit Service f36a15
		err = snd_config_get_id(s, &id;;
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "");
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		if (array <= 0) {
Packit Service f36a15
			delim = " ";
Packit Service f36a15
			if (quoted) {
Packit Service f36a15
				err = tplg_save_quoted(dst, id);
Packit Service f36a15
			} else {
Packit Service f36a15
				err = tplg_save_string(dst, id, 1);
Packit Service f36a15
				if (err < 0)
Packit Service f36a15
					return err;
Packit Service f36a15
			}
Packit Service f36a15
		} else {
Packit Service f36a15
			delim = "";
Packit Service f36a15
		}
Packit Service f36a15
		err = save_config(dst, level + 1, delim, s);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	if (level > 0) {
Packit Service f36a15
		pfx[level - 1] = '\0';
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "%s\n",
Packit Service f36a15
				       array > 0 ? "]" : "}");
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_save(snd_tplg_t *tplg, char **dst, int gindex, const char *prefix)
Packit Service f36a15
{
Packit Service f36a15
	struct tplg_table *tptr;
Packit Service f36a15
	struct tplg_elem *elem;
Packit Service f36a15
	struct list_head *list, *pos;
Packit Service f36a15
	char pfx2[16];
Packit Service f36a15
	unsigned int index;
Packit Service f36a15
	int err, count;
Packit Service f36a15
Packit Service f36a15
	snprintf(pfx2, sizeof(pfx2), "%s\t", prefix ?: "");
Packit Service f36a15
Packit Service f36a15
	/* write all blocks */
Packit Service f36a15
	for (index = 0; index < tplg_table_items; index++) {
Packit Service f36a15
		tptr = &tplg_table[index];
Packit Service f36a15
		list = (struct list_head *)((void *)tplg + tptr->loff);
Packit Service f36a15
Packit Service f36a15
		/* count elements */
Packit Service f36a15
		count = 0;
Packit Service f36a15
		list_for_each(pos, list) {
Packit Service f36a15
			elem = list_entry(pos, struct tplg_elem, list);
Packit Service f36a15
			if (gindex >= 0 && elem->index != gindex)
Packit Service f36a15
				continue;
Packit Service f36a15
			if (tptr->save == NULL && tptr->gsave == NULL) {
Packit Service f36a15
				SNDERR("unable to create %s block (no callback)",
Packit Service f36a15
				       tptr->id);
Packit Service f36a15
				err = -ENXIO;
Packit Service f36a15
				goto _err;
Packit Service f36a15
			}
Packit Service f36a15
			if (tptr->save)
Packit Service f36a15
				count++;
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		if (count == 0)
Packit Service f36a15
			continue;
Packit Service f36a15
Packit Service f36a15
		if (count > 1) {
Packit Service f36a15
			err = tplg_save_printf(dst, prefix, "%s {\n",
Packit Service f36a15
					       elem->table ?
Packit Service f36a15
						elem->table->id : "_NOID_");
Packit Service f36a15
		} else {
Packit Service f36a15
			err = tplg_save_printf(dst, prefix, "%s.",
Packit Service f36a15
					       elem->table ?
Packit Service f36a15
						elem->table->id : "_NOID_");
Packit Service f36a15
		}
Packit Service f36a15
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			goto _err;
Packit Service f36a15
Packit Service f36a15
		list_for_each(pos, list) {
Packit Service f36a15
			elem = list_entry(pos, struct tplg_elem, list);
Packit Service f36a15
			if (gindex >= 0 && elem->index != gindex)
Packit Service f36a15
				continue;
Packit Service f36a15
			if (count > 1) {
Packit Service f36a15
				err = tplg_save_printf(dst, pfx2, "");
Packit Service f36a15
				if (err < 0)
Packit Service f36a15
					goto _err;
Packit Service f36a15
			}
Packit Service f36a15
			err = tptr->save(tplg, elem, dst, count > 1 ? pfx2 : prefix);
Packit Service f36a15
			if (err < 0) {
Packit Service f36a15
				SNDERR("failed to save %s elements: %s",
Packit Service f36a15
				       tptr->id, snd_strerror(-err));
Packit Service f36a15
				goto _err;
Packit Service f36a15
			}
Packit Service f36a15
		}
Packit Service f36a15
		if (count > 1) {
Packit Service f36a15
			err = tplg_save_printf(dst, prefix, "}\n");
Packit Service f36a15
			if (err < 0)
Packit Service f36a15
				goto _err;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	/* save globals */
Packit Service f36a15
	for (index = 0; index < tplg_table_items; index++) {
Packit Service f36a15
		tptr = &tplg_table[index];
Packit Service f36a15
		if (tptr->gsave) {
Packit Service f36a15
			err = tptr->gsave(tplg, gindex, dst, prefix);
Packit Service f36a15
			if (err < 0)
Packit Service f36a15
				goto _err;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	return 0;
Packit Service f36a15
Packit Service f36a15
_err:
Packit Service f36a15
	free(*dst);
Packit Service f36a15
	*dst = NULL;
Packit Service f36a15
	return err;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_index_compar(const void *a, const void *b)
Packit Service f36a15
{
Packit Service f36a15
	const int *a1 = a, *b1 = b;
Packit Service f36a15
	return *a1 - *b1;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
static int tplg_index_groups(snd_tplg_t *tplg, int **indexes)
Packit Service f36a15
{
Packit Service f36a15
	struct tplg_table *tptr;
Packit Service f36a15
	struct tplg_elem *elem;
Packit Service f36a15
	struct list_head *list, *pos;
Packit Service f36a15
	unsigned int index, j, count, size;
Packit Service f36a15
	int *a, *b;
Packit Service f36a15
Packit Service f36a15
	count = 0;
Packit Service f36a15
	size = 16;
Packit Service f36a15
	a = malloc(size * sizeof(a[0]));
Packit Service f36a15
Packit Service f36a15
	for (index = 0; index < tplg_table_items; index++) {
Packit Service f36a15
		tptr = &tplg_table[index];
Packit Service f36a15
		list = (struct list_head *)((void *)tplg + tptr->loff);
Packit Service f36a15
		list_for_each(pos, list) {
Packit Service f36a15
			elem = list_entry(pos, struct tplg_elem, list);
Packit Service f36a15
			for (j = 0; j < count; j++) {
Packit Service f36a15
				if (a[j] == elem->index)
Packit Service f36a15
					break;
Packit Service f36a15
			}
Packit Service f36a15
			if (j < count)
Packit Service f36a15
				continue;
Packit Service f36a15
			if (count + 1 >= size) {
Packit Service f36a15
				size += 8;
Packit Service f36a15
				b = realloc(a, size * sizeof(a[0]));
Packit Service f36a15
				if (b == NULL) {
Packit Service f36a15
					free(a);
Packit Service f36a15
					return -ENOMEM;
Packit Service f36a15
				}
Packit Service f36a15
				a = b;
Packit Service f36a15
			}
Packit Service f36a15
			a[count++] = elem->index;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
	a[count] = -1;
Packit Service f36a15
Packit Service f36a15
	qsort(a, count, sizeof(a[0]), tplg_index_compar);
Packit Service f36a15
Packit Service f36a15
	*indexes = a;
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags)
Packit Service f36a15
{
Packit Service f36a15
	snd_input_t *in;
Packit Service f36a15
	snd_config_t *top, *top2;
Packit Service f36a15
	char *dst2;
Packit Service f36a15
	int *indexes, *a;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	assert(tplg);
Packit Service f36a15
	assert(dst);
Packit Service f36a15
	*dst = NULL;
Packit Service f36a15
Packit Service f36a15
	if (flags & SND_TPLG_SAVE_GROUPS) {
Packit Service f36a15
		err = tplg_index_groups(tplg, &indexes);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
		for (a = indexes; err >= 0 && *a >= 0; a++) {
Packit Service f36a15
			err = tplg_save_printf(dst, NULL,
Packit Service f36a15
					       "IndexGroup.%d {\n",
Packit Service f36a15
					       *a);
Packit Service f36a15
			if (err >= 0)
Packit Service f36a15
				err = tplg_save(tplg, dst, *a, "\t");
Packit Service f36a15
			if (err >= 0)
Packit Service f36a15
				err = tplg_save_printf(dst, NULL, "}\n");
Packit Service f36a15
		}
Packit Service f36a15
		free(indexes);
Packit Service f36a15
	} else {
Packit Service f36a15
		err = tplg_save(tplg, dst, -1, NULL);
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		goto _err;
Packit Service f36a15
Packit Service f36a15
	if (*dst == NULL)
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
Packit Service f36a15
	if (flags & SND_TPLG_SAVE_NOCHECK)
Packit Service f36a15
		return 0;
Packit Service f36a15
Packit Service f36a15
	/* always load configuration - check */
Packit Service f36a15
	err = snd_input_buffer_open(&in, *dst, strlen(*dst));
Packit Service f36a15
	if (err < 0) {
Packit Service f36a15
		SNDERR("could not create input buffer");
Packit Service f36a15
		goto _err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	err = snd_config_top(&top);
Packit Service f36a15
	if (err < 0) {
Packit Service f36a15
		snd_input_close(in);
Packit Service f36a15
		goto _err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	err = snd_config_load(top, in);
Packit Service f36a15
	snd_input_close(in);
Packit Service f36a15
	if (err < 0) {
Packit Service f36a15
		SNDERR("could not load configuration");
Packit Service f36a15
		snd_config_delete(top);
Packit Service f36a15
		goto _err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	if (flags & SND_TPLG_SAVE_SORT) {
Packit Service f36a15
		top2 = sort_config(NULL, top);
Packit Service f36a15
		if (top2 == NULL) {
Packit Service f36a15
			SNDERR("could not sort configuration");
Packit Service f36a15
			snd_config_delete(top);
Packit Service f36a15
			err = -EINVAL;
Packit Service f36a15
			goto _err;
Packit Service f36a15
		}
Packit Service f36a15
		snd_config_delete(top);
Packit Service f36a15
		top = top2;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	dst2 = NULL;
Packit Service f36a15
	err = save_config(&dst2, 0, NULL, top);
Packit Service f36a15
	snd_config_delete(top);
Packit Service f36a15
	if (err < 0) {
Packit Service f36a15
		SNDERR("could not save configuration");
Packit Service f36a15
		goto _err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	free(*dst);
Packit Service f36a15
	*dst = dst2;
Packit Service f36a15
	return 0;
Packit Service f36a15
Packit Service f36a15
_err:
Packit Service f36a15
	free(*dst);
Packit Service f36a15
	*dst = NULL;
Packit Service f36a15
	return err;
Packit Service f36a15
}