mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-09 23:55:42 +01:00
alsaucm: add json dump command
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
860ffda825
commit
49716fa61e
2 changed files with 249 additions and 4 deletions
251
alsaucm/dump.c
251
alsaucm/dump.c
|
@ -32,10 +32,14 @@ struct renderer {
|
||||||
const char *verb,
|
const char *verb,
|
||||||
const char *comment);
|
const char *comment);
|
||||||
int (*verb_end)(struct renderer *r);
|
int (*verb_end)(struct renderer *r);
|
||||||
|
int (*device_block_begin)(struct renderer *r);
|
||||||
|
int (*device_block_end)(struct renderer *r);
|
||||||
int (*device_begin)(struct renderer *r,
|
int (*device_begin)(struct renderer *r,
|
||||||
const char *device,
|
const char *device,
|
||||||
const char *comment);
|
const char *comment);
|
||||||
int (*device_end)(struct renderer *r);
|
int (*device_end)(struct renderer *r);
|
||||||
|
int (*modifier_block_begin)(struct renderer *r);
|
||||||
|
int (*modifier_block_end)(struct renderer *r);
|
||||||
int (*modifier_begin)(struct renderer *r,
|
int (*modifier_begin)(struct renderer *r,
|
||||||
const char *device,
|
const char *device,
|
||||||
const char *comment);
|
const char *comment);
|
||||||
|
@ -52,6 +56,10 @@ struct renderer {
|
||||||
void *opaque;
|
void *opaque;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text renderer
|
||||||
|
*/
|
||||||
|
|
||||||
struct text {
|
struct text {
|
||||||
char a[1];
|
char a[1];
|
||||||
};
|
};
|
||||||
|
@ -177,12 +185,12 @@ static int text_con_start(struct renderer *r)
|
||||||
|
|
||||||
static int text_value_begin(struct renderer *r)
|
static int text_value_begin(struct renderer *r)
|
||||||
{
|
{
|
||||||
return text_2nd_level(r, "Values [\n");
|
return text_2nd_level(r, "Values {\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int text_value_end(struct renderer *r)
|
static int text_value_end(struct renderer *r)
|
||||||
{
|
{
|
||||||
return text_2nd_level(r, "]\n");
|
return text_2nd_level(r, "}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int text_value(struct renderer *r, const char *ident, const char *value)
|
static int text_value(struct renderer *r, const char *ident, const char *value)
|
||||||
|
@ -217,6 +225,220 @@ static struct renderer text_renderer = {
|
||||||
.value = text_value,
|
.value = text_value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JSON renderer
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct json {
|
||||||
|
int block[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *jesc(const char *s, char *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
char *dst = buf;
|
||||||
|
char c = '"';
|
||||||
|
*dst++ = c;
|
||||||
|
buf_len--;
|
||||||
|
while (*s && buf_len > 2) {
|
||||||
|
if (*s == '\"') {
|
||||||
|
if (buf_len > 3) {
|
||||||
|
*dst++ = '"';
|
||||||
|
*dst++ = *s++;
|
||||||
|
buf_len -= 2;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dst++ = *s++;
|
||||||
|
}
|
||||||
|
*dst++ = c;
|
||||||
|
*dst = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JESC(s, esc) jesc((s), (esc), sizeof(esc))
|
||||||
|
|
||||||
|
static void json_block(struct renderer *r, int level, int last)
|
||||||
|
{
|
||||||
|
struct json *j = r->opaque;
|
||||||
|
printf((j->block[level] && !last) ? ",\n" : "\n");
|
||||||
|
j->block[level] = last ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_init(struct renderer *r)
|
||||||
|
{
|
||||||
|
printf("{\n \"Verbs\": {");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_done(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 0, 1);
|
||||||
|
printf(" }\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_verb_start(struct renderer *r, const char *verb, const char *comment)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
json_block(r, 0, 0);
|
||||||
|
printf(" %s: {", JESC(verb, buf));
|
||||||
|
if (comment && comment[0]) {
|
||||||
|
json_block(r, 1, 0);
|
||||||
|
printf(" \"Comment\": %s", JESC(comment, buf));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_verb_end(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 1, 1);
|
||||||
|
printf(" }");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_2nd_level_block_end(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 2, 1);
|
||||||
|
printf(" }");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_2nd_level_begin(struct renderer *r,
|
||||||
|
const char *val,
|
||||||
|
const char *comment)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
json_block(r, 2, 0);
|
||||||
|
printf(" %s: {", JESC(val, buf));
|
||||||
|
if (comment && comment[0]) {
|
||||||
|
json_block(r, 3, 0);
|
||||||
|
printf(" \"Comment\": %s", JESC(comment, buf));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_2nd_level_end(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 3, 1);
|
||||||
|
printf(" }");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_2nd_level(struct renderer *r, const char *txt)
|
||||||
|
{
|
||||||
|
printf(" %s", txt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_3rd_level(struct renderer *r, const char *txt)
|
||||||
|
{
|
||||||
|
printf(" %s", txt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_dev_block_start(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 1, 0);
|
||||||
|
printf(" \"Devices\": {");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_mod_block_start(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 1, 0);
|
||||||
|
printf(" \"Modifiers\": {");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_supcon_start(struct renderer *r, const char *key)
|
||||||
|
{
|
||||||
|
json_block(r, 3, 0);
|
||||||
|
if (json_2nd_level(r, key))
|
||||||
|
return 1;
|
||||||
|
printf(": [");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_supcon_value(struct renderer *r, const char *value, int last)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
JESC(value, buf);
|
||||||
|
json_block(r, 4, 0);
|
||||||
|
return json_3rd_level(r, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_supcon_end(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 4, 1);
|
||||||
|
return json_2nd_level(r, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_sup_start(struct renderer *r)
|
||||||
|
{
|
||||||
|
return json_supcon_start(r, "\"SupportedDevices\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_con_start(struct renderer *r)
|
||||||
|
{
|
||||||
|
return json_supcon_start(r, "\"ConflictingDevices\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_value_begin(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 3, 0);
|
||||||
|
return json_2nd_level(r, "\"Values\": {");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_value_end(struct renderer *r)
|
||||||
|
{
|
||||||
|
json_block(r, 4, 1);
|
||||||
|
return json_2nd_level(r, "}");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_value(struct renderer *r, const char *ident, const char *value)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
int err;
|
||||||
|
|
||||||
|
json_block(r, 4, 0);
|
||||||
|
JESC(ident, buf);
|
||||||
|
err = json_3rd_level(r, buf);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
JESC(value, buf);
|
||||||
|
printf(": %s", buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct renderer json_renderer = {
|
||||||
|
.init = json_init,
|
||||||
|
.done = json_done,
|
||||||
|
.verb_begin = json_verb_start,
|
||||||
|
.verb_end = json_verb_end,
|
||||||
|
.device_block_begin = json_dev_block_start,
|
||||||
|
.device_block_end = json_2nd_level_block_end,
|
||||||
|
.device_begin = json_2nd_level_begin,
|
||||||
|
.device_end = json_2nd_level_end,
|
||||||
|
.modifier_block_begin = json_mod_block_start,
|
||||||
|
.modifier_block_end = json_2nd_level_block_end,
|
||||||
|
.modifier_begin = json_2nd_level_begin,
|
||||||
|
.modifier_end = json_2nd_level_end,
|
||||||
|
.supported_begin = json_sup_start,
|
||||||
|
.supported_value = json_supcon_value,
|
||||||
|
.supported_end = json_supcon_end,
|
||||||
|
.conflict_begin = json_con_start,
|
||||||
|
.conflict_value = json_supcon_value,
|
||||||
|
.conflict_end = json_supcon_end,
|
||||||
|
.value_begin = json_value_begin,
|
||||||
|
.value_end = json_value_end,
|
||||||
|
.value = json_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* universal dump functions
|
||||||
|
*/
|
||||||
|
|
||||||
static int render_devlist(struct context *context,
|
static int render_devlist(struct context *context,
|
||||||
struct renderer *render,
|
struct renderer *render,
|
||||||
const char *verb,
|
const char *verb,
|
||||||
|
@ -350,6 +572,12 @@ static void render(struct context *context, struct renderer *render)
|
||||||
context->command, verb);
|
context->command, verb);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (dev_num == 0)
|
||||||
|
goto __mods;
|
||||||
|
if (render->device_block_begin && render->device_block_begin(render)) {
|
||||||
|
snd_use_case_free_list(dev_list, dev_num);
|
||||||
|
goto __end;
|
||||||
|
}
|
||||||
for (j = 0; j < dev_num; j += 2) {
|
for (j = 0; j < dev_num; j += 2) {
|
||||||
render->device_begin(render, dev_list[j + 0], dev_list[j + 1]);
|
render->device_begin(render, dev_list[j + 0], dev_list[j + 1]);
|
||||||
if (render_device(context, render, verb, dev_list[j + 0])) {
|
if (render_device(context, render, verb, dev_list[j + 0])) {
|
||||||
|
@ -359,6 +587,9 @@ static void render(struct context *context, struct renderer *render)
|
||||||
render->device_end(render);
|
render->device_end(render);
|
||||||
}
|
}
|
||||||
snd_use_case_free_list(dev_list, dev_num);
|
snd_use_case_free_list(dev_list, dev_num);
|
||||||
|
if (render->device_block_end && render->device_block_end(render))
|
||||||
|
goto __end;
|
||||||
|
__mods:
|
||||||
/* modifiers */
|
/* modifiers */
|
||||||
snprintf(buf, sizeof(buf), "_modifiers/%s", verb);
|
snprintf(buf, sizeof(buf), "_modifiers/%s", verb);
|
||||||
dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
|
dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
|
||||||
|
@ -367,11 +598,20 @@ static void render(struct context *context, struct renderer *render)
|
||||||
context->command, verb);
|
context->command, verb);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (dev_num == 0)
|
||||||
|
goto __verb_end;
|
||||||
|
if (render->modifier_block_begin && render->modifier_block_begin(render)) {
|
||||||
|
snd_use_case_free_list(dev_list, dev_num);
|
||||||
|
goto __end;
|
||||||
|
}
|
||||||
for (j = 0; j < dev_num; j += 2) {
|
for (j = 0; j < dev_num; j += 2) {
|
||||||
render->modifier_begin(render, dev_list[j + 0], dev_list[j + 1]);
|
render->modifier_begin(render, dev_list[j + 0], dev_list[j + 1]);
|
||||||
render->modifier_end(render);
|
render->modifier_end(render);
|
||||||
}
|
}
|
||||||
snd_use_case_free_list(dev_list, dev_num);
|
snd_use_case_free_list(dev_list, dev_num);
|
||||||
|
if (render->modifier_block_end && render->modifier_block_end(render))
|
||||||
|
goto __end;
|
||||||
|
__verb_end:
|
||||||
/* end */
|
/* end */
|
||||||
if (render->verb_end(render))
|
if (render->verb_end(render))
|
||||||
break;
|
break;
|
||||||
|
@ -385,14 +625,19 @@ __end:
|
||||||
void dump(struct context *context, const char *format)
|
void dump(struct context *context, const char *format)
|
||||||
{
|
{
|
||||||
struct renderer r;
|
struct renderer r;
|
||||||
|
struct text t;
|
||||||
|
struct json j;
|
||||||
|
|
||||||
r.opaque = NULL;
|
r.opaque = NULL;
|
||||||
if (strcasecmp(format, "text") == 0 ||
|
if (strcasecmp(format, "text") == 0 ||
|
||||||
strcasecmp(format, "txt") == 0) {
|
strcasecmp(format, "txt") == 0) {
|
||||||
struct text t;
|
|
||||||
memset(&t, 0, sizeof(t));
|
memset(&t, 0, sizeof(t));
|
||||||
r = text_renderer;
|
r = text_renderer;
|
||||||
r.opaque = &t;
|
r.opaque = &t;
|
||||||
|
} else if (strcasecmp(format, "json") == 0) {
|
||||||
|
memset(&j, 0, sizeof(j));
|
||||||
|
r = json_renderer;
|
||||||
|
r.opaque = &j;
|
||||||
}
|
}
|
||||||
if (r.opaque != NULL) {
|
if (r.opaque != NULL) {
|
||||||
render(context, &r);
|
render(context, &r);
|
||||||
|
|
|
@ -108,7 +108,7 @@ static void dump_help(struct context *context)
|
||||||
" reset reset sound card to default state\n"
|
" reset reset sound card to default state\n"
|
||||||
" reload reload configuration\n"
|
" reload reload configuration\n"
|
||||||
" listcards list available cards\n"
|
" listcards list available cards\n"
|
||||||
" dump FORMAT dump all config information (format: text)\n"
|
" dump FORMAT dump all config information (format: text,json)\n"
|
||||||
" list IDENTIFIER list command, for items with value + comment\n"
|
" list IDENTIFIER list command, for items with value + comment\n"
|
||||||
" list1 IDENTIFIER list command, for items without comments\n"
|
" list1 IDENTIFIER list command, for items without comments\n"
|
||||||
" get IDENTIFIER get string value\n"
|
" get IDENTIFIER get string value\n"
|
||||||
|
|
Loading…
Reference in a new issue