1//! @file io.hpp
2//! @author ryftchen
3//! @brief The declarations (io) in the utility module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#pragma once
8
9#include <functional>
10#include <istream>
11
12//! @brief The utility module.
13namespace utility // NOLINT(modernize-concat-nested-namespaces)
14{
15//! @brief I/O-operation-related functions in the utility module.
16namespace io
17{
18//! @brief Brief function description.
19//! @return function description (module_function)
20inline static const char* description() noexcept
21{
22 return "UTIL_IO";
23}
24extern const char* version() noexcept;
25
26extern std::string executeCommand(const std::string& command);
27extern void waitForUserInput(const std::function<bool(const std::string&)>& operation, const int timeout = -1);
28extern std::vector<std::string> readFileLines(
29 const std::string_view filename, const bool lock = false, const bool reverse = false, const int limit = -1);
30
31//! @brief Custom stream buffer for file descriptors.
32class FDStreamBuffer : public std::streambuf
33{
34public:
35 //! @brief Construct a new FDStreamBuffer object.
36 //! @param fd - file descriptor to associate with the stream buffer
37 explicit FDStreamBuffer(const int fd = -1) : fd{fd} {}
38 //! @brief Destroy the FDStreamBuffer object.
39 ~FDStreamBuffer() override;
40 //! @brief Construct a new FDStreamBuffer object.
41 FDStreamBuffer(const FDStreamBuffer&) = delete;
42 //! @brief Construct a new FDStreamBuffer object.
43 FDStreamBuffer(FDStreamBuffer&&) noexcept = default;
44 //! @brief The operator (=) overloading of FDStreamBuffer class.
45 //! @return reference of the FDStreamBuffer object
46 FDStreamBuffer& operator=(const FDStreamBuffer&) = delete;
47 //! @brief The operator (=) overloading of FDStreamBuffer class.
48 //! @return reference of the FDStreamBuffer object
49 FDStreamBuffer& operator=(FDStreamBuffer&&) noexcept = default;
50
51 //! @brief Set the file descriptor.
52 //! @param newFD - new file descriptor to associate with the stream buffer
53 void set(const int newFD);
54 //! @brief Reset the file descriptor.
55 void reset();
56
57private:
58 //! @brief File descriptor associated with the stream buffer.
59 int fd{-1};
60 //! @brief Size of the buffer.
61 static constexpr std::size_t bufferSize{4096};
62 //! @brief Buffer for reading data.
63 std::array<char, bufferSize> readBuffer{};
64 //! @brief Buffer for writing data.
65 std::array<char, bufferSize> writeBuffer{};
66
67 //! @brief Flush the output buffer with the file descriptor.
68 //! @return 0 if successful, otherwise -1
69 int flush();
70
71protected:
72 //! @brief Read data into the input buffer.
73 //! @return next character from the input buffer
74 int_type underflow() override;
75 //! @brief Write data from the output buffer.
76 //! @param c - character to write to the buffer
77 //! @return character written
78 int_type overflow(const int_type c) override;
79 //! @brief Synchronize the output buffer with the file descriptor.
80 //! @return 0 if successful, otherwise -1
81 int sync() override;
82 //! @brief Set the position indicator for the stream buffer.
83 //! @param off - offset to move the position indicator
84 //! @param way - direction to move the position indicator
85 //! @param mode - mode for seeking
86 //! @return new position if successful, otherwise -1
87 std::streampos seekoff(
88 const std::streamoff off, const std::ios_base::seekdir way, const std::ios_base::openmode mode) override;
89 //! @brief Set the position indicator to an absolute position.
90 //! @param sp - absolute position to set
91 //! @param mode - mode for seeking
92 //! @return new position if successful, otherwise -1
93 std::streampos seekpos(const std::streampos sp, const std::ios_base::openmode mode) override;
94 //! @brief Get the number of characters available for reading.
95 //! @return number of characters available in the input buffer
96 std::streamsize showmanyc() override;
97};
98
99//! @brief Handle reading from a file using a custom stream buffer.
100class FileReader
101{
102public:
103 //! @brief Construct a new FileReader object.
104 //! @param filename - file path to be read
105 explicit FileReader(const std::string_view filename) : name{filename} {}
106 //! @brief Destroy the FileReader object.
107 virtual ~FileReader();
108 //! @brief Construct a new FileReader object.
109 FileReader(const FileReader&) = delete;
110 //! @brief Construct a new FileReader object.
111 FileReader(FileReader&&) = delete;
112 //! @brief The operator (=) overloading of FileReader class.
113 //! @return reference of the FileReader object
114 FileReader& operator=(const FileReader&) = delete;
115 //! @brief The operator (=) overloading of FileReader class.
116 //! @return reference of the FileReader object
117 FileReader& operator=(FileReader&&) = delete;
118
119 //! @brief Checks if the file is currently opened.
120 //! @return be opened or not
121 bool isOpened() const;
122 //! @brief Open the file for reading.
123 void open();
124 //! @brief Close the file.
125 void close();
126 //! @brief Checks if the file is currently locked.
127 //! @return be locked or not
128 bool isLocked() const;
129 //! @brief Lock the file for shared reading.
130 void lock();
131 //! @brief Unlock the file.
132 void unlock();
133 //! @brief Get the input stream.
134 //! @return reference to the input stream
135 std::istream& stream() noexcept;
136
137private:
138 //! @brief Name of the file being read.
139 const std::string name;
140 //! @brief File descriptor associated with the file.
141 int fd{-1};
142 //! @brief Custom stream buffer for reading.
143 FDStreamBuffer strBuf;
144 //! @brief Input stream associated with the file.
145 std::istream input{&strBuf};
146 //! @brief Locking status.
147 bool lockActive{false};
148};
149
150//! @brief Handle writing from a file using a custom stream buffer.
151class FileWriter
152{
153public:
154 //! @brief Construct a new FileWriter object.
155 //! @param filename - file path to be written
156 explicit FileWriter(const std::string_view filename) : name{filename} {}
157 //! @brief Destroy the FileWriter object.
158 virtual ~FileWriter();
159 //! @brief Construct a new FileWriter object.
160 FileWriter(const FileWriter&) = delete;
161 //! @brief Construct a new FileWriter object.
162 FileWriter(FileWriter&&) = delete;
163 //! @brief The operator (=) overloading of FileWriter class.
164 //! @return reference of the FileWriter object
165 FileWriter& operator=(const FileWriter&) = delete;
166 //! @brief The operator (=) overloading of FileWriter class.
167 //! @return reference of the FileWriter object
168 FileWriter& operator=(FileWriter&&) = delete;
169
170 //! @brief Checks if the file is currently opened.
171 //! @return be opened or not
172 bool isOpened() const;
173 //! @brief Open the file for reading.
174 //! @param overwrite - overwrite or not
175 void open(const bool overwrite = false);
176 //! @brief Close the file.
177 void close();
178 //! @brief Checks if the file is currently locked.
179 //! @return be locked or not
180 bool isLocked() const;
181 //! @brief Lock the file for exclusive reading.
182 void lock();
183 //! @brief Unlock the file.
184 void unlock();
185 //! @brief Get the output stream.
186 //! @return reference to the output stream
187 std::ostream& stream() noexcept;
188
189private:
190 //! @brief Name of the file being written.
191 const std::string name;
192 //! @brief File descriptor associated with the file.
193 int fd{-1};
194 //! @brief Custom stream buffer for writing.
195 FDStreamBuffer strBuf;
196 //! @brief Output stream associated with the file.
197 std::ostream output{&strBuf};
198 //! @brief Locking status.
199 bool lockActive{false};
200};
201} // namespace io
202} // namespace utility
203