This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Provide filesystem::path overloads for file streams (LWG 2676, partial)


On 27/10/17 13:43 +0100, Jonathan Wakely wrote:
This implements part of LWG 2676. I haven't added the new members
taking wide character strings, because they're only needed on Windows,
where the Filesystem library doesn't work yet. I'll send a follow-up
patch about those overloads.

This patch should add the wide character overloads, for systems that
support _wfopen for opening a FILE from a wchar_t string (i.e. MinGW
and MinGW-w64). This is the missing part of LWG 2676.

These are not templates, so would require new symbols to be exported
from the library (but only for Windows). As is done with std::string
for now, I've just disabled the explicit instantiation declarations
for C++17, so the functions get implicitly instantiated as needed.

I'm not committing this, because I haven't tested it, and I get angry
people complaining why I try to support Windows in good faith. So this
is provided with no testing and not committed. Windows users can do
their own testing.


commit f6a912da2ebcfd1eaedb8fb894421f3accf9cb06
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Oct 24 19:11:06 2017 +0100

    create fstreams from wide strings

diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc
index eeb1e5e94b6..2114698a3b8 100644
--- a/libstdc++-v3/config/io/basic_file_stdio.cc
+++ b/libstdc++-v3/config/io/basic_file_stdio.cc
@@ -249,6 +249,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     return __ret;
   }
 
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+  __basic_file<char>*
+  __basic_file<char>::open(const wchar_t* __name, ios_base::openmode __mode)
+  {
+    __basic_file* __ret = NULL;
+    const char* __c_mode = fopen_mode(__mode);
+    if (__c_mode && !this->is_open())
+      {
+	wchar_t __wc_mode[4] = { };
+	int __i = 0;
+	do
+	  {
+	    switch(__c_mode[__i]) {
+	    case 'a': __wc_mode[__i] = L'a'; break;
+	    case 'b': __wc_mode[__i] = L'b'; break;
+	    case 'r': __wc_mode[__i] = L'r'; break;
+	    case 'w': __wc_mode[__i] = L'w'; break;
+	    case '+': __wc_mode[__i] = L'+'; break;
+	    default: return __ret;
+	    }
+	  }
+	while (__c_mode[++__i]);
+
+	if ((_M_cfile = _wfopen(__name, __wc_mode)))
+	  {
+	    _M_cfile_created = true;
+	    __ret = this;
+	  }
+      }
+    return __ret;
+  }
+#endif
+
   bool
   __basic_file<char>::is_open() const throw ()
   { return _M_cfile != 0; }
diff --git a/libstdc++-v3/config/io/basic_file_stdio.h b/libstdc++-v3/config/io/basic_file_stdio.h
index f959ea534cb..11dc47de809 100644
--- a/libstdc++-v3/config/io/basic_file_stdio.h
+++ b/libstdc++-v3/config/io/basic_file_stdio.h
@@ -84,6 +84,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __basic_file*
       open(const char* __name, ios_base::openmode __mode, int __prot = 0664);
 
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      __basic_file*
+      open(const wchar_t* __name, ios_base::openmode __mode);
+#endif
+
       __basic_file*
       sys_open(__c_file* __file, ios_base::openmode);
 
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 270dcbaf723..7ae3d4376aa 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -257,6 +257,7 @@ if $GLIBCXX_IS_NATIVE; then
 
   AC_CHECK_FUNCS(__cxa_thread_atexit_impl __cxa_thread_atexit)
   AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
+  AC_CHECK_FUNCS(_wfopen)
 
   # For iconv support.
   AM_ICONV
diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc
index 12ea977b997..5b094a3f6e1 100644
--- a/libstdc++-v3/include/bits/fstream.tcc
+++ b/libstdc++-v3/include/bits/fstream.tcc
@@ -207,6 +207,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __ret;
     }
 
+#if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+  template<typename _CharT, typename _Traits>
+    auto
+    basic_filebuf<_CharT, _Traits>::
+    open(const wchar_t* __s, ios_base::openmode __mode)
+    -> __filebuf_type*
+    {
+      __filebuf_type *__ret = 0;
+      if (!this->is_open())
+	{
+	  _M_file.open(__s, __mode);
+	  if (this->is_open())
+	    {
+	      _M_allocate_internal_buffer();
+	      _M_mode = __mode;
+
+	      // Setup initial buffer to 'uncommitted' mode.
+	      _M_reading = false;
+	      _M_writing = false;
+	      _M_set_buffer(-1);
+
+	      // Reset to initial state.
+	      _M_state_last = _M_state_cur = _M_state_beg;
+
+	      // 27.8.1.3,4
+	      if ((__mode & ios_base::ate)
+		  && this->seekoff(0, ios_base::end, __mode)
+		  == pos_type(off_type(-1)))
+		this->close();
+	      else
+		__ret = this;
+	    }
+	}
+      return __ret;
+    }
+#endif
+#endif // C++17
+
   template<typename _CharT, typename _Traits>
     typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
     basic_filebuf<_CharT, _Traits>::
@@ -1048,6 +1087,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Inhibit implicit instantiations for required instantiations,
   // which are defined via explicit instantiations elsewhere.
 #if _GLIBCXX_EXTERN_TEMPLATE
+#if !(__cplusplus >= 201703L && _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T)
   extern template class basic_filebuf<char>;
   extern template class basic_ifstream<char>;
   extern template class basic_ofstream<char>;
@@ -1060,6 +1100,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   extern template class basic_fstream<wchar_t>;
 #endif
 #endif
+#endif
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/include/std/fstream b/libstdc++-v3/include/std/fstream
index 3205f81fb47..5f928f44df3 100644
--- a/libstdc++-v3/include/std/fstream
+++ b/libstdc++-v3/include/std/fstream
@@ -314,6 +314,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return open(__s.c_str(), __mode); }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a wide character string.
+       *  @param  __mode  The open mode flags.
+       *  @return  @c this on success, NULL on failure
+       */
+      __filebuf_type*
+      open(const wchar_t* __s, ios_base::openmode __mode);
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.
@@ -536,6 +547,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @param  Create an input file stream.
+       *  @param  __s  Wide string specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       *
+       *  @c ios_base::in is automatically included in @a __mode.
+       */
+      basic_ifstream(const wchar_t* __s,
+		     ios_base::openmode __mode = ios_base::in)
+      : __istream_type(), _M_filebuf()
+      {
+	this->init(&_M_filebuf);
+	this->open(__s, __mode);
+      }
+#endif
+
       /**
        *  @param  Create an input file stream.
        *  @param  __s  filesystem::path specifying the filename.
@@ -658,6 +686,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file, as a wide character string.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode|in).  If that function
+       *  fails, @c failbit is set in the stream's error state.
+       */
+      void
+      open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in)
+      {
+	if (!_M_filebuf.open(__s, __mode | ios_base::in))
+	  this->setstate(ios_base::failbit);
+	else
+	  this->clear();
+      }
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.
@@ -772,6 +819,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @param  Create an output file stream.
+       *  @param  __s  Wide string specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       *
+       *  @c ios_base::out | @c ios_base::trunc is automatically included in
+       *  @a __mode.
+       */
+      basic_ofstream(const wchar_t* __s,
+		     ios_base::openmode __mode = ios_base::out|ios_base::trunc)
+      : __ostream_type(), _M_filebuf()
+      {
+	this->init(&_M_filebuf);
+	this->open(__s, __mode);
+      }
+#endif
+
       /**
        *  @param  Create an output file stream.
        *  @param  __s  filesystem::path specifying the filename.
@@ -897,6 +962,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode|out).  If that
+       *  function fails, @c failbit is set in the stream's error state.
+       */
+      void
+      open(const wchar_t* __s, ios_base::openmode __mode = ios_base::out)
+      {
+	if (!_M_filebuf.open(__s, __mode | ios_base::out))
+	  this->setstate(ios_base::failbit);
+	else
+	  this->clear();
+      }
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.
@@ -1007,6 +1091,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @param  Create an input/output file stream.
+       *  @param  __s  Wide string specifying the filename.
+       *  @param  __mode  Open file in specified mode (see std::ios_base).
+       */
+      basic_fstream(const wchar_t* __s,
+		    ios_base::openmode __mode = ios_base::in | ios_base::out)
+      : __iostream_type(0), _M_filebuf()
+      {
+	this->init(&_M_filebuf);
+	this->open(__s, __mode);
+      }
+#endif
+
       /**
        *  @param  Create an input/output file stream.
        *  @param  __s  filesystem::path specifying the filename.
@@ -1129,6 +1228,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
 #if __cplusplus >= 201703L
+#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
+      /**
+       *  @brief  Opens an external file.
+       *  @param  __s  The name of the file.
+       *  @param  __mode  The open mode flags.
+       *
+       *  Calls @c std::basic_filebuf::open(__s,__mode).  If that
+       *  function fails, @c failbit is set in the stream's error state.
+       */
+      void
+      open(const wchar_t* __s,
+	   ios_base::openmode __mode = ios_base::in | ios_base::out)
+      {
+	if (!_M_filebuf.open(__s, __mode))
+	  this->setstate(ios_base::failbit);
+	else
+	  this->clear();
+      }
+#endif
+
       /**
        *  @brief  Opens an external file.
        *  @param  __s  The name of the file, as a filesystem::path.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]