| 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. |
| 14 | namespace utility // NOLINT(modernize-concat-nested-namespaces) |
| 15 | { |
| 16 | //! @brief I/O-operation-related functions in the utility module. |
| 17 | namespace io |
| 18 | { |
| 19 | //! @brief Brief function description. |
| 20 | //! @return function description (module_function) |
| 21 | inline static const char* description() noexcept |
| 22 | { |
| 23 | return "UTIL_IO" ; |
| 24 | } |
| 25 | extern const char* version() noexcept; |
| 26 | |
| 27 | extern std::string executeCommand(const std::string& command); |
| 28 | extern void waitForUserInput(const std::function<bool(const std::string&)>& operation, const int timeout = -1); |
| 29 | extern 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. |
| 33 | class FDStreamBuffer : public std::streambuf |
| 34 | { |
| 35 | public: |
| 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 | |
| 58 | private: |
| 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 | |
| 72 | protected: |
| 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. |
| 101 | class FileReader |
| 102 | { |
| 103 | public: |
| 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 | |
| 138 | private: |
| 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. |
| 152 | class FileWriter |
| 153 | { |
| 154 | public: |
| 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 | |
| 190 | private: |
| 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 | |