2023-03-06 14:42:04 +01:00
|
|
|
// SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
// author: Max Kellermann <max.kellermann@gmail.com>
|
2014-08-07 18:54:06 +02:00
|
|
|
|
|
|
|
#include "BufferedReader.hxx"
|
|
|
|
#include "Reader.hxx"
|
|
|
|
#include "util/TextFile.hxx"
|
|
|
|
|
2023-03-05 08:43:32 +01:00
|
|
|
#include <algorithm> // for std::copy_n()
|
2021-12-07 11:49:59 +01:00
|
|
|
#include <cassert>
|
2020-03-13 01:08:53 +01:00
|
|
|
#include <cstdint>
|
2016-08-16 08:46:44 +02:00
|
|
|
#include <stdexcept>
|
|
|
|
|
2014-08-07 18:54:06 +02:00
|
|
|
bool
|
|
|
|
BufferedReader::Fill(bool need_more)
|
|
|
|
{
|
|
|
|
if (eof)
|
|
|
|
return !need_more;
|
|
|
|
|
|
|
|
auto w = buffer.Write();
|
2017-11-10 19:24:33 +01:00
|
|
|
if (w.empty()) {
|
2014-08-07 18:54:06 +02:00
|
|
|
if (buffer.GetCapacity() >= MAX_SIZE)
|
|
|
|
return !need_more;
|
|
|
|
|
|
|
|
buffer.Grow(buffer.GetCapacity() * 2);
|
|
|
|
w = buffer.Write();
|
2017-11-10 19:24:33 +01:00
|
|
|
assert(!w.empty());
|
2014-08-07 18:54:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-05 10:25:16 +02:00
|
|
|
std::size_t nbytes = reader.Read(w);
|
2014-08-07 18:54:06 +02:00
|
|
|
if (nbytes == 0) {
|
|
|
|
eof = true;
|
|
|
|
return !need_more;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.Append(nbytes);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-16 12:09:04 +02:00
|
|
|
void *
|
2021-12-07 11:49:59 +01:00
|
|
|
BufferedReader::ReadFull(std::size_t size)
|
2016-08-16 12:09:04 +02:00
|
|
|
{
|
|
|
|
while (true) {
|
|
|
|
auto r = Read();
|
2022-05-10 16:05:27 +02:00
|
|
|
if (r.size() >= size)
|
|
|
|
return r.data();
|
2016-08-16 12:09:04 +02:00
|
|
|
|
|
|
|
if (!Fill(true))
|
|
|
|
throw std::runtime_error("Premature end of file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-07 11:49:59 +01:00
|
|
|
std::size_t
|
2022-05-10 16:05:27 +02:00
|
|
|
BufferedReader::ReadFromBuffer(std::span<std::byte> dest) noexcept
|
2016-08-16 08:46:44 +02:00
|
|
|
{
|
2022-05-10 16:05:27 +02:00
|
|
|
const auto src = Read();
|
|
|
|
std::size_t nbytes = std::min(src.size(), dest.size());
|
|
|
|
std::copy_n(src.data(), nbytes, dest.data());
|
2016-08-16 11:47:31 +02:00
|
|
|
Consume(nbytes);
|
2016-08-16 08:46:44 +02:00
|
|
|
return nbytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-05-10 16:05:27 +02:00
|
|
|
BufferedReader::ReadFull(std::span<std::byte> dest)
|
2016-08-16 08:46:44 +02:00
|
|
|
{
|
|
|
|
while (true) {
|
2022-05-10 16:05:27 +02:00
|
|
|
std::size_t nbytes = ReadFromBuffer(dest);
|
|
|
|
dest = dest.subspan(nbytes);
|
|
|
|
if (dest.empty())
|
2016-08-16 08:46:44 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (!Fill(true))
|
|
|
|
throw std::runtime_error("Premature end of file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 18:54:06 +02:00
|
|
|
char *
|
|
|
|
BufferedReader::ReadLine()
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
char *line = ReadBufferedLine(buffer);
|
2015-01-21 23:43:32 +01:00
|
|
|
if (line != nullptr) {
|
|
|
|
++line_number;
|
2014-08-07 18:54:06 +02:00
|
|
|
return line;
|
2015-01-21 23:43:32 +01:00
|
|
|
}
|
2014-08-07 18:54:06 +02:00
|
|
|
} while (Fill(true));
|
|
|
|
|
2017-11-10 19:24:33 +01:00
|
|
|
if (!eof || buffer.empty())
|
2014-08-07 18:54:06 +02:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto w = buffer.Write();
|
2017-11-10 19:24:33 +01:00
|
|
|
if (w.empty()) {
|
2014-08-07 18:54:06 +02:00
|
|
|
buffer.Grow(buffer.GetCapacity() + 1);
|
|
|
|
w = buffer.Write();
|
2017-11-10 19:24:33 +01:00
|
|
|
assert(!w.empty());
|
2014-08-07 18:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* terminate the last line */
|
2023-10-05 10:25:16 +02:00
|
|
|
w[0] = {};
|
2014-08-07 18:54:06 +02:00
|
|
|
|
2023-10-05 10:25:16 +02:00
|
|
|
char *line = reinterpret_cast<char *>(buffer.Read().data());
|
2014-08-07 18:54:06 +02:00
|
|
|
buffer.Clear();
|
2015-01-21 23:43:32 +01:00
|
|
|
++line_number;
|
2014-08-07 18:54:06 +02:00
|
|
|
return line;
|
|
|
|
}
|