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