[cmake-developers] [PATCH v3 7/7] Add MinGW support for FStream

Dāvis Mosāns davispuh at gmail.com
Wed Jul 6 15:12:13 EDT 2016


std::basic_filebuf::open(const wchar_t *) isn't part of C++ standard
and it's only present for MSVC but it's not present in libstdc++ (MinGW)
so we implement this functionality using GNU stdio_filebuf extension and
_wfopen function.
---
 Source/kwsys/FStream.hxx.in | 117 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 109 insertions(+), 8 deletions(-)

diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in
index 681e4d8..f39f95a 100644
--- a/Source/kwsys/FStream.hxx.in
+++ b/Source/kwsys/FStream.hxx.in
@@ -14,33 +14,76 @@
 
 #include <@KWSYS_NAMESPACE@/Encoding.hxx>
 #include <fstream>
+#if defined(_WIN32) && !defined(_MSC_VER)
+#include <ext/stdio_filebuf.h>
+#endif
 
 namespace @KWSYS_NAMESPACE@
 {
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#if defined(_WIN32)
 # if defined(_NOEXCEPT)
 #  define @KWSYS_NAMESPACE at _FStream_NOEXCEPT _NOEXCEPT
 # else
 #  define @KWSYS_NAMESPACE at _FStream_NOEXCEPT
 # endif
+
+#if defined(_MSC_VER)
+
   template<typename CharType,typename Traits>
   class basic_filebuf : public std::basic_filebuf<CharType,Traits>
   {
+# if _MSC_VER >= 1400
     public:
       typedef std::basic_filebuf<CharType,Traits> my_base_type;
       basic_filebuf *open(char const *s,std::ios_base::openmode mode)
       {
+        const std::wstring wstr = Encoding::ToWide(s);
         return static_cast<basic_filebuf*>(
-          my_base_type::open(Encoding::ToWide(s).c_str(), mode)
+          my_base_type::open(wstr.c_str(), mode)
           );
       }
+# else
+#  pragma message("Warning! Opening non-ASCII files might fail!")
+# endif
+
   };
 
+#else
+
+  inline const std::wstring getcmode(const std::ios_base::openmode mode) {
+    std::wstring cmode;
+    bool plus = false;
+    if (mode & std::ios_base::app) {
+      cmode += L"a";
+      plus = mode & std::ios_base::in ? true : false;
+    } else if (mode & std::ios_base::trunc || mode & std::ios_base::out) {
+      cmode += L"w";
+      plus = mode & std::ios_base::in ? true : false;
+    } else {
+      cmode += L"r";
+    }
+    if (mode & std::ios_base::binary) {
+      cmode += L"b";
+    } else {
+      cmode += L"t";
+    }
+    if (plus) {
+      cmode += L"+";
+    }
+    return cmode;
+  };
+
+#endif
+
   template<typename CharType,typename Traits = std::char_traits<CharType> >
   class basic_ifstream : public std::basic_istream<CharType,Traits>
   {
   public:
+#if defined(_MSC_VER)
     typedef basic_filebuf<CharType,Traits> internal_buffer_type;
+#else
+    typedef __gnu_cxx::stdio_filebuf<CharType,Traits> internal_buffer_type;
+#endif
     typedef std::basic_istream<CharType,Traits> internal_stream_type;
 
     basic_ifstream() : internal_stream_type(new internal_buffer_type())
@@ -56,7 +99,24 @@ namespace @KWSYS_NAMESPACE@
     }
     void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::in)
     {
-      if(!buf_->open(file_name,mode | std::ios_base::in))
+      mode = mode | std::ios_base::in;
+#if defined(_MSC_VER)
+      const bool success = buf_->open(file_name,mode) != 0;
+#else
+      const std::wstring wstr = Encoding::ToWide(file_name);
+      bool success = false;
+      std::wstring cmode = getcmode(mode);
+      file_ = _wfopen(wstr.c_str(), cmode.c_str());
+      if (file_) {
+        if (buf_) {
+          delete buf_;
+        }
+        buf_ = new internal_buffer_type(file_, mode);
+        this->set_rdbuf(buf_);
+        success = true;
+      }
+#endif
+      if(!success)
         {
         this->setstate(std::ios_base::failbit);
         }
@@ -75,7 +135,14 @@ namespace @KWSYS_NAMESPACE@
     }
     void close()
     {
-      if(!buf_->close())
+      bool success = buf_->close() != 0;
+#if !defined(_MSC_VER)
+      if (file_) {
+        success = fclose(file_) == 0 ? success : false;
+        file_ = 0;
+      }
+#endif
+      if(!success)
         {
         this->setstate(std::ios_base::failbit);
         }
@@ -92,19 +159,26 @@ namespace @KWSYS_NAMESPACE@
 
     ~basic_ifstream() @KWSYS_NAMESPACE at _FStream_NOEXCEPT
     {
-      buf_->close();
+      close();
       delete buf_;
     }
 
   private:
     internal_buffer_type* buf_;
+#if !defined(_MSC_VER)
+    FILE *file_ = 0;
+#endif
 };
 
 template<typename CharType,typename Traits = std::char_traits<CharType> >
 class basic_ofstream : public std::basic_ostream<CharType,Traits>
 {
   public:
+#if defined(_MSC_VER)
   typedef basic_filebuf<CharType,Traits> internal_buffer_type;
+#else
+  typedef __gnu_cxx::stdio_filebuf<CharType,Traits> internal_buffer_type;
+#endif
   typedef std::basic_ostream<CharType,Traits> internal_stream_type;
 
   basic_ofstream() : internal_stream_type(new internal_buffer_type())
@@ -119,7 +193,24 @@ class basic_ofstream : public std::basic_ostream<CharType,Traits>
   }
   void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out)
   {
-    if(!buf_->open(file_name,mode | std::ios_base::out))
+    mode = mode | std::ios_base::out;
+#if defined(_MSC_VER)
+    const bool success = buf_->open(file_name,mode) != 0;
+#else
+    const std::wstring wstr = Encoding::ToWide(file_name);
+    bool success = false;
+    std::wstring cmode = getcmode(mode);
+    file_ = _wfopen(wstr.c_str(), cmode.c_str());
+    if (file_) {
+      if (buf_) {
+        delete buf_;
+      }
+      buf_ = new internal_buffer_type(file_, mode);
+      this->set_rdbuf(buf_);
+      success = true;
+    }
+#endif
+    if(!success)
     {
     this->setstate(std::ios_base::failbit);
     }
@@ -138,7 +229,14 @@ class basic_ofstream : public std::basic_ostream<CharType,Traits>
   }
   void close()
   {
-    if(!buf_->close())
+    bool success = buf_->close() != 0;
+#if !defined(_MSC_VER)
+    if (file_) {
+      success = fclose(file_) == 0 ? success : false;
+      file_ = 0;
+    }
+#endif
+    if(!success)
       {
       this->setstate(std::ios_base::failbit);
       }
@@ -154,12 +252,15 @@ class basic_ofstream : public std::basic_ostream<CharType,Traits>
   }
   ~basic_ofstream() @KWSYS_NAMESPACE at _FStream_NOEXCEPT
   {
-    buf_->close();
+    close();
     delete buf_;
   }
 
   private:
   internal_buffer_type* buf_;
+#if !defined(_MSC_VER)
+    FILE *file_ = 0;
+#endif
 };
 
   typedef basic_ifstream<char> ifstream;
-- 
2.9.0



More information about the cmake-developers mailing list