Blame src/topology/save.c

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