From ff4a7a7e2ac2370c72001112e85d5bc080f03594 Mon Sep 17 00:00:00 2001 From: Albert Chu Date: Wed, 29 Aug 2018 16:38:14 -0700 Subject: [PATCH] libflux/buffer: Add trimmed peek/read line variants For convenience, support flux_buffer_peek_trimmed_line() and flux_buffer_read_trimmed_line() variants, which will read lines but strip off any trailing newline characters. Fixes #1624 --- src/common/libflux/buffer.c | 38 +++++++++++++ src/common/libflux/buffer.h | 8 +++ src/common/libflux/test/buffer.c | 92 ++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/src/common/libflux/buffer.c b/src/common/libflux/buffer.c index 31e70fdeced1..3d329352949c 100644 --- a/src/common/libflux/buffer.c +++ b/src/common/libflux/buffer.c @@ -445,6 +445,25 @@ const void *flux_buffer_peek_line (flux_buffer_t *fb, int *lenp) return fb->buf; } +const void *flux_buffer_peek_trimmed_line (flux_buffer_t *fb, int *lenp) +{ + int tmp_lenp = 0; + + if (!flux_buffer_peek_line (fb, &tmp_lenp)) + return NULL; + + if (tmp_lenp) { + if (fb->buf[tmp_lenp - 1] == '\n') { + fb->buf[tmp_lenp - 1] = '\0'; + tmp_lenp--; + } + } + if (lenp) + (*lenp) = tmp_lenp; + + return fb->buf; +} + const void *flux_buffer_read_line (flux_buffer_t *fb, int *lenp) { int ret; @@ -465,6 +484,25 @@ const void *flux_buffer_read_line (flux_buffer_t *fb, int *lenp) return fb->buf; } +const void *flux_buffer_read_trimmed_line (flux_buffer_t *fb, int *lenp) +{ + int tmp_lenp = 0; + + if (!flux_buffer_read_line (fb, &tmp_lenp)) + return NULL; + + if (tmp_lenp) { + if (fb->buf[tmp_lenp - 1] == '\n') { + fb->buf[tmp_lenp - 1] = '\0'; + tmp_lenp--; + } + } + if (lenp) + (*lenp) = tmp_lenp; + + return fb->buf; +} + int flux_buffer_write_line (flux_buffer_t *fb, const char *data) { int ret; diff --git a/src/common/libflux/buffer.h b/src/common/libflux/buffer.h index 84499a870679..ac1b3cee34f0 100644 --- a/src/common/libflux/buffer.h +++ b/src/common/libflux/buffer.h @@ -74,6 +74,10 @@ int flux_buffer_drop_line (flux_buffer_t *fb); */ const void *flux_buffer_peek_line (flux_buffer_t *fb, int *lenp); +/* Identical to flux_buffer_peek_line(), but does not return trailing + * newline */ +const void *flux_buffer_peek_trimmed_line (flux_buffer_t *fb, int *lenp); + /* Read a line in the buffer and mark data as consumed. Return buffer * will include newline. Optionally return length of data returned in * [lenp]. If no line is available, returns pointer and length of 0. @@ -81,6 +85,10 @@ const void *flux_buffer_peek_line (flux_buffer_t *fb, int *lenp); */ const void *flux_buffer_read_line (flux_buffer_t *fb, int *lenp); +/* Identical to flux_buffer_read_line(), but does not return trailing + * newline */ +const void *flux_buffer_read_trimmed_line (flux_buffer_t *fb, int *lenp); + /* Write NUL terminated string data into the buffer and appends a * newline. Returns number of bytes written on success. */ diff --git a/src/common/libflux/test/buffer.c b/src/common/libflux/test/buffer.c index 05d766d9b066..25acb8b60c68 100644 --- a/src/common/libflux/test/buffer.c +++ b/src/common/libflux/test/buffer.c @@ -157,6 +157,45 @@ void basic (void) ok (flux_buffer_lines (fb) == 0, "flux_buffer_lines returns 0 after drop_line"); + /* write_line & peek_trimmed_line tests */ + + ok (flux_buffer_lines (fb) == 0, + "flux_buffer_lines returns 0 on no line"); + + ok (flux_buffer_write_line (fb, "foo") == 4, + "flux_buffer_write_line works"); + + ok (flux_buffer_bytes (fb) == 4, + "flux_buffer_bytes returns length of bytes written"); + + ok (flux_buffer_space (fb) == (FLUX_BUFFER_TEST_MAXSIZE - 4), + "flux_buffer_space returns length of space left"); + + ok (flux_buffer_lines (fb) == 1, + "flux_buffer_lines returns 1 on line written"); + + ok ((ptr = flux_buffer_peek_trimmed_line (fb, &len)) != NULL + && len == 3, + "flux_buffer_peek_trimmed_line works"); + + ok (!memcmp (ptr, "foo", 3), + "flux_buffer_peek_trimmed_line returns expected data"); + + ok (flux_buffer_bytes (fb) == 4, + "flux_buffer_bytes returns unchanged length after peek_trimmed_line"); + + ok (flux_buffer_drop_line (fb) == 4, + "flux_buffer_drop_line works"); + + ok (flux_buffer_bytes (fb) == 0, + "flux_buffer_bytes returns 0 after drop_line"); + + ok (flux_buffer_space (fb) == FLUX_BUFFER_TEST_MAXSIZE, + "flux_buffer_space initially returns FLUX_BUFFER_TEST_MAXSIZE"); + + ok (flux_buffer_lines (fb) == 0, + "flux_buffer_lines returns 0 after drop_line"); + /* write_line & read_line tests */ ok (flux_buffer_lines (fb) == 0, @@ -190,6 +229,39 @@ void basic (void) ok (flux_buffer_lines (fb) == 0, "flux_buffer_lines returns 0 after read_line"); + /* write_line & read_trimmed_line tests */ + + ok (flux_buffer_lines (fb) == 0, + "flux_buffer_lines returns 0 on no line"); + + ok (flux_buffer_write_line (fb, "foo") == 4, + "flux_buffer_write_line works"); + + ok (flux_buffer_bytes (fb) == 4, + "flux_buffer_bytes returns length of bytes written"); + + ok (flux_buffer_space (fb) == (FLUX_BUFFER_TEST_MAXSIZE - 4), + "flux_buffer_space returns length of space left"); + + ok (flux_buffer_lines (fb) == 1, + "flux_buffer_lines returns 1 on line written"); + + ok ((ptr = flux_buffer_read_trimmed_line (fb, &len)) != NULL + && len == 3, + "flux_buffer_read_trimmed_line works"); + + ok (!memcmp (ptr, "foo", 3), + "flux_buffer_read_trimmed_line returns expected data"); + + ok (flux_buffer_bytes (fb) == 0, + "flux_buffer_bytes returns 0 after read_trimmed_line"); + + ok (flux_buffer_space (fb) == FLUX_BUFFER_TEST_MAXSIZE, + "flux_buffer_space initially returns FLUX_BUFFER_TEST_MAXSIZE"); + + ok (flux_buffer_lines (fb) == 0, + "flux_buffer_lines returns 0 after read_trimmed_line"); + /* peek_to_fd tests */ ok (flux_buffer_write (fb, "foo", 3) == 3, @@ -914,9 +986,15 @@ void corner_case (void) ok (flux_buffer_peek_line (NULL, NULL) == NULL && errno == EINVAL, "flux_buffer_peek_line fails on NULL pointer"); + ok (flux_buffer_peek_trimmed_line (NULL, NULL) == NULL + && errno == EINVAL, + "flux_buffer_peek_trimmed_line fails on NULL pointer"); ok (flux_buffer_read_line (NULL, NULL) == NULL && errno == EINVAL, "flux_buffer_read_line fails on NULL pointer"); + ok (flux_buffer_read_trimmed_line (NULL, NULL) == NULL + && errno == EINVAL, + "flux_buffer_read_trimmed_line fails on NULL pointer"); ok (flux_buffer_write_line (NULL, "foo") < 0 && errno == EINVAL, "flux_buffer_write_line fails on NULL pointer"); @@ -946,10 +1024,18 @@ void corner_case (void) "flux_buffer_peek_line works when no data available"); ok (len == 0, "flux_buffer_peek_line returns length 0 when no data available"); + ok ((ptr = flux_buffer_peek_trimmed_line (fb, &len)) != NULL, + "flux_buffer_peek_trimmed_line works when no data available"); + ok (len == 0, + "flux_buffer_peek_trimmed_line returns length 0 when no data available"); ok ((ptr = flux_buffer_read_line (fb, &len)) != NULL, "flux_buffer_read_line works when no data available"); ok (len == 0, "flux_buffer_read_line returns length 0 when no data available"); + ok ((ptr = flux_buffer_read_trimmed_line (fb, &len)) != NULL, + "flux_buffer_read_trimmed_line works when no data available"); + ok (len == 0, + "flux_buffer_read_trimmed_line returns length 0 when no data available"); /* callback corner case tests */ @@ -1064,9 +1150,15 @@ void corner_case (void) ok (flux_buffer_peek_line (fb, NULL) == NULL && errno == EINVAL, "flux_buffer_peek_line fails on destroyed fb pointer"); + ok (flux_buffer_peek_trimmed_line (fb, NULL) == NULL + && errno == EINVAL, + "flux_buffer_peek_trimmed_line fails on destroyed fb pointer"); ok (flux_buffer_read_line (fb, NULL) == NULL && errno == EINVAL, "flux_buffer_read_line fails on destroyed fb pointer"); + ok (flux_buffer_read_trimmed_line (fb, NULL) == NULL + && errno == EINVAL, + "flux_buffer_read_trimmed_line fails on destroyed fb pointer"); ok (flux_buffer_write_line (fb, "foo") < 0 && errno == EINVAL, "flux_buffer_write_line fails on destroyed fb pointer");