Commit c9dc580c authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarIan Rogers <irogers@google.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: default avatarNamhyung 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 98b7ce0e
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -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__ */
+36 −0
Original line number Diff line number Diff line
@@ -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;
}