1 // Copyright (c) 2019-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 5 #include <util/string.h>
6 7 #include <iterator>
8 #include <memory>
9 #include <regex>
10 #include <stdexcept>
11 #include <string>
12 13 namespace util {
14 void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute)
15 {
16 if (search.empty()) return;
17 in_out = std::regex_replace(in_out, std::regex(search), substitute);
18 }
19 20 LineReader::LineReader(std::span<const std::byte> buffer, size_t max_line_length)
21 : start(buffer.begin()), end(buffer.end()), max_line_length(max_line_length), it(buffer.begin()) {}
22 23 std::optional<std::string_view> LineReader::ReadLine()
24 {
25 if (it == end) {
26 return std::nullopt;
27 }
28 29 auto line_start = it;
30 size_t count = 0;
31 while (it != end) {
32 // Read a character from the incoming buffer and increment the iterator
33 auto c = static_cast<char>(*it);
34 ++it;
35 ++count;
36 // If the character we just consumed was \n, the line is terminated.
37 // The \n itself does not count against max_line_length.
38 if (c == '\n') {
39 const std::string_view untrimmed_line(reinterpret_cast<const char*>(std::to_address(line_start)), count);
40 std::string_view line = RemoveSuffixView(untrimmed_line, "\n");
41 return RemoveSuffixView(line, "\r");
42 }
43 // If the character we just consumed gives us a line length greater
44 // than max_line_length, and we are not at the end of the line (or buffer) yet,
45 // that means the line we are currently reading is too long, and we throw.
46 if (count > max_line_length) {
47 // Reset iterator
48 it = line_start;
49 throw std::runtime_error("max_line_length exceeded by LineReader");
50 }
51 }
52 // End of buffer reached without finding a \n or exceeding max_line_length.
53 // Reset the iterator so the rest of the buffer can be read granularly
54 // with ReadLength() and return null to indicate a line was not found.
55 it = line_start;
56 return std::nullopt;
57 }
58 59 // Ignores max_line_length but won't overflow
60 std::string_view LineReader::ReadLength(size_t len)
61 {
62 if (len == 0) return {};
63 if (Remaining() < len) throw std::runtime_error("Not enough data in buffer");
64 std::string_view out(reinterpret_cast<const char*>(std::to_address(it)), len);
65 it += len;
66 return out;
67 }
68 69 size_t LineReader::Remaining() const
70 {
71 return std::distance(it, end);
72 }
73 74 size_t LineReader::Consumed() const
75 {
76 return std::distance(start, it);
77 }
78 } // namespace util
79