]> git.alsa-project.org Git - alsa-utils.git/commitdiff
alsaucm: add json dump command
authorJaroslav Kysela <perex@perex.cz>
Sat, 30 Nov 2019 19:30:33 +0000 (20:30 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sat, 30 Nov 2019 19:32:15 +0000 (20:32 +0100)
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
alsaucm/dump.c
alsaucm/usecase.c

index ae0af2f1f10857d4b13fbe8029b656b3dd1ad35e..bc638f1588e96c28d7c7ce2cf3a4d9133780a174 100644 (file)
@@ -32,10 +32,14 @@ struct renderer {
                          const char *verb,
                          const char *comment);
        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,
                            const char *device,
                            const char *comment);
        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,
                              const char *device,
                              const char *comment);
@@ -52,6 +56,10 @@ struct renderer {
        void *opaque;
 };
 
+/*
+ * Text renderer
+ */
+
 struct text {
        char a[1];
 };
@@ -177,12 +185,12 @@ static int text_con_start(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)
 {
-       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)
@@ -217,6 +225,220 @@ static struct renderer text_renderer = {
        .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,
                          struct renderer *render,
                          const char *verb,
@@ -350,6 +572,12 @@ static void render(struct context *context, struct renderer *render)
                                                        context->command, verb);
                        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) {
                        render->device_begin(render, dev_list[j + 0], dev_list[j + 1]);
                        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);
                }
                snd_use_case_free_list(dev_list, dev_num);
+               if (render->device_block_end && render->device_block_end(render))
+                       goto __end;
+__mods:
                /* modifiers */
                snprintf(buf, sizeof(buf), "_modifiers/%s", verb);
                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);
                        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) {
                        render->modifier_begin(render, dev_list[j + 0], dev_list[j + 1]);
                        render->modifier_end(render);
                }
                snd_use_case_free_list(dev_list, dev_num);
+               if (render->modifier_block_end && render->modifier_block_end(render))
+                       goto __end;
+__verb_end:
                /* end */
                if (render->verb_end(render))
                        break;
@@ -385,14 +625,19 @@ __end:
 void dump(struct context *context, const char *format)
 {
        struct renderer r;
+       struct text t;
+       struct json j;
 
        r.opaque = NULL;
        if (strcasecmp(format, "text") == 0 ||
            strcasecmp(format, "txt") == 0) {
-               struct text t;
                memset(&t, 0, sizeof(t));
                r = text_renderer;
                r.opaque = &t;
+       } else if (strcasecmp(format, "json") == 0) {
+               memset(&j, 0, sizeof(j));
+               r = json_renderer;
+               r.opaque = &j;
        }
        if (r.opaque != NULL) {
                render(context, &r);
index 44fc92bebfcdf134f95cad401cdc7a673b3f1978..1ed91ea56863b106da841841a6def0af73355fb9 100644 (file)
@@ -108,7 +108,7 @@ static void dump_help(struct context *context)
 "  reset                      reset sound card to default state\n"
 "  reload                     reload configuration\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"
 "  list1 IDENTIFIER           list command, for items without comments\n"
 "  get IDENTIFIER             get string value\n"