From: Bartosz Golaszewski Date: Wed, 21 Jun 2017 11:47:30 +0000 (+0200) Subject: gpiomon: simplify custom formats X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=d4d1c11f313e6269d0341c2bc1b854709ea56490;p=qemu-gpiodev%2Flibgpiod.git gpiomon: simplify custom formats Instead of replacing the format specifiers in a separate buffer, just make use of the output stream buffering. Also: update the gpiomon tests with some corner cases. Signed-off-by: Bartosz Golaszewski --- diff --git a/src/tools/gpiomon.c b/src/tools/gpiomon.c index 10b07d9..53402ac 100644 --- a/src/tools/gpiomon.c +++ b/src/tools/gpiomon.c @@ -70,94 +70,56 @@ struct callback_data { char *fmt; }; -static void replace_fmt(char **base, size_t off, const char *new) -{ - size_t newlen, baselen; - char *tmp; - - newlen = strlen(new); - baselen = strlen(*base); - - if (newlen > 2) { - /* - * FIXME This should be done with realloc() but valgrind - * is reporting problems with using uninitialized memory. - * - * Also: it could be made more efficient by allocating more - * memory at the beginning and then doubling the size of the - * buffer once the previous one is exhausted. - */ - tmp = malloc(baselen + newlen + 1); - if (!tmp) - die("out of memory"); - - memset(tmp, 0, baselen + newlen + 1); - strcpy(tmp, *base); - free(*base); - *base = tmp; - } - - memmove(*base + off + newlen, *base + off + 2, baselen - off - 2); - strncpy(*base + off, new, newlen); - - if (newlen < 2) - *(*base + baselen - 1) = '\0'; -} - static void event_print_custom(int type, const struct timespec *ts, struct callback_data *data) { - char repbuf[64], *str, *pos, fmt; - size_t off; + char *prev, *curr, fmt; - str = strdup(data->fmt); - if (!str) - die("out of memory"); - - for (off = 0;;) { - pos = strchr(str + off, '%'); - if (!pos) + for (prev = curr = data->fmt;;) { + curr = strchr(curr, '%'); + if (!curr) { + fputs(prev, stdout); break; + } - fmt = *(pos + 1); - off = pos - str; + if (prev != curr) + fwrite(prev, curr - prev, 1, stdout); - if (fmt == '%') { - memmove(str + off, str + off + 1, strlen(str) - off); - off += 1; - continue; - } + fmt = *(curr + 1); switch (fmt) { case 'o': - snprintf(repbuf, sizeof(repbuf), "%u", data->offset); - replace_fmt(&str, off, repbuf); + printf("%u", data->offset); break; case 'e': if (type == GPIOD_EVENT_CB_RISING_EDGE) - snprintf(repbuf, sizeof(repbuf), "1"); + fputc('1', stdout); else - snprintf(repbuf, sizeof(repbuf), "0"); - replace_fmt(&str, off, repbuf); + fputc('0', stdout); break; case 's': - snprintf(repbuf, sizeof(repbuf), "%ld", ts->tv_sec); - replace_fmt(&str, off, repbuf); + printf("%ld", ts->tv_sec); break; case 'n': - snprintf(repbuf, sizeof(repbuf), "%ld", ts->tv_nsec); - replace_fmt(&str, off, repbuf); + printf("%ld", ts->tv_nsec); break; + case '%': + fputc('%', stdout); + break; + case '\0': + fputc('%', stdout); + goto end; default: - off += 2; - continue; + fwrite(curr, 2, 1, stdout); + break; } - off += strlen(repbuf); + curr += 2; + prev = curr; } - printf("%s\n", str); - free(str); +end: + fputc('\n', stdout); } static void event_print_human_readable(int type, const struct timespec *ts, diff --git a/tests/tests-gpiomon.c b/tests/tests-gpiomon.c index 4080af9..19b9a16 100644 --- a/tests/tests-gpiomon.c +++ b/tests/tests-gpiomon.c @@ -242,7 +242,24 @@ TEST_DEFINE(gpiomon_custom_format_timestamp, "tools: gpiomon - custom output format: timestamp", 0, { 8, 8 }); -static void gpiomon_custom_format_double_percent(void) +static void gpiomon_custom_format_double_percent_sign(void) +{ + test_tool_run("gpiomon", "--num-events=1", "--format=%%", + test_chip_name(0), "3", (char *)NULL); + test_set_event(0, 3, TEST_EVENT_RISING, 100); + test_tool_wait(); + + TEST_ASSERT(test_tool_exited()); + TEST_ASSERT_RET_OK(test_tool_exit_status()); + TEST_ASSERT_NOT_NULL(test_tool_stdout()); + TEST_ASSERT_NULL(test_tool_stderr()); + TEST_ASSERT_STR_EQ(test_tool_stdout(), "%\n"); +} +TEST_DEFINE(gpiomon_custom_format_double_percent_sign, + "tools: gpiomon - custom output format: double percent sign", + 0, { 8, 8 }); + +static void gpiomon_custom_format_double_percent_sign_and_spec(void) { test_tool_run("gpiomon", "--num-events=1", "--format=%%e", test_chip_name(0), "3", (char *)NULL); @@ -255,8 +272,42 @@ static void gpiomon_custom_format_double_percent(void) TEST_ASSERT_NULL(test_tool_stderr()); TEST_ASSERT_STR_EQ(test_tool_stdout(), "%e\n"); } -TEST_DEFINE(gpiomon_custom_format_double_percent, - "tools: gpiomon - custom output format: double percent", +TEST_DEFINE(gpiomon_custom_format_double_percent_sign_and_spec, + "tools: gpiomon - custom output format: double percent sign with specifier", + 0, { 8, 8 }); + +static void gpiomon_custom_format_single_percent_sign(void) +{ + test_tool_run("gpiomon", "--num-events=1", "--format=%", + test_chip_name(0), "3", (char *)NULL); + test_set_event(0, 3, TEST_EVENT_RISING, 100); + test_tool_wait(); + + TEST_ASSERT(test_tool_exited()); + TEST_ASSERT_RET_OK(test_tool_exit_status()); + TEST_ASSERT_NOT_NULL(test_tool_stdout()); + TEST_ASSERT_NULL(test_tool_stderr()); + TEST_ASSERT_STR_EQ(test_tool_stdout(), "%\n"); +} +TEST_DEFINE(gpiomon_custom_format_single_percent_sign, + "tools: gpiomon - custom output format: single percent sign", + 0, { 8, 8 }); + +static void gpiomon_custom_format_single_percent_sign_between_chars(void) +{ + test_tool_run("gpiomon", "--num-events=1", "--format=foo % bar", + test_chip_name(0), "3", (char *)NULL); + test_set_event(0, 3, TEST_EVENT_RISING, 100); + test_tool_wait(); + + TEST_ASSERT(test_tool_exited()); + TEST_ASSERT_RET_OK(test_tool_exit_status()); + TEST_ASSERT_NOT_NULL(test_tool_stdout()); + TEST_ASSERT_NULL(test_tool_stderr()); + TEST_ASSERT_STR_EQ(test_tool_stdout(), "foo % bar\n"); +} +TEST_DEFINE(gpiomon_custom_format_single_percent_sign_between_chars, + "tools: gpiomon - custom output format: single percent sign between other characters", 0, { 8, 8 }); static void gpiomon_custom_format_unknown_specifier(void)