From bd024edbafb005149f3820462386bc6b66a6a595 Mon Sep 17 00:00:00 2001 From: dvdli Date: Fri, 4 Dec 2020 10:24:31 +0800 Subject: fix printing format and wrong control for data printing tinymix_detail_control took controls' name as its parameter to identify which control is that we want to print data of. However, if there are some controls with same name, we will always print the data of the first one. --- utils/tinymix.c | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/utils/tinymix.c b/utils/tinymix.c index 41ca269..1ed7a17 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -39,7 +39,8 @@ static void tinymix_list_controls(struct mixer *mixer, int print_all); -static void tinymix_detail_control(struct mixer *mixer, const char *control); +static void tinymix_detail_control(struct mixer_ctl *control); +static void tinymix_detail_control_by_name_or_id(struct mixer *mixer, const char *name_or_id); static int tinymix_set_value(struct mixer *mixer, const char *control, char **values, unsigned int num_values); @@ -114,7 +115,7 @@ int main(int argc, char **argv) mixer_close(mixer); return EXIT_FAILURE; } - tinymix_detail_control(mixer, argv[opts.optind + 1]); + tinymix_detail_control_by_name_or_id(mixer, argv[opts.optind + 1]); printf("\n"); } else if (strcmp(cmd, "set") == 0) { if ((opts.optind + 1) >= argc) { @@ -180,7 +181,7 @@ static void tinymix_list_controls(struct mixer *mixer, int print_all) num_values = mixer_ctl_get_num_values(ctl); printf("%u\t%s\t%u\t%-40s", i, type, num_values, name); if (print_all) - tinymix_detail_control(mixer, name); + tinymix_detail_control(ctl); printf("\n"); } } @@ -201,28 +202,34 @@ static void tinymix_print_enum(struct mixer_ctl *ctl) } } -static void tinymix_detail_control(struct mixer *mixer, const char *control) +static void tinymix_detail_control_by_name_or_id(struct mixer *mixer, const char *name_or_id) { struct mixer_ctl *ctl; - enum mixer_ctl_type type; - unsigned int num_values; - unsigned int i; - int min, max; - int ret; - char *buf = NULL; - if (isnumber(control)) - ctl = mixer_get_ctl(mixer, atoi(control)); + if (isnumber(name_or_id)) + ctl = mixer_get_ctl(mixer, atoi(name_or_id)); else - ctl = mixer_get_ctl_by_name(mixer, control); + ctl = mixer_get_ctl_by_name(mixer, name_or_id); if (!ctl) { fprintf(stderr, "Invalid mixer control\n"); return; } - type = mixer_ctl_get_type(ctl); - num_values = mixer_ctl_get_num_values(ctl); + tinymix_detail_control(ctl); +} + +static void tinymix_detail_control(struct mixer_ctl *control) +{ + enum mixer_ctl_type type; + unsigned int num_values; + unsigned int i; + int min, max; + int ret; + char *buf = NULL; + + type = mixer_ctl_get_type(control); + num_values = mixer_ctl_get_num_values(control); if ((type == MIXER_CTL_TYPE_BYTE) && (num_values > 0)) { buf = calloc(1, num_values); @@ -231,7 +238,7 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control) return; } - ret = mixer_ctl_get_array(ctl, buf, num_values); + ret = mixer_ctl_get_array(control, buf, num_values); if (ret < 0) { fprintf(stderr, "Failed to mixer_ctl_get_array\n"); free(buf); @@ -243,16 +250,16 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control) switch (type) { case MIXER_CTL_TYPE_INT: - printf("%d", mixer_ctl_get_value(ctl, i)); + printf("%d", mixer_ctl_get_value(control, i)); break; case MIXER_CTL_TYPE_BOOL: - printf("%s", mixer_ctl_get_value(ctl, i) ? "On" : "Off"); + printf("%s", mixer_ctl_get_value(control, i) ? "On" : "Off"); break; case MIXER_CTL_TYPE_ENUM: - tinymix_print_enum(ctl); + tinymix_print_enum(control); break; case MIXER_CTL_TYPE_BYTE: - printf(" %02x", buf[i]); + printf("%02hhx", buf[i]); break; default: printf("unknown"); @@ -264,8 +271,8 @@ static void tinymix_detail_control(struct mixer *mixer, const char *control) } if (type == MIXER_CTL_TYPE_INT) { - min = mixer_ctl_get_range_min(ctl); - max = mixer_ctl_get_range_max(ctl); + min = mixer_ctl_get_range_min(control); + max = mixer_ctl_get_range_max(control); printf(" (range %d->%d)", min, max); } -- cgit v1.2.3 From dedaf9bf110787e43bf3943816c19a3fd09bdc9b Mon Sep 17 00:00:00 2001 From: dvdli Date: Mon, 7 Dec 2020 11:12:51 +0800 Subject: duplicate an argv list to avoid the argv order changed --- utils/tinymix.c | 66 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/utils/tinymix.c b/utils/tinymix.c index 1ed7a17..c7b2035 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -66,10 +66,28 @@ void version(void) printf("tinymix version 2.0 (tinyalsa version %s)\n", TINYALSA_VERSION_STRING); } +static int is_command(char *arg) { + return strcmp(arg, "get") == 0 || strcmp(arg, "set") == 0 || + strcmp(arg, "controls") == 0 || strcmp(arg, "contents") == 0; +} + +static int find_command_position(int argc, char **argv) +{ + int i; + for (i = 0; i < argc; ++i) { + if (is_command(argv[i])) { + return i; + } + } + return -1; +} + int main(int argc, char **argv) { struct mixer *mixer; int card = 0, c; + int command_position = -1; + int i; char *cmd; struct optparse opts; static struct optparse_long long_options[] = { @@ -79,7 +97,18 @@ int main(int argc, char **argv) { 0, 0, 0 } }; - optparse_init(&opts, argv); + // optparse_long may change the order of the argv list. Duplicate one for parsing the options. + char **argv_options_list = (char **) calloc(argc + 1, sizeof(char *)); + if (!argv_options_list) { + fprintf(stderr, "Failed to allocate options list\n"); + return EXIT_FAILURE; + } + + for (i = 0; i < argc; ++i) { + argv_options_list[i] = argv[i]; + } + + optparse_init(&opts, argv_options_list); /* Detect the end of the options. */ while ((c = optparse_long(&opts, long_options, NULL)) != -1) { switch (c) { @@ -88,15 +117,18 @@ int main(int argc, char **argv) break; case 'h': usage(); + free(argv_options_list); return EXIT_SUCCESS; case 'v': version(); + free(argv_options_list); return EXIT_SUCCESS; case '?': - fprintf(stderr, "%s\n", opts.errmsg); - return EXIT_FAILURE; + default: + break; } } + free(argv_options_list); mixer = mixer_open(card); if (!mixer) { @@ -104,31 +136,38 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - cmd = argv[opts.optind]; - if (cmd == NULL) { - fprintf(stderr, "no command specified (see --help)\n"); + command_position = find_command_position(argc, argv); + + if (command_position < 0) { + usage(); mixer_close(mixer); return EXIT_FAILURE; - } else if (strcmp(cmd, "get") == 0) { - if ((opts.optind + 1) >= argc) { + } + + cmd = argv[command_position]; + if (strcmp(cmd, "get") == 0) { + if (command_position + 1 >= argc) { fprintf(stderr, "no control specified\n"); mixer_close(mixer); return EXIT_FAILURE; } - tinymix_detail_control_by_name_or_id(mixer, argv[opts.optind + 1]); + tinymix_detail_control_by_name_or_id(mixer, argv[command_position + 1]); printf("\n"); } else if (strcmp(cmd, "set") == 0) { - if ((opts.optind + 1) >= argc) { + if (command_position + 1 >= argc) { fprintf(stderr, "no control specified\n"); mixer_close(mixer); return EXIT_FAILURE; } - if ((opts.optind + 2) >= argc) { + if (command_position + 2 >= argc) { fprintf(stderr, "no value(s) specified\n"); mixer_close(mixer); return EXIT_FAILURE; } - int res = tinymix_set_value(mixer, argv[opts.optind + 1], &argv[opts.optind + 2], argc - opts.optind - 2); + int res = tinymix_set_value(mixer, + argv[command_position + 1], + &argv[command_position + 2], + argc - command_position - 2); if (res != 0) { mixer_close(mixer); return EXIT_FAILURE; @@ -138,7 +177,8 @@ int main(int argc, char **argv) } else if (strcmp(cmd, "contents") == 0) { tinymix_list_controls(mixer, 1); } else { - fprintf(stderr, "unknown command '%s' (see --help)\n", cmd); + fprintf(stderr, "unknown command '%s'\n", cmd); + usage(); mixer_close(mixer); return EXIT_FAILURE; } -- cgit v1.2.3 From f1b8ff3ed54a74294a8fa39bb74858f01afc7249 Mon Sep 17 00:00:00 2001 From: dvdli Date: Mon, 7 Dec 2020 11:47:42 +0800 Subject: formatting and remove tinymix prefix of static functions --- utils/tinymix.c | 117 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/utils/tinymix.c b/utils/tinymix.c index c7b2035..d1dd65c 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -37,15 +37,15 @@ #define OPTPARSE_IMPLEMENTATION #include "optparse.h" -static void tinymix_list_controls(struct mixer *mixer, int print_all); +static void list_controls(struct mixer *mixer, int print_all); -static void tinymix_detail_control(struct mixer_ctl *control); -static void tinymix_detail_control_by_name_or_id(struct mixer *mixer, const char *name_or_id); +static void print_control_values(struct mixer_ctl *control); +static void print_control_values_by_name_or_id(struct mixer *mixer, const char *name_or_id); -static int tinymix_set_value(struct mixer *mixer, const char *control, +static int set_values(struct mixer *mixer, const char *control, char **values, unsigned int num_values); -static void tinymix_print_enum(struct mixer_ctl *ctl); +static void print_enum(struct mixer_ctl *ctl); void usage(void) { @@ -151,7 +151,7 @@ int main(int argc, char **argv) mixer_close(mixer); return EXIT_FAILURE; } - tinymix_detail_control_by_name_or_id(mixer, argv[command_position + 1]); + print_control_values_by_name_or_id(mixer, argv[command_position + 1]); printf("\n"); } else if (strcmp(cmd, "set") == 0) { if (command_position + 1 >= argc) { @@ -164,18 +164,18 @@ int main(int argc, char **argv) mixer_close(mixer); return EXIT_FAILURE; } - int res = tinymix_set_value(mixer, - argv[command_position + 1], - &argv[command_position + 2], - argc - command_position - 2); + int res = set_values(mixer, + argv[command_position + 1], + &argv[command_position + 2], + argc - command_position - 2); if (res != 0) { mixer_close(mixer); return EXIT_FAILURE; } } else if (strcmp(cmd, "controls") == 0) { - tinymix_list_controls(mixer, 0); + list_controls(mixer, 0); } else if (strcmp(cmd, "contents") == 0) { - tinymix_list_controls(mixer, 1); + list_controls(mixer, 1); } else { fprintf(stderr, "unknown command '%s'\n", cmd); usage(); @@ -197,7 +197,7 @@ static int isnumber(const char *str) { return strlen(end) == 0; } -static void tinymix_list_controls(struct mixer *mixer, int print_all) +static void list_controls(struct mixer *mixer, int print_all) { struct mixer_ctl *ctl; const char *name, *type; @@ -221,12 +221,12 @@ static void tinymix_list_controls(struct mixer *mixer, int print_all) num_values = mixer_ctl_get_num_values(ctl); printf("%u\t%s\t%u\t%-40s", i, type, num_values, name); if (print_all) - tinymix_detail_control(ctl); + print_control_values(ctl); printf("\n"); } } -static void tinymix_print_enum(struct mixer_ctl *ctl) +static void print_enum(struct mixer_ctl *ctl) { unsigned int num_enums; unsigned int i; @@ -242,7 +242,7 @@ static void tinymix_print_enum(struct mixer_ctl *ctl) } } -static void tinymix_detail_control_by_name_or_id(struct mixer *mixer, const char *name_or_id) +static void print_control_values_by_name_or_id(struct mixer *mixer, const char *name_or_id) { struct mixer_ctl *ctl; @@ -256,10 +256,10 @@ static void tinymix_detail_control_by_name_or_id(struct mixer *mixer, const char return; } - tinymix_detail_control(ctl); + print_control_values(ctl); } -static void tinymix_detail_control(struct mixer_ctl *control) +static void print_control_values(struct mixer_ctl *control) { enum mixer_ctl_type type; unsigned int num_values; @@ -296,7 +296,7 @@ static void tinymix_detail_control(struct mixer_ctl *control) printf("%s", mixer_ctl_get_value(control, i) ? "On" : "Off"); break; case MIXER_CTL_TYPE_ENUM: - tinymix_print_enum(control); + print_enum(control); break; case MIXER_CTL_TYPE_BYTE: printf("%02hhx", buf[i]); @@ -370,54 +370,54 @@ fail: static int is_int(const char *value) { - return (value[0] >= '0') || (value[0] <= '9'); + return value[0] >= '0' || value[0] <= '9'; } struct parsed_int { - /** Wether or not the integer was valid. */ - int valid; - /** The value of the parsed integer. */ - int value; - /** The number of characters that were parsed. */ - unsigned int length; - /** The number of characters remaining in the string. */ - unsigned int remaining_length; - /** The remaining characters (or suffix) of the integer. */ - const char* remaining; + /** Wether or not the integer was valid. */ + int valid; + /** The value of the parsed integer. */ + int value; + /** The number of characters that were parsed. */ + unsigned int length; + /** The number of characters remaining in the string. */ + unsigned int remaining_length; + /** The remaining characters (or suffix) of the integer. */ + const char* remaining; }; static struct parsed_int parse_int(const char* str) { - struct parsed_int out = { - 0 /* valid */, - 0 /* value */, - 0 /* length */, - 0 /* remaining length */, - "" /* remaining characters */ - }; + struct parsed_int out = { + 0 /* valid */, + 0 /* value */, + 0 /* length */, + 0 /* remaining length */, + "" /* remaining characters */ + }; - unsigned int max = strlen(str); + unsigned int max = strlen(str); - for (unsigned int i = 0; i < max; i++) { + for (unsigned int i = 0; i < max; i++) { - char c = str[i]; + char c = str[i]; - if ((c < '0') || (c > '9')) { - break; - } + if (c < '0' || c > '9') { + break; + } - out.value *= 10; - out.value += c - '0'; + out.value *= 10; + out.value += c - '0'; - out.length++; - } + out.length++; + } - out.valid = out.length > 0; - out.remaining_length = max - out.length; - out.remaining = str + out.length; + out.valid = out.length > 0; + out.remaining_length = max - out.length; + out.remaining = str + out.length; - return out; + return out; } struct control_value @@ -442,21 +442,22 @@ static struct control_value to_control_value(const char* value_string) unsigned int i = 0; if (parsed_int.remaining[i] == '%') { - out.is_percent = 1; - i++; + out.is_percent = 1; + i++; } if (parsed_int.remaining[i] == '+') { - out.is_relative = 1; + out.is_relative = 1; } else if (parsed_int.remaining[i] == '-') { - out.is_relative = 1; - out.value *= -1; + out.is_relative = 1; + out.value *= -1; } return out; } -static int set_control_value(struct mixer_ctl* ctl, unsigned int i, const struct control_value* value) +static int set_control_value(struct mixer_ctl* ctl, unsigned int i, + const struct control_value* value) { int next_value = value->value; @@ -520,7 +521,7 @@ static int set_control_values(struct mixer_ctl* ctl, return 0; } -static int tinymix_set_value(struct mixer *mixer, const char *control, +static int set_values(struct mixer *mixer, const char *control, char **values, unsigned int num_values) { struct mixer_ctl *ctl; -- cgit v1.2.3 From 8ee99fc593797dabc042b249cd57b6abd7a81025 Mon Sep 17 00:00:00 2001 From: dvdli Date: Mon, 7 Dec 2020 15:03:16 +0800 Subject: add support setting negative values to tinymix --- utils/tinymix.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/utils/tinymix.c b/utils/tinymix.c index d1dd65c..2effa19 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -394,14 +394,20 @@ static struct parsed_int parse_int(const char* str) 0 /* value */, 0 /* length */, 0 /* remaining length */, - "" /* remaining characters */ + NULL /* remaining characters */ }; - unsigned int max = strlen(str); + size_t length = strlen(str); + size_t i = 0; + int negative = 0; - for (unsigned int i = 0; i < max; i++) { + if (i < length && str[i] == '-') { + negative = 1; + i++; + } - char c = str[i]; + while (i < length) { + char c = str[i++]; if (c < '0' || c > '9') { break; @@ -413,8 +419,12 @@ static struct parsed_int parse_int(const char* str) out.length++; } + if (negative) { + out.value *= -1; + } + out.valid = out.length > 0; - out.remaining_length = max - out.length; + out.remaining_length = length - out.length; out.remaining = str + out.length; return out; @@ -491,7 +501,8 @@ static int set_control_values(struct mixer_ctl* ctl, for (unsigned int i = 0; i < num_values; i++) { int res = set_control_value(ctl, i, &value); if (res != 0) { - fprintf(stderr, "Error: invalid value\n"); + fprintf(stderr, "Error: invalid value (%d%s%s)\n", value.value, + value.is_relative ? "r" : "", value.is_percent ? "%" : ""); return -1; } } @@ -512,7 +523,8 @@ static int set_control_values(struct mixer_ctl* ctl, int res = set_control_value(ctl, i, &v); if (res != 0) { - fprintf(stderr, "Error: invalid value for index %u\n", i); + fprintf(stderr, "Error: invalid value (%d%s%s) for index %u\n", v.value, + v.is_relative ? "r" : "", v.is_percent ? "%" : "", i); return -1; } } -- cgit v1.2.3 From 31dcaff5d2fa8ec0c11bc5b5057a1cd0dde7e110 Mon Sep 17 00:00:00 2001 From: dvdli Date: Mon, 7 Dec 2020 16:30:50 +0800 Subject: add usage of VALUES --- utils/tinymix.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/utils/tinymix.c b/utils/tinymix.c index 2effa19..31b8a19 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -51,14 +51,19 @@ void usage(void) { printf("usage: tinymix [options] \n"); printf("options:\n"); - printf("\t-h, --help : prints this help message and exits\n"); - printf("\t-v, --version : prints this version of tinymix and exits\n"); - printf("\t-D, --card NUMBER : specifies the card number of the mixer\n"); + printf("\t-h, --help : prints this help message and exits\n"); + printf("\t-v, --version : prints this version of tinymix and exits\n"); + printf("\t-D, --card NUMBER : specifies the card number of the mixer\n"); + printf("\n"); printf("commands:\n"); - printf("\tget NAME|ID : prints the values of a control\n"); - printf("\tset NAME|ID VALUE : sets the value of a control\n"); - printf("\tcontrols : lists controls of the mixer\n"); - printf("\tcontents : lists controls of the mixer and their contents\n"); + printf("\tget NAME|ID : prints the values of a control\n"); + printf("\tset NAME|ID VALUE(S) ... : sets the value of a control\n"); + printf("\t\tVALUE(S): integers, percents, and relative values\n"); + printf("\t\t\tIntegers: 0, 100, -100 ...\n"); + printf("\t\t\tPercents: 0%%, 100%% ...\n"); + printf("\t\t\tRelative values: 1+, 1-, 1%%+, 2%%+ ...\n"); + printf("\tcontrols : lists controls of the mixer\n"); + printf("\tcontents : lists controls of the mixer and their contents\n"); } void version(void) -- cgit v1.2.3 From 4acbc58a193b39fb13c093d966d43a33613f8020 Mon Sep 17 00:00:00 2001 From: dvdli Date: Wed, 9 Dec 2020 14:18:56 +0800 Subject: correct index of integer string and reduce the life time of variables --- utils/tinymix.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/utils/tinymix.c b/utils/tinymix.c index 31b8a19..5c0378c 100644 --- a/utils/tinymix.c +++ b/utils/tinymix.c @@ -78,8 +78,7 @@ static int is_command(char *arg) { static int find_command_position(int argc, char **argv) { - int i; - for (i = 0; i < argc; ++i) { + for (int i = 0; i < argc; ++i) { if (is_command(argv[i])) { return i; } @@ -89,11 +88,7 @@ static int find_command_position(int argc, char **argv) int main(int argc, char **argv) { - struct mixer *mixer; - int card = 0, c; - int command_position = -1; - int i; - char *cmd; + int card = 0; struct optparse opts; static struct optparse_long long_options[] = { { "card", 'D', OPTPARSE_REQUIRED }, @@ -109,12 +104,13 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - for (i = 0; i < argc; ++i) { + for (int i = 0; i < argc; ++i) { argv_options_list[i] = argv[i]; } optparse_init(&opts, argv_options_list); /* Detect the end of the options. */ + int c; while ((c = optparse_long(&opts, long_options, NULL)) != -1) { switch (c) { case 'D': @@ -135,21 +131,20 @@ int main(int argc, char **argv) } free(argv_options_list); - mixer = mixer_open(card); + struct mixer *mixer = mixer_open(card); if (!mixer) { fprintf(stderr, "Failed to open mixer\n"); return EXIT_FAILURE; } - command_position = find_command_position(argc, argv); - + int command_position = find_command_position(argc, argv); if (command_position < 0) { usage(); mixer_close(mixer); return EXIT_FAILURE; } - cmd = argv[command_position]; + char *cmd = argv[command_position]; if (strcmp(cmd, "get") == 0) { if (command_position + 1 >= argc) { fprintf(stderr, "no control specified\n"); @@ -415,6 +410,7 @@ static struct parsed_int parse_int(const char* str) char c = str[i++]; if (c < '0' || c > '9') { + --i; break; } -- cgit v1.2.3