From a54481131d9dc1ebbb2f82c71f4a250b3739b7fb Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 24 Feb 2020 14:33:58 +0100 Subject: [PATCH] Fix build on MinGW/Cygwin when -std=c++nn is passed That flag forces ISO conformance removing the declarations of the required _w* functions. Move the implementations using those into source files and undef __STRICT_ANSI__ inside that file Also allows to not use the *_s functions on MSVC as _CRT_SECURE_NO_WARNINGS can be safely define inside the cpp files. --- CMakeLists.txt | 2 +- build/Jamfile.v2 | 2 +- include/boost/nowide/cstdio.hpp | 45 +++-------- include/boost/nowide/cstdlib.hpp | 123 +++++++++---------------------- include/boost/nowide/filebuf.hpp | 35 +++------ src/cstdio.cpp | 74 +++++++++++++++++++ src/cstdlib.cpp | 121 ++++++++++++++++++++++++++++++ test/Jamfile.v2 | 1 + test/test_stdio.cpp | 16 +--- 9 files changed, 255 insertions(+), 164 deletions(-) create mode 100644 src/cstdio.cpp create mode 100644 src/cstdlib.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 42e31cd..2529b14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ endif() # Using glob here is ok as it is only for headers file(GLOB_RECURSE headers include/*.hpp) -add_library(boost_nowide src/iostream.cpp ${headers}) +add_library(boost_nowide src/cstdio.cpp src/cstdlib.cpp src/iostream.cpp ${headers}) add_library(Boost::nowide ALIAS boost_nowide) set_target_properties(boost_nowide PROPERTIES CXX_VISIBILITY_PRESET hidden diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 95d5632..639492d 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -14,7 +14,7 @@ project boost/nowide shared:BOOST_NOWIDE_DYN_LINK=1 ; -SOURCES = iostream ; +SOURCES = cstdio cstdlib iostream ; lib boost_nowide : $(SOURCES).cpp diff --git a/include/boost/nowide/cstdio.hpp b/include/boost/nowide/cstdio.hpp index 7a313ad..bf48045 100644 --- a/include/boost/nowide/cstdio.hpp +++ b/include/boost/nowide/cstdio.hpp @@ -1,5 +1,6 @@ // // Copyright (c) 2012 Artyom Beilis (Tonkikh) +// Copyright (c) 2020 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -8,18 +9,9 @@ #ifndef BOOST_NOWIDE_CSTDIO_HPP_INCLUDED #define BOOST_NOWIDE_CSTDIO_HPP_INCLUDED -#include - -#ifdef BOOST_WINDOWS -#include -#endif +#include #include -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable : 4996) -#endif - namespace boost { namespace nowide { #if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN) @@ -32,43 +24,24 @@ namespace nowide { /// /// \brief Same as freopen but file_name and mode are UTF-8 strings /// - inline FILE* freopen(const char* file_name, const char* mode, FILE* stream) - { - const wstackstring wname(file_name); - const wshort_stackstring wmode(mode); - return _wfreopen(wname.get(), wmode.get(), stream); - } + BOOST_NOWIDE_DECL FILE* freopen(const char* file_name, const char* mode, FILE* stream); /// /// \brief Same as fopen but file_name and mode are UTF-8 strings /// - inline FILE* fopen(const char* file_name, const char* mode) - { - const wstackstring wname(file_name); - const wshort_stackstring wmode(mode); - return _wfopen(wname.get(), wmode.get()); - } + BOOST_NOWIDE_DECL FILE* fopen(const char* file_name, const char* mode); /// /// \brief Same as rename but old_name and new_name are UTF-8 strings /// - inline int rename(const char* old_name, const char* new_name) - { - const wstackstring wold(old_name), wnew(new_name); - return _wrename(wold.get(), wnew.get()); - } + BOOST_NOWIDE_DECL int rename(const char* old_name, const char* new_name); /// /// \brief Same as rename but name is UTF-8 string /// - inline int remove(const char* name) - { - const wstackstring wname(name); - return _wremove(wname.get()); - } + BOOST_NOWIDE_DECL int remove(const char* name); #endif + namespace detail { + BOOST_NOWIDE_DECL FILE* wfopen(const wchar_t* filename, const wchar_t* mode); + } } // namespace nowide } // namespace boost -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - #endif diff --git a/include/boost/nowide/cstdlib.hpp b/include/boost/nowide/cstdlib.hpp index 3385fbb..657222e 100644 --- a/include/boost/nowide/cstdlib.hpp +++ b/include/boost/nowide/cstdlib.hpp @@ -8,12 +8,8 @@ #ifndef BOOST_NOWIDE_CSTDLIB_HPP_INCLUDED #define BOOST_NOWIDE_CSTDLIB_HPP_INCLUDED -#include -#ifdef BOOST_WINDOWS -#include -#include -#include -#else +#include +#if !BOOST_WINDOWS #include #endif @@ -21,9 +17,6 @@ namespace boost { namespace nowide { #if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN) using std::getenv; - using ::setenv; - using ::unsetenv; - using ::putenv; using std::system; #else /// @@ -31,91 +24,43 @@ namespace nowide { /// /// This function is not thread safe or reenterable as defined by the standard library /// - inline char* getenv(const char* key) - { - static stackstring value; - - const wshort_stackstring name(key); - - static const size_t buf_size = 64; - wchar_t buf[buf_size]; - std::vector tmp; - wchar_t* ptr = buf; - size_t n = GetEnvironmentVariableW(name.get(), buf, buf_size); - if(n == 0 && GetLastError() == 203) // ERROR_ENVVAR_NOT_FOUND - return 0; - if(n >= buf_size) - { - tmp.resize(n + 1, L'\0'); - n = GetEnvironmentVariableW(name.get(), &tmp[0], static_cast(tmp.size() - 1)); - // The size may have changed - if(n >= tmp.size() - 1) - return 0; - ptr = &tmp[0]; - } - value.convert(ptr); - return value.get(); - } - /// - /// \brief UTF-8 aware setenv, \a key - the variable name, \a value is a new UTF-8 value, - /// - /// if overwrite is not 0, that the old value is always overwritten, otherwise, - /// if the variable exists it remains unchanged - /// - inline int setenv(const char* key, const char* value, int overwrite) - { - const wshort_stackstring name(key); - if(!overwrite) - { - wchar_t unused[2]; - if(GetEnvironmentVariableW(name.get(), unused, 2) != 0 || GetLastError() != 203) // ERROR_ENVVAR_NOT_FOUND - return 0; - } - const wstackstring wval(value); - if(SetEnvironmentVariableW(name.get(), wval.get())) - return 0; - return -1; - } - /// - /// \brief Remove environment variable \a key - /// - inline int unsetenv(const char* key) - { - const wshort_stackstring name(key); - if(SetEnvironmentVariableW(name.get(), 0)) - return 0; - return -1; - } - /// - /// \brief UTF-8 aware putenv implementation, expects string in format KEY=VALUE - /// - inline int putenv(char* string) - { - const char* key = string; - const char* key_end = string; - while(*key_end != '=' && *key_end != '\0') - key_end++; - if(*key_end == '\0') - return -1; - const wshort_stackstring wkey(key, key_end); - const wstackstring wvalue(key_end + 1); - - if(SetEnvironmentVariableW(wkey.get(), wvalue.get())) - return 0; - return -1; - } + BOOST_NOWIDE_DECL char* getenv(const char* key); /// /// Same as std::system but cmd is UTF-8. /// - inline int system(const char* cmd) - { - if(!cmd) - return _wsystem(0); - const wstackstring wcmd(cmd); - return _wsystem(wcmd.get()); - } + BOOST_NOWIDE_DECL int system(const char* cmd); + #endif + /// + /// \brief Set environment variable \a key to \a value + /// + /// if overwrite is not 0, that the old value is always overwritten, otherwise, + /// if the variable exists it remains unchanged + /// + /// \a key and \a value are UTF-8 on Windows + /// \return zero on success, else nonzero + /// + BOOST_NOWIDE_DECL int setenv(const char* key, const char* value, int overwrite); + + /// + /// \brief Remove environment variable \a key + /// + /// \a key is UTF-8 on Windows + /// \return zero on success, else nonzero + /// + BOOST_NOWIDE_DECL int unsetenv(const char* key); + + /// + /// \brief Adds or changes an environment variable, \a string must be in format KEY=VALUE + /// + /// \a string MAY become part of the environment, hence changes to the value MAY change + /// the environment. For portability it is hence recommended NOT to change it. + /// \a string is UTF-8 on Windows + /// \return zero on success, else nonzero + /// + BOOST_NOWIDE_DECL int putenv(char* string); + } // namespace nowide } // namespace boost diff --git a/include/boost/nowide/filebuf.hpp b/include/boost/nowide/filebuf.hpp index 4fbe428..9faca47 100644 --- a/include/boost/nowide/filebuf.hpp +++ b/include/boost/nowide/filebuf.hpp @@ -1,6 +1,6 @@ // // Copyright (c) 2012 Artyom Beilis (Tonkikh) -// Copyright (c) 2019 Alexander Grund +// Copyright (c) 2019-2020 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -11,6 +11,7 @@ #include #if BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS +#include #include #include #include @@ -23,18 +24,12 @@ #include #endif -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable : 4996 4244 4800) -#endif - namespace boost { namespace nowide { #if !BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS && !defined(BOOST_NOWIDE_DOXYGEN) using std::basic_filebuf; using std::filebuf; #else // Windows - /// /// \brief This forward declaration defines the basic_filebuf type. /// @@ -103,14 +98,7 @@ namespace nowide { const wchar_t* smode = get_mode(mode); if(!smode) return 0; -#ifdef BOOST_WINDOWS - file_ = ::_wfopen(s, smode); -#else - const stackstring name(s); - const short_stackstring smode2(smode); - file_ = std::fopen(name.get(), smode2.get()); -#endif - + file_ = detail::wfopen(s, smode); if(!file_) return 0; if(ate && std::fseek(file_, 0, SEEK_END) != 0) @@ -177,7 +165,7 @@ namespace nowide { if(owns_buffer_) delete[] buffer_; buffer_ = s; - buffer_size_ = (n >= 0) ? n : 0; + buffer_size_ = (n >= 0) ? static_cast(n) : 0; return this; } @@ -197,7 +185,7 @@ namespace nowide { setp(buffer_, buffer_ + buffer_size_); if(c != EOF) { - *buffer_ = c; + *buffer_ = Traits::to_char_type(c); pbump(1); } } else if(c != EOF) @@ -206,7 +194,7 @@ namespace nowide { { make_buffer(); setp(buffer_, buffer_ + buffer_size_); - *buffer_ = c; + *buffer_ = Traits::to_char_type(c); pbump(1); } else if(std::fputc(c, file_) == EOF) { @@ -247,7 +235,7 @@ namespace nowide { const int c = std::fgetc(file_); if(c == EOF) return EOF; - last_char_ = c; + last_char_ = Traits::to_char_type(c); setg(&last_char_, &last_char_, &last_char_ + 1); } else { @@ -305,7 +293,8 @@ namespace nowide { case std::ios_base::end: whence = SEEK_END; break; default: assert(false); return EOF; } - if(std::fseek(file_, off, whence) != 0) + assert(off <= std::numeric_limits::max()); + if(std::fseek(file_, static_cast(off), whence) != 0) return EOF; return std::ftell(file_); } @@ -330,7 +319,7 @@ namespace nowide { const std::streamsize off = gptr() - egptr(); setg(0, 0, 0); assert(off <= std::numeric_limits::max()); - if(off && std::fseek(file_, off, SEEK_CUR) != 0) + if(off && std::fseek(file_, static_cast(off), SEEK_CUR) != 0) return false; } return true; @@ -427,8 +416,4 @@ namespace nowide { } // namespace nowide } // namespace boost -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - #endif diff --git a/src/cstdio.cpp b/src/cstdio.cpp new file mode 100644 index 0000000..0b0e75c --- /dev/null +++ b/src/cstdio.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// Copyright (c) 2020 Alexander Grund +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#define BOOST_NOWIDE_SOURCE + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#elif(defined(__MINGW32__) || defined(__CYGWIN__)) && defined(__STRICT_ANSI__) +// Need the _w* functions which are extensions on MinGW/Cygwin +#undef __STRICT_ANSI__ +#endif + +#include +#include + +namespace boost { +namespace nowide { + namespace detail { + FILE* wfopen(const wchar_t* filename, const wchar_t* mode) + { +#ifdef BOOST_WINDOWS + return ::_wfopen(filename, mode); +#else + const stackstring name(filename); + const short_stackstring smode2(mode); + return std::fopen(name.get(), smode2.get()); +#endif + } + } // namespace detail + +#ifdef BOOST_WINDOWS + /// + /// \brief Same as freopen but file_name and mode are UTF-8 strings + /// + FILE* freopen(const char* file_name, const char* mode, FILE* stream) + { + const wstackstring wname(file_name); + const wshort_stackstring wmode(mode); + return _wfreopen(wname.get(), wmode.get(), stream); + } + /// + /// \brief Same as fopen but file_name and mode are UTF-8 strings + /// + FILE* fopen(const char* file_name, const char* mode) + { + const wstackstring wname(file_name); + const wshort_stackstring wmode(mode); + return _wfopen(wname.get(), wmode.get()); + } + /// + /// \brief Same as rename but old_name and new_name are UTF-8 strings + /// + int rename(const char* old_name, const char* new_name) + { + const wstackstring wold(old_name), wnew(new_name); + return _wrename(wold.get(), wnew.get()); + } + /// + /// \brief Same as rename but name is UTF-8 string + /// + int remove(const char* name) + { + const wstackstring wname(name); + return _wremove(wname.get()); + } +#endif +} // namespace nowide +} // namespace boost diff --git a/src/cstdlib.cpp b/src/cstdlib.cpp new file mode 100644 index 0000000..8fbda07 --- /dev/null +++ b/src/cstdlib.cpp @@ -0,0 +1,121 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// Copyright (c) 2020 Alexander Grund +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#define BOOST_NOWIDE_SOURCE + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#elif(defined(__MINGW32__) || defined(__CYGWIN__)) && defined(__STRICT_ANSI__) +// Need the _w* functions which are extensions on MinGW/Cygwin +#undef __STRICT_ANSI__ +#endif + +#include + +#if !BOOST_WINDOWS +namespace boost { +namespace nowide { + int setenv(const char* key, const char* value, int overwrite) + { + return ::setenv(key, value, overwrite); + } + + int unsetenv(const char* key) + { + return ::unsetenv(key); + } + + int putenv(char* string) + { + return ::putenv(string); + } +} // namespace nowide +} // namespace boost +#else +#include +#include +#include + +namespace boost { +namespace nowide { + char* getenv(const char* key) + { + static stackstring value; + + const wshort_stackstring name(key); + + static const size_t buf_size = 64; + wchar_t buf[buf_size]; + std::vector tmp; + wchar_t* ptr = buf; + size_t n = GetEnvironmentVariableW(name.get(), buf, buf_size); + if(n == 0 && GetLastError() == 203) // ERROR_ENVVAR_NOT_FOUND + return 0; + if(n >= buf_size) + { + tmp.resize(n + 1, L'\0'); + n = GetEnvironmentVariableW(name.get(), &tmp[0], static_cast(tmp.size() - 1)); + // The size may have changed + if(n >= tmp.size() - 1) + return 0; + ptr = &tmp[0]; + } + value.convert(ptr); + return value.get(); + } + + int setenv(const char* key, const char* value, int overwrite) + { + const wshort_stackstring name(key); + if(!overwrite) + { + wchar_t unused[2]; + if(GetEnvironmentVariableW(name.get(), unused, 2) != 0 || GetLastError() != 203) // ERROR_ENVVAR_NOT_FOUND + return 0; + } + const wstackstring wval(value); + if(SetEnvironmentVariableW(name.get(), wval.get())) + return 0; + return -1; + } + + int unsetenv(const char* key) + { + const wshort_stackstring name(key); + if(SetEnvironmentVariableW(name.get(), 0)) + return 0; + return -1; + } + + int putenv(char* string) + { + const char* key = string; + const char* key_end = string; + while(*key_end != '=' && *key_end != '\0') + key_end++; + if(*key_end == '\0') + return -1; + const wshort_stackstring wkey(key, key_end); + const wstackstring wvalue(key_end + 1); + + if(SetEnvironmentVariableW(wkey.get(), wvalue.get())) + return 0; + return -1; + } + + int system(const char* cmd) + { + if(!cmd) + return _wsystem(0); + const wstackstring wcmd(cmd); + return _wsystem(wcmd.get()); + } +} // namespace nowide +} // namespace boost +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2597709..2fb6d99 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -10,6 +10,7 @@ import testing ; project : requirements + /boost/nowide//boost_nowide pedantic on gcc:-Wno-long-long diff --git a/test/test_stdio.cpp b/test/test_stdio.cpp index 76dadca..5766458 100644 --- a/test/test_stdio.cpp +++ b/test/test_stdio.cpp @@ -8,26 +8,18 @@ // #include + +#include #include #include #include #include "test.hpp" -#ifdef _MSC_VER -FILE* wfopen(const wchar_t* filename, const wchar_t* mode) -{ - FILE* f; - return (_wfopen_s(&f, filename, mode) == 0) ? f : NULL; -} -#else -#define wfopen _wfopen -#endif - bool file_exists(const std::string& filename) { #ifdef BOOST_WINDOWS - FILE* f = wfopen(boost::nowide::widen(filename).c_str(), L"r"); + FILE* f = boost::nowide::detail::wfopen(boost::nowide::widen(filename).c_str(), L"r"); #else FILE* f = std::fopen(filename.c_str(), "r"); #endif @@ -43,7 +35,7 @@ bool file_exists(const std::string& filename) void create_test_file(const std::string& filename) { #ifdef BOOST_WINDOWS - FILE* f = wfopen(boost::nowide::widen(filename).c_str(), L"w"); + FILE* f = boost::nowide::detail::wfopen(boost::nowide::widen(filename).c_str(), L"w"); #else FILE* f = std::fopen(filename.c_str(), "w"); #endif