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