diff --git a/.travis.yml b/.travis.yml index 0128bbc..54efeaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ -# Copyright 2016-2019 Peter Dimov +# Copyright 2016 - 2019 Peter Dimov +# Copyright 2017 - 2019 James E. King III +# Copyright 2019 - 2020 Alexander Grund # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -10,231 +12,113 @@ branches: only: - master - develop + - /bugfix\/.*/ - /feature\/.*/ + - /fix\/.*/ + - /pr\/.*/ env: - matrix: - - BOGUS_JOB=true + global: + - B2_LINK=link=shared,static + - B2_VARIANT=variant=debug,release + - UBSAN_OPTIONS=print_stacktrace=1 + +anchors: + libcpp: &libcpp { apt: { packages: [libc++-dev, libc++-helpers] } } + clang-33: &clang-33 { apt: { packages: [ "clang-3.3"] } } + clang-34: &clang-34 { apt: { packages: [ "clang-3.4"] } } + clang-35: &clang-35 { apt: { packages: [ "clang-3.5"], sources: [ "ubuntu-toolchain-r-test" ] } } + clang-36: &clang-36 { apt: { packages: [ "clang-3.6"], sources: [ "ubuntu-toolchain-r-test" ] } } + clang-37: &clang-37 { apt: { packages: [ "clang-3.7"], sources: [ "ubuntu-toolchain-r-test" ] } } + clang-38: &clang-38 { apt: { packages: [ "clang-3.8"], sources: [ "ubuntu-toolchain-r-test" ] } } + clang-39: &clang-39 { apt: { packages: [ "clang-3.9"], sources: [ "ubuntu-toolchain-r-test" ] } } + clang-4: &clang-4 { apt: { packages: [ "clang-4.0", + "libstdc++-6-dev" ], sources: [ "llvm-toolchain-xenial-4.0", + "ubuntu-toolchain-r-test" ] } } + clang-5: &clang-5 { apt: { packages: [ "clang-5.0", + "libstdc++-7-dev" ], sources: [ "llvm-toolchain-xenial-5.0", + "ubuntu-toolchain-r-test" ] } } + clang-6: &clang-6 { apt: { packages: [ "clang-6.0", + "libc6-dbg", + "libc++-dev", + "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-6.0", + "ubuntu-toolchain-r-test" ] } } + clang-7: &clang-7 { apt: { packages: [ "clang-7", + "libc6-dbg", + "libc++-dev", + "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-7", + "ubuntu-toolchain-r-test" ] } } + clang-8: &clang-8 { apt: { packages: [ "clang-8", + "libc6-dbg", + "libc++-dev", + "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-8", + "ubuntu-toolchain-r-test" ] } } + clang-9: &clang-9 { apt: { packages: [ "clang-9" ], sources: [ "ubuntu-toolchain-r-test", + { sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main', + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'} ] } } + + gcc-44: &gcc-44 { apt: { packages: [ "g++-4.4" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-46: &gcc-46 { apt: { packages: [ "g++-4.6" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-47: &gcc-47 { apt: { packages: [ "g++-4.7" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-48: &gcc-48 { apt: { packages: [ "g++-4.8" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-49: &gcc-49 { apt: { packages: [ "g++-4.9" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-5: &gcc-5 { apt: { packages: [ "g++-5" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-6: &gcc-6 { apt: { packages: [ "g++-6" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-7: &gcc-7 { apt: { packages: [ "g++-7" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-8: &gcc-8 { apt: { packages: [ "g++-8" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-9: &gcc-9 { apt: { packages: [ "g++-9" ], sources: [ "ubuntu-toolchain-r-test" ] } } jobs: - exclude: - - env: BOGUS_JOB=true - include: - - stage: essential - compiler: g++-4.4 - env: CXXSTD=98,0x - addons: - apt: - packages: [g++-4.4] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-9 - env: UBSAN=1 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold - addons: - apt: - packages: [g++-9] - sources: [ubuntu-toolchain-r-test] - - - dist: trusty - compiler: /usr/bin/clang++ - env: CXXSTD=03,11 - addons: - apt: - packages: [clang-3.3] - - - compiler: clang++-9 - env: UBSAN=1 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 VISIBILITY=global - addons: - apt: - packages: [clang-9] - sources: - - ubuntu-toolchain-r-test - - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - - - dist: trusty - compiler: clang++-libc++ - env: UBSAN=1 CXXSTD=03,11,14 UBSAN_OPTIONS=print_stacktrace=1 - addons: - apt: - packages: [libc++-dev, libc++-helpers] - + - { compiler: g++-4.4, env: 'B2_CXXSTD=98,0x', addons: *gcc-44, stage: essential } + - { compiler: g++-9, env: 'SANITIZERS=1 B2_CXXSTD=03,11,14,17,2a B2_LINKFLAGS="linkflags=-fuse-ld=gold"', addons: *gcc-9 } + - { compiler: clang++, env: 'B2_CXXSTD=03,11', addons: *clang-33, dist: trusty } + - { compiler: clang++-9, env: 'SANITIZERS=1 B2_CXXSTD=03,11,14,17,2a B2_CXXFLAGS="visibility=global"', addons: *clang-9 } + - { compiler: clang++-libc++, env: 'SANITIZERS=1 B2_CXXSTD=03,11,14', addons: *libcpp, dist: trusty } - os: osx compiler: clang++ - env: UBSAN=1 CXXSTD=03,11,14,1z UBSAN_OPTIONS=print_stacktrace=1 + # DYLD_LIBRARY_PATH causes problems on system() spawned processes -> static build only + env: SANITIZERS=1 B2_CXXSTD=03,11,14,1z B2_LINK=link=static + # Codecov + - compiler: g++-8 + env: COMMENT=codecov.io B2_CXXSTD=03,11 GCOV=gcov-8 + addons: *gcc-8 + script: + - cd $BOOST_ROOT/libs/$SELF + - $BOOST_CI/ci/travis/codecov.sh # Additional compiler versions tested for completenes - - stage: additional - compiler: g++ - env: CXXSTD=03,11 + - { compiler: g++, env: 'B2_CXXSTD=03,11', stage: additional } + - { compiler: g++-4.6, env: 'B2_CXXSTD=03,0x', addons: *gcc-46 } + - { compiler: g++-4.7, env: 'B2_CXXSTD=03,11', addons: *gcc-47 } + - { compiler: g++-4.8, env: 'B2_CXXSTD=03,11', addons: *gcc-48 } + - { compiler: g++-4.9, env: 'B2_CXXSTD=03,11', addons: *gcc-49 } + - { compiler: g++-5, env: 'B2_CXXSTD=03,11,14,1z', addons: *gcc-5 } + - { compiler: g++-6, env: 'B2_CXXSTD=03,11,14,1z', addons: *gcc-6 } + - { compiler: g++-7, env: 'B2_CXXSTD=03,11,14,17', addons: *gcc-7 } + - { compiler: g++-8, env: 'B2_CXXSTD=03,11,14,17,2a', addons: *gcc-8 } + - { compiler: g++-9, env: 'B2_CXXSTD=03,11,14,17,2a', addons: *gcc-9 } + - { compiler: clang++, env: 'B2_CXXSTD=03,11', addons: *clang-34, dist: trusty } + - { compiler: clang++-3.5, env: 'B2_CXXSTD=03,11', addons: *clang-35 } + - { compiler: clang++-3.6, env: 'B2_CXXSTD=03,11,14,1z', addons: *clang-36 } + - { compiler: clang++-3.7, env: 'B2_CXXSTD=03,11,14,1z', addons: *clang-37 } + - { compiler: clang++-3.8, env: 'B2_CXXSTD=03,11,14,1z', addons: *clang-38 } + - { compiler: clang++-3.9, env: 'B2_CXXSTD=03,11,14,1z', addons: *clang-39 } + - { compiler: clang++-4.0, env: 'B2_CXXSTD=03,11,14,1z', addons: *clang-4 } + - { compiler: clang++-5.0, env: 'B2_CXXSTD=03,11,14,1z', addons: *clang-5 } + - { compiler: clang++-6.0, env: 'B2_CXXSTD=03,11,14,17', addons: *clang-6 } + - { compiler: clang++-7, env: 'B2_CXXSTD=03,11,14,17,2a', addons: *clang-7 } + - { compiler: clang++-8, env: 'B2_CXXSTD=03,11,14,17,2a', addons: *clang-8 } + - { compiler: clang++-9, env: 'B2_CXXSTD=03,11,14,17,2a', addons: *clang-9 } + - { compiler: clang++-libc++, env: 'B2_CXXSTD=03,11,14', addons: *libcpp } - - compiler: g++-4.6 - env: CXXSTD=03,0x - addons: - apt: - packages: [g++-4.6] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-4.7 - env: CXXSTD=03,11 - addons: - apt: - packages: [g++-4.7] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-4.8 - env: CXXSTD=03,11 - addons: - apt: - packages: [g++-4.8] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-4.9 - env: CXXSTD=03,11 - addons: - apt: - packages: [g++-4.9] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-5 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [g++-5] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-6 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [g++-6] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-7 - env: CXXSTD=03,11,14,17 - addons: - apt: - packages: [g++-7] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-8 - env: CXXSTD=03,11,14,17,2a - addons: - apt: - packages: [g++-8] - sources: [ubuntu-toolchain-r-test] - - - compiler: g++-9 - env: CXXSTD=03,11,14,17,2a - addons: - apt: - packages: [g++-9] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++ - env: CXXSTD=03,11 - - - dist: trusty - compiler: /usr/bin/clang++ - env: CXXSTD=03,11 - addons: - apt: - packages: [clang-3.4] - - - compiler: clang++-3.5 - env: CXXSTD=03,11 - addons: - apt: - packages: [clang-3.5] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-3.6 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [clang-3.6] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-3.7 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [clang-3.7] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-3.8 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [clang-3.8] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-3.9 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [clang-3.9] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-4.0 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [clang-4.0] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-5.0 - env: CXXSTD=03,11,14,1z - addons: - apt: - packages: [clang-5.0] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-6.0 - env: CXXSTD=03,11,14,17 - addons: - apt: - packages: [clang-6.0] - sources: [ubuntu-toolchain-r-test] - - - compiler: clang++-7 - env: CXXSTD=03,11,14,17,2a - addons: - apt: - packages: [clang-7] - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-7 - - - compiler: clang++-8 - env: CXXSTD=03,11,14,17,2a - addons: - apt: - packages: [clang-8] - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 - - - compiler: clang++-9 - env: CXXSTD=03,11,14,17,2a - addons: - apt: - packages: [clang-9] - sources: - - ubuntu-toolchain-r-test - - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - - - compiler: clang++-libc++ - env: CXXSTD=03,11,14 - addons: - apt: - packages: [libc++-dev, libc++-helpers] - - - os: osx +# Coverity Scan + - if: (env(COVERITY_SCAN_NOTIFICATION_EMAIL) IS present) AND (branch IN (develop, master)) AND (type IN (cron, push)) compiler: clang++ - env: CXXSTD=03,11,14,1z + env: COMMENT="Coverity Scan" + script: + - cd $BOOST_ROOT/libs/$SELF + - $BOOST_CI/ci/travis/coverity.sh stages: - essential @@ -242,34 +126,29 @@ stages: if: type != "pull_request" install: - - BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true - - cd .. - - git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root - - cd boost-root - - git submodule update --init tools/boostdep - - mkdir -p libs/nowide - - cp -r $TRAVIS_BUILD_DIR/* libs/nowide - - python tools/boostdep/depinst/depinst.py nowide - - ./bootstrap.sh - - ./b2 headers - -script: - | - if [[ "$TRAVIS_COMPILER" =~ clang\+\+ ]]; then - TOOLSET=clang + if [[ "$SANITIZERS" == "1" ]]; then + export B2_CXXFLAGS="$B2_CXXFLAGS address-sanitizer=norecover undefined-sanitizer=norecover" + fi + which $TRAVIS_COMPILER + if [[ "$TRAVIS_COMPILER" =~ clang ]]; then + export B2_TOOLSET=clang elif [[ "$TRAVIS_COMPILER" =~ g\+\+ ]]; then - TOOLSET=gcc + export B2_TOOLSET=gcc else false fi - # DYLD_LIBRARY_PATH causes problems on system() spawned processes - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - LINK=static - else - LINK=static,shared - fi - - which $TRAVIS_COMPILER - - $TRAVIS_COMPILER --version + export BOOST_CI=$PWD/boost-ci + - git clone https://github.com/boostorg/boost-ci.git $BOOST_CI + - cp $BOOST_CI/.codecov.yml . + # Workaround + - cp -pr $BOOST_CI/ci . + - echo "build-project test ;" > Jamfile.v2 + + - source $BOOST_CI/ci/travis/install.sh && set +x - | - echo "using $TOOLSET : : $TRAVIS_COMPILER ;" > ~/user-config.jam - - ./b2 -j3 libs/nowide/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release link=$LINK ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} ${VISIBILITY:+visibility=$VISIBILITY} + echo "using $B2_TOOLSET : : $TRAVIS_COMPILER ;" > ~/user-config.jam + +script: + - cd $BOOST_ROOT/libs/$SELF + - $BOOST_CI/ci/travis/build.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/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/README.md b/README.md index d5943b4..6d8bcfd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Boost.Nowide -Branch | Travis | Appveyor | Github | 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) | [![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) | [![Documentation](https://img.shields.io/badge/documentation-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/nowide/index.html) +Branch | Travis | Appveyor | Github | Coverity Scan | 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) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/20464/badge.svg)](https://scan.coverity.com/projects/boostorg-nowide) | [![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) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/20464/badge.svg)](https://scan.coverity.com/projects/boostorg-nowide) | [![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) @@ -11,6 +11,16 @@ 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 Wide API. +### License + +Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt). + +### Properties + +* C++03 +* 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. @@ -63,3 +73,10 @@ A CMake-Config file will be installed alongside Boost.Nowide so `find_package(bo 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/appveyor.yml b/appveyor.yml index 50cbe79..8ef46dd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,6 @@ -# Copyright 2016-2019 Peter Dimov +# Copyright 2016, 2017 Peter Dimov +# Copyright 2017 - 2019 James E. King III +# Copyright 2019 - 2020 Alexander Grund # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -10,47 +12,89 @@ branches: only: - master - develop + - /bugfix\/.*/ - /feature\/.*/ + - /fix\/.*/ + - /pr\/.*/ matrix: fast_finish: false environment: + global: + # see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties + # to use the default for a given environment, comment it out; recommend you build debug and release however: + # on Windows it is important to exercise all the possibilities, especially shared vs static, however most + # libraries that care about this exercise it in their Jamfiles... + # B2_ADDRESS_MODEL: 64,32 + B2_LINK: shared,static + # B2_THREADING: threading=multi,single + B2_VARIANT: release,debug matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-12.0,msvc-14.0 - ADDRMD: 32,64 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: msvc-14.1 - CXXSTD: 14,17 - ADDRMD: 32,64 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: clang-win - CXXSTD: 14,17 - ADDRMD: 64 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: msvc-14.2 - CXXSTD: 14,17 - ADDRMD: 32,64 + - FLAVOR: Visual Studio 2019 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + B2_ADDRESS_MODEL: 32,64 + B2_CXXFLAGS: -permissive- + B2_CXXSTD: 14,17,latest # 2a + B2_TOOLSET: msvc-14.2 BOOST_CMAKE: 1 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + + - FLAVOR: Visual Studio 2017 C++2a Strict + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: 32,64 + B2_CXXFLAGS: -permissive- + B2_CXXSTD: latest # 2a + B2_TOOLSET: msvc-14.1 + + - FLAVOR: Visual Studio 2017 C++14/17 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: 32,64 + B2_CXXSTD: 14,17 + B2_TOOLSET: msvc-14.1 + + - FLAVOR: clang-cl + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: 64 + B2_CXXSTD: 11,14,17 + B2_TOOLSET: clang-win + + - FLAVOR: Visual Studio 2015 C++14 (Default) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_ADDRESS_MODEL: 64,32 + B2_TOOLSET: msvc-14.0 + + - FLAVOR: Visual Studio 2008, 2010, 2012, 2013 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0 + + - FLAVOR: cygwin (32-bit) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 ADDPATH: C:\cygwin\bin; - TOOLSET: gcc - CXXSTD: 03,11,14,1z - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_ADDRESS_MODEL: 32 + B2_CXXSTD: 03,11,14,1z + B2_TOOLSET: gcc + + - FLAVOR: cygwin (64-bit) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 ADDPATH: C:\cygwin64\bin; - TOOLSET: gcc - CXXSTD: 03,11,14,1z - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_ADDRESS_MODEL: 64 + B2_CXXSTD: 03,11,14,1z + B2_TOOLSET: gcc + + - FLAVOR: mingw32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_ADDRESS_MODEL: 32 ADDPATH: C:\mingw\bin; - TOOLSET: gcc - CXXSTD: 03,11,14,1z - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_TOOLSET: gcc + B2_CXXSTD: 03,11,14,1z + + - FLAVOR: mingw64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin; - TOOLSET: gcc - CXXSTD: 03,11,14,1z + B2_ADDRESS_MODEL: 64 + B2_TOOLSET: gcc + B2_CXXSTD: 03,11,14,1z + # CMake builds - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 GENERATOR: Visual Studio 14 2015 Win64 @@ -64,42 +108,43 @@ environment: CMAKE: true install: - - set BOOST_BRANCH=develop - - if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master - - cd .. - - git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root - - cd boost-root - - git submodule update --init tools/boostdep - - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\nowide\ - - python tools/boostdep/depinst/depinst.py nowide - - cmd /c bootstrap - - b2 -d0 headers + - set SELF=%APPVEYOR_PROJECT_NAME:-=_% + - git clone https://github.com/boostorg/boost-ci.git C:\boost-ci + - xcopy /s /e /q /i C:\boost-ci\ci .\ci + - ci\appveyor\install.bat build: off test_script: - PATH=%ADDPATH%%PATH% - - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - - if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% - - b2 -j3 libs/nowide/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release link=shared,static + - IF DEFINED B2_ADDRESS_MODEL (SET B2_ADDRESS_MODEL=address-model=%B2_ADDRESS_MODEL%) + - IF DEFINED B2_LINK (SET B2_LINK=link=%B2_LINK%) + - IF DEFINED B2_VARIANT (SET B2_VARIANT=variant=%B2_VARIANT%) + - IF DEFINED B2_CXXFLAGS (SET B2_CXXFLAGS=cxxflags=%B2_CXXFLAGS%) + # The definition of B2_TOOLCXX omits B2_CXXSTD= if it was not defined above + - IF NOT DEFINED B2_CXXSTD (SET B2_TOOLCXX=toolset=%B2_TOOLSET%) ELSE (SET B2_TOOLCXX=toolset=%B2_TOOLSET% cxxstd=%B2_CXXSTD%) + # Echo the complete build command to the build log + - IF NOT DEFINED SCRIPT (ECHO b2 libs/%SELF:\=/%/test %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3) + # Now go build... + - IF DEFINED SCRIPT (call libs\%SELF%\%SCRIPT%) ELSE (b2 libs/%SELF:\=/%/test %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3) - ps: | If ("$env:BOOST_CMAKE" -eq "1") { ./b2 --clean mkdir __build_static | cd cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=nowide .. - cmake --build . --config Debug + cmake --build . --config Debug --parallel 4 ctest --output-on-failure --build-config Debug - cmake --build . --config Release + cmake --build . --config Release --parallel 4 ctest --output-on-failure --build-config Release cd .. mkdir __build_shared | cd cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBUILD_SHARED_LIBS=ON -DBOOST_INCLUDE_LIBRARIES=nowide .. - cmake --build . --config Debug + cmake --build . --config Debug --parallel 4 ctest --output-on-failure --build-config Debug - cmake --build . --config Release + cmake --build . --config Release --parallel 4 ctest --output-on-failure --build-config Release } @@ -116,9 +161,7 @@ for: - cd build - cmake -G "%GENERATOR%" -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% .. - build: - project: build/boost_nowide.sln - parallel: true + build_script: cmake --build . --config %configuration% --parallel 4 test_script: - ctest --output-on-failure -C %configuration% --parallel 4 diff --git a/include/boost/nowide/config.hpp b/include/boost/nowide/config.hpp index 15f24b5..0114473 100644 --- a/include/boost/nowide/config.hpp +++ b/include/boost/nowide/config.hpp @@ -79,6 +79,15 @@ #define BOOST_NOWIDE_FALLTHROUGH BOOST_FALLTHROUGH #endif +// MSVC 2015 (1900) has reasonable C++11 support (especially auto-generated move ctors) +// libstdc++ < 5 does not support movable streams +#if(__cplusplus >= 201103L || (defined(BOOST_MSVC) && BOOST_MSVC >= 1900)) \ + && (!defined(BOOST_LIBSTDCXX_VERSION) || BOOST_LIBSTDCXX_VERSION >= 50000) +#define BOOST_NOWIDE_CXX11 1 +#else +#define BOOST_NOWIDE_CXX11 0 +#endif + namespace boost { /// /// \brief This namespace includes implementations of the standard library functions and diff --git a/include/boost/nowide/filebuf.hpp b/include/boost/nowide/filebuf.hpp index aa4c1be..d23c8b3 100644 --- a/include/boost/nowide/filebuf.hpp +++ b/include/boost/nowide/filebuf.hpp @@ -48,10 +48,6 @@ namespace nowide { template<> class basic_filebuf : public std::basic_streambuf { - // Non-copyable - basic_filebuf(const basic_filebuf&); - basic_filebuf& operator=(const basic_filebuf&); - typedef std::char_traits Traits; public: @@ -65,7 +61,50 @@ namespace nowide { setg(0, 0, 0); setp(0, 0); } +#if !BOOST_NOWIDE_CXX11 + private: + // Non-copyable + basic_filebuf(const basic_filebuf&); + basic_filebuf& operator=(const basic_filebuf&); + public: +#else + basic_filebuf(const basic_filebuf&) = delete; + basic_filebuf& operator=(const basic_filebuf&) = delete; + basic_filebuf(basic_filebuf&& other) noexcept : basic_filebuf() + { + swap(other); + } + basic_filebuf& operator=(basic_filebuf&& other) noexcept + { + swap(other); + return *this; + } + void swap(basic_filebuf& rhs) + { + std::basic_streambuf::swap(rhs); + using std::swap; + swap(buffer_size_, rhs.buffer_size_); + swap(buffer_, rhs.buffer_); + swap(file_, rhs.file_); + swap(owns_buffer_, rhs.owns_buffer_); + swap(last_char_, rhs.last_char_); + swap(mode_, rhs.mode_); + // Fixup last_char references + if(epptr() == &rhs.last_char_) + setp(&last_char_, &last_char_); + if(egptr() == &rhs.last_char_) + rhs.setg(&last_char_, gptr() == &rhs.last_char_ ? &last_char_ : &last_char_ + 1, &last_char_ + 1); + if(rhs.epptr() == &last_char_) + setp(&rhs.last_char_, &rhs.last_char_); + if(rhs.egptr() == &rhs.last_char_) + { + rhs.setg(&rhs.last_char_, + rhs.gptr() == &last_char_ ? &rhs.last_char_ : &rhs.last_char_ + 1, + &rhs.last_char_ + 1); + } + } +#endif virtual ~basic_filebuf() { close(); diff --git a/include/boost/nowide/fstream.hpp b/include/boost/nowide/fstream.hpp index 754c528..0bd144b 100644 --- a/include/boost/nowide/fstream.hpp +++ b/include/boost/nowide/fstream.hpp @@ -100,6 +100,18 @@ namespace nowide { using fstream_impl::is_open; using fstream_impl::close; using fstream_impl::rdbuf; +#if BOOST_NOWIDE_CXX11 + using fstream_impl::swap; + basic_ifstream(const basic_ifstream& other) = delete; + basic_ifstream& operator=(const basic_ifstream& rhs) = delete; + basic_ifstream(basic_ifstream&& other) noexcept : fstream_impl(std::move(other)) + {} + basic_ifstream& operator=(basic_ifstream&& rhs) noexcept + { + fstream_impl::operator=(std::move(rhs)); + return *this; + } +#endif }; /// @@ -140,6 +152,18 @@ namespace nowide { using fstream_impl::is_open; using fstream_impl::close; using fstream_impl::rdbuf; +#if BOOST_NOWIDE_CXX11 + using fstream_impl::swap; + basic_ofstream(const basic_ofstream& other) = delete; + basic_ofstream& operator=(const basic_ofstream& rhs) = delete; + basic_ofstream(basic_ofstream&& other) noexcept : fstream_impl(std::move(other)) + {} + basic_ofstream& operator=(basic_ofstream&& rhs) + { + fstream_impl::operator=(std::move(rhs)); + return *this; + } +#endif }; #ifdef BOOST_MSVC @@ -186,7 +210,41 @@ namespace nowide { using fstream_impl::is_open; using fstream_impl::close; using fstream_impl::rdbuf; +#if BOOST_NOWIDE_CXX11 + using fstream_impl::swap; + basic_fstream(const basic_fstream& other) = delete; + basic_fstream& operator=(const basic_fstream& rhs) = delete; + basic_fstream(basic_fstream&& other) noexcept : fstream_impl(std::move(other)) + {} + basic_fstream& operator=(basic_fstream&& rhs) + { + fstream_impl::operator=(std::move(rhs)); + return *this; + } +#endif }; +#if BOOST_NOWIDE_CXX11 + template + void swap(basic_filebuf& lhs, basic_filebuf& rhs) + { + lhs.swap(rhs); + } + template + void swap(basic_ifstream& lhs, basic_ifstream& rhs) + { + lhs.swap(rhs); + } + template + void swap(basic_ofstream& lhs, basic_ofstream& rhs) + { + lhs.swap(rhs); + } + template + void swap(basic_fstream& lhs, basic_fstream& rhs) + { + lhs.swap(rhs); + } +#endif /// /// Same as std::filebuf but accepts UTF-8 strings under Windows @@ -235,6 +293,28 @@ namespace nowide { fstream_impl() : stream_base(&buf_) {} +#if BOOST_NOWIDE_CXX11 + fstream_impl(const fstream_impl& other) = delete; + fstream_impl& operator=(const fstream_impl& other) = delete; + + fstream_impl(fstream_impl&& other) noexcept : base_buf_holder(std::move(other)), + stream_base(std::move(other)) + { + this->set_rdbuf(rdbuf()); + } + fstream_impl& operator=(fstream_impl&& rhs) noexcept + { + base_buf_holder::operator=(std::move(rhs)); + stream_base::operator=(std::move(rhs)); + return *this; + } + void swap(fstream_impl& other) + { + stream_base::swap(other); + rdbuf()->swap(*other.rdbuf()); + } +#endif + void open(const std::string& file_name, std::ios_base::openmode mode = T_StreamType::mode()) { open(file_name.c_str(), mode); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ec5973..4e64e3f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,15 +19,16 @@ 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_NOWIDE_STANDALONE) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4478814..6a3c096 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -28,6 +28,8 @@ run test_env.cpp : : : BOOST_NOWIDE_TEST_INCLUDE_WINDOWS=1 : test_env_wi run test_fs.cpp : : : /boost/filesystem//boost_filesystem/off : ; run test_fstream.cpp ; run test_fstream.cpp : : : BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 windows:no : test_internal_fstream ; +run test_fstream_cxx11.cpp ; +run test_fstream_cxx11.cpp : : : BOOST_NOWIDE_USE_FILEBUF_REPLACEMENT=1 windows:no : test_internal_fstream_cxx11 ; run test_iostream.cpp ; run test_stackstring.cpp ; run test_stdio.cpp ; diff --git a/test/test_fs.cpp b/test/test_fs.cpp index 5fdba71..320c8b2 100644 --- a/test/test_fs.cpp +++ b/test/test_fs.cpp @@ -65,6 +65,7 @@ int main() std::cerr << "Failed : " << e.what() << std::endl; return 1; } + std::cout << "Ok" << std::endl; return 0; } diff --git a/test/test_fstream_cxx11.cpp b/test/test_fstream_cxx11.cpp new file mode 100644 index 0000000..532f756 --- /dev/null +++ b/test/test_fstream_cxx11.cpp @@ -0,0 +1,210 @@ +// +// 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 + +#if BOOST_NOWIDE_CXX11 + +#include "test.hpp" +#include +#include +#include +#include +#include + +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 +std::string get_file_contents(T& stream) +{ + TEST(stream); + std::string s((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); + 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"); + } + nw::remove(filename.c_str()); +} + +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"); + } + nw::remove(filename.c_str()); +} + +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"); + } + nw::remove(filename.c_str()); +} + +int main(int, char** argv) +{ + const std::string exampleFilename = std::string(argv[0]) + "-\xd7\xa9-\xd0\xbc-\xce\xbd.txt"; + try + { + test_ifstream(exampleFilename); + test_ofstream(exampleFilename); + test_fstream(exampleFilename); + } catch(const std::exception& e) + { + std::cerr << e.what() << std::endl; + return 1; + } + std::cout << "Ok" << std::endl; + return 0; +} + +#else + +#include + +int main() +{ + std::cout << "Test skipped as there is no C++11 support by the compiler" << std::endl; + return 0; +} + +#endif