cppx-core
filesystem-util.hpp
Go to the documentation of this file.
1 #pragma once // Source encoding: UTF-8 with BOM (π is a lowercase Greek "pi").
2 
3 #include <cppx-core/failure-handling/macro-fail.hpp> // CPPX_FAIL
4 #include <cppx-core/language/syntax/macro-define_tag.hpp> // CPPX_DEFINE_TAG
5 #include <cppx-core/language/syntax/macro-use.hpp> // CPPX_USE_STD
6 #include <cppx-core/language/tmp/basic-Enable_if_.hpp> // cppx::Enable_if_
7 #include <cppx-core/language/tmp/basic-type-traits.hpp> // cppx::is_same_type_
8 #include <cppx-core/language/types/C_str_.hpp> // cppx::C_str
9 #include <cppx-core/text/basic-string-building.hpp> // cppx::operator<<
10 #include <cppx-core/text/string-util.hpp> // cppx::quoted
11 
12 #include <c/stdio.hpp> // fopen, Windows _wfopen
13 #include <algorithm> // std::copy
14 #include <filesystem> // std::filesystem
15 #include <string> // std::(string, wstring)
16 #include <utility> // std::exchange
17 
18 CPPX_DEFINE_TAG( Read );
19 CPPX_DEFINE_TAG( Write );
20 CPPX_DEFINE_TAG( Append );
21 namespace cppx
22 {
23  namespace fs = std::filesystem;
24  CPPX_USE_STD( copy, exchange, string );
25 
26  inline namespace fs_util
27  {
28  template<
29  class Fs_path,
31  >
32  auto utf8_from( const Fs_path& path )
33  -> string
34  {
35  if constexpr( is_same_type_<string, decltype( path.u8string() )> )
36  {
37  return path.u8string();
38  }
39  else
40  {
41  $with( path.u8string() ) { return string( _.begin(), _.end() ); }
42  }
43  }
44 
45  inline auto open_c_file( const fs::path& path, const C_str options )
46  -> P_<FILE>
47  {
48  #ifdef _WIN32
49  using std::wstring;
50  const auto woptions = wstring( options, options + strlen( options ) );
51  return _wfopen( path.wstring().c_str(), woptions.c_str() );
52  #else
53  return fopen( path.string().c_str(), options );
54  #endif
55  }
56 
57  class C_file
58  {
59  C_file( const C_file& ) = delete;
60  auto operator=( const C_file& ) -> C_file& = delete;
61 
62  P_<FILE> m_file;
63 
64  public:
65  auto file_pointer() const
66  -> P_<FILE>
67  { return m_file; }
68 
69  operator P_<FILE> () const { return file_pointer(); }
70 
71  auto release()
72  -> P_<FILE>
73  { return exchange( m_file, nullptr ); }
74 
76  {
77  if( m_file ) { fclose( m_file ); }
78  }
79 
80  C_file( tag::Read, const fs::path& path ):
81  m_file( open_c_file( path, "rb" ) )
82  {
83  hopefully( m_file != nullptr )
84  or CPPX_FAIL(
85  "Unable to open "s << quoted( cppx::utf8_from( path ) ) << " for reading"
86  );
87  }
88 
89  C_file( tag::Write, const fs::path& path ):
90  m_file( open_c_file( path, "wb" ) )
91  {
92  hopefully( m_file != nullptr )
93  or CPPX_FAIL(
94  "Unable to open "s << quoted( cppx::utf8_from( path ) ) << " for writing"
95  );
96  }
97 
98  C_file( tag::Append, const fs::path& path ):
99  m_file( open_c_file( path, "wab" ) )
100  {
101  hopefully( m_file != nullptr )
102  or CPPX_FAIL(
103  "Unable to open "s << quoted( cppx::utf8_from( path ) ) << " for appending"
104  );
105  }
106  };
107  } // namespace fs_util
108 } // cppx
Some_type * P_
Creates a raw pointer type.
is_base_and_derived_, is_same_type_, is_a_, is_const_, is_class_, is_fixed_point_,...
auto hopefully(const Truth condition) -> Truth
CPPX_DEFINE_TAG(Read)
auto file_pointer() const -> P_< FILE >
Enable_if_ is just more readable than enable_if_t.
C_str for char const*; Wide_c_str for wchar_t const*; and Mutable_c_str and Mutable_wide_c_str as dit...
CPPX_USE_STD(basic_string, basic_string_view, bitset, char_traits, size)
C_file(tag::Append, const fs::path &path)
$define_tag(NAME) defines NAME as a ~unique pointer type in namespace tag.
auto utf8_from(const Fs_path &path) -> string
auto release() -> P_< FILE >
auto quoted(const string_view &sv) -> string
Definition: string-util.hpp:60
C_str_< char > C_str
Definition: C_str_.hpp:38
C_file(tag::Write, const fs::path &path)
auto open_c_file(const fs::path &path, const C_str options) -> P_< FILE >
#define CPPX_FAIL(...)
Definition: macro-fail.hpp:10
std::enable_if_t< condition, Result > Enable_if_
Just more readable than enable_if_t.
Macros for generating more concise and clear using statements, primarily $use_cppx and $use_std,...
C_file(tag::Read, const fs::path &path)
constexpr Truth is_same_type_