• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,const char * verb,const char * comment)96 static int text_verb_start(struct renderer *r, const char *verb, const char *comment)
97 {
98 	char buf1[128], buf2[128];
99 	printf("Verb.%s {\n", ESC(verb, buf1));
100 	if (comment && comment[0])
101 		printf("\tComment %s\n", ESC(comment, buf2));
102 	return 0;
103 }
104 
text_verb_end(struct renderer * r)105 static int text_verb_end(struct renderer *r)
106 {
107 	printf("}\n");
108 	return 0;
109 }
110 
text_2nd_level_begin(struct renderer * r,const char * key,const char * val,const char * comment)111 static int text_2nd_level_begin(struct renderer *r,
112 				const char *key,
113 				const char *val,
114 				const char *comment)
115 {
116 	char buf1[128], buf2[128];
117 	printf("\t%s.%s {\n", key, ESC(val, buf1));
118 	if (comment && comment[0])
119 		printf("\t\tComment %s\n", ESC(comment, buf2));
120 	return 0;
121 }
122 
text_2nd_level_end(struct renderer * r)123 static int text_2nd_level_end(struct renderer *r)
124 {
125 	printf("\t}\n");
126 	return 0;
127 }
128 
text_2nd_level(struct renderer * r,const char * txt)129 static int text_2nd_level(struct renderer *r, const char *txt)
130 {
131 	printf("\t\t%s", txt);
132 	return 0;
133 }
134 
text_3rd_level(struct renderer * r,const char * txt)135 static int text_3rd_level(struct renderer *r, const char *txt)
136 {
137 	printf("\t\t\t%s", txt);
138 	return 0;
139 }
140 
text_dev_start(struct renderer * r,const char * dev,const char * comment)141 static int text_dev_start(struct renderer *r, const char *dev, const char *comment)
142 {
143 	return text_2nd_level_begin(r, "Device", dev, comment);
144 }
145 
text_mod_start(struct renderer * r,const char * dev,const char * comment)146 static int text_mod_start(struct renderer *r, const char *dev, const char *comment)
147 {
148 	return text_2nd_level_begin(r, "Modifier", dev, comment);
149 }
150 
text_supcon_start(struct renderer * r,const char * key)151 static int text_supcon_start(struct renderer *r, const char *key)
152 {
153 	if (text_2nd_level(r, key))
154 		return 1;
155 	printf(" [\n");
156 	return 0;
157 }
158 
text_supcon_value(struct renderer * r,const char * value,int last)159 static int text_supcon_value(struct renderer *r, const char *value, int last)
160 {
161 	char buf[256];
162 	ESC(value, buf);
163 	if (!last && strlen(buf) < sizeof(buf) - 2)
164 		strcat(buf, ",");
165 	if (text_3rd_level(r, buf))
166 		return 1;
167 	printf("\n");
168 	return 0;
169 }
170 
text_supcon_end(struct renderer * r)171 static int text_supcon_end(struct renderer *r)
172 {
173 	return text_2nd_level(r, "]\n");
174 }
175 
text_sup_start(struct renderer * r)176 static int text_sup_start(struct renderer *r)
177 {
178 	return text_supcon_start(r, "SupportedDevices");
179 }
180 
text_con_start(struct renderer * r)181 static int text_con_start(struct renderer *r)
182 {
183 	return text_supcon_start(r, "ConflictingDevices");
184 }
185 
text_value_begin(struct renderer * r)186 static int text_value_begin(struct renderer *r)
187 {
188 	return text_2nd_level(r, "Values {\n");
189 }
190 
text_value_end(struct renderer * r)191 static int text_value_end(struct renderer *r)
192 {
193 	return text_2nd_level(r, "}\n");
194 }
195 
text_value(struct renderer * r,const char * ident,const char * value)196 static int text_value(struct renderer *r, const char *ident, const char *value)
197 {
198 	char buf1[256], buf2[256];
199 	int err;
200 
201 	ESC(ident, buf1);
202 	err = text_3rd_level(r, buf1);
203 	if (err < 0)
204 		return err;
205 	ESC(value, buf2);
206 	printf(" %s\n", buf2);
207 	return 0;
208 }
209 
210 static struct renderer text_renderer = {
211 	.verb_begin = text_verb_start,
212 	.verb_end = text_verb_end,
213 	.device_begin = text_dev_start,
214 	.device_end = text_2nd_level_end,
215 	.modifier_begin = text_mod_start,
216 	.modifier_end = text_2nd_level_end,
217 	.supported_begin = text_sup_start,
218 	.supported_value = text_supcon_value,
219 	.supported_end = text_supcon_end,
220 	.conflict_begin = text_con_start,
221 	.conflict_value = text_supcon_value,
222 	.conflict_end = text_supcon_end,
223 	.value_begin = text_value_begin,
224 	.value_end = text_value_end,
225 	.value = text_value,
226 };
227 
228 /*
229  * JSON renderer
230  */
231 
232 struct json {
233 	int block[5];
234 };
235 
jesc(const char * s,char * buf,size_t buf_len)236 static char *jesc(const char *s, char *buf, size_t buf_len)
237 {
238 	char *dst = buf;
239 	char c = '"';
240 	*dst++ = c;
241 	buf_len--;
242 	while (*s && buf_len > 2) {
243 		if (*s == '"') {
244 			if (buf_len > 3) {
245 				*dst++ = '\\';
246 				*dst++ = *s++;
247 				buf_len -= 2;
248 				continue;
249 			} else {
250 				break;
251 			}
252 		}
253 		*dst++ = *s++;
254 	}
255 	*dst++ = c;
256 	*dst = '\0';
257 	return buf;
258 }
259 
260 #define JESC(s, esc) jesc((s), (esc), sizeof(esc))
261 
json_block(struct renderer * r,int level,int last)262 static void json_block(struct renderer *r, int level, int last)
263 {
264 	struct json *j = r->opaque;
265 	printf((j->block[level] && !last) ? ",\n" : "\n");
266 	j->block[level] = last ? 0 : 1;
267 }
268 
json_init(struct renderer * r)269 static int json_init(struct renderer *r)
270 {
271 	printf("{\n  \"Verbs\": {");
272 	return 0;
273 }
274 
json_done(struct renderer * r)275 static void json_done(struct renderer *r)
276 {
277 	json_block(r, 0, 1);
278 	printf("  }\n}\n");
279 }
280 
json_verb_start(struct renderer * r,const char * verb,const char * comment)281 static int json_verb_start(struct renderer *r, const char *verb, const char *comment)
282 {
283 	char buf[256];
284 	json_block(r, 0, 0);
285 	printf("    %s: {", JESC(verb, buf));
286 	if (comment && comment[0]) {
287 		json_block(r, 1, 0);
288 		printf("      \"Comment\": %s", JESC(comment, buf));
289 	}
290 	return 0;
291 }
292 
json_verb_end(struct renderer * r)293 static int json_verb_end(struct renderer *r)
294 {
295 	json_block(r, 1, 1);
296 	printf("    }");
297 	return 0;
298 }
299 
json_2nd_level_block_end(struct renderer * r)300 static int json_2nd_level_block_end(struct renderer *r)
301 {
302 	json_block(r, 2, 1);
303 	printf("      }");
304 	return 0;
305 }
306 
json_2nd_level_begin(struct renderer * r,const char * val,const char * comment)307 static int json_2nd_level_begin(struct renderer *r,
308 				const char *val,
309 				const char *comment)
310 {
311 	char buf[256];
312 	json_block(r, 2, 0);
313 	printf("        %s: {", JESC(val, buf));
314 	if (comment && comment[0]) {
315 		json_block(r, 3, 0);
316 		printf("          \"Comment\": %s", JESC(comment, buf));
317 	}
318 	return 0;
319 }
320 
json_2nd_level_end(struct renderer * r)321 static int json_2nd_level_end(struct renderer *r)
322 {
323 	json_block(r, 3, 1);
324 	printf("        }");
325 	return 0;
326 }
327 
json_2nd_level(struct renderer * r,const char * txt)328 static int json_2nd_level(struct renderer *r, const char *txt)
329 {
330 	printf("          %s", txt);
331 	return 0;
332 }
333 
json_3rd_level(struct renderer * r,const char * txt)334 static int json_3rd_level(struct renderer *r, const char *txt)
335 {
336 	printf("            %s", txt);
337 	return 0;
338 }
339 
json_dev_block_start(struct renderer * r)340 static int json_dev_block_start(struct renderer *r)
341 {
342 	json_block(r, 1, 0);
343 	printf("      \"Devices\": {");
344 	return 0;
345 }
346 
json_mod_block_start(struct renderer * r)347 static int json_mod_block_start(struct renderer *r)
348 {
349 	json_block(r, 1, 0);
350 	printf("      \"Modifiers\": {");
351 	return 0;
352 }
353 
json_supcon_start(struct renderer * r,const char * key)354 static int json_supcon_start(struct renderer *r, const char *key)
355 {
356 	json_block(r, 3, 0);
357 	if (json_2nd_level(r, key))
358 		return 1;
359 	printf(": [");
360 	return 0;
361 }
362 
json_supcon_value(struct renderer * r,const char * value,int last)363 static int json_supcon_value(struct renderer *r, const char *value, int last)
364 {
365 	char buf[256];
366 	JESC(value, buf);
367 	json_block(r, 4, 0);
368 	return json_3rd_level(r, buf);
369 }
370 
json_supcon_end(struct renderer * r)371 static int json_supcon_end(struct renderer *r)
372 {
373 	json_block(r, 4, 1);
374 	return json_2nd_level(r, "]");
375 }
376 
json_sup_start(struct renderer * r)377 static int json_sup_start(struct renderer *r)
378 {
379 	return json_supcon_start(r, "\"SupportedDevices\"");
380 }
381 
json_con_start(struct renderer * r)382 static int json_con_start(struct renderer *r)
383 {
384 	return json_supcon_start(r, "\"ConflictingDevices\"");
385 }
386 
json_value_begin(struct renderer * r)387 static int json_value_begin(struct renderer *r)
388 {
389 	json_block(r, 3, 0);
390 	return json_2nd_level(r, "\"Values\": {");
391 }
392 
json_value_end(struct renderer * r)393 static int json_value_end(struct renderer *r)
394 {
395 	json_block(r, 4, 1);
396 	return json_2nd_level(r, "}");
397 }
398 
json_value(struct renderer * r,const char * ident,const char * value)399 static int json_value(struct renderer *r, const char *ident, const char *value)
400 {
401 	char buf[256];
402 	int err;
403 
404 	json_block(r, 4, 0);
405 	JESC(ident, buf);
406 	err = json_3rd_level(r, buf);
407 	if (err < 0)
408 		return err;
409 	JESC(value, buf);
410 	printf(": %s", buf);
411 	return 0;
412 }
413 
414 static struct renderer json_renderer = {
415 	.init = json_init,
416 	.done = json_done,
417 	.verb_begin = json_verb_start,
418 	.verb_end = json_verb_end,
419 	.device_block_begin = json_dev_block_start,
420 	.device_block_end = json_2nd_level_block_end,
421 	.device_begin = json_2nd_level_begin,
422 	.device_end = json_2nd_level_end,
423 	.modifier_block_begin = json_mod_block_start,
424 	.modifier_block_end = json_2nd_level_block_end,
425 	.modifier_begin = json_2nd_level_begin,
426 	.modifier_end = json_2nd_level_end,
427 	.supported_begin = json_sup_start,
428 	.supported_value = json_supcon_value,
429 	.supported_end = json_supcon_end,
430 	.conflict_begin = json_con_start,
431 	.conflict_value = json_supcon_value,
432 	.conflict_end = json_supcon_end,
433 	.value_begin = json_value_begin,
434 	.value_end = json_value_end,
435 	.value = json_value,
436 };
437 
438 /*
439  * universal dump functions
440  */
441 
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 *))442 static int render_devlist(struct context *context,
443 			  struct renderer *render,
444 			  const char *verb,
445 			  const char *device,
446 			  const char *list,
447 			  int (*begin)(struct renderer *),
448 			  int (*value)(struct renderer *, const char *value, int last),
449 			  int (*end)(struct renderer *))
450 {
451 	snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
452 	const char **dev_list;
453 	char buf[256];
454 	int err = 0, j, dev_num;
455 
456 	snprintf(buf, sizeof(buf), "%s/%s/%s", list, device, verb);
457 	dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
458 	if (dev_num < 0) {
459 		fprintf(stderr, "%s: unable to get %s for verb '%s' for device '%s'\n",
460 			context->command, list, verb, device);
461 		return dev_num;
462 	}
463 	if (dev_num > 0) {
464 		err = begin(render);
465 		if (err < 0)
466 			goto __err;
467 		for (j = 0; j < dev_num; j++) {
468 			err = value(render, dev_list[j], j + 1 == dev_num);
469 			if (err < 0)
470 				goto __err;
471 		}
472 		err = end(render);
473 	}
474 __err:
475 	snd_use_case_free_list(dev_list, dev_num);
476 	return err;
477 }
478 
render_values(struct context * context,struct renderer * render,const char * verb,const char * device)479 static int render_values(struct context *context,
480 			 struct renderer *render,
481 			 const char *verb,
482 			 const char *device)
483 {
484 	snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
485 	const char **list, *value;
486 	char buf[256];
487 	int err = 0, j, num;
488 
489 	snprintf(buf, sizeof(buf), "_identifiers/%s/%s", device, verb);
490 	num = snd_use_case_get_list(uc_mgr, buf, &list);
491 	if (num < 0) {
492 		fprintf(stderr, "%s: unable to get _identifiers for verb '%s' for device '%s': %s\n",
493 			context->command, verb, device, snd_strerror(num));
494 		return num;
495 	}
496 	if (num == 0)
497 		goto __err;
498 	if (render->value_begin) {
499 		err = render->value_begin(render);
500 		if (err < 0)
501 			goto __err;
502 	}
503 	for (j = 0; j < num; j++) {
504 		snprintf(buf, sizeof(buf), "%s/%s/%s", list[j], device, verb);
505 		err = snd_use_case_get(uc_mgr, buf, &value);
506 		if (err < 0) {
507 			fprintf(stderr, "%s: unable to get value '%s' for verb '%s' for device '%s': %s\n",
508 				context->command, list[j], verb, device, snd_strerror(err));
509 			goto __err;
510 		}
511 		err = render->value(render, list[j], value);
512 		free((char *)value);
513 		if (err < 0)
514 			goto __err;
515 	}
516 	if (render->value_end)
517 		err = render->value_end(render);
518 __err:
519 	snd_use_case_free_list(list, num);
520 	return err;
521 }
522 
render_device(struct context * context,struct renderer * render,const char * verb,const char * device)523 static int render_device(struct context *context,
524 			 struct renderer *render,
525 			 const char *verb,
526 			 const char *device)
527 {
528 	int err;
529 
530 	err = render_devlist(context, render, verb, device,
531 			     "_supporteddevs",
532 			     render->supported_begin,
533 			     render->supported_value,
534 			     render->supported_end);
535 	if (err < 0)
536 		return err;
537 	err = render_devlist(context, render, verb, device,
538 			     "_conflictingdevs",
539 			     render->conflict_begin,
540 			     render->conflict_value,
541 			     render->conflict_end);
542 	if (err < 0)
543 		return err;
544 	return render_values(context, render, verb, device);
545 }
546 
render(struct context * context,struct renderer * render)547 static void render(struct context *context, struct renderer *render)
548 {
549 	snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
550 	int i, j, num, dev_num;
551 	const char **list, **dev_list, *verb, *comment;
552 	char buf[256];
553 
554 	num = snd_use_case_verb_list(uc_mgr, &list);
555 	if (num < 0) {
556 		fprintf(stderr, "%s: no verbs found\n", context->command);
557 		return;
558 	}
559 	if (render->init && render->init(render))
560 		goto __end;
561 	for (i = 0; i < num; i += 2) {
562 		/* verb */
563 		verb = list[i + 0];
564 		comment = list[i + 1];
565 		if (render->verb_begin(render, verb, comment))
566 			break;
567 		/* devices */
568 		snprintf(buf, sizeof(buf), "_devices/%s", verb);
569 		dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
570 		if (dev_num < 0) {
571 			fprintf(stderr, "%s: unable to get devices for verb '%s'\n",
572 							context->command, verb);
573 			continue;
574 		}
575 		if (dev_num == 0)
576 			goto __mods;
577 		if (render->device_block_begin && render->device_block_begin(render)) {
578 			snd_use_case_free_list(dev_list, dev_num);
579 			goto __end;
580 		}
581 		for (j = 0; j < dev_num; j += 2) {
582 			render->device_begin(render, dev_list[j + 0], dev_list[j + 1]);
583 			if (render_device(context, render, verb, dev_list[j + 0])) {
584 				snd_use_case_free_list(dev_list, dev_num);
585 				goto __end;
586 			}
587 			render->device_end(render);
588 		}
589 		snd_use_case_free_list(dev_list, dev_num);
590 		if (render->device_block_end && render->device_block_end(render))
591 			goto __end;
592 __mods:
593 		/* modifiers */
594 		snprintf(buf, sizeof(buf), "_modifiers/%s", verb);
595 		dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
596 		if (dev_num < 0) {
597 			fprintf(stderr, "%s: unable to get modifiers for verb '%s'\n",
598 							context->command, verb);
599 			continue;
600 		}
601 		if (dev_num == 0)
602 			goto __verb_end;
603 		if (render->modifier_block_begin && render->modifier_block_begin(render)) {
604 			snd_use_case_free_list(dev_list, dev_num);
605 			goto __end;
606 		}
607 		for (j = 0; j < dev_num; j += 2) {
608 			render->modifier_begin(render, dev_list[j + 0], dev_list[j + 1]);
609 			render->modifier_end(render);
610 		}
611 		snd_use_case_free_list(dev_list, dev_num);
612 		if (render->modifier_block_end && render->modifier_block_end(render))
613 			goto __end;
614 __verb_end:
615 		/* end */
616 		if (render->verb_end(render))
617 			break;
618 	}
619 	if (render->done)
620 		render->done(render);
621 __end:
622 	snd_use_case_free_list(list, num);
623 }
624 
dump(struct context * context,const char * format)625 void dump(struct context *context, const char *format)
626 {
627 	struct renderer r;
628 	struct text t;
629 	struct json j;
630 
631 	r.opaque = NULL;
632 	if (strcasecmp(format, "text") == 0 ||
633 	    strcasecmp(format, "txt") == 0) {
634 		memset(&t, 0, sizeof(t));
635 		r = text_renderer;
636 		r.opaque = &t;
637 	} else if (strcasecmp(format, "json") == 0) {
638 		memset(&j, 0, sizeof(j));
639 		r = json_renderer;
640 		r.opaque = &j;
641 	}
642 	if (r.opaque != NULL) {
643 		render(context, &r);
644 		return;
645 	}
646 	fprintf(stderr, "%s: unknown dump format '%s'\n",
647 					context->command, format);
648 }
649