diff options
Diffstat (limited to 'src/build_log.cc')
-rw-r--r-- | src/build_log.cc | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/src/build_log.cc b/src/build_log.cc index 01fb001..5803ada 100644 --- a/src/build_log.cc +++ b/src/build_log.cc @@ -113,24 +113,52 @@ void BuildLog::Close() { class LineReader { public: - explicit LineReader(FILE* file) : file_(file) {} + explicit LineReader(FILE* file) + : file_(file), buf_end_(buf_), line_start_(buf_), line_end_(NULL) {} // Reads a \n-terminated line from the file passed to the constructor. // On return, *line_start points to the beginning of the next line, and // *line_end points to the \n at the end of the line. If no newline is seen // in a fixed buffer size, *line_end is set to NULL. Returns false on EOF. bool ReadLine(char** line_start, char** line_end) { - if (!fgets(buf_, sizeof(buf_), file_)) - return false; + if (line_start_ >= buf_end_ || !line_end_) { + // Buffer empty, refill. + size_t size_read = fread(buf_, 1, sizeof(buf_), file_); + if (!size_read) + return false; + line_start_ = buf_; + buf_end_ = buf_ + size_read; + } else { + // Advance to next line in buffer. + line_start_ = line_end_ + 1; + } - *line_start = buf_; - *line_end = strchr(buf_, '\n'); + line_end_ = (char*)memchr(line_start_, '\n', buf_end_ - line_start_); + if (!line_end_) { + // No newline. Move rest of data to start of buffer, fill rest. + size_t already_consumed = line_start_ - buf_; + size_t size_rest = (buf_end_ - buf_) - already_consumed; + memmove(buf_, line_start_, size_rest); + + size_t read = fread(buf_ + size_rest, 1, sizeof(buf_) - size_rest, file_); + buf_end_ = buf_ + size_rest + read; + line_start_ = buf_; + line_end_ = (char*)memchr(line_start_, '\n', buf_end_ - line_start_); + } + + *line_start = line_start_; + *line_end = line_end_; return true; } private: FILE* file_; char buf_[256 << 10]; + char* buf_end_; // Points one past the last valid byte in |buf_|. + + char* line_start_; + // Points at the next \n in buf_ after line_start, or NULL. + char* line_end_; }; bool BuildLog::Load(const string& path, string* err) { |