diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp index 972249fef96bc..528542cccf324 100644 --- a/libc/src/__support/File/file.cpp +++ b/libc/src/__support/File/file.cpp @@ -42,7 +42,7 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) { if (pos > 0) { // If the buffer is not empty // Flush the buffer const size_t write_size = pos; - auto write_result = platform_write(this, buf, write_size); + FileIOResult write_result = platform_write(this, buf, write_size); pos = 0; // Buffer is now empty so reset pos to the beginning. // If less bytes were written than expected, then an error occurred. if (write_result < write_size) { @@ -52,7 +52,7 @@ FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) { } } - auto write_result = platform_write(this, data, len); + FileIOResult write_result = platform_write(this, data, len); if (write_result < len) err = true; return write_result; @@ -99,7 +99,7 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { // is full. const size_t write_size = pos; - auto buf_result = platform_write(this, buf, write_size); + FileIOResult buf_result = platform_write(this, buf, write_size); size_t bytes_written = buf_result.value; pos = 0; // Buffer is now empty so reset pos to the beginning. @@ -121,7 +121,8 @@ FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) { pos = remainder.size(); } else { - auto result = platform_write(this, remainder.data(), remainder.size()); + FileIOResult result = + platform_write(this, remainder.data(), remainder.size()); size_t bytes_written = buf_result.value; // If less bytes were written than expected, then an error occurred. Return @@ -190,6 +191,17 @@ FileIOResult File::read_unlocked(void *data, size_t len) { prev_op = FileOp::READ; + if (bufmode == _IONBF) { // unbuffered. + return read_unlocked_nbf(static_cast(data), len); + } else if (bufmode == _IOFBF) { // fully buffered + return read_unlocked_fbf(static_cast(data), len); + } else /*if (bufmode == _IOLBF) */ { // line buffered + // There is no line buffered mode for read. Use fully buffered instead. + return read_unlocked_fbf(static_cast(data), len); + } +} + +size_t File::copy_data_from_buf(uint8_t *data, size_t len) { cpp::span bufref(static_cast(buf), bufsize); cpp::span dataref(static_cast(data), len); @@ -209,32 +221,42 @@ FileIOResult File::read_unlocked(void *data, size_t len) { for (size_t i = 0; i < available_data; ++i) dataref[i] = bufref[i + pos]; read_limit = pos = 0; // Reset the pointers. + + return available_data; +} + +FileIOResult File::read_unlocked_fbf(uint8_t *data, size_t len) { + // Read data from the buffer first. + size_t available_data = copy_data_from_buf(data, len); + if (available_data == len) + return available_data; + // Update the dataref to reflect that fact that we have already // copied |available_data| into |data|. - dataref = cpp::span(dataref.data() + available_data, - dataref.size() - available_data); - size_t to_fetch = len - available_data; + cpp::span dataref(static_cast(data) + available_data, + to_fetch); + if (to_fetch > bufsize) { - auto result = platform_read(this, dataref.data(), to_fetch); + FileIOResult result = platform_read(this, dataref.data(), to_fetch); size_t fetched_size = result.value; if (result.has_error() || fetched_size < to_fetch) { if (!result.has_error()) eof = true; else err = true; - return {available_data + fetched_size, result.has_error()}; + return {available_data + fetched_size, result.error}; } return len; } // Fetch and buffer another buffer worth of data. - auto result = platform_read(this, buf, bufsize); + FileIOResult result = platform_read(this, buf, bufsize); size_t fetched_size = result.value; read_limit += fetched_size; size_t transfer_size = fetched_size >= to_fetch ? to_fetch : fetched_size; for (size_t i = 0; i < transfer_size; ++i) - dataref[i] = bufref[i]; + dataref[i] = buf[i]; pos += transfer_size; if (result.has_error() || fetched_size < to_fetch) { if (!result.has_error()) @@ -245,6 +267,26 @@ FileIOResult File::read_unlocked(void *data, size_t len) { return {transfer_size + available_data, result.error}; } +FileIOResult File::read_unlocked_nbf(uint8_t *data, size_t len) { + // Check whether there is a character in the ungetc buffer. + size_t available_data = copy_data_from_buf(data, len); + if (available_data == len) + return available_data; + + // Directly copy the data into |data|. + cpp::span dataref(static_cast(data) + available_data, + len - available_data); + FileIOResult result = platform_read(this, dataref.data(), dataref.size()); + + if (result.has_error() || result < dataref.size()) { + if (!result.has_error()) + eof = true; + else + err = true; + } + return {result + available_data, result.error}; +} + int File::ungetc_unlocked(int c) { // There is no meaning to unget if: // 1. You are trying to push back EOF. @@ -287,7 +329,7 @@ ErrorOr File::seek(off_t offset, int whence) { FileLock lock(this); if (prev_op == FileOp::WRITE && pos > 0) { - auto buf_result = platform_write(this, buf, pos); + FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { err = true; return Error(buf_result.error); @@ -325,7 +367,7 @@ ErrorOr File::tell() { int File::flush_unlocked() { if (prev_op == FileOp::WRITE && pos > 0) { - auto buf_result = platform_write(this, buf, pos); + FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { err = true; return buf_result.error; diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h index 42e1d11b4ab1a..5c97a9c6419f0 100644 --- a/libc/src/__support/File/file.h +++ b/libc/src/__support/File/file.h @@ -280,6 +280,10 @@ class File { FileIOResult write_unlocked_fbf(const uint8_t *data, size_t len); FileIOResult write_unlocked_nbf(const uint8_t *data, size_t len); + FileIOResult read_unlocked_fbf(uint8_t *data, size_t len); + FileIOResult read_unlocked_nbf(uint8_t *data, size_t len); + size_t copy_data_from_buf(uint8_t *data, size_t len); + constexpr void adjust_buf() { if (read_allowed() && (buf == nullptr || bufsize == 0)) { // We should allow atleast one ungetc operation.