tools/record: deduplicate the device opening logic

With a new helper function strv_from_argv we can re-use the device opening
loop for all the use-cases we have.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2021-03-26 10:06:47 +10:00
parent 4da9349a91
commit 7f4df04d59
4 changed files with 86 additions and 28 deletions

View file

@ -58,6 +58,36 @@ next_word(const char **state, size_t *len, const char *separators)
return next;
}
/**
* Return a null-terminated string array with the contents of argv
* duplicated.
*
* Use strv_free() to free the array.
*
* @return A null-terminated string array or NULL on errors
*/
char**
strv_from_argv(int argc, char **argv)
{
char **strv = NULL;
assert(argc >= 0);
if (argc == 0)
return NULL;
strv = zalloc((argc + 1) * sizeof *strv);
for (int i = 0; i < argc; i++) {
char *copy = safe_strdup(argv[i]);
if (!copy) {
strv_free(strv);
return NULL;
}
strv[i] = copy;
}
return strv;
}
/**
* Return a null-terminated string array with the tokens in the input
* string, e.g. "one two\tthree" with a separator list of " \t" will return

View file

@ -252,6 +252,7 @@ safe_atod(const char *str, double *val)
return true;
}
char **strv_from_argv(int argc, char **argv);
char **strv_from_string(const char *in, const char *separator);
char *strv_join(char **strv, const char *joiner);

View file

@ -1022,6 +1022,44 @@ START_TEST(strsplit_test)
}
END_TEST
START_TEST(strargv_test)
{
struct argv_test {
int argc;
char *argv[10];
int expected;
} tests[] = {
{ 0, {NULL}, 0 },
{ 1, {"hello", "World"}, 1 },
{ 2, {"hello", "World"}, 2 },
{ 2, {"", " "}, 2 },
{ 2, {"", NULL}, 0 },
{ 2, {NULL, NULL}, 0 },
{ 1, {NULL, NULL}, 0 },
{ 3, {"hello", NULL, "World"}, 0 },
};
struct argv_test *t;
ARRAY_FOR_EACH(tests, t) {
char **strv = strv_from_argv(t->argc, t->argv);
if (t->expected == 0) {
ck_assert(strv == NULL);
} else {
int count = 0;
char **s = strv;
while (*s) {
ck_assert_str_eq(*s, t->argv[count]);
count++;
s++;
}
ck_assert_int_eq(t->expected, count);
strv_free(strv);
}
}
}
END_TEST
START_TEST(kvsplit_double_test)
{
struct kvsplit_dbl_test {
@ -1378,6 +1416,7 @@ litest_utils_suite(void)
tcase_add_test(tc, safe_atou_base_8_test);
tcase_add_test(tc, safe_atod_test);
tcase_add_test(tc, strsplit_test);
tcase_add_test(tc, strargv_test);
tcase_add_test(tc, kvsplit_double_test);
tcase_add_test(tc, strjoin_test);
tcase_add_test(tc, strstrip_test);

View file

@ -2448,13 +2448,13 @@ mainloop(struct record_context *ctx)
}
static bool
init_device(struct record_context *ctx, char *path, bool grab)
init_device(struct record_context *ctx, const char *path, bool grab)
{
struct record_device *d;
int fd, rc;
d = zalloc(sizeof(*d));
d->devnode = path;
d->devnode = safe_strdup(path);
d->nevents = 0;
d->events_sz = 5000;
d->events = zalloc(d->events_sz * sizeof(*d->events));
@ -2698,6 +2698,7 @@ main(int argc, char **argv)
bool all = false, with_libinput = false, grab = false;
int ndevices;
int rc = EXIT_FAILURE;
char **paths = NULL;
list_init(&ctx.devices);
list_init(&ctx.sources);
@ -2791,39 +2792,25 @@ main(int argc, char **argv)
goto out;
}
/* Now collect all device paths and init our device struct */
if (all) {
char **devices; /* NULL-terminated */
char **d;
devices = all_devices();
d = devices;
while (*d) {
if (!init_device(&ctx, safe_strdup(*d), grab)) {
strv_free(devices);
goto out;
}
d++;
}
strv_free(devices);
} else if (ndevices > 1) {
for (int i = ndevices; i > 0; i -= 1) {
char *devnode = safe_strdup(argv[optind + i - 1]);
if (!init_device(&ctx, devnode, grab))
goto out;
}
paths = all_devices();
} else if (ndevices >= 1) {
paths = strv_from_argv(ndevices, &argv[optind]);
} else {
char *path;
path = ndevices <= 0 ? select_device() : safe_strdup(argv[optind++]);
char *path = select_device();
if (path == NULL) {
goto out;
}
if (!init_device(&ctx, path, grab))
paths = strv_from_argv(1, &path);
free(path);
}
for (char **p = paths; *p; p++) {
if (!init_device(&ctx, *p, grab)) {
goto out;
}
}
if (with_libinput && !init_libinput(&ctx))
@ -2831,6 +2818,7 @@ main(int argc, char **argv)
rc = mainloop(&ctx);
out:
strv_free(paths);
list_for_each_safe(d, &ctx.devices, link) {
if (d->device)
libinput_device_unref(d->device);