xref: /third_party/alsa-utils/alsaucm/dump.c (revision c72fcc34)
1/*
2 *  This library is free software; you can redistribute it and/or
3 *  modify it under the terms of the GNU Lesser General Public
4 *  License as published by the Free Software Foundation; either
5 *  version 2 of the License, or (at your option) any later version.
6 *
7 *  This library is distributed in the hope that it will be useful,
8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 *  Lesser General Public License for more details.
11 *
12 *  You should have received a copy of the GNU General Public License
13 *  along with this program; if not, write to the Free Software
14 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 *  Copyright (C) 2019 Red Hat Inc.
17 *  Authors: Jaroslav Kysela <perex@perex.cz>
18 */
19
20#include <stdio.h>
21#include <string.h>
22#include <alsa/asoundlib.h>
23#include <alsa/use-case.h>
24#include "usecase.h"
25#include "aconfig.h"
26#include "version.h"
27
28struct renderer {
29	int (*init)(struct renderer *r);
30	void (*done)(struct renderer *r);
31	int (*verb_begin)(struct renderer *r,
32			  const char *verb,
33			  const char *comment);
34	int (*verb_end)(struct renderer *r);
35	int (*device_block_begin)(struct renderer *r);
36	int (*device_block_end)(struct renderer *r);
37	int (*device_begin)(struct renderer *r,
38			    const char *device,
39			    const char *comment);
40	int (*device_end)(struct renderer *r);
41	int (*modifier_block_begin)(struct renderer *r);
42	int (*modifier_block_end)(struct renderer *r);
43	int (*modifier_begin)(struct renderer *r,
44			      const char *device,
45			      const char *comment);
46	int (*modifier_end)(struct renderer *r);
47	int (*supported_begin)(struct renderer *r);
48	int (*supported_value)(struct renderer *r, const char *value, int last);
49	int (*supported_end)(struct renderer *r);
50	int (*conflict_begin)(struct renderer *r);
51	int (*conflict_value)(struct renderer *r, const char *value, int last);
52	int (*conflict_end)(struct renderer *r);
53	int (*value_begin)(struct renderer *r);
54	int (*value_end)(struct renderer *r);
55	int (*value)(struct renderer *r, const char *ident, const char *value);
56	void *opaque;
57};
58
59/*
60 * Text renderer
61 */
62
63struct text {
64	char a[1];
65};
66
67static char *tesc(const char *s, char *buf, size_t buf_len)
68{
69	char *dst = buf;
70	char c = '\0';
71	if (strchr(s, '"') || strchr(s, ' ') || strchr(s, '.')) {
72		*dst++ = c = '"';
73		buf_len--;
74	}
75	while (*s && buf_len > 2) {
76		if (*s == '"') {
77			if (buf_len > 3) {
78				*dst++ = '\\';
79				*dst++ = *s++;
80				buf_len -= 2;
81				continue;
82			} else {
83				break;
84			}
85		}
86		*dst++ = *s++;
87	}
88	if (c)
89		*dst++ = c;
90	*dst = '\0';
91	return buf;
92}
93
94#define ESC(s, esc) tesc((s), (esc), sizeof(esc))
95
96static int text_verb_start(struct renderer *r ATTRIBUTE_UNUSED,
97			   const char *verb, const char *comment)
98{
99	char buf1[128], buf2[128];
100	printf("Verb.%s {\n", ESC(verb, buf1));
101	if (comment && comment[0])
102		printf("\tComment %s\n", ESC(comment, buf2));
103	return 0;
104}
105
106static int text_verb_end(struct renderer *r ATTRIBUTE_UNUSED)
107{
108	printf("}\n");
109	return 0;
110}
111
112static int text_2nd_level_begin(struct renderer *r ATTRIBUTE_UNUSED,
113				const char *key,
114				const char *val,
115				const char *comment)
116{
117	char buf1[128], buf2[128];
118	printf("\t%s.%s {\n", key, ESC(val, buf1));
119	if (comment && comment[0])
120		printf("\t\tComment %s\n", ESC(comment, buf2));
121	return 0;
122}
123
124static int text_2nd_level_end(struct renderer *r ATTRIBUTE_UNUSED)
125{
126	printf("\t}\n");
127	return 0;
128}
129
130static int text_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
131{
132	printf("\t\t%s", txt);
133	return 0;
134}
135
136static int text_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
137{
138	printf("\t\t\t%s", txt);
139	return 0;
140}
141
142static int text_dev_start(struct renderer *r, const char *dev, const char *comment)
143{
144	return text_2nd_level_begin(r, "Device", dev, comment);
145}
146
147static int text_mod_start(struct renderer *r, const char *dev, const char *comment)
148{
149	return text_2nd_level_begin(r, "Modifier", dev, comment);
150}
151
152static int text_supcon_start(struct renderer *r, const char *key)
153{
154	if (text_2nd_level(r, key))
155		return 1;
156	printf(" [\n");
157	return 0;
158}
159
160static int text_supcon_value(struct renderer *r, const char *value, int last)
161{
162	char buf[256];
163	ESC(value, buf);
164	if (!last && strlen(buf) < sizeof(buf) - 2)
165		strcat(buf, ",");
166	if (text_3rd_level(r, buf))
167		return 1;
168	printf("\n");
169	return 0;
170}
171
172static int text_supcon_end(struct renderer *r)
173{
174	return text_2nd_level(r, "]\n");
175}
176
177static int text_sup_start(struct renderer *r)
178{
179	return text_supcon_start(r, "SupportedDevices");
180}
181
182static int text_con_start(struct renderer *r)
183{
184	return text_supcon_start(r, "ConflictingDevices");
185}
186
187static int text_value_begin(struct renderer *r)
188{
189	return text_2nd_level(r, "Values {\n");
190}
191
192static int text_value_end(struct renderer *r)
193{
194	return text_2nd_level(r, "}\n");
195}
196
197static int text_value(struct renderer *r, const char *ident, const char *value)
198{
199	char buf1[256], buf2[256];
200	int err;
201
202	ESC(ident, buf1);
203	err = text_3rd_level(r, buf1);
204	if (err < 0)
205		return err;
206	ESC(value, buf2);
207	printf(" %s\n", buf2);
208	return 0;
209}
210
211static struct renderer text_renderer = {
212	.verb_begin = text_verb_start,
213	.verb_end = text_verb_end,
214	.device_begin = text_dev_start,
215	.device_end = text_2nd_level_end,
216	.modifier_begin = text_mod_start,
217	.modifier_end = text_2nd_level_end,
218	.supported_begin = text_sup_start,
219	.supported_value = text_supcon_value,
220	.supported_end = text_supcon_end,
221	.conflict_begin = text_con_start,
222	.conflict_value = text_supcon_value,
223	.conflict_end = text_supcon_end,
224	.value_begin = text_value_begin,
225	.value_end = text_value_end,
226	.value = text_value,
227};
228
229/*
230 * JSON renderer
231 */
232
233struct json {
234	int block[5];
235};
236
237static char *jesc(const char *s, char *buf, size_t buf_len)
238{
239	char *dst = buf;
240	char c = '"';
241	*dst++ = c;
242	buf_len--;
243	while (*s && buf_len > 2) {
244		if (*s == '"') {
245			if (buf_len > 3) {
246				*dst++ = '\\';
247				*dst++ = *s++;
248				buf_len -= 2;
249				continue;
250			} else {
251				break;
252			}
253		}
254		*dst++ = *s++;
255	}
256	*dst++ = c;
257	*dst = '\0';
258	return buf;
259}
260
261#define JESC(s, esc) jesc((s), (esc), sizeof(esc))
262
263static void json_block(struct renderer *r, int level, int last)
264{
265	struct json *j = r->opaque;
266	printf((j->block[level] && !last) ? ",\n" : "\n");
267	j->block[level] = last ? 0 : 1;
268}
269
270static int json_init(struct renderer *r ATTRIBUTE_UNUSED)
271{
272	printf("{\n  \"Verbs\": {");
273	return 0;
274}
275
276static void json_done(struct renderer *r)
277{
278	json_block(r, 0, 1);
279	printf("  }\n}\n");
280}
281
282static int json_verb_start(struct renderer *r, const char *verb, const char *comment)
283{
284	char buf[256];
285	json_block(r, 0, 0);
286	printf("    %s: {", JESC(verb, buf));
287	if (comment && comment[0]) {
288		json_block(r, 1, 0);
289		printf("      \"Comment\": %s", JESC(comment, buf));
290	}
291	return 0;
292}
293
294static int json_verb_end(struct renderer *r)
295{
296	json_block(r, 1, 1);
297	printf("    }");
298	return 0;
299}
300
301static int json_2nd_level_block_end(struct renderer *r)
302{
303	json_block(r, 2, 1);
304	printf("      }");
305	return 0;
306}
307
308static int json_2nd_level_begin(struct renderer *r,
309				const char *val,
310				const char *comment)
311{
312	char buf[256];
313	json_block(r, 2, 0);
314	printf("        %s: {", JESC(val, buf));
315	if (comment && comment[0]) {
316		json_block(r, 3, 0);
317		printf("          \"Comment\": %s", JESC(comment, buf));
318	}
319	return 0;
320}
321
322static int json_2nd_level_end(struct renderer *r)
323{
324	json_block(r, 3, 1);
325	printf("        }");
326	return 0;
327}
328
329static int json_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
330{
331	printf("          %s", txt);
332	return 0;
333}
334
335static int json_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
336{
337	printf("            %s", txt);
338	return 0;
339}
340
341static int json_dev_block_start(struct renderer *r)
342{
343	json_block(r, 1, 0);
344	printf("      \"Devices\": {");
345	return 0;
346}
347
348static int json_mod_block_start(struct renderer *r)
349{
350	json_block(r, 1, 0);
351	printf("      \"Modifiers\": {");
352	return 0;
353}
354
355static int json_supcon_start(struct renderer *r, const char *key)
356{
357	json_block(r, 3, 0);
358	if (json_2nd_level(r, key))
359		return 1;
360	printf(": [");
361	return 0;
362}
363
364static int json_supcon_value(struct renderer *r, const char *value,
365			     int last ATTRIBUTE_UNUSED)
366{
367	char buf[256];
368	JESC(value, buf);
369	json_block(r, 4, 0);
370	return json_3rd_level(r, buf);
371}
372
373static int json_supcon_end(struct renderer *r)
374{
375	json_block(r, 4, 1);
376	return json_2nd_level(r, "]");
377}
378
379static int json_sup_start(struct renderer *r)
380{
381	return json_supcon_start(r, "\"SupportedDevices\"");
382}
383
384static int json_con_start(struct renderer *r)
385{
386	return json_supcon_start(r, "\"ConflictingDevices\"");
387}
388
389static int json_value_begin(struct renderer *r)
390{
391	json_block(r, 3, 0);
392	return json_2nd_level(r, "\"Values\": {");
393}
394
395static int json_value_end(struct renderer *r)
396{
397	json_block(r, 4, 1);
398	return json_2nd_level(r, "}");
399}
400
401static int json_value(struct renderer *r, const char *ident, const char *value)
402{
403	char buf[256];
404	int err;
405
406	json_block(r, 4, 0);
407	JESC(ident, buf);
408	err = json_3rd_level(r, buf);
409	if (err < 0)
410		return err;
411	JESC(value, buf);
412	printf(": %s", buf);
413	return 0;
414}
415
416static struct renderer json_renderer = {
417	.init = json_init,
418	.done = json_done,
419	.verb_begin = json_verb_start,
420	.verb_end = json_verb_end,
421	.device_block_begin = json_dev_block_start,
422	.device_block_end = json_2nd_level_block_end,
423	.device_begin = json_2nd_level_begin,
424	.device_end = json_2nd_level_end,
425	.modifier_block_begin = json_mod_block_start,
426	.modifier_block_end = json_2nd_level_block_end,
427	.modifier_begin = json_2nd_level_begin,
428	.modifier_end = json_2nd_level_end,
429	.supported_begin = json_sup_start,
430	.supported_value = json_supcon_value,
431	.supported_end = json_supcon_end,
432	.conflict_begin = json_con_start,
433	.conflict_value = json_supcon_value,
434	.conflict_end = json_supcon_end,
435	.value_begin = json_value_begin,
436	.value_end = json_value_end,
437	.value = json_value,
438};
439
440/*
441 * universal dump functions
442 */
443
444static int render_devlist(struct context *context,
445			  struct renderer *render,
446			  const char *verb,
447			  const char *device,
448			  const char *list,
449			  int (*begin)(struct renderer *),
450			  int (*value)(struct renderer *, const char *value, int last),
451			  int (*end)(struct renderer *))
452{
453	snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
454	const char **dev_list;
455	char buf[256];
456	int err = 0, j, dev_num;
457
458	snprintf(buf, sizeof(buf), "%s/%s/%s", list, device, verb);
459	dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
460	if (dev_num < 0) {
461		fprintf(stderr, "%s: unable to get %s for verb '%s' for device '%s'\n",
462			context->command, list, verb, device);
463		return dev_num;
464	}
465	if (dev_num > 0) {
466		err = begin(render);
467		if (err < 0)
468			goto __err;
469		for (j = 0; j < dev_num; j++) {
470			err = value(render, dev_list[j], j + 1 == dev_num);
471			if (err < 0)
472				goto __err;
473		}
474		err = end(render);
475	}
476__err:
477	snd_use_case_free_list(dev_list, dev_num);
478	return err;
479}
480
481static int render_values(struct context *context,
482			 struct renderer *render,
483			 const char *verb,
484			 const char *device)
485{
486	snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
487	const char **list, *value;
488	char buf[256];
489	int err = 0, j, num;
490
491	snprintf(buf, sizeof(buf), "_identifiers/%s/%s", device, verb);
492	num = snd_use_case_get_list(uc_mgr, buf, &list);
493	if (num < 0) {
494		fprintf(stderr, "%s: unable to get _identifiers for verb '%s' for device '%s': %s\n",
495			context->command, verb, device, snd_strerror(num));
496		return num;
497	}
498	if (num == 0)
499		goto __err;
500	if (render->value_begin) {
501		err = render->value_begin(render);
502		if (err < 0)
503			goto __err;
504	}
505	for (j = 0; j < num; j++) {
506		snprintf(buf, sizeof(buf), "%s/%s/%s", list[j], device, verb);
507		err = snd_use_case_get(uc_mgr, buf, &value);
508		if (err < 0) {
509			fprintf(stderr, "%s: unable to get value '%s' for verb '%s' for device '%s': %s\n",
510				context->command, list[j], verb, device, snd_strerror(err));
511			goto __err;
512		}
513		err = render->value(render, list[j], value);
514		free((char *)value);
515		if (err < 0)
516			goto __err;
517	}
518	if (render->value_end)
519		err = render->value_end(render);
520__err:
521	snd_use_case_free_list(list, num);
522	return err;
523}
524
525static int render_device(struct context *context,
526			 struct renderer *render,
527			 const char *verb,
528			 const char *device)
529{
530	int err;
531
532	err = render_devlist(context, render, verb, device,
533			     "_supporteddevs",
534			     render->supported_begin,
535			     render->supported_value,
536			     render->supported_end);
537	if (err < 0)
538		return err;
539	err = render_devlist(context, render, verb, device,
540			     "_conflictingdevs",
541			     render->conflict_begin,
542			     render->conflict_value,
543			     render->conflict_end);
544	if (err < 0)
545		return err;
546	return render_values(context, render, verb, device);
547}
548
549static void render(struct context *context, struct renderer *render)
550{
551	snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
552	int i, j, num, dev_num;
553	const char **list, **dev_list, *verb, *comment;
554	char buf[256];
555
556	num = snd_use_case_verb_list(uc_mgr, &list);
557	if (num < 0) {
558		fprintf(stderr, "%s: no verbs found\n", context->command);
559		return;
560	}
561	if (render->init && render->init(render))
562		goto __end;
563	for (i = 0; i < num; i += 2) {
564		/* verb */
565		verb = list[i + 0];
566		comment = list[i + 1];
567		if (render->verb_begin(render, verb, comment))
568			break;
569		/* devices */
570		snprintf(buf, sizeof(buf), "_devices/%s", verb);
571		dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
572		if (dev_num < 0) {
573			fprintf(stderr, "%s: unable to get devices for verb '%s'\n",
574							context->command, verb);
575			continue;
576		}
577		if (dev_num == 0)
578			goto __mods;
579		if (render->device_block_begin && render->device_block_begin(render)) {
580			snd_use_case_free_list(dev_list, dev_num);
581			goto __end;
582		}
583		for (j = 0; j < dev_num; j += 2) {
584			render->device_begin(render, dev_list[j + 0], dev_list[j + 1]);
585			if (render_device(context, render, verb, dev_list[j + 0])) {
586				snd_use_case_free_list(dev_list, dev_num);
587				goto __end;
588			}
589			render->device_end(render);
590		}
591		snd_use_case_free_list(dev_list, dev_num);
592		if (render->device_block_end && render->device_block_end(render))
593			goto __end;
594__mods:
595		/* modifiers */
596		snprintf(buf, sizeof(buf), "_modifiers/%s", verb);
597		dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
598		if (dev_num < 0) {
599			fprintf(stderr, "%s: unable to get modifiers for verb '%s'\n",
600							context->command, verb);
601			continue;
602		}
603		if (dev_num == 0)
604			goto __verb_end;
605		if (render->modifier_block_begin && render->modifier_block_begin(render)) {
606			snd_use_case_free_list(dev_list, dev_num);
607			goto __end;
608		}
609		for (j = 0; j < dev_num; j += 2) {
610			render->modifier_begin(render, dev_list[j + 0], dev_list[j + 1]);
611			render->modifier_end(render);
612		}
613		snd_use_case_free_list(dev_list, dev_num);
614		if (render->modifier_block_end && render->modifier_block_end(render))
615			goto __end;
616__verb_end:
617		/* end */
618		if (render->verb_end(render))
619			break;
620	}
621	if (render->done)
622		render->done(render);
623__end:
624	snd_use_case_free_list(list, num);
625}
626
627void dump(struct context *context, const char *format)
628{
629	struct renderer r;
630	struct text t;
631	struct json j;
632
633	r.opaque = NULL;
634	if (strcasecmp(format, "text") == 0 ||
635	    strcasecmp(format, "txt") == 0) {
636		memset(&t, 0, sizeof(t));
637		r = text_renderer;
638		r.opaque = &t;
639	} else if (strcasecmp(format, "json") == 0) {
640		memset(&j, 0, sizeof(j));
641		r = json_renderer;
642		r.opaque = &j;
643	}
644	if (r.opaque != NULL) {
645		render(context, &r);
646		return;
647	}
648	fprintf(stderr, "%s: unknown dump format '%s'\n",
649					context->command, format);
650}
651