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 
28 struct 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 
63 struct text {
64 	char a[1];
65 };
66 
tesc(const char *s, char *buf, size_t buf_len)67 static 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 
text_verb_start(struct renderer *r ATTRIBUTE_UNUSED, const char *verb, const char *comment)96 static 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 
text_verb_end(struct renderer *r ATTRIBUTE_UNUSED)106 static int text_verb_end(struct renderer *r ATTRIBUTE_UNUSED)
107 {
108 	printf("}\n");
109 	return 0;
110 }
111 
text_2nd_level_begin(struct renderer *r ATTRIBUTE_UNUSED, const char *key, const char *val, const char *comment)112 static 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 
text_2nd_level_end(struct renderer *r ATTRIBUTE_UNUSED)124 static int text_2nd_level_end(struct renderer *r ATTRIBUTE_UNUSED)
125 {
126 	printf("\t}\n");
127 	return 0;
128 }
129 
text_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)130 static int text_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
131 {
132 	printf("\t\t%s", txt);
133 	return 0;
134 }
135 
text_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)136 static 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 
text_dev_start(struct renderer *r, const char *dev, const char *comment)142 static 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 
text_mod_start(struct renderer *r, const char *dev, const char *comment)147 static 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 
text_supcon_start(struct renderer *r, const char *key)152 static 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 
text_supcon_value(struct renderer *r, const char *value, int last)160 static 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 
text_supcon_end(struct renderer *r)172 static int text_supcon_end(struct renderer *r)
173 {
174 	return text_2nd_level(r, "]\n");
175 }
176 
text_sup_start(struct renderer *r)177 static int text_sup_start(struct renderer *r)
178 {
179 	return text_supcon_start(r, "SupportedDevices");
180 }
181 
text_con_start(struct renderer *r)182 static int text_con_start(struct renderer *r)
183 {
184 	return text_supcon_start(r, "ConflictingDevices");
185 }
186 
text_value_begin(struct renderer *r)187 static int text_value_begin(struct renderer *r)
188 {
189 	return text_2nd_level(r, "Values {\n");
190 }
191 
text_value_end(struct renderer *r)192 static int text_value_end(struct renderer *r)
193 {
194 	return text_2nd_level(r, "}\n");
195 }
196 
text_value(struct renderer *r, const char *ident, const char *value)197 static 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 
211 static 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 
233 struct json {
234 	int block[5];
235 };
236 
jesc(const char *s, char *buf, size_t buf_len)237 static 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 
json_block(struct renderer *r, int level, int last)263 static 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 
json_init(struct renderer *r ATTRIBUTE_UNUSED)270 static int json_init(struct renderer *r ATTRIBUTE_UNUSED)
271 {
272 	printf("{\n  \"Verbs\": {");
273 	return 0;
274 }
275 
json_done(struct renderer *r)276 static void json_done(struct renderer *r)
277 {
278 	json_block(r, 0, 1);
279 	printf("  }\n}\n");
280 }
281 
json_verb_start(struct renderer *r, const char *verb, const char *comment)282 static 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 
json_verb_end(struct renderer *r)294 static int json_verb_end(struct renderer *r)
295 {
296 	json_block(r, 1, 1);
297 	printf("    }");
298 	return 0;
299 }
300 
json_2nd_level_block_end(struct renderer *r)301 static int json_2nd_level_block_end(struct renderer *r)
302 {
303 	json_block(r, 2, 1);
304 	printf("      }");
305 	return 0;
306 }
307 
json_2nd_level_begin(struct renderer *r, const char *val, const char *comment)308 static 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 
json_2nd_level_end(struct renderer *r)322 static int json_2nd_level_end(struct renderer *r)
323 {
324 	json_block(r, 3, 1);
325 	printf("        }");
326 	return 0;
327 }
328 
json_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)329 static int json_2nd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
330 {
331 	printf("          %s", txt);
332 	return 0;
333 }
334 
json_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)335 static int json_3rd_level(struct renderer *r ATTRIBUTE_UNUSED, const char *txt)
336 {
337 	printf("            %s", txt);
338 	return 0;
339 }
340 
json_dev_block_start(struct renderer *r)341 static int json_dev_block_start(struct renderer *r)
342 {
343 	json_block(r, 1, 0);
344 	printf("      \"Devices\": {");
345 	return 0;
346 }
347 
json_mod_block_start(struct renderer *r)348 static int json_mod_block_start(struct renderer *r)
349 {
350 	json_block(r, 1, 0);
351 	printf("      \"Modifiers\": {");
352 	return 0;
353 }
354 
json_supcon_start(struct renderer *r, const char *key)355 static 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 
json_supcon_value(struct renderer *r, const char *value, int last ATTRIBUTE_UNUSED)364 static 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 
json_supcon_end(struct renderer *r)373 static int json_supcon_end(struct renderer *r)
374 {
375 	json_block(r, 4, 1);
376 	return json_2nd_level(r, "]");
377 }
378 
json_sup_start(struct renderer *r)379 static int json_sup_start(struct renderer *r)
380 {
381 	return json_supcon_start(r, "\"SupportedDevices\"");
382 }
383 
json_con_start(struct renderer *r)384 static int json_con_start(struct renderer *r)
385 {
386 	return json_supcon_start(r, "\"ConflictingDevices\"");
387 }
388 
json_value_begin(struct renderer *r)389 static int json_value_begin(struct renderer *r)
390 {
391 	json_block(r, 3, 0);
392 	return json_2nd_level(r, "\"Values\": {");
393 }
394 
json_value_end(struct renderer *r)395 static int json_value_end(struct renderer *r)
396 {
397 	json_block(r, 4, 1);
398 	return json_2nd_level(r, "}");
399 }
400 
json_value(struct renderer *r, const char *ident, const char *value)401 static 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 
416 static 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 
render_devlist(struct context *context, struct renderer *render, const char *verb, const char *device, const char *list, int (*begin)(struct renderer *), int (*value)(struct renderer *, const char *value, int last), int (*end)(struct renderer *))444 static 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 
render_values(struct context *context, struct renderer *render, const char *verb, const char *device)481 static 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 
render_device(struct context *context, struct renderer *render, const char *verb, const char *device)525 static 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 
render(struct context *context, struct renderer *render)549 static 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 
dump(struct context *context, const char *format)627 void 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