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. --- Source/kwsys/CMakeLists.txt | 5 ++ Source/kwsys/Configure.hxx.in | 7 ++- Source/kwsys/FStream.hxx.in | 86 ++++++++++++++++++++++++++++++---- Source/kwsys/kwsysPlatformTestsCXX.cxx | 6 +++ bootstrap | 11 +++++ 5 files changed, 105 insertions(+), 10 deletions(-)
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 33a97e6..297a7bd 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -636,6 +636,11 @@ IF(KWSYS_USE_SystemInformation) ENDIF() ENDIF() +IF(KWSYS_USE_FStream) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H + "Checking whether <ext/stdio_filebuf.h> is available" DIRECT) +ENDIF() + #----------------------------------------------------------------------------- # Choose a directory for the generated headers. IF(NOT KWSYS_HEADER_ROOT) diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in index ff8e49d..4ce680d 100644 --- a/Source/kwsys/Configure.hxx.in +++ b/Source/kwsys/Configure.hxx.in @@ -17,6 +17,8 @@ /* Whether wstring is available. */ #define @KWSYS_NAMESPACE@_STL_HAS_WSTRING @KWSYS_STL_HAS_WSTRING@ +/* Whether <ext/stdio_filebuf.h> is available. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ /* If building a C++ file in kwsys itself, give the source file access to the macros without a configured namespace. */ @@ -24,8 +26,9 @@ # if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS # define kwsys @KWSYS_NAMESPACE@ # endif -# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING +# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING +# define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H #endif #endif diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in index 248b0cb..c13f91d 100644 --- a/Source/kwsys/FStream.hxx.in +++ b/Source/kwsys/FStream.hxx.in @@ -12,20 +12,32 @@ #ifndef @KWSYS_NAMESPACE@_FStream_hxx #define @KWSYS_NAMESPACE@_FStream_hxx +#include <@KWSYS_NAMESPACE@/Configure.hxx> #include <@KWSYS_NAMESPACE@/Encoding.hxx> #include <fstream> +#if defined(_WIN32) +# if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_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) || @KWSYS_NAMESPACE@_CXX_HAS_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) @@ -35,25 +47,73 @@ namespace @KWSYS_NAMESPACE@ 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_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() + basic_efilebuf() : file_(0) { buf_ = 0; } bool _open(char const *file_name,std::ios_base::openmode mode) { - if (is_open()) { + 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; } @@ -78,12 +138,21 @@ namespace @KWSYS_NAMESPACE@ 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) + static void _set_state(bool success, std::basic_ios<CharType,Traits> *ios, basic_efilebuf* efilebuf) { +#if !defined(_MSC_VER) + ios->rdbuf(efilebuf->buf_); +#endif if (!success) { ios->setstate(std::ios_base::failbit); } else { @@ -100,6 +169,7 @@ namespace @KWSYS_NAMESPACE@ protected: internal_buffer_type* buf_; + FILE *file_; }; template<typename CharType,typename Traits = std::char_traits<CharType> > @@ -127,12 +197,12 @@ class basic_ifstream : public std::basic_istream<CharType,Traits>, void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::in) { mode = mode | std::ios_base::in; - this->_set_state(this->_open(file_name, mode), this); + this->_set_state(this->_open(file_name, mode), this, this); } void close() { - this->_set_state(this->_close(), this); + this->_set_state(this->_close(), this, this); } internal_buffer_type *rdbuf() const @@ -169,12 +239,12 @@ class basic_ofstream : public std::basic_ostream<CharType,Traits>, void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out) { mode = mode | std::ios_base::out; - this->_set_state(this->_open(file_name, mode), this); + this->_set_state(this->_open(file_name, mode), this, this); } void close() { - this->_set_state(this->_close(), this); + this->_set_state(this->_close(), this, this); } internal_buffer_type *rdbuf() const diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index fc87f91..8414692 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -349,3 +349,9 @@ int main() void f(std ::wstring*) {} int main() { return 0; } #endif + +#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H +#include <ext/stdio_filebuf.h> +int main() { return 0; } +#endif + diff --git a/bootstrap b/bootstrap index 0411c64..c0628e1 100755 --- a/bootstrap +++ b/bootstrap @@ -512,6 +512,7 @@ cmake_kwsys_config_replace_string () s/@KWSYS_LFS_REQUESTED@/${KWSYS_LFS_REQUESTED}/g; s/@KWSYS_NAME_IS_KWSYS@/${KWSYS_NAME_IS_KWSYS}/g; s/@KWSYS_STL_HAS_WSTRING@/${KWSYS_STL_HAS_WSTRING}/g; + s/@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@/${KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H}/g; }" >> "${OUTFILE}${_tmp}" if [ -f "${OUTFILE}${_tmp}" ]; then if "${_diff}" "${OUTFILE}" "${OUTFILE}${_tmp}" > /dev/null 2> /dev/null ; then @@ -1183,6 +1184,7 @@ KWSYS_BUILD_SHARED=0 KWSYS_LFS_AVAILABLE=0 KWSYS_LFS_REQUESTED=0 KWSYS_STL_HAS_WSTRING=0 +KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H=0 KWSYS_CXX_HAS_SETENV=0 KWSYS_CXX_HAS_UNSETENV=0 KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=0 @@ -1225,6 +1227,15 @@ else echo "${cmake_cxx_compiler} does not have stl wstring" fi +if cmake_try_run "${cmake_cxx_compiler}" \ + "${cmake_cxx_flags} -DTEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H" \ + "${cmake_source_dir}/Source/kwsys/kwsysPlatformTestsCXX.cxx" >> cmake_bootstrap.log 2>&1; then + KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H=1 + echo "${cmake_cxx_compiler} has <ext/stdio_filebuf.h>" +else + echo "${cmake_cxx_compiler} does not have <ext/stdio_filebuf.h>" +fi + # Just to be safe, let us store compiler and flags to the header file cmake_bootstrap_version='$Revision$' -- 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