1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci Copyright(c) 2019 Red Hat Inc. 3d5ac70f0Sopenharmony_ci All rights reserved. 4d5ac70f0Sopenharmony_ci 5d5ac70f0Sopenharmony_ci This library is free software; you can redistribute it and/or modify 6d5ac70f0Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 7d5ac70f0Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of 8d5ac70f0Sopenharmony_ci the License, or (at your option) any later version. 9d5ac70f0Sopenharmony_ci 10d5ac70f0Sopenharmony_ci This program is distributed in the hope that it will be useful, 11d5ac70f0Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 12d5ac70f0Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13d5ac70f0Sopenharmony_ci GNU Lesser General Public License for more details. 14d5ac70f0Sopenharmony_ci 15d5ac70f0Sopenharmony_ci Authors: Jaroslav Kysela <perex@perex.cz> 16d5ac70f0Sopenharmony_ci*/ 17d5ac70f0Sopenharmony_ci 18d5ac70f0Sopenharmony_ci#include "tplg_local.h" 19d5ac70f0Sopenharmony_ci 20d5ac70f0Sopenharmony_ci#define SAVE_ALLOC_SHIFT (13) /* 8192 bytes */ 21d5ac70f0Sopenharmony_ci#define PRINT_ALLOC_SHIFT (10) /* 1024 bytes */ 22d5ac70f0Sopenharmony_ci#define PRINT_BUF_SIZE_MAX (1024 * 1024) 23d5ac70f0Sopenharmony_ci#define NEXT_CHUNK(val, shift) ((((val) >> (shift)) + 1) << (shift)) 24d5ac70f0Sopenharmony_ci 25d5ac70f0Sopenharmony_civoid tplg_buf_init(struct tplg_buf *buf) 26d5ac70f0Sopenharmony_ci{ 27d5ac70f0Sopenharmony_ci buf->dst = NULL; 28d5ac70f0Sopenharmony_ci buf->dst_len = 0; 29d5ac70f0Sopenharmony_ci buf->printf_buf = NULL; 30d5ac70f0Sopenharmony_ci buf->printf_buf_size = 0; 31d5ac70f0Sopenharmony_ci} 32d5ac70f0Sopenharmony_ci 33d5ac70f0Sopenharmony_civoid tplg_buf_free(struct tplg_buf *buf) 34d5ac70f0Sopenharmony_ci{ 35d5ac70f0Sopenharmony_ci free(buf->dst); 36d5ac70f0Sopenharmony_ci free(buf->printf_buf); 37d5ac70f0Sopenharmony_ci} 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_cichar *tplg_buf_detach(struct tplg_buf *buf) 40d5ac70f0Sopenharmony_ci{ 41d5ac70f0Sopenharmony_ci char *ret = buf->dst; 42d5ac70f0Sopenharmony_ci free(buf->printf_buf); 43d5ac70f0Sopenharmony_ci return ret; 44d5ac70f0Sopenharmony_ci} 45d5ac70f0Sopenharmony_ci 46d5ac70f0Sopenharmony_ciint tplg_save_printf(struct tplg_buf *dst, const char *pfx, const char *fmt, ...) 47d5ac70f0Sopenharmony_ci{ 48d5ac70f0Sopenharmony_ci va_list va; 49d5ac70f0Sopenharmony_ci char *s; 50d5ac70f0Sopenharmony_ci size_t n, l, t, pl; 51d5ac70f0Sopenharmony_ci int ret = 0; 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_ci if (pfx == NULL) 54d5ac70f0Sopenharmony_ci pfx = ""; 55d5ac70f0Sopenharmony_ci 56d5ac70f0Sopenharmony_ci va_start(va, fmt); 57d5ac70f0Sopenharmony_ci n = vsnprintf(dst->printf_buf, dst->printf_buf_size, fmt, va); 58d5ac70f0Sopenharmony_ci va_end(va); 59d5ac70f0Sopenharmony_ci 60d5ac70f0Sopenharmony_ci if (n >= PRINT_BUF_SIZE_MAX) { 61d5ac70f0Sopenharmony_ci ret = -EOVERFLOW; 62d5ac70f0Sopenharmony_ci goto end; 63d5ac70f0Sopenharmony_ci } 64d5ac70f0Sopenharmony_ci 65d5ac70f0Sopenharmony_ci if (n >= dst->printf_buf_size) { 66d5ac70f0Sopenharmony_ci t = NEXT_CHUNK(n + 1, PRINT_ALLOC_SHIFT); 67d5ac70f0Sopenharmony_ci s = realloc(dst->printf_buf, t); 68d5ac70f0Sopenharmony_ci if (!s) { 69d5ac70f0Sopenharmony_ci ret = -ENOMEM; 70d5ac70f0Sopenharmony_ci goto end; 71d5ac70f0Sopenharmony_ci } 72d5ac70f0Sopenharmony_ci dst->printf_buf = s; 73d5ac70f0Sopenharmony_ci dst->printf_buf_size = t; 74d5ac70f0Sopenharmony_ci va_start(va, fmt); 75d5ac70f0Sopenharmony_ci n = vsnprintf(dst->printf_buf, n + 1, fmt, va); 76d5ac70f0Sopenharmony_ci va_end(va); 77d5ac70f0Sopenharmony_ci } 78d5ac70f0Sopenharmony_ci 79d5ac70f0Sopenharmony_ci pl = strlen(pfx); 80d5ac70f0Sopenharmony_ci l = dst->dst_len; 81d5ac70f0Sopenharmony_ci t = l + pl + n + 1; 82d5ac70f0Sopenharmony_ci /* allocate chunks */ 83d5ac70f0Sopenharmony_ci if (dst->dst == NULL || 84d5ac70f0Sopenharmony_ci (l >> SAVE_ALLOC_SHIFT) != (t >> SAVE_ALLOC_SHIFT)) { 85d5ac70f0Sopenharmony_ci s = realloc(dst->dst, NEXT_CHUNK(t, SAVE_ALLOC_SHIFT)); 86d5ac70f0Sopenharmony_ci if (s == NULL) { 87d5ac70f0Sopenharmony_ci ret = -ENOMEM; 88d5ac70f0Sopenharmony_ci goto end; 89d5ac70f0Sopenharmony_ci } 90d5ac70f0Sopenharmony_ci } else { 91d5ac70f0Sopenharmony_ci s = dst->dst; 92d5ac70f0Sopenharmony_ci } 93d5ac70f0Sopenharmony_ci 94d5ac70f0Sopenharmony_ci if (pl > 0) 95d5ac70f0Sopenharmony_ci strcpy(s + l, pfx); 96d5ac70f0Sopenharmony_ci strcpy(s + l + pl, dst->printf_buf); 97d5ac70f0Sopenharmony_ci dst->dst = s; 98d5ac70f0Sopenharmony_ci dst->dst_len = t - 1; 99d5ac70f0Sopenharmony_ciend: 100d5ac70f0Sopenharmony_ci return ret; 101d5ac70f0Sopenharmony_ci} 102d5ac70f0Sopenharmony_ci 103d5ac70f0Sopenharmony_ciint tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value) 104d5ac70f0Sopenharmony_ci{ 105d5ac70f0Sopenharmony_ci if ((value % 1000) != 0) { 106d5ac70f0Sopenharmony_ci if (value > 0xfffffff0) 107d5ac70f0Sopenharmony_ci return snprintf(dst, dst_size, "%d", (int)value); 108d5ac70f0Sopenharmony_ci if (value >= 0xffff0000) 109d5ac70f0Sopenharmony_ci return snprintf(dst, dst_size, "0x%x", value); 110d5ac70f0Sopenharmony_ci } 111d5ac70f0Sopenharmony_ci return snprintf(dst, dst_size, "%u", value); 112d5ac70f0Sopenharmony_ci} 113d5ac70f0Sopenharmony_ci 114d5ac70f0Sopenharmony_cistatic int tplg_pprint_integer(snd_config_t *n, char **ret) 115d5ac70f0Sopenharmony_ci{ 116d5ac70f0Sopenharmony_ci long lval; 117d5ac70f0Sopenharmony_ci int err, type; 118d5ac70f0Sopenharmony_ci char buf[16]; 119d5ac70f0Sopenharmony_ci 120d5ac70f0Sopenharmony_ci type = snd_config_get_type(n); 121d5ac70f0Sopenharmony_ci if (type == SND_CONFIG_TYPE_INTEGER) { 122d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &lval); 123d5ac70f0Sopenharmony_ci if (err < 0) 124d5ac70f0Sopenharmony_ci return err; 125d5ac70f0Sopenharmony_ci if (lval < INT_MIN || lval > UINT_MAX) 126d5ac70f0Sopenharmony_ci return snd_config_get_ascii(n, ret); 127d5ac70f0Sopenharmony_ci } else if (type == SND_CONFIG_TYPE_INTEGER64) { 128d5ac70f0Sopenharmony_ci long long llval; 129d5ac70f0Sopenharmony_ci err = snd_config_get_integer64(n, &llval); 130d5ac70f0Sopenharmony_ci if (err < 0) 131d5ac70f0Sopenharmony_ci return err; 132d5ac70f0Sopenharmony_ci if (llval < INT_MIN || llval > UINT_MAX) 133d5ac70f0Sopenharmony_ci return snd_config_get_ascii(n, ret); 134d5ac70f0Sopenharmony_ci lval = llval; 135d5ac70f0Sopenharmony_ci } else { 136d5ac70f0Sopenharmony_ci lval = 0; 137d5ac70f0Sopenharmony_ci } 138d5ac70f0Sopenharmony_ci err = tplg_nice_value_format(buf, sizeof(buf), (unsigned int)lval); 139d5ac70f0Sopenharmony_ci if (err < 0) 140d5ac70f0Sopenharmony_ci return err; 141d5ac70f0Sopenharmony_ci *ret = strdup(buf); 142d5ac70f0Sopenharmony_ci if (*ret == NULL) 143d5ac70f0Sopenharmony_ci return -ENOMEM; 144d5ac70f0Sopenharmony_ci return 0; 145d5ac70f0Sopenharmony_ci} 146d5ac70f0Sopenharmony_ci 147d5ac70f0Sopenharmony_cistatic int _compar(const void *a, const void *b) 148d5ac70f0Sopenharmony_ci{ 149d5ac70f0Sopenharmony_ci const snd_config_t *c1 = *(snd_config_t **)a; 150d5ac70f0Sopenharmony_ci const snd_config_t *c2 = *(snd_config_t **)b; 151d5ac70f0Sopenharmony_ci const char *id1, *id2; 152d5ac70f0Sopenharmony_ci if (snd_config_get_id(c1, &id1)) return 0; 153d5ac70f0Sopenharmony_ci if (snd_config_get_id(c2, &id2)) return 0; 154d5ac70f0Sopenharmony_ci return strcmp(id1, id2); 155d5ac70f0Sopenharmony_ci} 156d5ac70f0Sopenharmony_ci 157d5ac70f0Sopenharmony_cistatic snd_config_t *sort_config(const char *id, snd_config_t *src) 158d5ac70f0Sopenharmony_ci{ 159d5ac70f0Sopenharmony_ci snd_config_t *dst, **a; 160d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 161d5ac70f0Sopenharmony_ci int index, array, count; 162d5ac70f0Sopenharmony_ci 163d5ac70f0Sopenharmony_ci if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) { 164d5ac70f0Sopenharmony_ci if (snd_config_copy(&dst, src) >= 0) 165d5ac70f0Sopenharmony_ci return dst; 166d5ac70f0Sopenharmony_ci return NULL; 167d5ac70f0Sopenharmony_ci } 168d5ac70f0Sopenharmony_ci count = 0; 169d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, src) 170d5ac70f0Sopenharmony_ci count++; 171d5ac70f0Sopenharmony_ci a = malloc(sizeof(dst) * count); 172d5ac70f0Sopenharmony_ci if (a == NULL) 173d5ac70f0Sopenharmony_ci return NULL; 174d5ac70f0Sopenharmony_ci array = snd_config_is_array(src); 175d5ac70f0Sopenharmony_ci index = 0; 176d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, src) { 177d5ac70f0Sopenharmony_ci snd_config_t *s = snd_config_iterator_entry(i); 178d5ac70f0Sopenharmony_ci a[index++] = s; 179d5ac70f0Sopenharmony_ci } 180d5ac70f0Sopenharmony_ci if (array <= 0) 181d5ac70f0Sopenharmony_ci qsort(a, count, sizeof(a[0]), _compar); 182d5ac70f0Sopenharmony_ci if (snd_config_make_compound(&dst, id, count == 1)) 183d5ac70f0Sopenharmony_ci goto lerr; 184d5ac70f0Sopenharmony_ci for (index = 0; index < count; index++) { 185d5ac70f0Sopenharmony_ci snd_config_t *s = a[index]; 186d5ac70f0Sopenharmony_ci const char *id2; 187d5ac70f0Sopenharmony_ci if (snd_config_get_id(s, &id2)) { 188d5ac70f0Sopenharmony_ci snd_config_delete(dst); 189d5ac70f0Sopenharmony_ci goto lerr; 190d5ac70f0Sopenharmony_ci } 191d5ac70f0Sopenharmony_ci s = sort_config(id2, s); 192d5ac70f0Sopenharmony_ci if (s == NULL || snd_config_add(dst, s)) { 193d5ac70f0Sopenharmony_ci if (s) 194d5ac70f0Sopenharmony_ci snd_config_delete(s); 195d5ac70f0Sopenharmony_ci snd_config_delete(dst); 196d5ac70f0Sopenharmony_ci goto lerr; 197d5ac70f0Sopenharmony_ci } 198d5ac70f0Sopenharmony_ci } 199d5ac70f0Sopenharmony_ci free(a); 200d5ac70f0Sopenharmony_ci return dst; 201d5ac70f0Sopenharmony_cilerr: 202d5ac70f0Sopenharmony_ci free(a); 203d5ac70f0Sopenharmony_ci return NULL; 204d5ac70f0Sopenharmony_ci} 205d5ac70f0Sopenharmony_ci 206d5ac70f0Sopenharmony_cistatic int tplg_check_quoted(const unsigned char *p) 207d5ac70f0Sopenharmony_ci{ 208d5ac70f0Sopenharmony_ci for ( ; *p != '\0'; p++) { 209d5ac70f0Sopenharmony_ci switch (*p) { 210d5ac70f0Sopenharmony_ci case ' ': 211d5ac70f0Sopenharmony_ci case '=': 212d5ac70f0Sopenharmony_ci case ';': 213d5ac70f0Sopenharmony_ci case ',': 214d5ac70f0Sopenharmony_ci case '.': 215d5ac70f0Sopenharmony_ci case '{': 216d5ac70f0Sopenharmony_ci case '}': 217d5ac70f0Sopenharmony_ci case '\'': 218d5ac70f0Sopenharmony_ci case '"': 219d5ac70f0Sopenharmony_ci return 1; 220d5ac70f0Sopenharmony_ci default: 221d5ac70f0Sopenharmony_ci if (*p <= 31 || *p >= 127) 222d5ac70f0Sopenharmony_ci return 1; 223d5ac70f0Sopenharmony_ci 224d5ac70f0Sopenharmony_ci } 225d5ac70f0Sopenharmony_ci } 226d5ac70f0Sopenharmony_ci return 0; 227d5ac70f0Sopenharmony_ci} 228d5ac70f0Sopenharmony_ci 229d5ac70f0Sopenharmony_cistatic int tplg_save_quoted(struct tplg_buf *dst, const char *str) 230d5ac70f0Sopenharmony_ci{ 231d5ac70f0Sopenharmony_ci static const char nibble[16] = "0123456789abcdef"; 232d5ac70f0Sopenharmony_ci unsigned char *p, *d, *t; 233d5ac70f0Sopenharmony_ci int c; 234d5ac70f0Sopenharmony_ci 235d5ac70f0Sopenharmony_ci d = t = alloca(strlen(str) * 5 + 1 + 1); 236d5ac70f0Sopenharmony_ci for (p = (unsigned char *)str; *p != '\0'; p++) { 237d5ac70f0Sopenharmony_ci c = *p; 238d5ac70f0Sopenharmony_ci switch (c) { 239d5ac70f0Sopenharmony_ci case '\n': 240d5ac70f0Sopenharmony_ci *t++ = '\\'; 241d5ac70f0Sopenharmony_ci *t++ = 'n'; 242d5ac70f0Sopenharmony_ci break; 243d5ac70f0Sopenharmony_ci case '\t': 244d5ac70f0Sopenharmony_ci *t++ = '\\'; 245d5ac70f0Sopenharmony_ci *t++ = 't'; 246d5ac70f0Sopenharmony_ci break; 247d5ac70f0Sopenharmony_ci case '\v': 248d5ac70f0Sopenharmony_ci *t++ = '\\'; 249d5ac70f0Sopenharmony_ci *t++ = 'v'; 250d5ac70f0Sopenharmony_ci break; 251d5ac70f0Sopenharmony_ci case '\b': 252d5ac70f0Sopenharmony_ci *t++ = '\\'; 253d5ac70f0Sopenharmony_ci *t++ = 'b'; 254d5ac70f0Sopenharmony_ci break; 255d5ac70f0Sopenharmony_ci case '\r': 256d5ac70f0Sopenharmony_ci *t++ = '\\'; 257d5ac70f0Sopenharmony_ci *t++ = 'r'; 258d5ac70f0Sopenharmony_ci break; 259d5ac70f0Sopenharmony_ci case '\f': 260d5ac70f0Sopenharmony_ci *t++ = '\\'; 261d5ac70f0Sopenharmony_ci *t++ = 'f'; 262d5ac70f0Sopenharmony_ci break; 263d5ac70f0Sopenharmony_ci case '\'': 264d5ac70f0Sopenharmony_ci *t++ = '\\'; 265d5ac70f0Sopenharmony_ci *t++ = c; 266d5ac70f0Sopenharmony_ci break; 267d5ac70f0Sopenharmony_ci default: 268d5ac70f0Sopenharmony_ci if (c >= 32 && c <= 126) { 269d5ac70f0Sopenharmony_ci *t++ = c; 270d5ac70f0Sopenharmony_ci } else { 271d5ac70f0Sopenharmony_ci *t++ = '\\'; 272d5ac70f0Sopenharmony_ci *t++ = 'x'; 273d5ac70f0Sopenharmony_ci *t++ = nibble[(c >> 4) & 0x0f]; 274d5ac70f0Sopenharmony_ci *t++ = nibble[(c >> 0) & 0x0f]; 275d5ac70f0Sopenharmony_ci } 276d5ac70f0Sopenharmony_ci break; 277d5ac70f0Sopenharmony_ci } 278d5ac70f0Sopenharmony_ci } 279d5ac70f0Sopenharmony_ci *t = '\0'; 280d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, NULL, "'%s'", d); 281d5ac70f0Sopenharmony_ci} 282d5ac70f0Sopenharmony_ci 283d5ac70f0Sopenharmony_cistatic int tplg_save_string(struct tplg_buf *dst, const char *str, int id) 284d5ac70f0Sopenharmony_ci{ 285d5ac70f0Sopenharmony_ci const unsigned char *p = (const unsigned char *)str; 286d5ac70f0Sopenharmony_ci 287d5ac70f0Sopenharmony_ci if (!p || !*p) 288d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, NULL, "''"); 289d5ac70f0Sopenharmony_ci 290d5ac70f0Sopenharmony_ci if (!id && ((*p >= '0' && *p <= '9') || *p == '-')) 291d5ac70f0Sopenharmony_ci return tplg_save_quoted(dst, str); 292d5ac70f0Sopenharmony_ci 293d5ac70f0Sopenharmony_ci if (tplg_check_quoted(p)) 294d5ac70f0Sopenharmony_ci return tplg_save_quoted(dst, str); 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, NULL, "%s", str); 297d5ac70f0Sopenharmony_ci} 298d5ac70f0Sopenharmony_ci 299d5ac70f0Sopenharmony_cistatic int save_config(struct tplg_buf *dst, int level, const char *delim, snd_config_t *src) 300d5ac70f0Sopenharmony_ci{ 301d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 302d5ac70f0Sopenharmony_ci snd_config_t *s; 303d5ac70f0Sopenharmony_ci const char *id; 304d5ac70f0Sopenharmony_ci char *pfx; 305d5ac70f0Sopenharmony_ci unsigned int count; 306d5ac70f0Sopenharmony_ci int type, err, quoted, array; 307d5ac70f0Sopenharmony_ci 308d5ac70f0Sopenharmony_ci if (delim == NULL) 309d5ac70f0Sopenharmony_ci delim = ""; 310d5ac70f0Sopenharmony_ci 311d5ac70f0Sopenharmony_ci type = snd_config_get_type(src); 312d5ac70f0Sopenharmony_ci if (type != SND_CONFIG_TYPE_COMPOUND) { 313d5ac70f0Sopenharmony_ci char *val; 314d5ac70f0Sopenharmony_ci if (type == SND_CONFIG_TYPE_INTEGER || 315d5ac70f0Sopenharmony_ci type == SND_CONFIG_TYPE_INTEGER64) { 316d5ac70f0Sopenharmony_ci err = tplg_pprint_integer(src, &val); 317d5ac70f0Sopenharmony_ci } else { 318d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(src, &val); 319d5ac70f0Sopenharmony_ci } 320d5ac70f0Sopenharmony_ci if (err < 0) 321d5ac70f0Sopenharmony_ci return err; 322d5ac70f0Sopenharmony_ci if (type == SND_CONFIG_TYPE_STRING) { 323d5ac70f0Sopenharmony_ci /* hexa array pretty print */ 324d5ac70f0Sopenharmony_ci id = strchr(val, '\n'); 325d5ac70f0Sopenharmony_ci if (id) { 326d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "\n"); 327d5ac70f0Sopenharmony_ci if (err < 0) 328d5ac70f0Sopenharmony_ci goto retval; 329d5ac70f0Sopenharmony_ci for (id++; *id == '\t'; id++) { 330d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "\t"); 331d5ac70f0Sopenharmony_ci if (err < 0) 332d5ac70f0Sopenharmony_ci goto retval; 333d5ac70f0Sopenharmony_ci } 334d5ac70f0Sopenharmony_ci delim = ""; 335d5ac70f0Sopenharmony_ci } 336d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "%s'%s'\n", delim, val); 337d5ac70f0Sopenharmony_ci } else { 338d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "%s%s\n", delim, val); 339d5ac70f0Sopenharmony_ci } 340d5ac70f0Sopenharmony_ciretval: 341d5ac70f0Sopenharmony_ci free(val); 342d5ac70f0Sopenharmony_ci return err; 343d5ac70f0Sopenharmony_ci } 344d5ac70f0Sopenharmony_ci 345d5ac70f0Sopenharmony_ci count = 0; 346d5ac70f0Sopenharmony_ci quoted = 0; 347d5ac70f0Sopenharmony_ci array = snd_config_is_array(src); 348d5ac70f0Sopenharmony_ci s = NULL; 349d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, src) { 350d5ac70f0Sopenharmony_ci s = snd_config_iterator_entry(i); 351d5ac70f0Sopenharmony_ci err = snd_config_get_id(s, &id); 352d5ac70f0Sopenharmony_ci if (err < 0) 353d5ac70f0Sopenharmony_ci return err; 354d5ac70f0Sopenharmony_ci if (!quoted && tplg_check_quoted((unsigned char *)id)) 355d5ac70f0Sopenharmony_ci quoted = 1; 356d5ac70f0Sopenharmony_ci count++; 357d5ac70f0Sopenharmony_ci } 358d5ac70f0Sopenharmony_ci if (count == 0) 359d5ac70f0Sopenharmony_ci return 0; 360d5ac70f0Sopenharmony_ci 361d5ac70f0Sopenharmony_ci if (count == 1) { 362d5ac70f0Sopenharmony_ci err = snd_config_get_id(s, &id); 363d5ac70f0Sopenharmony_ci if (err >= 0 && level > 0) 364d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "."); 365d5ac70f0Sopenharmony_ci if (err >= 0) 366d5ac70f0Sopenharmony_ci err = tplg_save_string(dst, id, 1); 367d5ac70f0Sopenharmony_ci if (err >= 0) 368d5ac70f0Sopenharmony_ci err = save_config(dst, level, " ", s); 369d5ac70f0Sopenharmony_ci return err; 370d5ac70f0Sopenharmony_ci } 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_ci pfx = alloca(level + 1); 373d5ac70f0Sopenharmony_ci memset(pfx, '\t', level); 374d5ac70f0Sopenharmony_ci pfx[level] = '\0'; 375d5ac70f0Sopenharmony_ci 376d5ac70f0Sopenharmony_ci if (level > 0) { 377d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "%s%s\n", delim, 378d5ac70f0Sopenharmony_ci array > 0 ? "[" : "{"); 379d5ac70f0Sopenharmony_ci if (err < 0) 380d5ac70f0Sopenharmony_ci return err; 381d5ac70f0Sopenharmony_ci } 382d5ac70f0Sopenharmony_ci 383d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, src) { 384d5ac70f0Sopenharmony_ci s = snd_config_iterator_entry(i); 385d5ac70f0Sopenharmony_ci const char *id; 386d5ac70f0Sopenharmony_ci err = snd_config_get_id(s, &id); 387d5ac70f0Sopenharmony_ci if (err < 0) 388d5ac70f0Sopenharmony_ci return err; 389d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, ""); 390d5ac70f0Sopenharmony_ci if (err < 0) 391d5ac70f0Sopenharmony_ci return err; 392d5ac70f0Sopenharmony_ci if (array <= 0) { 393d5ac70f0Sopenharmony_ci delim = " "; 394d5ac70f0Sopenharmony_ci if (quoted) { 395d5ac70f0Sopenharmony_ci err = tplg_save_quoted(dst, id); 396d5ac70f0Sopenharmony_ci } else { 397d5ac70f0Sopenharmony_ci err = tplg_save_string(dst, id, 1); 398d5ac70f0Sopenharmony_ci } 399d5ac70f0Sopenharmony_ci if (err < 0) 400d5ac70f0Sopenharmony_ci return err; 401d5ac70f0Sopenharmony_ci } else { 402d5ac70f0Sopenharmony_ci delim = ""; 403d5ac70f0Sopenharmony_ci } 404d5ac70f0Sopenharmony_ci err = save_config(dst, level + 1, delim, s); 405d5ac70f0Sopenharmony_ci if (err < 0) 406d5ac70f0Sopenharmony_ci return err; 407d5ac70f0Sopenharmony_ci } 408d5ac70f0Sopenharmony_ci 409d5ac70f0Sopenharmony_ci if (level > 0) { 410d5ac70f0Sopenharmony_ci pfx[level - 1] = '\0'; 411d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "%s\n", 412d5ac70f0Sopenharmony_ci array > 0 ? "]" : "}"); 413d5ac70f0Sopenharmony_ci if (err < 0) 414d5ac70f0Sopenharmony_ci return err; 415d5ac70f0Sopenharmony_ci } 416d5ac70f0Sopenharmony_ci 417d5ac70f0Sopenharmony_ci return 0; 418d5ac70f0Sopenharmony_ci} 419d5ac70f0Sopenharmony_ci 420d5ac70f0Sopenharmony_cistatic int tplg_save(snd_tplg_t *tplg, struct tplg_buf *dst, 421d5ac70f0Sopenharmony_ci int gindex, const char *prefix) 422d5ac70f0Sopenharmony_ci{ 423d5ac70f0Sopenharmony_ci struct tplg_table *tptr; 424d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 425d5ac70f0Sopenharmony_ci struct list_head *list, *pos; 426d5ac70f0Sopenharmony_ci char pfx2[16]; 427d5ac70f0Sopenharmony_ci unsigned int index; 428d5ac70f0Sopenharmony_ci int err, count; 429d5ac70f0Sopenharmony_ci 430d5ac70f0Sopenharmony_ci snprintf(pfx2, sizeof(pfx2), "%s\t", prefix ?: ""); 431d5ac70f0Sopenharmony_ci 432d5ac70f0Sopenharmony_ci /* write all blocks */ 433d5ac70f0Sopenharmony_ci for (index = 0; index < tplg_table_items; index++) { 434d5ac70f0Sopenharmony_ci tptr = &tplg_table[index]; 435d5ac70f0Sopenharmony_ci list = (struct list_head *)((void *)tplg + tptr->loff); 436d5ac70f0Sopenharmony_ci 437d5ac70f0Sopenharmony_ci /* count elements */ 438d5ac70f0Sopenharmony_ci count = 0; 439d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 440d5ac70f0Sopenharmony_ci elem = list_entry(pos, struct tplg_elem, list); 441d5ac70f0Sopenharmony_ci if (gindex >= 0 && elem->index != gindex) 442d5ac70f0Sopenharmony_ci continue; 443d5ac70f0Sopenharmony_ci if (tptr->save == NULL && tptr->gsave == NULL) { 444d5ac70f0Sopenharmony_ci SNDERR("unable to create %s block (no callback)", 445d5ac70f0Sopenharmony_ci tptr->id); 446d5ac70f0Sopenharmony_ci err = -ENXIO; 447d5ac70f0Sopenharmony_ci goto _err; 448d5ac70f0Sopenharmony_ci } 449d5ac70f0Sopenharmony_ci if (tptr->save) 450d5ac70f0Sopenharmony_ci count++; 451d5ac70f0Sopenharmony_ci } 452d5ac70f0Sopenharmony_ci 453d5ac70f0Sopenharmony_ci if (count == 0) 454d5ac70f0Sopenharmony_ci continue; 455d5ac70f0Sopenharmony_ci 456d5ac70f0Sopenharmony_ci if (count > 1) { 457d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, prefix, "%s {\n", 458d5ac70f0Sopenharmony_ci elem->table ? 459d5ac70f0Sopenharmony_ci elem->table->id : "_NOID_"); 460d5ac70f0Sopenharmony_ci } else { 461d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, prefix, "%s.", 462d5ac70f0Sopenharmony_ci elem->table ? 463d5ac70f0Sopenharmony_ci elem->table->id : "_NOID_"); 464d5ac70f0Sopenharmony_ci } 465d5ac70f0Sopenharmony_ci 466d5ac70f0Sopenharmony_ci if (err < 0) 467d5ac70f0Sopenharmony_ci goto _err; 468d5ac70f0Sopenharmony_ci 469d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 470d5ac70f0Sopenharmony_ci elem = list_entry(pos, struct tplg_elem, list); 471d5ac70f0Sopenharmony_ci if (gindex >= 0 && elem->index != gindex) 472d5ac70f0Sopenharmony_ci continue; 473d5ac70f0Sopenharmony_ci if (count > 1) { 474d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx2, ""); 475d5ac70f0Sopenharmony_ci if (err < 0) 476d5ac70f0Sopenharmony_ci goto _err; 477d5ac70f0Sopenharmony_ci } 478d5ac70f0Sopenharmony_ci err = tptr->save(tplg, elem, dst, count > 1 ? pfx2 : prefix); 479d5ac70f0Sopenharmony_ci if (err < 0) { 480d5ac70f0Sopenharmony_ci SNDERR("failed to save %s elements: %s", 481d5ac70f0Sopenharmony_ci tptr->id, snd_strerror(-err)); 482d5ac70f0Sopenharmony_ci goto _err; 483d5ac70f0Sopenharmony_ci } 484d5ac70f0Sopenharmony_ci } 485d5ac70f0Sopenharmony_ci if (count > 1) { 486d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, prefix, "}\n"); 487d5ac70f0Sopenharmony_ci if (err < 0) 488d5ac70f0Sopenharmony_ci goto _err; 489d5ac70f0Sopenharmony_ci } 490d5ac70f0Sopenharmony_ci } 491d5ac70f0Sopenharmony_ci 492d5ac70f0Sopenharmony_ci /* save globals */ 493d5ac70f0Sopenharmony_ci for (index = 0; index < tplg_table_items; index++) { 494d5ac70f0Sopenharmony_ci tptr = &tplg_table[index]; 495d5ac70f0Sopenharmony_ci if (tptr->gsave) { 496d5ac70f0Sopenharmony_ci err = tptr->gsave(tplg, gindex, dst, prefix); 497d5ac70f0Sopenharmony_ci if (err < 0) 498d5ac70f0Sopenharmony_ci goto _err; 499d5ac70f0Sopenharmony_ci } 500d5ac70f0Sopenharmony_ci } 501d5ac70f0Sopenharmony_ci 502d5ac70f0Sopenharmony_ci return 0; 503d5ac70f0Sopenharmony_ci 504d5ac70f0Sopenharmony_ci_err: 505d5ac70f0Sopenharmony_ci return err; 506d5ac70f0Sopenharmony_ci} 507d5ac70f0Sopenharmony_ci 508d5ac70f0Sopenharmony_cistatic int tplg_index_compar(const void *a, const void *b) 509d5ac70f0Sopenharmony_ci{ 510d5ac70f0Sopenharmony_ci const int *a1 = a, *b1 = b; 511d5ac70f0Sopenharmony_ci return *a1 - *b1; 512d5ac70f0Sopenharmony_ci} 513d5ac70f0Sopenharmony_ci 514d5ac70f0Sopenharmony_cistatic int tplg_index_groups(snd_tplg_t *tplg, int **indexes) 515d5ac70f0Sopenharmony_ci{ 516d5ac70f0Sopenharmony_ci struct tplg_table *tptr; 517d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 518d5ac70f0Sopenharmony_ci struct list_head *list, *pos; 519d5ac70f0Sopenharmony_ci unsigned int index, j, count, size; 520d5ac70f0Sopenharmony_ci int *a, *b; 521d5ac70f0Sopenharmony_ci 522d5ac70f0Sopenharmony_ci count = 0; 523d5ac70f0Sopenharmony_ci size = 16; 524d5ac70f0Sopenharmony_ci a = malloc(size * sizeof(a[0])); 525d5ac70f0Sopenharmony_ci 526d5ac70f0Sopenharmony_ci for (index = 0; index < tplg_table_items; index++) { 527d5ac70f0Sopenharmony_ci tptr = &tplg_table[index]; 528d5ac70f0Sopenharmony_ci list = (struct list_head *)((void *)tplg + tptr->loff); 529d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 530d5ac70f0Sopenharmony_ci elem = list_entry(pos, struct tplg_elem, list); 531d5ac70f0Sopenharmony_ci for (j = 0; j < count; j++) { 532d5ac70f0Sopenharmony_ci if (a[j] == elem->index) 533d5ac70f0Sopenharmony_ci break; 534d5ac70f0Sopenharmony_ci } 535d5ac70f0Sopenharmony_ci if (j < count) 536d5ac70f0Sopenharmony_ci continue; 537d5ac70f0Sopenharmony_ci if (count + 1 >= size) { 538d5ac70f0Sopenharmony_ci size += 8; 539d5ac70f0Sopenharmony_ci b = realloc(a, size * sizeof(a[0])); 540d5ac70f0Sopenharmony_ci if (b == NULL) { 541d5ac70f0Sopenharmony_ci free(a); 542d5ac70f0Sopenharmony_ci return -ENOMEM; 543d5ac70f0Sopenharmony_ci } 544d5ac70f0Sopenharmony_ci a = b; 545d5ac70f0Sopenharmony_ci } 546d5ac70f0Sopenharmony_ci a[count++] = elem->index; 547d5ac70f0Sopenharmony_ci } 548d5ac70f0Sopenharmony_ci } 549d5ac70f0Sopenharmony_ci a[count] = -1; 550d5ac70f0Sopenharmony_ci 551d5ac70f0Sopenharmony_ci qsort(a, count, sizeof(a[0]), tplg_index_compar); 552d5ac70f0Sopenharmony_ci 553d5ac70f0Sopenharmony_ci *indexes = a; 554d5ac70f0Sopenharmony_ci return 0; 555d5ac70f0Sopenharmony_ci} 556d5ac70f0Sopenharmony_ci 557d5ac70f0Sopenharmony_ciint snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) 558d5ac70f0Sopenharmony_ci{ 559d5ac70f0Sopenharmony_ci struct tplg_buf buf, buf2; 560d5ac70f0Sopenharmony_ci snd_input_t *in; 561d5ac70f0Sopenharmony_ci snd_config_t *top, *top2; 562d5ac70f0Sopenharmony_ci int *indexes, *a; 563d5ac70f0Sopenharmony_ci int err; 564d5ac70f0Sopenharmony_ci 565d5ac70f0Sopenharmony_ci assert(tplg); 566d5ac70f0Sopenharmony_ci assert(dst); 567d5ac70f0Sopenharmony_ci *dst = NULL; 568d5ac70f0Sopenharmony_ci 569d5ac70f0Sopenharmony_ci tplg_buf_init(&buf); 570d5ac70f0Sopenharmony_ci 571d5ac70f0Sopenharmony_ci if (flags & SND_TPLG_SAVE_GROUPS) { 572d5ac70f0Sopenharmony_ci err = tplg_index_groups(tplg, &indexes); 573d5ac70f0Sopenharmony_ci if (err < 0) 574d5ac70f0Sopenharmony_ci return err; 575d5ac70f0Sopenharmony_ci for (a = indexes; err >= 0 && *a >= 0; a++) { 576d5ac70f0Sopenharmony_ci err = tplg_save_printf(&buf, NULL, 577d5ac70f0Sopenharmony_ci "IndexGroup.%d {\n", 578d5ac70f0Sopenharmony_ci *a); 579d5ac70f0Sopenharmony_ci if (err >= 0) 580d5ac70f0Sopenharmony_ci err = tplg_save(tplg, &buf, *a, "\t"); 581d5ac70f0Sopenharmony_ci if (err >= 0) 582d5ac70f0Sopenharmony_ci err = tplg_save_printf(&buf, NULL, "}\n"); 583d5ac70f0Sopenharmony_ci } 584d5ac70f0Sopenharmony_ci free(indexes); 585d5ac70f0Sopenharmony_ci } else { 586d5ac70f0Sopenharmony_ci err = tplg_save(tplg, &buf, -1, NULL); 587d5ac70f0Sopenharmony_ci } 588d5ac70f0Sopenharmony_ci 589d5ac70f0Sopenharmony_ci if (err < 0) 590d5ac70f0Sopenharmony_ci goto _err; 591d5ac70f0Sopenharmony_ci 592d5ac70f0Sopenharmony_ci if (buf.dst == NULL) { 593d5ac70f0Sopenharmony_ci err = -EINVAL; 594d5ac70f0Sopenharmony_ci goto _err; 595d5ac70f0Sopenharmony_ci } 596d5ac70f0Sopenharmony_ci 597d5ac70f0Sopenharmony_ci if (flags & SND_TPLG_SAVE_NOCHECK) { 598d5ac70f0Sopenharmony_ci *dst = tplg_buf_detach(&buf); 599d5ac70f0Sopenharmony_ci return 0; 600d5ac70f0Sopenharmony_ci } 601d5ac70f0Sopenharmony_ci 602d5ac70f0Sopenharmony_ci /* always load configuration - check */ 603d5ac70f0Sopenharmony_ci err = snd_input_buffer_open(&in, buf.dst, strlen(buf.dst)); 604d5ac70f0Sopenharmony_ci if (err < 0) { 605d5ac70f0Sopenharmony_ci SNDERR("could not create input buffer"); 606d5ac70f0Sopenharmony_ci goto _err; 607d5ac70f0Sopenharmony_ci } 608d5ac70f0Sopenharmony_ci 609d5ac70f0Sopenharmony_ci err = snd_config_top(&top); 610d5ac70f0Sopenharmony_ci if (err < 0) { 611d5ac70f0Sopenharmony_ci snd_input_close(in); 612d5ac70f0Sopenharmony_ci goto _err; 613d5ac70f0Sopenharmony_ci } 614d5ac70f0Sopenharmony_ci 615d5ac70f0Sopenharmony_ci err = snd_config_load(top, in); 616d5ac70f0Sopenharmony_ci snd_input_close(in); 617d5ac70f0Sopenharmony_ci if (err < 0) { 618d5ac70f0Sopenharmony_ci SNDERR("could not load configuration"); 619d5ac70f0Sopenharmony_ci snd_config_delete(top); 620d5ac70f0Sopenharmony_ci goto _err; 621d5ac70f0Sopenharmony_ci } 622d5ac70f0Sopenharmony_ci 623d5ac70f0Sopenharmony_ci if (flags & SND_TPLG_SAVE_SORT) { 624d5ac70f0Sopenharmony_ci top2 = sort_config(NULL, top); 625d5ac70f0Sopenharmony_ci if (top2 == NULL) { 626d5ac70f0Sopenharmony_ci SNDERR("could not sort configuration"); 627d5ac70f0Sopenharmony_ci snd_config_delete(top); 628d5ac70f0Sopenharmony_ci err = -EINVAL; 629d5ac70f0Sopenharmony_ci goto _err; 630d5ac70f0Sopenharmony_ci } 631d5ac70f0Sopenharmony_ci snd_config_delete(top); 632d5ac70f0Sopenharmony_ci top = top2; 633d5ac70f0Sopenharmony_ci } 634d5ac70f0Sopenharmony_ci 635d5ac70f0Sopenharmony_ci tplg_buf_init(&buf2); 636d5ac70f0Sopenharmony_ci err = save_config(&buf2, 0, NULL, top); 637d5ac70f0Sopenharmony_ci snd_config_delete(top); 638d5ac70f0Sopenharmony_ci if (err < 0) { 639d5ac70f0Sopenharmony_ci SNDERR("could not save configuration"); 640d5ac70f0Sopenharmony_ci goto _err; 641d5ac70f0Sopenharmony_ci } 642d5ac70f0Sopenharmony_ci 643d5ac70f0Sopenharmony_ci tplg_buf_free(&buf); 644d5ac70f0Sopenharmony_ci *dst = tplg_buf_detach(&buf2); 645d5ac70f0Sopenharmony_ci return 0; 646d5ac70f0Sopenharmony_ci 647d5ac70f0Sopenharmony_ci_err: 648d5ac70f0Sopenharmony_ci tplg_buf_free(&buf); 649d5ac70f0Sopenharmony_ci *dst = NULL; 650d5ac70f0Sopenharmony_ci return err; 651d5ac70f0Sopenharmony_ci} 652