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 Handling from a file using a custom stream buffer.
100//! @tparam Stream - type of stream
101template <typename Stream>
102class FileHandle
103{
104public:
105 //! @brief Construct a new FileHandle object.
106 //! @param filename - file path to be accessed
107 explicit FileHandle(const std::string_view filename) : name{filename} {}
108 //! @brief Destroy the FileHandle object.
109 virtual ~FileHandle();
110 //! @brief Construct a new FileHandle object.
111 FileHandle(const FileHandle&) = delete;
112 //! @brief Construct a new FileHandle object.
113 FileHandle(FileHandle&&) = delete;
114 //! @brief The operator (=) overloading of FileHandle class.
115 //! @return reference of the FileHandle object
116 FileHandle& operator=(const FileHandle&) = delete;
117 //! @brief The operator (=) overloading of FileHandle class.
118 //! @return reference of the FileHandle object
119 FileHandle& operator=(FileHandle&&) = delete;
120
121 //! @brief Checks if the file is currently opened.
122 //! @return be opened or not
123 [[nodiscard]] bool isOpened() const;
124 //! @brief Close the file.
125 void close();
126 //! @brief Checks if the file is currently locked.
127 //! @return be locked or not
128 [[nodiscard]] bool isLocked() const;
129 //! @brief Unlock the file.
130 void unlock();
131 //! @brief Get the stream.
132 //! @return reference to the stream
133 Stream& stream() noexcept;
134
135protected:
136 //! @brief Open the file descriptor with the specified flag.
137 //! @param flag - flag forwarded to open
138 //! @param action - action name
139 void doOpen(const int flag, const std::string_view action);
140 //! @brief Lock the file descriptor with the specified mode.
141 //! @param mode - mode forwarded to lock
142 //! @param action - action name
143 void doLock(const int mode, const std::string_view action);
144 //! @brief Name of the file being accessed.
145 const std::string name;
146 //! @brief File descriptor associated with the file.
147 int fd{-1};
148 //! @brief Custom stream buffer.
149 FDStreamBuffer stmBuf;
150 //! @brief Stream associated with the file.
151 Stream stm{&stmBuf};
152 //! @brief Locking status.
153 bool lockActive{false};
154};
155
156extern template class FileHandle<std::istream>;
157extern template class FileHandle<std::ostream>;
158
159//! @brief Handle reading from a file using a custom stream buffer.
160class FileReader final : public FileHandle<std::istream>
161{
162public:
163 using FileHandle::FileHandle;
164 //! @brief Open the file for reading.
165 void open();
166 //! @brief Lock the file for shared reading.
167 void lock();
168};
169
170//! @brief Handle writing from a file using a custom stream buffer.
171class FileWriter final : public FileHandle<std::ostream>
172{
173public:
174 using FileHandle::FileHandle;
175 //! @brief Open the file for writing.
176 //! @param overwrite - overwrite or not
177 void open(const bool overwrite = false);
178 //! @brief Lock the file for exclusive writing.
179 void lock();
180};
181} // namespace io
182} // namespace utility
183