std::basic_filebuf::open(const wchar_t *) isn't part of C++ standard and it's only present for MSVC but it isn't present in libstdc++ (MinGW) so we implement this functionality using GNU libstdc++ stdio_filebuf extension and _wfopen function. --- CMakeLists.txt | 14 +++ Source/kwsys/CMakeLists.txt | 8 ++ Source/kwsys/FStream.hxx.in | 235 +++++++++++++++++++++++++++++++------------- 3 files changed, 187 insertions(+), 70 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt index 792b5a5..b53c6b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,6 +273,20 @@ macro (CMAKE_BUILD_UTILITIES) CMAKE_SET_TARGET_FOLDER(${KWSYS_NAMESPACE}TestSharedForward "${kwsys_folder}") endif() + IF(KWSYS_USE_SystemTools) + SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_FStream 1) + SET(KWSYS_USE_Encoding 1) + ENDIF() + + IF(KWSYS_USE_FStream) + INCLUDE(CheckIncludeFileCXX) + CHECK_INCLUDE_FILE_CXX(ext/stdio_filebuf.h HAVE_EXT_STDIO_FILEBUF_H) + IF(HAVE_EXT_STDIO_FILEBUF_H) + add_definitions(-DHAVE_EXT_STDIO_FILEBUF_H=1) + ENDIF() + ENDIF() + #--------------------------------------------------------------------- # Setup third-party libraries. # Everything in the tree should be able to include files from the diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 33a97e6..02ba2db 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -636,6 +636,14 @@ IF(KWSYS_USE_SystemInformation) ENDIF() ENDIF() +IF(KWSYS_USE_FStream) + INCLUDE(CheckIncludeFileCXX) + CHECK_INCLUDE_FILE_CXX(ext/stdio_filebuf.h HAVE_EXT_STDIO_FILEBUF_H) + IF(HAVE_EXT_STDIO_FILEBUF_H) + add_definitions(-DHAVE_EXT_STDIO_FILEBUF_H=1) + ENDIF() +ENDIF() + #----------------------------------------------------------------------------- # Choose a directory for the generated headers. IF(NOT KWSYS_HEADER_ROOT) diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in index 681e4d8..eb911c9 100644 --- a/Source/kwsys/FStream.hxx.in +++ b/Source/kwsys/FStream.hxx.in @@ -14,152 +14,247 @@ #include <@KWSYS_NAMESPACE@/Encoding.hxx> #include <fstream> +#if defined(_WIN32) +# if !defined(_MSC_VER) && defined(HAVE_EXT_STDIO_FILEBUF_H) +# include <ext/stdio_filebuf.h> +# elif !defined(_MSC_VER) || _MSC_VER < 1400 +# pragma message("WARNING: Opening non-ASCII files might fail!") +# endif +#endif namespace @KWSYS_NAMESPACE@ { -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(_WIN32) && (defined(_MSC_VER) || defined(HAVE_EXT_STDIO_FILEBUF_H)) # if defined(_NOEXCEPT) # define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT # else # define @KWSYS_NAMESPACE@_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) ); } +# endif + }; + +#else + + inline 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 && (mode & std::ios_base::in) == 0)) { + cmode += L"w"; + plus = mode & std::ios_base::in ? true : false; + } else { + cmode += L"r"; + plus = mode & std::ios_base::out ? true : false; + } + if (plus) { + cmode += L"+"; + } + if (mode & std::ios_base::binary) { + cmode += L"b"; + } else { + cmode += L"t"; + } + return cmode; }; +#endif + template<typename CharType,typename Traits = std::char_traits<CharType> > - class basic_ifstream : public std::basic_istream<CharType,Traits> + class basic_efilebuf { + 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 + + basic_efilebuf() : file_(0) + { + buf_ = 0; + } + + bool _open(char const *file_name,std::ios_base::openmode mode) + { + if (is_open() || file_) { + return false; + } +#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); + success = true; + } +#endif + return success; + } + + bool is_open() + { + if (!buf_) { + return false; + } + return buf_->is_open(); + } + + bool is_open() const + { + if (!buf_) { + return false; + } + return buf_->is_open(); + } + + bool _close() + { + bool success = false; + if (buf_) { + success = buf_->close() != 0; +#if !defined(_MSC_VER) + if (file_) { + success = fclose(file_) == 0 ? success : false; + file_ = 0; + } +#endif + } + return success; + } + + static void _set_state(bool success, std::basic_ios<CharType,Traits> *ios, internal_buffer_type* buf_) + { +#if !defined(_MSC_VER) + ios->rdbuf(buf_); +#endif + if (!success) { + ios->setstate(std::ios_base::failbit); + } else { + ios->clear(); + } + } + + ~basic_efilebuf() + { + if (buf_) { + delete buf_; + } + } + + protected: + internal_buffer_type* buf_; + FILE *file_; + }; + +template<typename CharType,typename Traits = std::char_traits<CharType> > +class basic_ifstream : public std::basic_istream<CharType,Traits>, + public basic_efilebuf<CharType,Traits> +{ + using basic_efilebuf<CharType,Traits>::is_open; + public: - typedef basic_filebuf<CharType,Traits> internal_buffer_type; + typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type internal_buffer_type; typedef std::basic_istream<CharType,Traits> internal_stream_type; basic_ifstream() : internal_stream_type(new internal_buffer_type()) { - buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); + this->buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); } explicit basic_ifstream(char const *file_name, std::ios_base::openmode mode = std::ios_base::in) : internal_stream_type(new internal_buffer_type()) { - buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); + this->buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); open(file_name,mode); } + 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)) - { - this->setstate(std::ios_base::failbit); - } - else - { - this->clear(); - } - } - bool is_open() - { - return buf_->is_open(); - } - bool is_open() const - { - return buf_->is_open(); + mode = mode | std::ios_base::in; + this->_set_state(this->_open(file_name, mode), this, this->buf_); } + void close() { - if(!buf_->close()) - { - this->setstate(std::ios_base::failbit); - } - else - { - this->clear(); - } + this->_set_state(this->_close(), this, this->buf_); } internal_buffer_type *rdbuf() const { - return buf_; + return this->buf_; } ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { - buf_->close(); - delete buf_; + close(); } - - private: - internal_buffer_type* buf_; }; template<typename CharType,typename Traits = std::char_traits<CharType> > -class basic_ofstream : public std::basic_ostream<CharType,Traits> +class basic_ofstream : public std::basic_ostream<CharType,Traits>, + public basic_efilebuf<CharType,Traits> { + using basic_efilebuf<CharType,Traits>::is_open; + public: - typedef basic_filebuf<CharType,Traits> internal_buffer_type; + typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type internal_buffer_type; typedef std::basic_ostream<CharType,Traits> internal_stream_type; basic_ofstream() : internal_stream_type(new internal_buffer_type()) { - buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); + this->buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); } explicit basic_ofstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::out) : internal_stream_type(new internal_buffer_type()) { - buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); + this->buf_ = static_cast<internal_buffer_type *>(internal_stream_type::rdbuf()); open(file_name,mode); } 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)) - { - this->setstate(std::ios_base::failbit); - } - else - { - this->clear(); - } - } - bool is_open() - { - return buf_->is_open(); - } - bool is_open() const - { - return buf_->is_open(); + mode = mode | std::ios_base::out; + this->_set_state(this->_open(file_name, mode), this, this->buf_); } + void close() { - if(!buf_->close()) - { - this->setstate(std::ios_base::failbit); - } - else - { - this->clear(); - } + this->_set_state(this->_close(), this, this->buf_); } internal_buffer_type *rdbuf() const { - return buf_.get(); + return this->buf_; } + ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { - buf_->close(); - delete buf_; + close(); } - - private: - internal_buffer_type* buf_; }; typedef basic_ifstream<char> ifstream; -- 2.9.0 -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake-developers