diff --git a/include/tmp/file b/include/tmp/file index 74163b4..6513e70 100644 --- a/include/tmp/file +++ b/include/tmp/file @@ -7,10 +7,12 @@ #define TMP_FILE_H #include +#include #include #include #include #include +#include #ifdef __GLIBCXX__ #include @@ -18,6 +20,18 @@ namespace tmp { +/// Implementation-defined handle type to the file +#if defined(_WIN32) +using file_native_handle = void*; // HANDLE +#elif __has_include() +using file_native_handle = int; // POSIX file descriptor +#else +#error "Target platform not supported" +#endif + +extern "C++" std::FILE* create_file(); +extern "C++" file_native_handle get_native_handle(std::FILE* file) noexcept; + /// tmp::file is a smart handle that manages a binary temporary file, ensuring /// its deletion when the handle goes out of scope /// @@ -53,17 +67,27 @@ namespace tmp { class file : public std::iostream { public: /// Implementation-defined handle type to the file -#if defined(_WIN32) - using native_handle_type = void*; // HANDLE -#elif __has_include() - using native_handle_type = int; // POSIX file descriptor -#else -#error "Target platform not supported" -#endif + using native_handle_type = file_native_handle; /// Creates and opens a binary temporary file as if by POSIX `tmpfile` /// @throws std::filesystem::filesystem_error if cannot create a file - explicit file(); + explicit file() + : std::iostream(std::addressof(sb)), + underlying(create_file(), &std::fclose) { +#if defined(_MSC_VER) + sb = std::filebuf(underlying.get()); +#elif defined(_LIBCPP_VERSION) + sb.__open(fileno(underlying.get()), binary | in | out); +#else + sb = __gnu_cxx::stdio_filebuf(underlying.get(), binary | in | out); +#endif + + if (!sb.is_open()) { + std::error_code ec = std::make_error_code(std::io_errc::stream); + throw std::filesystem::filesystem_error("Cannot create a temporary file", + ec); + } + } file(const file&) = delete; file& operator=(const file&) = delete; @@ -87,7 +111,9 @@ public: /// Returns an implementation-defined handle to this file /// @returns The underlying implementation-defined handle - native_handle_type native_handle() const noexcept; + native_handle_type native_handle() const noexcept { + return get_native_handle(underlying.get()); + } /// Closes and deletes this file ~file() noexcept override = default; diff --git a/src/abi.hpp b/src/abi.hpp index ea6a7aa..31d21da 100644 --- a/src/abi.hpp +++ b/src/abi.hpp @@ -4,6 +4,7 @@ #ifndef TMP_ABI_H #define TMP_ABI_H +#include #include #include @@ -15,10 +16,16 @@ namespace tmp { -std::filesystem::path abi create_directory(std::string_view prefix); -void abi remove_all(const std::filesystem::path& path) noexcept; +auto abi create_directory(std::string_view prefix) -> std::filesystem::path; +auto abi remove_all(const std::filesystem::path& path) noexcept -> void; -class abi file; +auto abi create_file() -> std::FILE*; +auto abi get_native_handle(std::FILE* file) noexcept -> +#if defined(_WIN32) + void*; +#elif __has_include() + int; +#endif } // namespace tmp #endif // TMP_ABI_H diff --git a/src/directory.cpp b/src/directory.cpp index 636a633..8d81af4 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -22,6 +22,7 @@ namespace tmp { namespace { + namespace fs = std::filesystem; /// Checks if the given prefix is valid to attach to a temporary directory name diff --git a/src/file.cpp b/src/file.cpp index 6115789..27c12fa 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -23,7 +23,6 @@ #endif namespace tmp { -namespace { namespace fs = std::filesystem; @@ -35,22 +34,6 @@ static_assert(std::is_trivially_copyable_v); static_assert(std::is_same_v); #endif -#ifndef _MSC_VER -/// Open mode for binary temporary files -constexpr auto mode = std::ios::binary | std::ios::in | std::ios::out; -#endif - -/// Returns an implementation-defined handle to the file -/// @param[in] file The file to the native handle for -/// @returns The underlying implementation-defined handle -file::native_handle_type get_native_handle(std::FILE* file) noexcept { -#ifdef _WIN32 - return reinterpret_cast(_get_osfhandle(_fileno(file))); -#else - return fileno(file); -#endif -} - /// Creates and opens a binary temporary file as if by POSIX `tmpfile` /// @returns A pointer to the file stream associated with the temporary file /// @throws fs::filesystem_error if cannot create a temporary file @@ -63,26 +46,15 @@ std::FILE* create_file() { return file; } -} // namespace -file::file() - : std::iostream(std::addressof(sb)), - underlying(create_file(), &std::fclose) { -#if defined(_MSC_VER) - sb = std::filebuf(underlying.get()); -#elif defined(_LIBCPP_VERSION) - sb.__open(get_native_handle(underlying.get()), mode); +/// Returns an implementation-defined handle to the file +/// @param[in] file The file to the native handle for +/// @returns The underlying implementation-defined handle +file::native_handle_type get_native_handle(std::FILE* file) noexcept { +#ifdef _WIN32 + return reinterpret_cast(_get_osfhandle(_fileno(file))); #else - sb = __gnu_cxx::stdio_filebuf(underlying.get(), mode); + return fileno(file); #endif - - if (!sb.is_open()) { - std::error_code ec = std::make_error_code(std::io_errc::stream); - throw fs::filesystem_error("Cannot create a temporary file", ec); - } -} - -file::native_handle_type file::native_handle() const noexcept { - return get_native_handle(underlying.get()); } } // namespace tmp