| #include "util/stream/line_input.hh" |
| |
| #include "util/exception.hh" |
| #include "util/file.hh" |
| #include "util/read_compressed.hh" |
| #include "util/stream/chain.hh" |
| |
| #include <algorithm> |
| #include <vector> |
| |
| namespace util { namespace stream { |
| |
| void LineInput::Run(const ChainPosition &position) { |
| ReadCompressed reader(fd_); |
| // Holding area for beginning of line to be placed in next block. |
| std::vector<char> carry; |
| |
| for (Link block(position); ; ++block) { |
| char *to = static_cast<char*>(block->Get()); |
| char *begin = to; |
| char *end = to + position.GetChain().BlockSize(); |
| std::copy(carry.begin(), carry.end(), to); |
| to += carry.size(); |
| while (to != end) { |
| std::size_t got = reader.Read(to, end - to); |
| if (!got) { |
| // EOF |
| block->SetValidSize(to - begin); |
| ++block; |
| block.Poison(); |
| return; |
| } |
| to += got; |
| } |
| |
| // Find the last newline. |
| char *newline; |
| for (newline = to - 1; ; --newline) { |
| UTIL_THROW_IF(newline < begin, Exception, "Did not find a newline in " << position.GetChain().BlockSize() << " bytes of input of " << NameFromFD(fd_) << ". Is this a text file?"); |
| if (*newline == '\n') break; |
| } |
| |
| // Copy everything after the last newline to the carry. |
| carry.clear(); |
| carry.resize(to - (newline + 1)); |
| std::copy(newline + 1, to, &*carry.begin()); |
| |
| block->SetValidSize(newline + 1 - begin); |
| } |
| } |
| |
| }} // namespaces |