|
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 |
8875a0 |
} else {
|
|
Packit Service |
8875a0 |
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 |
8875a0 |
if (snd_config_make_compound(&dst, id, count == 1))
|
|
Packit Service |
8875a0 |
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 |
8875a0 |
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 |
8875a0 |
goto lerr;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
free(a);
|
|
Packit Service |
db8eaa |
return dst;
|
|
Packit Service |
8875a0 |
lerr:
|
|
Packit Service |
8875a0 |
free(a);
|
|
Packit Service |
8875a0 |
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 |
}
|