SHA256
1
0
forked from pool/alsa-utils
alsa-utils/0008-alsaucm-add-text-dump-command.patch

560 lines
15 KiB
Diff
Raw Normal View History

Accepting request 766332 from home:tiwai:branches:multimedia:libs - Backport upstream patches: A few portability fixes, alsaucm fixes and extensions, alsatplg minor fixes, alsa-info.sh extensions: 0001-treewide-sys-poll-to-poll.patch 0002-treewide-Fix-wrong-formats-on-32-bit.patch 0003-treewide-Fix-printf-formats.patch 0004-aplay-Adjust-buffer-sizes-to-fix-snprintf-warnings.patch 0005-aplay-Limit-VUMeter-progress-bar-to-100-for-negative.patch 0006-alsactl-sysfs-add-sys-kernel-uevent_seqnum-check-to-.patch 0007-alsaucm-use-the-first-sound-card-use-case-name-hw-CA.patch 0008-alsaucm-add-text-dump-command.patch 0009-alsaucm-add-json-dump-command.patch 0010-alsaucm-dump-fix-the-prefixed.patch 0011-alsactl-fix-sched-idle-set-it-really-to-SCHED_IDLE.patch 0012-configure-Fix-linking-of-alsatplg-with-the-older-lib.patch 0013-alsatplg-add-n-normalize-option.patch 0014-alsatplg-add-s-sort-and-fix-memory-leaks.patch 0015-alsatplg-fix-another-small-leak-in-normalize_config.patch 0016-alsa-info.sh-Consolidate-PCI-device-output.patch 0017-alsa-info.sh-Read-from-proc-modules-and-sort-the-res.patch 0018-alsa-info.sh-Simplify-iteration-over-cards-when-call.patch 0019-alsa-info.sh-Use-existing-function-to-print-ALSA-con.patch 0020-alsa-info.sh-Exit-script-after-writing-information-t.patch 0021-alsa-info.sh-Replace-gauge-with-infobox-for-upload-d.patch 0022-alsa-info.sh-Remove-progress-spinner-during-upload-w.patch 0023-alsa-info.sh-Condense-nested-commands-for-file-uploa.patch 0024-alsa-info.sh-Condense-nested-commands-for-formatting.patch 0025-alsa-info.sh-Perform-test-for-wget-earlier.patch 0026-alsa-info.sh-Warn-after-actual-upload-failure-do-not.patch OBS-URL: https://build.opensuse.org/request/show/766332 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa-utils?expand=0&rev=165
2020-01-22 15:28:06 +01:00
From 860ffda82518dad6018f877f58aed1485d49e3a0 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Wed, 27 Nov 2019 08:51:29 +0100
Subject: [PATCH 08/26] alsaucm: add text dump command
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
alsaucm/Makefile.am | 2 +-
alsaucm/dump.c | 403 ++++++++++++++++++++++++++++++++++++++++++++++++++++
alsaucm/usecase.c | 22 ++-
alsaucm/usecase.h | 35 +++++
4 files changed, 447 insertions(+), 15 deletions(-)
create mode 100644 alsaucm/dump.c
create mode 100644 alsaucm/usecase.h
diff --git a/alsaucm/Makefile.am b/alsaucm/Makefile.am
index 4b447dd6758a..03f99e030a88 100644
--- a/alsaucm/Makefile.am
+++ b/alsaucm/Makefile.am
@@ -5,7 +5,7 @@ if USE_RST2MAN
man_MANS = alsaucm.1
endif
-alsaucm_SOURCES = usecase.c
+alsaucm_SOURCES = usecase.c dump.c
AM_CPPFLAGS = \
-Wall -I$(top_srcdir)/include
diff --git a/alsaucm/dump.c b/alsaucm/dump.c
new file mode 100644
index 000000000000..ae0af2f1f108
--- /dev/null
+++ b/alsaucm/dump.c
@@ -0,0 +1,403 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2019 Red Hat Inc.
+ * Authors: Jaroslav Kysela <perex@perex.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <alsa/asoundlib.h>
+#include <alsa/use-case.h>
+#include "usecase.h"
+#include "aconfig.h"
+#include "version.h"
+
+struct renderer {
+ int (*init)(struct renderer *r);
+ void (*done)(struct renderer *r);
+ int (*verb_begin)(struct renderer *r,
+ const char *verb,
+ const char *comment);
+ int (*verb_end)(struct renderer *r);
+ int (*device_begin)(struct renderer *r,
+ const char *device,
+ const char *comment);
+ int (*device_end)(struct renderer *r);
+ int (*modifier_begin)(struct renderer *r,
+ const char *device,
+ const char *comment);
+ int (*modifier_end)(struct renderer *r);
+ int (*supported_begin)(struct renderer *r);
+ int (*supported_value)(struct renderer *r, const char *value, int last);
+ int (*supported_end)(struct renderer *r);
+ int (*conflict_begin)(struct renderer *r);
+ int (*conflict_value)(struct renderer *r, const char *value, int last);
+ int (*conflict_end)(struct renderer *r);
+ int (*value_begin)(struct renderer *r);
+ int (*value_end)(struct renderer *r);
+ int (*value)(struct renderer *r, const char *ident, const char *value);
+ void *opaque;
+};
+
+struct text {
+ char a[1];
+};
+
+static char *tesc(const char *s, char *buf, size_t buf_len)
+{
+ char *dst = buf;
+ char c = '\0';
+ if (strchr(s, '"') || strchr(s, ' ') || strchr(s, '.')) {
+ *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++;
+ }
+ if (c)
+ *dst++ = c;
+ *dst = '\0';
+ return buf;
+}
+
+#define ESC(s, esc) tesc((s), (esc), sizeof(esc))
+
+static int text_verb_start(struct renderer *r, const char *verb, const char *comment)
+{
+ char buf1[128], buf2[128];
+ printf("Verb.%s {\n", ESC(verb, buf1));
+ if (comment && comment[0])
+ printf("\tComment %s\n", ESC(comment, buf2));
+ return 0;
+}
+
+static int text_verb_end(struct renderer *r)
+{
+ printf("}\n");
+ return 0;
+}
+
+static int text_2nd_level_begin(struct renderer *r,
+ const char *key,
+ const char *val,
+ const char *comment)
+{
+ char buf1[128], buf2[128];
+ printf("\t%s.%s {\n", key, ESC(val, buf1));
+ if (comment && comment[0])
+ printf("\t\tComment %s\n", ESC(comment, buf2));
+ return 0;
+}
+
+static int text_2nd_level_end(struct renderer *r)
+{
+ printf("\t}\n");
+ return 0;
+}
+
+static int text_2nd_level(struct renderer *r, const char *txt)
+{
+ printf("\t\t%s", txt);
+ return 0;
+}
+
+static int text_3rd_level(struct renderer *r, const char *txt)
+{
+ printf("\t\t\t%s", txt);
+ return 0;
+}
+
+static int text_dev_start(struct renderer *r, const char *dev, const char *comment)
+{
+ return text_2nd_level_begin(r, "Device", dev, comment);
+}
+
+static int text_mod_start(struct renderer *r, const char *dev, const char *comment)
+{
+ return text_2nd_level_begin(r, "Modifier", dev, comment);
+}
+
+static int text_supcon_start(struct renderer *r, const char *key)
+{
+ if (text_2nd_level(r, key))
+ return 1;
+ printf(" [\n");
+ return 0;
+}
+
+static int text_supcon_value(struct renderer *r, const char *value, int last)
+{
+ char buf[256];
+ ESC(value, buf);
+ if (!last && strlen(buf) < sizeof(buf) - 2)
+ strcat(buf, ",");
+ if (text_3rd_level(r, buf))
+ return 1;
+ printf("\n");
+ return 0;
+}
+
+static int text_supcon_end(struct renderer *r)
+{
+ return text_2nd_level(r, "]\n");
+}
+
+static int text_sup_start(struct renderer *r)
+{
+ return text_supcon_start(r, "SupportedDevices");
+}
+
+static int text_con_start(struct renderer *r)
+{
+ return text_supcon_start(r, "ConflictingDevices");
+}
+
+static int text_value_begin(struct renderer *r)
+{
+ return text_2nd_level(r, "Values [\n");
+}
+
+static int text_value_end(struct renderer *r)
+{
+ return text_2nd_level(r, "]\n");
+}
+
+static int text_value(struct renderer *r, const char *ident, const char *value)
+{
+ char buf1[256], buf2[256];
+ int err;
+
+ ESC(ident, buf1);
+ err = text_3rd_level(r, buf1);
+ if (err < 0)
+ return err;
+ ESC(value, buf2);
+ printf(" %s\n", buf2);
+ return 0;
+}
+
+static struct renderer text_renderer = {
+ .verb_begin = text_verb_start,
+ .verb_end = text_verb_end,
+ .device_begin = text_dev_start,
+ .device_end = text_2nd_level_end,
+ .modifier_begin = text_mod_start,
+ .modifier_end = text_2nd_level_end,
+ .supported_begin = text_sup_start,
+ .supported_value = text_supcon_value,
+ .supported_end = text_supcon_end,
+ .conflict_begin = text_con_start,
+ .conflict_value = text_supcon_value,
+ .conflict_end = text_supcon_end,
+ .value_begin = text_value_begin,
+ .value_end = text_value_end,
+ .value = text_value,
+};
+
+static int 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 *))
+{
+ snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
+ const char **dev_list;
+ char buf[256];
+ int err = 0, j, dev_num;
+
+ snprintf(buf, sizeof(buf), "%s/%s/%s", list, device, verb);
+ dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
+ if (dev_num < 0) {
+ fprintf(stderr, "%s: unable to get %s for verb '%s' for device '%s'\n",
+ context->command, list, verb, device);
+ return dev_num;
+ }
+ if (dev_num > 0) {
+ err = begin(render);
+ if (err < 0)
+ goto __err;
+ for (j = 0; j < dev_num; j++) {
+ err = value(render, dev_list[j], j + 1 == dev_num);
+ if (err < 0)
+ goto __err;
+ }
+ err = end(render);
+ }
+__err:
+ snd_use_case_free_list(dev_list, dev_num);
+ return err;
+}
+
+static int render_values(struct context *context,
+ struct renderer *render,
+ const char *verb,
+ const char *device)
+{
+ snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
+ const char **list, *value;
+ char buf[256];
+ int err = 0, j, num;
+
+ snprintf(buf, sizeof(buf), "_identifiers/%s/%s", device, verb);
+ num = snd_use_case_get_list(uc_mgr, buf, &list);
+ if (num < 0) {
+ fprintf(stderr, "%s: unable to get _identifiers for verb '%s' for device '%s': %s\n",
+ context->command, verb, device, snd_strerror(num));
+ return num;
+ }
+ if (num == 0)
+ goto __err;
+ if (render->value_begin) {
+ err = render->value_begin(render);
+ if (err < 0)
+ goto __err;
+ }
+ for (j = 0; j < num; j++) {
+ snprintf(buf, sizeof(buf), "%s/%s/%s", list[j], device, verb);
+ err = snd_use_case_get(uc_mgr, buf, &value);
+ if (err < 0) {
+ fprintf(stderr, "%s: unable to get value '%s' for verb '%s' for device '%s': %s\n",
+ context->command, list[j], verb, device, snd_strerror(err));
+ goto __err;
+ }
+ err = render->value(render, list[j], value);
+ free((char *)value);
+ if (err < 0)
+ goto __err;
+ }
+ if (render->value_end)
+ err = render->value_end(render);
+__err:
+ snd_use_case_free_list(list, num);
+ return err;
+}
+
+static int render_device(struct context *context,
+ struct renderer *render,
+ const char *verb,
+ const char *device)
+{
+ int err;
+
+ err = render_devlist(context, render, verb, device,
+ "_supporteddevs",
+ render->supported_begin,
+ render->supported_value,
+ render->supported_end);
+ if (err < 0)
+ return err;
+ err = render_devlist(context, render, verb, device,
+ "_conflictingdevs",
+ render->conflict_begin,
+ render->conflict_value,
+ render->conflict_end);
+ if (err < 0)
+ return err;
+ return render_values(context, render, verb, device);
+}
+
+static void render(struct context *context, struct renderer *render)
+{
+ snd_use_case_mgr_t *uc_mgr = context->uc_mgr;
+ int i, j, num, dev_num;
+ const char **list, **dev_list, *verb, *comment;
+ char buf[256];
+
+ num = snd_use_case_verb_list(uc_mgr, &list);
+ if (num < 0) {
+ fprintf(stderr, "%s: no verbs found\n", context->command);
+ return;
+ }
+ if (render->init && render->init(render))
+ goto __end;
+ for (i = 0; i < num; i += 2) {
+ /* verb */
+ verb = list[i + 0];
+ comment = list[i + 1];
+ if (render->verb_begin(render, verb, comment))
+ break;
+ /* devices */
+ snprintf(buf, sizeof(buf), "_devices/%s", verb);
+ dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
+ if (dev_num < 0) {
+ fprintf(stderr, "%s: unable to get devices for verb '%s'\n",
+ context->command, verb);
+ continue;
+ }
+ 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])) {
+ snd_use_case_free_list(dev_list, dev_num);
+ goto __end;
+ }
+ render->device_end(render);
+ }
+ snd_use_case_free_list(dev_list, dev_num);
+ /* modifiers */
+ snprintf(buf, sizeof(buf), "_modifiers/%s", verb);
+ dev_num = snd_use_case_get_list(uc_mgr, buf, &dev_list);
+ if (dev_num < 0) {
+ fprintf(stderr, "%s: unable to get modifiers for verb '%s'\n",
+ context->command, verb);
+ continue;
+ }
+ 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);
+ /* end */
+ if (render->verb_end(render))
+ break;
+ }
+ if (render->done)
+ render->done(render);
+__end:
+ snd_use_case_free_list(list, num);
+}
+
+void dump(struct context *context, const char *format)
+{
+ struct renderer r;
+
+ 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;
+ }
+ if (r.opaque != NULL) {
+ render(context, &r);
+ return;
+ }
+ fprintf(stderr, "%s: unknown dump format '%s'\n",
+ context->command, format);
+}
diff --git a/alsaucm/usecase.c b/alsaucm/usecase.c
index 8b1c8c7182a0..44fc92bebfcd 100644
--- a/alsaucm/usecase.c
+++ b/alsaucm/usecase.c
@@ -38,24 +38,12 @@
#include <getopt.h>
#include <alsa/asoundlib.h>
#include <alsa/use-case.h>
+#include "usecase.h"
#include "aconfig.h"
#include "version.h"
#define MAX_BUF 256
-struct context {
- snd_use_case_mgr_t *uc_mgr;
- const char *command;
- char *card;
- char **argv;
- int argc;
- int arga;
- char *batch;
- unsigned int interactive:1;
- unsigned int no_open:1;
- unsigned int do_exit:1;
-};
-
enum uc_cmd {
/* management */
OM_UNKNOWN = 0,
@@ -63,6 +51,7 @@ enum uc_cmd {
OM_RESET,
OM_RELOAD,
OM_LISTCARDS,
+ OM_DUMP,
OM_LIST2,
OM_LIST1,
@@ -88,11 +77,13 @@ static struct cmd cmds[] = {
{ OM_RESET, 0, 1, "reset" },
{ OM_RELOAD, 0, 1, "reload" },
{ OM_LISTCARDS, 0, 0, "listcards" },
+ { OM_DUMP, 1, 1, "dump" },
{ OM_LIST1, 1, 1, "list1" },
{ OM_LIST2, 1, 1, "list" },
{ OM_SET, 2, 1, "set" },
{ OM_GET, 1, 1, "get" },
{ OM_GETI, 1, 1, "geti" },
+ { OM_DUMP, 1, 1, "dump" },
{ OM_HELP, 0, 0, "help" },
{ OM_QUIT, 0, 0, "quit" },
{ OM_HELP, 0, 0, "h" },
@@ -117,6 +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"
" 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"
@@ -185,7 +177,6 @@ static void my_exit(struct context *context, int exitcode)
snd_config_update_free_global();
exit(exitcode);
}
-
static void do_initial_open(struct context *context)
{
int card, err;
@@ -288,6 +279,9 @@ static int do_one(struct context *context, struct cmd *cmd, char **argv)
}
snd_use_case_free_list(list, err);
break;
+ case OM_DUMP:
+ dump(context, argv[0]);
+ break;
case OM_LIST1:
case OM_LIST2:
switch (cmd->code) {
diff --git a/alsaucm/usecase.h b/alsaucm/usecase.h
new file mode 100644
index 000000000000..a85716a652e2
--- /dev/null
+++ b/alsaucm/usecase.h
@@ -0,0 +1,35 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __USECASE_H
+#define __USECASE_H
+
+struct context {
+ snd_use_case_mgr_t *uc_mgr;
+ const char *command;
+ char *card;
+ char **argv;
+ int argc;
+ int arga;
+ char *batch;
+ unsigned int interactive:1;
+ unsigned int no_open:1;
+ unsigned int do_exit:1;
+};
+
+void dump(struct context *context, const char *format);
+
+#endif
--
2.16.4