2
0
mirror of https://github.com/boostorg/nowide.git synced 2026-02-21 15:12:30 +00:00

Merge pull request #71 from Flamefire/fix_CI_and_bugs

Fix CI and bugs detected
This commit is contained in:
Alexander Grund
2020-02-25 23:08:54 +01:00
committed by GitHub
21 changed files with 549 additions and 325 deletions

View File

@@ -262,8 +262,14 @@ script:
else
false
fi
# DYLD_LIBRARY_PATH causes problems on system() spawned processes
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
LINK=static
else
LINK=static,shared
fi
- which $TRAVIS_COMPILER
- $TRAVIS_COMPILER --version
- |
echo "using $TOOLSET : : $TRAVIS_COMPILER ;" > ~/user-config.jam
- ./b2 -j3 libs/nowide/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} ${VISIBILITY:+visibility=$VISIBILITY}
- ./b2 -j3 libs/nowide/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release link=$LINK ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} ${VISIBILITY:+visibility=$VISIBILITY}

View File

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

View File

@@ -13,7 +13,7 @@ branches:
- /feature\/.*/
matrix:
fast_finish: true
fast_finish: false
environment:
matrix:
@@ -81,7 +81,7 @@ test_script:
- PATH=%ADDPATH%%PATH%
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 -j3 libs/nowide/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release
- b2 -j3 libs/nowide/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release link=shared,static
- ps: |
If ("$env:BOOST_CMAKE" -eq "1") {
./b2 --clean

View File

@@ -14,7 +14,7 @@ project boost/nowide
<link>shared:<define>BOOST_NOWIDE_DYN_LINK=1
;
SOURCES = iostream ;
SOURCES = cstdio cstdlib iostream ;
lib boost_nowide
: $(SOURCES).cpp

View File

@@ -46,22 +46,31 @@
#include <boost/config/auto_link.hpp>
#endif // auto-linking disabled
/// @def BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS
/// @brief Define to 1 to use internal classes from fstream.hpp
/// @def BOOST_NOWIDE_USE_WCHAR_OVERLOADS
/// @brief Whether to use the wchar_t* overloads in fstream/filebuf
/// Enabled on Windows and Cygwin as the latter may use wchar_t in filesystem::path
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#define BOOST_NOWIDE_USE_WCHAR_OVERLOADS 1
#else
#define BOOST_NOWIDE_USE_WCHAR_OVERLOADS 0
#endif
/// @def BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
/// @brief Define to 1 to use internal class from filebuf.hpp
///
/// - On Non-Windows platforms: Define to 1 to use the same classes from header <fstream.hpp>
/// that are used on Windows.
/// - On Non-Windows platforms: Define to 1 to use the same class from header <filebuf.hpp>
/// that is used on Windows.
/// - On Windows: No effect, always overwritten to 1
///
/// Affects boost::nowide::basic_filebuf,
/// boost::nowide::basic_ofstream, boost::nowide::basic_ifstream, boost::nowide::basic_fstream
#if defined(BOOST_WINDOWS)
#ifdef BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS
#undef BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS
#if defined(BOOST_WINDOWS) || BOOST_NOWIDE_USE_WCHAR_OVERLOADS
#ifdef BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
#undef BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
#endif
#define BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS 1
#elif !defined(BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS)
#define BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS 0
#define BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT 1
#elif !defined(BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT)
#define BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT 0
#endif
#if BOOST_VERSION < 106500 && defined(BOOST_GCC) && __GNUC__ >= 7

View File

@@ -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 <boost/config.hpp>
#ifdef BOOST_WINDOWS
#include <boost/nowide/stackstring.hpp>
#endif
#include <boost/nowide/config.hpp>
#include <cstdio>
#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

View File

@@ -8,12 +8,8 @@
#ifndef BOOST_NOWIDE_CSTDLIB_HPP_INCLUDED
#define BOOST_NOWIDE_CSTDLIB_HPP_INCLUDED
#include <boost/config.hpp>
#ifdef BOOST_WINDOWS
#include <boost/nowide/stackstring.hpp>
#include <boost/nowide/windows.hpp>
#include <vector>
#else
#include <boost/nowide/config.hpp>
#if !BOOST_WINDOWS
#include <cstdlib>
#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<wchar_t> 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<unsigned>(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

View File

@@ -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
@@ -10,7 +10,8 @@
#define BOOST_NOWIDE_FILEBUF_HPP_INCLUDED
#include <boost/nowide/config.hpp>
#if BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS
#if BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/stackstring.hpp>
#include <cassert>
#include <cstdio>
@@ -23,18 +24,12 @@
#include <fstream>
#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)
#if !BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT && !defined(BOOST_NOWIDE_DOXYGEN)
using std::basic_filebuf;
using std::filebuf;
#else // Windows
///
/// \brief This forward declaration defines the basic_filebuf type.
///
@@ -97,20 +92,13 @@ namespace nowide {
if(is_open())
return NULL;
validate_cvt(this->getloc());
const bool ate = bool(mode & std::ios_base::ate);
const bool ate = (mode & std::ios_base::ate) != 0;
if(ate)
mode = mode ^ std::ios_base::ate;
mode &= ~std::ios_base::ate;
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<size_t>(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<long>::max());
if(std::fseek(file_, static_cast<long>(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<long>::max());
if(off && std::fseek(file_, off, SEEK_CUR) != 0)
if(off && std::fseek(file_, static_cast<long>(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

View File

@@ -77,7 +77,7 @@ namespace nowide {
{
open(file_name, mode);
}
#ifdef BOOST_WINDOWS
#if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
explicit basic_ifstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::in)
{
open(file_name, mode);
@@ -118,7 +118,7 @@ namespace nowide {
{
open(file_name, mode);
}
#ifdef BOOST_WINDOWS
#if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
explicit basic_ofstream(const wchar_t* file_name, std::ios_base::openmode mode = std::ios_base::out)
{
open(file_name, mode);
@@ -162,7 +162,7 @@ namespace nowide {
{
open(file_name, mode);
}
#ifdef BOOST_WINDOWS
#if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
explicit basic_fstream(const wchar_t* file_name,
std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
{
@@ -187,9 +187,6 @@ namespace nowide {
using fstream_impl::close;
using fstream_impl::rdbuf;
};
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
///
/// Same as std::filebuf but accepts UTF-8 strings under Windows
@@ -225,6 +222,7 @@ namespace nowide {
public T_StreamType::template stream_base<CharType, Traits>::type
{
typedef basic_filebuf<CharType, Traits> internal_buffer_type;
typedef buf_holder<internal_buffer_type> base_buf_holder;
typedef typename T_StreamType::template stream_base<CharType, Traits>::type stream_base;
public:
@@ -232,7 +230,9 @@ namespace nowide {
using stream_base::clear;
protected:
fstream_impl() : stream_base(rdbuf())
using base_buf_holder::buf_;
fstream_impl() : stream_base(&buf_)
{}
void open(const std::string& file_name, std::ios_base::openmode mode = T_StreamType::mode())
@@ -243,7 +243,7 @@ namespace nowide {
typename detail::enable_if_path<Path, void>::type open(const Path& file_name,
std::ios_base::openmode mode = T_StreamType::mode())
{
return open(file_name.c_str(), mode);
open(file_name.c_str(), mode);
}
void open(const char* file_name, std::ios_base::openmode mode = T_StreamType::mode())
{
@@ -252,7 +252,7 @@ namespace nowide {
else
clear();
}
#ifdef BOOST_WINDOWS
#if BOOST_NOWIDE_USE_WCHAR_OVERLOADS
void open(const wchar_t* file_name, std::ios_base::openmode mode = T_StreamType::mode())
{
if(!rdbuf()->open(file_name, mode | T_StreamType::mode_modifier()))
@@ -277,10 +277,12 @@ namespace nowide {
internal_buffer_type* rdbuf() const
{
return const_cast<internal_buffer_type*>(&this->buf_);
return const_cast<internal_buffer_type*>(&buf_);
}
};
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
/// Trait to heuristically check for a *::filesystem::path
/// Done by checking for make_preferred and filename member functions with correct signature
template<typename T>

View File

@@ -34,50 +34,6 @@ namespace nowide {
typedef CharOut output_char;
typedef CharIn input_char;
basic_stackstring(const basic_stackstring& other) : data_(NULL)
{
*this = other;
}
friend void swap(basic_stackstring& lhs, basic_stackstring& rhs)
{
if(lhs.uses_stack_memory())
{
if(rhs.uses_stack_memory())
{
for(size_t i = 0; i < buffer_size; i++)
std::swap(lhs.buffer_[i], rhs.buffer_[i]);
} else
{
lhs.data_ = rhs.data_;
rhs.data_ = rhs.buffer_;
for(size_t i = 0; i < buffer_size; i++)
rhs.buffer_[i] = lhs.buffer_[i];
}
} else if(rhs.uses_stack_memory())
{
rhs.data_ = lhs.data_;
lhs.data_ = lhs.buffer_;
for(size_t i = 0; i < buffer_size; i++)
lhs.buffer_[i] = rhs.buffer_[i];
} else
std::swap(lhs.data_, rhs.data_);
}
basic_stackstring& operator=(const basic_stackstring& other)
{
if(this != &other)
{
clear();
const size_t len = other.length();
if(other.uses_stack_memory())
data_ = buffer_;
else
data_ = new output_char[len + 1];
std::memcpy(data_, other.data_, sizeof(output_char) * (len + 1));
}
return *this;
}
basic_stackstring() : data_(NULL)
{
buffer_[0] = 0;
@@ -90,6 +46,36 @@ namespace nowide {
{
convert(begin, end);
}
basic_stackstring(const basic_stackstring& other) : data_(NULL)
{
*this = other;
}
basic_stackstring& operator=(const basic_stackstring& other)
{
if(this != &other)
{
clear();
const size_t len = other.length();
if(other.uses_stack_memory())
data_ = buffer_;
else if(other.data_)
data_ = new output_char[len + 1];
else
{
data_ = NULL;
return *this;
}
std::memcpy(data_, other.data_, sizeof(output_char) * (len + 1));
}
return *this;
}
~basic_stackstring()
{
clear();
}
output_char* convert(const input_char* input)
{
if(input)
@@ -132,9 +118,30 @@ namespace nowide {
delete[] data_;
data_ = NULL;
}
~basic_stackstring()
friend void swap(basic_stackstring& lhs, basic_stackstring& rhs)
{
clear();
if(lhs.uses_stack_memory())
{
if(rhs.uses_stack_memory())
{
for(size_t i = 0; i < buffer_size; i++)
std::swap(lhs.buffer_[i], rhs.buffer_[i]);
} else
{
lhs.data_ = rhs.data_;
rhs.data_ = rhs.buffer_;
for(size_t i = 0; i < buffer_size; i++)
rhs.buffer_[i] = lhs.buffer_[i];
}
} else if(rhs.uses_stack_memory())
{
rhs.data_ = lhs.data_;
lhs.data_ = lhs.buffer_;
for(size_t i = 0; i < buffer_size; i++)
lhs.buffer_[i] = rhs.buffer_[i];
} else
std::swap(lhs.data_, rhs.data_);
}
private:

74
src/cstdio.cpp Normal file
View File

@@ -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 <boost/nowide/cstdio.hpp>
#include <boost/nowide/stackstring.hpp>
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

121
src/cstdlib.cpp Normal file
View File

@@ -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 <boost/nowide/cstdlib.hpp>
#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 <boost/nowide/stackstring.hpp>
#include <vector>
#include <windows.h>
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<wchar_t> 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<unsigned>(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

View File

@@ -31,12 +31,12 @@
#endif
#if defined(NOWIDE_WINDOWS)
#ifdef BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS
#undef BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS
#ifdef BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
#undef BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
#endif
#define BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS 1
#elif !defined(BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS)
#define BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS 0
#define BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT 1
#elif !defined(BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT)
#define BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT 0
#endif
#endif

View File

@@ -27,7 +27,7 @@ boost_nowide_add_test(test_system_n SRC test_system.cpp DEFINITIONS BOOST_NOWIDE
if(WIN32)
boost_nowide_add_test(test_system_w SRC test_system.cpp DEFINITIONS BOOST_NOWIDE_TEST_USE_NARROW=0)
else()
boost_nowide_add_test(test_internal_fstream SRC test_fstream.cpp DEFINITIONS BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS=1)
boost_nowide_add_test(test_internal_fstream SRC test_fstream.cpp DEFINITIONS BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1)
endif()
if(NOT BOOST_NOWIDE_STANDALONE)
@@ -40,4 +40,4 @@ endif()
if(NOT BOOST_SUPERPROJECT_SOURCE_DIR)
find_package(Boost 1.56 REQUIRED COMPONENTS chrono)
endif()
boost_nowide_add_test(benchmark_fstream COMPILE_ONLY DEFINITIONS BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS=1 LIBRARIES Boost::chrono)
boost_nowide_add_test(benchmark_fstream COMPILE_ONLY DEFINITIONS BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 LIBRARIES Boost::chrono)

View File

@@ -10,6 +10,7 @@
import testing ;
project : requirements
<library>/boost/nowide//boost_nowide
<warnings>pedantic
<warnings-as-errors>on
<toolset>gcc:<cxxflags>-Wno-long-long
@@ -26,12 +27,11 @@ run test_env.cpp ;
run test_env.cpp : : : <define>BOOST_NOWIDE_TEST_INCLUDE_WINDOWS=1 : test_env_win ;
run test_fs.cpp : : : <library>/boost/filesystem//boost_filesystem/<warnings-as-errors>off : ;
run test_fstream.cpp ;
run test_fstream.cpp : : : <define>BOOST_NOWIDE_USE_FSTREAM_REPLACEMENTS=1 <target-os>windows:<build>no : test_internal_fstream;
run test_iostream.cpp : : : <library>/boost/nowide//boost_nowide <link>static : test_iostream_static ;
run test_iostream.cpp : : : <library>/boost/nowide//boost_nowide <link>shared : test_iostream_shared ;
run test_fstream.cpp : : : <define>BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 <target-os>windows:<build>no : test_internal_fstream ;
run test_iostream.cpp ;
run test_stackstring.cpp ;
run test_stdio.cpp ;
run test_system.cpp : : : <define>BOOST_NOWIDE_TEST_USE_NARROW=1 <target-os>windows:<library>shell32 : test_system_n ;
run test_system.cpp : : : <define>BOOST_NOWIDE_TEST_USE_NARROW=0 <target-os>windows:<library>shell32 <build>no <target-os>windows:<build>yes: test_system_w ;
run test_system.cpp : : : <define>BOOST_NOWIDE_TEST_USE_NARROW=0 <target-os>windows:<library>shell32 <build>no <target-os>windows:<build>yes : test_system_w ;
compile benchmark_fstream.cpp : <define>BOOST_NOWIDE_USE_WIN_FSTREAM=1 <library>/boost/chrono//boost_chrono/;
compile benchmark_fstream.cpp : <define>BOOST_NOWIDE_USE_WIN_FSTREAM=1 <library>/boost/chrono//boost_chrono/ ;

View File

@@ -19,11 +19,17 @@
#include <iomanip>
#include <iostream>
#include <map>
#include <stdexcept>
#include <vector>
#ifdef BOOST_MSVC
#pragma warning(disable : 4996) // function unsafe/deprecated
#endif
template<typename Key, typename Value, typename Key2>
Value get(const std::map<Key, Value>& map, const Key2& key)
{
typename std::map<Key, Value>::const_iterator it = map.find(key);
if(it == map.end())
throw std::runtime_error("Key not found");
return it->second;
}
namespace nw = boost::nowide;
template<typename FStream>
@@ -66,7 +72,7 @@ class io_stdio
public:
io_stdio(const char* file, bool read)
{
f_ = std::fopen(file, read ? "r" : "w+");
f_ = nw::fopen(file, read ? "r" : "w+");
TEST(f_);
}
~io_stdio()
@@ -201,8 +207,8 @@ perf_data test_io_driver(const char* file, const char* type)
double read_speed = 0, write_speed = 0;
for(int i = 0; i < repeats; i++)
{
read_speed += results[i].read.at(block_size);
write_speed += results[i].write.at(block_size);
read_speed += get(results[i].read, block_size);
write_speed += get(results[i].write, block_size);
}
results[0].read[block_size] = read_speed / repeats;
results[0].write[block_size] = write_speed / repeats;
@@ -221,9 +227,9 @@ void print_perf_data(const std::map<size_t, double>& stdio_data,
for(int block_size = MIN_BLOCK_SIZE; block_size <= MAX_BLOCK_SIZE; block_size *= 2)
{
std::cout << std::setw(8) << block_size << " ";
std::cout << std::fixed << std::setprecision(3) << std::setw(8) << stdio_data.at(block_size) << " MB/s ";
std::cout << std::fixed << std::setprecision(3) << std::setw(8) << std_data.at(block_size) << " MB/s ";
std::cout << std::fixed << std::setprecision(3) << std::setw(8) << nowide_data.at(block_size) << " MB/s ";
std::cout << std::fixed << std::setprecision(3) << std::setw(8) << get(stdio_data, block_size) << " MB/s ";
std::cout << std::fixed << std::setprecision(3) << std::setw(8) << get(std_data, block_size) << " MB/s ";
std::cout << std::fixed << std::setprecision(3) << std::setw(8) << get(nowide_data, block_size) << " MB/s ";
std::cout << std::endl;
}
}

View File

@@ -9,23 +9,64 @@
#ifndef BOOST_NOWIDE_LIB_TEST_H_INCLUDED
#define BOOST_NOWIDE_LIB_TEST_H_INCLUDED
#include <cstdlib>
#include <sstream>
#include <stdexcept>
#if defined(_MSC_VER) && defined(_CPPLIB_VER) && defined(_DEBUG)
#include <crtdbg.h>
#endif
namespace boost {
namespace nowide {
struct test_monitor
{
test_monitor()
{
#if defined(_MSC_VER) && (_MSC_VER > 1310)
// disable message boxes on assert(), abort()
::_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#if defined(_MSC_VER) && defined(_CPPLIB_VER) && defined(_DEBUG)
// disable message boxes on iterator debugging violations
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif
}
};
} // namespace nowide
} // namespace boost
inline boost::nowide::test_monitor& test_mon()
{
static boost::nowide::test_monitor instance;
return instance;
}
/// Function called when a test failed to be able set a breakpoint for debugging
inline void test_failed(const std::string& msg)
{
throw std::runtime_error(msg);
}
#ifdef _MSC_VER
#define DISABLE_CONST_EXPR_DETECTED __pragma(warning(push)) __pragma(warning(disable : 4127))
#define DISABLE_CONST_EXPR_DETECTED_POP __pragma(warning(pop))
#else
#define DISABLE_CONST_EXPR_DETECTED
#define DISABLE_CONST_EXPR_DETECTED_POP
#endif
#define TEST(x) \
do \
{ \
test_mon(); \
if(x) \
break; \
std::ostringstream ss; \
ss << "Error " #x " in " << __FILE__ << ':' << __LINE__ << " " << __FUNCTION__; \
test_failed(ss.str()); \
} while(0)
DISABLE_CONST_EXPR_DETECTED \
} while(0) DISABLE_CONST_EXPR_DETECTED_POP
#endif // #ifndef BOOST_NOWIDE_LIB_TEST_H_INCLUDED

View File

@@ -16,9 +16,17 @@
#include "test.hpp"
#ifdef BOOST_MSVC
#pragma warning(disable : 4996) // function unsafe/deprecated
#endif
// "Safe" strcpy version with NULL termination to make MSVC runtime happy
// which warns when using strncpy
template<size_t size>
void strcpy_safe(char (&dest)[size], const char* src)
{
size_t len = std::strlen(src);
if(len >= size)
len = size - 1u;
std::memcpy(dest, src, len);
dest[len] = 0;
}
int main()
{
@@ -26,7 +34,7 @@ int main()
{
std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd";
char penv[256] = {0};
strncpy(penv, ("BOOST_TEST2=" + example + "x").c_str(), sizeof(penv) - 1);
strcpy_safe(penv, ("BOOST_TEST2=" + example + "x").c_str());
TEST(boost::nowide::setenv("BOOST_TEST1", example.c_str(), 1) == 0);
TEST(boost::nowide::getenv("BOOST_TEST1"));
@@ -42,7 +50,7 @@ int main()
// But GLIBC has an extension that unsets the env var instead
char penv2[256] = {0};
const char* sPenv2 = "BOOST_TEST1SOMEGARBAGE=";
strncpy(penv2, sPenv2, sizeof(penv2) - 1);
strcpy_safe(penv2, sPenv2);
// End the string before the equals sign -> Expect fail
penv2[strlen("BOOST_TEST1")] = '\0';
TEST(boost::nowide::putenv(penv2) == -1);

View File

@@ -50,7 +50,6 @@ bool file_contents_equal(const char* filepath, const char (&contents)[N], bool b
return true;
}
template<typename FStream>
void test_with_different_buffer_sizes(const char* filepath)
{
/* Important part of the standard for mixing input with output:
@@ -63,13 +62,13 @@ void test_with_different_buffer_sizes(const char* filepath)
{
std::cout << "Buffer size = " << i << std::endl;
char buf[16];
FStream f;
nw::fstream f;
// Different conditions when setbuf might be called: Usually before opening a file is OK
if(i >= 0)
f.rdbuf()->pubsetbuf((i == 0) ? NULL : buf, i);
f.open(filepath, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
TEST(f);
// Add 'abcdefg'
TEST(f.put('a'));
TEST(f.put('b'));
TEST(f.put('c'));
@@ -77,67 +76,84 @@ void test_with_different_buffer_sizes(const char* filepath)
TEST(f.put('e'));
TEST(f.put('f'));
TEST(f.put('g'));
// Read first char
TEST(f.seekg(0));
TEST(f.get() == 'a');
TEST(f.gcount() == 1u);
// Skip next char
TEST(f.seekg(1, std::ios::cur));
TEST(f.get() == 'c');
TEST(f.gcount() == 1u);
// Go back 1 char
TEST(f.seekg(-1, std::ios::cur));
TEST(f.get() == 'c');
TEST(f.gcount() == 1u);
// Test switching between read->write->read
// case 1) overwrite, flush, read
TEST(f.seekg(1));
TEST(f.put('B'));
TEST(f.flush()); // Flush when changing out->in
TEST(f.get() == 'c');
TEST(f.gcount() == 1u);
TEST(f.seekg(1));
TEST(f.get() == 'B');
TEST(f.gcount() == 1u);
// case 2) overwrite, seek, read
TEST(f.seekg(2));
TEST(f.put('C'));
TEST(f.seekg(3)); // Seek when changing out->in
TEST(f.get() == 'd');
TEST(f.gcount() == 1u);
// Check that sequence from start equals expected
TEST(f.seekg(0));
TEST(f.get() == 'a');
TEST(f.get() == 'B');
TEST(f.get() == 'C');
TEST(f.get() == 'd');
TEST(f.get() == 'e');
// Putback after flush
// Putback after flush is implementation defined
// Boost.Nowide: Works
#if BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
TEST(f << std::flush);
TEST(f.putback('e'));
TEST(f.putback('d'));
TEST(f.get() == 'd');
TEST(f.get() == 'e');
#endif
// Rest of sequence
TEST(f.get() == 'f');
TEST(f.get() == 'g');
TEST(f.get() == EOF);
// Put back until front of file is reached
f.clear();
TEST(f.seekg(1));
TEST(f.get() == 'B');
TEST(f.putback('B'));
// Putting back multiple chars is not possible on all implementations after a seek/flush
if(f.putback('a'))
{
TEST(!f.putback('x')); // At beginning of file -> No putback possible
// Get characters that were putback to avoid MSVC bug https://github.com/microsoft/STL/issues/342
f.clear();
TEST(f.get() == 'a');
TEST(f.get() == 'B');
} else
{
f.clear();
TEST(f.get() == 'B');
}
#if BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT
TEST(f.putback('a'));
TEST(!f.putback('x')); // At beginning of file -> No putback possible
// Get characters that were putback to avoid MSVC bug https://github.com/microsoft/STL/issues/342
f.clear();
TEST(f.get() == 'a');
#endif
TEST(f.get() == 'B');
f.close();
TEST(nw::remove(filepath) == 0);
}
}
template<typename FileBuf>
void test_close(const char* filepath)
{
const std::string filepath2 = std::string(filepath) + ".2";
// Make sure file does not exist yet
nw::remove(filepath2.c_str());
TEST(!file_exists(filepath2.c_str()));
FileBuf buf;
nw::filebuf buf;
TEST(buf.open(filepath, std::ios_base::out) == &buf);
TEST(buf.is_open());
// Opening when already open fails
@@ -487,17 +503,11 @@ int main(int, char** argv)
test_fstream(exampleFilename.c_str());
test_is_open(exampleFilename.c_str());
std::cout << "Complex IO - Sanity Check" << std::endl;
// Don't use chars the std stream can't properly handle
test_with_different_buffer_sizes<std::fstream>((std::string(argv[0]) + "-bufferSize.txt").c_str());
std::cout << "Complex IO - Test" << std::endl;
test_with_different_buffer_sizes<nw::fstream>(exampleFilename.c_str());
std::cout << "Complex IO" << std::endl;
test_with_different_buffer_sizes(exampleFilename.c_str());
std::cout << "filebuf::close - Sanity Check" << std::endl;
// Don't use chars the std stream can't properly handle
test_close<std::filebuf>((std::string(argv[0]) + "-bufferSize.txt").c_str());
std::cout << "filebuf::close - Test" << std::endl;
test_close<nw::filebuf>(exampleFilename.c_str());
std::cout << "filebuf::close" << std::endl;
test_close(exampleFilename.c_str());
std::cout << "Flush - Sanity Check" << std::endl;
test_flush<std::ifstream, std::ofstream>(exampleFilename.c_str());

View File

@@ -1,5 +1,6 @@
//
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
// 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
@@ -10,6 +11,7 @@
#include "test_sets.hpp"
#include <boost/nowide/stackstring.hpp>
#include <iostream>
#include <vector>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1700
#pragma warning(disable : 4428) // universal-character-name encountered in source
@@ -48,19 +50,19 @@ int main()
const wchar_t* wempty = L"";
{
// Default constructed string is NULL
std::cout << "-- Default constructed string is NULL" << std::endl;
const boost::nowide::short_stackstring s;
TEST(s.get() == NULL);
}
{
// NULL ptr passed to ctor results in NULL
std::cout << "-- NULL ptr passed to ctor results in NULL" << std::endl;
const boost::nowide::short_stackstring s(NULL);
TEST(s.get() == NULL);
const boost::nowide::short_stackstring s2(NULL, NULL);
TEST(s2.get() == NULL);
}
{
// NULL ptr passed to convert results in NULL
std::cout << "-- NULL ptr passed to convert results in NULL" << std::endl;
boost::nowide::short_stackstring s(L"foo");
TEST(s.get() == std::string("foo"));
s.convert(NULL);
@@ -71,7 +73,7 @@ int main()
TEST(s2.get() == NULL);
}
{
// An empty string is accepted
std::cout << "-- An empty string is accepted" << std::endl;
const boost::nowide::short_stackstring s(wempty);
TEST(s.get());
TEST(s.get() == std::string());
@@ -80,7 +82,7 @@ int main()
TEST(s2.get() == std::string());
}
{
// An empty string is accepted
std::cout << "-- An empty string is accepted" << std::endl;
boost::nowide::short_stackstring s, s2;
TEST(s.convert(wempty));
TEST(s.get() == std::string());
@@ -88,8 +90,7 @@ int main()
TEST(s2.get() == std::string());
}
{
// Will be put on heap
TEST(whello.size() >= 3);
std::cout << "-- Will be put on heap" << std::endl;
boost::nowide::basic_stackstring<wchar_t, char, 3> sw;
TEST(sw.convert(hello.c_str()));
TEST(sw.get() == whello);
@@ -97,53 +98,61 @@ int main()
TEST(sw.get() == whello);
}
{
// Will be put on stack
TEST(whello.size() < 5);
boost::nowide::basic_stackstring<wchar_t, char, 5> sw;
std::cout << "-- Will be put on stack" << std::endl;
boost::nowide::basic_stackstring<wchar_t, char, 40> sw;
TEST(sw.convert(hello.c_str()));
TEST(sw.get() == whello);
TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size()));
TEST(sw.get() == whello);
}
{
// Will be put on heap
TEST(hello.size() >= 5);
boost::nowide::basic_stackstring<char, wchar_t, 5> sw;
std::cout << "-- Will be put on heap" << std::endl;
boost::nowide::basic_stackstring<char, wchar_t, 3> sw;
TEST(sw.convert(whello.c_str()));
TEST(sw.get() == hello);
TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size()));
TEST(sw.get() == hello);
}
{
// Will be put on stack
TEST(hello.size() < 10);
boost::nowide::basic_stackstring<char, wchar_t, 10> sw;
std::cout << "-- Will be put on stack" << std::endl;
boost::nowide::basic_stackstring<char, wchar_t, 40> sw;
TEST(sw.convert(whello.c_str()));
TEST(sw.get() == hello);
TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size()));
TEST(sw.get() == hello);
}
{
typedef boost::nowide::basic_stackstring<char, wchar_t, 5> stackstring;
const std::string heapVal = hello;
TEST(heapVal.size() >= 5); // Will be put on heap
const std::wstring wtest = L"test";
const std::string stackVal = "test";
TEST(stackVal.size() < 5); // Will be put on stack
const stackstring heap(whello.c_str());
const stackstring stack(wtest.c_str());
typedef boost::nowide::basic_stackstring<wchar_t, char, 6> stackstring;
const std::wstring heapVal = L"heapValue";
TEST(heapVal.size() >= 6); // Will be put on heap
const std::wstring stackVal = L"stack";
TEST(stackVal.size() < 6); // Will be put on stack
const stackstring heap(boost::nowide::narrow(heapVal).c_str());
const stackstring stack(boost::nowide::narrow(stackVal).c_str());
{
stackstring sw2(heap), sw3;
stackstring sw2(heap), sw3, sEmpty;
sw3 = heap;
TEST(sw2.get() == heapVal);
TEST(sw3.get() == heapVal);
// Self assign avoiding clang self-assign-overloaded warning
sw3 = static_cast<const stackstring&>(sw3);
TEST(sw3.get() == heapVal);
// Assign empty
sw3 = sEmpty;
TEST(sw3.get() == NULL);
}
{
stackstring sw2(stack), sw3;
stackstring sw2(stack), sw3, sEmpty;
sw3 = stack;
TEST(sw2.get() == stackVal);
TEST(sw3.get() == stackVal);
// Self assign avoiding clang self-assign-overloaded warning
sw3 = static_cast<const stackstring&>(sw3);
TEST(sw3.get() == stackVal);
// Assign empty
sw3 = sEmpty;
TEST(sw3.get() == NULL);
}
{
stackstring sw2(stack);
@@ -156,18 +165,24 @@ int main()
TEST(sw2.get() == stackVal);
}
{
stackstring sw2(heap), sw3(stack);
stackstring sw2(heap), sw3(stack), sEmpty1, sEmpty2;
swap(sw2, sw3);
TEST(sw2.get() == stackVal);
TEST(sw3.get() == heapVal);
swap(sw2, sw3);
TEST(sw2.get() == heapVal);
TEST(sw3.get() == stackVal);
swap(sw2, sEmpty1);
TEST(sEmpty1.get() == heapVal);
TEST(sw2.get() == NULL);
swap(sw3, sEmpty2);
TEST(sEmpty2.get() == stackVal);
TEST(sw3.get() == NULL);
}
{
stackstring sw2(heap), sw3(heap);
sw3.get()[0] = 'z';
const std::string val2 = sw3.get();
const std::wstring val2 = sw3.get();
swap(sw2, sw3);
TEST(sw2.get() == val2);
TEST(sw3.get() == heapVal);
@@ -175,15 +190,28 @@ int main()
{
stackstring sw2(stack), sw3(stack);
sw3.get()[0] = 'z';
const std::string val2 = sw3.get();
const std::wstring val2 = sw3.get();
swap(sw2, sw3);
TEST(sw2.get() == val2);
TEST(sw3.get() == stackVal);
}
// Sanity check
std::cout << "-- Sanity check" << std::endl;
TEST(stack.get() == stackVal);
TEST(heap.get() == heapVal);
}
{
std::cout << "-- Test putting stackstrings into vector (done by args) class" << std::endl;
// Use a smallish buffer, to have stack and heap values
typedef boost::nowide::basic_stackstring<wchar_t, char, 5> stackstring;
std::vector<stackstring> strings;
strings.resize(2);
TEST(strings[0].convert("1234") == std::wstring(L"1234"));
TEST(strings[1].convert("Hello World") == std::wstring(L"Hello World"));
strings.push_back(stackstring("FooBar"));
TEST(strings[0].get() == std::wstring(L"1234"));
TEST(strings[1].get() == std::wstring(L"Hello World"));
TEST(strings[2].get() == std::wstring(L"FooBar"));
}
std::cout << "- Stackstring" << std::endl;
run_all(stackstring_to_wide, stackstring_to_narrow);
std::cout << "- Heap Stackstring" << std::endl;

View File

@@ -8,19 +8,18 @@
//
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/convert.hpp>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include "test.hpp"
#ifdef BOOST_MSVC
#pragma warning(disable : 4996) // function unsafe/deprecated
#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
@@ -36,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
@@ -45,14 +44,24 @@ void create_test_file(const std::string& filename)
std::fclose(f);
}
#if BOOST_MSVC
#include <crtdbg.h> // For _CrtSetReportMode
void noop_invalid_param_handler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned, uintptr_t)
{}
#endif
int main(int, char** argv)
{
const std::string prefix = argv[0];
const std::string filename = prefix + "\xd7\xa9-\xd0\xbc-\xce\xbd.txt";
#if BOOST_MSVC
// Prevent abort on freopen(NULL, ...)
_set_invalid_parameter_handler(noop_invalid_param_handler);
#endif
try
{
// fopen - existing file
std::cout << " -- fopen - existing file" << std::endl;
{
create_test_file(filename);
FILE* f = boost::nowide::fopen(filename.c_str(), "r");
@@ -62,26 +71,26 @@ int main(int, char** argv)
TEST(strcmp(buf, "test\n") == 0);
std::fclose(f);
}
// remove
std::cout << " -- remove" << std::endl;
{
create_test_file(filename);
TEST(file_exists(filename));
TEST(boost::nowide::remove(filename.c_str()) == 0);
TEST(!file_exists(filename));
}
// fopen non-existing file
std::cout << " -- fopen non-existing file" << std::endl;
{
boost::nowide::remove(filename.c_str());
TEST(!file_exists(filename));
TEST(boost::nowide::fopen(filename.c_str(), "r") == NULL);
TEST(!file_exists(filename));
}
// freopen
std::cout << " -- freopen" << std::endl;
{
create_test_file(filename);
FILE* f = boost::nowide::fopen(filename.c_str(), "r+");
TEST(f);
// Can read & write
std::cout << " -- Can read & write" << std::endl;
{
char buf[32];
TEST(std::fgets(buf, 32, f) != 0);
@@ -95,7 +104,7 @@ int main(int, char** argv)
FILE* f2 = boost::nowide::freopen(NULL, "r", f);
if(!f2)
f2 = boost::nowide::freopen(filename.c_str(), "r", f);
// no write possible
std::cout << " -- no write possible" << std::endl;
{
TEST(f2 == f);
TEST(std::fputs("not-written\n", f) < 0);
@@ -106,7 +115,7 @@ int main(int, char** argv)
TEST(std::fgets(buf, 32, f) != 0);
TEST(strcmp(buf, "foobar\n") == 0);
}
// Reopen different file
std::cout << " -- Reopen different file" << std::endl;
const std::string filename2 = filename + ".1.txt";
TEST(boost::nowide::freopen(filename2.c_str(), "w", f) == f);
{
@@ -121,7 +130,7 @@ int main(int, char** argv)
std::fclose(f);
boost::nowide::remove(filename2.c_str());
}
// rename
std::cout << " -- rename" << std::endl;
{
create_test_file(filename);
const std::string filename2 = filename + ".1.txt";