tools api: Add io__getline

Reads a line to allocated memory up to a newline following the getline
API.

Committer notes:

It also adds this new function to the 'api io' 'perf test' entry:

  $ perf test "api io"
   64: Test api io                                                     : Ok
  $

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tom Rix <trix@redhat.com>
Cc: llvm@lists.linux.dev
Link: https://lore.kernel.org/r/20230403184033.1836023-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2023-04-03 11:40:30 -07:00 committed by Arnaldo Carvalho de Melo
parent 98b7ce0ed8
commit c9dc580c43
2 changed files with 81 additions and 0 deletions

View File

@ -7,7 +7,9 @@
#ifndef __API_IO__
#define __API_IO__
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct io {
@ -112,4 +114,47 @@ static inline int io__get_dec(struct io *io, __u64 *dec)
}
}
/* Read up to and including the first newline following the pattern of getline. */
static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out)
{
char buf[128];
int buf_pos = 0;
char *line = NULL, *temp;
size_t line_len = 0;
int ch = 0;
/* TODO: reuse previously allocated memory. */
free(*line_out);
while (ch != '\n') {
ch = io__get_char(io);
if (ch < 0)
break;
if (buf_pos == sizeof(buf)) {
temp = realloc(line, line_len + sizeof(buf));
if (!temp)
goto err_out;
line = temp;
memcpy(&line[line_len], buf, sizeof(buf));
line_len += sizeof(buf);
buf_pos = 0;
}
buf[buf_pos++] = (char)ch;
}
temp = realloc(line, line_len + buf_pos + 1);
if (!temp)
goto err_out;
line = temp;
memcpy(&line[line_len], buf, buf_pos);
line[line_len + buf_pos] = '\0';
line_len += buf_pos;
*line_out = line;
*line_len_out = line_len;
return line_len;
err_out:
free(line);
return -ENOMEM;
}
#endif /* __API_IO__ */

View File

@ -289,6 +289,40 @@ static int test_get_dec(void)
return ret;
}
static int test_get_line(void)
{
char path[PATH_MAX];
struct io io;
char test_string[1024];
char *line = NULL;
size_t i, line_len = 0;
size_t buf_size = 128;
int ret = 0;
for (i = 0; i < 512; i++)
test_string[i] = 'a';
test_string[512] = '\n';
for (i = 513; i < 1023; i++)
test_string[i] = 'b';
test_string[1023] = '\0';
if (setup_test(path, test_string, buf_size, &io))
return -1;
EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 513);
EXPECT_EQUAL((int)strlen(line), 513);
for (i = 0; i < 512; i++)
EXPECT_EQUAL(line[i], 'a');
EXPECT_EQUAL(line[512], '\n');
EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 510);
for (i = 0; i < 510; i++)
EXPECT_EQUAL(line[i], 'b');
free(line);
cleanup_test(path, &io);
return ret;
}
static int test__api_io(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
@ -300,6 +334,8 @@ static int test__api_io(struct test_suite *test __maybe_unused,
ret = TEST_FAIL;
if (test_get_dec())
ret = TEST_FAIL;
if (test_get_line())
ret = TEST_FAIL;
return ret;
}