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 <jwak...@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.