diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/libs/nowide | |
parent | Initial commit. (diff) | |
download | ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/nowide')
36 files changed, 3674 insertions, 0 deletions
diff --git a/src/boost/libs/nowide/CMakeLists.txt b/src/boost/libs/nowide/CMakeLists.txt new file mode 100644 index 000000000..aec107828 --- /dev/null +++ b/src/boost/libs/nowide/CMakeLists.txt @@ -0,0 +1,73 @@ +# Builds the libraries for Boost.Nowide +# +# Options: +# Boost_NOWIDE_INSTALL +# Boost_NOWIDE_WERROR +# BUILD_TESTING +# +# Created target: Boost::nowide +# +# When not using CMake to link against the shared library on windows define -DBOOST_NOWIDE_DYN_LINK + +cmake_minimum_required(VERSION 3.9) +# Version number starts at 10 to avoid conflicts with Boost version +set(_version 10.0.1) +if(BOOST_SUPERPROJECT_SOURCE_DIR) + set(_version ${BOOST_SUPERPROJECT_VERSION}) +endif() +project(boost_nowide VERSION ${_version} LANGUAGES CXX) + +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif() + +list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + # Make sure all binarys (especially exe/dll) are in one directory for tests to work + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +endif() + +include(BoostAddOptions) +include(BoostAddWarnings) +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + include(CTest) +endif() + +# Using glob here is ok as it is only for headers +file(GLOB_RECURSE headers include/*.hpp) +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 + VISIBILITY_INLINES_HIDDEN ON + VERSION ${PROJECT_VERSION} + EXPORT_NAME nowide +) +if(BUILD_SHARED_LIBS) + target_compile_definitions(boost_nowide PUBLIC BOOST_NOWIDE_DYN_LINK) +endif() +target_compile_definitions(boost_nowide PUBLIC BOOST_NOWIDE_NO_LIB) +target_include_directories(boost_nowide PUBLIC include) +boost_add_warnings(boost_nowide pedantic ${Boost_NOWIDE_WERROR}) + +if(BOOST_SUPERPROJECT_SOURCE_DIR) + target_link_libraries(boost_nowide PUBLIC Boost::config Boost::smart_ptr Boost::static_assert) + set(Boost_NOWIDE_INSTALL OFF) # smart_ptr does not support installation +else() + # Default boost libs are static on windows and dynamic on linux + if(WIN32 AND NOT DEFINED Boost_USE_STATIC_LIBS) + set(Boost_USE_STATIC_LIBS ON) + endif() + find_package(Boost 1.56 REQUIRED) + target_link_libraries(boost_nowide PUBLIC Boost::boost) +endif() + +if(BUILD_TESTING) + add_subdirectory(test) +endif() + +if(Boost_NOWIDE_INSTALL) + include(InstallTargets) + install_targets(TARGETS boost_nowide NAMESPACE Boost CONFIG_FILE ${PROJECT_SOURCE_DIR}/Config.cmake.in) +endif() diff --git a/src/boost/libs/nowide/Config.cmake.in b/src/boost/libs/nowide/Config.cmake.in new file mode 100644 index 000000000..05dcc7bda --- /dev/null +++ b/src/boost/libs/nowide/Config.cmake.in @@ -0,0 +1,20 @@ +@PACKAGE_INIT@ + +set(_boost_nowide_superproject "@BOOST_SUPERPROJECT_SOURCE_DIR@") + +include(CMakeFindDependencyMacro) +if(_boost_nowide_superproject) +foreach(dep IN ITEMS boost_config boost_smart_ptr boost_static_assert) + find_dependency(${dep}) +endforeach() +else() +# Default boost libs are static on windows and dynamic on linux +if(WIN32 AND "${Boost_USE_STATIC_LIBS}" STREQUAL "") + set(Boost_USE_STATIC_LIBS ON) +endif() +find_dependency(Boost 1.56) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") + +check_required_components("@PROJECT_NAME@") diff --git a/src/boost/libs/nowide/LICENSE b/src/boost/libs/nowide/LICENSE new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/src/boost/libs/nowide/LICENSE @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/boost/libs/nowide/README.md b/src/boost/libs/nowide/README.md new file mode 100644 index 000000000..7ac024f04 --- /dev/null +++ b/src/boost/libs/nowide/README.md @@ -0,0 +1,82 @@ +# Boost.Nowide + +Branch | Travis | Appveyor | Github | codecov.io | Documentation +------------|--------|----------|--------|------------|-------------- +[master](https://github.com/boostorg/nowide/tree/master) | [![Build Status](https://travis-ci.com/boostorg/nowide.svg?branch=master)](https://travis-ci.com/boostorg/nowide) | [![Build status](https://ci.appveyor.com/api/projects/status/w5sywrekwd66say4/branch/master?svg=true)](https://ci.appveyor.com/project/Flamefire/nowide-fr98b/branch/master) | ![](https://github.com/boostorg/nowide/workflows/CI%20Tests/badge.svg?branch=master) | [![codecov](https://codecov.io/gh/boostorg/nowide/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/nowide/branch/master) | [![Documentation](https://img.shields.io/badge/documentation-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/nowide/index.html) +[develop](https://github.com/boostorg/nowide/tree/develop) | [![Build Status](https://travis-ci.com/boostorg/nowide.svg?branch=develop)](https://travis-ci.com/boostorg/nowide) | [![Build status](https://ci.appveyor.com/api/projects/status/w5sywrekwd66say4/branch/develop?svg=true)](https://ci.appveyor.com/project/Flamefire/nowide-fr98b/branch/develop) | ![](https://github.com/boostorg/nowide/workflows/CI%20Tests/badge.svg?branch=develop) | [![codecov](https://codecov.io/gh/boostorg/nowide/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/nowide/branch/develop) | [![Documentation](https://img.shields.io/badge/documentation-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/nowide/index.html) + +Coverity Scan: [![Coverity Scan Build Status](https://scan.coverity.com/projects/20464/badge.svg)](https://scan.coverity.com/projects/boostorg-nowide) + +Library for cross-platform, unicode aware programming. + +The library provides an implementation of standard C and C++ library functions, such that their inputs are UTF-8 aware on Windows without requiring to use the Wide API. + +### License + +Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). + +### Properties + +* C++03 **(will be raised to C++11 by mid 2020)** +* optional C++11/17 support +* Usable outside of Boost via CMake + +# Quickstart + +Instead of using the standard library functions use the corresponding member of Boost.Nowide with the same name. +On Linux those are (mostly) aliases for the `std` ones, but on Windows they accept UTF-8 as input and use the wide API for the underlying functionality. + +Examples: +- `std::ifstream -> boost::nowide::ifstream` +- `std::fopen -> boost::nowide::fopen` +- `std::fclose -> boost::nowide::fclose` +- `std::getenv -> boost::nowide::getenv` +- `std::putenv -> boost::nowide::putenv` +- `std::cout -> boost::nowide::cout` + +To also convert your input arguments to UTF-8 on Windows use: + +``` +int main(int argc, char **argv) +{ + boost::nowide::args _(argc, argv); // Must use an instance! + ... +} +``` + +See the [Documentation](https://www.boost.org/doc/libs/master/libs/nowide/index.html) for details. + +# Compile + +## With Boost + +Compile and install the Boost super project the usual way via `./b2`. +The headers and library will then be available together with all other Boost libraries. +From within CMake you can then use `find_package(boost_nowide)` and link against `Boost::nowide`. + +## With CMake + +Boost.Nowide fully supports CMake. +So you can use `add_subdirectory("path-to-boost-nowide-repo")` and link your project against the target `Boost::nowide`. + +You can also pre-compile and install Boost.Nowide via the usual workflow: +``` +mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local +make install +``` + +A CMake-Config file will be installed alongside Boost.Nowide so `find_package(boost_nowide)` does work out-of the box +(provided it was installed into a "standard" location or its `INSTALL_PREFIX` was added to `CMAKE_PREFIX_PATH`). + +# Boost.Filesystem integration + +Boost.Nowide integrates with Boost.Filesystem: +- Call `boost::nowide::nowide_filesystem()` to imbue UTF-8 into Boost.Filesystem (for use by `boost::filesystem::path`) such that narrow strings passed into Boost.Filesystem are treated as UTF-8 on Windows + +### More information + +* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-nowide) +* [Report bugs](https://github.com/boostorg/nowide/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. +* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). +* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[nowide]` tag at the beginning of the subject line. diff --git a/src/boost/libs/nowide/build/Jamfile.v2 b/src/boost/libs/nowide/build/Jamfile.v2 new file mode 100644 index 000000000..639492d41 --- /dev/null +++ b/src/boost/libs/nowide/build/Jamfile.v2 @@ -0,0 +1,24 @@ +# Boost Nowide Library Build Jamfile + +# (C) Copyright Beman Dawes 2002, 2006, Artyom Beilis 2012 +# + +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or www.boost.org/LICENSE_1_0.txt) + +# See library home page at http://www.boost.org/libs/nowide + +project boost/nowide + : source-location ../src + : usage-requirements # pass these requirement to dependents (i.e. users) + <link>shared:<define>BOOST_NOWIDE_DYN_LINK=1 + ; + +SOURCES = cstdio cstdlib iostream ; + +lib boost_nowide + : $(SOURCES).cpp + : <link>shared:<define>BOOST_NOWIDE_DYN_LINK=1 + ; + +boost-install boost_nowide ; diff --git a/src/boost/libs/nowide/cmake/BoostAddOptions.cmake b/src/boost/libs/nowide/cmake/BoostAddOptions.cmake new file mode 100644 index 000000000..079b21283 --- /dev/null +++ b/src/boost/libs/nowide/cmake/BoostAddOptions.cmake @@ -0,0 +1,14 @@ +# Add common options for the current library project +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR BOOST_SUPERPROJECT_SOURCE_DIR) + set(def_INSTALL ON) + set(def_WERROR ON) +else() + set(def_INSTALL OFF) + set(def_WERROR OFF) +endif() + +string(TOUPPER ${PROJECT_NAME} name) +string(REPLACE BOOST_ Boost_ name ${name}) + +option(${name}_INSTALL "Install library" "${def_INSTALL}") +option(${name}_WERROR "Treat warnings as errors" "${def_WERROR}") diff --git a/src/boost/libs/nowide/cmake/BoostAddWarnings.cmake b/src/boost/libs/nowide/cmake/BoostAddWarnings.cmake new file mode 100644 index 000000000..12d185447 --- /dev/null +++ b/src/boost/libs/nowide/cmake/BoostAddWarnings.cmake @@ -0,0 +1,43 @@ +# Enable warnings for the given target +# Arguments: +# target: Non-interface library or executable +# level: Which warnings to add. Valid values: off, on, all, extra +# warningsAsErrors: Optional, ON to treat warnings as errors +# Optionally can pass a bool as warnings-as-errors +function(boost_add_warnings target level) + if(ARGC GREATER 2) + set(warningsAsErrors ${ARGV2}) + else() + set(warningsAsErrors OFF) + endif() + set(allowed_levels off on all extra pedantic) + if(NOT level IN_LIST allowed_levels) + message(FATAL_ERROR "${level} is not a valid warning level (${allowed_levels})") + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(supression -Wno-long-long) + set(warn_off -w) + set(warn_on -Wall ${supression}) + set(warn_all -Wall ${supression}) + set(warn_extra -Wall -Wextra ${supression}) + set(warn_pedantic -Wall -Wextra -pedantic ${supression}) + set(werror -Werror) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + set(warn_off -w0) + foreach(_lvl IN ITEMS on all extra pedantic) + set(warn_${_lvl} -w1) + endforeach() + set(werror "") + elseif(MSVC) + set(warn_off /W0) + set(warn_on /W3) + foreach(_lvl IN ITEMS all extra pedantic) + set(warn_${_lvl} /W4) + endforeach() + set(werror /WX) + endif() + target_compile_options(${target} PRIVATE ${warn_${level}}) + if(warningsAsErrors) + target_compile_options(${target} PRIVATE ${werror}) + endif() +endfunction() diff --git a/src/boost/libs/nowide/cmake/InstallTargets.cmake b/src/boost/libs/nowide/cmake/InstallTargets.cmake new file mode 100644 index 000000000..9022b325d --- /dev/null +++ b/src/boost/libs/nowide/cmake/InstallTargets.cmake @@ -0,0 +1,73 @@ +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +# Install all passed libraries including <PROJECT_NAME>Config.cmake and <PROJECT_NAME>ConfigVersion.cmake +# Assumes that your headers are in 'include/' +# Uses GNUInstallDirs to determine install locations +# Note: Use of BUILD_INTERFACE for headers is not required as it will be fixed up +# Arguments: +# - TARGETS: List of targets to install +# - NAMESPACE: Namespace to use (Installed libraries will be available as "Namespace::Name") +# - CONFIG_FILE: If passed, this will be used to configure the *Config.cmake, +# else a reasonable default will be used which is enough if there are no dependencies +# - VERSION_COMPATIBILITY: Compatibility with requested version. Defaults to SemVer semantics (SameMajorVersion) +function(install_targets) + cmake_parse_arguments(PARSE_ARGV 0 ARG "" "NAMESPACE;CONFIG_FILE;VERSION_COMPATIBILITY" "TARGETS") + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Invalid argument(s): ${ARG_UNPARSED_ARGUMENTS}") + endif() + if(ARG_NAMESPACE) + string(APPEND ARG_NAMESPACE "::") + endif() + if(NOT ARG_CONFIG_FILE) + set(ARG_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in") + file(WRITE ${ARG_CONFIG_FILE} + "@PACKAGE_INIT@\n" + "include(\"\${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake\")\n" + "check_required_components(\"@PROJECT_NAME@\")\n" + ) + endif() + if(NOT ARG_VERSION_COMPATIBILITY) + set(ARG_VERSION_COMPATIBILITY SameMajorVersion) + endif() + + # Fixup INTERFACE_INCLUDE_DIRECTORIES: + # Wrap source includes into BUILD_INTERFACE + foreach(tgt IN LISTS ARG_TARGETS) + get_target_property(old_inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES) + set(inc_dirs "") + foreach(dir IN LISTS old_inc_dirs) + string(FIND "${dir}" "${PROJECT_SOURCE_DIR}" pos) + string(FIND "${dir}" "${PROJECT_BINARY_DIR}" pos2) + if(pos EQUAL 0 OR pos2 EQUAL 0) + set(dir "$<BUILD_INTERFACE:${dir}>") + endif() + list(APPEND inc_dirs "${dir}") + endforeach() + set_target_properties(${tgt} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${inc_dirs}") + endforeach() + + install(TARGETS ${ARG_TARGETS} + EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + set(configFile ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake) + set(versionFile ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake) + set(configInstallDestination lib/cmake/${PROJECT_NAME}) + + configure_package_config_file(${ARG_CONFIG_FILE} ${configFile} INSTALL_DESTINATION ${configInstallDestination}) + write_basic_package_version_file(${versionFile} COMPATIBILITY ${ARG_VERSION_COMPATIBILITY}) + + install(FILES ${configFile} ${versionFile} DESTINATION ${configInstallDestination}) + + install( + EXPORT ${PROJECT_NAME}Targets + NAMESPACE ${ARG_NAMESPACE} + DESTINATION ${configInstallDestination} + ) +endfunction() diff --git a/src/boost/libs/nowide/codecov.yml b/src/boost/libs/nowide/codecov.yml new file mode 100644 index 000000000..d0a05c07e --- /dev/null +++ b/src/boost/libs/nowide/codecov.yml @@ -0,0 +1,10 @@ +codecov: + max_report_age: off + require_ci_to_pass: yes + notify: + after_n_builds: 2 + wait_for_ci: yes +comment: + layout: "diff, files" +ignore: + - "test/test.hpp" diff --git a/src/boost/libs/nowide/index.html b/src/boost/libs/nowide/index.html new file mode 100644 index 000000000..d94330dd0 --- /dev/null +++ b/src/boost/libs/nowide/index.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> +<head> + <title>Boost.Nowide Documentation</title> + <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" /> + <meta http-equiv="refresh" content="0; URL=doc/html/index.html" /> +</head> + +<body> + Automatic redirection failed, please go to <a href= + "doc/html/index.html">doc/html/index.html</a> +</body> +</html> +<!-- Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) Distributed under the Boost Software License, Version 1.0 --> diff --git a/src/boost/libs/nowide/meta/libraries.json b/src/boost/libs/nowide/meta/libraries.json new file mode 100644 index 000000000..70bf0af2c --- /dev/null +++ b/src/boost/libs/nowide/meta/libraries.json @@ -0,0 +1,11 @@ +{ + "key": "nowide", + "name": "Nowide", + "authors": [ + "Artyom Beilis" + ], + "description": "Standard library functions with UTF-8 API on Windows.", + "category": [ + "System" + ] +} diff --git a/src/boost/libs/nowide/src/cstdio.cpp b/src/boost/libs/nowide/src/cstdio.cpp new file mode 100644 index 000000000..0b0e75c9b --- /dev/null +++ b/src/boost/libs/nowide/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 <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 diff --git a/src/boost/libs/nowide/src/cstdlib.cpp b/src/boost/libs/nowide/src/cstdlib.cpp new file mode 100644 index 000000000..52540d0c4 --- /dev/null +++ b/src/boost/libs/nowide/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 <boost/nowide/cstdlib.hpp> + +#if !defined(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 diff --git a/src/boost/libs/nowide/src/iostream.cpp b/src/boost/libs/nowide/src/iostream.cpp new file mode 100644 index 000000000..0acd04e0b --- /dev/null +++ b/src/boost/libs/nowide/src/iostream.cpp @@ -0,0 +1,270 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// +// 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 +#include <boost/nowide/iostream.hpp> + +#ifndef BOOST_WINDOWS + +namespace boost { +namespace nowide { + /// Avoid empty compilation unit warnings + /// \internal + BOOST_NOWIDE_DECL void dummy_exported_function() + {} +} // namespace nowide +} // namespace boost + +#else + +#include <boost/nowide/convert.hpp> +#include <cassert> +#include <cstring> +#include <iostream> +#include <vector> + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include <windows.h> + +namespace boost { +namespace nowide { + namespace detail { + + namespace { + bool is_atty_handle(HANDLE h) + { + if(h) + { + DWORD dummy; + return GetConsoleMode(h, &dummy) != FALSE; + } + return false; + } + } // namespace + + class console_output_buffer : public std::streambuf + { + public: + console_output_buffer(HANDLE h) : handle_(h) + {} + + protected: + int sync() + { + return overflow(traits_type::eof()); + } + int overflow(int c) + { + if(!handle_) + return -1; + int n = static_cast<int>(pptr() - pbase()); + int r = 0; + + if(n > 0 && (r = write(pbase(), n)) < 0) + return -1; + if(r < n) + { + std::memmove(pbase(), pbase() + r, n - r); + } + setp(buffer_, buffer_ + buffer_size); + pbump(n - r); + if(c != traits_type::eof()) + sputc(traits_type::to_char_type(c)); + return 0; + } + + private: + typedef detail::utf::utf_traits<char> decoder; + typedef detail::utf::utf_traits<wchar_t> encoder; + + int write(const char* p, int n) + { + namespace uf = detail::utf; + const char* b = p; + const char* e = p + n; + DWORD size = 0; + if(n > buffer_size) + return -1; + wchar_t* out = wbuffer_; + uf::code_point c; + size_t decoded = 0; + while((c = decoder::decode(p, e)) != uf::incomplete) + { + if(c == uf::illegal) + c = BOOST_NOWIDE_REPLACEMENT_CHARACTER; + assert(out - wbuffer_ + encoder::width(c) <= static_cast<int>(wbuffer_size)); + out = encoder::encode(c, out); + decoded = p - b; + } + if(!WriteConsoleW(handle_, wbuffer_, static_cast<DWORD>(out - wbuffer_), &size, 0)) + return -1; + return static_cast<int>(decoded); + } + + static const int buffer_size = 1024; + static const int wbuffer_size = buffer_size * encoder::max_width; + char buffer_[buffer_size]; + wchar_t wbuffer_[wbuffer_size]; + HANDLE handle_; + }; + + class console_input_buffer : public std::streambuf + { + public: + console_input_buffer(HANDLE h) : handle_(h), wsize_(0) + {} + + protected: + int pbackfail(int c) + { + if(c == traits_type::eof()) + return traits_type::eof(); + + if(gptr() != eback()) + { + gbump(-1); + *gptr() = traits_type::to_char_type(c); + return 0; + } + + if(pback_buffer_.empty()) + { + pback_buffer_.resize(4); + char* b = &pback_buffer_[0]; + char* e = b + pback_buffer_.size(); + setg(b, e - 1, e); + *gptr() = traits_type::to_char_type(c); + } else + { + size_t n = pback_buffer_.size(); + std::vector<char> tmp; + tmp.resize(n * 2); + memcpy(&tmp[n], &pback_buffer_[0], n); + tmp.swap(pback_buffer_); + char* b = &pback_buffer_[0]; + char* e = b + n * 2; + char* p = b + n - 1; + *p = traits_type::to_char_type(c); + setg(b, p, e); + } + + return 0; + } + + int underflow() + { + if(!handle_) + return -1; + if(!pback_buffer_.empty()) + pback_buffer_.clear(); + + size_t n = read(); + setg(buffer_, buffer_, buffer_ + n); + if(n == 0) + return traits_type::eof(); + return std::char_traits<char>::to_int_type(*gptr()); + } + + private: + typedef detail::utf::utf_traits<wchar_t> decoder; + typedef detail::utf::utf_traits<char> encoder; + + size_t read() + { + namespace uf = detail::utf; + DWORD read_wchars = 0; + size_t n = wbuffer_size - wsize_; + if(!ReadConsoleW(handle_, wbuffer_ + wsize_, static_cast<DWORD>(n), &read_wchars, 0)) + return 0; + wsize_ += read_wchars; + char* out = buffer_; + wchar_t* p = wbuffer_; + wchar_t* e = wbuffer_ + wsize_; + uf::code_point c = 0; + while((c = decoder::decode(p, e)) != uf::incomplete) + { + if(c == uf::illegal) + c = BOOST_NOWIDE_REPLACEMENT_CHARACTER; + assert(out - buffer_ + encoder::width(c) <= static_cast<int>(buffer_size)); + out = encoder::encode(c, out); + wsize_ = e - p; + } + + if(wsize_ > 0) + std::memmove(wbuffer_, e - wsize_, sizeof(wchar_t) * wsize_); + + return out - buffer_; + } + + static const size_t wbuffer_size = 1024; + static const size_t buffer_size = wbuffer_size * encoder::max_width; + char buffer_[buffer_size]; + wchar_t wbuffer_[wbuffer_size]; + HANDLE handle_; + size_t wsize_; + std::vector<char> pback_buffer_; + }; + + winconsole_ostream::winconsole_ostream(int fd, winconsole_ostream* tieStream) : std::ostream(0) + { + HANDLE h = 0; + switch(fd) + { + case 1: h = GetStdHandle(STD_OUTPUT_HANDLE); break; + case 2: h = GetStdHandle(STD_ERROR_HANDLE); break; + } + if(is_atty_handle(h)) + { + d.reset(new console_output_buffer(h)); + std::ostream::rdbuf(d.get()); + } else + { + std::ostream::rdbuf(fd == 1 ? std::cout.rdbuf() : std::cerr.rdbuf()); + } + if(tieStream) + tie(tieStream); + } + winconsole_ostream::~winconsole_ostream() + { + try + { + flush(); + } catch(...) + {} + } + + winconsole_istream::winconsole_istream(winconsole_ostream* tieStream) : std::istream(0) + { + HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + if(is_atty_handle(h)) + { + d.reset(new console_input_buffer(h)); + std::istream::rdbuf(d.get()); + } else + { + std::istream::rdbuf(std::cin.rdbuf()); + } + if(tieStream) + tie(tieStream); + } + + winconsole_istream::~winconsole_istream() + {} + + } // namespace detail + + detail::winconsole_ostream cout(1, NULL); + detail::winconsole_istream cin(&cout); + detail::winconsole_ostream cerr(2, &cout); + detail::winconsole_ostream clog(2, &cout); +} // namespace nowide +} // namespace boost + +#endif diff --git a/src/boost/libs/nowide/standalone/config.hpp b/src/boost/libs/nowide/standalone/config.hpp new file mode 100644 index 000000000..8a07e20d4 --- /dev/null +++ b/src/boost/libs/nowide/standalone/config.hpp @@ -0,0 +1,81 @@ +// +// 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) +// +#ifndef NOWIDE_CONFIG_HPP_INCLUDED +#define NOWIDE_CONFIG_HPP_INCLUDED + +#include <boost/nowide/replacement.hpp> + +#if(defined(__WIN32) || defined(_WIN32) || defined(WIN32)) && !defined(__CYGWIN__) +#define NOWIDE_WINDOWS +#endif + +#ifdef _MSC_VER +#define NOWIDE_MSVC _MSC_VER +#endif + +#ifdef __GNUC__ +#define BOOST_SYMBOL_VISIBLE __attribute__((__visibility__("default"))) +#endif + +#ifndef BOOST_SYMBOL_VISIBLE +#define BOOST_SYMBOL_VISIBLE +#endif + +#ifdef NOWIDE_WINDOWS +#define BOOST_SYMBOL_EXPORT __declspec(dllexport) +#define BOOST_SYMBOL_IMPORT __declspec(dllimport) +#else +#define BOOST_SYMBOL_EXPORT BOOST_SYMBOL_VISIBLE +#define BOOST_SYMBOL_IMPORT +#endif + +#if defined(BOOST_NOWIDE_DYN_LINK) +#ifdef BOOST_NOWIDE_SOURCE +#define BOOST_NOWIDE_DECL BOOST_SYMBOL_EXPORT +#else +#define BOOST_NOWIDE_DECL BOOST_SYMBOL_IMPORT +#endif // BOOST_NOWIDE_SOURCE +#else +#define BOOST_NOWIDE_DECL +#endif // BOOST_NOWIDE_DYN_LINK + +#ifndef NOWIDE_DECL +#define NOWIDE_DECL +#endif + +#if defined(NOWIDE_WINDOWS) +#ifdef BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT +#undef BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT +#endif +#define BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT 1 +#elif !defined(BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT) +#define BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT 0 +#endif + +#if defined(__GNUC__) && __GNUC__ >= 7 +#define BOOST_NOWIDE_FALLTHROUGH __attribute__((fallthrough)) +#else +#define BOOST_NOWIDE_FALLTHROUGH +#endif + +// MSVC 2015 (1900) has reasonable C++11 support (especially auto-generated move ctors) +#if __cplusplus >= 201103L || (defined(NOWIDE_MSVC) && NOWIDE_MSVC >= 1900) +#define BOOST_NOWIDE_CXX11 1 +#else +#define BOOST_NOWIDE_CXX11 0 +#endif + +#if !defined(BOOST_LIKELY) +#define BOOST_LIKELY(x) x +#endif +#if !defined(BOOST_UNLIKELY) +#define BOOST_UNLIKELY(x) x +#endif + +#endif diff --git a/src/boost/libs/nowide/standalone/cstdint.hpp b/src/boost/libs/nowide/standalone/cstdint.hpp new file mode 100644 index 000000000..7dacb5af6 --- /dev/null +++ b/src/boost/libs/nowide/standalone/cstdint.hpp @@ -0,0 +1,12 @@ +#ifndef NOWIDE_CSTDINT_HPP +#define NOWIDE_CSTDINT_HPP + +#include <cstdint> + +namespace nowide { +typedef std::uint32_t uint32_t; +typedef std::uint16_t uint16_t; +typedef std::uint8_t uint8_t; +} // namespace nowide + +#endif diff --git a/src/boost/libs/nowide/standalone/scoped_ptr.hpp b/src/boost/libs/nowide/standalone/scoped_ptr.hpp new file mode 100644 index 000000000..37761a9d1 --- /dev/null +++ b/src/boost/libs/nowide/standalone/scoped_ptr.hpp @@ -0,0 +1,87 @@ +#ifndef NOWIDE_SCOPED_PTR_HPP +#define NOWIDE_SCOPED_PTR_HPP + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov, +// Copyright (C) 2012 Artyom Beilis +// +// 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) +// +// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm +// + +#include <cassert> + +namespace nowide { + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::auto_ptr if your needs are more complex. + +template<class T> +class scoped_ptr // noncopyable +{ +private: + T* px; + + scoped_ptr(scoped_ptr const&); + scoped_ptr& operator=(scoped_ptr const&); + + typedef scoped_ptr<T> this_type; + + void operator==(scoped_ptr const&) const; + void operator!=(scoped_ptr const&) const; + +public: + typedef T element_type; + + explicit scoped_ptr(T* p = 0) : px(p) // never throws + {} + + ~scoped_ptr() // never throws + { + delete px; + } + + void reset(T* p = 0) // never throws + { + assert(p == 0 || p != px); // catch self-reset errors + this_type(p).swap(*this); + } + + T& operator*() const // never throws + { + assert(px != 0); + return *px; + } + + T* operator->() const // never throws + { + assert(px != 0); + return px; + } + + T* get() const // never throws + { + return px; + } + + operator bool() const + { + return px != 0; + } + + void swap(scoped_ptr& b) // never throws + { + T* tmp = b.px; + b.px = px; + px = tmp; + } +}; + +} // namespace nowide + +#endif diff --git a/src/boost/libs/nowide/standalone/static_assert.hpp b/src/boost/libs/nowide/standalone/static_assert.hpp new file mode 100644 index 000000000..b772f30e0 --- /dev/null +++ b/src/boost/libs/nowide/standalone/static_assert.hpp @@ -0,0 +1,7 @@ +#ifndef NOWIDE_STATIC_ASSERT_HPP +#define NOWIDE_STATIC_ASSERT_HPP + +#define NOWIDE_STATIC_ASSERT(c) static_assert(c, #c) +#define NOWIDE_STATIC_ASSERT_MSG(c, msg) static_assert(c, msg) + +#endif diff --git a/src/boost/libs/nowide/test/CMakeLists.txt b/src/boost/libs/nowide/test/CMakeLists.txt new file mode 100644 index 000000000..4f7c4976b --- /dev/null +++ b/src/boost/libs/nowide/test/CMakeLists.txt @@ -0,0 +1,38 @@ +function(boost_nowide_add_test name) + cmake_parse_arguments(PARSE_ARGV 1 ARG "COMPILE_ONLY" "SRC" "LIBRARIES;DEFINITIONS;ARGS") + if(NOT ARG_SRC) + set(ARG_SRC ${name}.cpp) + endif() + set(name ${PROJECT_NAME}-${name}) + + add_executable(${name} ${ARG_SRC}) + target_link_libraries(${name} PRIVATE Boost::nowide ${ARG_LIBRARIES}) + boost_add_warnings(${name} pedantic ${Boost_NOWIDE_WERROR}) + target_compile_definitions(${name} PRIVATE BOOST_ALL_NO_LIB ${ARG_DEFINITIONS}) + if(NOT ARG_COMPILE_ONLY) + add_test(NAME ${name} COMMAND ${name} ${ARG_ARGS}) + endif() +endfunction() + +boost_nowide_add_test(test_codecvt) +boost_nowide_add_test(test_convert) +boost_nowide_add_test(test_env) +boost_nowide_add_test(test_env_win SRC test_env.cpp DEFINITIONS BOOST_NOWIDE_TEST_INCLUDE_WINDOWS) +boost_nowide_add_test(test_fstream) +boost_nowide_add_test(test_fstream_cxx11) +boost_nowide_add_test(test_iostream) +boost_nowide_add_test(test_stackstring) +boost_nowide_add_test(test_stdio) +boost_nowide_add_test(test_system_n SRC test_system.cpp DEFINITIONS BOOST_NOWIDE_TEST_USE_NARROW=1) +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_FILEBUF_REPLACEMENT=1) + boost_nowide_add_test(test_internal_fstream_cxx11 SRC test_fstream_cxx11.cpp DEFINITIONS BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1) +endif() + +if(NOT BOOST_SUPERPROJECT_SOURCE_DIR) + find_package(Boost 1.56 REQUIRED COMPONENTS filesystem system chrono) +endif() +boost_nowide_add_test(test_fs LIBRARIES Boost::filesystem) +boost_nowide_add_test(benchmark_fstream COMPILE_ONLY DEFINITIONS BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 LIBRARIES Boost::chrono) diff --git a/src/boost/libs/nowide/test/Jamfile.v2 b/src/boost/libs/nowide/test/Jamfile.v2 new file mode 100644 index 000000000..738dc0e59 --- /dev/null +++ b/src/boost/libs/nowide/test/Jamfile.v2 @@ -0,0 +1,39 @@ +# Boost Nowide Library test Jamfile + +# Copyright Beman Dawes 2003, 2006, Artyom Beilis 2012 + +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt + +# See library home page at http://www.boost.org/libs/nowide + +import testing ; + +project : requirements + <library>/boost/nowide//boost_nowide + <warnings>pedantic + <warnings-as-errors>on + <toolset>gcc:<cxxflags>-Wno-long-long + <toolset>darwin:<cxxflags>-Wno-long-long + <toolset>pathscale:<cxxflags>-Wno-long-long + <toolset>clang:<cxxflags>-Wno-long-long + ; + +lib shell32 ; + +run test_codecvt.cpp ; +run test_convert.cpp ; +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_FILEBUF_REPLACEMENT=1 <target-os>windows:<build>no : test_internal_fstream ; +run test_fstream_cxx11.cpp ; +run test_fstream_cxx11.cpp : : : <define>BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 <target-os>windows:<build>no : test_internal_fstream_cxx11 ; +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 <target-os>darwin,<link>shared:<build>no : 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 ; + +compile benchmark_fstream.cpp : <define>BOOST_NOWIDE_USE_WIN_FSTREAM=1 <library>/boost/chrono//boost_chrono/ ; diff --git a/src/boost/libs/nowide/test/benchmark_fstream.cpp b/src/boost/libs/nowide/test/benchmark_fstream.cpp new file mode 100644 index 000000000..7ebcfcb72 --- /dev/null +++ b/src/boost/libs/nowide/test/benchmark_fstream.cpp @@ -0,0 +1,273 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// Copyright (c) 2019 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_TEST_NO_MAIN + +#include <boost/nowide/convert.hpp> +#include <boost/nowide/cstdio.hpp> +#include <boost/nowide/fstream.hpp> +#define BOOST_CHRONO_HEADER_ONLY +#include <boost/chrono.hpp> +#include <algorithm> +#include <cstdio> +#include <fstream> +#include <iomanip> +#include <iostream> +#include <map> +#include <stdexcept> +#include <vector> + +#include "test.hpp" + +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> +class io_fstream +{ +public: + explicit io_fstream(const char* file, bool read) + { + f_.open(file, read ? std::fstream::in : std::fstream::out | std::fstream::trunc); + TEST(f_); + } + // coverity[exn_spec_violation] + ~io_fstream() + { + f_.close(); + } + void write(const char* buf, int size) + { + TEST(f_.write(buf, size)); + } + void read(char* buf, int size) + { + TEST(f_.read(buf, size)); + } + void rewind() + { + f_.seekg(0); + f_.seekp(0); + } + void flush() + { + f_ << std::flush; + } + +private: + FStream f_; +}; + +class io_stdio +{ +public: + io_stdio(const char* file, bool read) + { + f_ = nw::fopen(file, read ? "r" : "w+"); + TEST(f_); + } + ~io_stdio() + { + std::fclose(f_); + f_ = 0; + } + void write(const char* buf, int size) + { + TEST(std::fwrite(buf, 1, size, f_) == static_cast<size_t>(size)); + } + void read(char* buf, int size) + { + TEST(std::fread(buf, 1, size, f_) == static_cast<size_t>(size)); + } + void rewind() + { + std::rewind(f_); + } + void flush() + { + std::fflush(f_); + } + +private: + FILE* f_; +}; + +#if defined(_MSC_VER) +extern "C" void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) +#define BOOST_NOWIDE_READ_WRITE_BARRIER() _ReadWriteBarrier() +#elif defined(__GNUC__) +#if(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 +#define BOOST_NOWIDE_READ_WRITE_BARRIER() __sync_synchronize() +#else +#define BOOST_NOWIDE_READ_WRITE_BARRIER() __asm__ __volatile__("" : : : "memory") +#endif +#else +#define BOOST_NOWIDE_READ_WRITE_BARRIER() (void) +#endif + +struct perf_data +{ + // Block-size to read/write performance in MB/s + std::map<size_t, double> read, write; +}; + +char rand_char() +{ + // coverity[dont_call] + return static_cast<char>(std::rand()); +} + +std::vector<char> get_rand_data(int size) +{ + std::vector<char> data(size); + std::generate(data.begin(), data.end(), rand_char); + return data; +} + +static const int MIN_BLOCK_SIZE = 32; +static const int MAX_BLOCK_SIZE = 8192; + +template<typename FStream> +perf_data test_io(const char* file) +{ + namespace chrono = boost::chrono; + typedef chrono::high_resolution_clock clock; + typedef chrono::duration<double, boost::milli> milliseconds; + perf_data results; + // Use vector to force write to memory and avoid possible reordering + std::vector<clock::time_point> start_and_end(2); + const int data_size = 64 * 1024 * 1024; + for(int block_size = MIN_BLOCK_SIZE / 2; block_size <= MAX_BLOCK_SIZE; block_size *= 2) + { + std::vector<char> buf = get_rand_data(block_size); + FStream tmp(file, false); + tmp.rewind(); + start_and_end[0] = clock::now(); + BOOST_NOWIDE_READ_WRITE_BARRIER(); + for(int size = 0; size < data_size; size += block_size) + { + tmp.write(&buf[0], block_size); + BOOST_NOWIDE_READ_WRITE_BARRIER(); + } + tmp.flush(); + start_and_end[1] = clock::now(); + // heatup + if(block_size >= MIN_BLOCK_SIZE) + { + const milliseconds duration = chrono::duration_cast<milliseconds>(start_and_end[1] - start_and_end[0]); + const double speed = data_size / duration.count() / 1024; // MB/s + results.write[block_size] = speed; + std::cout << " write block size " << std::setw(8) << block_size << " " << std::fixed + << std::setprecision(3) << speed << " MB/s" << std::endl; + } + } + for(int block_size = MIN_BLOCK_SIZE; block_size <= MAX_BLOCK_SIZE; block_size *= 2) + { + std::vector<char> buf = get_rand_data(block_size); + FStream tmp(file, true); + tmp.rewind(); + start_and_end[0] = clock::now(); + BOOST_NOWIDE_READ_WRITE_BARRIER(); + for(int size = 0; size < data_size; size += block_size) + { + tmp.read(&buf[0], block_size); + BOOST_NOWIDE_READ_WRITE_BARRIER(); + } + start_and_end[1] = clock::now(); + const milliseconds duration = chrono::duration_cast<milliseconds>(start_and_end[1] - start_and_end[0]); + const double speed = data_size / duration.count() / 1024; // MB/s + results.read[block_size] = speed; + std::cout << " read block size " << std::setw(8) << block_size << " " << std::fixed << std::setprecision(3) + << speed << " MB/s" << std::endl; + } + TEST(std::remove(file) == 0); + return results; +} + +template<typename FStream> +perf_data test_io_driver(const char* file, const char* type) +{ + std::cout << "Testing I/O performance for " << type << std::endl; + const int repeats = 5; + std::vector<perf_data> results(repeats); + + for(int i = 0; i < repeats; i++) + results[i] = test_io<FStream>(file); + for(int block_size = MIN_BLOCK_SIZE; block_size <= MAX_BLOCK_SIZE; block_size *= 2) + { + double read_speed = 0, write_speed = 0; + for(int i = 0; i < repeats; i++) + { + 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; + } + return results[0]; +} + +void print_perf_data(const std::map<size_t, double>& stdio_data, + const std::map<size_t, double>& std_data, + const std::map<size_t, double>& nowide_data) +{ + std::cout << "block size" + << " stdio " + << " std::fstream " + << "nowide::fstream" << std::endl; + 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) << 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; + } +} + +void test_perf(const char* file) +{ + perf_data stdio_data = test_io_driver<io_stdio>(file, "stdio"); + perf_data std_data = test_io_driver<io_fstream<std::fstream> >(file, "std::fstream"); + perf_data nowide_data = test_io_driver<io_fstream<nw::fstream> >(file, "nowide::fstream"); + std::cout << "================== Read performance ==================" << std::endl; + print_perf_data(stdio_data.read, std_data.read, nowide_data.read); + std::cout << "================== Write performance =================" << std::endl; + print_perf_data(stdio_data.write, std_data.write, nowide_data.write); +} + +int main(int argc, char** argv) +{ + std::string filename = "perf_test_file.dat"; + if(argc == 2) + { + filename = argv[1]; + } else if(argc != 1) + { + std::cerr << "Usage: " << argv[0] << " [test_filepath]" << std::endl; + return 1; + } + try + { + test_perf(filename.c_str()); + } catch(const std::runtime_error& err) + { + std::cerr << "Benchmarking failed: " << err.what() << std::endl; + return 1; + } + return 0; +} diff --git a/src/boost/libs/nowide/test/exampleProject/CMakeLists.txt b/src/boost/libs/nowide/test/exampleProject/CMakeLists.txt new file mode 100644 index 000000000..9aa5ec40d --- /dev/null +++ b/src/boost/libs/nowide/test/exampleProject/CMakeLists.txt @@ -0,0 +1,10 @@ +# Project testing to consume Boost.Nowide +cmake_minimum_required(VERSION 3.8.0) +project(nowide_example_project) + +find_package(boost_nowide 10.0 REQUIRED) + +add_executable(example example_main.cpp) +target_link_libraries(example PRIVATE Boost::nowide) +enable_testing() +add_test(NAME example COMMAND example) diff --git a/src/boost/libs/nowide/test/exampleProject/example_main.cpp b/src/boost/libs/nowide/test/exampleProject/example_main.cpp new file mode 100644 index 000000000..91245985a --- /dev/null +++ b/src/boost/libs/nowide/test/exampleProject/example_main.cpp @@ -0,0 +1,20 @@ +// +// Copyright (c) 2019 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) +// + +#include <boost/nowide/args.hpp> +#include <boost/nowide/convert.hpp> + +int main(int argc, char** argv, char** env) +{ + boost::nowide::args _(argc, argv, env); + if(argc < 1) + return 1; + if(boost::nowide::narrow(boost::nowide::widen(argv[0])) != argv[0]) + return 1; + return 0; +} diff --git a/src/boost/libs/nowide/test/test.hpp b/src/boost/libs/nowide/test/test.hpp new file mode 100644 index 000000000..a8f96622d --- /dev/null +++ b/src/boost/libs/nowide/test/test.hpp @@ -0,0 +1,109 @@ +// +// 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 +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NOWIDE_LIB_TEST_H_INCLUDED +#define BOOST_NOWIDE_LIB_TEST_H_INCLUDED + +#include <cstdlib> +#include <iostream> +#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 char* expr, const char* file, const int line, const char* function) +{ + std::ostringstream ss; + ss << "Error " << expr << " at " << file << ':' << line << " in " << function; + throw std::runtime_error(ss.str()); +} + +template<typename T, typename U> +inline void test_equal_impl(const T& lhs, const U& rhs, const char* file, const int line, const char* function) +{ + if(lhs == rhs) + return; + std::ostringstream ss; + ss << "[" << lhs << "!=" << rhs << "]"; + test_failed(ss.str().c_str(), file, line, function); +} + +#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; \ + test_failed(#x, __FILE__, __LINE__, __FUNCTION__); \ + DISABLE_CONST_EXPR_DETECTED \ + } while(0) DISABLE_CONST_EXPR_DETECTED_POP +#define TEST_EQ(lhs, rhs) \ + do \ + { \ + test_mon(); \ + test_equal_impl((lhs), (rhs), __FILE__, __LINE__, __FUNCTION__); \ + break; \ + DISABLE_CONST_EXPR_DETECTED \ + } while(0) DISABLE_CONST_EXPR_DETECTED_POP + +#endif // #ifndef BOOST_NOWIDE_LIB_TEST_H_INCLUDED + +#ifndef BOOST_NOWIDE_TEST_NO_MAIN +// Tests should implement this +void test_main(int argc, char** argv, char** env); + +int main(int argc, char** argv, char** env) +{ + try + { + test_main(argc, argv, env); + } catch(const std::exception& e) + { + std::cerr << "Failed " << e.what() << std::endl; + return 1; + } + return 0; +} +#endif diff --git a/src/boost/libs/nowide/test/test_codecvt.cpp b/src/boost/libs/nowide/test/test_codecvt.cpp new file mode 100644 index 000000000..7acc0f1fa --- /dev/null +++ b/src/boost/libs/nowide/test/test_codecvt.cpp @@ -0,0 +1,328 @@ +// +// Copyright (c) 2015 Artyom Beilis (Tonkikh) +// +// 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) +// + +#include <boost/nowide/utf8_codecvt.hpp> + +#include <boost/nowide/convert.hpp> +#include <cstring> +#include <iomanip> +#include <iostream> +#include <locale> +#include <vector> + +#include "test.hpp" +#include "test_sets.hpp" + +static const char* utf8_name = + "\xf0\x9d\x92\x9e-\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82.txt"; +static const std::wstring wide_name_str = boost::nowide::widen(utf8_name); +static const wchar_t* wide_name = wide_name_str.c_str(); + +typedef std::codecvt<wchar_t, char, std::mbstate_t> cvt_type; + +void test_codecvt_in_n_m(const cvt_type& cvt, size_t n, size_t m) +{ + const wchar_t* wptr = wide_name; + size_t wlen = std::wcslen(wide_name); + size_t u8len = std::strlen(utf8_name); + const char* from = utf8_name; + const char* end = from; + const char* real_end = utf8_name + u8len; + const char* from_next = from; + std::mbstate_t mb = std::mbstate_t(); + while(from_next < real_end) + { + if(from == end) + { + end = from + n; + if(end > real_end) + end = real_end; + } + + wchar_t buf[128]; + wchar_t* to = buf; + wchar_t* to_end = to + m; + wchar_t* to_next = to; + + std::mbstate_t mb2 = mb; + std::codecvt_base::result r = cvt.in(mb, from, end, from_next, to, to_end, to_next); + + int count = cvt.length(mb2, from, end, to_end - to); +#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST + TEST(std::memcmp(&mb, &mb2, sizeof(mb)) == 0); + if(count != from_next - from) + { + std::cout << count << " " << from_next - from << std::endl; + } + TEST(count == from_next - from); +#else + TEST(count == to_next - to); +#endif + + if(r == cvt_type::partial) + { + end += n; + if(end > real_end) + end = real_end; + } else + TEST(r == cvt_type::ok); + while(to != to_next) + { + TEST(*wptr == *to); + wptr++; + to++; + } + to = to_next; + from = from_next; + } + TEST(wptr == wide_name + wlen); + TEST(from == real_end); +} + +void test_codecvt_out_n_m(const cvt_type& cvt, size_t n, size_t m) +{ + const char* nptr = utf8_name; + size_t wlen = std::wcslen(wide_name); + size_t u8len = std::strlen(utf8_name); + + std::mbstate_t mb = std::mbstate_t(); + + const wchar_t* from_next = wide_name; + const wchar_t* real_from_end = wide_name + wlen; + + char buf[256]; + char* to = buf; + char* to_next = to; + char* to_end = to + n; + char* real_to_end = buf + sizeof(buf); + + while(from_next < real_from_end) + { + const wchar_t* from = from_next; + const wchar_t* from_end = from + m; + if(from_end > real_from_end) + from_end = real_from_end; + if(to_end == to) + { + to_end = to + n; + } + + std::codecvt_base::result r = cvt.out(mb, from, from_end, from_next, to, to_end, to_next); + if(r == cvt_type::partial) + { + // If those are equal, then "partial" probably means: Need more input + // Otherwise "Need more output" + if(from_next != from_end) + { + TEST(to_end - to_next < cvt.max_length()); + to_end += n; + if(to_end > real_to_end) + to_end = real_to_end; + } + } else + { + TEST(r == cvt_type::ok); + } + + while(to != to_next) + { + TEST(*nptr == *to); + nptr++; + to++; + } + from = from_next; + } + TEST(nptr == utf8_name + u8len); + TEST(from_next == real_from_end); + TEST(cvt.unshift(mb, to, to + n, to_next) == cvt_type::ok); + TEST(to_next == to); +} + +void test_codecvt_conv() +{ + std::cout << "Conversions " << std::endl; + std::locale l(std::locale::classic(), new boost::nowide::utf8_codecvt<wchar_t>()); + + const cvt_type& cvt = std::use_facet<cvt_type>(l); + const size_t utf8_len = std::strlen(utf8_name); + const size_t wide_len = std::wcslen(wide_name); + + for(size_t i = 1; i <= utf8_len + 1; i++) + { + for(size_t j = 1; j <= wide_len + 1; j++) + { + try + { + test_codecvt_in_n_m(cvt, i, j); + test_codecvt_out_n_m(cvt, i, j); + } catch(...) + { + std::cerr << "Wlen=" << j << " Nlen=" << i << std::endl; + throw; + } + } + } +} + +void test_codecvt_err() +{ + std::cout << "Errors " << std::endl; + std::locale l(std::locale::classic(), new boost::nowide::utf8_codecvt<wchar_t>()); + + const cvt_type& cvt = std::use_facet<cvt_type>(l); + + std::cout << "- UTF-8" << std::endl; + { + { + wchar_t buf[4]; + wchar_t* const to = buf; + wchar_t* const to_end = buf + 4; + const char* err_utf = "1\xFF\xFF\xd7\xa9"; + std::mbstate_t mb = std::mbstate_t(); + const char* from = err_utf; + const char* from_end = from + std::strlen(from); + const char* from_next = from; + wchar_t* to_next = to; + TEST(cvt.in(mb, from, from_end, from_next, to, to_end, to_next) == cvt_type::ok); + TEST(from_next == from + 5); + TEST(to_next == to + 4); + TEST(std::wstring(to, to_end) == boost::nowide::widen(err_utf)); + } + { + wchar_t buf[4]; + wchar_t* const to = buf; + wchar_t* const to_end = buf + 4; + const char* err_utf = "1\xd7"; // 1 valid, 1 incomplete UTF-8 char + std::mbstate_t mb = std::mbstate_t(); + const char* from = err_utf; + const char* from_end = from + std::strlen(from); + const char* from_next = from; + wchar_t* to_next = to; + TEST(cvt.in(mb, from, from_end, from_next, to, to_end, to_next) == cvt_type::partial); + TEST(from_next == from + 1); + TEST(to_next == to + 1); + TEST(std::wstring(to, to_next) == std::wstring(L"1")); + } + { + char buf[4] = {}; + char* const to = buf; + char* const to_end = buf + 4; + char* to_next = to; + const wchar_t* err_utf = L"\xD800"; // Trailing UTF-16 surrogate + std::mbstate_t mb = std::mbstate_t(); + const wchar_t* from = err_utf; + const wchar_t* from_end = from + 1; + const wchar_t* from_next = from; + cvt_type::result res = cvt.out(mb, from, from_end, from_next, to, to_end, to_next); +#ifdef BOOST_MSVC +#pragma warning(disable : 4127) // Constant expression detected +#endif + if(sizeof(wchar_t) == 2) + { + TEST(res == cvt_type::partial); + TEST(from_next == from_end); + TEST(to_next == to); + TEST(buf[0] == 0); + } else + { + TEST(res == cvt_type::ok); + TEST(from_next == from_end); + TEST(to_next == to + 3); + // surrogate is invalid + TEST(std::string(to, to_next) == boost::nowide::narrow(wreplacement_str)); + } + } + } + + std::cout << "- UTF-16/32" << std::endl; + { + char buf[32]; + char* to = buf; + char* to_end = buf + 32; + char* to_next = to; + wchar_t err_buf[3] = {'1', 0xDC9E, 0}; // second surrogate not works both for UTF-16 and 32 + const wchar_t* err_utf = err_buf; + { + std::mbstate_t mb = std::mbstate_t(); + const wchar_t* from = err_utf; + const wchar_t* from_end = from + std::wcslen(from); + const wchar_t* from_next = from; + TEST(cvt.out(mb, from, from_end, from_next, to, to_end, to_next) == cvt_type::ok); + TEST(from_next == from + 2); + TEST(to_next == to + 4); + TEST(std::string(to, to_next) == "1" + boost::nowide::narrow(wreplacement_str)); + } + } +} + +std::wstring codecvt_to_wide(const std::string& s) +{ + std::locale l(std::locale::classic(), new boost::nowide::utf8_codecvt<wchar_t>()); + + const cvt_type& cvt = std::use_facet<cvt_type>(l); + + std::mbstate_t mb = std::mbstate_t(); + const char* const from = s.c_str(); + const char* const from_end = from + s.size(); + const char* from_next = from; + + std::vector<wchar_t> buf(s.size() + 2); // +1 for possible incomplete char, +1 for NULL + wchar_t* const to = &buf[0]; + wchar_t* const to_end = to + buf.size(); + wchar_t* to_next = to; + + cvt_type::result res = cvt.in(mb, from, from_end, from_next, to, to_end, to_next); + if(res == cvt_type::partial) + { + TEST(to_next < to_end); + *(to_next++) = BOOST_NOWIDE_REPLACEMENT_CHARACTER; + } else + TEST(res == cvt_type::ok); + + return std::wstring(to, to_next); +} + +std::string codecvt_to_narrow(const std::wstring& s) +{ + std::locale l(std::locale::classic(), new boost::nowide::utf8_codecvt<wchar_t>()); + + const cvt_type& cvt = std::use_facet<cvt_type>(l); + + std::mbstate_t mb = std::mbstate_t(); + const wchar_t* const from = s.c_str(); + const wchar_t* const from_end = from + s.size(); + const wchar_t* from_next = from; + + std::vector<char> buf((s.size() + 1) * 4 + 1); // +1 for possible incomplete char, +1 for NULL + char* const to = &buf[0]; + char* const to_end = to + buf.size(); + char* to_next = to; + + cvt_type::result res = cvt.out(mb, from, from_end, from_next, to, to_end, to_next); + if(res == cvt_type::partial) + { + TEST(to_next < to_end); + return std::string(to, to_next) + boost::nowide::narrow(wreplacement_str); + } else + TEST(res == cvt_type::ok); + + return std::string(to, to_next); +} + +void test_codecvt_subst() +{ + std::cout << "Substitutions " << std::endl; + run_all(codecvt_to_wide, codecvt_to_narrow); +} + +void test_main(int, char**, char**) +{ + test_codecvt_conv(); + test_codecvt_err(); + test_codecvt_subst(); +} diff --git a/src/boost/libs/nowide/test/test_convert.cpp b/src/boost/libs/nowide/test/test_convert.cpp new file mode 100644 index 000000000..788689c97 --- /dev/null +++ b/src/boost/libs/nowide/test/test_convert.cpp @@ -0,0 +1,118 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// +// 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) +// + +#include <boost/nowide/convert.hpp> +#include <iostream> + +#include "test.hpp" +#include "test_sets.hpp" + +#if defined(BOOST_MSVC) && BOOST_MSVC < 1700 +#pragma warning(disable : 4428) // universal-character-name encountered in source +#endif + +std::wstring widen_buf_ptr(const std::string& s) +{ + wchar_t buf[50]; + TEST(boost::nowide::widen(buf, 50, s.c_str()) == buf); + return buf; +} + +std::string narrow_buf_ptr(const std::wstring& s) +{ + char buf[50]; + TEST(boost::nowide::narrow(buf, 50, s.c_str()) == buf); + return buf; +} + +std::wstring widen_buf_range(const std::string& s) +{ + wchar_t buf[50]; + TEST(boost::nowide::widen(buf, 50, s.c_str(), s.c_str() + s.size()) == buf); + return buf; +} + +std::string narrow_buf_range(const std::wstring& s) +{ + char buf[50]; + TEST(boost::nowide::narrow(buf, 50, s.c_str(), s.c_str() + s.size()) == buf); + return buf; +} + +std::wstring widen_raw_string(const std::string& s) +{ + return boost::nowide::widen(s.c_str()); +} + +std::string narrow_raw_string(const std::wstring& s) +{ + return boost::nowide::narrow(s.c_str()); +} + +std::wstring widen_raw_string_and_size(const std::string& s) +{ + // Remove NULL + const std::string s2 = s + "DummyData"; + return boost::nowide::widen(s2.c_str(), s.size()); +} + +std::string narrow_raw_string_and_size(const std::wstring& s) +{ + // Remove NULL + const std::wstring s2 = s + L"DummyData"; + return boost::nowide::narrow(s2.c_str(), s.size()); +} + +void test_main(int, char**, char**) +{ + std::string hello = "\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d"; + std::wstring whello = L"\u05e9\u05dc\u05d5\u05dd"; + std::wstring whello_3e = L"\u05e9\u05dc\u05d5\ufffd"; + std::wstring whello_3 = L"\u05e9\u05dc\u05d5"; + + std::cout << "- boost::nowide::widen" << std::endl; + { + const char* b = hello.c_str(); + const char* e = b + hello.size(); + wchar_t buf[6] = {0, 0, 0, 0, 0, 1}; + TEST(boost::nowide::widen(buf, 5, b, e) == buf); + TEST(buf == whello); + TEST(buf[5] == 1); + TEST(boost::nowide::widen(buf, 4, b, e) == 0); + TEST(boost::nowide::widen(buf, 5, b, e - 1) == buf); + TEST(buf == whello_3e); + TEST(boost::nowide::widen(buf, 5, b, e - 2) == buf); + TEST(buf == whello_3); + TEST(boost::nowide::widen(buf, 5, b, b) == buf && buf[0] == 0); + TEST(boost::nowide::widen(buf, 5, b, b + 2) == buf && buf[1] == 0 && buf[0] == whello[0]); + } + std::cout << "- boost::nowide::narrow" << std::endl; + { + const wchar_t* b = whello.c_str(); + const wchar_t* e = b + whello.size(); //-V594 + char buf[10] = {0}; + buf[9] = 1; + TEST(boost::nowide::narrow(buf, 9, b, e) == buf); + TEST(buf == hello); + TEST(buf[9] == 1); + TEST(boost::nowide::narrow(buf, 8, b, e) == 0); + TEST(boost::nowide::narrow(buf, 7, b, e - 1) == buf); + TEST(buf == hello.substr(0, 6)); + } + + std::cout << "- (output_buffer, buffer_size, input_raw_string)" << std::endl; + run_all(widen_buf_ptr, narrow_buf_ptr); + std::cout << "- (output_buffer, buffer_size, input_raw_string, string_len)" << std::endl; + run_all(widen_buf_range, narrow_buf_range); + std::cout << "- (input_raw_string)" << std::endl; + run_all(widen_raw_string, narrow_raw_string); + std::cout << "- (input_raw_string, size)" << std::endl; + run_all(widen_raw_string_and_size, narrow_raw_string_and_size); + std::cout << "- (const std::string&)" << std::endl; + run_all(boost::nowide::widen, boost::nowide::narrow); +} diff --git a/src/boost/libs/nowide/test/test_env.cpp b/src/boost/libs/nowide/test/test_env.cpp new file mode 100644 index 000000000..f9de36a5e --- /dev/null +++ b/src/boost/libs/nowide/test/test_env.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// +// 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) +// + +#include <boost/nowide/cstdlib.hpp> +#include <cstring> + +#if defined(BOOST_NOWIDE_TEST_INCLUDE_WINDOWS) && defined(BOOST_WINDOWS) +#include <windows.h> +#endif + +#include "test.hpp" + +// "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; +} + +void test_main(int, char**, char**) +{ + std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; + char penv[256] = {0}; + 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")); + TEST(boost::nowide::getenv("BOOST_TEST1") == example); + TEST(boost::nowide::setenv("BOOST_TEST1", "xx", 0) == 0); + TEST(boost::nowide::getenv("BOOST_TEST1") == example); + TEST(boost::nowide::putenv(penv) == 0); + TEST(boost::nowide::getenv("BOOST_TEST2")); + TEST(boost::nowide::getenv("BOOST_TEST_INVALID") == 0); + TEST(boost::nowide::getenv("BOOST_TEST2") == example + "x"); +#ifdef BOOST_WINDOWS + // Passing a variable without an equals sign (before \0) is an error + // But GLIBC has an extension that unsets the env var instead + char penv2[256] = {0}; + const char* sPenv2 = "BOOST_TEST1SOMEGARBAGE="; + strcpy_safe(penv2, sPenv2); + // End the string before the equals sign -> Expect fail + penv2[strlen("BOOST_TEST1")] = '\0'; + TEST(boost::nowide::putenv(penv2) == -1); + TEST(boost::nowide::getenv("BOOST_TEST1")); + TEST(boost::nowide::getenv("BOOST_TEST1") == example); +#endif +} diff --git a/src/boost/libs/nowide/test/test_fs.cpp b/src/boost/libs/nowide/test/test_fs.cpp new file mode 100644 index 000000000..1859bd8d1 --- /dev/null +++ b/src/boost/libs/nowide/test/test_fs.cpp @@ -0,0 +1,61 @@ +// +// Copyright (c) 2015 Artyom Beilis (Tonkikh) +// +// 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) +// + +#include <boost/nowide/filesystem.hpp> + +#include <boost/nowide/convert.hpp> +#include <boost/nowide/cstdio.hpp> +#include <boost/nowide/fstream.hpp> +#include <boost/filesystem/operations.hpp> + +#include "test.hpp" + +void test_main(int, char**, char**) +{ + boost::nowide::nowide_filesystem(); + const std::string prefix = boost::filesystem::unique_path("nowide-%%%%-%%%%-").string(); + const std::string utf8_name = + prefix + "\xf0\x9d\x92\x9e-\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82.txt"; + + { + boost::nowide::ofstream f(utf8_name.c_str()); + TEST(f); + f << "Test" << std::endl; + } + + TEST(boost::filesystem::is_regular_file(boost::nowide::widen(utf8_name))); + TEST(boost::filesystem::is_regular_file(utf8_name)); + + TEST(boost::nowide::remove(utf8_name.c_str()) == 0); + + TEST(!boost::filesystem::is_regular_file(boost::nowide::widen(utf8_name))); + TEST(!boost::filesystem::is_regular_file(utf8_name)); + + const boost::filesystem::path path = utf8_name; + { + boost::nowide::ofstream f(path); + TEST(f); + f << "Test" << std::endl; + TEST(is_regular_file(path)); + } + { + boost::nowide::ifstream f(path); + TEST(f); + std::string test; + f >> test; + TEST(test == "Test"); + } + { + boost::nowide::fstream f(path); + TEST(f); + std::string test; + f >> test; + TEST(test == "Test"); + } + boost::filesystem::remove(path); +} diff --git a/src/boost/libs/nowide/test/test_fstream.cpp b/src/boost/libs/nowide/test/test_fstream.cpp new file mode 100644 index 000000000..9fdd1f87b --- /dev/null +++ b/src/boost/libs/nowide/test/test_fstream.cpp @@ -0,0 +1,513 @@ +// +// Copyright (c) 2015 Artyom Beilis (Tonkikh) +// Copyright (c) 2019 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) +// + +#include <boost/nowide/fstream.hpp> + +#include <boost/nowide/convert.hpp> +#include <boost/nowide/cstdio.hpp> +#include <fstream> +#include <iostream> +#include <string> + +#include "test.hpp" + +namespace nw = boost::nowide; + +void make_empty_file(const char* filepath) +{ + nw::ofstream f(filepath, std::ios_base::out | std::ios::trunc); + TEST(f); +} + +bool file_exists(const char* filepath) +{ + FILE* f = nw::fopen(filepath, "r"); + if(f) + { + std::fclose(f); + return true; + } else + return false; +} + +std::string read_file(const char* filepath, bool binary_mode = false) +{ + FILE* f = nw::fopen(filepath, binary_mode ? "rb" : "r"); + TEST(f); + std::string content; + int c; + while((c = std::fgetc(f)) != EOF) + content.push_back(static_cast<char>(c)); + std::fclose(f); + return content; +} + +void test_with_different_buffer_sizes(const char* filepath) +{ + /* Important part of the standard for mixing input with output: + However, output shall not be directly followed by input without an intervening call to the fflush function + or to a file positioning function (fseek, fsetpos, or rewind), + and input shall not be directly followed by output without an intervening call to a file positioning function, + unless the input operation encounters end-of-file. + */ + for(int i = -1; i < 16; i++) + { + std::cout << "Buffer size = " << i << std::endl; + char buf[16]; + 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')); + TEST(f.put('d')); + 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 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 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); + } +} + +void test_close(const char* filepath) +{ + const std::string filepath2 = std::string(filepath) + ".2"; + // Make sure file does not exist yet + TEST(!file_exists(filepath2.c_str()) || nw::remove(filepath2.c_str()) == 0); + TEST(!file_exists(filepath2.c_str())); + nw::filebuf buf; + TEST(buf.open(filepath, std::ios_base::out) == &buf); + TEST(buf.is_open()); + // Opening when already open fails + TEST(buf.open(filepath2.c_str(), std::ios_base::out) == NULL); + // Still open + TEST(buf.is_open()); + TEST(buf.close() == &buf); + // Failed opening did not create file + TEST(!file_exists(filepath2.c_str())); + // But it should work now: + TEST(buf.open(filepath2.c_str(), std::ios_base::out) == &buf); + TEST(buf.close() == &buf); + TEST(file_exists(filepath2.c_str())); + TEST(nw::remove(filepath) == 0); + TEST(nw::remove(filepath2.c_str()) == 0); +} + +template<typename IFStream, typename OFStream> +void test_flush(const char* filepath) +{ + OFStream fo(filepath, std::ios_base::out | std::ios::trunc); + TEST(fo); + std::string curValue; + for(int repeat = 0; repeat < 2; repeat++) + { + for(size_t len = 1; len <= 1024; len *= 2) + { + char c = static_cast<char>(len % 13 + repeat + 'a'); // semi-random char + std::string input(len, c); + fo << input; + curValue += input; + TEST(fo.flush()); + std::string s; + // Note: Flush on read area is implementation defined, so check whole file instead + IFStream fi(filepath); + TEST(fi >> s); + // coverity[tainted_data] + TEST(s == curValue); + } + } +} + +void test_ofstream_creates_file(const char* filename) +{ + TEST(!file_exists(filename) || nw::remove(filename) == 0); + TEST(!file_exists(filename)); + // Ctor + { + nw::ofstream fo(filename); + TEST(fo); + } + TEST(file_exists(filename)); + TEST(read_file(filename).empty()); + TEST(nw::remove(filename) == 0); + // Open + { + nw::ofstream fo; + fo.open(filename); + TEST(fo); + } + TEST(file_exists(filename)); + TEST(read_file(filename).empty()); + TEST(nw::remove(filename) == 0); +} + +// Create filename file with content "test\n" +void test_ofstream_write(const char* filename) +{ + // char* ctor + { + nw::ofstream fo(filename); + TEST(fo << "test" << 2 << std::endl); + } + // char* open + TEST(read_file(filename) == "test2\n"); + TEST(nw::remove(filename) == 0); + { + nw::ofstream fo; + fo.open(filename); + TEST(fo << "test" << 2 << std::endl); + } + TEST(read_file(filename) == "test2\n"); + TEST(nw::remove(filename) == 0); + // string ctor + { + std::string name = filename; + nw::ofstream fo(name); + TEST(fo << "test" << 2 << std::endl); + } + TEST(read_file(filename) == "test2\n"); + TEST(nw::remove(filename) == 0); + // string open + { + nw::ofstream fo; + fo.open(std::string(filename)); + TEST(fo << "test" << 2 << std::endl); + } + TEST(read_file(filename) == "test2\n"); + TEST(nw::remove(filename) == 0); + // Binary mode + { + nw::ofstream fo(filename, std::ios::binary); + TEST(fo << "test" << 2 << std::endl); + } + TEST(read_file(filename, true) == "test2\n"); + TEST(nw::remove(filename) == 0); + // At end + { + { + nw::ofstream fo(filename); + TEST(fo << "test" << 2 << std::endl); + } + nw::ofstream fo(filename, std::ios::ate | std::ios::in); + fo << "second" << 2 << std::endl; + } + TEST(read_file(filename) == "test2\nsecond2\n"); + TEST(nw::remove(filename) == 0); +} + +void test_ifstream_open_read(const char* filename) +{ + // Create test file + { + nw::ofstream fo(filename); + TEST(fo << "test" << std::endl); + } + + // char* Ctor + { + nw::ifstream fi(filename); + TEST(fi); + std::string tmp; + TEST(fi >> tmp); + TEST(tmp == "test"); + } + // char* open + { + nw::ifstream fi; + fi.open(filename); + TEST(fi); + std::string tmp; + TEST(fi >> tmp); + TEST(tmp == "test"); + } + // string ctor + { + std::string name = filename; + nw::ifstream fi(name); + TEST(fi); + std::string tmp; + TEST(fi >> tmp); + TEST(tmp == "test"); + } + // string open + { + nw::ifstream fi; + fi.open(std::string(filename)); + TEST(fi); + std::string tmp; + TEST(fi >> tmp); + TEST(tmp == "test"); + } + // Binary mode + { + nw::ifstream fi(filename, std::ios::binary); + TEST(fi); + std::string tmp; + TEST(fi >> tmp); + TEST(tmp == "test"); + } + // At end + { + // Need binary file or position check might be throw off by newline conversion + { + nw::ofstream fo(filename, nw::fstream::binary); + TEST(fo << "test"); + } + nw::ifstream fi(filename, nw::fstream::ate | nw::fstream::binary); + TEST(fi); + TEST(fi.tellg() == std::streampos(4)); + fi.seekg(-2, std::ios_base::cur); + std::string tmp; + TEST(fi >> tmp); + TEST(tmp == "st"); + } + // Fail on non-existing file + TEST(nw::remove(filename) == 0); + { + nw::ifstream fi(filename); + TEST(!fi); + } +} + +void test_fstream(const char* filename) +{ + const std::string sFilename = filename; + TEST(!file_exists(filename) || nw::remove(filename) == 0); + TEST(!file_exists(filename)); + // Fail on non-existing file + { + nw::fstream f(filename); + TEST(!f); + nw::fstream f2(sFilename); + TEST(!f2); + } + { + nw::fstream f; + f.open(filename); + TEST(!f); + f.open(sFilename); + TEST(!f); + } + TEST(!file_exists(filename)); + // Create empty file (Ctor) + { + nw::fstream f(filename, std::ios::out); + TEST(f); + } + TEST(read_file(filename).empty()); + // Char* ctor + { + nw::fstream f(filename); + TEST(f); + TEST(f << "test"); + std::string tmp; + TEST(f.seekg(0)); + TEST(f >> tmp); + TEST(tmp == "test"); + } + TEST(read_file(filename) == "test"); + // String ctor + { + nw::fstream f(sFilename); + TEST(f); + TEST(f << "string_ctor"); + std::string tmp; + TEST(f.seekg(0)); + TEST(f >> tmp); + TEST(tmp == "string_ctor"); + } + TEST(read_file(filename) == "string_ctor"); + TEST(nw::remove(filename) == 0); + // Create empty file (open) + { + nw::fstream f; + f.open(filename, std::ios::out); + TEST(f); + } + TEST(read_file(filename).empty()); + // Open + { + nw::fstream f; + f.open(filename); + TEST(f); + TEST(f << "test"); + std::string tmp; + TEST(f.seekg(0)); + TEST(f >> tmp); + TEST(tmp == "test"); + } + TEST(read_file(filename) == "test"); + // Ctor existing file + { + nw::fstream f(filename); + TEST(f); + std::string tmp; + TEST(f >> tmp); + TEST(tmp == "test"); + TEST(f.eof()); + f.clear(); + TEST(f << "second"); + } + TEST(read_file(filename) == "testsecond"); + // Trunc & binary + { + nw::fstream f(filename, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary); + TEST(f); + TEST(f << "test2"); + std::string tmp; + TEST(f.seekg(0)); + TEST(f >> tmp); + TEST(tmp == "test2"); + } + TEST(read_file(filename) == "test2"); + // Reading in write mode fails (existing file!) + { + nw::fstream f(filename, std::ios::out); + std::string tmp; + TEST(!(f >> tmp)); + f.clear(); + TEST(f << "foo"); + TEST(f.seekg(0)); + TEST(!(f >> tmp)); + } + TEST(read_file(filename) == "foo"); + // Writing in read mode fails (existing file!) + { + nw::fstream f(filename, std::ios::in); + TEST(!(f << "bar")); + f.clear(); + std::string tmp; + TEST(f >> tmp); + TEST(tmp == "foo"); + } + TEST(read_file(filename) == "foo"); + TEST(nw::remove(filename) == 0); +} + +template<typename T> +bool is_open(T& stream) +{ + // There are const and non const versions of is_open, so test both + TEST(stream.is_open() == const_cast<const T&>(stream).is_open()); + return stream.is_open(); +} + +template<typename T> +void do_test_is_open(const char* filename) +{ + T f; + TEST(!is_open(f)); + f.open(filename); + TEST(f); + TEST(is_open(f)); + f.close(); + TEST(f); + TEST(!is_open(f)); +} + +void test_is_open(const char* filename) +{ + // Note the order: Output before input so file exists + do_test_is_open<nw::ofstream>(filename); + do_test_is_open<nw::ifstream>(filename); + do_test_is_open<nw::fstream>(filename); + TEST(nw::remove(filename) == 0); +} + +void test_main(int, char** argv, char**) +{ + const std::string exampleFilename = std::string(argv[0]) + "-\xd7\xa9-\xd0\xbc-\xce\xbd.txt"; + std::cout << "Testing fstream" << std::endl; + test_ofstream_creates_file(exampleFilename.c_str()); + test_ofstream_write(exampleFilename.c_str()); + test_ifstream_open_read(exampleFilename.c_str()); + test_fstream(exampleFilename.c_str()); + test_is_open(exampleFilename.c_str()); + + std::cout << "Complex IO" << std::endl; + test_with_different_buffer_sizes(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()); + std::cout << "Flush - Test" << std::endl; + test_flush<nw::ifstream, nw::ofstream>(exampleFilename.c_str()); +} diff --git a/src/boost/libs/nowide/test/test_fstream_cxx11.cpp b/src/boost/libs/nowide/test/test_fstream_cxx11.cpp new file mode 100644 index 000000000..3ad16b711 --- /dev/null +++ b/src/boost/libs/nowide/test/test_fstream_cxx11.cpp @@ -0,0 +1,201 @@ +// +// Copyright (c) 2019 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) +// + +#include <boost/nowide/config.hpp> + +#if BOOST_NOWIDE_CXX11 + +#include <boost/nowide/fstream.hpp> + +#include <boost/nowide/cstdio.hpp> +#include <iterator> +#include <utility> + +#include "test.hpp" + +namespace nw = boost::nowide; + +void create_file(const std::string& filename, const std::string& contents) +{ + nw::ofstream f(filename, std::ios::trunc); + TEST(f << contents); +} + +template<typename T> +std::string get_file_contents(T& stream) +{ + TEST(stream); + std::string s((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>()); + return s; +} + +std::string get_file_contents(const std::string& filename) +{ + nw::ifstream f(filename); + return get_file_contents(f); +} + +nw::ifstream make_ifstream(const std::string& filename) +{ + nw::ifstream f(filename); + TEST(f); + std::string s; + TEST(f >> s); + TEST(s == "Hello"); + return f; +} + +void test_ifstream(const std::string& filename) +{ + create_file(filename, "Hello\nWorld"); + // Move construct + { + nw::ifstream f = make_ifstream(filename); + TEST(f); + std::string s; + TEST(f >> s); + TEST(s == "World"); + } + // Move assign + { + nw::ifstream f; + { + nw::ifstream f2 = make_ifstream(filename); + f = std::move(f2); + } + TEST(f); + std::string s; + TEST(f >> s); + TEST(s == "World"); + } + // Swap + { + nw::ifstream f; + { + nw::ifstream f2 = make_ifstream(filename); + swap(f, f2); + TEST(!f2.is_open()); + } + TEST(f); + std::string s; + TEST(f >> s); + TEST(s == "World"); + } + TEST(nw::remove(filename.c_str()) == 0); +} + +nw::ofstream make_ofstream(const std::string& filename) +{ + nw::ofstream f(filename); + TEST(f); + TEST(f << "Hello"); + return f; +} + +void test_ofstream(const std::string& filename) +{ + // Move construct + { + nw::ofstream f = make_ofstream(filename); + TEST(f); + TEST(f << " world"); + f.close(); + TEST(get_file_contents(filename) == "Hello world"); + } + // Move assign + { + nw::ofstream f; + { + nw::ofstream f2 = make_ofstream(filename); + f = std::move(f2); + } + TEST(f); + TEST(f << " world"); + f.close(); + TEST(get_file_contents(filename) == "Hello world"); + } + // Swap + { + nw::ofstream f; + { + nw::ofstream f2 = make_ofstream(filename); + swap(f, f2); + TEST(!f2.is_open()); + } + TEST(f); + TEST(f << " world"); + f.close(); + TEST(get_file_contents(filename) == "Hello world"); + } + TEST(nw::remove(filename.c_str()) == 0); +} + +nw::fstream make_fstream(const std::string& filename) +{ + create_file(filename, ""); + nw::fstream f(filename); + TEST(f << "Hello"); + return f; +} + +void test_fstream(const std::string& filename) +{ + // Move construct + { + nw::fstream f = make_fstream(filename); + TEST(f); + TEST(f << " world"); + f.seekg(0); + TEST(get_file_contents(f) == "Hello world"); + } + // Move assign + { + nw::fstream f; + { + nw::fstream f2 = make_fstream(filename); + f = std::move(f2); + } + TEST(f); + TEST(f << " world"); + f.seekg(0); + TEST(get_file_contents(f) == "Hello world"); + } + // Swap + { + nw::fstream f; + { + nw::fstream f2 = make_fstream(filename); + swap(f, f2); + TEST(!f2.is_open()); + } + TEST(f); + TEST(f << " world"); + f.seekg(0); + TEST(get_file_contents(f) == "Hello world"); + } + TEST(nw::remove(filename.c_str()) == 0); +} + +void test_main(int, char** argv, char**) +{ + const std::string exampleFilename = std::string(argv[0]) + "-\xd7\xa9-\xd0\xbc-\xce\xbd.txt"; + test_ifstream(exampleFilename); + test_ofstream(exampleFilename); + test_fstream(exampleFilename); +} + +#else + +#include <iostream> + +int main() +{ + std::cout << "Test skipped as there is no C++11 support by the compiler" << std::endl; +} + +#endif diff --git a/src/boost/libs/nowide/test/test_iostream.cpp b/src/boost/libs/nowide/test/test_iostream.cpp new file mode 100644 index 000000000..cd5078f10 --- /dev/null +++ b/src/boost/libs/nowide/test/test_iostream.cpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2015 Artyom Beilis (Tonkikh) +// +// 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) +// + +#include <boost/nowide/iostream.hpp> + +#include <boost/nowide/detail/utf.hpp> +#include <string> + +#include "test.hpp" + +bool isValidUTF8(const std::string& s) +{ + using namespace boost::nowide::detail::utf; + for(std::string::const_iterator it = s.begin(); it != s.end();) + { + code_point c = utf_traits<char>::decode(it, s.end()); + if(!is_valid_codepoint(c)) + return false; + } + return true; +} + +void test_main(int argc, char** argv, char**) +{ + const char* example = "Basic letters: \xd7\xa9-\xd0\xbc-\xce\xbd\n" + "East Asian Letters: \xe5\x92\x8c\xe5\xb9\xb3\n" + "Non-BMP letters: \xf0\x9d\x84\x9e\n" + "Invalid UTF-8: `\xFF' `\xd7\xFF' `\xe5\xFF\x8c' `\xf0\x9d\x84\xFF' \n" + "\n"; + + // If we are using the standard rdbuf we can only put back 1 char + if(boost::nowide::cin.rdbuf() == std::cin.rdbuf()) + { + std::cout << "Using std::cin" << std::endl; + int maxval = 15000; + for(int i = 0; i < maxval; i++) + { + char c = i % 96 + ' '; + TEST(boost::nowide::cin.putback(c)); + int ci = i % 96 + ' '; + TEST(boost::nowide::cin.get() == ci); + } + } else + { + int maxval = 15000; + for(int i = 0; i < maxval; i++) + { + char c = i % 96 + ' '; + TEST(boost::nowide::cin.putback(c)); + } + for(int i = maxval - 1; i >= 0; i--) + { + int c = i % 96 + ' '; + TEST(boost::nowide::cin.get() == c); + } + } + boost::nowide::cout << "Normal I/O:" << std::endl; + boost::nowide::cout << example << std::endl; + boost::nowide::cerr << example << std::endl; + + boost::nowide::cout << "Flushing each character:" << std::endl; + + for(const char* s = example; *s; s++) + { + boost::nowide::cout << *s << std::flush; + TEST(boost::nowide::cout); + } + + TEST(boost::nowide::cout); + TEST(boost::nowide::cerr); + if(argc == 2 && argv[1] == std::string("-i")) + { + std::string v1, v2; + boost::nowide::cin >> v1 >> v2; + TEST(boost::nowide::cin); + TEST(isValidUTF8(v1)); + TEST(isValidUTF8(v2)); + boost::nowide::cout << "First: " << v1 << std::endl; + boost::nowide::cout << "Second: " << v2 << std::endl; + TEST(boost::nowide::cout); + } +} diff --git a/src/boost/libs/nowide/test/test_sets.hpp b/src/boost/libs/nowide/test/test_sets.hpp new file mode 100644 index 000000000..10243e9b8 --- /dev/null +++ b/src/boost/libs/nowide/test/test_sets.hpp @@ -0,0 +1,135 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// +// 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) +// +#ifndef BOOST_NOWIDE_TEST_SETS_HPP_INCLUDED +#define BOOST_NOWIDE_TEST_SETS_HPP_INCLUDED + +#include <boost/nowide/config.hpp> +#include <iostream> +#include <string> + +struct utf8_to_wide +{ + const char* utf8; + const wchar_t* wide; +}; + +struct wide_to_utf8 +{ + const wchar_t* wide; + const char* utf8; +}; + +#if defined(BOOST_MSVC) && BOOST_MSVC < 1700 +#pragma warning(disable : 4428) // universal-character-name encountered in source +#endif + +const std::wstring wreplacement_str(1, wchar_t(BOOST_NOWIDE_REPLACEMENT_CHARACTER)); + +// clang-format off +const utf8_to_wide roundtrip_tests[] = { + {"", L""}, + {"\xf0\x9d\x92\x9e-\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82.txt", + L"\U0001D49E-\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042.txt"}, + {"\xd7\xa9-\xd0\xbc-\xce\xbd.txt", + L"\u05e9-\u043c-\u03bd.txt"}, + {"\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d", + L"\u05e9\u05dc\u05d5\u05dd"}, +}; + +const utf8_to_wide invalid_utf8_tests[] = { + {"\xFF\xFF", L"\ufffd\ufffd"}, + {"\xd7\xa9\xFF", L"\u05e9\ufffd"}, + {"\xd7", L"\ufffd"}, + {"\xFF\xd7\xa9", L"\ufffd\u05e9"}, + {"\xFF\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82", L"\uFFFD\u043F\u0440\u0438\u0432\u0435\u0442"}, + {"\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82\xFF", L"\u043F\u0440\u0438\u0432\u0435\u0442\uFFFD"}, + {"\xE3\x82\xFF\xE3\x81\x82", L"\ufffd\u3042"}, + {"\xE3\xFF\x84\xE3\x81\x82", L"\ufffd\ufffd\u3042"}, +}; + +const wide_to_utf8 invalid_wide_tests[] = { + {L"\xDC01\x05e9", "\xEF\xBF\xBD\xd7\xa9"}, + {L"\x05e9\xD800", "\xd7\xa9\xEF\xBF\xBD"}, + {L"\xDC00\x20\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042", + "\xEF\xBF\xBD \xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82"}, + {L"\u3084\u3042\xDC00\x20\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042", + "\xE3\x82\x84\xE3\x81\x82\xEF\xBF\xBD \xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82"}, +}; + + +const wide_to_utf8 invalid_utf16_tests[] = { + {L"\xD800\x20\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042", + "\xEF\xBF\xBD\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82"}, + {L"\u3084\u3042\xD800\x20\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042", + "\xE3\x82\x84\xE3\x81\x82\xEF\xBF\xBD\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82"}, +}; + +const wide_to_utf8 invalid_utf32_tests[] = { + {L"\xD800\x20\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042", + "\xEF\xBF\xBD \xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82"}, + {L"\u3084\u3042\xD800\x20\u043F\u0440\u0438\u0432\u0435\u0442-\u3084\u3042", + "\xE3\x82\x84\xE3\x81\x82\xEF\xBF\xBD \xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82-\xE3\x82\x84\xE3\x81\x82"}, +}; + +// clang-format on + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4127) // Constant expression detected +#endif + +template<typename T, size_t N> +size_t array_size(const T (&)[N]) +{ + return N; +} + +void run_all(std::wstring (*to_wide)(const std::string&), std::string (*to_narrow)(const std::wstring&)) +{ + for(size_t i = 0; i < array_size(roundtrip_tests); i++) + { + std::cout << " Roundtrip " << i << std::endl; + TEST(roundtrip_tests[i].utf8 == to_narrow(roundtrip_tests[i].wide)); + TEST(to_wide(roundtrip_tests[i].utf8) == roundtrip_tests[i].wide); + } + + for(size_t i = 0; i < array_size(invalid_utf8_tests); i++) + { + std::cout << " Invalid UTF8 " << i << std::endl; + TEST(to_wide(invalid_utf8_tests[i].utf8) == invalid_utf8_tests[i].wide); + } + + for(size_t i = 0; i < array_size(invalid_wide_tests); i++) + { + std::cout << " Invalid Wide " << i << std::endl; + TEST(to_narrow(invalid_wide_tests[i].wide) == invalid_wide_tests[i].utf8); + } + + size_t total = 0; + const wide_to_utf8* ptr = 0; + if(sizeof(wchar_t) == 2) + { + ptr = invalid_utf16_tests; + total = array_size(invalid_utf16_tests); + } else + { + ptr = invalid_utf32_tests; + total = array_size(invalid_utf32_tests); + } + for(size_t i = 0; i < total; i++) + { + std::cout << " Invalid UTF16/32 " << i << std::endl; + TEST(to_narrow(ptr[i].wide) == ptr[i].utf8); + } +} + +#endif + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif diff --git a/src/boost/libs/nowide/test/test_stackstring.cpp b/src/boost/libs/nowide/test/test_stackstring.cpp new file mode 100644 index 000000000..df675c54c --- /dev/null +++ b/src/boost/libs/nowide/test/test_stackstring.cpp @@ -0,0 +1,256 @@ +// +// 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 +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/nowide/stackstring.hpp> +#include <iostream> +#include <vector> + +#include "test.hpp" +#include "test_sets.hpp" + +#if defined(BOOST_MSVC) && BOOST_MSVC < 1700 +#pragma warning(disable : 4428) // universal-character-name encountered in source +#endif + +template<typename CharOut, typename CharIn, size_t BufferSize> +class test_basic_stackstring : public boost::nowide::basic_stackstring<CharOut, CharIn, BufferSize> +{ +public: + typedef boost::nowide::basic_stackstring<CharOut, CharIn, BufferSize> parent; + +#if BOOST_NOWIDE_CXX11 + using parent::parent; +#else + test_basic_stackstring() + {} + explicit test_basic_stackstring(const CharIn* input) : parent(input) + {} + test_basic_stackstring(const CharIn* begin, const CharIn* end) : parent(begin, end) + {} +#endif + using parent::uses_stack_memory; + bool uses_heap_memory() const + { + return !uses_stack_memory() && this->get(); + } +}; + +typedef test_basic_stackstring<wchar_t, char, 256> test_wstackstring; +typedef test_basic_stackstring<char, wchar_t, 256> test_stackstring; + +std::wstring stackstring_to_wide(const std::string& s) +{ + const test_wstackstring ss(s.c_str()); + TEST(ss.uses_stack_memory()); + return ss.get(); +} + +std::string stackstring_to_narrow(const std::wstring& s) +{ + const test_stackstring ss(s.c_str()); + TEST(ss.uses_stack_memory()); + return ss.get(); +} + +std::wstring heap_stackstring_to_wide(const std::string& s) +{ + const test_basic_stackstring<wchar_t, char, 1> ss(s.c_str()); + TEST(ss.uses_heap_memory() || s.empty()); + return ss.get(); +} + +std::string heap_stackstring_to_narrow(const std::wstring& s) +{ + const test_basic_stackstring<char, wchar_t, 1> ss(s.c_str()); + TEST(ss.uses_heap_memory() || s.empty()); + return ss.get(); +} + +void test_main(int, char**, char**) +{ + std::string hello = "\xd7\xa9\xd7\x9c\xd7\x95\xd7\x9d"; + std::wstring whello = boost::nowide::widen(hello); + const wchar_t* wempty = L""; + + { + std::cout << "-- Default constructed string is NULL" << std::endl; + const boost::nowide::short_stackstring s; + TEST(s.get() == 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); + } + { + 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); + TEST(s.get() == NULL); + boost::nowide::short_stackstring s2(L"foo"); + TEST(s2.get() == std::string("foo")); + s2.convert(NULL, NULL); + TEST(s2.get() == NULL); + } + { + std::cout << "-- An empty string is accepted" << std::endl; + const boost::nowide::short_stackstring s(wempty); + TEST(s.get()); + TEST(s.get() == std::string()); + const boost::nowide::short_stackstring s2(wempty, wempty); + TEST(s2.get()); + TEST(s2.get() == std::string()); + } + { + std::cout << "-- An empty string is accepted" << std::endl; + boost::nowide::short_stackstring s, s2; + TEST(s.convert(wempty)); + TEST(s.get() == std::string()); + TEST(s2.convert(wempty, wempty)); + TEST(s2.get() == std::string()); + } + { + std::cout << "-- Will be put on heap" << std::endl; + test_basic_stackstring<wchar_t, char, 3> sw; + TEST(sw.convert(hello.c_str())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == whello); + TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == whello); + } + { + std::cout << "-- Will be put on stack" << std::endl; + test_basic_stackstring<wchar_t, char, 40> sw; + TEST(sw.convert(hello.c_str())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == whello); + TEST(sw.convert(hello.c_str(), hello.c_str() + hello.size())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == whello); + } + { + std::cout << "-- Will be put on heap" << std::endl; + test_basic_stackstring<char, wchar_t, 3> sw; + TEST(sw.convert(whello.c_str())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == hello); + TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size())); + TEST(sw.uses_heap_memory()); + TEST(sw.get() == hello); + } + { + std::cout << "-- Will be put on stack" << std::endl; + test_basic_stackstring<char, wchar_t, 40> sw; + TEST(sw.convert(whello.c_str())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == hello); + TEST(sw.convert(whello.c_str(), whello.c_str() + whello.size())); + TEST(sw.uses_stack_memory()); + TEST(sw.get() == hello); + } + { + typedef test_basic_stackstring<wchar_t, char, 6> stackstring; + const std::wstring heapVal = L"heapValue"; + const std::wstring stackVal = L"stack"; + const stackstring heap(boost::nowide::narrow(heapVal).c_str()); + const stackstring stack(boost::nowide::narrow(stackVal).c_str()); + TEST(heap.uses_heap_memory()); + TEST(stack.uses_stack_memory()); + + { + 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); //-V570 + TEST(sw3.get() == heapVal); + // Assign empty + sw3 = sEmpty; //-V820 + TEST(sw3.get() == NULL); + } + { + 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); //-V570 + TEST(sw3.get() == stackVal); + // Assign empty + sw3 = sEmpty; //-V820 + TEST(sw3.get() == NULL); + } + { + stackstring sw2(stack); + sw2 = heap; + TEST(sw2.get() == heapVal); + } + { + stackstring sw2(heap); + sw2 = stack; + TEST(sw2.get() == stackVal); + } + { + 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::wstring val2 = sw3.get(); + swap(sw2, sw3); + TEST(sw2.get() == val2); + TEST(sw3.get() == heapVal); + } + { + stackstring sw2(stack), sw3(stack); + sw3.get()[0] = 'z'; + const std::wstring val2 = sw3.get(); + swap(sw2, sw3); + TEST(sw2.get() == val2); + TEST(sw3.get() == stackVal); + } + 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; + run_all(heap_stackstring_to_wide, heap_stackstring_to_narrow); +} diff --git a/src/boost/libs/nowide/test/test_stdio.cpp b/src/boost/libs/nowide/test/test_stdio.cpp new file mode 100644 index 000000000..250b6019d --- /dev/null +++ b/src/boost/libs/nowide/test/test_stdio.cpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// Copyright (c) 2019 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) +// + +#include <boost/nowide/cstdio.hpp> + +#include <boost/nowide/convert.hpp> +#include <cstdlib> +#include <cstring> +#include <iostream> + +#include "test.hpp" + +bool file_exists(const std::string& filename) +{ +#ifdef BOOST_WINDOWS + FILE* f = boost::nowide::detail::wfopen(boost::nowide::widen(filename).c_str(), L"r"); +#else + FILE* f = std::fopen(filename.c_str(), "r"); +#endif + bool result = false; + if(f) + { + std::fclose(f); + result = true; + } + return result; +} + +void create_test_file(const std::string& filename) +{ +#ifdef BOOST_WINDOWS + FILE* f = boost::nowide::detail::wfopen(boost::nowide::widen(filename).c_str(), L"w"); +#else + FILE* f = std::fopen(filename.c_str(), "w"); +#endif + TEST(f); + TEST(std::fputs("test\n", f) >= 0); + 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 + +void test_main(int, char** argv, char**) +{ + 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 + + std::cout << " -- fopen - existing file" << std::endl; + { + create_test_file(filename); + FILE* f = boost::nowide::fopen(filename.c_str(), "r"); + TEST(f); + char buf[16]; + TEST(std::fgets(buf, 16, f) != 0); + TEST(strcmp(buf, "test\n") == 0); + std::fclose(f); + } + 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)); + } + 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)); + } + std::cout << " -- freopen" << std::endl; + { + create_test_file(filename); + FILE* f = boost::nowide::fopen(filename.c_str(), "r+"); + TEST(f); + std::cout << " -- Can read & write" << std::endl; + { + char buf[32]; + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "test\n") == 0); + TEST(std::fseek(f, 0, SEEK_END) == 0); + TEST(std::fputs("foobar\n", f) >= 0); + } + // Reopen in read mode + // Note that changing the mode is not possibly on all implementations + // E.g. MSVC disallows NULL completely as the file parameter + FILE* f2 = boost::nowide::freopen(NULL, "r", f); + if(!f2) + f2 = boost::nowide::freopen(filename.c_str(), "r", f); + std::cout << " -- no write possible" << std::endl; + { + TEST(f2 == f); + TEST(std::fputs("not-written\n", f) < 0); + TEST(std::fseek(f, 0, SEEK_SET) == 0); + char buf[32]; + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "test\n") == 0); + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "foobar\n") == 0); + } + std::cout << " -- Reopen different file" << std::endl; + const std::string filename2 = filename + ".1.txt"; + TEST(boost::nowide::freopen(filename2.c_str(), "w", f) == f); + { + char buf[32]; + TEST(std::fputs("baz\n", f) >= 0); + std::fclose(f); + f = boost::nowide::fopen(filename2.c_str(), "r"); + TEST(f); + TEST(std::fgets(buf, 32, f) != 0); + TEST(strcmp(buf, "baz\n") == 0); + } + std::fclose(f); + boost::nowide::remove(filename2.c_str()); + } + std::cout << " -- rename" << std::endl; + { + create_test_file(filename); + const std::string filename2 = filename + ".1.txt"; + boost::nowide::remove(filename2.c_str()); + TEST(file_exists(filename)); + TEST(!file_exists(filename2)); + TEST(boost::nowide::rename(filename.c_str(), filename2.c_str()) == 0); + TEST(!file_exists(filename)); + TEST(file_exists(filename2)); + TEST(boost::nowide::remove(filename.c_str()) < 0); + TEST(boost::nowide::remove(filename2.c_str()) == 0); + } +} diff --git a/src/boost/libs/nowide/test/test_system.cpp b/src/boost/libs/nowide/test/test_system.cpp new file mode 100644 index 000000000..3a6f64580 --- /dev/null +++ b/src/boost/libs/nowide/test/test_system.cpp @@ -0,0 +1,178 @@ +// +// Copyright (c) 2012 Artyom Beilis (Tonkikh) +// +// 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) +// +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include <boost/nowide/cstdlib.hpp> + +#include <boost/nowide/args.hpp> +#include <boost/nowide/detail/convert.hpp> +#include <algorithm> +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <string> +#include <vector> + +#include "test.hpp" + +bool is_ascii(const std::string& s) +{ + for(std::string::const_iterator it = s.begin(); it != s.end(); ++it) + { + if(static_cast<unsigned char>(*it) > 0x7F) + return false; + } + return true; +} + +std::string replace_non_ascii(const std::string& s) +{ + std::string::const_iterator it = s.begin(); + namespace utf = boost::nowide::detail::utf; + typedef utf::utf_traits<char> utf8; + std::string result; + result.reserve(s.size()); + while(it != s.end()) + { + utf::code_point c = utf8::decode(it, s.end()); + TEST(c != utf::illegal && c != utf::incomplete); + if(c > 0x7F) + c = '?'; // WinAPI seems to do this + result.push_back(static_cast<char>(c)); + } + return result; +} + +void compare_string_arrays(char** main_val, char** utf8_val, bool sort) +{ + std::vector<std::string> vec_main, vec_utf8; + for(; *main_val; ++main_val) + vec_main.push_back(std::string(*main_val)); + for(; *utf8_val; ++utf8_val) + vec_utf8.push_back(std::string(*utf8_val)); + // Same number of strings + TEST_EQ(vec_main.size(), vec_utf8.size()); + if(sort) + { + // Order doesn't matter + std::sort(vec_main.begin(), vec_main.end()); + std::sort(vec_utf8.begin(), vec_utf8.end()); + } + for(size_t i = 0; i < vec_main.size(); ++i) + { + // Skip strings with non-ascii chars + if(is_ascii(vec_main[i]) && vec_main[i] != vec_utf8[i]) + TEST_EQ(vec_main[i], replace_non_ascii(vec_utf8[i])); + } +} + +void compare_getenv(char** env) +{ + // For all all variables in env check against getenv + for(char** e = env; *e != 0; e++) + { + const char* key_begin = *e; + const char* key_end = strchr(key_begin, '='); + TEST(key_end); + std::string key = std::string(key_begin, key_end); + const char* std_value = std::getenv(key.c_str()); + const char* bnw_value = boost::nowide::getenv(key.c_str()); + // If std_value is set, bnw value must be too and be equal, else bnw value must be unset too + if(std_value) + { + TEST(bnw_value); + // Compare only if ascii + if(is_ascii(std_value) && std::string(std_value) != std::string(bnw_value)) + TEST_EQ(std_value, replace_non_ascii(bnw_value)); + } else + TEST(!bnw_value); + } +} + +const std::string example = "\xd7\xa9-\xd0\xbc-\xce\xbd"; + +void run_child(int argc, char** argv, char** env) +{ + // Test arguments + TEST(argc == 2); + TEST_EQ(argv[1], example); + TEST(argv[2] == 0); + + // Test getenv + TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST")); + TEST_EQ(boost::nowide::getenv("BOOST_NOWIDE_TEST"), example); + TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST_NONE") == 0); + // Empty variables are unreliable on windows, hence skip. E.g. using "set FOO=" unsets FOO +#ifndef BOOST_WINDOWS + TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); + TEST_EQ(boost::nowide::getenv("BOOST_NOWIDE_EMPTY"), std::string()); +#endif // !_WIN32 + + // This must be contained in env + std::string sample = "BOOST_NOWIDE_TEST=" + example; + bool found = false; + for(char** e = env; *e != 0; e++) + { + if(*e == sample) + found = true; + } + TEST(found); + + std::cout << "Subprocess ok" << std::endl; +} + +void run_parent(const char* exe_path) +{ +#if BOOST_NOWIDE_TEST_USE_NARROW + TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST", example.c_str(), 1) == 0); + TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST_NONE", example.c_str(), 1) == 0); + TEST(boost::nowide::unsetenv("BOOST_NOWIDE_TEST_NONE") == 0); + TEST(boost::nowide::setenv("BOOST_NOWIDE_EMPTY", "", 1) == 0); + TEST(boost::nowide::getenv("BOOST_NOWIDE_EMPTY")); + std::string command = "\""; + command += exe_path; + command += "\" "; + command += example; + TEST(boost::nowide::system(command.c_str()) == 0); + std::cout << "Parent ok" << std::endl; +#else + std::wstring envVar = L"BOOST_NOWIDE_TEST=" + boost::nowide::widen(example); + TEST(_wputenv(envVar.c_str()) == 0); + std::wstring wcommand = boost::nowide::widen(exe_path) + L" " + boost::nowide::widen(example); + TEST(_wsystem(wcommand.c_str()) == 0); + std::cout << "Wide Parent ok" << std::endl; +#endif +} + +void test_main(int argc, char** argv, char** env) +{ + const int old_argc = argc; + char** old_argv = argv; + char** old_env = env; + { + boost::nowide::args _(argc, argv, env); + TEST(argc == old_argc); + std::cout << "Checking arguments" << std::endl; + compare_string_arrays(old_argv, argv, false); + std::cout << "Checking env" << std::endl; + compare_string_arrays(old_env, env, true); + compare_getenv(env); + } + // When `args` is destructed the old values must be restored + TEST(argc == old_argc); + TEST(argv == old_argv); + TEST(env == old_env); + + boost::nowide::args a(argc, argv, env); + if(argc == 1) + run_parent(argv[0]); + else + run_child(argc, argv, env); +} diff --git a/src/boost/libs/nowide/tools/create_standalone.sh b/src/boost/libs/nowide/tools/create_standalone.sh new file mode 100644 index 000000000..76d9df096 --- /dev/null +++ b/src/boost/libs/nowide/tools/create_standalone.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +set -euo pipefail + +cd "$(dirname "$0")/.." + +if ! [ -e "tools/create_standalone.sh" ]; then + echo "Could not change to repo root" + exit 1 +fi + +targetFolder="${1:-nowide_standalone}" + +# If target folder exists fail, unless it is the default in which case it is removed +if [ -e "$targetFolder" ]; then + if [[ "$targetFolder" == "nowide_standalone" ]]; then + rm -r "$targetFolder" + else + echo "Target folder $targetFolder exists" + exit 1 + fi +fi + +mkdir -p "$targetFolder"/include + +cp -r include/boost/nowide "$targetFolder"/include +cp -r src test cmake CMakeLists.txt LICENSE "$targetFolder" +cp standalone/*.hpp "$targetFolder"/include/nowide +mv "$targetFolder/cmake/BoostAddOptions.cmake" "$targetFolder/cmake/NowideAddOptions.cmake" +mv "$targetFolder/cmake/BoostAddWarnings.cmake" "$targetFolder/cmake/NowideAddWarnings.cmake" +find "$targetFolder" -name 'Jamfile*' -delete + +SOURCES=$(find "$targetFolder" -name '*.hpp' -or -name '*.cpp') +SOURCES_NO_BOOST=$(echo "$SOURCES" | grep -v 'filesystem.hpp') + +sed 's/BOOST_NOWIDE_/NOWIDE_/g' -i $SOURCES +sed 's/BOOST_/NOWIDE_/g' -i $SOURCES +sed 's/boost::nowide/nowide/g' -i $SOURCES +sed 's/boost::chrono/std::chrono/g' -i $SOURCES +sed 's/boost::milli/std::milli/g' -i $SOURCES +sed 's/boost::/nowide::/g' -i $SOURCES_NO_BOOST +sed '/namespace boost/d' -i $SOURCES +sed 's/<boost\/chrono.hpp/<chrono/g' -i $SOURCES +sed 's/<boost\/nowide\//<nowide\//g' -i $SOURCES +sed 's/<boost\//<nowide\//g' -i $SOURCES_NO_BOOST +sed '/config\/abi_/d' -i $SOURCES + +CMLs=$(find "$targetFolder" -name 'CMakeLists.txt' -or -name '*.cmake') + +sed 's/ BOOST_ALL_NO_LIB//' -i $CMLs +sed 's/BOOST_NOWIDE_/NOWIDE_/g' -i $CMLs +sed 's/Boost_NOWIDE_/NOWIDE_/g' -i $CMLs +sed 's/boost_nowide/nowide/g' -i $CMLs +sed 's/boost_/nowide_/g' -i $CMLs +sed 's/Boost::nowide/nowide::nowide/g' -i $CMLs +sed 's/Boost/Nowide/g' -i $CMLs +sed 's/ OR BOOST_SUPERPROJECT_SOURCE_DIR//' -i $CMLs + +sed '/PUBLIC BOOST_NOWIDE_NO_LIB)/d' -i "$targetFolder/CMakeLists.txt" +sed '/^if(BOOST_SUPERPROJECT_SOURCE_DIR)/,/^endif/d' -i "$targetFolder/CMakeLists.txt" +sed '/add_warnings/atarget_compile_features(nowide PUBLIC cxx_std_11)' -i "$targetFolder/CMakeLists.txt" +sed 's/NAMESPACE Nowide CONFIG_FILE.*$/NAMESPACE nowide)/' -i "$targetFolder/CMakeLists.txt" + +sed '/if(NOT BOOST_SUPERPROJECT_SOURCE_DIR)/,/endif/d' -i "$targetFolder/test/CMakeLists.txt" +sed 's/ LIBRARIES Nowide::chrono//' -i "$targetFolder/test/CMakeLists.txt" +sed '/Nowide::filesystem/d' -i "$targetFolder/test/CMakeLists.txt" |