Skip to content

Commit

Permalink
feat: Filesystem::getline() (#4569)
Browse files Browse the repository at this point in the history
Convenience function to safely read one line of text from an open FILE*
and return it as a string.

Signed-off-by: Larry Gritz <[email protected]>
  • Loading branch information
lgritz authored Jan 7, 2025
1 parent 3663310 commit c8b33ae
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/include/OpenImageIO/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ OIIO_UTIL_API int fseek (FILE *file, int64_t offset, int whence);
/// Version of ftell that works with 64 bit offsets on all systems.
OIIO_UTIL_API int64_t ftell (FILE *file);

/// Read one line of text from an open text file file until the hitting a
/// newline, reaching `maxlen` characters without encountering a newline, or
/// reaching the end of the file, and return the characters read as a
/// std::string. The newline will be included in the returned string, unless
/// the line was too long, in which case the string returned will be the
/// partial result with no newline at the end. If an error occurs or if the
/// end of the file is encountered before either a newline is reached or
/// maxlen characters are read, an empty string will be returned.
OIIO_UTIL_API std::string getline(FILE* file, size_t maxlen = 4096);

/// Return the current (".") directory path.
///
OIIO_UTIL_API std::string current_path ();
Expand Down
18 changes: 18 additions & 0 deletions src/libutil/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,24 @@ Filesystem::ftell(FILE* file)



std::string
Filesystem::getline(FILE* file, size_t maxlen)
{
std::string result;
char* buf;
OIIO_ALLOCATE_STACK_OR_HEAP(buf, char, maxlen + 1);
if (fgets(buf, int(maxlen + 1), file)) {
buf[maxlen] = 0; // be sure it is terminated
if (!feof(file))
result.assign(buf);
} else {
result.assign("");
}
return result;
}



void
Filesystem::open(OIIO::ifstream& stream, string_view path,
std::ios_base::openmode mode)
Expand Down
39 changes: 39 additions & 0 deletions src/libutil/filesystem_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,44 @@ test_last_write_time()



void
test_getline()
{
const char* contents = "Line 1\n"
"Line 2\n"
"Really really really long long line line 3\n"
"Line 4\n"
"Line 5 no newline";
const char* tmpfilename = "getline.txt";
Filesystem::write_text_file(tmpfilename, contents);

FILE* in = Filesystem::fopen(tmpfilename, "r");
OIIO_CHECK_ASSERT(in != nullptr);
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), "Line 1\n");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), "Line 2\n");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30),
"Really really really long long");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), " line line 3\n");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), "Line 4\n");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), ""); // EOF before \n
fclose(in);

// Again, with a complete line at the end to be sure we read it
Filesystem::write_text_file(tmpfilename, "Line 1\n"
"Line 2\n");
in = Filesystem::fopen(tmpfilename, "r");
OIIO_CHECK_ASSERT(in != nullptr);
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), "Line 1\n");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), "Line 2\n");
OIIO_CHECK_EQUAL(Filesystem::getline(in, 30), "");
OIIO_CHECK_ASSERT(feof(in));
fclose(in);

Filesystem::remove(tmpfilename);
}



int
main(int /*argc*/, char* /*argv*/[])
{
Expand All @@ -617,6 +655,7 @@ main(int /*argc*/, char* /*argv*/[])
test_scan_sequences();
test_mem_proxies();
test_last_write_time();
test_getline();

return unit_test_failures;
}

0 comments on commit c8b33ae

Please sign in to comment.