diff --git a/3rdparty/boost_filesystem/.gitattributes b/3rdparty/boost_filesystem/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/3rdparty/boost_filesystem/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/3rdparty/boost_filesystem/.github/workflows/ci.yml b/3rdparty/boost_filesystem/.github/workflows/ci.yml new file mode 100644 index 0000000..b00fcfd --- /dev/null +++ b/3rdparty/boost_filesystem/.github/workflows/ci.yml @@ -0,0 +1,517 @@ +# Copyright 2021-2022 Andrey Semashev +# +# 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) + +name: CI + +on: + pull_request: + push: + branches: + - master + - develop + - feature/** + +concurrency: + group: ${{format('{0}:{1}', github.repository, github.ref)}} + cancel-in-progress: true + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + # Linux, gcc + - toolset: gcc-4.4 + cxxstd: "98,0x" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - g++-4.4 + sources: + - "ppa:ubuntu-toolchain-r/test" + - toolset: gcc-4.6 + cxxstd: "03,0x" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - g++-4.6 + sources: + - "ppa:ubuntu-toolchain-r/test" + - toolset: gcc-4.7 + cxxstd: "03,11" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - g++-4.7 + - toolset: gcc-4.8 + cxxstd: "03,11" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-4.8 + - toolset: gcc-4.9 + cxxstd: "03,11" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - g++-4.9 + extra_tests: 1 + - toolset: gcc-5 + cxxstd: "03,11,14,1z" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - g++-5 + - toolset: gcc-6 + cxxstd: "03,11,14,1z" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-6 + - toolset: gcc-7 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-7 + - toolset: gcc-8 + cxxstd: "03,11,14,17,2a" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - g++-8 + - toolset: gcc-9 + cxxstd: "03,11,14,17,2a" + os: ubuntu-20.04 + install: + - g++-9 + - toolset: gcc-10 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - g++-10 + - toolset: gcc-11 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + os: ubuntu-20.04 + install: + - g++-11 + sources: + - "ppa:ubuntu-toolchain-r/test" + - toolset: gcc-12 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + os: ubuntu-22.04 + install: + - g++-12 + - name: UBSAN + toolset: gcc-11 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu" + ubsan: 1 + build_variant: debug + os: ubuntu-20.04 + install: + - g++-11 + sources: + - "ppa:ubuntu-toolchain-r/test" + + # Linux, clang + - toolset: clang + compiler: clang++-3.5 + cxxstd: "03,11" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - clang-3.5 + - toolset: clang + compiler: clang++-3.6 + cxxstd: "03,11,14" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - clang-3.6 + - toolset: clang + compiler: clang++-3.7 + cxxstd: "03,11,14" + os: ubuntu-latest + container: ubuntu:16.04 + install: + - clang-3.7 + - toolset: clang + compiler: clang++-3.8 + cxxstd: "03,11,14" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - clang-3.8 + - toolset: clang + compiler: clang++-3.9 + cxxstd: "03,11,14" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-3.9 + - toolset: clang + compiler: clang++-4.0 + cxxstd: "03,11,14" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-4.0 + - toolset: clang + compiler: clang++-5.0 + cxxstd: "03,11,14,1z" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-5.0 + - toolset: clang + compiler: clang++-6.0 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-6.0 + - toolset: clang + compiler: clang++-7 + cxxstd: "03,11,14,17" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-7 + # Note: clang-8 does not fully support C++20, so it is not compatible with libstdc++-8 in this mode + - toolset: clang + compiler: clang++-8 + cxxstd: "03,11,14,17,2a" + os: ubuntu-latest + container: ubuntu:18.04 + install: + - clang-8 + - g++-7 + gcc_toolchain: 7 + - toolset: clang + compiler: clang++-9 + cxxstd: "03,11,14,17,2a" + os: ubuntu-20.04 + install: + - clang-9 + - toolset: clang + compiler: clang++-10 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-10 + - toolset: clang + compiler: clang++-11 + cxxstd: "03,11,14,17,20" + os: ubuntu-22.04 + install: + - clang-11 + - toolset: clang + compiler: clang++-12 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + os: ubuntu-22.04 + install: + - clang-12 + - toolset: clang + compiler: clang++-13 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + os: ubuntu-22.04 + install: + - clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + os: ubuntu-22.04 + install: + - clang-15 + - toolset: clang + compiler: clang++-15 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + os: ubuntu-22.04 + install: + - clang-15 + - libc++-15-dev + - libc++abi-15-dev + - toolset: clang + compiler: clang++-16 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + os: ubuntu-22.04 + install: + - clang-16 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-16 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + os: ubuntu-22.04 + install: + - clang-16 + - libc++-16-dev + - libc++abi-16-dev + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - name: UBSAN + toolset: clang + compiler: clang++-15 + cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" + cxxflags: -stdlib=libc++ + linkflags: "-stdlib=libc++ -lubsan" + ubsan: 1 + build_variant: debug + os: ubuntu-22.04 + install: + - clang-15 + - libc++-15-dev + - libc++abi-15-dev + + - toolset: clang + cxxstd: "03,11,14,17,2a" + os: macos-11 + + - name: CMake tests + cmake_tests: 1 + os: ubuntu-20.04 + + timeout-minutes: 60 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ] + then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] + then + echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV + if [ -f "/etc/debian_version" ] + then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] + then + PYTHON_PACKAGE="python-is-python3" + else + PYTHON_PACKAGE="python" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake + fi + fi + git config --global pack.threads 0 + + - uses: actions/checkout@v3 + + - name: Install packages + if: matrix.install + run: | + declare -a SOURCE_KEYS SOURCES + if [ -n "${{join(matrix.source_keys, ' ')}}" ] + then + SOURCE_KEYS=("${{join(matrix.source_keys, '" "')}}") + fi + if [ -n "${{join(matrix.sources, ' ')}}" ] + then + SOURCES=("${{join(matrix.sources, '" "')}}") + fi + for key in "${SOURCE_KEYS[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + echo "Adding key: $key" + wget -O - "$key" | sudo apt-key add - && break || sleep 2 + done + done + if [ ${#SOURCES[@]} -gt 0 ] + then + APT_ADD_REPO_COMMON_ARGS=("-y") + APT_ADD_REPO_SUPPORTED_ARGS="$(apt-add-repository --help | perl -ne 'if (/^\s*-n/) { print "n"; } elsif (/^\s*-P/) { print "P"; } elsif (/^\s*-S/) { print "S"; } elsif (/^\s*-U/) { print "U"; }')" + if [ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*n*}" ] + then + APT_ADD_REPO_COMMON_ARGS+=("-n") + fi + APT_ADD_REPO_HAS_SOURCE_ARGS="$([ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*P*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*S*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*U*}" ] && echo 1 || echo 0)" + for source in "${SOURCES[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + APT_ADD_REPO_ARGS=("${APT_ADD_REPO_COMMON_ARGS[@]}") + if [ $APT_ADD_REPO_HAS_SOURCE_ARGS -ne 0 ] + then + case "$source" in + "ppa:"*) + APT_ADD_REPO_ARGS+=("-P") + ;; + "deb "*) + APT_ADD_REPO_ARGS+=("-S") + ;; + *) + APT_ADD_REPO_ARGS+=("-U") + ;; + esac + fi + APT_ADD_REPO_ARGS+=("$source") + echo "apt-add-repository ${APT_ADD_REPO_ARGS[@]}" + sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 + done + done + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} + + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=\"$GCC_TOOLCHAIN_ROOT\"" >> $GITHUB_ENV + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=() + GIT_VERSION="$(git --version | sed -e 's/git version //')" + GIT_HAS_JOBS=1 + if [ -f "/etc/debian_version" ] + then + if $(dpkg --compare-versions "$GIT_VERSION" lt 2.8.0) + then + GIT_HAS_JOBS=0 + fi + else + declare -a GIT_VER=(${GIT_VERSION//./ }) + declare -a GIT_MIN_VER=(2 8 0) + for ((i=0; i<${#GIT_VER[@]}; i++)) + do + if [ -z "${GIT_MIN_VER[i]}" ] + then + GIT_MIN_VER[i]=0 + fi + if [ "${GIT_VER[i]}" -lt "${GIT_MIN_VER[i]}" ] + then + GIT_HAS_JOBS=0 + break + fi + done + fi + if [ "$GIT_HAS_JOBS" -ne 0 ] + then + DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") + fi + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + if [ -n "${{matrix.extra_tests}}" ] + then + DEPINST_ARGS+=("--include" "example") + fi + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + if [ -z "${{matrix.cmake_tests}}" ] + then + ./bootstrap.sh + ./b2 headers + if [ -n "${{matrix.compiler}}" -o -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n "using ${{matrix.toolset}} : : ${{matrix.compiler}}" > ~/user-config.jam + if [ -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n " : \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\" \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\"" >> ~/user-config.jam + fi + echo " ;" >> ~/user-config.jam + fi + fi + + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root + if [ -n "${{matrix.extra_tests}}" ] + then + export BOOST_FILESYSTEM_TEST_WITH_EXAMPLES=1 + fi + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.ubsan}}" ] + then + export UBSAN_OPTIONS="print_stacktrace=1" + B2_ARGS+=("cxxflags=-fsanitize=undefined -fno-sanitize-recover=undefined" "linkflags=-fsanitize=undefined -fuse-ld=gold" "define=UBSAN=1" "debug-symbols=on" "visibility=global") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + B2_ARGS+=("libs/$LIBRARY/test") + ./b2 "${B2_ARGS[@]}" + + - name: Run CMake tests + if: matrix.cmake_tests + run: | + cd ../boost-root + mkdir __build_static__ && cd __build_static__ + cmake ../libs/$LIBRARY/test/test_cmake + cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS + cd .. + mkdir __build_shared__ && cd __build_shared__ + cmake -DBUILD_SHARED_LIBS=On ../libs/$LIBRARY/test/test_cmake + cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS diff --git a/3rdparty/boost_filesystem/.gitignore b/3rdparty/boost_filesystem/.gitignore new file mode 100644 index 0000000..dd33fb1 --- /dev/null +++ b/3rdparty/boost_filesystem/.gitignore @@ -0,0 +1,46 @@ +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# IDE generated files # +####################### + +# Visual Studio +Debug +Release +.sdf +.suo diff --git a/3rdparty/boost_filesystem/CMakeLists.txt b/3rdparty/boost_filesystem/CMakeLists.txt new file mode 100644 index 0000000..0bf3304 --- /dev/null +++ b/3rdparty/boost_filesystem/CMakeLists.txt @@ -0,0 +1,252 @@ +# Copyright 2019 Mike Dev +# Copyright 2020-2022 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +# +# NOTE: CMake support for Boost.Filesystem is currently experimental at best +# and the interface is likely to change in the future + +cmake_minimum_required(VERSION 3.5) +project(BoostFilesystem VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +include(CheckCXXSourceCompiles) + +set(BOOST_FILESYSTEM_NO_DEPRECATED OFF CACHE BOOL "Disable deprecated functionality of Boost.Filesystem") +set(BOOST_FILESYSTEM_DISABLE_SENDFILE OFF CACHE BOOL "Disable usage of sendfile API in Boost.Filesystem") +set(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE OFF CACHE BOOL "Disable usage of copy_file_range API in Boost.Filesystem") +set(BOOST_FILESYSTEM_DISABLE_STATX OFF CACHE BOOL "Disable usage of statx API in Boost.Filesystem") +set(BOOST_FILESYSTEM_DISABLE_GETRANDOM OFF CACHE BOOL "Disable usage of getrandom API in Boost.Filesystem") +set(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM OFF CACHE BOOL "Disable usage of arc4random API in Boost.Filesystem") +set(BOOST_FILESYSTEM_DISABLE_BCRYPT OFF CACHE BOOL "Disable usage of BCrypt API in Boost.Filesystem") +set(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI OFF CACHE BOOL "Use WASI under emscripten in Boost.Filesystem") + +# Note: We can't use the Boost::library targets in the configure checks as they may not yet be included +# by the superproject when this CMakeLists.txt is included. We also don't want to hardcode include paths +# of the needed libraries and their dependencies, recursively, as this is too fragile and requires maintenance. +# Instead, we collect include paths of all libraries and use them in the configure checks. This works faster +# if there is a unified Boost include tree in the filesystem (i.e. if `b2 headers` was run or we're in the +# official monolithic Boost distribution tree). +include(cmake/BoostLibraryIncludes.cmake) + +set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/src" ${BOOST_LIBRARY_INCLUDES}) + +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_attribute_init_priority.cpp>" BOOST_FILESYSTEM_HAS_INIT_PRIORITY) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_cxx20_atomic_ref.cpp>" BOOST_FILESYSTEM_HAS_CXX20_ATOMIC_REF) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_stat_st_blksize.cpp>" BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_stat_st_mtim.cpp>" BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_stat_st_mtimensec.cpp>" BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_stat_st_mtimespec.cpp>" BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_stat_st_birthtimensec.cpp>" BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_stat_st_birthtimespec.cpp>" BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +if(NOT BOOST_FILESYSTEM_DISABLE_STATX) + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_statx.cpp>" BOOST_FILESYSTEM_HAS_STATX) + if(NOT BOOST_FILESYSTEM_HAS_STATX) + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_statx_syscall.cpp>" BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + endif() +endif() +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_fdopendir_nofollow.cpp>" BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_dirent_d_type.cpp>" BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_posix_at_apis.cpp>" BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +if(WIN32 AND NOT BOOST_FILESYSTEM_DISABLE_BCRYPT) + set(CMAKE_REQUIRED_LIBRARIES bcrypt) + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_bcrypt.cpp>" BOOST_FILESYSTEM_HAS_BCRYPT) + unset(CMAKE_REQUIRED_LIBRARIES) +endif() + +unset(CMAKE_REQUIRED_INCLUDES) + +set(BOOST_FILESYSTEM_SOURCES + src/codecvt_error_category.cpp + src/exception.cpp + src/operations.cpp + src/directory.cpp + src/path.cpp + src/path_traits.cpp + src/portability.cpp + src/unique_path.cpp + src/utf8_codecvt_facet.cpp +) +if(WIN32 OR CYGWIN) + list(APPEND BOOST_FILESYSTEM_SOURCES src/windows_file_codecvt.cpp) +endif() + +add_library(boost_filesystem ${BOOST_FILESYSTEM_SOURCES}) +add_library(Boost::filesystem ALIAS boost_filesystem) + +get_target_property(BOOST_FILESYSTEM_TARGET_TYPE boost_filesystem TYPE) +if(BOOST_FILESYSTEM_TARGET_TYPE STREQUAL "SHARED_LIBRARY") + set(CMAKE_REQUIRED_LIBRARIES "-Wl,--no-undefined") + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_linkflag_no_undefined.cpp>" BOOST_FILESYSTEM_HAS_LINKFLAG_NO_UNDEFINED) + unset(CMAKE_REQUIRED_LIBRARIES) + if(NOT BOOST_FILESYSTEM_HAS_LINKFLAG_NO_UNDEFINED) + set(CMAKE_REQUIRED_LIBRARIES "-Wl,-undefined,error") + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_linkflag_no_undefined.cpp>" BOOST_FILESYSTEM_HAS_LINKFLAG_UNDEFINED_ERROR) + unset(CMAKE_REQUIRED_LIBRARIES) + endif() + if(BOOST_FILESYSTEM_HAS_LINKFLAG_NO_UNDEFINED) + if(NOT CMAKE_VERSION VERSION_LESS 3.13) + target_link_options(boost_filesystem PRIVATE "-Wl,--no-undefined") + else() + target_link_libraries(boost_filesystem PRIVATE "-Wl,--no-undefined") + endif() + elseif(BOOST_FILESYSTEM_HAS_LINKFLAG_UNDEFINED_ERROR) + if(NOT CMAKE_VERSION VERSION_LESS 3.13) + target_link_options(boost_filesystem PRIVATE "-Wl,-undefined,error") + else() + target_link_libraries(boost_filesystem PRIVATE "-Wl,-undefined,error") + endif() + endif() +endif() + +target_include_directories(boost_filesystem PUBLIC include) +target_include_directories(boost_filesystem PRIVATE src) + +target_compile_definitions(boost_filesystem + PUBLIC + # NOTE: + # We deactivate autolinking, because cmake based builds don't need it + # and we don't implement name mangling for the library file anyway. + # Ususally the parent CMakeLists.txt file should already have globally defined BOOST_ALL_NO_LIB + BOOST_FILESYSTEM_NO_LIB + $<$,SHARED_LIBRARY>:BOOST_FILESYSTEM_DYN_LINK=1> + $<$,STATIC_LIBRARY>:BOOST_FILESYSTEM_STATIC_LINK=1> + + PRIVATE + BOOST_FILESYSTEM_SOURCE +) + +if(WIN32) + target_compile_definitions(boost_filesystem PRIVATE + _SCL_SECURE_NO_WARNINGS + _SCL_SECURE_NO_DEPRECATE + _CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_DEPRECATE + ) +endif() + +if(WIN32 OR CYGWIN) + target_compile_definitions(boost_filesystem PRIVATE + BOOST_USE_WINDOWS_H + WIN32_LEAN_AND_MEAN + NOMINMAX + ) +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND + (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 12 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 12) AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329 + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105651 + target_compile_options(boost_filesystem PRIVATE + -Wno-restrict + ) +endif() + +if(BOOST_FILESYSTEM_NO_DEPRECATED) + target_compile_definitions(boost_filesystem PUBLIC BOOST_FILESYSTEM_NO_DEPRECATED) +endif() + +if(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_INIT_PRIORITY) +endif() + +if(BOOST_FILESYSTEM_DISABLE_SENDFILE) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_SENDFILE) +endif() +if(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) +endif() +if(BOOST_FILESYSTEM_DISABLE_STATX) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_STATX) +endif() +if(BOOST_FILESYSTEM_DISABLE_GETRANDOM) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_GETRANDOM) +endif() +if(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_ARC4RANDOM) +endif() +if(BOOST_FILESYSTEM_DISABLE_BCRYPT) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_BCRYPT) +endif() +if(BOOST_FILESYSTEM_DISABLE_EMSCRIPTEN_WASI) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_DISABLE_EMSCRIPTEN_WASI) +endif() + +if(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) +endif() +if(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +endif() +if(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +endif() +if(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +endif() +if(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +endif() +if(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +endif() +if(BOOST_FILESYSTEM_HAS_STATX) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STATX) +endif() +if(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +endif() +if(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) +endif() +if(BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE) +endif() +if(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +endif() + +target_link_libraries(boost_filesystem + PUBLIC + Boost::assert + Boost::config + Boost::container_hash + Boost::core + Boost::detail + Boost::io + Boost::iterator + Boost::smart_ptr + Boost::system + Boost::type_traits + + PRIVATE + Boost::predef +) + +if(NOT BOOST_FILESYSTEM_HAS_CXX20_ATOMIC_REF) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF) + target_link_libraries(boost_filesystem + PRIVATE + Boost::atomic + ) +endif() + +if(WIN32) + if(BOOST_FILESYSTEM_HAS_BCRYPT) + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_BCRYPT) + target_link_libraries(boost_filesystem PRIVATE bcrypt) + else() + target_compile_definitions(boost_filesystem PRIVATE BOOST_FILESYSTEM_HAS_WINCRYPT) + if(NOT WINCE) + target_link_libraries(boost_filesystem PRIVATE advapi32) + else() + target_link_libraries(boost_filesystem PRIVATE coredll) + endif() + endif() + + target_link_libraries(boost_filesystem + PRIVATE + Boost::winapi + ) +endif() diff --git a/3rdparty/boost_filesystem/README.md b/3rdparty/boost_filesystem/README.md new file mode 100644 index 0000000..9af3f01 --- /dev/null +++ b/3rdparty/boost_filesystem/README.md @@ -0,0 +1,28 @@ +# Boost.Filesystem + +Boost.Filesystem, part of collection of the [Boost C++ Libraries](https://github.com/boostorg), provides facilities to manipulate files and directories, and the paths that identify them. + +### Directories + +* **doc** - Documentation sources +* **include** - Interface headers of Boost.Filesystem +* **src** - Compilable source files of Boost.Filesystem +* **test** - Boost.Filesystem unit tests +* **example** - Boost.Filesystem usage examples + +### More information + +* [Documentation](https://boost.org/libs/filesystem) +* [Report bugs](https://github.com/boostorg/filesystem/issues/new). 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](https://github.com/boostorg/filesystem/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). + +### Build status + +Branch | GitHub Actions | AppVeyor | Test Matrix | Dependencies | +:-------------: | -------------- | -------- | ----------- | ------------ | +[`master`](https://github.com/boostorg/filesystem/tree/master) | [![GitHub Actions](https://github.com/boostorg/filesystem/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/filesystem/actions?query=branch%3Amaster) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/nx3e7bcavvn3q953/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/filesystem/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/filesystem.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/filesystem.html) +[`develop`](https://github.com/boostorg/filesystem/tree/develop) | [![GitHub Actions](https://github.com/boostorg/filesystem/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/filesystem/actions?query=branch%3Adevelop) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/nx3e7bcavvn3q953/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/filesystem/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/filesystem.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/filesystem.html) + +### License + +Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). diff --git a/3rdparty/boost_filesystem/VERSION b/3rdparty/boost_filesystem/VERSION new file mode 100644 index 0000000..b4210c3 --- /dev/null +++ b/3rdparty/boost_filesystem/VERSION @@ -0,0 +1 @@ +boost-1.83.0 (commit https://github.com/boostorg/filesystem/commit/e65ddb6ef21697970f7d1438f7a46c5233940059) \ No newline at end of file diff --git a/3rdparty/boost_filesystem/appveyor.yml b/3rdparty/boost_filesystem/appveyor.yml new file mode 100644 index 0000000..3ef1a92 --- /dev/null +++ b/3rdparty/boost_filesystem/appveyor.yml @@ -0,0 +1,124 @@ +# Copyright 2016, 2017 Peter Dimov +# Copyright 2019-2022 Andrey Semashev +# 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) + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + - /feature\/.*/ + +environment: + matrix: + - TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0 + ADDRMD: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-14.0 + ADDRMD: 32,64 + EXTRA_TESTS: 1 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-14.1 + CXXSTD: 14,17,latest + ADDRMD: 32,64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - TOOLSET: msvc-14.2 + ADDRMD: 32,64 + CXXSTD: 14,17,20,latest + THREADING: single,multi + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - TOOLSET: msvc-14.3 + ADDRMD: 32,64 + CXXSTD: 14,17,20,latest + THREADING: single,multi + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + - TOOLSET: clang-win + ADDRMD: 32 + CXXSTD: 14,17,latest + ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - TOOLSET: clang-win + ADDRMD: 64 + CXXSTD: 14,17,latest + ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - TOOLSET: gcc + CXXSTD: 03,11,14,1z + ADDPATH: C:\cygwin\bin; + THREADING: single,multi + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + CXXSTD: 03,11,14,1z + ADDPATH: C:\cygwin64\bin; + EXTRA_TESTS: 1 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + CXXSTD: 03,11,14,1z + ADDPATH: C:\mingw\bin; + EXTRA_TESTS: 1 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + CXXSTD: 03,11,14,1z + ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin; + EXTRA_TESTS: 1 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + CXXSTD: 03,11,14,17 + ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin; + THREADING: single,multi + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + CXXSTD: 03,11,14,17,2a + ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin; + THREADING: single,multi + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TEST_CMAKE: 1 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + +install: + - set GIT_FETCH_JOBS=8 + - 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 init tools/build + - git submodule init tools/boostdep + - git submodule init tools/boost_install + - git submodule init libs/headers + - git submodule init libs/config + - git submodule update --jobs %GIT_FETCH_JOBS% + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\filesystem + - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include=example" + - python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" filesystem + - cmd /c bootstrap + - b2 -d0 headers + +build: off + +test_script: + - PATH=%ADDPATH%%PATH% + - if not "%ENV_SCRIPT%" == "" call "%ENV_SCRIPT%" + - if not "%EXTRA_TESTS%" == "" set BOOST_FILESYSTEM_TEST_WITH_EXAMPLES=1 + - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% + - if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% + - if not "%THREADING%" == "" set THREADING=threading=%THREADING% + - b2 -j %NUMBER_OF_PROCESSORS% libs/filesystem/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% %THREADING% + +for: + - matrix: + only: [TEST_CMAKE: 1] + test_script: + - mkdir __build_static__ + - cd __build_static__ + - cmake ../libs/filesystem/test/test_cmake + - cmake --build . --target boost_filesystem_cmake_self_test -j %NUMBER_OF_PROCESSORS% + - cd .. + - mkdir __build_shared__ + - cd __build_shared__ + - cmake -DBUILD_SHARED_LIBS=On ../libs/filesystem/test/test_cmake + - cmake --build . --target boost_filesystem_cmake_self_test -j %NUMBER_OF_PROCESSORS% diff --git a/3rdparty/boost_filesystem/bug/Jamfile.v2 b/3rdparty/boost_filesystem/bug/Jamfile.v2 new file mode 100644 index 0000000..c6e8d6e --- /dev/null +++ b/3rdparty/boost_filesystem/bug/Jamfile.v2 @@ -0,0 +1,17 @@ +# Boost Filesystem Library Bug report Jamfile + +# Copyright Beman Dawes 2014 +# Distributed under the Boost Software License, Version 1.0. +# See www.boost.org/LICENSE_1_0.txt + +# Library home page: http://www.boost.org/libs/filesystem + +project + : requirements + /boost/filesystem//boost_filesystem + ; + +exe bug : bug.cpp : static ; + +# install in ./bin; invoke via "b2", not "b2 install" +install bin : bug ; diff --git a/3rdparty/boost_filesystem/bug/bug.cpp b/3rdparty/boost_filesystem/bug/bug.cpp new file mode 100644 index 0000000..b361731 --- /dev/null +++ b/3rdparty/boost_filesystem/bug/bug.cpp @@ -0,0 +1,19 @@ +// filesystem/bug/bug.cpp + +#include +#include + +namespace fs = boost::filesystem; + +int test_main(int, char*[]) // note name +{ + BOOST_TEST(2 + 2 == 5); // one convertible-to-bool argument + BOOST_TEST_EQ(4 + 4, 9); // two EqualityComparible arguments + BOOST_TEST(fs::exists(".")); // should pass, so nothing reported + + return ::boost::report_errors(); // required +} + +// Copyright Beman Dawes 2014 +// Distributed under the Boost Software License, Version 1.0. +// www.boost.org/LICENSE_1_0.txt diff --git a/3rdparty/boost_filesystem/bug/index.html b/3rdparty/boost_filesystem/bug/index.html new file mode 100644 index 0000000..985b9c0 --- /dev/null +++ b/3rdparty/boost_filesystem/bug/index.html @@ -0,0 +1,13 @@ + + + + + +Automatic redirection failed, please go to +../doc/issue_reporting.html. +
+

© Copyright Beman Dawes, 2014

+

Distributed under the Boost Software License, Version 1.0. +See http://www.boost.org/LICENSE_1_0.txt

+ + diff --git a/3rdparty/boost_filesystem/cmake/BoostLibraryIncludes.cmake b/3rdparty/boost_filesystem/cmake/BoostLibraryIncludes.cmake new file mode 100644 index 0000000..b875bbd --- /dev/null +++ b/3rdparty/boost_filesystem/cmake/BoostLibraryIncludes.cmake @@ -0,0 +1,37 @@ +# Copyright 2022 Andrey Semashev +# +# 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 +# +# After including this module, BOOST_LIBRARY_INCLUDES variable is set to the list of include +# directories for all Boost libraries. If the monolithic include directory is found, it is +# used instead. + +if (NOT CMAKE_VERSION VERSION_LESS 3.10) + include_guard() +endif() + +# Generates a list of include paths for all Boost libraries in \a result variable. Uses unified Boost include tree, if available. +function(generate_boost_include_paths result) + if (IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../../../boost" AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/../../../boost/version.hpp") + get_filename_component(include_dir "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) + set(${result} "${include_dir}" PARENT_SCOPE) + return() + endif() + file(GLOB path_list LIST_DIRECTORIES True "${CMAKE_CURRENT_LIST_DIR}/../../../libs/*") + foreach(path IN LISTS path_list) + if (IS_DIRECTORY "${path}/include") + get_filename_component(include_dir "${path}/include" ABSOLUTE) + list(APPEND include_list "${include_dir}") + endif() + endforeach() + set(${result} ${include_list} PARENT_SCOPE) +endfunction() + +if (NOT DEFINED BOOST_LIBRARY_INCLUDES) + generate_boost_include_paths(__BOOST_LIBRARY_INCLUDES) + # Save the paths in a global property to avoid scanning the filesystem if this module is used in multiple libraries + set(BOOST_LIBRARY_INCLUDES ${__BOOST_LIBRARY_INCLUDES} CACHE INTERNAL "List of all Boost library include paths") + unset(__BOOST_LIBRARY_INCLUDES) + # message(STATUS "Boost library includes: ${BOOST_LIBRARY_INCLUDES}") +endif() diff --git a/3rdparty/boost_filesystem/config/Jamfile.v2 b/3rdparty/boost_filesystem/config/Jamfile.v2 new file mode 100644 index 0000000..1b36276 --- /dev/null +++ b/3rdparty/boost_filesystem/config/Jamfile.v2 @@ -0,0 +1,48 @@ +# +# Copyright Andrey Semashev 2020 - 2021. +# 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) +# + +obj has_attribute_init_priority : has_attribute_init_priority.cpp : ../src ; +explicit has_attribute_init_priority ; +obj has_cxx20_atomic_ref : has_cxx20_atomic_ref.cpp : ../src ; +explicit has_cxx20_atomic_ref ; +obj has_stat_st_blksize : has_stat_st_blksize.cpp : ../src ; +explicit has_stat_st_blksize ; +obj has_stat_st_mtim : has_stat_st_mtim.cpp : ../src ; +explicit has_stat_st_mtim ; +obj has_stat_st_mtimensec : has_stat_st_mtimensec.cpp : ../src ; +explicit has_stat_st_mtimensec ; +obj has_stat_st_mtimespec : has_stat_st_mtimespec.cpp : ../src ; +explicit has_stat_st_mtimespec ; +obj has_statx : has_statx.cpp : ../src ; +explicit has_statx ; +obj has_statx_syscall : has_statx_syscall.cpp : ../src ; +explicit has_statx_syscall ; +obj has_stat_st_birthtim : has_stat_st_birthtim.cpp : ../src ; +explicit has_stat_st_birthtim ; +obj has_stat_st_birthtimensec : has_stat_st_birthtimensec.cpp : ../src ; +explicit has_stat_st_birthtimensec ; +obj has_stat_st_birthtimespec : has_stat_st_birthtimespec.cpp : ../src ; +explicit has_stat_st_birthtimespec ; +obj has_fdopendir_nofollow : has_fdopendir_nofollow.cpp : ../src ; +explicit has_fdopendir_nofollow ; +obj has_dirent_d_type : has_dirent_d_type.cpp : ../src ; +explicit has_dirent_d_type ; +obj has_posix_at_apis : has_posix_at_apis.cpp : ../src ; +explicit has_posix_at_apis ; + +lib bcrypt ; +explicit bcrypt ; + +exe has_bcrypt : has_bcrypt.cpp : ../src bcrypt ; +explicit has_bcrypt ; +obj is_windows_ce : is_windows_ce.cpp ; +explicit is_windows_ce ; + +lib has_linkflag_no_undefined : has_linkflag_no_undefined.cpp : shared "-Wl,--no-undefined" ; +explicit has_linkflag_no_undefined ; +lib has_linkflag_undefined_error : has_linkflag_no_undefined.cpp : shared "-Wl,-undefined,error" ; +explicit has_linkflag_undefined_error ; diff --git a/3rdparty/boost_filesystem/config/has_attribute_init_priority.cpp b/3rdparty/boost_filesystem/config/has_attribute_init_priority.cpp new file mode 100644 index 0000000..87d3eba --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_attribute_init_priority.cpp @@ -0,0 +1,20 @@ +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +struct global_class +{ + global_class() {} + ~global_class() {} +}; + +__attribute__ ((init_priority(32767))) +global_class g_object; + +int main() +{ + return 0; +} diff --git a/3rdparty/boost_filesystem/config/has_bcrypt.cpp b/3rdparty/boost_filesystem/config/has_bcrypt.cpp new file mode 100644 index 0000000..855d16e --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_bcrypt.cpp @@ -0,0 +1,34 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +// Include platform_config.hpp first so that windows.h is guaranteed to be not included +#include "platform_config.hpp" + +#include +#include +#if !BOOST_OS_WINDOWS && !BOOST_OS_CYGWIN +#error "This config test is for Windows only" +#endif + +#include +#include +#if !(BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 && BOOST_WINAPI_PARTITION_APP_SYSTEM) +#error "No BCrypt API" +#endif + +#include +#include +#include + +int main() +{ + unsigned char buf[16] = {}; + boost::winapi::BCRYPT_ALG_HANDLE_ handle; + boost::winapi::NTSTATUS_ status = boost::winapi::BCryptOpenAlgorithmProvider(&handle, boost::winapi::BCRYPT_RNG_ALGORITHM_, NULL, 0); + status = boost::winapi::BCryptGenRandom(handle, reinterpret_cast< boost::winapi::PUCHAR_ >(static_cast< unsigned char* >(buf)), static_cast< boost::winapi::ULONG_ >(sizeof(buf)), 0); + boost::winapi::BCryptCloseAlgorithmProvider(handle, 0); +} diff --git a/3rdparty/boost_filesystem/config/has_cxx20_atomic_ref.cpp b/3rdparty/boost_filesystem/config/has_cxx20_atomic_ref.cpp new file mode 100644 index 0000000..1fb407f --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_cxx20_atomic_ref.cpp @@ -0,0 +1,19 @@ +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include + +typedef void func_t(); + +int main() +{ + func_t* func = 0; + std::atomic_ref< func_t* > ref(func); + ref.load(std::memory_order_relaxed); + ref.store((func_t*)0, std::memory_order_relaxed); + return 0; +} diff --git a/3rdparty/boost_filesystem/config/has_dirent_d_type.cpp b/3rdparty/boost_filesystem/config/has_dirent_d_type.cpp new file mode 100644 index 0000000..d93cbfd --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_dirent_d_type.cpp @@ -0,0 +1,39 @@ +// Copyright 2023 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include + +int main() +{ + DIR* dir = opendir("."); + dirent* ent = readdir(dir); + switch (ent->d_type) + { + case DT_REG: + break; + case DT_DIR: + break; + case DT_LNK: + break; + case DT_SOCK: + break; + case DT_FIFO: + break; + case DT_BLK: + break; + case DT_CHR: + break; + case DT_UNKNOWN: + break; + default: + break; + } + return 0; +} diff --git a/3rdparty/boost_filesystem/config/has_fdopendir_nofollow.cpp b/3rdparty/boost_filesystem/config/has_fdopendir_nofollow.cpp new file mode 100644 index 0000000..009a730 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_fdopendir_nofollow.cpp @@ -0,0 +1,20 @@ +// Copyright 2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include +#include + +int main() +{ + int fd = open(".", O_DIRECTORY | O_RDONLY | O_NOFOLLOW); + DIR* dir = fdopendir(fd); + return dir != 0; +} diff --git a/3rdparty/boost_filesystem/config/has_linkflag_no_undefined.cpp b/3rdparty/boost_filesystem/config/has_linkflag_no_undefined.cpp new file mode 100644 index 0000000..ae8f940 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_linkflag_no_undefined.cpp @@ -0,0 +1,27 @@ +// Copyright 2023 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#if defined(_MSC_VER) +// MSVC's link.exe does not support -Wl,... flags, but doesn't fail the linking. +// The linker may be used by different compilers, not only MSVC. +// Luckily, those compilers all pretend to be MSVC. +#error "MSVC and compatible compilers don't support -Wl,... flags" +#endif + +#if defined(__OpenBSD__) +// On OpenBSD, shared libraries are not linked to libc, as there are multiple +// libc versions installed, and loading multiple different versions into the +// process is considered dangerous. Only the main executable is linked against +// one of them, which will be used by all shared libraries loaded into the +// process. This renders -Wl,--no-undefined unusable for shared libraries. +#error "-Wl,--no-undefined is broken for shared libraries on OpenBSD" +#endif + +int main() +{ + return 0; +} diff --git a/3rdparty/boost_filesystem/config/has_posix_at_apis.cpp b/3rdparty/boost_filesystem/config/has_posix_at_apis.cpp new file mode 100644 index 0000000..094b629 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_posix_at_apis.cpp @@ -0,0 +1,41 @@ +// Copyright 2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include + +int main() +{ + int fd1 = openat(AT_FDCWD, "foo", O_DIRECTORY | O_RDONLY); + int fd2 = openat(fd1, "bar", O_DIRECTORY | O_RDONLY); + int res = unlinkat(fd2, "zoo", 0); + res |= unlinkat(fd1, "bar", AT_REMOVEDIR); + res |= renameat(AT_FDCWD, "x", fd1, "y"); + + struct stat st; + res |= fstatat(fd1, "y", &st, AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW); + + res |= linkat(fd1, "y", fd1, "z", 0); + res |= symlinkat("foo/z", fd1, "sz"); + + char buf[128u]; + res |= readlinkat(fd1, "sz", buf, sizeof(buf)); + + res |= mkdirat(fd1, "dir", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + + res |= fchmodat(fd1, "x", S_IRUSR | S_IWUSR, 0); + + struct timespec times[2] = {}; + res |= utimensat(fd1, "x", times, AT_SYMLINK_NOFOLLOW); + + return res != 0; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_birthtim.cpp b/3rdparty/boost_filesystem/config/has_stat_st_birthtim.cpp new file mode 100644 index 0000000..3564391 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_birthtim.cpp @@ -0,0 +1,19 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_birthtim.tv_sec = 1; + st.st_birthtim.tv_nsec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_birthtimensec.cpp b/3rdparty/boost_filesystem/config/has_stat_st_birthtimensec.cpp new file mode 100644 index 0000000..0a20cc0 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_birthtimensec.cpp @@ -0,0 +1,19 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_birthtime = 1; + st.st_birthtimensec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_birthtimespec.cpp b/3rdparty/boost_filesystem/config/has_stat_st_birthtimespec.cpp new file mode 100644 index 0000000..175b293 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_birthtimespec.cpp @@ -0,0 +1,19 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_birthtimespec.tv_sec = 1; + st.st_birthtimespec.tv_nsec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_blksize.cpp b/3rdparty/boost_filesystem/config/has_stat_st_blksize.cpp new file mode 100644 index 0000000..eafed7b --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_blksize.cpp @@ -0,0 +1,18 @@ +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_blksize = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_mtim.cpp b/3rdparty/boost_filesystem/config/has_stat_st_mtim.cpp new file mode 100644 index 0000000..6d024d1 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_mtim.cpp @@ -0,0 +1,18 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_mtim.tv_nsec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_mtimensec.cpp b/3rdparty/boost_filesystem/config/has_stat_st_mtimensec.cpp new file mode 100644 index 0000000..36f6117 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_mtimensec.cpp @@ -0,0 +1,18 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_mtimensec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_stat_st_mtimespec.cpp b/3rdparty/boost_filesystem/config/has_stat_st_mtimespec.cpp new file mode 100644 index 0000000..02373f3 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_stat_st_mtimespec.cpp @@ -0,0 +1,18 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include + +int main() +{ + struct stat st; + st.st_mtimespec.tv_nsec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_statx.cpp b/3rdparty/boost_filesystem/config/has_statx.cpp new file mode 100644 index 0000000..d2ea017 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_statx.cpp @@ -0,0 +1,21 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include +#include + +int main() +{ + struct statx st; + int res = statx(AT_FDCWD, ".", AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_BTIME, &st); + st.stx_btime.tv_sec = 1; + st.stx_btime.tv_nsec = 10; +} diff --git a/3rdparty/boost_filesystem/config/has_statx_syscall.cpp b/3rdparty/boost_filesystem/config/has_statx_syscall.cpp new file mode 100644 index 0000000..571fe14 --- /dev/null +++ b/3rdparty/boost_filesystem/config/has_statx_syscall.cpp @@ -0,0 +1,35 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include + +// Note: Include other libc headers for stat() as well to ensure there is no conflict between +// Linux kernel headers and libc headers. +#include +#include +#include +#include + +#if defined(__ANDROID__) && (__ANDROID_API__ < 30) +// Even though statx syscall number is defined, it is blacklisted by seccomp in runtime until Android 11 +#error "statx syscall is not supported until Android 11" +#endif + +#if !defined(__NR_statx) +#error "No statx syscall" +#endif + +int main() +{ + struct statx st; + int res = syscall(__NR_statx, AT_FDCWD, ".", AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_BTIME, &st); + st.stx_btime.tv_sec = 1; + st.stx_btime.tv_nsec = 10; +} diff --git a/3rdparty/boost_filesystem/config/is_windows_ce.cpp b/3rdparty/boost_filesystem/config/is_windows_ce.cpp new file mode 100644 index 0000000..8681670 --- /dev/null +++ b/3rdparty/boost_filesystem/config/is_windows_ce.cpp @@ -0,0 +1,14 @@ +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#if !defined(_WIN32_WCE) +#error "This is not Windows CE" +#endif + +int main() +{ +} diff --git a/3rdparty/boost_filesystem/doc/Jamfile.v2 b/3rdparty/boost_filesystem/doc/Jamfile.v2 new file mode 100644 index 0000000..06a6151 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/Jamfile.v2 @@ -0,0 +1,23 @@ +# Boost Filesystem Library Example Jamfile + +# Copyright Beman Dawes 2010 + +# Distributed under the Boost Software License, Version 1.0. +# See www.boost.org/LICENSE_1_0.txt + +# Library home page: http://www.boost.org/libs/filesystem + +project + : requirements + /boost/filesystem//boost_filesystem + static + ; + +exe path_table : path_table.cpp ; +install path_table-copy : path_table : . ; + +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease ; +explicit boostrelease ; diff --git a/3rdparty/boost_filesystem/doc/POSIX_filename_encoding.txt b/3rdparty/boost_filesystem/doc/POSIX_filename_encoding.txt new file mode 100644 index 0000000..14c45c0 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/POSIX_filename_encoding.txt @@ -0,0 +1,55 @@ +http://www.linuxfromscratch.org/blfs/view/svn/introduction/locale-issues.html + +"The POSIX standard mandates that the filename encoding is the encoding implied by the current LC_CTYPE locale category." + +------- + +http://mail.nl.linux.org/linux-utf8/2001-02/msg00103.html + +From: Markus Kuhn + +Tom Tromey wrote on 2001-02-05 00:36 UTC: +> Kai> IMAO, a *real* filesystem should use some encoding of ISO 10646 - +> Kai> UTF-8, UTF-16, or UTF-32 are all viable options. The same should +> Kai> be true for the kernel filename interfaces. +> +> I like this, but what should I do right now? + +The POSIX kernel file system interface is engraved into stone and +extremely unlikely to change. File names are arbitrary binary strings, +with only the '/' and '\0' bytes having any special semantics. You can +use arbitrary coded character sets on it as long as they do not +introduce '/' and '\0' bytes spuriously. Writers and readers have to +somehow agree on what encoding to use and the only really practical way +is to use the same encoding on all systems that share files. Eventually, +everyone will be using UTF-8 for file names on POSIX systems. Right now, +I would recommend users to use only ASCII for filenames, as this is +already UTF-8 and therefore simplifies migration. Using the ISO 8859, +JIS, etc. filenames should soon be considered deprecated practice. + +> I work on libgcj, the runtime component of gcj, the Java front end to +> GCC. In libgcj of course we use UCS-2 everywhere, since that is what +> Java does. Currently, for Unixy systems, we assume that all file +> names are UTF-8. + +The best solution is to assume that the file names are in the +locale-specific multi-byte encoding. Simply use mbrtowc and wcrtomb to +convert between Unicode and the locale-dependent multi-byte encoding +used in file names and text files if the ISO C 99 symbol +__STDC_ISO_10646__ is defined (which guarantees that wchar_t = UCS). On +Linux, this has been the case since glibc 2.2. + +> (Actually, we do something notably worse, which is +> assume that file names are Java-style UTF-8, with the weird encoding +> for \u0000.) + +\u0000 = NUL was never a character allowed in filenames under POSIX. +Raise an exception if someone tries to use it in a filename. Problem +solved. + +I never understood, why Java found it necessary to introduce two +distinct ASCII NUL characters. + +------ + +Interesting idea. Use iconv to create shift-jis or other mbcs test cases. diff --git a/3rdparty/boost_filesystem/doc/deprecated.html b/3rdparty/boost_filesystem/doc/deprecated.html new file mode 100644 index 0000000..2b5260a --- /dev/null +++ b/3rdparty/boost_filesystem/doc/deprecated.html @@ -0,0 +1,491 @@ + + + + + + + +Filesystem Deprecated Features + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Deprecated Features +
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

Deprecated names and features

+

As the library evolves over time, names sometimes +change or old features are removed to make way for new features. To ease transition, Boost.Filesystem deprecates +the old names and features, but by default continues to provide many of them. +The deprecated names and other workarounds can be suppressed by defining macro +BOOST_FILESYSTEM_NO_DEPRECATED, and this is recommended for all new code.

+

In the table, ✔ indicates a synonym or other +workaround is provided unless +BOOST_FILESYSTEM_NO_DEPRECATED is defined.

+

Additionally, when not disabled, most of the deprecated components will generate +compilation warnings when used. These warnings are intended to highlight the library usage that +needs to be updated. For convenience during the transition period, these warnings +can be suppressed by defining BOOST_FILESYSTEM_ALLOW_DEPRECATED macro.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Component or location +

Old name, now deprecated

+ ✔ +

New name

class pathbranch_path()parent_path()
+ class path + canonize() +   + Function removed
+ class path + default_name_check() + ✔ + Function removed
+ class path + default_name_check(name_check) + ✔ + Function removed
+ class path + default_name_check_writable() + ✔ + Function removed
class pathdirectory_string()string
class pathexternal_directory_string()native()
class pathexternal_file_string()native()
class pathfile_string()string()
class pathhas_branch_path()has_parent_path()
class pathhas_leaf()has_filename()
class pathis_complete()is_absolute()
class pathleaf()filename()
+ class path + native_directory_string() + ✔ + string()
+ class path + native_file_string() + ✔ + string()
+ class path + normalize() + ✔ + Function removed
+ class path + path(const string_type& str, name_check) + ✔ + Function removed. Workaround ignores name_check + argument.
+ class path + path(const string_type::value_type* s,  name_check) + ✔ + Function removed. Workaround ignores name_check + argument.
+ class path +

remove_leaf()

+ ✔ +

remove_filename()

+ class path +

Construction, assignment and appending from container types.

+ ✔ +

Use string types or iterators as the source for path construction, assignment and appending.

+ path.hpp + template<class String, class Traits>
+  class basic_path;
+   + Class template basic_path is replaced by class path. + No workaround for an explicitly coded basic_path is provided, + but see the next row - path.
+ path.hpp + typedef basic_path<std::string, path_traits> path + ✔ + class path
+ path.hpp + typedef basic_path<std::wstring, wpath_traits> wpath + ✔ + Removed; use class path instead. Workaround provides + typedef path wpath
+ operations.hpp + initial_path() + ✔ + Function removed
+ operations.hpp +

template <class Path>
+ Path complete(const Path& p,
+ const Path& base=
+   initial_path<Path>())

+ ✔ +

path absolute(const path& p, const path& base=
+  current_path())

+ operations.hpp + is_regular(file_status f) + ✔ +

+ is_regular_file(file_status f)

+ operations.hpp + symbolic_link_exists(const path& ph) +   + Function removed
+ operations.hpp + copy_directory(const path& from, const path& to) +   + Function removed, use create_directory(const path& to, const path& from) instead (note the reversed order of arguments)
+ class directory_entry + filename() + ✔ + Function removed, use path().filename() instead.
+ class directory_entry + leaf() + ✔ + Function removed, use path().filename() instead.
+ class directory_entry + string() + ✔ + Function removed, use path().string() instead.
class recursive_directory_iteratorlevel()depth()
class recursive_directory_iteratorno_push_pending()!recursion_pending()
class recursive_directory_iteratorno_push()disable_recursion_pending()
directory.hppenum class symlink_optionRemoved; use corresponding values of enum class directory_options instead.
+ directory.hpp + wrecursive_directory_iterator typedef + ✔ + Removed; use class recursive_directory_iterator instead. Workaround provides + typedef recursive_directory_iterator wrecursive_directory_iterator
+ operations.hpp + The header provides filesystem_error, file_status, directory_entry, directory_iterator, recursive_directory_iterator and associated enums and functions. + ✔ + These components were moved to separate headers exception.hpp, file_status.hpp and directory.hpp. + The workaround is to include the new headers or filesystem.hpp. The new headers are still included by operations.hpp if + BOOST_FILESYSTEM_NO_DEPRECATED is not defined.
+ string_file.hpp + The header provides utility functions for loading and saving a string to/from file. + ✔ + The header is deprecated, use a different implementation of these functions. Unavailable if BOOST_FILESYSTEM_NO_DEPRECATED is defined and will be permanently removed in a future release.
+ path_traits.hpp + The header contains implementation details of class path. + ✔ + The header is deprecated and should not be used in user's code. Unavailable if BOOST_FILESYSTEM_NO_DEPRECATED is defined and will be permanently removed in a future release.
+ Macro definitions + BOOST_WINDOW_API +   + No longer supported; API selection is always automatic.
+ Macro definitions + BOOST_POSIX_API +   + No longer supported; API selection is always automatic.
+ Macro definitions + BOOST_WINDOW_PATH +   + No longer supported; native path format selection is always automatic.
+ Macro definitions + BOOST_POSIX_PATH +   + No longer supported; native path format selection is always automatic.
+ Build system + Auto-linking on Windows +   + No longer supported. When users are linking against static library of Boost.Filesystem, + they are recommended to explicitly add Boost.Filesystem dependencies to their linker command + line. Shared library of Boost.Filesystem is not affected by this as it is already linked with + all its dependencies.
+ +

Deprecation rationale

+

initial_path function

+

Full implementation of initial_path() would require +support from the C++ runtime startup code, and that doesn't seem likely to +happen. Depending on the user to call initial_path() at the +beginning of main() is too error prone.  An equivalent +function can trivially be provided by a user.

+ +
+ +

© Copyright Beman Dawes, 2002-2005, 2010

+

© Copyright Andrey Semashev, 2019-2021

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/design.htm b/3rdparty/boost_filesystem/doc/design.htm new file mode 100644 index 0000000..2fe1db0 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/design.htm @@ -0,0 +1,351 @@ + + + + + + + +Boost Filesystem Library Design + + + + + +

+Filesystem +Library Design

+ +

Introduction
+Requirements
+Realities
+Rationale
+Abandoned_Designs
+References

+ +

Introduction

+ +

The primary motivation for beginning work on the Filesystem Library was +frustration with Boost administrative tools.  Scripts were written in +Python, Perl, Bash, and Windows command languages.  There was no single +scripting language familiar and acceptable to all Boost administrators. Yet they +were all skilled C++ programmers - why couldn't C++ be used as the scripting +language?

+ +

The key feature C++ lacked for script-like applications was the ability to +perform portable filesystem operations on directories and their contents. The +Filesystem Library was developed to fill that void.

+ +

The intent is not to compete with traditional scripting languages, but to +provide a solution for situations where C++ is already the language +of choice..

+ +

Requirements

+
    +
  • Be able to write portable script-style filesystem operations in modern + C++.
    +
    + Rationale: This is a common programming need. It is both an + embarrassment and a hardship that this is not possible with either the current + C++ or Boost libraries.  The need is particularly acute + when C++ is the only toolset allowed in the tool chain.  File system + operations are provided by many languages used on multiple platforms, + such as Perl and Python, as well as by many platform specific scripting + languages. All operating systems provide some form of API for filesystem + operations, and the POSIX bindings are increasingly available even on + operating systems not normally associated with POSIX, such as the Mac, z/OS, + or OS/390.
  • +
  • Work within the realities described below.
    +
    + Rationale: This isn't a research project. The need is for something that works on + today's platforms, including some of the embedded operating systems + with limited file systems. Because of the emphasis on portability, such a + library would be much more useful if standardized. That means being able to + work with a much wider range of platforms that just Unix or Windows and their + clones.
  • +
  • Avoid dangerous programming practices. Particularly, all-too-easy-to-ignore error notifications + and use of global variables. If a dangerous feature is provided, identify it as such.
    +
    + Rationale: Normally this would be covered by "the usual Boost requirements...", + but it is mentioned explicitly because the equivalent native platform and + scripting language interfaces often depend on all-too-easy-to-ignore error + notifications and global variables like "current + working directory".
  • +
  • Structure the library so that it is still useful even if some functionality + does not map well onto a given platform or directory tree. Particularly, much + useful functionality should be portable even to flat +(non-hierarchical) filesystems.
    +
    + Rationale: Much functionality which does not + require a hierarchical directory structure is still useful on flat-structure + filesystems.  There are many systems, particularly embedded systems, + where even very limited functionality is still useful.
  • +
+
    +
  • Interface smoothly with current C++ Standard Library input/output + facilities.  For example, paths should be + easy to use in std::basic_fstream constructors.
    +
    + Rationale: One of the most common uses of file system functionality is to + manipulate paths for eventual use in input/output operations.  + Thus the need to interface smoothly with standard library I/O.
  • +
  • Suitable for eventual standardization. The implication of this requirement + is that the interface be close to minimal, and that great care be take + regarding portability.
    +
    + Rationale: The lack of file system operations is a serious hole + in the current standard, with no other known candidates to fill that hole. + Libraries with elaborate interfaces and difficult to port specifications are much less likely to be accepted for + standardization.
  • +
  • The usual Boost requirements and + guidelines apply.
  • +
  • Encourage, but do not require, portability in path names.
    +
    + Rationale: For paths which originate from user input it is unreasonable to + require portable path syntax.
  • +
  • Avoid giving the illusion of portability where portability in fact does not + exist.
    +
    + Rationale: Leaving important behavior unspecified or "implementation defined" does a + great disservice to programmers using a library because it makes it appear + that code relying on the behavior is portable, when in fact there is nothing + portable about it. The only case where such under-specification is acceptable is when both users and implementors know from + other sources exactly what behavior is required, yet for some reason it isn't + possible to specify it exactly.
  • +
+

Realities

+
    +
  • Some operating systems have a single directory tree root, others have + multiple roots.
  • +
  • Some file systems provide both a long and short form of filenames.
  • +
  • Some file systems have different syntax for file paths and directory + paths.
  • +
  • Some file systems have different rules for valid file names and valid + directory names.
  • +
  • Some file systems (ISO-9660, level 1, for example) use very restricted + (so-called 8.3) file names.
  • +
  • Some operating systems allow file systems with different + characteristics to be "mounted" within a directory tree.  Thus an + ISO-9660 or Windows + file system may end up as a sub-tree of a POSIX directory tree.
  • +
  • Wide-character versions of directory and file operations are available on some operating + systems, and not available on others.
  • +
  • There is no law that says directory hierarchies have to be specified in + terms of left-to-right decent from the root.
  • +
  • Some file systems have a concept of file "version number" or "generation + number".  Some don't.
  • +
  • Not all operating systems use single character separators in path names.  Some use + paired notations. A typical fully-specified OpenVMS filename + might look something like this:
    +
    +    DISK$SCRATCH:[GEORGE.PROJECT1.DAT]BIG_DATA_FILE.NTP;5
    +

    + The general OpenVMS format is:
    +
    +     + Device:[directories.dot.separated]filename.extension;version_number
  • +
  • For common file systems, determining if two descriptors are for same + entity is extremely difficult or impossible.  For example, the concept of + equality can be different for each portion of a path - some portions may be + case or locale sensitive, others not. Case sensitivity is a property of the + pathname itself, and not the platform. Determining collating sequence is even + worse.
  • +
  • Race-conditions may occur. Directory trees, directories, files, and file attributes are in effect shared between all threads, processes, and computers which have access to the + filesystem.  That may well include computers on the other side of the + world or in orbit around the world. This implies that file system operations + may fail in unexpected ways. For example:
    +
    +      assert( exists("foo") == exists("foo") ); + // may fail!
    +     assert( is_directory("foo") == is_directory("foo"); + // may fail!
    +

    + In the first example, the file may have been deleted between calls to + exists().  In the second example, the file may have been deleted and then + replaced by a directory of the same name between the calls to is_directory().
  • +
  • Even though an application may be portable, it still will have to traffic + in system specific paths occasionally; user provided input is a common + example.
  • +
  • Symbolic links cause canonical and + normal form of some paths to represent different files or directories. For + example, given the directory hierarchy /a/b/c, with a symbolic + link in /a named x  pointing to b/c, + then under POSIX Pathname Resolution rules a path of "/a/x/.." + should resolve to "/a/b". If "/a/x/.." were first + normalized to "/a", it would resolve incorrectly. (Case supplied + by Walter Landry.)
  • +
+ +

Rationale

+ +

The Requirements and +Realities above drove much of the C++ interface design.  In particular, +the desire to make script-like code straightforward caused a great deal of +effort to go into ensuring that apparently simple expressions like exists( "foo" +) work as expected.

+ +

See the FAQ for the rationale behind many detailed +design decisions.

+ +

Several key insights went into the path class design:

+
    +
  • Decoupling of the input formats, internal conceptual (vector<string> + or other sequence) + model, and output formats.
  • +
  • Providing two input formats (generic and O/S specific) broke a major + design deadlock.
  • +
  • Providing several output formats solved another set of previously + intractable problems.
  • +
  • Several non-obvious functions (particularly decomposition and composition) + are required to support portable code. (Peter Dimov, Thomas Witt, Glen + Knowles, others.)
  • +
+ +

Error checking was a particularly difficult area. One key insight was that +with file and directory names, portability isn't a universal truth.  +Rather, the programmer must think out the question "What operating systems do I +want this path to be portable to?"  By providing support for several +answers to that question, the Filesystem Library alerts programmers of the need +to ask it in the first place.

+

Abandoned Designs

+

operations.hpp

+

Dietmar Kühl's original directory_iterator design and implementation supported +wide-character file and directory names. It was abandoned after extensive +discussions among Library Working Group members failed to identify portable +semantics for wide-character names on systems not providing native support. See +FAQ.

+

Previous iterations of the interface design used explicitly named functions providing a +large number of convenience operations, with no compile-time or run-time +options. There were so many function names that they were very confusing to use, +and the interface was much larger. Any benefits seemed theoretical rather than +real.

+

Designs based on compile time (rather than runtime) flag and option selection +(via policy, enum, or int template parameters) became so complicated that they +were abandoned, often after investing quite a bit of time and effort. The need +to qualify attribute or option names with namespaces, even aliases, made use in +template parameters ugly; that wasn't fully appreciated until actually writing +real code.

+

Yet another set of convenience functions ( for example, remove with +permissive, prune, recurse, and other options, plus predicate, and possibly +other, filtering features) were abandoned because the details became both +complex and contentious.

+ +

What is left is a toolkit of low-level operations from which the user can +create more complex convenience operations, plus a very small number of +convenience functions which were found to be useful enough to justify inclusion.

+ +

path.hpp

+ +

There were so many abandoned path designs, I've lost track. Policy-based +class templates in several flavors, constructor supplied runtime policies, +operation specific runtime policies, they were all considered, often +implemented, and ultimately abandoned as far too complicated for any small +benefits observed.

+ +

Additional design considerations apply to Internationalization.

+ +

error checking

+ +

A number of designs for the error checking machinery were abandoned, some +after experiments with implementations. Totally automatic error checking was +attempted in particular. But automatic error checking tended to make the overall +library design much more complicated.

+ +

Some designs associated error checking mechanisms with paths.  Some with +operations functions.  A policy-based error checking template design was +partially implemented, then abandoned as too complicated for everyday +script-like programs.

+ +

The final design, which depends partially on explicit error checking function +calls,  is much simpler and straightforward, although it does depend to +some extent on programmer discipline.  But it should allow programmers who +are concerned about portability to be reasonably sure that their programs will +work correctly on their choice of target systems.

+ +

References

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
[IBM-01]IBM Corporation, z/OS V1R3.0 C/C++ Run-Time +Library Reference, SA22-7821-02, 2001, + + www-1.ibm.com/servers/eserver/zseries/zos/bkserv/
[ISO-9660]International Standards Organization, 1988
[Kuhn]UTF-8 and Unicode FAQ for Unix/Linux, + + www.cl.cam.ac.uk/~mgk25/unicode.html
[MSDN] Microsoft Platform SDK for Windows, Storage Start +Page, + + msdn.microsoft.com/library/en-us/fileio/base/storage_start_page.asp
[POSIX-01]IEEE Std 1003.1-2001, ISO/IEC 9945:2002, and The Open Group Base Specifications, Issue 6. Also known as The + Single UNIX® Specification, Version 3. + Available from each of the organizations involved in its creation. For + example, read online or download from + + www.unix.org/single_unix_specification/. The ISO JTC1/SC22/WG15 - POSIX +homepage is + www.open-std.org/jtc1/sc22/WG15/
[URI]RFC-2396, Uniform Resource Identifiers (URI): Generic +Syntax, + www.ietf.org/rfc/rfc2396.txt
[UTF-16]Wikipedia, UTF-16, + + en.wikipedia.org/wiki/UTF-16
[Wulf-Shaw-73]William Wulf, Mary Shaw, Global +Variable Considered Harmful, ACM SIGPLAN Notices, 8, 2, 1973, pp. 23-34
+ +
+ +

© Copyright Beman Dawes, 2002

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt)

+ + + + diff --git a/3rdparty/boost_filesystem/doc/do_list.html b/3rdparty/boost_filesystem/doc/do_list.html new file mode 100644 index 0000000..6f4d4f4 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/do_list.html @@ -0,0 +1,146 @@ + + + + + + + +Do List + + + + + +

Boost Filesystem Do List
+24 June 2010

+ +

Beta 1 comments

+
    +
  • + +

    Zach Laine:

  • +
+
+
The descriptions for portable_name() and portable_directory_name()
+appear to be at odds.
+
+portable_name() : ... && (name is "." or "..", and the first character
+not a period or hyphen)
+
+portable_directory_name(): ... && (name is "." or ".."  or contains no periods)
+
+Should portable_name() be "... && (name is "." or "..", or contains no
+periods) && (first character not a hyphen)"?  Maybe I'm missing
+something?
+
+
    +
  • +

    Scott McMurray - treat as Wish List:

  • +
+
+
- uncomplete(p, base)
+
+My pet request.  It may be useful to simplify other functions as well,
+since there's no current way to go from an absolute path to a relative
+one, meaning that most functions need to handle relative ones even
+when that might not be natural.  With this functionality,
+preconditions requiring absolute paths would be less onerous.
+
+   Precondition: p.is_absolute() && base.is_absolute()
+
+   Effects: Extracts a path, rp, from p relative to base such that
+canonical(p) == complete(rp, base).  Any ".." path elements in rp form
+a prefix.
+
+   Returns: The extracted path.
+
+   Postconditions: For the returned path, rp, rp.is_relative() ==
+(p.root_name() == b.root_name()).
+
+[Notes: This function simplifies paths by omitting context.  It is
+particularly useful for serializing paths such that it can be usefully
+moved between hosts where the context may be different, such as inside
+source control trees.  It can also be helpful for display to users,
+such as in shells where paths are often shown relative to $HOME.
+
+In the presence of symlinks, the result of this function may differ
+between implementations, as some may expand symlinks that others may
+not.  The simplest implementation uses canonical to expand both p and
+base, then removes the common prefix and prepends the requisite ".."
+elements.  Smarter implementations will avoid expanding symlinks
+unnecessarily.  No implementation is expected to discover new symlinks
+to return paths with fewer elements.]
+
+

Docs

+
    +
  • Reorganize files - delete examples that no longer apply.
  • +
  • Should minimal.css be changed to used relative font sizes? See + http://www.w3schools.com/CSS/pr_font_font-size.asp\
  • +
  • Document behavior of path::replace_extension has change WRT argument w/o a + dot.
  • +
  • Document leading //: no longer treated specially. + But is that really correct?
  • +
  • Behavior of root_path() has been changed. Change + needs to be propagated to trunk?
  • +
  • Regenerate path decomposition table.
  • +
+ +

Code

+

All

+
    +
  • Move semantics.
  • +
  • Use BOOST_DELETED, BOOST_DEFAULTED, where + appropriate.
  • +
  • Other C++0x features.
  • +
+

Class path

+
    +
  • Windows, POSIX, conversions for char16_t, char32_t for C++0x compilers.
  • +
  • Add Windows Alternate Data Stream test cases. See http://en.wikipedia.org/wiki/NTFS + Features.
  • +
  • Add test case: relational operators on paths differing only in trailing + separator. Rationale?
  • +
  • Provide the name check functions for more character types? Templatize? + take a path argument?
  • +
  • Add codepage 936/950/etc test cases.
  • +
  • Should UDT's be supported?
  • +
  • Should path iteration to a separator result in:
    + -- the actual separator used
    + -- the preferred separator
    + -- the generic separator <-- makes it easier to write portable code
    + -- a dot
  • +
+

Operations

+
    +
  • Would complete(), system_complete() be clearer if renamed absolute(), + absolute_system() (or absolute_native())?
  • +
  • Review all operations.cpp code for race conditions similar to #2925. Fix + or document.
  • +
  • Enable all BOOST_FILESYSTEM_NO_DEPRECATED code.
  • +
  • rename and remove names are problems. If users says "using + namespace boost::filesystem"
    + and some header included stdio, there is just too much chance of silent error.
  • +
  • create_directories error handling needs work.
  • +
  • Fold convenience.hpp into operations.hpp
  • +
  • Two argument recursive_directory_iterator ctor isn't recognizing throws(). + Would it be better to fold into a single two argument ctor with default?
  • +
  • Add the push_directory class from tools/release/required_files.cpp
  • +
+ +

Miscellaneous

+
    +
  • Regular classes need hash functions.
  • +
+ +
+

© Copyright Beman Dawes, 2010

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/faq.htm b/3rdparty/boost_filesystem/doc/faq.htm new file mode 100644 index 0000000..1f38392 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/faq.htm @@ -0,0 +1,148 @@ + + + + + + + +Filesystem FAQ + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem FAQ +
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

+Frequently Asked Questions

+

General questions

+

Why not support a concept of specific kinds of file systems, such as posix_file_system or windows_file_system.

+

Portability is one of the most important requirements for the +library. Features specific to a particular operating system or file system +can always be accessed by using the operating system's API.

+ +

+Class path questions

+

Why base the generic pathname format on POSIX?

+

POSIX is an ISO Standard. It is the basis for the most familiar +pathname formats, +not just for POSIX-based operating systems but also for Windows and the +URL portion of URI's. It is ubiquitous and +familiar.  On many systems, it is very easy to implement because it is +either the native operating system format (Unix and Windows) or via an +operating system supplied +POSIX library (z/OS, OS/390, and many more.)

+

Why not use a full URI (Universal Resource Identifier) based path?

+

URI's would promise more than the Filesystem Library can actually deliver, +since URI's extend far beyond what most operating systems consider a file or a +directory.  Thus for the primary "portable script-style file system +operations" requirement of the Filesystem Library, full URI's appear to be over-specification.

+

Why isn't path a base class with derived directory_path and +file_path classes?

+

Why bother?  The behavior of all three classes is essentially identical. +Several early versions did require users to identify each path as a file or +directory path, and this seemed to increase coding errors and decrease code +readability. There was no apparent upside benefit.

+

Why do path decomposition functions yielding a single element return a +path rather than a string?

+

Interface simplicity. If they returned strings, flavors would be needed for +different string and character types.

+

Why don't path member functions have overloads with error_code& arguments?

+

They have not been requested by users; the need for error reporting via +error_code seems limited to operations failures rather than path failures.

+

Operations function questions

+

Why not supply a 'handle' type, and let the file and directory operations +traffic in it?

+

It isn't clear there is any feasible way to meet the "portable script-style +file system operations" requirement with such a system. File systems exist where operations are usually performed on + some non-string handle type. The classic Mac OS has been mentioned explicitly as a case where +trafficking in paths isn't always natural.   

+

The case for the "handle" (opaque data type to identify a file) +style may be strongest for directory iterator value type.  (See Jesse Jones' Jan 28, +2002, Boost postings). However, as class path has evolved, it seems sufficient +even as the directory iterator value type.

+

Why are the operations functions so low-level?

+

To provide a toolkit from which higher-level functionality can be created.

+

An +extended attempt to add convenience functions on top of, or as a replacement +for, the low-level functionality failed because there is no widely acceptable +set of simple semantics for most convenience functions considered.  +Attempts to provide alternate semantics via either run-time options or +compile-time polices became overly complicated in relation to the value +delivered, or became contentious.  OTOH, the specific functionality needed for several trial +applications was very easy for the user to construct from the lower-level +toolkit functions.  See Failed +Attempts.

+

Isn't it inconsistent then to provide a few convenience functions?

+

Yes, but experience with both this library, POSIX, and Windows, indicates +the utility of certain convenience functions, and that it is possible to provide +simple, yet widely acceptable, semantics for them. For example, remove_all().

+

Why are there directory_iterator overloads for operations.hpp +predicate functions? Isn't two ways to do the same thing poor design?

+

Yes, two ways to do the same thing is often a poor design practice. But the +iterator versions are often much more efficient. Calling status() during +iteration over a directory containing 15,000 files took 6 seconds for the path +overload, and 1 second for the iterator overload, for tests on a freshly booted +machine. Times were .90 seconds and .30 seconds, for tests after prior use of +the directory. This performance gain is large enough to justify deviating from +preferred design practices. Neither overload alone meets all needs.

+

Why are the operations functions so picky about errors?

+

Safety. The default is to be safe rather than sorry. This is particularly +important given the reality that on many computer systems files and directories +are globally shared resources, and thus subject to +race conditions.

+

Why are attributes accessed via named functions rather than property maps?

+

For commonly used attributes (existence, directory or file, emptiness), +simple syntax and guaranteed presence outweigh other considerations. Because +access to many other attributes is inherently system dependent, +property maps are viewed as the best hope for access and modification, but it is +better design to provide such functionality in a separate library. (Historical +note: even the apparently simple attribute "read-only" turned out to be so +system depend as to be disqualified as a "guaranteed presence" operation.)

+

Why isn't automatic name portability error detection provided?

+

A number (at least six) of designs for name validity error +detection were evaluated, including at least four complete implementations.  +While the details for rejection differed, all of the more powerful name validity checking +designs distorted other +otherwise simple aspects of the library. Even the simple name checking provided +in prior library versions was a constant source of user complaints. While name checking can be helpful, it +isn't important enough to justify added a lot of additional complexity.

+

Why are paths sometimes manipulated by member functions and sometimes by +non-member functions?

+

The design rule is that purely lexical operations are supplied as class +path member +functions, while operations performed by the operating system are provided as +free functions.

+
+

© Copyright Beman Dawes, 2002

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + diff --git a/3rdparty/boost_filesystem/doc/index.htm b/3rdparty/boost_filesystem/doc/index.htm new file mode 100644 index 0000000..114eabe --- /dev/null +++ b/3rdparty/boost_filesystem/doc/index.htm @@ -0,0 +1,498 @@ + + + + + + + +Filesystem Home + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Library
+ Version 4
+
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports   +
+

+ + + + + + + +
+ Contents
+ Introduction
+ Documentation
+ Using the library
+ Coding guidelines
+ Cautions
+ Headers
+ Example programs
+ Implementation
+ Macros
+ Building the object-library
+ Notes for Cygwin users
+ Version history
+  with acknowledgements
+

+

Introduction

+

The Boost.Filesystem library provides facilities to manipulate files and directories, +and the paths that identify them.

+ +

The features of the library include:

+ +
    +
  • A modern C++ interface, highly compatible with the C++ standard + library.
  • +
+
+
+ +

Many users say the interface is their primary motivation for using +Boost.Filesystem. They like its use of familiar idioms based on standard library +containers, iterators, and algorithms. They like having errors reported by +throwing exceptions.

+ +
+
+
    +
  • Portability between operating systems.
      +
    • At the C++ syntax level, it is convenient to learn and use one interface + regardless of the operating system.
    • +
    • At the semantic level, behavior of code is reasonably portable across + operating systems.
    • +
    • Dual generic or native path format support encourages program + portability, yet still allows communication with users in system specific + formats.
    • +
    +
  • +
  • Error handling and reporting via C++ exceptions (the default) or error + codes.
      +
    • C++ exceptions are the preferred error reporting mechanism for most + applications. The exception thrown includes the detailed error code + information important for diagnosing the exact cause of file system errors.
    • +
    • Error reporting via error code allows user code that provides detailed + error recovery to avoid becoming so littered with try-catch blocks as to be + unmaintainable.
    • +
    +
  • +
  • Suitable for a broad spectrum of applications, ranging from simple + script-like operations to extremely complex production code.
      +
    • At the simple script-like end of the spectrum, the intent is not to + compete with Python, Perl, or shell languages, but rather to provide + filesystem operations when C++ is already the language of choice.
    • +
    • +

      Finer grained control over operations and error handling is available to + support more complex applications or other cases where throwing exceptions + isn't desired.

    • +
    +
  • +
  • +

    Forms the basis for + + ISO/IEC TS 18822, the C++ standard library Filesystem Technical + Specification.

  • +
+ +

Documentation

+ +

Tutorial - A gentle introduction to +the library, with example programs provided for you to experiment with.

+ +

Reference - Formal documentation in the +style of the C++ standard for +every component of the library.

+ +

FAQ - Frequently asked questions.

+ +

Portability Guide - Help for those +concerned with writing code to run on multiple operating systems.

+ +

Deprecated Features - Identifies +deprecated features and their replacements.

+ +

Version 4 Description - Summary of changes from +Version 3.

+ +

Version 3 Introduction - Aimed at users of prior +Boost.Filesystem versions.

+ +

Version 3 Design - Historical document +from the start of the Version 3 design process.

+ +

Original Design - Historical document from +the start of the Version 1 design process.

+ +

Do List - Boost.Filesystem development work +in the pipeline.

+ +

Using the library

+

Boost.Filesystem is implemented as a separately compiled library, so you must install +binaries in a location that can be found by your linker. If you followed the +Boost Getting Started instructions, that's already been done for you.

+

Coding guidelines

+

For new code, defining BOOST_FILESYSTEM_NO_DEPRECATED before +including filesystem headers is strongly recommended. This prevents inadvertent +use of old features, particularly legacy function names, that have been replaced +and are going to go away in the future.

+

Cautions

+

After reading the tutorial you can dive right into simple, +script-like programs using the Filesystem Library! Before doing any serious +work, however, there a few cautions to be aware of:

+

Effects and Postconditions not guaranteed in the presence of race-conditions

+

Filesystem function specifications follow the C++ Standard Library form, specifying behavior in terms of +effects and postconditions. If +a race-condition exists, a function's +postconditions may no longer be true by the time the function returns to the +caller.

+
+

Explanation: The state of files and directories is often +globally shared, and thus may be changed unexpectedly by other threads, +processes, or even other computers having network access to the filesystem. As an +example of the difficulties this can cause, note that the following asserts +may fail:

+
+

assert( exists( "foo" ) == exists( "foo" ) );  // +(1)
+
+remove_all( "foo" );
+assert( !exists( "foo" ) );  // (2)
+
+assert( is_directory( "foo" ) == is_directory( "foo" ) ); // +(3)

+
+

(1) will fail if a non-existent "foo" comes into existence, or an +existent "foo" is removed, between the first and second call to exists(). +This could happen if, during the execution of the example code, another thread, +process, or computer is also performing operations in the same directory.

+

(2) will fail if between the call to remove_all() and the call to +exists() a new file or directory named "foo" is created by another +thread, process, or computer.

+

(3) will fail if another thread, process, or computer removes an +existing file "foo" and then creates a directory named "foo", between the +example code's two calls to is_directory().

+
+

Exceptions

+

Unless otherwise specified, Boost.Filesystem functions throw +basic_filesystem_error +exceptions to report failures such as I/O errors. Implementations may also use C++ Standard Library functions +which can throw std::bad_alloc exceptions to report memory allocation +errors. These exceptions may be thrown even +though the error condition leading to the exception is not explicitly specified +in the function's "Throws" paragraph.

+

Nominally non-throwing versions are provided for +operational functions that +access the external file system, since these are often used +in contexts where error codes may be the preferred way to report an error. Even +the nominally non-throwing versions of functions will throw std::bad_alloc +exceptions to report memory allocation errors. However, functions marked +noexcept never throw exceptions.

+ +

Headers

+ +

The Boost.Filesystem library provides several headers:

+ +
    +
  • Header <boost/filesystem.hpp> + provides access to all features of the library, except file streams.
  • +
  • Header <boost/filesystem/fstream.hpp> + inherits the same components as the C++ Standard + Library's fstream header, but files are identified by const path& + arguments rather that const char* arguments.
  • +
+ +

Example programs

+

See the tutorial for example programs.

+

Implementation

+

The current implementation supports operating systems which provide +the POSIX or Windows API's.

+

The library is in regular use on Apple OS X, HP-UX, IBM AIX, Linux, +Microsoft Windows, SGI IRIX, and Sun Solaris operating systems using a variety +of compilers. It is also used by several smart phone operating systems.

+ +

Macros

+

Users may define the following macros if desired. Sensible defaults are +provided, so users can ignore these macros unless they have special needs.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Macro NameDefaultEffect if defined
BOOST_FILESYSTEM_VERSION3Selects the Boost.Filesystem library version. Can have values of 3 or 4. + Defining to 4 also implies BOOST_FILESYSTEM_NO_DEPRECATED.
BOOST_FILESYSTEM_NO_DEPRECATEDNot defined.Deprecated features are excluded from headers.
BOOST_FILESYSTEM_DYN_LINKDefined if BOOST_ALL_DYN_LINK is defined, + otherwise not defined.The Boost.Filesystem library is dynamically linked. If not defined, + static linking is assumed.
BOOST_FILESYSTEM_NO_LIBDefined if BOOST_ALL_NO_LIB is defined, + otherwise not defined.Boost.Filesystem library does not use the Boost auto-link + facility.
BOOST_FILESYSTEM_DISABLE_SENDFILENot defined. sendfile API presence detected at library build time.Boost.Filesystem library does not use the sendfile system call on Linux. The sendfile system call started accepting regular file descriptors as the target in Linux 2.6.33.
BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGENot defined. copy_file_range API presence detected at library build time.Boost.Filesystem library does not use the copy_file_range system call on Linux. The copy_file_range system call was introduced in Linux kernel 4.5 and started operating across filesystems in 5.3.
BOOST_FILESYSTEM_DISABLE_STATXNot defined. statx presence detected at library build time.Boost.Filesystem library does not use the statx system call on Linux. The statx system call was introduced in Linux kernel 4.11.
BOOST_FILESYSTEM_DISABLE_GETRANDOMNot defined. getrandom API presence detected at library build time.Boost.Filesystem library does not use the getrandom system call on Linux. The getrandom system call was introduced in Linux kernel 3.17.
BOOST_FILESYSTEM_DISABLE_ARC4RANDOMNot defined. arc4random API presence detected at library build time.Boost.Filesystem library does not use the arc4random_buf system call on BSD systems. The arc4random API was introduced in OpenBSD 2.1 and FreeBSD 8.0.
BOOST_FILESYSTEM_DISABLE_BCRYPTNot defined. BCrypt API presence detected at library build time.Boost.Filesystem library does not use the BCrypt API on Windows. Has no effect on other platforms.
+

User-defined BOOST_POSIX_API and BOOST_WINDOWS_API macros are no longer +supported.

+

Building the object-library

+

The object-library will be built automatically if you are using the Boost +build system. See +Getting Started. It can also be +built manually using a Jamfile +supplied in directory libs/filesystem/build, or the user can construct an IDE +project or make file which includes the object-library source files.

+

The object-library source files are +supplied in the src directory. These source files implement the +library for POSIX or Windows compatible operating systems; no implementation is +supplied for other operating systems. Note that many operating systems not +normally thought of as POSIX systems, such as mainframe legacy +operating systems or embedded operating systems, support POSIX compatible file +systems and so will work with the Filesystem Library.

+

The object-library can be built for static or dynamic (shared/dll) linking. +This is controlled by the BOOST_ALL_DYN_LINK or BOOST_FILESYSTEM_DYN_LINK +macros. See the Separate +Compilation page for a description of the techniques used.

+

Note for Cygwin users

+

Cygwin version 1.7 or later is +required because only versions of GCC with wide character strings are supported.

+ +

The library's implementation code treats Cygwin as a Windows platform, and +thus uses the Windows API and uses Windows path syntax as the native path +syntax.

+ +

Version history

+ +

Version 4

+ +

Under development - Improve compatibility with std::filesystem introduced in C++17 +(original proposal: ISO +C++ File System Technical Specification). The Filesystem TS was based on +Boost.Filesystem Version 3, with only a small number of changes. Most user code +written for Version 3 should work unchanged with Version 4. The differences can be seen in a +separate section.

+ +

Version 3

+ +

Boost 1.44.0 - June, 2010 - Internationalization via single class path. +More uniform error handling.

+ +

Peter Dimov suggested use of a single path class rather than a basic_path +class template. That idea was the basis for the Version 3 redesign.

+ +

Thanks for comments from Robert Stewart, Zach Laine, Peter Dimov, Gregory +Peele, Scott McMurray, John Bytheway, Jeff Flinn, Jeffery Bosboom.

+ +

Version 2

+ +

Boost 1.34.0 - May, 2007 - Internationalization via basic_path +template.

+ +

So many people have contributed comments and bug reports that it isn't any +longer possible to acknowledge them individually. That said, Peter Dimov and Rob +Stewart need to be specially thanked for their many constructive criticisms and +suggestions. Terence +Wilson and Chris Frey contributed timing programs which helped illuminate +performance issues.

+ +

Version 1

+ +

Boost 1.30.0 - March, 2003 - Initial official Boost release.

+ +

The Filesystem Library was designed and implemented by Beman Dawes. The +original directory_iterator and filesystem_error classes were +based on prior work from Dietmar Kühl, as modified by Jan Langer. Thomas Witt +was a particular help in later stages of initial development. Peter Dimov and +Rob Stewart made many useful suggestions and comments over a long period of +time. Howard Hinnant helped with internationalization issues.

+ +

Key design requirements and +design realities were developed during +extensive discussions on the Boost mailing list, followed by comments on the +initial implementation. Numerous helpful comments were then received during the +Formal Review.

Participants included +Aaron Brashears, +Alan Bellingham, +Aleksey Gurtovoy, +Alex Rosenberg, +Alisdair Meredith, +Andy Glew, +Anthony Williams, +Baptiste Lepilleur, +Beman Dawes, +Bill Kempf, +Bill Seymour, +Carl Daniel, +Chris Little, +Chuck Allison, +Craig Henderson, +Dan Nuffer, +Dan'l Miller, +Daniel Frey, +Darin Adler, +David Abrahams, +David Held, +Davlet Panech, +Dietmar Kühl, +Douglas Gregor, +Dylan Nicholson, +Ed Brey, +Eric Jensen, +Eric Woodruff, +Fedder Skovgaard, +Gary Powell, +Gennaro Prota, +Geoff Leyland, +George Heintzelman, +Giovanni Bajo, +Glen Knowles, +Hillel Sims, +Howard Hinnant, +Jaap Suter, +James Dennett, +Jan Langer, +Jani Kajala, +Jason Stewart, +Jeff Garland, +Jens Maurer, +Jesse Jones, +Jim Hyslop, +Joel de Guzman, +Joel Young, +John Levon, +John Maddock, +John Williston, +Jonathan Caves, +Jonathan Biggar, +Jurko, +Justus Schwartz, +Keith Burton, +Ken Hagen, +Kostya Altukhov, +Mark Rodgers, +Martin Schuerch, +Matt Austern, +Matthias Troyer, +Mattias Flodin, +Michiel Salters, +Mickael Pointier, +Misha Bergal, +Neal Becker, +Noel Yap, +Parksie, +Patrick Hartling, Pavel Vozenilek, +Pete Becker, +Peter Dimov, +Rainer Deyke, +Rene Rivera, +Rob Lievaart, +Rob Stewart, +Ron Garcia, +Ross Smith, +Sashan, +Steve Robbins, +Thomas Witt, +Tom Harris, +Toon Knapen, +Victor Wagner, +Vincent Finn, +Vladimir Prus, and +Yitzhak Sapir + +

A lengthy discussion on the C++ committee's library reflector illuminated the "illusion +of portability" problem, particularly in postings by PJ Plauger and Pete Becker.

+ +

Walter Landry provided much help illuminating symbolic link use cases for +version 1.31.0. 

+ +
+ +

© Copyright Beman Dawes, 2002-2005

+

© Copyright Andrey Semashev, 2021

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/issue_reporting.html b/3rdparty/boost_filesystem/doc/issue_reporting.html new file mode 100644 index 0000000..818337b --- /dev/null +++ b/3rdparty/boost_filesystem/doc/issue_reporting.html @@ -0,0 +1,222 @@ + + + + + + +Filesystem issue reporting + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Bug Reporting +
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

Boost.Filesystem issues such as bug reports or feature requests should be +reported via a GitHub ticket.

+

GitHub pull requests +are encouraged, too, although anything beyond really trivial fixes needs a +ticket.

+

Bug reports

+

A timely response to your bug report is much more likely if the problem can +be immediately reproduced without guesswork and regression tests can be easily +created.

+

You need to provide the following:

+
    +
  1. A simple test program +that:
      +
    • Illustrates the problem, and
    • +
    • Automatically yields an unambiguous pass or fail result - returning zero + for pass and non-zero for fail is preferred, and
    • +
    • Can be used as the basis for adding tests to Boost.Filesystem's + regression test suite.
    • +
    +
  2. +
  3. The compiler, standard library, platform, and Boost version you + used to build and run your test program.
  4. +
  5. A description of how to build and run the test program. +
  6. +
  7. A copy of the output from the test + program, if any.
  8. +
  9. An email address for follow-up questions.
  10. +
+

See Rationale to find out why the above is needed.

+

For a mostly automatic framework to provide the above, read on!

+

Bug reporting framework

+

The directory <boost-root>/libs/filesystem/bug> provides a bug test program (bug.cpp) +and a build file (Jamfile.v2). Here is what you need to do:

+
    +
  1. Add one or more test cases to bug.cpp + using any text or program editor.
  2. +
  3. Build and test.
  4. +
  5. Attach copies of the Test output and test + program to the Trac + ticket.
  6. +
+

That's it! When you complete those steps, you will be done!

+

The test output supplies all of the basic information about the compiler, std +library, platform, Boost version, and command line, and the test cases you have +added should make it easy for the library maintainer to reproduce the problem.

+

Using the framework

+

bug.cpp

+

Here is bug.cpp as supplied. To report a real bug, use +BOOST_TEST and BOOST_TEST_EQ macros to build your own +test cases. You can delete the three tests already in bug.cpp:

+
+
#include <boost/detail/lightweight_test_report.hpp>
+#include <boost/filesystem.hpp>
+
+namespace fs = boost::filesystem;
+
+int test_main(int, char*[])     // note name
+{
+  BOOST_TEST(2 + 2 == 5);       // one convertible-to-bool argument; this one fails!
+  BOOST_TEST_EQ(4 + 4, 9);      // two EqualityComparible arguments; this one fails!
+  BOOST_TEST(fs::exists("."));  // should pass, so nothing should be reported
+
+  return ::boost::report_errors();   // required
+}
+
+
+

Build and test

+ + +

POSIX-like systems:

+ + +
+
cd <boost-root>/libs/filesystem/bug
+../../../b2 -a
+bin/bug
+
+

Windows:

+
+
cd <boost-root>\libs\filesystem\bug
+..\..\..\b2 -a
+bin\bug
+
+

Test output

+ + +

Running the test on Windows produced this test output:

+ + +
+ + +
Microsoft Visual C++ version 14.0
+Dinkumware standard library version 610
+Win32
+Boost version 1.58.0
+Command line: bin\bug
+bug.cpp(10): test '2 + 2 == 5' failed in function
+  'int __cdecl test_main(int,char *[])'
+bug.cpp(11): test '4 + 4 == 9' failed in function
+  'int __cdecl test_main(int,char *[])': '8' != '9'
+2 errors detected.
+
+

The test framework runs test_main() from a try +block with a catch block that reports exceptions via +std::exception what(). So the output will differ if an exception is +thrown.

+

Background information

+

You should now have enough information to file an easy-to-reproduce bug +report. So you can skip reading the rest of this page unless you need to do +something a bit out of the ordinary.

+

b2 command line

+

b2 (formerly bjam) usage:  b2 +[options] [properties] [target]

+

Boost.Build b2 has many options, properties, and targets, but you will not +need most of them for bug reporting. Here are a few you might find helpful:

+

Options

+
+

-a    Rebuild everything rather than + just out-of-date targets. Used in the example build above to ensure libraries + are built with the same setup as the test program.

+
+

Properties

+
+

address-model=n  n is 32 or 64. + Explicitly request either 32-bit or 64-bit code generation. This typically + requires that your compiler is appropriately configured.

+

variant=string      string is + debug or release.

+

toolset=string      The C++ + compiler to use. For example, gcc-4.9, clang-3.3, + or msvc-14.0.

+

include=string      + Additional include paths for C and C++ compilers.

+

cxxflags=string      + Custom options to pass to the C++ compiler.

+

define=string      + Additional macro definitions for C and C++ compilers. string should be + either SYMBOL or + SYMBOL=VALUE

+
+

Rationale

+

Here is the request list again, with rationale added:

+
    +
  1. A simple test program +that:
      +
    • +

      Illustrates the problem [Code communicates more clearly than + prose. If it looks like it will it will take some time to figure out exactly what the + problem is, or worse yet, might result in a wild-goose chase, the bug report + gets set aside to be worked on later and then is often forgotten.] and

    • +
    • Automatically yields an unambiguous pass or fail result - returning zero + for pass and non-zero for fail is preferred [Prevents + miscommunications and allows use in automatic regression tests.], and
    • +
    • Can be used as the basis for adding tests to Boost.Filesystem's + regression test suite [With good test cases fixes come easier and + regressions become less likely].
    • +
    +
  2. +
  3. The compiler, standard library, platform, and Boost version you + used to build and run your test program. [The implementation includes much + platform dependent code, and also depends on the other factors mentioned. Know + these things upfront brings the bug report into focus without having to ask + for more information. ]
  4. +
  5. A description of how to build and run the test program. [If b2 + (formerly known as bjam) is used as the build engine, this is not a concern, + but otherwise much more information is needed.]
  6. +
  7. A copy of the output from the test + program, if any. [Avoids misinterpreting results.]
  8. +
  9. An email address for follow-up questions. [Trac comments are the + primary means of response, but it is disheartening when a trac question is not + answered and there is no email address attached for followup.]
  10. +
+
+

© Copyright Beman Dawes, 2014

+

© Copyright Andrey Semashev, 2019, 2021

+

Distributed under the Boost Software +License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + diff --git a/3rdparty/boost_filesystem/doc/path_table.cpp b/3rdparty/boost_filesystem/doc/path_table.cpp new file mode 100644 index 0000000..157a424 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/path_table.cpp @@ -0,0 +1,254 @@ +// Generate an HTML table showing path decomposition ---------------------------------// + +// Copyright Beman Dawes 2005. + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/filesystem for documentation. + +// For purposes of generating the table, support both POSIX and Windows paths + +#include "boost/filesystem.hpp" +#include +#include + +using boost::filesystem::path; +using std::string; +using std::cout; + +namespace { +std::ifstream infile; +std::ofstream posix_outfile; +std::ifstream posix_infile; +std::ofstream outfile; + +bool posix; + +const string empty_string; + +struct column_base +{ + virtual string heading() const = 0; + virtual string cell_value(const path& p) const = 0; +}; + +struct c0 : public column_base +{ + string heading() const { return string("string()"); } + string cell_value(const path& p) const { return p.string(); } +} o0; + +struct c1 : public column_base +{ + string heading() const { return string("generic_
string()
"); } + string cell_value(const path& p) const { return p.generic_string(); } +} o1; + +struct c2 : public column_base +{ + string heading() const { return string("Iteration
over
Elements"); } + string cell_value(const path& p) const + { + string s; + for (path::iterator i(p.begin()); i != p.end(); ++i) + { + if (i != p.begin()) + s += ','; + s += (*i).string(); + } + return s; + } +} o2; + +struct c3 : public column_base +{ + string heading() const { return string("root_
path()
"); } + string cell_value(const path& p) const { return p.root_path().string(); } +} o3; + +struct c4 : public column_base +{ + string heading() const { return string("root_
name()
"); } + string cell_value(const path& p) const { return p.root_name().string(); } +} o4; + +struct c5 : public column_base +{ + string heading() const { return string("root_
directory()
"); } + string cell_value(const path& p) const { return p.root_directory().string(); } +} o5; + +struct c6 : public column_base +{ + string heading() const { return string("relative_
path()
"); } + string cell_value(const path& p) const { return p.relative_path().string(); } +} o6; + +struct c7 : public column_base +{ + string heading() const { return string("parent_
path()
"); } + string cell_value(const path& p) const { return p.parent_path().string(); } +} o7; + +struct c8 : public column_base +{ + string heading() const { return string("filename()"); } + string cell_value(const path& p) const { return p.filename().string(); } +} o8; + +const column_base* column[] = { &o2, &o0, &o1, &o3, &o4, &o5, &o6, &o7, &o8 }; + +// do_cell ---------------------------------------------------------------// + +void do_cell(const string& test_case, int i) +{ + string temp = column[i]->cell_value(path(test_case)); + string value; + outfile << ""; + if (temp.empty()) + value = "empty"; + else + value = string("") + temp + ""; + + if (posix) + posix_outfile << value << '\n'; + else + { + std::getline(posix_infile, temp); + if (value != temp) // POSIX and Windows differ + { + value.insert(0, "
"); + value.insert(0, temp); + value.insert(0, ""); + value += ""; + } + outfile << value; + } + outfile << "\n"; +} + +// do_row ------------------------------------------------------------------// + +void do_row(const string& test_case) +{ + outfile << "\n"; + + if (test_case.empty()) + outfile << "empty\n"; + else + outfile << "" << test_case << "\n"; + + for (int i = 0; i < sizeof(column) / sizeof(column_base&); ++i) + { + do_cell(test_case, i); + } + + outfile << "\n"; +} + +// do_table ----------------------------------------------------------------// + +void do_table() +{ + outfile << "

Path Decomposition Table

\n" + "

Shaded entries indicate cases where POSIX and Windows\n" + "implementations yield different results. The top value is the\n" + "POSIX result and the bottom value is the Windows result.\n" + "\n" + "

\n"; + + // generate the column headings + + outfile << "

\n"; + + for (int i = 0; i < sizeof(column) / sizeof(column_base&); ++i) + { + outfile << "\n"; + } + + outfile << "\n"; + + // generate a row for each input line + + string test_case; + while (std::getline(infile, test_case)) + { + if (!test_case.empty() && *--test_case.end() == '\r') + test_case.erase(test_case.size() - 1); + if (test_case.empty() || test_case[0] != '#') + do_row(test_case); + } + + outfile << "
Constructor
argument
" << column[i]->heading() << "
\n"; +} + +} // unnamed namespace + +// main ------------------------------------------------------------------------------// + +#define BOOST_NO_CPP_MAIN_SUCCESS_MESSAGE +#include + +int cpp_main(int argc, char* argv[]) // note name! +{ + if (argc != 5) + { + std::cerr << "Usage: path_table \"POSIX\"|\"Windows\" input-file posix-file output-file\n" + "Run on POSIX first, then on Windows\n" + " \"POSIX\" causes POSIX results to be saved in posix-file;\n" + " \"Windows\" causes POSIX results read from posix-file\n" + " input-file contains the paths to appear in the table.\n" + " posix-file will be used for POSIX results\n" + " output-file will contain the generated HTML.\n"; + return 1; + } + + infile.open(argv[2]); + if (!infile) + { + std::cerr << "Could not open input file: " << argv[2] << std::endl; + return 1; + } + + if (string(argv[1]) == "POSIX") + { + posix = true; + posix_outfile.open(argv[3]); + if (!posix_outfile) + { + std::cerr << "Could not open POSIX output file: " << argv[3] << std::endl; + return 1; + } + } + else + { + posix = false; + posix_infile.open(argv[3]); + if (!posix_infile) + { + std::cerr << "Could not open POSIX input file: " << argv[3] << std::endl; + return 1; + } + } + + outfile.open(argv[4]); + if (!outfile) + { + std::cerr << "Could not open output file: " << argv[2] << std::endl; + return 1; + } + + outfile << "\n" + "\n" + "Path Decomposition Table\n" + "\n" + "\n"; + + do_table(); + + outfile << "\n" + "\n"; + + return 0; +} diff --git a/3rdparty/boost_filesystem/doc/path_table.txt b/3rdparty/boost_filesystem/doc/path_table.txt new file mode 100644 index 0000000..40809c6 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/path_table.txt @@ -0,0 +1,50 @@ +# Paths for the reference.html Path Decomposition Table +# +# This is the input file for path_table, which generates the actual html +# +# Copyright Beman Dawes 2010 +# +# Distributed under the Boost Software License, Version 1.0. +# See www.boost.org/LICENSE_1_0.txt +# +# Note that an empty line is treated as input rather than as a comment + +. +.. +foo +/ +/foo +foo/ +/foo/ +foo/bar +/foo/bar +//net +//net/foo +///foo/// +///foo///bar +/. +./ +/.. +../ +foo/. +foo/.. +foo/./ +foo/./bar +foo/.. +foo/../ +foo/../bar +c: +c:/ +c:foo +c:/foo +c:foo/ +c:/foo/ +c:/foo/bar +prn: +c:\ +c:foo +c:\foo +c:foo\ +c:\foo\ +c:\foo/ +c:/foo\bar diff --git a/3rdparty/boost_filesystem/doc/portability_guide.htm b/3rdparty/boost_filesystem/doc/portability_guide.htm new file mode 100644 index 0000000..7e1a948 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/portability_guide.htm @@ -0,0 +1,241 @@ + + + + + + + +Portability Guide + + + + + +

+Path +Name Portability +Guide

+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

+Introduction
+name_check functions
+File and directory name recommendations

+

Introduction

+

Like any other C++ program which performs I/O operations, there is no +guarantee that a program using Boost.Filesystem will be portable between +operating systems. Critical aspects of I/O such as how the operating system +interprets paths are unspecified by the C and C++ Standards.

+

It is not possible to know if a file or directory name will be +valid (and thus portable) for an unknown operating system. There is always the possibility that an operating system could use +names which are unusual (numbers less than 4096, for example) or very +limited in size (maximum of six character names, for example). In other words, +portability is never absolute; it is always relative to specific operating +systems or +file systems.

+

It is possible, however, to know in advance if a directory or file name is likely to be valid for a particular +operating system. It is also possible to construct names which are +likely to be portable to a large number of modern and legacy operating systems.

+ +

Almost all modern operating systems support multiple file systems. At the +minimum, they support a native file system plus a CD-ROM file system (Generally +ISO-9669, often with Joliet extensions).

+ +

Each file system +may have its own naming rules. For example, modern versions of Windows support NTFS, FAT, FAT32, and ISO-9660 file systems, among others, and the naming rules +for those file systems differ. Each file system may also have +differing rules for overall path validity, such as a maximum length or number of +sub-directories. Some legacy systems have different rules for directory names +versus regular file names.

+ +

As a result, Boost.Filesystem's name_check functions +cannot guarantee directory and file name portability. Rather, they are intended to +give the programmer a "fighting chance" to achieve portability by early +detection of common naming problems.

+ +

name_check functions

+ +

A name_check function +returns true if its argument is valid as a directory and regular file name for a +particular operating or file system. A number of these functions are provided.

+ +

The portable_name function is of particular +interest because it has been carefully designed to provide wide +portability yet not overly restrict expressiveness.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Library Supplied name_check Functions
FunctionDescription
portable_posix_name(const + std::string& name)Returns: true if !name.empty() && name contains only the characters + specified in Portable Filename Character Set rules as defined in by + POSIX (www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html).
+ The allowed characters are 0-9, a-z, A-Z, + '.', '_', and '-'.

Use: + applications which must be portable to any POSIX system.

windows_name(const + std::string& name)Returns:  true if !name.empty() && name contains + only the characters specified by the Windows platform SDK as valid + regardless of the file system && (name is "." or + ".."  or does not end with a trailing space or period).  + The allowed characters are anything except 0x0-0x1F, '<', + '>', ':', '"', '/', + '\', and '|'.

+ Use: applications which must be portable to Windows.

+

Note: Reserved device names are not valid as file names, but are + not being detected because they are still valid as a path. Specifically, + CON, PRN, AUX, CLOCK$, NUL, COM[1-9], LPT[1-9], and these names followed by + an extension (for example, NUL.tx7).

portable_name(const + std::string& name)Returns:  windows_name(name) && portable_posix_name(name) + && (name is "." or "..", and the first character not a period or hyphen).

Use: applications which must be portable to a wide variety of + modern operating systems, large and small, and to some legacy O/S's. The + first character not a period or hyphen restriction is a requirement of + several older operating systems.

+ portable_directory_name(const std::string& name)Returns: portable_name(name) && (name is "." + or ".."  or contains no periods).

Use: applications + which must be portable to a wide variety of platforms, including OpenVMS.

+ portable_file_name(const std::string& name)Returns: portable_name(name) && any period is followed by one to three additional + non-period characters.

Use: + applications which must be portable to a wide variety of platforms, + including OpenVMS and other systems which have a concept of "file extension" + but limit its length.

native(const + std::string& name)Returns: Implementation defined. Returns + true for names considered valid by the operating system's native file + systems.

Note: May return true for some names not considered valid + by the operating system under all conditions (particularly on operating systems which support + multiple file systems.)

+ +

File and directory name recommendations

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RecommendationRationale
Limit file and directory names to the characters A-Z, a-z, 0-9, period, hyphen, and + underscore.

Use any of the "portable_" + name check functions to enforce this recommendation.

These are the characters specified by the POSIX standard for portable directory and + file names, and are also valid for Windows, Mac, and many other modern file systems.
Do not use a period or hyphen as the first + character of a name. Do not use period as the last character of a name.

+ Use portable_name, + portable_directory_name, or + portable_file_name to enforce this + recommendation.

Some operating systems treat have special rules for the + first character of names. POSIX, for example. Windows does not permit period + as the last character.
Do not use periods in directory names.

Use + portable_directory_name to enforce + this recommendation.

Requirement for ISO-9660 without Juliet extensions, OpenVMS filesystem, and other legacy systems.
Do not use more that one period in a file name, and limit + the portion after the period to three characters.

Use + portable_file_name to enforce this + recommendation.

Requirement for ISO-9660 level 1, OpenVMS filesystem, and + other legacy systems.
Do not assume names are case sensitive. For example, do not expected a directory to be + able to hold separate elements named "Foo" and "foo". Some file systems are case insensitive.  For example, Windows + NTFS is case preserving in the way it stores names, but case insensitive in + searching for names (unless running under the POSIX sub-system, it which + case it does case sensitive searches).
Do not assume names are case insensitive.  For example, do not expect a file + created with the name of "Foo" to be opened successfully with the name of "foo".Some file systems are case sensitive.  For example, POSIX.
Don't use hyphens in names.ISO-9660 level 1, and possibly some legacy systems, do not permit + hyphens.
Limit the length of the string returned by path::string() to + 255 characters.  + Note that ISO 9660 has an explicit directory tree depth limit of 8, although + this depth limit is removed by the Juliet extensions.Some operating systems place limits on the total path length.  For example, + Windows 2000 limits paths to 260 characters total length.
Limit the length of any one name in a path.  Pick the specific limit according to + the operating systems and or file systems you wish portability to:
+    Not a concern::  POSIX, Windows, MAC OS X.
+    31 characters: Classic Mac OS
+   8 characters + period + 3 characters: ISO 9660 level 1
+   32 characters: ISO 9660 level 2 and 3
+   128 characters (64 if Unicode): ISO 9660 with Juliet extensions
Limiting name length can markedly reduce the expressiveness of file names, yet placing + only very high limits on lengths inhibits widest portability.
+ +
+ +

© Copyright Beman Dawes, 2002, 2003

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt)

+ + + + diff --git a/3rdparty/boost_filesystem/doc/reference.html b/3rdparty/boost_filesystem/doc/reference.html new file mode 100644 index 0000000..e998fa9 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/reference.html @@ -0,0 +1,4688 @@ + + + + + + + + + + + + + +Filesystem Reference + + + + + + + + + + + +
+

+ +boost.png (6897 bytes)

+ Filesystem Library
+ Version 4
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

Reference Documentation

+ + + +

Table of Contents

+ + + + + + + +
+

Introduction
+ Definitions
+ Conformance
+ + Header <boost/filesystem.hpp> synopsis
+ Error reporting
+ Class path
+    path conversions
+    path + conversions to native format
+    path + conversions to generic format
+    path + encoding conversions
+    path requirements
+     path constructors
+    path assignments
+     path appends
+     path concatenation
+    path modifiers
+    path native + format observers
+    path generic + format observers
+    path compare
+    path decomposition
+    path query
+    path iterators
+ +    path deprecated functions
+    path non-member functions
+    path inserters and extractors
+  Class filesystem_error
+    filesystem_error + constructors
+    filesystem_error path1
+    filesystem_error path2
+    filesystem_error what

+

+ Enum file_type
+ Enum perms
+ Class + file_status
+    + + file_status constructors
+    file_status-modifiers observers
+    file_status-observers modifiers
+Class directory_entry
+    +directory_entry constructors
+    directory_entry observers
+    directory_entry modifiers
+Class directory_iterator
+    directory_iterator + members
+Class recursive_directory_iterator
+ + Operational functions
+      absolute
+     canonical
+     copy
+     copy_directory
+     copy_file
+     copy_symlink
+     create_directories
+     create_directory
+     create_hard_link
+     create_symlink
+     creation_time
+     current_path
+     exists
+     equivalent
+     file_size
+     hard_link_count

+

+ +     initial_path
+     is_block_file
+     is_character_file
+     is_directory
+     is_empty
+     is_fifo
+     is_other
+     is_regular_file
+     is_reparse_file
+     is_socket
+     is_symlink
+     last_write_time
+     permissions
+     read_symlink
+     relative
+     remove
+     remove_all
+     rename
+     resize_file
+     space
+     status
+     status_known
+     symlink_status
+     system_complete
+     temp_directory_path
+     unique_path
+     weakly_canonical
+ File streams
+Path decomposition table
+ Long paths on Windows and the + \\?\ namespace prefix
+Acknowledgements
+References

+ + +

Introduction

+ +

This reference documentation describes components that C++ programs may use +to perform operations involving file systems, including paths, regular files, +and directories.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

C++11 Support

This reference + documentation is written as if all compilers supported C++11. Where + possible, the implementation falls back to C++03 if a C++11 feature is not + available.

+

+ C++11 Feature

+

+ Action if not supported by compiler

+

+ noexcept

+

Keyword omitted.

+

+ constexpr

+

Keyword omitted.

+

R-value references

+

Function signature omitted.

+

Defaulted and deleted functions

+

Workaround replacement functions provided.

+

Initializer lists

+

Not currently used.

+

Variadic templates

+

Not currently used.

+

Range-based for statements

+

Supporting functions always provided; they do no harm even for C++03 + compilers.

+
+ + + +

Conformance [fs.conformance]

+ +

ISO/IEC 9945 conformance [fs.conform.9945]

+

Some behavior in this reference documentation is specified by reference to ISO/IEC 9945. How such behavior is actually implemented is unspecified.

+
+

[Note: This constitutes an "as if" rule for implementation of +operating system dependent behavior. In practice implementations will usually call native +operating system API's. —end note]

+
+

Implementations are encouraged to provide such behavior + +as it is defined by ISO/IEC 9945. Implementations shall document any +behavior that differs from the behavior defined by ISO/IEC 9945. Implementations that do not support exact +ISO/IEC 9945 behavior are +encouraged to provide behavior as close to ISO/IEC 9945 behavior as is reasonable given the +limitations of actual operating systems and file systems. If an implementation cannot provide any +reasonable behavior, the implementation shall report an error in an +implementation-defined manner.

+
+

[Note: Such errors might be reported by an #error directive, a +static_assert, a filesystem_error exception, a special +return value, or some other manner. —end note]

+
+

Implementations are not required to provide behavior that is not supported by +a particular file system.

+
+

[Example: The +FAT file system used by some memory cards, camera memory, and floppy discs +does not support hard links, symlinks, and many other features of more capable +file systems. Implementations are only required to support the FAT features +supported by the host operating system. —end example]

+
+

The behavior of functions described in this +reference +may differ from their specification in +the presence of file system races. No diagnostic is required.

+

If the possibility of a file system race would make it unreliable for a program to +test for a precondition before calling a function described in this reference documentation, +Requires is not specified for the condition. Instead, the condition is +specified as a Throws condition.

+
+

[Note: As a design practice, preconditions are not specified when it +is unreasonable for a program to detect them prior to calling the function. +—end note]

+
+

Operating system dependent conformance [fs.conform.os]

+

Some behavior is specified in this reference documentation as being +operating system dependent ([fs.def.osdep]). The operation system an +implementation is dependent upon is implementation defined.

+

It is permissible for an implementation to be dependent upon an operating +system emulator rather than the actual operating system.

+
+

[Example: An implementation uses Cygwin, a Linux® API emulator for +some Windows® operating system versions. The implementation would define Cygwin +as its operating system. Users could refer to the Cygwin documentation to find +details of the operating system dependent behavior.  —end example]

+

It is user and conformance test +detectable that such an implementation is running on Cygwin. Users would be +misled and conformance tests would fail if the implementation defined Linux or +Windows rather than Cygwin as the operating system, since real behavior is a +blend of the two.

+
+

Definitions [fs.definitions]

+

The following definitions shall apply throughout this reference documentation:

+

operating system dependent behavior +[fs.def.osdep]

+

Behavior that is dependent upon the behavior +and characteristics of an operating system. See [fs.conform.os].

+

file [fs.def.file]

+

An object that can be written to, or read from, or both. A file +has certain attributes, including type. File types include regular files +and directories. Other types of files, such as symbolic links, may be supported by the +implementation.

+

file system [fs.def.filesystem]

+

A collection of files and certain of their attributes.

+

filename [fs.def.filename]

+

The name of a file. Filenames + "."  +and ".."  have special meaning. The follow characteristics of + filenames are operating system dependent:

+
    +
  • +

    The permitted characters. See [fs.os.examples].

    +
  • +
  • +

    Specific filenames that are not permitted.

    +
  • +
  • +

    Additional filenames that have special meaning.

    +
  • +
  • +

    Case awareness and sensitivity during path resolution.

    +
  • +
  • +

    Special rules that may apply to file types other than regular + files, such as directories.

    +
  • +
+

path [fs.def.path]

+

A sequence of elements that identify +the location of a file within a filesystem. The elements are the root-nameopt, +root-directoryopt, and an optional sequence of filenames. [Note: +A pathname is the concrete representation of a path. —end note]

+ +

absolute path [fs.def.absolute-path]

+

A path that +unambiguously +identifies the location of a file without reference to an additional starting +location. The elements of a path that determine if it is absolute are +operating system dependent.

+ +

relative path [fs.def.relative-path]

+

A path that +is not absolute, and so only +unambiguously +identifies the location of a file when resolved relative to +an implied starting location. The elements of a path that determine if it is +relative are operating system dependent.  [Note: +Paths "." and ".." are relative paths. —end note]

+

canonical path [fs.def.canonical-path]

+

An absolute path that has +no elements that are symbolic links, and no "." or ".." elements.

+

pathname [fs.def.pathname]

+

A character string that represents +the name of a +path. Pathnames are formatted according to the generic pathname grammar or an +operating system dependent +native pathname format.

+ +

native pathname format [fs.def.native]

+

The operating system dependent pathname format accepted by the host operating system.

+

normal form path [fs.def.normal]

+

A path with no redundant directory separators, current directory (dot) or parent directory (dot-dot) +elements. The normal form for an empty path is an empty path. [v3: The normal form +for a path ending in a directory-separator that is not the root directory +is the same path with a current directory (dot) element appended.]

+

link [fs.def.link]

+

A directory entry object that associates a +filename with a file. On some file systems, several directory entries can +associate names with the same file.

+

hard link [fs.def.hardlink]

+

A link to an existing file. Some +file systems support multiple hard links to a file. If the last hard link to a +file is removed, the file itself is removed.

+
+

[Note: A hard link can be thought of as a shared-ownership smart +pointer to a file. —end note]

+
+

symbolic link [fs.def.symlink]

+

A type of file with the +property that when the file is encountered during pathname resolution, a string +stored by the file is used to modify the pathname resolution.

+
+

[Note: A symbolic link can be thought of as a raw pointer to a file. +If the file pointed to does not exist, the symbolic link is said to be a +"dangling" symbolic link. —end note]

+
+

file system race [fs.def.race]

+

The condition that occurs +when multiple threads, processes, or computers interleave access and +modification of +the same object within a file system.

+

Generic pathname format [path.generic]

+

pathname:
+            root-nameopt +root-directoryopt relative-pathopt

+

root-name:
+           
An +operating system dependent name that identifies the starting location for +absolute paths.

+
+
+

[Note: Many operating systems define a name +beginning with two directory-separator characters as a root-name +that identifies network or other resource locations. Some operating systems define a single letter followed by a colon as a drive +specifier - a root-name identifying a specific device such as a disc drive. —end note]

+
+
+

root-directory:
+            +directory-separator

+

relative-path:
+            +filename
+            relative-path +directory-separator
+            relative-path +directory-separator filename

+

filename:
+            name
+           
"."
+           
+".."

+

preferred-separator:
+           
An +operating system dependent directory separator character. May be a synonym for "/".

+

directory-separator:
+            "/"
+      "/"
directory-separator
+            +preferred-separator
+            +preferred-separator directory-separator

+

Multiple successive directory-separator characters are considered to +be the same as one directory-separator character.

+

The filename +"." is considered to be a reference to the current directory. The +filename ".." is considered to be a reference to the +parent +directory. Specific filenames may have special meanings for a particular +operating system.

+

Operating system dependent examples (Informative) [fs.os.examples]

+

Certain features are specified in this reference documentation as being operating system dependent. The following table shows the application of those +specifications for operating systems that use the ISO/IEC 9945 or Windows® application program interfaces +(APIs).[footnote1]

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Feature

+

Section

+

ISO/IEC 9945
+ POSIX
® API

+

Windows® API

+

Notes

+

path
+ ::value_type

+

[class.path]

+

char

+

wchar_t

+

 

+

path::preferred
+ _separator

+

[class.path]

+

'/'

+

L'\\' (single backslash)

+

 

+

path("/")
+ .is_absolute()
+ path("c:/")
+ .is_absolute()

+

[path
.query]

+


+ true
+
+ false

+


+ false
+
+ true

+

 

+

path argument disambiguation between generic format and + native format

+

[path.arg
.fmt.cvt]

+

Not required

+

Not required

+

There is no need to distinguish between the generic format and native + format for these operating systems.

+

path argument format conversion

+

[path.arg
.fmt.cvt]

+

No conversion performed

+

No conversion performed

+

The generic format is already acceptable to the native API of these operating systems.

+

path
+ ("/cats/jane")
+ .c_str()
+ path|
+ ("/cats/jane/")
+ .c_str()

+

[path.arg
.fmt.cvt]

+


+
+ "/cats/jane"
+
+
+ "/cats/jane/"

+


+
+ L"/cats/jane"
+
+
+ L"/cats/jane/"

+

These operating systems accept the same native separator between + directory names and a final file name, so no format conversion is performed. + Other operating systems might require conversion.

+

Format conversion by path native format observers

+

[path.native
.obs]

+

No conversion performed

+

No conversion performed

+

For efficiency, path objects are required to store pathnames in the native + format regardless of operating system.

+

Format conversion by path generic format observers

+

[path
.generic
.obs]

+

No conversion performed

+

Backslashes converted to slashes

+

 

+

p.
+ make_preferred()

+

[fs.path
.modifiers]

+

No change

+

Slashes converted to backslashes

+

 

+

Characters prohibited in filenames

+

[fs.def
.filename]

+

0x00, '/'

+

0x00-0x1F, '"', '*', '*', + '<', + '>', '?', '\\' (single backslash), + '/', '|'

+

Many operating systems prohibit the ASCII control characters (0x00-0x1F) + in filenames.

+

Initial imbued path locale

+

[path
.imbued
.locale]

+

std::
+  locale("")
+
[footnote 2]

+

Implementation supplied locale using MultiByte
+  ToWideChar
+ and WideChar
+  ToMultiByte
with a codepage of CP_ACP + if AreFileApisANSI is true, otherwise codepage CP_OEMCP.[footnote + 3]

+

Apple OS X®:  Implementation supplied locale providing UTF-8 codecvt + facet.[footnote 4]

+

[footnote1] OS X® and Windows® are examples of commercially +available operating systems. This information is given for the convenience of +users of this document and does not constitute an endorsement by ISO or IEC of +these products.

+

[footnote 2] Rationale: ISO C specifies std::locale("") as "the locale-specific native +environment", while ISO/IEC 9945 says it "Specifies an implementation-defined native +environment."

+

[footnote 3] Rationale: This is the current behavior of C and C++ +standard library functions that perform file operations using narrow character +strings to identify paths. Changing this behavior would be surprising and at +variance with existing code, particularly where user input is involved.

+

[footnote 4] Rationale: Vendor's documentation states "All BSD +system functions expect their string parameters to be in UTF-8 encoding and +nothing else."

+

Header <boost/filesystem.hpp> synopsis +[filesystem.synopsis]

+ + + +
namespace boost
+{
+  namespace filesystem
+  {
+    class path;
+
+    bool lexicographical_compare(path::iterator first1, path::iterator last1,
+      path::iterator first2, path::iterator last2);
+    void swap(path& lhs, path& rhs) noexcept;
+    std::size_t hash_value(const path& p);
+
+    bool operator==(const path& lhs, const path& rhs);
+    bool operator!=(const path& lhs, const path& rhs);
+    bool operator< (const path& lhs, const path& rhs);
+    bool operator<=(const path& lhs, const path& rhs);
+    bool operator> (const path& lhs, const path& rhs);
+    bool operator>=(const path& lhs, const path& rhs);
+
+    path operator/ (const path& lhs, const path& rhs);
+
+    std::ostream&  operator<<( std::ostream& os, const path& p );
+    std::wostream& operator<<( std::wostream& os, const path& p );
+    std::istream&  operator>>( std::istream& is, path& p );
+    std::wistream& operator>>( std::wistream& is, path& p )
+
+    class filesystem_error;
+    class directory_entry;
+
+    class directory_iterator;
+
+    // enable c++11 range-based for statements
+    const directory_iterator& begin(const directory_iterator& iter);
+    directory_iterator end(const directory_iterator&);
+
+
+    // enable BOOST_FOREACH
+    directory_iterator& range_begin(directory_iterator& iter);
+    directory_iterator range_begin(const directory_iterator& iter);
+    directory_iterator range_end(const directory_iterator&);
+
+    class recursive_directory_iterator;
+
+    // enable c++11 range-based for statements
+    const recursive_directory_iterator&
+      begin(const recursive_directory_iterator& iter);
+    recursive_directory_iterator
+      end(const recursive_directory_iterator&);
+
+
+    // enable BOOST_FOREACH
+    recursive_directory_iterator&
+      range_begin(recursive_directory_iterator& iter);
+    recursive_directory_iterator
+      range_begin(const recursive_directory_iterator& iter);
+    recursive_directory_iterator
+      range_end(const recursive_directory_iterator&);
+
+    enum file_type
+    {
+      status_error, file_not_found, regular_file, directory_file,
+      symlink_file, block_file, character_file, fifo_file, socket_file,
+      reparse_file, type_unknown
+    };
+
+    enum perms
+    {
+      no_perms,
+      owner_read, owner_write, owner_exe, owner_all,
+      group_read, group_write, group_exe, group_all,
+      others_read, others_write, others_exe, others_all, all_all,
+      set_uid_on_exe, set_gid_on_exe, sticky_bit,
+      perms_mask, perms_not_known,
+      add_perms, remove_perms, symlink_perms
+    };
+
+    class file_status;
+
+    struct space_info  // returned by space function
+    {
+      uintmax_t capacity;
+      uintmax_t free;
+      uintmax_t available; // free space available to non-privileged process
+    };
+
+    enum class copy_options
+    {
+      none = 0u,
+      // copy_file options
+      skip_existing,
+      overwrite_existing,
+      update_existing,
+      synchronize_data,
+      synchronize,
+      // copy options
+      recursive,
+      copy_symlinks,
+      skip_symlinks,
+      directories_only,
+      create_symlinks,
+      create_hard_links
+    };
+
+    // Deprecated, use copy_options instead
+    enum class copy_option
+    {
+      none = copy_options::none,
+      fail_if_exists = none,
+      overwrite_if_exists = copy_options::overwrite_existing
+    };
+
+    enum class directory_options
+    {
+      none = 0u,
+      skip_permission_denied,
+      follow_directory_symlink,
+      pop_on_error
+    };
+
+    // Deprecated, use directory_options instead
+    enum class symlink_option
+    {
+      none = directory_options::none,
+      no_recurse = none,
+      recurse = directory_options::follow_directory_symlink
+    };
+
+    // operational functions
+
+    path         absolute(const path& p, const path& base=current_path());
+    path         absolute(const path& p, system::error_code& ec);
+    path         absolute(const path& p, const path& base,
+                   system::error_code& ec);
+
+    path         canonical(const path& p, const path& base = current_path());
+    path         canonical(const path& p, system::error_code& ec);
+    path         canonical(const path& p, const path& base,
+                   system::error_code& ec);
+
+    void         copy(const path& from, const path& to);
+    void         copy(const path& from, const path& to,
+                   system::error_code& ec);
+    void         copy(const path& from, const path& to,
+                   copy_options options);
+    void         copy(const path& from, const path& to,
+                   copy_options options, system::error_code& ec);
+
+    // Deprecated, use create_directory instead
+    void         copy_directory(const path& from, const path& to);
+    void         copy_directory(const path& from, const path& to,
+                   system::error_code& ec);
+
+    bool         copy_file(const path& from, const path& to);
+    bool         copy_file(const path& from, const path& to,
+                   system::error_code& ec);
+    bool         copy_file(const path& from, const path& to,
+                   copy_options options);
+    bool         copy_file(const path& from, const path& to,
+                   copy_options options, system::error_code& ec);
+    // Deprecated, use overloads taking copy_options instead
+    bool         copy_file(const path& from, const path& to,
+                   copy_option options);
+    bool         copy_file(const path& from, const path& to,
+                   copy_option options, system::error_code& ec);
+
+    void         copy_symlink(const path& existing_symlink,
+                   const path& new_symlink);
+    void         copy_symlink(const path& existing_symlink,
+                   const path& new_symlink, system::error_code& ec);
+
+    bool         create_directories(const path& p);
+    bool         create_directories(const path& p,
+                   system::error_code& ec);
+
+    bool         create_directory(const path& p);
+    bool         create_directory(const path& p, system::error_code& ec);
+    bool         create_directory(const path& p, const path& existing);
+    bool         create_directory(const path& p, const path& existing, system::error_code& ec);
+
+    void         create_directory_symlink(const path& to,
+                   const path& new_symlink);
+    void         create_directory_symlink(const path& to,
+                   const path& new_symlink, system::error_code& ec);
+
+    void         create_hard_link(const path& to, const path& new_hard_link);
+    void         create_hard_link(const path& to, const path& new_hard_link,
+                                  system::error_code& ec);
+
+    void         create_symlink(const path& to, const path& new_symlink);
+    void         create_symlink(const path& to, const path& new_symlink,
+                                system::error_code& ec);
+
+    std::time_t  creation_time(const path& p);
+    std::time_t  creation_time(const path& p, system::error_code& ec);
+
+    path         current_path();
+    path         current_path(system::error_code& ec);
+    void         current_path(const path& p);
+    void         current_path(const path& p, system::error_code& ec);
+
+    bool         exists(file_status s) noexcept;
+    bool         exists(const path& p);
+    bool         exists(const path& p, system::error_code& ec) noexcept;
+
+    bool         equivalent(const path& p1, const path& p2);
+    bool         equivalent(const path& p1, const path& p2,
+                   system::error_code& ec);
+
+    uintmax_t    file_size(const path& p);
+    uintmax_t    file_size(const path& p, system::error_code& ec);
+
+    uintmax_t    hard_link_count(const path& p);
+    uintmax_t    hard_link_count(const path& p, system::error_code& ec);
+
+    const path&  initial_path();
+    const path&  initial_path(system::error_code& ec);
+
+    bool         is_block_file(file_status s) noexcept;
+    bool         is_block_file(const path& p);
+    bool         is_block_file(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_character_file(file_status s) noexcept;
+    bool         is_character_file(const path& p);
+    bool         is_character_file(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_directory(file_status s) noexcept;
+    bool         is_directory(const path& p);
+    bool         is_directory(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_empty(const path& p);
+    bool         is_empty(const path& p, system::error_code& ec);
+
+    bool         is_fifo(file_status s) noexcept;
+    bool         is_fifo(const path& p);
+    bool         is_fifo(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_other(file_status s) noexcept;
+    bool         is_other(const path& p,);
+    bool         is_other(const path& p, system::error_code& ec) noexcept;
+
+    bool         is_regular_file(file_status s) noexcept;
+    bool         is_regular_file(const path& p);
+    bool         is_regular_file(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_reparse_file(file_status s) noexcept;
+    bool         is_reparse_file(const path& p);
+    bool         is_reparse_file(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_socket(file_status s) noexcept;
+    bool         is_socket(const path& p);
+    bool         is_socket(const path& p,
+                   system::error_code& ec) noexcept;
+
+    bool         is_symlink(file_status s noexcept);
+    bool         is_symlink(const path& p);
+    bool         is_symlink(const path& p, system::error_code& ec) noexcept;
+
+    std::time_t  last_write_time(const path& p);
+    std::time_t  last_write_time(const path& p, system::error_code& ec);
+    void         last_write_time(const path& p, const std::time_t new_time);
+    void         last_write_time(const path& p, const std::time_t new_time,
+                                 system::error_code& ec);
+
+    path         read_symlink(const path& p);
+    path         read_symlink(const path& p, system::error_code& ec);
+
+    path         relative(const path& p, system::error_code& ec);
+    path         relative(const path& p, const path& base=current_path());
+    path         relative(const path& p,
+                     const path& base, system::error_code& ec);
+
+    bool         remove(const path& p);
+    bool         remove(const path& p, system::error_code& ec);
+
+    uintmax_t    remove_all(const path& p);
+    uintmax_t    remove_all(const path& p, system::error_code& ec);
+
+    void         rename(const path& from, const path& to);
+    void         rename(const path& from, const path& to,
+                   system::error_code& ec);
+
+    void         resize_file(const path& p, uintmax_t size);
+    void         resize_file(const path& p, uintmax_t size,
+                   system::error_code& ec);
+
+    space_info   space(const path& p);
+    space_info   space(const path& p, system::error_code& ec);
+
+    file_status  status(const path& p);
+    file_status  status(const path& p, system::error_code& ec) noexcept;
+
+    bool         status_known(file_status s) noexcept;
+
+    file_status  symlink_status(const path& p);
+    file_status  symlink_status(const path& p,
+                   system::error_code& ec) noexcept;
+
+    path         system_complete(const path& p);
+    path         system_complete(const path& p, system::error_code& ec);
+
+    path         temp_directory_path();
+    path         temp_directory_path(system::error_code& ec);
+
+    path         unique_path(const path& model="%%%%-%%%%-%%%%-%%%%");
+    path         unique_path(const path& model, system::error_code& ec);
+
+    path         weakly_canonical(const path& p, const path& base=current_path());
+    path         weakly_canonical(const path& p, system::error_code& ec);
+    path         weakly_canonical(const path& p, const path& base,
+                   system::error_code& ec);
+
+  }  // namespace filesystem
+}  // namespace boost
+ + + +

Error reporting [fs.err.report]

+

Filesystem library functions often provide two overloads, one that +throws an exception to report file system errors, and another that sets an error_code.

+
+

[Note: This supports two common use cases:

+
    +
  • +

    Uses where file system +errors are truly exceptional and indicate a serious failure. Throwing an + exception is the most appropriate response. This is the preferred default for + most everyday programming.

  • +
  • +

    Uses where file system errors are routine and do not necessarily represent + failure. Returning an error code is the most appropriate response. This allows + application specific error handling, including simply ignoring the error.

  • +
+

—end note]

+
+

Functions not having an argument of type system::error_code& report errors as follows, unless otherwise specified:

+
    +
  • +

    When a call by the + implementation to an operating system or other underlying API results in an + error that prevents the function from meeting its specifications, an exception + of type +filesystem_error is thrown.

  • +
  • +

    Failure to allocate storage is reported by throwing an exception as described in the C++ standard, + 17.6.4.10 [res.on.exception.handling].

  • +
  • +

    Destructors throw nothing.

  • +
+

Functions having an argument of type system::error_code& report errors as follows, unless otherwise + specified:

+
    +
  • +

    If a call by the + implementation to an operating system or other underlying API results in an + error that prevents the function from meeting its specifications, the +system::error_code& argument is set as + appropriate for the specific error. Otherwise, clear() + is called on the +system::error_code& argument.

  • +
  • +

    Failure to allocate storage is reported by + throwing an exception as described in the C++ standard, + 17.6.4.10 [res.on.exception.handling].

  • +
+

Class path [class.path]

+

An object of class path represents a path, +and contains a pathname Such an object is concerned only with the lexical and syntactic aspects +of a path. The path does not necessarily exist in external storage, and the +pathname is not necessarily valid for the current operating +system or for a particular file system.

+ +
+ +
namespace boost
+{
+  namespace filesystem
+  {
+      class path
+      {
+      public:
+        typedef see below                                    value_type;
+        typedef std::basic_string<value_type>                string_type;
+        typedef std::codecvt<wchar_t, char, std::mbstate_t>  codecvt_type;
+        constexpr value_type                                 dot;
+        constexpr value_type                                 separator;
+        constexpr value_type                                 preferred_separator;
+
+        // constructors and destructor
+        path();
+        path(const path& p);
+        path(path&& p) noexcept;
+
+        template <class Source>
+          path(Source const& source, const codecvt_type& cvt=codecvt());
+
+        template <class InputIterator>
+          path(InputIterator begin, InputIterator end,
+            const codecvt_type& cvt=codecvt());
+
+       ~path();
+
+        // assignments
+        path& operator=(const path& p);
+        path& operator=(path&& p) noexcept;
+
+        template <class Source>
+          path& operator=(Source const& source);
+
+        path& assign(const path& p);
+        path& assign(path&& p) noexcept;
+        template <class Source>
+          path& assign(Source const& source,
+            const codecvt_type& cvt=codecvt())
+
+        template <class InputIterator>
+          path& assign(InputIterator begin, InputIterator end,
+            const codecvt_type& cvt=codecvt());
+
+        // appends
+        path& operator/=(const path& p);
+
+        template <class Source>
+          path& operator/=(Source const& source);
+
+        path& append(const path& x);
+        template <class Source>
+          path& append(Source const& source,
+            const codecvt_type& cvt=codecvt());
+
+        template <class InputIterator>
+          path& append(InputIterator begin, InputIterator end,
+            const codecvt_type& cvt=codecvt());
+
+        // concatenation
+        path& operator+=(const path& x);
+        template <class Source>
+          path& operator+=(Source const& source);
+        path& operator+=(value_type x);
+        template <class CharT>
+          path& operator+=(CharT x);
+
+        path& concat(const path& x);
+        template <class Source>
+          path& concat(Source const& x,
+            const codecvt_type& cvt=codecvt());
+        template <class InputIterator>
+          path& concat(InputIterator begin, InputIterator end,
+            const codecvt_type& cvt=codecvt());
+
+        // modifiers
+        void  clear();
+        path& make_preferred();
+        path& remove_filename();
+        path& remove_filename_and_trailing_separators();
+        path& replace_filename(const path& replacement);
+        path& replace_extension(const path& new_extension = path());
+        void  swap(path& rhs) noexcept;
+
+        // lexical operations
+        path lexically_normal() const;
+        path lexically_relative(const path& base) const;
+        path lexically_proximate(const path& base) const;
+
+        // native format observers
+        const string_type&  native() const noexcept;  // native format, encoding
+        const value_type*   c_str() const noexcept;   // native().c_str()
+        string_type::size_type size() const noexcept; // native().size()
+
+        template <class String>
+          String  string(const codecvt_type& cvt=codecvt()) const;
+        string    string(const codecvt_type& cvt=codecvt()) const;
+        wstring   wstring(const codecvt_type& cvt=codecvt()) const;
+
+        // generic format observers
+        template <class String>
+          String  generic_string() const;
+
+        string    generic_string(const codecvt_type& cvt=codecvt()) const;
+        wstring   generic_wstring(const codecvt_type& cvt=codecvt()) const;
+
+        // compare
+        int   compare(const path& p) const noexcept;
+        int   compare(const std::string& s) const;
+        int   compare(const value_type* s) const;
+
+        // decomposition
+        path  root_name() const;
+        path  root_directory() const;
+        path  root_path() const;
+        path  relative_path() const;
+        path  parent_path() const;
+        path  filename() const;
+        path  stem() const;
+        path  extension() const;
+
+        // query
+        bool empty() const;
+        bool filename_is_dot() const;
+        bool filename_is_dot_dot() const;
+        bool has_root_name() const;
+        bool has_root_directory() const;
+        bool has_root_path() const;
+        bool has_relative_path() const;
+        bool has_parent_path() const;
+        bool has_filename() const;
+        bool has_stem() const;
+        bool has_extension() const;
+        bool is_absolute() const;
+        bool is_relative() const;
+
+        // iterators
+        class iterator;
+        typedef iterator const_iterator;
+        class reverse_iterator;
+        typedef reverse_iterator const_reverse_iterator;
+
+        iterator begin() const;
+        iterator end() const;
+        reverse_iterator rbegin() const;
+        reverse_iterator rend() const;
+
+        // imbued locale
+        static std::locale imbue(const std::locale& loc);
+        static const codecvt_type & codecvt();
+
+      private:
+        string_type pathname;  // exposition only
+      };
+
+  }  // namespace filesystem
+}  // namespace boost
+ +
+ +

value_type is a typedef for the +character type used by the operating system to represent pathnames.

+ + +

path Usage concerns [path.usage]

+ +

Multithreading concerns

+ +

Filesystem library functions are not protected against data races. [Modifying +an object of a Filesystem library type that is shared between threads risks +undefined behavior unless objects of that type are explicitly specified as being +sharable without data races or the user supplies a locking mechanism. —end +note] [Note: Thus the Filesystem library behaves as if it were part +of the standard library, and C++ standard 17.6.4.10 Shared objects and the +library [res.on.objects] would thus apply.  —end note]

+ +

Windows concerns

+ +

Visual C++ at least through version 2012 does not employ C++11-style static +initialization locks, so the initialization of path::codecvt() can +race, either with itself or path::imbue() if they are called from +a different thread. A workaround is to call:

+ +
+

path::codecvt();  // ensure VC++ does not race during +initialization.

+ +
+

in the main thread before launching any additional threads. [Note: The +obvious fix of the Filesystem implementation doing the locking doesn't work +because of unrelated problems with the Microsoft compiler; for static linking +the runtime tries to do the initialization before main() starts, but doesn't +permit operating system lock calls at that time.  —end note]

+ +

POSIX concerns

+ +

Filesystem library initialization may throw an exception on POSIX +systems (e.g. Linux, but not Mac OS X) that use environmental variables to +determine the encoding of paths. This happens when std::locale("") +throws because an environmental variable such as LANG is set to an invalid +value, so it can affect any use of  std::locale(""), not just +the Filesystem library. Filesystem uses lazy initialization so the exception is +only thrown if a valid std::locale("") is actually needed, and also +so that the exception is thrown after main() starts.

+ +

Rather than waiting until a call to some Filesystem library function +unexpectedly triggers the exception when it calls path::codecvt(), +a program that needs be highly robust against environmental variable problems +may want to preemptively call std::locale("") within a try block, +catch the exception, and diagnose or repair the invalid environmental variable.

+ +

path Conversions [path.cvt]

+

path argument conversions [path.arg.cvt]

+
path argument +format conversions [path.arg.fmt.cvt]
+

Member function arguments that take character sequences representing paths +may use the generic pathname format or +the native pathname format. Iff such arguments +are in the generic format and the generic format is not acceptable to the +operating system as a native path, conversion to native format shall be performed +during the processing of the argument. See [fs.os.examples].

+
+

[Note: Depending on the operating system, there may be no unambiguous way for an implementation to +always be able to distinguish between native format and generic format arguments. +This is by design as it simplifies use for operating systems that do not require +disambiguation. Should an implementation encounter an +operating system where disambiguation is required, an implementation can defined +an extension to distinguish between the formats. +—end note]

+
+ +

If the native format requires +paths for regular files to be formatted differently from paths for directories, the +path shall be treated as a directory path if last element is a separator, +otherwise it shall be treated as a regular file path.

+ +
+path argument encoding conversions +[path.arg.encoding.cvt]
+

For member function arguments that take character sequences representing +paths, if the value type of the argument is not value_type and one +of the value types is char and the other is wchar_t, conversion to value_type +shall be performed by the path::codecvt() facet. ([path.imbued.locale]).

+

path Conversions +to generic format [fs.cvt.to.generic]

+

Generic format observer functions +shall return strings formatted according to the generic pathname format +using preferred-separator. See [fs.os.examples].

+

path Requirements [path.req]

+

Template parameters named InputIterator are required to meet the +requirements for a C++ standard library InputIterator compliant iterator. The iterator's value type is required +to be one of: char, wchar_t. Collectively, these types are referred to as supported path character types.

+

Template parameters named Source are required to be one of:

+
    +
  • +

    A std::basic_string, std::basic_string_view, boost::container::basic_string or boost::basic_string_view specialization with a value type of one of the supported path character types.

  • +
  • +

    v3, deprecated: A container with a value type of one of the supported path character types.

  • +
  • +

    A pointer into a null terminated string. The value type is required + to be a supported path character type.

  • +
  • +

    A C-array of supported path character type containing a null terminated string.

  • +
  • +

    A boost::filesystem::directory_entry.

  • +
+ +

+path constructors [path.construct]

+ +
template <class Source>
+path(Source const& source, const codecvt_type& cvt=codecvt());
+ + +
template <class InputIterator>
+path(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt());
+ +
+

Effects: Stores the contents [begin,end) + of source in pathname, converting format and + encoding if required ([path.arg.convert]).

+
+

+path assignments [path.assign]

+ +
path& operator=(const path& p);
+path& operator=(path&& p) noexcept;
+template <class Source>
+path& operator=(Source const& source);
+path& assign(const path& p);
+path& assign(path&& p) noexcept;
+template <class Source>
+path& assign(Source const& source, const codecvt_type& cvt=codecvt());
+template <class InputIterator>
+path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt());
+ +
+

Effects: Stores the contents [begin,end) + or source or p in pathname, converting format and + encoding if required ([path.arg.convert]).

+

+ Returns: *this

+
+

path appends +[path.append]

+

The append operations use + operator/= to denote their semantic effect of appending + preferred-separator when needed.

+ +
path& operator/=(const path& p);
+path& append(const path& p);
+ +
+

Effects:

+
+

v3: Appends path::preferred_separator to pathname, + converting format and encoding if required ([path.arg.convert]), unless:

+
    +
  • +

    an added separator + would be redundant, or

  • +
  • +

    would change a relative path to an absolute path, or

  • +
  • +

    p.empty(), or

  • +
  • +

    *p.native().cbegin() is a directory separator.

  • +
+

Then appends p.native() to pathname.

+

v4: If p.is_absolute() || (p.has_root_name() && p.root_name() != root_name()), assigns p to *this. Otherwise, modifies *this as if by these steps: +

    +
  • If p.has_root_directory(), removes root directory and relative path, if any.
  • +
  • Let x be a path with contents of p without a root name. If has_filename() is true and x does not start with a directory separator, appends path::preferred_separator.
  • +
  • Appends x.native().
  • +
+

+

[Note: Whether the path is absolute or not depends on the target OS conventions. Because of this, the result of append operation may be different for different operating systems for some paths. For example, path("//net/foo") / "/bar" will result in "/bar" on POSIX systems and "//net/foo/bar" on Windows because "/bar" is an absolute path on POSIX systems but not on Windows. For portable behavior avoid appending paths with non-empty root path. —end note]

+
+

Returns: *this

+
+ +
template <class Source>
+path& operator/=(Source const & source);
+template <class Source>
+path& append(Source const & source, const codecvt_type& cvt=codecvt());
+template <class InputIterator>
+path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt());
+ +
+

Effects:

+
+

As if append(path(args)), where args is the list of arguments passed to the operation.

+
+

Returns: *this

+
+ +

path concatenation [path.concat]

+ +
path& operator+=(const path& p);
+path& operator+=(value_type x);
+template <class Source>
+path& operator+=(Source const& source);
+template <class CharT>
+path& operator+=(CharT x);
+path& concat(const path& p);
+template <class Source>
+path& concat(Source const& source, const codecvt_type& cvt=codecvt());
+template <class InputIterator>
+path& concat(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt());
+ +

Postcondition: native() == prior_native + effective-argument, + where prior_native is native() prior to the call to operator+=, + and effective-argument is:

+
  • +

    p.native() if p is present and is const path&, otherwise

  • +
  • +

    s, where s is + std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
    s(begin, end)
    , + if begin and end arguments are present, otherwise

  • +
  • +

    x.

If the value type of effective-argument would not be path::value_type, the actual argument or argument range is first + converted so that effective-argument has value type path::value_type.

+

Returns: *this

+
+

+path modifiers [path.modifiers]

+ +
void clear();
+ +
+

Postcondition: this->empty() is true.

+
+ +
path& make_preferred();
+ +
+

Effects: directory-separators are converted to preferred-separators. + See [fs.os.examples].

+

Returns: *this

+
+ + + +
path& remove_filename();
+ +
+

Effects: v3: As if, *this = parent_path();

+

[Note: This function is needed to efficiently implement directory_iterator. It is exposed to allow additional uses. The actual + implementation may be much more efficient than *this = parent_path()  —end + note]

+

v4: Removes the filename() path element.

+

[Note: Unlike v3, the trailing directory separator(s) are not removed.—end + note]

+

Returns: *this. +

+ +
path& remove_filename_and_trailing_separators();
+ +
+

Effects: As if, *this = parent_path();

+

[Note: This function is similar to path::remove_filename from v3, but is also usable in v4.—end + note]

+

Returns: *this. +

+ +
path& replace_filename(const path& replacement);
+ +
+

Effects: As if, remove_filename().append(replacement);

+

Returns: *this. +

+ +
path& replace_extension(const path& new_extension = path());
+ +
+

Effects:

+
    +
  • +

    Any existing extension() is removed from the stored path, + then

  • +
  • +

    iff + new_extension is not empty and does not begin with a dot + character, a dot character is appended to the stored path, then

  • +
  • +

    + new_extension is appended to the stored path.

  • +
+

Returns: *this

+
+ +
void swap(path& rhs) noexcept;
+ +
+

Effects: Swaps the contents of the two paths.

+

Complexity: constant time.

+
+ +

path lexical operations + [path.lex.ops]

+
path lexically_normal() const;
+
+

Overview: Returns *this with redundant current directory +(dot), parent directory (dot-dot), and directory-separator elements removed.

+

Returns: *this in normal form.

+

Remarks: Uses operator/= to compose the returned path.

+

[Example:

+

std::cout << path("foo/./bar/..").lexically_normal() << std::endl;    // outputs "foo"
+std::cout << path("foo/.///bar/../").lexically_normal() << std::endl; // v3: outputs "foo/."
+                                                                      // v4: outputs "foo/"

+

On Windows, the +returned path's directory-separator characters will be backslashes rather than slashes, but that +does not affect path equality. —end example]

+
+ +
path lexically_relative(const path& base) const;
+
+

Overview: Returns *this made relative to base. + Treats empty or identical paths as corner cases, not errors. Does not resolve + symlinks. Does not first normalize *this or base.

+ +

Remarks: Uses std::mismatch(begin(), end(), base.begin(), base.end()), to determine the first mismatched element of + *this and base. Uses operator== to + determine if elements match.

+ +

Returns:

+ +
    +
  • + path() if the first mismatched element of *this is equal to + begin() or the first mismatched element + of base is equal to base.begin(), or
      +
  • +
  • + path(".") if the first mismatched element of + *this is equal to + end() and the first mismatched element + of base is equal to base.end(), or
      +
  • +
  • An object of class path composed via application of + operator/= path("..") for each element in the half-open + range [first + mismatched element of base, base.end()), and then + application of operator/= for each element in the half-open + range + [first mismatched element of *this, end()). +
  • +
+ +

[Example:

+

assert(path("/a/d").lexically_relative("/a/b/c") == "../../d");
+assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c");
+assert(path("a/b/c").lexically_relative("a") == "b/c");
+assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
+assert(path("a/b/c").lexically_relative("a/b/c") == ".");
+assert(path("a/b").lexically_relative("c/d") == "");

+

The above assertions will succeed. On Windows, the +returned path's directory-separators will be backslashes rather than +forward slashes, but that +does not affect path equality. —end example]

+ +

[Note: If symlink following semantics are desired, use the operational function + relative  —end note]

+ +

[Note: If normalization is needed to ensure + consistent matching of elements, apply lexically_normal() + to *this, base, or both. —end note]

+ +
path lexically_proximate(const path& base) const;
+
+

Returns: If lexically_relative(base) returns a non-empty path, returns that path. +Otherwise returns *this.

+ +

[Note: If symlink following semantics are desired, use the operational function + relative  —end note]

+ +

[Note: If normalization is needed to ensure + consistent matching of elements, apply lexically_normal() + to *this, base, or both. —end note]

+ +
+ + +

path native format observers +[path.native.obs]

+

The string returned by all native format observers is in the native pathname format.

+ +
const string_type& native() const noexcept;
+ +
+

Returns: pathname.

+
+ +
const value_type* c_str() const noexcept;
+ +
+

Returns: pathname.c_str().

+
+ +
string_type::size_type size() const noexcept;
+ +
+

Returns: pathname.size().

+
+ +
template <class String>
+String string(const codecvt_type& cvt=codecvt()) const;
+ +
+

Returns: pathname.

+

Remarks: If string_type is a different type than String, conversion is performed by cvt.

+
+ +
string string(const codecvt_type& cvt=codecvt()) const;
+wstring wstring(const codecvt_type& cvt=codecvt()) const;
+ +
+

Returns: pathname.

+

Remarks: If string_type is a different type than +function's return type, conversion is performed by cvt.

+
+ +

path generic format observers +[path.generic.obs]

+

The string returned by all generic format observers is in the generic pathname format.

+ +
template <class String>
+String generic_string(const codecvt_type& cvt=codecvt()) const;
+ +
+

Returns: pathname.

+

Remarks: If string_type is a different type than String, conversion is performed by cvt.

+
+ +
string generic_string(const codecvt_type& cvt=codecvt()) const;
+wstring generic_wstring(const codecvt_type& cvt=codecvt()) const;
+ +
+

Returns: pathname.

+

Remarks:  If string_type is a different type than +function's return type, conversion is performed by cvt.

+
+ +

path compare [path.compare]

+ +
int compare(const path& p) const noexcept;
+ +
+

Returns: A value less than 0 if the elements of *this are lexicographically less than the elements of p, otherwise a + value greater than 0 if the elements of *this are + lexicographically greater than the elements of p, otherwise 0.

+

Remark: The elements are determined as if by iteration over the half-open + range [begin(), end()) for *this and  p.

+
+ +
int compare(const std::string& s) const
+ +
+

Returns: compare(path(s)).

+
+ +
int compare(const value_type* s) const
+ +
+

Returns: compare(path(s)).

+
+

path decomposition +[path.decompose]

+

See the Path decomposition table for examples +for values returned by decomposition functions. The Tutorial may also be +helpful.

+ +
path root_name() const;
+ +
+

Returns: root-name, if pathname includes root-name, otherwise path().

+
+ +
path root_directory() const;
+ +
+

Returns: root-directory, if pathname includes root-directory, otherwise path().

+

If root-directory is composed of slash name, slash is +excluded from the returned string.

+
+ +
path root_path() const;
+ +
+

Returns: root_name() / root_directory()

+
+ +
path relative_path() const;
+ +
+

Returns: A path composed from pathname, if !empty(), beginning +with the first filename after root-path. Otherwise, path().

+
+ +
path parent_path() const;
+ +
+

Returns: (empty() || begin() == --end()) ? path() : pp, where pp is constructed as if by + starting with an empty path and successively applying operator/= for each element in the range begin(), --end().

+

[Example:

+
+ +
std::cout << path("/foo/bar.txt").parent_path(); // outputs "/foo"
+std::cout << path("/foo/bar").parent_path();     // outputs "/foo"
+std::cout << path("/foo/bar/").parent_path();    // outputs "/foo/bar"
+std::cout << path("/").parent_path();            // outputs ""
+std::cout << path(".").parent_path();            // outputs ""
+std::cout << path("..").parent_path();           // outputs ""
+ +
+

See the last bullet item in the + forward traversal order list for why the "/foo/bar/" example + doesn't output "/foo".

+

—end example]

+
+ +
path filename() const;
+ +
+

Returns: v3: empty() ? path() : *--end()
+ v4: *this == root_path() ? path() : *--end()

+

[Example:

+
+ +
std::cout << path("/foo/bar.txt").filename(); // outputs "bar.txt"
+std::cout << path("/foo/bar").filename();     // outputs "bar"
+std::cout << path("/foo/bar/").filename();    // v3 outputs "."
+                                              // v4 outputs ""
+std::cout << path("/").filename();            // v3 outputs "/"
+                                              // v4 outputs ""
+std::cout << path(".").filename();            // outputs "."
+std::cout << path("..").filename();           // outputs ".."
+ +
+

See the last bullet item in the + forward traversal order list for why the "/foo/bar/" example + doesn't output "bar".

+

—end example]

+
+ +
path stem() const;
+ +
+

Returns: If p.filename() does not contain dots, consist solely of one + or to two dots, [Since v4: or contains exactly one dot as the initial character,] returns p.filename(). + Otherwise returns the substring of p.filename() starting at its beginning and + ending at the last dot (the dot is not included).

+

[Example:

+
+ +
std::cout << path("/foo/bar.txt").stem() << '\n'; // outputs "bar"
+std::cout << path(".hidden").stem() << '\n';      // v3 outputs ""
+                                                  // v4 outputs ".hidden"
+path p = "foo.bar.baz.tar";
+for (; !p.extension().empty(); p = p.stem())
+  std::cout << p.extension() << '\n';
+  // outputs: .tar
+  //          .baz
+  //          .bar
+ +
+

—end example]

+
+ +
path extension() const;
+ +
+

Returns: The substring of p.filename() that is not included + in p.stem().

+

Remarks: Implementations are permitted but not required to define additional + behavior for file systems which append additional elements to extensions, such + as alternate data streams or partitioned dataset names.

+

[Example:

+
+ +
std::cout << path("/foo/bar.txt").extension(); // outputs ".txt"
+ +
+

—end example]

+

[Note: The dot is included in the return value so that it is + possible to distinguish between no extension and an empty extension. + See + https://lists.boost.org/Archives/boost/2010/02/162028.php for more + extensive rationale.  —end note]

+
+

path query [path.query]

+ +
bool empty() const;
+ +
+

Returns: m_pathname.empty().

+
+ +
bool filename_is_dot() const;
+ +
+

Returns: filename() == path(".")

+

[Example:

+
+ +
std::cout << path(".").filename_is_dot();     // outputs 1
+std::cout << path("/.").filename_is_dot();    // outputs 1
+std::cout << path("foo/.").filename_is_dot(); // outputs 1
+std::cout << path("foo/").filename_is_dot();  // v3 outputs 1, v4 outputs 0
+std::cout << path("/").filename_is_dot();     // outputs 0
+std::cout << path("/foo").filename_is_dot();  // outputs 0
+std::cout << path("/foo.").filename_is_dot(); // outputs 0
+std::cout << path("..").filename_is_dot();    // outputs 0
+ +
+

See the last bullet item in the forward traversal order + list for why path("foo/").filename() is a dot filename in v3.

+

—end example]

+
+ +
bool filename_is_dot_dot() const;
+ +
+

Returns: filename() == path("..")

+
+ +
bool has_root_path() const;
+ +
+

Returns: !root_path().empty()

+
+ +
bool has_root_name() const;
+ +
+

Returns: !root_name().empty()

+
+ +
bool has_root_directory() const;
+ +
+

Returns: !root_directory().empty()

+
+ +
bool has_relative_path() const;
+ +
+

Returns: !relative_path().empty()

+
+ +
bool has_parent_path() const;
+ +
+

Returns: !parent_path().empty()

+
+ +
bool has_filename() const;
+ +
+

Returns: !filename().empty()

+
+ +
bool has_stem() const;
+ +
+

Returns: !stem().empty()

+
+ +
bool has_extension() const;
+ +
+

Returns: !extension().empty()

+
+ +
bool is_absolute() const;
+ +
+

Returns: true if the elements of root_path() uniquely identify a directory, else false.

+

[Note: Path is considered absolute on POSIX systems if it has a root directory, and on Windows - if it has both root name and root directory. —end note]

+
+ +
bool is_relative() const;
+ +
+

Returns: !is_absolute().

+
+

+path iterators [path.itr]

+

Path iterators iterator, const_iterator, +reverse_iterator, and const_reverse_iterator iterate over the elements of the stored pathname.

+

Path iterators are constant iterators satisfying +the requirements of a bidirectional iterator (C++ Std, 24.1.4 Bidirectional +iterators [lib.bidirectional.iterators]). The value_type  of +an iterator is path.

+
+

[Note: Path iterators store their value objects internally +and when dereferenced return references to those internal objects. They cannot +be used with iterator adaptors such as std::reverse_iterator that +assume references obtained by dereferencing an iterator point to objects that +out-live the iterator itself. —end note]

+
+

Calling any non-const member function of a path object + invalidates all iterators referring to elements of that object.

+

The forward traversal order is as follows:

+
    +
  • The root-name element, if present.
  • +
  • The root-directory element, if present, in the generic format. + [Note: the generic format is required to ensure lexicographical + comparison works correctly. —end note]
  • +
  • Each successive filename element, if present.
  • +
  • [v3: Dot] [v4: Empty path], if one or more trailing non-root directory separators + are present.
  • +
+
+

[Note: Treating the last element during iteration as [v3: dot] [v4: an empty path] when + there is a trailing directory separator enables lexical (i.e. syntactic) + distinction between paths to directories versus paths to regular files. Such a + distinction is usually irrelevant on POSIX and Windows based operating + systems, but may be a requirement on other operating systems. —end note]

+
+

The backward traversal order is the reverse of forward traversal.

+
iterator begin() const;
+
+

Returns: An iterator for the first element in forward traversal + order. If no elements are present, the end iterator.

+
+
iterator end() const;
+
+

Returns: The end iterator.

+
+
reverse_iterator rbegin() const;
+
+

Returns: An iterator for the first element in backward traversal + order. If no elements are present, the end iterator.

+
+
reverse_iterator rend() const;
+
+

Returns: The end iterator.

+
+

path + imbued locale [path.imbued.locale]

+

path operations sometimes require encoding conversions between + pathname and some other string object where one of the value types + is char and the other is wchar_t. Such conversions + shall be performed by the path::codecvt() facet.

+
+

[Example: + ... —end example]

+
+
static std::locale imbue(const std::locale& loc);
+
+

Effects: Stores a copy of loc as the imbued path + locale.

+

Returns: The previous imbued path locale.

+

Remarks: The initial value of the imbued path locale is + operating system dependent. It shall be a locale with a codecvt + facet for a char string encoding appropriate for the operating + system. See ([fs.os.examples]). 

+
+
static const codecvt_type& codecvt();
+
+

Returns: The codecvt facet for the imbued path + locale .

+
+ + +

path deprecated functions

+

Several member functions from previous versions of class path have been deprecated, either because they have been renamed or because the +functionality is no longer desirable or has become obsolete.

+

Deprecated functions available by default; will be suppressed if BOOST_FILESYSTEM_NO_DEPRECATED is defined:

+
+
path&  remove_leaf()           { return remove_filename(); }
+path   leaf() const            { return filename(); }
+path   branch_path() const     { return parent_path(); }
+bool   has_leaf() const        { return !m_path.empty(); }
+bool   has_branch_path() const { return !parent_path().empty(); }
+
+

Deprecated functions not available by default; will be supplied if BOOST_FILESYSTEM_DEPRECATED is defined:

+
+
const std::string  file_string() const               { return native_string(); }
+const std::string  directory_string() const          { return native_string(); }
+const std::string  native_file_string() const        { return native_string(); }
+const std::string  native_directory_string() const   { return native_string(); }
+const string_type  external_file_string() const      { return native(); }
+const string_type  external_directory_string() const { return native(); }
+
+ +

path non-member functions +[path.non-member]

+ +
bool lexicographical_compare(path::iterator first1, path::iterator last1,
+                             path::iterator first2, path::iterator last2);
+
+

Returns: true if the sequence of native() strings for the elements defined by the half-open range [first1, last1) is + lexicographically less than the sequence of native() strings for + the elements defined by the half-open range [first2, last2). Returns false otherwise.

+

Remarks: If two sequences have the same number of elements and their + corresponding elements are equivalent, then neither sequence is + lexicographically less than the other. If one sequence is a prefix of the + other, then the shorter sequence is lexicographically less than the longer + sequence. Otherwise, the lexicographical comparison of the sequences yields + the same result as the comparison of the first corresponding pair of elements + that are not equivalent.

+

[Note: A path aware lexicographical_compare algorithm is provided for historical reasons. —end note]

+
+ +
+ +
path lexically_normal(const path& p);
+ +
+ +
+

Overview: Returns p with redundant current + directory (dot), parent directory (dot-dot), and + directory-separator elements removed.

+

Returns: p in + + normal form.

+

Remarks: Uses operator/= to compose the + returned path.

+

[Example:

+

assert(lexically_normal("foo/./bar/..") == "foo");
+ assert(lexically_normal("foo/.///bar/../") == "foo/.");

+

All of the above assertions will succeed. On Windows, the + returned path's directory-separator characters will be backslashes + rather than slashes, but that does not affect path equality. + —end example]

+
+ +
+ +
path lexically_relative(const path& p, const path& base);
+ +
+ +
+

Overview: Returns p made relative to + base. Treats empty or identical paths as corner cases, not errors. Does + not resolve symlinks. Does not first normalize p or base.

+

Remarks: Uses std::mismatch(p.begin(), p.end(), + base.begin(), base.end()), to determine the first mismatched element of + p and base. Uses operator== to + determine if elements match.

+

Returns:

+
    +
  • +

    path() if the first mismatched element of p + is equal to p.begin() or the first mismatched element of + base is equal to base.begin(), or
    +  

  • +
  • +

    path(".") if the first mismatched element of + p is equal to p.end() and the first mismatched element + of base is equal to base.end(), or
    +  

  • +
  • +

    An object of class path composed via application + of operator/= path("..") for each element in the half-open + range [first mismatched element of base, base.end()), + and then application of operator/= for each element in the + half-open range [first mismatched element of p, p.end()). +

  • +
+

[Example:

+

assert(lexically_relative("/a/d", "/a/b/c") == "../../d");
+ assert(lexically_relative("/a/b/c", "/a/d") == "../b/c");
+ assert(lexically_relative("a/b/c", "a") == "b/c");
+ assert(lexically_relative("a/b/c", "a/b/c/x/y") == "../..");
+ assert(lexically_relative("a/b/c", "a/b/c") == ".");
+ assert(lexically_relative("a/b", "c/d") == "");

+

All of the above assertions will succeed. On Windows, the + returned path's directory-separators will be backslashes rather than + forward slashes, but that does not affect path equality. —end + example]

+

[Note: If symlink following semantics are desired, use the + operational function + + relative  —end note]

+

[Note: If normalization is needed to ensure consistent matching of elements, wrap + p, base, or both in calls + lexically_normal(). —end note]

+
+
void swap(path& lhs, path& rhs) noexcept;
+
+

Effects: lhs.swap(rhs).

+
+
std::size_t hash_value(const path& p);
+
+

Returns: A hash value for the path p. If + for two paths, p1 == p2 then hash_value(p1) == hash_value(p2).

+

This allows paths to be used with Boost.Hash.

+
+
bool operator< (const path& lhs, const path& rhs);
+
+

Returns: return lhs.compare(rhs.begin) < 0.

+
+
bool operator<=(const path& lhs, const path& rhs);
+
+

Returns: !(rhs < lhs).

+
+
bool operator> (const path& lhs, const path& rhs);
+
+

Returns: rhs < lhs.

+
+
bool operator>=(const path& lhs, const path& rhs);
+
+

Returns: !(lhs < rhs).

+
+
bool operator==(const path& lhs, const path& rhs);
+
+

Returns: !(lhs < rhs) && !(rhs < lhs).

+

[Note: Path equality and path + equivalence have different semantics.

+

Equality is determined by the path non-member operator==, which considers the two path's lexical + representations only. Thus path("foo") == "bar" is never true.

+

Equivalence is determined by the equivalent() non-member function, which determines if two paths resolve to the same file system entity. + Thus equivalent("foo", "bar") will be true when both paths resolve to the same file.

+

Programmers wishing to determine if two paths are "the same" must decide if + "the same" means "the same representation" or "resolve to the same actual + file", and choose the appropriate function accordingly. —end note]

+
+
bool operator!=(const path& lhs, const path& rhs);
+
+

Returns: !(lhs == rhs).

+
+
path operator/ (const path& lhs, const path& rhs);
+
+

Returns: path(lhs) /= rhs.

+
+

path inserter + and extractor [path.io]

+

The inserter and extractor delimit the string with double-quotes (") +so that paths with embedded spaces will round trip correctly. Ampersand (&) +is as an escape character, so the path can itself contain double quotes.

+
template <class Char, class Traits>
+std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
+                                             const path& p);
+
+
+

Effects: Insert characters into os:

+
    +
  • +

    A double-quote.

    +
  • +
  • +

    Each character in p.string<std::basic_string<Char>>(). + If the character to be inserted is equal to the escape character or a + double-quote, as determined by operator==, first insert the + escape character.

    +
  • +
  • +

    A double-quote.

    +
  • +
+

[Note: Effects are similar to: +

std::basic_string<Char> str(p.string<std::basic_string<Char>>());
+os << boost::io::quoted(str, static_cast<Char>('&'));
+—end note]

+

Returns: os

+
+
template <class Char, class Traits>
+std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is,
+                                             path& p);
+
+
+

Effects:  Extract characters from is:

+
    +
  • If the first character that would be extracted is equal to double-quote, + as determined by operator==, then:
      +
    • Discard the initial double-quote.
    • +
    • Save the value and then turn off the skipws flag.
    • +
    • p.clear()
    • +
    • Until an unescaped double-quote character is reached or + is.not_good(), extract characters from is and append + them to p, except that if an escape character is reached, + ignore it and append the next character to p.
    • +
    • Discard the final double-quote character.
    • +
    • Restore the skipws flag to its original value.
    • +
    +
  • +
  • Otherwise, is >> p.
  • +
+

[Note: Effects are similar to: +

std::basic_string<Char> str;
+is >> boost::io::quoted(str, static_cast<Char>('&'));
+p = str;
—end note]

+

Returns: is

+
+

Class filesystem_error +[class.filesystem_error]

+
namespace boost
+{
+  namespace filesystem
+  {
+      class filesystem_error : public system_error
+      {
+      public:
+        filesystem_error();
+        filesystem_error(const filesystem_error&);
+        filesystem_error(const std::string& what_arg,
+          system::error_code ec);
+        filesystem_error(const std::string& what_arg,
+          const path& p1, system::error_code ec);
+        filesystem_error(const std::string& what_arg,
+          const path& p1, const path& p2, system::error_code ec);
+
+        filesystem_error& filesystem_error(const filesystem_error&);
+       ~filesystem_error();
+
+        filesystem_error& operator=(const filesystem_error&);
+
+        const path& path1() const;
+        const path& path2() const;
+
+        const char * what() const;
+      };
+  }  // namespace filesystem
+}  // namespace boost
+

The class template filesystem_error defines the type of +objects thrown as exceptions to report file system errors from functions described in this +reference documentation.

+

filesystem_error members +[filesystem_error.members]

+
filesystem_error(const std::string& what_arg, error_code ec);
+
+

Postcondition:

+ + + + + + + + + + + + + + + + + + + + + +
ExpressionValue
+ runtime_error::what() + what_arg.c_str()
code()ec
path1().empty()true
path2().empty()true
+
+
filesystem_error(const std::string& what_arg, const path& p1, error_code ec);
+
+

Postcondition:

+ + + + + + + + + + + + + + + + + + + + + +
ExpressionValue
+ runtime_error::what() + what_arg.c_str()
code()ec
path1()Reference to stored copy of p1
path2().empty()true
+
+
filesystem_error(const std::string& what_arg, const path& p1, const path& p2, error_code ec);
+
+

Postcondition:

+ + + + + + + + + + + + + + + + + + + + + +
ExpressionValue
+ runtime_error::what() + + what_arg.c_str()
code()ec
path1()Reference to stored copy of p1
path2()Reference to stored copy of p2
+
+
const path& path1() const;
+
+

Returns: Reference to copy of p1 stored by the + constructor, or, if none, an empty path.

+
+
const path& path2() const;
+
+

Returns: Reference to copy of p2 stored by the + constructor, or, if none, an empty path.

+
+
const char* what() const;
+
+

Returns: A string containing runtime_error::what(). The exact format is unspecified. + Implementations are encouraged but not required to include path1.native_string()if not empty, path2.native_string()if + not empty, and system_error::what() strings in the returned + string.

+
+

Enum file_type [enum.file_type]

+

This enum specifies constants uses to identify file types.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Constant NameMeaning
status_errorAn error occurred while trying to obtain the status of the file. The + file simply not being found is not considered a status error.
file_not_foundThe file could not be found
regular_fileRegular file
directory_fileDirectory file
symlink_fileSymbolic link file
block_fileBlock special file
character_fileCharacter special file
fifo_fileFIFO or pipe file
socket_fileSocket file
type_unknownThe file exists, but it is of a system specific type not covered by any + of the above cases.
+

Enum perms [enum.perms]

+

This enum specifies bitmask constants uses to identify file +permissions. ISO/IEC 9945 +(POSIX) specifies actual values, and those values have been adopted here because +they are very familiar and ingrained for many POSIX +users.

+
+

Windows: All permissions except write are currently ignored. There is only a +single write permission; setting write permission for owner, group, or others +sets write permission for all, and removing write permission for owner, group, +or others removes write permission for all.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValue
+ (octal)
ISO/IEC 9945
+ macro
Definition or notes
+

no_perms

0There are no permissions set for the file. Note: file_not_found is no_perms rather than perms_not_known
owner_read0400 S_IRUSR Read permission, owner
owner_write0200 S_IWUSR Write permission, owner
owner_exe0100 S_IXUSR Execute/search permission, owner
owner_all0700 S_IRWXU Read, write, execute/search by owner; owner_read | owner_write | owner_exe
group_read040 S_IRGRP Read permission, group
group_write020 S_IWGRP Write permission, group
group_exe010 S_IXGRP Execute/search permission, group
group_all070 S_IRWXG Read, write, execute/search by group; group_read | group_write | group_exe
others_read04 S_IROTH Read permission, others
others_write02 S_IWOTH Write permission, others
others_exe01 S_IXOTH Execute/search permission, others
others_all07 S_IRWXORead, write, execute/search by others; others_read | others_write | others_exe
all_all0777 owner_all | group_all | others_all
set_uid_on_exe04000 S_ISUID Set-user-ID on execution
set_gid_on_exe02000 S_ISGID Set-group-ID on execution
sticky_bit 01000 S_ISVTX Operating system dependent. Inherently non-portable, even between ISO/IEC 9945 + operating systems.
perms_mask07777  all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit
perms_not_known0xFFFF + The permissions are not known, such as when a file_status object + is created without specifying the permissions
+

add_perms

0x1000 +

permissions() adds the argument permission bits to the + file's current bits

remove_perms0x2000 + permissions() removes the argument permission bits from the + file's current bits
symlink_perms0x4000 + On ISO/IEC 9945 + permissions() resolves symlinks unless + symlink_perms is specified. + Meaningless on Windows as + permissions() never resolves symlinks. + Meaningless on Mac OS X and some other BSD systems as + permissions() always resolves symlinks. Get over it.
+

Class file_status [class.file_status]

+
namespace boost
+{
+  namespace filesystem
+  {
+      class file_status
+      {
+      public:
+
+        // constructors
+        file_status() noexcept;
+        explicit file_status(file_type ft, perms prms = perms_not_known) noexcept;
+
+        // compiler generated
+        file_status(const file_status&) noexcept;
+        file_status& operator=(const file_status&) noexcept;
+       ~file_status() noexcept;
+
+        // observers
+        file_type  type() const noexcept;
+        perms      permissions() const noexcept;
+
+        // modifiers
+        void       type(file_type ft) noexcept;
+        void       permissions(perms prms) noexcept;
+      };
+  }  // namespace filesystem
+}  // namespace boost
+

An object of type file_status stores information about the type +and permissions of a file.

+

file_status constructors +[file_status.cons]

+
explicit file_status() noexcept;
+
+

Postconditions: type() == status_error, permissions() == perms_not_known.

+
+
explicit file_status(file_type ft, perms prms = perms_not_known) noexcept;
+
+

Postconditions: type() == ft, permissions() == prms.

+
+

file_status observers [file_status.obs]

+
file_type type() const noexcept;
+
+

Returns: The value of type() specified by the postconditions of the most recent call to a constructor, operator=, or type(file_type) function.

+
+
perms permissions() const noexcept;
+
+

Returns: The value of permissions() specified by the postconditions of the most recent call to a constructor, operator=, or permissions(perms) function.

+
+

file_status modifiers [file_status.mods]

+
void type(file_type ft) noexcept;
+
+

Postconditions: type() == ft.

+
+
void permissions(perms prms) noexcept;
+
+

Postconditions: permissions() == prms.

+
+

Class directory_entry [class.directory_entry]

+ +
namespace boost
+{
+  namespace filesystem
+  {
+      class directory_entry
+      {
+      public:
+
+        // constructors and destructor
+        directory_entry();
+        directory_entry(const directory_entry&);
+        explicit directory_entry(const path& p);
+        directory_entry(const path& p, system::error_code& ec);       // v4-only
+        directory_entry(const path& p, file_status st,                // v3-only
+          file_status symlink_st=file_status());
+       ~directory_entry();
+
+        // modifiers
+        directory_entry& operator=(const directory_entry&);
+        void assign(const path& p);
+        void assign(const path& p, system::error_code& ec);           // v4-only
+        void assign(const path& p, file_status st,                    // v3-only
+          file_status symlink_st=file_status());
+        void replace_filename(const path& p);
+        void replace_filename(const path& p, system::error_code& ec); // v4-only
+        void replace_filename(const path& p, file_status st,          // v3-only
+          file_status symlink_st=file_status());
+
+        void refresh();
+        void refresh(system::error_code& ec);
+
+        // observers
+        const path&  path() const;
+
+        file_status  status() const;
+        file_status  status(system::error_code& ec) const;
+        file_status  symlink_status() const;
+        file_status  symlink_status(system::error_code& ec) const;
+        file_type file_type() const;
+        file_type file_type(system::error_code& ec) const;
+        file_type symlink_file_type() const;
+        file_type symlink_file_type(system::error_code& ec) const;
+
+        bool exists() const;
+        bool exists(system::error_code& ec) const;
+        bool is_regular_file() const;
+        bool is_regular_file(system::error_code& ec) const;
+        bool is_directory() const;
+        bool is_directory(system::error_code& ec) const;
+        bool is_symlink() const;
+        bool is_symlink(system::error_code& ec) const;
+        bool is_block_file() const;
+        bool is_block_file(system::error_code& ec) const;
+        bool is_character_file() const;
+        bool is_character_file(system::error_code& ec) const;
+        bool is_fifo() const;
+        bool is_fifo(system::error_code& ec) const;
+        bool is_socket() const;
+        bool is_socket(system::error_code& ec) const;
+        bool is_reparse_file() const;
+        bool is_reparse_file(system::error_code& ec) const;
+        bool is_other() const;
+        bool is_other(system::error_code& ec) const;
+
+        bool operator< (const directory_entry& rhs);
+        bool operator==(const directory_entry& rhs);
+        bool operator!=(const directory_entry& rhs);
+        bool operator< (const directory_entry& rhs);
+        bool operator<=(const directory_entry& rhs);
+        bool operator> (const directory_entry& rhs);
+        bool operator>=(const directory_entry& rhs);
+      private:
+        path                 m_path;           // for exposition only
+        mutable file_status  m_status;         // for exposition only; stat()-like
+        mutable file_status  m_symlink_status; // for exposition only; lstat()-like
+      };
+
+  }  // namespace filesystem
+}  // namespace boost
+ +

A directory_entry object stores a path object, +as well as some amount of cached information about the file identified by the path. +Currently, the cached information includes a file_status object for non-symbolic +link status and a file_status object for symbolic link status.

+
+

[Note: Because status() on a pathname may be a relatively expensive operation, +some operating systems provide status information as a byproduct of directory +iteration. Caching such status information can result is significant time savings. Cached and +non-cached results may differ in the presence of file system races. —end note]

+

Actual cold-boot timing of iteration over +a directory with 15,047 entries was six seconds for non-cached status queries +versus one second for cached status queries. Windows XP, 3.0 GHz processor, with +a moderately fast hard-drive. Similar speedups are expected on Linux and BSD-derived +systems that provide status as a by-product of directory iteration.

+

[Note: The exact set of cached information may vary from one Boost.Filesystem version +to another, and also between different operating systems and underlying file systems. Users' code +must not rely on whether a certain piece of information is cached or not. This means that calling +most observers and modifiers of directory_entry may or may not result in a filesystem +query that may potentially fail. Information caching is exclusively a performance feature aimed +at reducing the amount of such queries. —end note]

+
+

directory_entry constructors +[directory_entry.cons]

+
directory_entry();
+
+

Postcondition:

+ + + + + + + + + + + + + + + + + +
ExpressionValue
path().empty()true
status()file_status()
symlink_status()file_status()
+
+
explicit directory_entry(const path& p);
+directory_entry(const path& p, system::error_code& ec); // v4-only
+
+

Effects:

+

v3: Initializes m_path from p and default-constructs m_status and m_symlink_status.

+

[Note: The cached file statuses will be updated when queried by the caller or by an explicit call to refresh. —end note]

+

v4: Initializes m_path from p and calls refresh() or refresh(ec), respectively.

+

Postcondition: path() == p if no error occurs, otherwise path().empty() == true.

+
+
directory_entry(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only
+
+

v3: Postcondition:

+ + + + + + + + + + + + + + + + + +
ExpressionValue
path()p
status()st
symlink_status()symlink_st
+
+

directory_entry modifiers +[directory_entry.mods]

+
void assign(const path& p);
+void assign(const path& p, system::error_code& ec); // v4-only
+
+

Effects:

+

v3: Assigns p to m_path and file_status() to m_status and m_symlink_status.

+

[Note: The cached file statuses will be updated when queried by the caller or by an explicit call to refresh. —end note]

+

v4: Assigns p to m_path and calls refresh() or refresh(ec), respectively. If an error + occurs, the value of the cached data is unspecified.

+
+
void assign(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only
+
+

v3: Postcondition:

+ + + + + + + + + + + + + + + + + +
ExpressionValue
path()p
status()st
symlink_status()symlink_st
+
+
void replace_filename(const path& p);
+void replace_filename(const path& p, system::error_code& ec); // v4-only
+
+

Effects:

+

v3: Calls m_path.replace_filename(p) and assigns file_status() to m_status and m_symlink_status.

+

[Note: The cached file statuses will be updated when queried by the caller or by an explicit call to refresh. —end note]

+

v4: Calls m_path.replace_filename(p) and then refresh() or refresh(ec), respectively. If an error + occurs, the value of the cached data is unspecified.

+
+
void replace_filename(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only
+
+

Effects: v3: Calls m_path.replace_filename(p) and assigns st to m_status and symlink_st + to m_symlink_status.

+
+
void refresh();
+void refresh(system::error_code& ec);
+
+

Effects: Updates any cached data by querying the filesystem about the file identified by m_path. If an error occurs, + the value of the cached data is unspecified.

+
+

directory_entry observers +[directory_entry.obs]

+
const path& path() const;
+
+

Returns: m_path

+
+
file_status status() const;
+file_status status(system::error_code& ec) const;
+
+

Effects: If !status_known(m_status), calls refresh() or refresh(ec), respectively.

+

Returns: m_status

+

Throws: As specified in Error reporting.

+
+
file_status  symlink_status() const;
+file_status  symlink_status(system::error_code& ec) const;
+
+

Effects: If !status_known(m_symlink_status), calls refresh() or refresh(ec), respectively.

+

Returns: m_symlink_status

+

Throws: As specified in Error reporting.

+
+
file_type file_type() const;
+file_type file_type(system::error_code& ec) const;
+
+

Effects: Equivalent to status().type() or status(ec).type(), respectively.

+

[Note: The implementation may be more efficient than calling status, if the information + about the file type is cached, but permissions are not. —end note]

+
+
file_type symlink_file_type() const;
+file_type symlink_file_type(system::error_code& ec) const;
+
+

Effects: Equivalent to symlink_status().type() or symlink_status(ec).type(), respectively.

+

[Note: The implementation may be more efficient than calling symlink_status, if the information + about the file type is cached, but permissions are not. —end note]

+
+
bool exists() const;
+bool exists(system::error_code& ec) const;
+
+

Effects: Equivalent to exists(status()) or exists(status(ec)), respectively.

+
+
bool is_regular_file() const;
+bool is_regular_file(system::error_code& ec) const;
+
+

Effects: Equivalent to is_regular_file(status()) or is_regular_file(status(ec)), respectively.

+
+
bool is_directory() const;
+bool is_directory(system::error_code& ec) const;
+
+

Effects: Equivalent to is_directory(status()) or is_directory(status(ec)), respectively.

+
+
bool is_symlink() const;
+bool is_symlink(system::error_code& ec) const;
+
+

Effects: Equivalent to is_symlink(symlink_status()) or is_symlink(symlink_status(ec)), respectively.

+
+
bool is_block_file() const;
+bool is_block_file(system::error_code& ec) const;
+
+

Effects: Equivalent to is_block_file(status()) or is_block_file(status(ec)), respectively.

+
+
bool is_character_file() const;
+bool is_character_file(system::error_code& ec) const;
+
+

Effects: Equivalent to is_character_file(status()) or is_character_file(status(ec)), respectively.

+
+
bool is_fifo() const;
+bool is_fifo(system::error_code& ec) const;
+
+

Effects: Equivalent to is_fifo(status()) or is_fifo(status(ec)), respectively.

+
+
bool is_socket() const;
+bool is_socket(system::error_code& ec) const;
+
+

Effects: Equivalent to is_socket(status()) or is_socket(status(ec)), respectively.

+
+
bool is_reparse_file() const;
+bool is_reparse_file(system::error_code& ec) const;
+
+

Effects: Equivalent to is_reparse_file(symlink_status()) or is_reparse_file(symlink_status(ec)), respectively.

+
+
bool is_other() const;
+bool is_other(system::error_code& ec) const;
+
+

Effects: Equivalent to is_other(status()) or is_other(status(ec)), respectively.

+
+
bool operator==(const directory_entry& rhs);
+
+

Returns: m_path == rhs.m_path.

+
+
bool operator!=(const directory_entry& rhs);
+
+

Returns: m_path != rhs.m_path.

+
+
bool operator< (const directory_entry& rhs);
+
+

Returns: m_path < rhs.m_path.

+
+
bool operator<=(const directory_entry& rhs);
+
+

Returns: m_path <= rhs.m_path.

+
+
bool operator> (const directory_entry& rhs);
+
+

Returns: m_path > rhs.m_path.

+
+
bool operator>=(const directory_entry& rhs);
+
+

Returns: m_path >= rhs.m_path.

+
+

Class directory_iterator +[class.directory_iterator]

+

Objects of type directory_iterator provide standard library +compliant iteration over the contents of a directory. Also see class recursive_directory_iterator.

+
namespace boost
+{
+  namespace filesystem
+  {
+      class directory_iterator
+      {
+      public:
+        // member functions
+
+        directory_iterator() noexcept;  // creates the "end" iterator
+        directory_iterator(const directory_iterator&);
+        explicit directory_iterator(const path& p, directory_options opts = directory_options::none);
+        directory_iterator(const path& p, system::error_code& ec);
+        directory_iterator(const path& p, directory_options opts, system::error_code& ec);
+       ~directory_iterator();
+
+        directory_iterator& operator=(const directory_iterator&);
+
+        directory_iterator& operator++();
+        directory_iterator& increment(system::error_code& ec);
+
+        // other members as required by
+        //  C++ Std, 24.1.1 Input iterators [input.iterators]
+      };
+
+  }  // namespace filesystem
+}  // namespace boost
+

directory_iterator satisfies the requirements of an +input iterator (C++ Std, 24.2.1, Input iterators [input.iterators]).

+

A directory_iterator reads successive elements from the directory for +which it was constructed, as if by calling ISO/IEC 9945 readdir() or readdir_r(). After a directory_iterator is constructed, and every time operator++ is called, +it reads a directory element and stores information about it in an object of type directory_entry. operator++ is not equality preserving; that is, i == j does not imply that ++i == ++j.

+
+

[Note: The practical consequence of not preserving equality is that directory iterators +can only be used for single-pass algorithms. —end note]

+
+

If the end of the directory elements is reached, the iterator shall become equal to +the end iterator value. The constructor directory_iterator() with no arguments always constructs an end iterator object, which +shall be the only valid iterator for the end condition. The result of operator* on an end iterator is not defined. For any other iterator value +a const directory_entry& is returned. The result of operator-> on an end iterator is +undefined behavior. For any other iterator value a const directory_entry* is +returned.

+

Two end iterators are always equal. An end iterator shall not be equal to a non-end +iterator.

+
+

The above wording is based on the +Standard Library's istream_iterator wording.

+
+

The result of calling the path() member of the directory_entry object obtained by dereferencing a directory_iterator is a reference to a path object composed of the directory argument from which the iterator was +constructed with filename of the directory entry appended as if by operator/=.

+

Directory iteration shall not yield directory entries for the current (dot) +and parent (dot dot) directories.

+

The order of directory entries obtained by dereferencing successive +increments of a directory_iterator is unspecified.

+
+

[Note: Programs performing directory iteration may wish to test if the +path obtained by dereferencing a directory iterator actually exists. It could be +a +symbolic link to a non-existent file. Programs recursively +walking directory trees for purposes of removing and renaming entries may wish +to avoid following symbolic links.

+

If a file is removed from or added to a directory after the +construction of a directory_iterator for the directory, it is +unspecified whether or not subsequent incrementing of the iterator will ever +result in an iterator whose value is the removed or added directory entry. See +ISO/IEC 9945 readdir_r(). —end note]

+
+

directory_iterator members +[directory_iterator.members]

+ +

directory_iterator() +noexcept;

+ +
+ +

Effects: Constructs the end iterator.

+ +
+ +
explicit directory_iterator(const path& p, directory_options opts = directory_options::none);
+directory_iterator(const path& p, system::error_code& ec);
+directory_iterator(const path& p, directory_options opts, system::error_code& ec);
+
+ +

Effects: Constructs an iterator representing the first +entry in the directory p resolves to, if any; otherwise, the end iterator. +If opening the directory fails with a permission_denied error and (opts & directory_options::skip_permission_denied) != 0, +constructs the end iterator and ignores the error (the operation completes successfully). If opts is not specified, it is assumed to be directory_options::none.

+ +

Throws: As specified in Error reporting.

+ +

[Note: To iterate over the current directory, use directory_iterator(".") rather than directory_iterator(""). —end note]

+
+
directory_iterator& operator++();
+directory_iterator& increment(system::error_code& ec);
+
+ +

Effects: As specified by the C++ Standard, 24.1.1 Input iterators [input.iterators]. In case of error the iterator is left in the end state.

+ +

Returns: *this.

+ +

Throws: As specified in Error reporting.

+ +
+

directory_iterator non-member functions

+
const directory_iterator& begin(const directory_iterator& iter);
+
+

Returns: iter.

+
+
directory_iterator end(const directory_iterator&);
+
+

Returns: directory_iterator().

+
+

Class recursive_directory_iterator +[class.rec.dir.itr]

+

Objects of type recursive_directory_iterator provide standard library +compliant iteration over the contents of a directory, including recursion into +its sub-directories.

+
namespace boost
+{
+  namespace filesystem
+  {
+      class recursive_directory_iterator :
+        public iterator<input_iterator_tag, directory_entry>
+      {
+      public:
+
+        // constructors and destructor
+        recursive_directory_iterator() noexcept;
+        recursive_directory_iterator(const recursive_directory_iterator&);
+        explicit recursive_directory_iterator(const path& p,
+          directory_options opts = directory_options::none);
+        recursive_directory_iterator(const path& p,
+          directory_options opts, system::error_code& ec);
+        // deprecated constructors, use overloads accepting directory_options instead
+        explicit recursive_directory_iterator(const path& p,
+          symlink_option opts = symlink_option::none);
+        recursive_directory_iterator(const path& p,
+          symlink_option opts, system::error_code& ec);
+        recursive_directory_iterator(const path& p, system::error_code& ec);
+       ~recursive_directory_iterator();
+
+        // observers
+        int depth() const noexcept;
+        bool recursion_pending() const noexcept;
+
+        // deprecated observers
+        int level() const noexcept;
+        bool no_push_pending() const noexcept;
+
+        // modifiers
+        recursive_directory_iterator& operator=(const recursive_directory_iterator&);
+
+        recursive_directory_iterator& operator++();
+        recursive_directory_iterator& increment(system::error_code& ec);
+
+        void pop();
+        void pop(system::error_code& ec);
+        void disable_recursion_pending(bool value = true) noexcept;
+
+        // deprecated modifiers
+        void no_push(bool value = true);
+
+        // other members as required by
+        //  C++ Std, Input iterators [input.iterators]
+
+      private:
+        // actual data members will probably be stored in a shared object,
+        // or some similar mechanism, to achieve the required input iterator
+        // copy semantics
+        int            m_depth;              // for exposition only
+        bool           m_recursion_pending;  // for exposition only
+        directory_options m_options;         // for exposition only
+      };
+
+  }  // namespace filesystem
+}  // namespace boost
+ +

The behavior of a recursive_directory_iterator is the same +as a directory_iterator unless otherwise specified.

+
    +
  • Incrementing a recursive_directory_iterator pointing to a + directory causes that directory itself to be iterated over, as specified by + the operator++ and increment functions.
  • +
  • When a recursive_directory_iterator reaches the end of the directory currently being iterated + over, or when pop() is called, m_depth is + decremented, and iteration of the parent directory continues.
  • +
+
recursive_directory_iterator() noexcept;
+
+ +

Effects: Constructs the end iterator.

+ +
+ +
explicit recursive_directory_iterator(const path& p, directory_options opts = directory_options::none);
+recursive_directory_iterator(const path& p, directory_options opts, system::error_code& ec);
+explicit recursive_directory_iterator(const path& p, symlink_option opts = symlink_option::none);
+recursive_directory_iterator(const path& p, symlink_option opts, system::error_code& ec);
+recursive_directory_iterator(const path& p, system::error_code& ec);
+
+ +

Effects:  Constructs an iterator representing the first +entry in the directory p resolves to, if any; otherwise, the end iterator.

+ +

Postcondition: Unless the end iterator was constructed, depth() == 0 && recursion_pending() == true && m_options == opts. +For the signature without the opts argument, opts is assumed to be directory_options::none.

+ +

Throws: As specified in Error reporting.

+ +

[Note: To iterate over the current directory, use recursive_directory_iterator(".") rather than recursive_directory_iterator(""). —end note]

+ +

[Note: By default, recursive_directory_iterator does not +follow directory symlinks. To follow directory symlinks, specify directory_options::follow_directory_symlink in opts. —end note]

+
+
int depth() const noexcept;
+int level() const noexcept;
+
+

Requires: *this != recursive_directory_iterator().

+

Returns: m_depth.

+
+
bool recursion_pending() const noexcept;
+
+

Requires: *this != recursive_directory_iterator().

+

Returns: m_recursion_pending.

+
+
bool no_push_pending() const noexcept;
+
+

Requires: *this != recursive_directory_iterator().

+

Returns: !recursion_pending().

+
+
recursive_directory_iterator& operator++();
+recursive_directory_iterator& increment(system::error_code& ec);
+
+ +

Effects: As specified by the C++ Standard, 24.1.1 Input iterators [input.iterators], +except:

+ +
    +
  • + +

    if recursion_pending() && is_directory(this->status()) +&& (!is_symlink(this->symlink_status()) || (m_options & directory_options::follow_directory_symlink) != 0) then: +

      +
    • +

      directory (*this)->path() is opened and recursively iterated into and m_depth is incremented;

      +
    • +
    • +

      if opening the directory fails with a permission_denied error and (m_options & directory_options::skip_permission_denied) != 0, + increment the iterator on the current level and ignore the error (the operation completes successfully).

      +
    • +
    +

    + +
  • +
  • if there are no more directory entries at this level then m_depth +is decremented and iteration of the parent directory resumes.
  • +
+ +

If the operation completes with an error, then +

    +
  • if (m_options & directory_options::pop_on_error) != 0, the iterator is left in a state as if after repeatedly calling pop() until it succeeds or the iterator becomes equal to an end iterator; any pop() failures are not reported to the caller;
  • +
  • otherwise, the iterator is left equal to an end iterator.
  • +
+

+ +

Postcondition: recursion_pending() == true.

+ +

Returns: *this.

+ +

Throws: As specified in Error reporting.

+ +
+
void pop();
+void pop(system::error_code& ec);
+
+

Requires: *this != recursive_directory_iterator().

+

Effects: If depth() == 0, set *this to recursive_directory_iterator(). + Otherwise, --m_depth, cease iteration of the directory currently being + iterated over, and continue iteration over the parent directory.

+

If the operation completes with an error, then +

    +
  • if (m_options & directory_options::pop_on_error) != 0, the iterator is left in a state as if after repeatedly calling pop() until it succeeds or the iterator becomes equal to an end iterator; any pop() failures are not reported to the caller;
  • +
  • otherwise, the iterator is left equal to an end iterator.
  • +
+

+
+
void disable_recursion_pending(bool value = true) noexcept;
+void no_push(bool value = true) noexcept;
+
+

Requires: *this != recursive_directory_iterator().

+

Postcondition: recursion_pending() == !value.

+

[Note: These functions are used to prevent + unwanted recursion into a directory. —end note]

+
+

recursive_directory_iterator non-member functions

+
const recursive_directory_iterator& begin(const recursive_directory_iterator& iter);
+
+

Returns: iter.

+
+
recursive_directory_iterator end(const recursive_directory_iterator&);
+
+

Returns: recursive_directory_iterator().

+
+

Operational functions [fs.op.funcs]

+

Operational functions query or modify files, including directories, in external +storage.

+

Operational functions access a file by resolving an +object of class path to a particular file in a file hierarchy. The +path is resolved as if by the ISO/IEC 9945 Pathname Resolution mechanism.

+

[Note: Because hardware failures, network failures, file system races, and many +other kinds of errors occur frequently in file system operations, users should be aware +that any filesystem operational function, no matter how apparently innocuous, may encounter +an error. See Error reporting. —end note]

+
path absolute(const path& p, const path& base=current_path());
+path absolute(const path& p, system::error_code& ec);
+path absolute(const path& p, const path& base, system::error_code& ec);
+
+

Returns: A absolute path composed according to the + following table

+ + + + + + + + + + + + + + + + +
 p.
+ has_root_directory()
!p.has_root_directory()
p.has_root_name()return preturn
+ p.root_name()
+ / absolute(base)
+    .root_directory()
+  / absolute(base)
+    .relative_path()
+ / p.relative_path()
!p.has_root_name()return
+ absolute(base)
+  .root_name()
+  / p
return absolute(base)
+ / p
+

For the overload without a base argument, base is current_path().

+

[Note: For the returned path, rp, rp.is_absolute() is true. —end note]

+

Throws:  As specified in Error reporting.

+
+
path canonical(const path& p, const path& base = current_path());
+path canonical(const path& p, system::error_code& ec);
+path canonical(const path& p, const path& base, system::error_code& ec);
+
+

Overview: Converts p, which must exist, to an absolute +path that has no symbolic link, dot, +or dot-dot elements.

+

Returns: A canonical path that refers to +the same file system object as absolute(p, base). For the overload +without a base argument, base is current_path().

+

Throws:  As specified in Error reporting.

+ +

Remarks: !exists(p) is an error.

+ +

[Note: Canonical pathnames allow security checking of a path (eg. + does this path live in /home/goodguy or /home/badguy?)  —end note]

+ +
+
void copy(const path& from, const path& to);
+void copy(const path& from, const path& to, system::error_code& ec);
+
+

Effects: copy(from, to, copy_options::none[, ec]).

+

Throws: As specified in Error reporting.

+
+
void copy(const path& from, const path& to, copy_options options);
+void copy(const path& from, const path& to, copy_options options, system::error_code& ec);
+
+

Precondition: options must contain at most one option from each of the following groups: +

    +
  • copy_options::skip_existing, copy_options::overwrite_existing or copy_options::update_existing;
  • +
  • copy_options::synchronize_data or copy_options::synchronize;
  • +
  • copy_options::recursive;
  • +
  • copy_options::copy_symlinks or copy_options::skip_symlinks;
  • +
  • copy_options::directories_only, copy_options::create_symlinks or copy_options::create_hard_links.
  • +

+

Effects: Let f and t be file_status objects obtained the following way: +

    +
  • If (options & (copy_options::create_symlinks | copy_options::skip_symlinks)) != copy_options::none then f = symlink_status(from) and t = symlink_status(to);
  • +
  • Otherwise, if (options & copy_options::copy_symlinks) != copy_options::none then f = symlink_status(from) and t = status(to);
  • +
  • Otherwise, f = status(from) and t = status(to).
  • +
+ Then, report an error if: +
    +
  • !exists(f), or
  • +
  • equivalent(from, to), or
  • +
  • is_other(f) || is_other(t), or
  • +
  • is_directory(f) && is_regular_file(t).
  • +
+ Otherwise, if is_symlink(f), then: +
    +
  • If (options & copy_options::skip_symlinks) != copy_options::none then return;
  • +
  • Otherwise if !exists(t) && (options & copy_options::copy_symlinks) != copy_options::none then copy_symlink(from, to);
  • +
  • Otherwise report error.
  • +
+ Otherwise, if is_regular_file(f), then: +
    +
  • If (options & copy_options::directories_only) != copy_options::none then return;
  • +
  • Otherwise if (options & copy_options::create_symlinks) != copy_options::none then create_symlink(link, to), where link is determined as follows: +
      +
    • If from.is_absolute() then link equals to from;
    • +
    • Otherwise, link is equivalent to relative(absolute(to.parent_path()), absolute(from.parent_path())) / from.filename().
    • +
    +
  • +
  • Otherwise if (options & copy_options::create_hard_links) != copy_options::none then create_hard_link(from, to);
  • +
  • Otherwise if is_directory(t) then copy_file(from, to / from.filename(), options);
  • +
  • Otherwise copy_file(from, to, options).
  • +
+ Otherwise, if is_directory(f), then: +
    +
  • If (options & copy_options::create_symlinks) != copy_options::none then report error with error code equal to make_error_code(system::errc::is_a_directory);
  • +
  • Otherwise if +
      +
    • (options & copy_options::recursive) != copy_options::none, or
    • +
    • options == copy_options::none and this call to copy is not a recursive call from copy
    • +
    + then: +
      +
    • If !exists(t), then create_directory(to, from).
    • +
    • Then, iterate over files in from and for each directory_entry x obtained during iteration invoke copy(x.path(), to / x.path().filename(), options).
    • +
    +
  • +
  • Otherwise, return.
  • +
+ Otherwise, for all unsupported file types of f report error.

+ +

Throws: As specified in Error reporting.

+ +
+
void copy_directory(const path& from, const path& to);
+void copy_directory(const path& from, const path& to, system::error_code& ec);
+
+

Effects: Creates directory to, with + attributes copied from directory from. The set of attributes + copied is operating system dependent.

+ +

[Note: For ISO 9945/POSIX based operating systems the + attributes are those copied by native API stat(from.c_str(), &from_stat) + followed by mkdir(to.c_str(),from_stat.st_mode).  For + Windows based operating systems the attributes are those copied by native + API CreateDirectoryExW(from.c_str(), to.c_str(), 0) + —end note] + +

Throws: As specified in Error reporting.

+ +

[Note: This operation is deprecated, use create_directory instead. —end note]

+
+ +
bool copy_file(const path& from, const path& to);
+bool copy_file(const path& from, const path& to, system::error_code& ec);
+
+

Effects: return copy_file(from, to, copy_options::none[, ec]).

+ +

Throws: As specified in Error reporting.

+ +
+
bool copy_file(const path& from, const path& to, copy_options options);
+bool copy_file(const path& from, const path& to, copy_options options, system::error_code& ec);
+bool copy_file(const path& from, const path& to, copy_option options);
+bool copy_file(const path& from, const path& to, copy_option options, system::error_code& ec);
+
+

Precondition: options must contain at most one option from each of the following groups: +

    +
  • copy_options::skip_existing, copy_options::overwrite_existing or copy_options::update_existing;
  • +
  • copy_options::synchronize_data or copy_options::synchronize.
  • +
+

+

Effects: Report an error if: +

    +
  • !is_regular_file(from), or
  • +
  • exists(to) && !is_regular_file(to), or
  • +
  • exists(to) && equivalent(from, to), or
  • +
  • exists(to) && (options & (copy_options::skip_existing | copy_options::overwrite_existing)) == copy_options::none.
  • +
+ Otherwise, return successfully with no effect if: +
    +
  • exists(to) && (options & copy_options::skip_existing) != copy_options::none, or
  • +
  • exists(to) && (options & copy_options::update_existing) != copy_options::none and last write time of from is more recent than that of to.
  • +
+ Otherwise: +
    +
  • The contents and attributes of the file from resolves to are copied to the file to resolves to; then
  • +
  • If (options & copy_options::synchronize) != copy_options::none, the written data and attributes are synchronized with the permanent storage; otherwise
  • +
  • If (options & copy_options::synchronize_data) != copy_options::none, the written data is synchronized with the permanent storage.
  • +
+

+

Returns: true if the file was copied without error, otherwise false.

+

Throws: As specified in Error reporting.

+

[Note: The overloads taking copy_option are deprecated. Their effect is equivalent to the corresponding overloads taking copy_options after casting the options argument to copy_options.]

+

[Note: When copy_options::update_existing is specified, checking the write times of from and to may not be atomic with the copy operation. Another process may create or modify the file identified by to after the file modification times have been checked but before copying starts. In this case the target file will be overwritten.]

+

[Note: The copy_options::synchronize_data and copy_options::synchronize options may have a significant performance impact. The copy_options::synchronize_data option may be less expensive than copy_options::synchronize. However, without these options, upon returning from copy_file it is not guaranteed that the copied file is completely written and preserved in case of a system failure. Any delayed write operations may fail after the function returns, at the point of physically writing the data to the underlying media, and this error will not be reported to the caller.]

+
+
void copy_symlink(const path& existing_symlink, const path& new_symlink);
+void copy_symlink(const path& existing_symlink, const path& new_symlink, system::error_code& ec);
+
+

Effects: create_symlink(read_symlink(existing_symlink[, ec]), new_symlink[, ec]).

+ +

Throws: As specified in Error reporting.

+ +
+
bool create_directories(const path& p);
+bool create_directories(const path& p, system::error_code& ec);
+
+

Effects: Establishes the postcondition by calling + create_directory() for any element of p that does not + exist.

+

Postcondition: is_directory(p)

+

Returns: true if a new directory was created, otherwise + false.

+

Throws: As specified in Error reporting.

+

Complexity: O(n+1) where n is the number of elements + of p that do not exist.

+
+
bool create_directory(const path& p);
+bool create_directory(const path& p, system::error_code& ec);
+bool create_directory(const path& p, const path& existing);
+bool create_directory(const path& p, const path& existing, system::error_code& ec);
+
+

Effects: Establishes the postcondition by attempting to create the + directory p resolves to, as if by ISO/IEC 9945 + mkdir(). For overloads without existing argument, the new directory is created with S_IRWXU|S_IRWXG|S_IRWXO mode. + Overloads with existing argument obtain mode from existing, which must be a path to an existing directory. On Windows, + CreateDirectoryW(p.c_str(), NULL) is used when existing is not specified and CreateDirectoryExW(existing.c_str(), p.c_str(), NULL) otherwise. + Creation failure because p resolves to an existing directory shall not be + treated as an error.

+

Postcondition: is_directory(p)

+

Returns: true if a new directory was created, otherwise false.

+

Throws: As specified in Error reporting.

+
+
void create_directory_symlink(const path& to, const path& new_symlink);
+void create_directory_symlink(const path& to, const path& new_symlink, system::error_code& ec);
+
+

Effects: Establishes the postcondition, as if by ISO/IEC 9945 symlink().

+

+ Postcondition: new_symlink resolves to a symbolic link file that + contains an unspecified representation of to.

+

Throws: As specified in Error reporting.

+

[Note: Some operating systems, such as Windows, require symlink creation to + identify that the link is to a directory. Portable code should use create_directory_symlink() to create directory symlinks rather than create_symlink() —end note]

+

[Note: Some operating systems do not support symbolic links at all or support + them only for regular files. + Some file systems do not + support + symbolic links regardless of the operating system - the FAT file system used on + memory cards and flash drives, for example. —end note]

+
+
void create_hard_link(const path& to, const path& new_hard_link);
+void create_hard_link(const path& to, const path& new_hard_link, system::error_code& ec);
+
+

Effects: Establishes the postcondition, as if by ISO/IEC 9945 link().

+

Postcondition:

+
    +
  •  exists(to) && + exists(new_hard_link) && equivalent(to, + + new_hard_link)
  • +
  • The contents of the file or directory + to resolves to are unchanged.
  • +
+

Throws: As specified in Error reporting.

+

[Note: Some operating systems do not support hard links at all or support + them only for regular files. Some file systems do not support hard + links regardless of the operating system - the FAT file system used on memory + cards and flash drives, for example. Some file systems limit the number of + links per file. —end note]

+
+
void create_symlink(const path& to, const path& new_symlink);
+void create_symlink(const path& to, const path& new_symlink, system::error_code& ec);
+
+

Effects: Establishes the postcondition, as if by ISO/IEC 9945 symlink().

+

+ Postcondition: new_symlink resolves to a symbolic link file that + contains an unspecified representation of to.

+

Throws: As specified in Error reporting.

+

[Note: Some operating systems do not support symbolic links at all or support + them only for regular files. + Some file systems do not + support + symbolic links regardless of the operating system - the FAT system used on + memory cards and flash drives, for example. —end note]

+
+
path current_path();
+path current_path(system::error_code& ec);
+
+

Returns: The current working directory path, as if by ISO/IEC + 9945 getcwd(). is_absolute() is true for the returned path.

+

Throws: As specified in Error reporting.

+

[Note: The current_path() name was chosen to emphasize that the return is a + path, not just a single directory name.

+

The current path as returned by many operating systems is a dangerous + global variable. It may be changed unexpectedly by a third-party or system + library functions, or by another thread.  —end note]

+
+
void current_path(const path& p);
+void current_path(const path& p, system::error_code& ec);
+
+

Effects: Establishes the postcondition, as if by ISO/IEC 9945 chdir().

+

Postcondition: equivalent(p, current_path()).

+

Throws: As specified in Error reporting.

+

[Note: The current path for many operating systems is a dangerous + global state. It may be changed unexpectedly by a third-party or system + library functions, or by another thread.  —end note]

+
+
bool exists(file_status s) noexcept;
+
+

Returns: status_known(s) && s.type() != file_not_found

+
+
bool exists(const path& p);
+bool exists(const path& p, system::error_code& ec) noexcept;
+
+

Returns: exists(status(p)) or exists(status(p, ec)), + respectively.

+

Throws: As specified in Error reporting.

+
+
bool equivalent(const path& p1, const path& p2);
+bool equivalent(const path& p1, const path& p2, system::error_code& ec);
+
+

Effects: Determines file_status s1 and s2, as if by status(p1) and  status(p2), + respectively.

+

Returns: true, if sf1 == + sf2 and p1 and p2 resolve to the same file + system entity, else false.

+
+

Two paths are considered to resolve to the same + file system entity if two candidate entities reside on the same device at the + same location. This is determined as if by the values of the ISO/IEC 9945 stat structure, obtained as if by stat() for the two paths, having equal st_dev values + and equal st_ino values.

+

[Note: ISO/IEC 9945 requires that "st_dev must be unique within a Local Area Network". Conservative + ISO/IEC 9945 implementations may also wish to check for equal st_size and st_mtime values. Windows implementations may use GetFileInformationByHandle() as a surrogate for stat(), + and consider "same" to be equal values for dwVolumeSerialNumber, nFileIndexHigh, nFileIndexLow, nFileSizeHigh, nFileSizeLow, ftLastWriteTime.dwLowDateTime, and ftLastWriteTime.dwHighDateTime. —end note]

+
+

Throws: filesystem_error if (!exists(s1) && !exists(s2)) || (is_other(s1) && is_other(s2)), + otherwise as specified in Error reporting.

+
+ +
uintmax_t file_size(const path& p);
+uintmax_t file_size(const path& p, system::error_code& ec);
+ +
+

Returns: If exists(p) && is_regular_file(p), the size + in bytes + of the file p resolves to, determined as if by the value of + the ISO/IEC 9945 stat structure member st_size obtained as if by + ISO/IEC 9945 stat(). + Otherwise, static_cast<uintmax_t>(-1).

+

Throws: As specified in Error reporting.

+
+
uintmax_t hard_link_count(const path& p);
+uintmax_t hard_link_count(const path& p, system::error_code& ec);
+
+ +

Returns: The number of hard links for p.

+

Throws: As specified in Error reporting.

+ +
+ +
const path& initial_path();
+const path& initial_path(system::error_code& ec);
+
+

Returns: current_path() as of the first call to initial_path().

+

[Note: initial_path() is not thread safe, and may return an undesirable result + if called subsequent to a change to the current directory. These problems can + be avoided by calling initial_path() immediately on entry to + main().  —end note]

+

Throws: For the first call, as specified in Error reporting. Subsequent calls throw nothing.

+
+
bool is_block_file(file_status s) noexcept;
+
+

Returns: s.type() == block_file

+
+
bool is_block_file(const path& p);
+bool is_block_file(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_block_file(status(p)) or is_block_file(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws +nothing.

+
+
bool is_character_file(file_status s) noexcept;
+
+

Returns: s.type() == character_file

+
+
bool is_character_file(const path& p);
+bool is_character_file(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_character_file(status(p)) or is_character_file(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws +nothing.

+
+
bool is_directory(file_status s) noexcept;
+
+

Returns: s.type() == directory_file

+
+
bool is_directory(const path& p);
+bool is_directory(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_directory(status(p)) or is_directory(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws +nothing.

+
+
bool is_empty(const path& p);
+bool is_empty(const path& p, system::error_code& ec);
+
+

Effects: Determines file_status s, as if by status(p, ec).

+

Returns: is_directory(s)
+         ? directory_iterator(p) == directory_iterator()
+         : file_size(p) == 0;

+
+
bool is_fifo(file_status s) noexcept;
+
+

Returns: s.type() == fifo_file

+
+
bool is_fifo(const path& p);
+bool is_fifo(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_fifo(status(p)) or is_fifo(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws +nothing.

+
+
bool is_other(file_status s) noexcept;
+
+

Returns: return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s)

+
+
bool is_other(const path& p);
+bool is_other(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_other(status(p)) or is_other(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws + nothing.

+
+
bool is_regular_file(file_status s) noexcept;
+
+

Returns: s.type() == regular_file

+
+
bool is_regular_file(const path& p);
+bool is_regular_file(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_regular_file(status(p)) or is_regular_file(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws + nothing.

+
+
bool is_reparse_file(file_status s) noexcept;
+
+

Returns: s.type() == reparse_file

+
+
bool is_reparse_file(const path& p);
+bool is_reparse_file(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_reparse_file(symlink_status(p)) or is_reparse_file(symlink_status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws + nothing.

+
+
bool is_socket(file_status s) noexcept;
+
+

Returns: s.type() == socket_file

+
+
bool is_socket(const path& p);
+bool is_socket(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_socket(status(p)) or is_socket(status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws + nothing.

+
+
bool is_symlink(file_status s) noexcept;
+
+

Returns: s.type() == symlink_file

+
+
bool is_symlink(const path& p);
+bool is_symlink(const path& p, system::error_code& ec) noexcept;
+
+

Returns: is_symlink(symlink_status(p)) or is_symlink(symlink_status(p, ec)), + respectively. The overload with argument ec returns false if an error occurs.

+

Throws: filesystem_error; the overload with argument ec throws + nothing.

+
+
std::time_t creation_time(const path& p);
+std::time_t creation_time(const path& p, system::error_code& ec);
+
+

Returns: The time of creation of the file to which p resolves.

+

Throws: As specified in Error reporting.

+

[Note: Not all platforms support querying file creation time. Where not supported, the operation will fail with + errc::function_not_supported error code. —end note]

+
+
std::time_t last_write_time(const path& p);
+std::time_t last_write_time(const path& p, system::error_code& ec);
+
+

Returns: The time of last data modification of p, determined as if by the + value of the ISO/IEC 9945 stat structure member st_mtime  obtained + as if by ISO/IEC 9945 stat().

+

Throws: As specified in Error reporting.

+
+
void last_write_time(const path& p, const std::time_t new_time);
+void last_write_time(const path& p, const std::time_t new_time, system::error_code& ec);
+
+

Effects: Sets the time of last data modification of the file + resolved to by p to new_time, as if by ISO/IEC + 9945 stat() followed by + ISO/IEC 9945 utime().

+

Throws: As specified in Error reporting.

+

[Note: A postcondition of last_write_time(p) == new_time is not specified since it might not hold for file systems + with coarse time granularity. —end note]

+
+
void permissions(const path& p, perms prms);
+void permissions(const path& p, perms prms, system::error_code& ec);
+
+

+ Requires: !((prms & add_perms) && (prms & remove_perms)).

+

Effects: Applies the effective permissions bits from prms to the file p resolves to, as if by + ISO/IEC 9945 fchmodat(). The effective permission bits are determined as + specified by the following table.

+ + + + + + + + + + + + + + + + + +
bits present in prmsEffective bits applied
Neither add_perms nor remove_permsprms & perms_mask
add_perms +

status(p).permissions() | (prms & perms_mask)

remove_permsstatus(p).permissions() & ~(prms & perms_mask)
+

[Note: Conceptually permissions are viewed as bits, but the actual + implementation may use some other mechanism. —end note]

+

Throws: As specified in Error reporting.

+
+
path read_symlink(const path& p);
+path read_symlink(const path& p, system::error_code& ec);
+
+

Returns:  If p resolves to a symbolic + link, a path object containing the contents of that symbolic + link. Otherwise an empty path object.

+

Throws: As specified in Error reporting. [Note: It is an error if p does not + resolve to a symbolic link. —end note]

+
+
path relative(const path& p, system::error_code& ec);
+
+

Returns: relative(p, current_path(), ec).

+

Throws:  As specified in Error reporting.

+
+
path relative(const path& p, const path& base=current_path());
+path relative(const path& p, const path& base, system::error_code& ec);
+
+

Overview: Returns p made relative to base. + Treats empty or identical paths as corner cases, not errors. Resolves symlinks + and normalizes both p and base before other + processing.

+

Returns: weakly_canonical(p).lexically_relative(weakly_canonical(base)). The second form returns path() + if an error occurs.

+

Throws: As specified in Error reporting.

+
+
bool remove(const path& p);
+bool remove(const path& p, system::error_code& ec);
+
+

Effects:  If exists(symlink_status(p,ec)), it is + removed + as if by ISO/IEC 9945 remove().

+
+

[Note: A symbolic link is itself removed, rather than the file it + resolves to being removed. —end note]

+
+

Postcondition: !exists(symlink_status(p)).

+

Returns:  false if p did not exist, otherwise true.

+

Throws: As specified in Error reporting.

+
+
uintmax_t remove_all(const path& p);
+uintmax_t remove_all(const path& p, system::error_code& ec);
+
+

Effects:  Recursively deletes the contents of p if it exists, + then deletes file p itself, + as if by ISO/IEC 9945 remove().

+
+

[Note: A symbolic link is itself removed, rather than the file it + resolves to being removed. —end note]

+
+

Postcondition: !exists(p)

+

Returns: The number of files removed.

+

Throws: As specified in Error reporting.

+
+
void rename(const path& old_p, const path& new_p);
+void rename(const path& old_p, const path& new_p, system::error_code& ec);
+
+

Effects: Renames old_p to new_p, as if by + ISO/IEC 9945 rename().

+
+

[Note: If old_p and new_p resolve to the + same existing file, no action is taken. Otherwise, if new_p resolves to an + existing non-directory file, it is removed, while if new_p resolves to an + existing directory, it is removed if empty on ISO/IEC 9945 but is an error on Windows. A symbolic link is itself renamed, rather than + the file it resolves to being renamed. —end note]

+
+

Throws: As specified in Error reporting.

+
+
void resize_file(const path& p, uintmax_t new_size);
+void resize_file(const path& p, uintmax_t new_size, system::error_code& ec);
+
+

Postcondition: file_size() == new_size.

+

Throws: As specified in Error reporting.

+

Remarks: Achieves its postconditions as if by ISO/IEC 9945 truncate().

+
+
space_info space(const path& p);
+space_info space(const path& p, system::error_code& ec);
+
+

Returns: An object of type space_info. The value of the space_info object is determined as if by + using ISO/IEC 9945 statvfs() to obtain an ISO/IEC 9945 struct + statvfs, + and then multiplying its f_blocks, f_bfree, + and f_bavail members by its f_frsize member, + and assigning the results to the capacity, free, + and available members respectively. Any members for which the + value cannot be determined shall be set to -1.

+

Throws: As specified in Error reporting.

+
+
file_status status(const path& p);
+
+

Effects: As if:

+
+
system::error_code ec;
+file_status result = status(p, ec);
+if (result == status_error)
+  throw filesystem_error(implementation-supplied-message, p, ec);
+return result;
+
+

Returns: See above.

+

Throws: filesystem_error. +[Note: result values of file_status(file_not_found)and file_status(type_unknown) are not considered failures and do not + cause an exception to be +thrown. —end note]

+
+
file_status status(const path& p, system::error_code& ec) noexcept;
+
+

Effects:

+
+

If possible, determines the attributes + of the file p resolves to, as if by ISO/IEC 9945 stat().

+ If, during attribute determination, the underlying file system API reports + an error, sets ec to indicate the specific error reported. + Otherwise, ec.clear().
+

[Note: This allows users to inspect the specifics of underlying + API errors even when the value returned by status() is not file_status(status_error)—end note]

+
+
+

Returns:

+
+

If ec != error_code():

+
    +
  • If the specific error indicates that p cannot be resolved + because some element of the path does not exist, return + file_status(file_not_found). [Note: ISO/IEC 9945 errors that + indicate this are ENOENT or ENOTDIR. Windows equivalents + include ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_INVALID_NAME, + ERROR_INVALID_PARAMETER, ERROR_BAD_PATHNAME, and ERROR_BAD_NETPATH. -- + end note]
  • +
  • Otherwise, if the specific error indicates that p can be resolved + but the attributes cannot be determined, return + file_status(type_unknown). [Note: For example, Windows + ERROR_SHARING_VIOLATION errors. For ISO/IEC 9945, the case never arises. —end + note]
  • +
  • Otherwise, return + file_status(status_error).
  • +
+
+

[Note: These semantics distinguish between p being known not to exist, p existing but not being able to determine its attributes, + and there being an error that prevents even knowing if p exists. These + distinctions are important to some use cases. â€”end note]

+
+

Otherwise,

+
    +
  • If the attributes indicate a regular file, as if by ISO/IEC 9945 S_ISREG(), + return + file_status(regular_file). [Note: +regular_file implies appropriate <fstream> operations + would succeed, assuming no hardware, permission, access, or file system + race + errors. Lack of +regular_file does not necessarily imply <fstream> operations would +fail on a directory. +—end note]
  • +
  • Otherwise, if the attributes indicate a directory, as if by ISO/IEC 9945 + S_ISDIR(), + return + file_status(directory_file). [Note: directory_file implies +directory_iterator(p)would succeed. +—end note]
  • +
  • Otherwise, if the attributes indicate a block special file, as if by ISO/IEC 9945 + S_ISBLK(), + return + file_status(block_file).
  • +
  • Otherwise, if the attributes indicate a character special file, as if by ISO/IEC 9945 + S_ISCHR(), + return + file_status(character_file).
  • +
  • Otherwise, if the attributes indicate a fifo or pipe file, as if by + ISO/IEC 9945 + S_ISFIFO(), + return + file_status(fifo_file).
  • +
  • Otherwise, if the attributes indicate a socket, as if by ISO/IEC + 9945 + S_ISSOCK(), + return + file_status(socket_file).
  • +
  • Otherwise, return + file_status(type_unknown).
  • +
+
+

Remarks: If a symbolic link is encountered during pathname + resolution, + pathname resolution continues using the contents of the symbolic link.

+
+
bool status_known(file_status s) noexcept;
+
+

Returns: s.type() != status_error

+
+
file_status symlink_status(const path& p);
+file_status symlink_status(const path& p, system::error_code& ec) noexcept;
+
+

Effects:  Same as status(), above, + except that the attributes + of p are determined as if by ISO/IEC 9945 lstat().

+
+
+

Returns: Same as status(), above, except + that if the attributes indicate a symbolic link, as if by ISO/IEC 9945 S_ISLNK(), return file_status(symlink_file).

+

Remarks: Pathname resolution terminates if p names a symbolic link.

+

Throws: filesystem_error; overload with error_code& throws + nothing.

+
+
path system_complete(const path& p);
+path system_complete(const path& p, system::error_code& ec);
+
+

Effects: Composes an absolute path from p, using the + same rules used by the operating system to resolve a path passed as the + filename argument to standard library open functions.

+

Returns: The composed path.

+

Postcondition: For the returned path, rp, rp.is_absolute() is true.

+

Throws: As specified in Error reporting.

+

[Note: For ISO/IEC 9945, system_complete(p) has the same semantics as absolute(p, current_path()).

+

For Windows, system_complete(p) has the + same semantics as absolute(p, current_path()) if p.is_absolute() || !p.has_root_name() or p and base have the same root_name(). + Otherwise it acts like absolute(p, kinky), where kinky is the current directory for the p.root_name() drive. This will + be the current directory of that drive the last time it was set, and thus may + be residue left over from a prior program run by the command + processor! Although these semantics are often useful, they are also very + error-prone.

+
+
path temp_directory_path();
+path temp_directory_path(system::error_code& ec);
+
+

Returns: A directory path suitable for temporary files under the + conventions of the operating system. The specifics of how this path is + determined are implementation defined. An error shall be reported if !exists(p) + || !is_directory(p), where p is the path to be returned.

+

ISO/IEC 9945: The path supplied by the first environment variable found in the + list TMPDIR, TMP, TEMP, TEMPDIR. If none of these are found, "/tmp", + or, if macro __ANDROID__ is defined, "/data/local/tmp".

+

Windows: The path reported by the Windows GetTempPath API function.

+

Throws: As specified in Error reporting.

+

[Note: The temp_directory_path() name was chosen to emphasize that the return is a + path, not just a single directory name.  —end note]

+
+
path unique_path(const path& model="%%%%-%%%%-%%%%-%%%%");
+path unique_path(const path& model, system::error_code& ec);
+
+

The unique_path function generates a path name suitable for + creating temporary files, including directories. The name is based + on a model that uses the percent sign character to specify replacement by a + random hexadecimal digit. [Note: The more bits of randomness in the + generated path name, the less likelihood of prior existence or being guessed. + Each replacement hexadecimal digit in the model adds four bits of randomness. + The default model thus provides 64 bits of randomness. This is sufficient for + most applications. —end note]

+

Returns: A path identical to model, except that each + occurrence of a percent sign character is replaced by a random hexadecimal + digit character in the range 0-9, a-f.

+

Throws: As specified in Error reporting.

+

Remarks: Implementations are encouraged to obtain the required + randomness via a cryptographically secure pseudo-random number generator, such as one + provided by the operating system. [Note: Such generators may block + until sufficient entropy develops. —end note]

+
+
path weakly_canonical(const path& p, const path& base=current_path());
+path weakly_canonical(const path& p, system::error_code& ec);
+path weakly_canonical(const path& p, const path& base, system::error_code& ec);
+
+

Overview: Returns p with symlinks resolved and the + result normalized.

+

Effects: Let head be the path composed of the leading + elements of p that exist and tail — from the rest of p. + Where not specified, base is obtained from current_path() or current_path(ec) + Calls canonical(head, base) or canonical(head, base, ec), + appends tail to the returned path using operator/. + The result is then normalized and returned.

+

Postcondition: The returned path is in + + normal form.

+

Remarks: Uses operator/= to compose the returned path. + Uses the status function to determine existence.

+

Remarks: Implementations are encouraged to avoid unnecessary + normalization such as when canonical has already been called on + the entirety of p.

+

Throws:  As specified in Error reporting.

+
+
+ + + + +

File streams

+

<boost/filesystem/fstream.hpp> header

+

Replacements are provided for the file stream classes from the C++ standard +library's <fstream> header. These replacement classes +publicly inherit from the standard library classes. In the Boost.Filesystem +version, constructors and open functions take const path& arguments +instead of const char* arguments. There are no other differences in syntax or +semantics.

+
namespace boost
+{
+  namespace filesystem
+  {
+    template < class charT, class traits = std::char_traits<charT> >
+    class basic_filebuf : public std::basic_filebuf<charT,traits>
+    {
+    public:
+      basic_filebuf<charT,traits>*
+        open(const path& p, std::ios_base::openmode mode);
+    };
+
+    template < class charT, class traits = std::char_traits<charT> >
+    class basic_ifstream : public std::basic_ifstream<charT,traits>
+    {
+    public:
+      explicit basic_ifstream(const path& p, std::ios_base::openmode mode=std::ios_base::in)
+      void open(const path& p, std::ios_base::openmode mode=std::ios_base::in);
+    };
+
+    template < class charT, class traits = std::char_traits<charT> >
+    class basic_ofstream : public std::basic_ofstream<charT,traits>
+    {
+    public:
+      explicit basic_ofstream(const path& p, std::ios_base::openmode mode=std::ios_base::out);
+      void open(const path& p, std::ios_base::openmode mode=std::ios_base::out);
+    };
+
+    template < class charT, class traits = std::char_traits<charT> >
+    class basic_fstream : public std::basic_fstream<charT,traits>
+    {
+    public:
+      explicit basic_fstream(const path& p,
+        std::ios_base::openmode mode=std::ios_base::in | std::ios_base::out);
+      void open(const path& p,
+        std::ios_base::openmode mode=std::ios_base::in | std::ios_base::out);
+    };
+
+    typedef basic_filebuf<char> filebuf;
+    typedef basic_ifstream<char> ifstream;
+    typedef basic_ofstream<char> ofstream;
+    typedef basic_fstream<char> fstream;
+
+    typedef basic_filebuf<wchar_t> wfilebuf;
+    typedef basic_ifstream<wchar_t> wifstream;
+    typedef basic_fstream<wchar_t> wfstream;
+    typedef basic_ofstream<wchar_t> wofstream;
+
+  }  // namespace filesystem
+}  // namespace boost
+ + +

<boost/filesystem/cstdio.hpp> header

+

This header provides a std::fopen overload from <cstdio> C++ standard library header. +The overload accepts const path& as its first argument instead of const char* and has no +other differences from its standard counterpart.

+
namespace boost
+{
+  namespace filesystem
+  {
+    std::FILE* fopen(const path& p, const char* mode);
+
+  }  // namespace filesystem
+}  // namespace boost
+ +

Path decomposition table

+

The table is generated by a program compiled with the Boost implementation.

+

Shaded entries indicate cases where ISO/IEC 9945 (POSIX) and Windows implementations yield different results. The top value is the +ISO/IEC 9945 result and the bottom value is the Windows result.
+ +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Constructor
argument
Iteration
over
Elements
string()generic_
string()
root_
path()
root_
name()
root_
directory()
relative_
path()
parent_
path()
filename()
emptyemptyemptyemptyemptyemptyemptyemptyemptyempty
....emptyemptyempty.empty.
........emptyemptyempty..empty..
foofoofoofooemptyemptyemptyfooemptyfoo
/////empty/emptyempty/
/foo/,foo/foo/foo/empty/foo/foo
foo/foo,.foo/foo/emptyemptyemptyfoo/foo.
/foo//,foo,./foo//foo//empty/foo//foo.
foo/barfoo,barfoo/barfoo/baremptyemptyemptyfoo/barfoobar
/foo/bar/,foo,bar/foo/bar/foo/bar/empty/foo/bar/foobar
//net//net//net//net//net//netemptyemptyempty//net
//net/foo//net,/,foo//net/foo//net/foo//net///net/foo//net/foo
///foo////,foo,.///foo//////foo////empty/foo//////foo.
///foo///bar/,foo,bar///foo///bar///foo///bar/empty/foo///bar///foobar
/./,./././empty/./.
./.,.././emptyemptyempty./..
/../,../../../empty/../..
../..,.../../emptyemptyempty../...
foo/.foo,.foo/.foo/.emptyemptyemptyfoo/.foo.
foo/..foo,..foo/..foo/..emptyemptyemptyfoo/..foo..
foo/./foo,.,.foo/./foo/./emptyemptyemptyfoo/./foo/..
foo/./barfoo,.,barfoo/./barfoo/./baremptyemptyemptyfoo/./barfoo/.bar
foo/..foo,..foo/..foo/..emptyemptyemptyfoo/..foo..
foo/../foo,..,.foo/../foo/../emptyemptyemptyfoo/../foo/...
foo/../barfoo,..,barfoo/../barfoo/../baremptyemptyemptyfoo/../barfoo/..bar
c:c:c:c:empty
c:
empty
c:
emptyc:
empty
emptyc:
c:/c:,.
c:,/
c:/c:/empty
c:/
empty
c:
empty
/
c:/
empty
c:.
/
c:fooc:foo
c:,foo
c:fooc:fooempty
c:
empty
c:
emptyc:foo
foo
empty
c:
c:foo
foo
c:/fooc:,foo
c:,/,foo
c:/fooc:/fooempty
c:/
empty
c:
empty
/
c:/foo
foo
c:
c:/
foo
c:foo/c:foo,.
c:,foo,.
c:foo/c:foo/empty
c:
empty
c:
emptyc:foo/
foo/
c:foo.
c:/foo/c:,foo,.
c:,/,foo,.
c:/foo/c:/foo/empty
c:/
empty
c:
empty
/
c:/foo/
foo/
c:/foo.
c:/foo/barc:,foo,bar
c:,/,foo,bar
c:/foo/barc:/foo/barempty
c:/
empty
c:
empty
/
c:/foo/bar
foo/bar
c:/foobar
prn:prn:prn:prn:empty
prn:
empty
prn:
emptyprn:
empty
emptyprn:
c:\c:\
c:,/
c:\c:\
c:/
empty
c:\
empty
c:
empty
\
c:\
empty
empty
c:
c:\
\
c:fooc:foo
c:,foo
c:fooc:fooempty
c:
empty
c:
emptyc:foo
foo
empty
c:
c:foo
foo
c:\fooc:\foo
c:,/,foo
c:\fooc:\foo
c:/foo
empty
c:\
empty
c:
empty
\
c:\foo
foo
empty
c:\
c:\foo
foo
c:foo\c:foo\
c:,foo,.
c:foo\c:foo\
c:foo/
empty
c:
empty
c:
emptyc:foo\
foo\
empty
c:foo
c:foo\
.
c:\foo\c:\foo\
c:,/,foo,.
c:\foo\c:\foo\
c:/foo/
empty
c:\
empty
c:
empty
\
c:\foo\
foo\
empty
c:\foo
c:\foo\
.
c:\foo/c:\foo,.
c:,/,foo,.
c:\foo/c:\foo/
c:/foo/
empty
c:\
empty
c:
empty
\
c:\foo/
foo/
c:\foo.
c:/foo\barc:,foo\bar
c:,/,foo,bar
c:/foo\barc:/foo\bar
c:/foo/bar
empty
c:/
empty
c:
empty
/
c:/foo\bar
foo\bar
c:
c:/foo
foo\bar
bar
+ +

Long paths on Windows and the +\\?\ namespace prefix

+

The Microsoft Windows "Maximum Path Length Limitation" specifies:

+
+

In the Windows API (with some exceptions ...), the maximum length for a path +is MAX_PATH, which is defined as 260 characters.

+

The Windows API has many functions that also have Unicode versions to permit +an extended-length path for a maximum total path length of 32,767 characters. +... To specify an extended-length path, use the "\\?\" prefix. For +example, "\\?\D:\very long path". [C++ string literals +require backslashes be doubled, of course.]

+
+

Because most Boost.Filesystem operational functions just pass the contents of +a class path object to the Windows API, they do work with the extended-length +prefixes. But some won't work, because to the limitations imposed by Windows.

+

Effectively, the "\\?\" prefix informs the underlying Windows API +that the path identifies an object in the Win32 filesystem namespace and disables +most of the internal path processing, including normalization, by the Windows API. +While it lifts the length limitation, this imposes a number of other restrictions on +the acceptable paths that are listed in the section below. There are a number of +other prefixes that have different special meanings, such as "\\.\" (a local +device namespace prefix) and "\??\" (NT object namespace prefix). Note that +UNC paths can be extended with the prefixes by referring to a special "UNC" +device. For example, "\\server\share" can be extended as "\\?\UNC\server\share".

+

In terms of Boost.Filesystem, the namespace prefixes are considered as parts of the path's +root name. For example, the root name of "\\?\c:\foo" is "\\?\c:". +This interpretation is chosen to allow root paths to be iterable, that is you can list +the contents of the "\\?\c:\" directory, provided that drive C: exists and you have +the necessary permissions. [Note: You can't list the contents of "\\?\" +as such path does not exist.]

+ +

Cautions for paths with namespace prefixes

+
    +
  • Individual components of a path are still are limited to whatever is + supported for the particular filesystem, commonly 255 characters.
  • +
  • Only backslashes are acceptable as directory separators. Slashes are + not treated as separators.
  • +
  • All paths must be absolute and must not contain "." or ".." components.
  • +
  • Once an absolute path grows beyond 260 characters, it is essentially + poisoned and all operations must use extended-length prefixes. So even a + simple operation like create_directory("a") will fail if the + absolute path of the resulting directory would exceed 260 characters.
  • +
  • Certain Boost.Filesystem functions that decompose their argument path and + then work on individual relative directories or files will not work properly + with namespace prefix paths.
  • +
+ +

Acknowledgements

+

This Filesystem Library is dedicated to my wife, Sonda, who provided the +support necessary to see both a trial implementation and the proposal itself +through to completion. She gave me the strength to continue after a difficult +year of cancer treatment in the middle of it all.

+

Many people contributed technical comments, ideas, and suggestions to the +Boost Filesystem Library. See http://www.boost.org/libs/filesystem/doc/index.htm#Acknowledgements.

+

Dietmar Kühl contributed the original Boost Filesystem Library directory_iterator design. Peter Dimov, Walter Landry, Rob Stewart, and Thomas +Witt were particularly helpful in refining the library.

+

The create_directories, extension, basename, and replace_extension functions +were developed by Vladimir Prus. The temp_directory_path function was +contributed by Jeff Flinn. David Svoboda suggested the canonical function and +provided pseudo-code.

+

Howard Hinnant and John Maddock reviewed a draft of the version 2 proposal, and +identified a number of mistakes or weaknesses, resulting in a more polished +final document.

+

Peter Dimov suggested a single class path, with member templates to adapt to +multiple string types. His idea became the basis for the version 3 path design.

+

References

+ + + + + + + + + +
[ISO/IEC 9945]ISO/IEC 9945:2003, IEEE Std 1003.1-2001, and The Open Group + Base Specifications, Issue 6. Also known as The Single UNIX® + Specification, Version 3. Available from each of the organizations involved + in its creation. For example, read online or download from www.unix.org/single_unix_specification/. The ISO JTC1/SC22/WG15 - + POSIX homepage is www.open-std.org/jtc1/sc22/WG15/
[Abrahams]Dave Abrahams, Error and Exception Handling, www.boost.org/more/error_handling.html
+
+

© Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010, 2011

+

© Copyright Andrey Semashev, 2019-2021

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + diff --git a/3rdparty/boost_filesystem/doc/relative_proposal.html b/3rdparty/boost_filesystem/doc/relative_proposal.html new file mode 100644 index 0000000..81c7093 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/relative_proposal.html @@ -0,0 +1,509 @@ + + + + + + + +Filesystem Relative Proposal + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Relative
+ Draft Proposal
+
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

+ Introduction
+    Acknowledgement
+    Preliminary implementation
+Requirements
+Issues
+ + Design decisions
+    Provide separate lexical and + operational relative functions
+    Provide +separate lexical and operational proximate functions
+    Add lexical functions as path member functions
+    Provide a non-member function +lexically_normal returning a + normal form path
+    Provide a weakly_canonical operational function
+    Resolve issues in ways that "just work" for users
+    Specify lexical relative in terms + of std::mismatch
+    Specify operational relative in terms of + weakly_canonical
+    Specify operational relative in terms of + lexically + relative
+Proposed wording
+    Define normal form
+    New class path member functions
+        Synopsis
+        Specification
+    New operational functions
+        Synopsis
+        Specification

+ +

+ Introduction

+ +

There have been requests for a Filesystem library relative function for at + least ten years.

+ +

+ The requested functionality seems simple - given two paths with a common + prefix, return the non-common suffix portion of one of the paths such that + it is relative to the other path.

+ +

+ In terms of the Filesystem library,

+ +
+
path p("/a/b/c");
+path base("/a/b");
+path rel = relative(p, base);  // the requested function
+cout << rel << endl;           // outputs "c"
+assert(absolute(rel, base) == p);
+
+

If that was all there was to it, the Filesystem library would have had a +relative function years ago.

+
+

Blocking issues: Clashing requirements, symlinks, directory placeholders (dot, +dot-dot), user-expectations, corner cases.

+
+

Acknowledgement

+

A paper by Jamie Allsop, Additions to Filesystem supporting Relative Paths, +is what broke my mental logjam. Much of what follows is based directly on +Jamie's analysis and proposal. The weakly_canonical function and +aspects of the semantic specifications are my contributions. Mistakes, of +course, are mine.

+

Preliminary implementation

+

A preliminary implementation is available in the + +feature/relative2 branch of the Boost Filesystem Git repository. See + +github.com/boostorg/filesystem/tree/feature/relative2

+

Requirements

+Requirement 1: Some uses require symlinks be followed; i.e. the path must be resolved in + the actual file system.

Requirement 2: Some uses require symlinks not be followed; i.e. the path must not be + resolved in the actual file system.

+Requirement 3: Some uses require removing redundant current directory (dot) + or parent directory (dot-dot) placeholders.

+Requirement 4: Some uses do not require removing redundant current directory (dot) + or parent directory (dot-dot) placeholders since the path is known to +be +already in normal form.

+

Issues

+

Issue 1: What happens if p +and base are themselves relative?

+Issue 2: What happens if there is no common prefix? Is this an error, the whole of + p is relative to base, or something else?

+Issue 3: What happens if p, base, or both are empty?

+Issue 4: What happens if p and base are the same?

+Issue 5: How is the "common prefix" determined?

+Issue 6: What happens if portions of p or base exist but + the entire path does not exist and yet symlinks need to be followed?

+Issue 7: What happens when a symlink in the existing portion of a path is affected + by a directory (dot-dot) placeholder in a later non-existent portion of + the path?

+

Issue 8: Overly complex semantics (and thus +specifications) in preliminary designs made reasoning about uses difficult.

+

Issue 9: Some uses never have redundant current directory (dot) + or parent directory (dot-dot) placeholders, so a removal operation + would be an unnecessary expense although otherwise harmless.

+ +

+ Design decisions

+ +

+ Provide separate lexical and + operational relative functions

+ +

+ Resolves the conflict between requirement 1 + and requirement 2 and ensures both + requirements are met.

+ +

+ A purely lexical function is needed by users working with directory + hierarchies that do not actually exist.

+ +

+ An operational function that queries the current file system for existence + and follows symlinks is needed by users working with actual existing + directory hierarchies.

+ +

+ Provide separate lexical and operational + proximate functions

+ +

+ Although not the only possibility, a likely fallback when the relative + functions cannot find a relative path is to return the path being made relative. As + a convenience, the proximate functions do just that.

+ +

+ Add lexical functions as + path member functions

+ +

+ The Filesystem library is unusual in that it has several functions with + both lexical (i.e. cheap) and operational (i.e. expensive due to file + system access) forms with differing semantics. It is important that users + choose the form that meets their application's specific needs. The library + has always made the distinction via the convention of lexical functions + being members of class path, while operational functions are + non-member functions. The lexical functions proposed here also use the + name prefix lexically_ to drive home the distinction.

+ +

+ For the contrary argument, see Sutter and Alexandrescu, C++ Coding Standards, 44: + "Prefer writing nonmember nonfriend functions", and Meyers, Effective C++ Third Edition, 23: + "Prefer non-member non-friend functions to member functions."

+ +

+ Provide a non-member function + lexically_normal returning a + normal form path

+ +

+ Enables resolution of requirement 3 and + requirement 4 in a way consistent with + issue 9. Is a contributor to the resolution of + issue 8.

+ +

+ "Normalization" is the process of removing redundant current directory (dot) + , parent + directory (dot-dot), and directory separator elements.

+ +

+ Normalization is a byproduct the current canonical function. + But for the path returned by the + proposed weakly_canonical function, + only any leading canonic portion is in canonical form. So any trailing + portion of the returned path has not been normalized.

+ +

+ Jamie Allsop has proposed adding a separate normalization function returning a + path, and I agree with him.

+ +

+ Boost.filesystem has a deprecated non-const normalization function that + modifies the path, but I agree with Jamie that a function returning a path + is a better solution.

+ +

+ Provide a weakly_canonical operational function

+ +

+ Resolves issue 6, issue 7, + issue 9, and is a contributor to the resolution of + issue 8.

+ +

+ The operational function + weakly_canonical(p) returns a path composed of + canonical(x)/y, where x is a path composed of the + longest leading sequence of elements in p that exist, and + y is a path composed of the remaining trailing non-existent elements of + p if any. "weakly" refers to weakened existence + requirements compared to the existing canonical function.

+ +
    +
  • Having weakly_canonical as a separate function, and then + specifying the processing of operational relative arguments in + terms of calls to weakly_canonical makes it much easier to + specify the operational relative function and reason about it. + The difficulty of reasoning about operational relative + semantics before the invention of weakly_canonical was what led to its + initial development.
  • +
  • Having weakly_canonical as a separate function also allows + use in other contexts.
  • +
  • Specifying the return be in normal form is an + engineering trade-off to resolve issue 7 in a way that + just works for most use cases.
  • +
  • Specifying normative encouragement to not perform unneeded normalization + is a reasonable resolution for issue 9.
  • +
+ +

+ Resolve issues in ways that "just work" for users

+ +

+ Resolves issues 1, 2, + 3, 4, 6, + and 7. Is a contributor to the resolution of + issue 8.

+ +

+ The "just works" approach was suggested by Jamie Allsop. It is implemented + by specifying a reasonable return value for all of the "What happens + if..." corner case issues, rather that treating them as hard errors + requiring an exception or error code.

+ +

+ Specify lexically relative in terms + of std::mismatch

+ +

+ Resolves issue 5. Is a contributor to the + resolution of issue 8.

+ +

+ Specify operational relative in terms of + weakly_canonical

+ +

+ Is a contributor to the resolution of issue 8.

+ +
    +
  • Covers a wide range of uses cases since a single function works for + existing, non-existing, and partially existing paths.
  • +
  • Works correctly for partially existing paths that contain symlinks.
  • +
+ +

+ Specify operational relative in terms of + lexically + relative

+ +

+ Is a contributor to the resolution of issue 5 and + issue 8.

+ +

+ If would be confusing to users and difficult to specify correctly if the + two functions had differing semantics:

+
    +
  • When either or both paths are empty.
  • +
  • When all elements of the two paths match exactly.
  • +
  • Because different matching algorithms were used.
  • +
  • Because although the same matching algorithm was used, it was applied in different ways.
  • +
+ +

+ These problems are avoided by specifying operational relative + in terms of lexical relative after preparatory + calls to operational functions.

+ +

Proposed wording

+ +

"Overview:" sections below are +non-normative experiments attempting to make the normative reference +specifications easier to grasp.

+ +

Define normal form

+ +

A path is in normal form if it has no +redundant current directory (dot) or parent directory (dot-dot) +elements. The normal form for an empty path is an empty path. The normal form +for a path ending in a directory-separator that is not the root directory +is the same path with a current directory (dot) element appended.

+ +

The last sentence above is not +necessary for POSIX-like or Windows-like operating systems, but supports systems +like OpenVMS that use different syntax for directory and regular-file names.

+ +

New class path member functions

+ +

Synopsis

+ +
path lexically_normal() const;
+path lexically_relative(const path& base) const;
+path lexically_proximate(const path& base) const;
+ +

Specification

+ + +
path lexically_normal() const;
+
+

Overview: Returns *this with redundant current directory +(dot), parent directory (dot-dot), and directory-separator elements removed.

+

Returns: *this in normal form.

+

Remarks: Uses operator/= to compose the returned path.

+

[Example:

+

assert(path("foo/./bar/..").lexically_normal() == "foo");
+assert(path("foo/.///bar/../").lexically_normal() == "foo/.");

+

The above assertions will succeed. On Windows, the +returned path's directory-separator characters will be backslashes rather than slashes, but that +does not affect path equality. —end example]

+
+ +
path lexically_relative(const path& base) const;
+
+

Overview: Returns *this made relative to base. + Treats empty or identical paths as corner cases, not errors. Does not resolve + symlinks. Does not first normalize *this or base.

+ +

Remarks: Uses std::mismatch(begin(), end(), base.begin(), base.end()), to determine the first mismatched element of + *this and base. Uses operator== to + determine if elements match.

+ +

Returns:

+ +
    +
  • + path() if the first mismatched element of *this is equal to + begin() or the first mismatched element + of base is equal to base.begin(), or
      +
  • +
  • + path(".") if the first mismatched element of + *this is equal to + end() and the first mismatched element + of base is equal to base.end(), or
      +
  • +
  • An object of class path composed via application of + operator/= path("..") for each element in the half-open + range [first + mismatched element of base, base.end()), and then + application of operator/= for each element in the half-open + range + [first mismatched element of *this, end()). +
  • +
+ +

[Example:

+

assert(path("/a/d").lexically_relative("/a/b/c") == "../../d");
+assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c");
+assert(path("a/b/c").lexically_relative("a") == "b/c");
+assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
+assert(path("a/b/c").lexically_relative("a/b/c") == ".");
+assert(path("a/b").lexically_relative("c/d") == "");

+

The above assertions will succeed. On Windows, the +returned path's directory-separators will be backslashes rather than +forward slashes, but that +does not affect path equality. —end example]

+ +

[Note: If symlink following semantics are desired, use the operational function + relative  —end note]

+ +

[Note: If normalization is needed to ensure + consistent matching of elements, apply lexically_normal() + to *this, base, or both. —end note]

+ +
+ + +
path lexically_proximate(const path& base) const;
+ +
+ +

Returns: If the value of lexically_relative(base) is + not an empty path, return it. Otherwise return *this.

+ +

[Note: If symlink following semantics are desired, use the operational function + proximate  —end note]

+ +

[Note: If normalization is needed to ensure + consistent matching of elements, apply lexically_normal() + to *this, base, or both. —end note]

+ +
+ + +

New operational functions

+ + +

Synopsis

+ + +
path weakly_canonical(const path& p);
+path weakly_canonical(const path& p, system::error_code& ec);
+path relative(const path& p, system::error_code& ec);
+path relative(const path& p, const path& base=current_path());
+path relative(const path& p, const path& base, system::error_code& ec);
+path proximate(const path& p, system::error_code& ec);
+path proximate(const path& p, const path& base=current_path());
+path proximate(const path& p, const path& base, system::error_code& ec);
+
+

Specification

+ +
path weakly_canonical(const path& p);
+path weakly_canonical(const path& p, system::error_code& ec);
+
+Overview: Returns p with symlinks resolved and the result +normalized.

+Returns: +A path composed of the result of calling the canonical function on +a path composed of the leading elements of p that exist, if any, +followed by the elements of p that do not exist, if any.

+

Postcondition: The returned path is in normal form.

+

Remarks: Uses operator/= to compose the returned path. +Uses the status function to determine existence.

+

Remarks: Implementations are encouraged to avoid unnecessary +normalization such as when canonical has already been called on the +entirety of p.

+

Throws:  As specified in Error reporting.

+
+
path relative(const path& p, system::error_code& ec);
+
+

Returns: relative(p, current_path(), ec).

+

Throws:  As specified in Error reporting.

+ +
+
path relative(const path& p, const path& base=current_path());
+path relative(const path& p, const path& base, system::error_code& ec);
+
+

Overview: Returns p made relative to + base. Treats empty or identical paths as corner cases, not errors. + Resolves symlinks and normalizes both p and base + before other processing.

+ +

Returns: weakly_canonical(p).lexically_relative(weakly_canonical(base)). The second form returns path() if an error occurs.

+

Throws: As specified in Error reporting.

+
+ +
path proximate(const path& p, system::error_code& ec);
+
+

Returns: proximate(p, current_path(), ec).

+

Throws:  As specified in Error reporting.

+ +
+
path proximate(const path& p, const path& base=current_path());
+path proximate(const path& p, const path& base, system::error_code& ec);
+
+ +

Returns: weakly_canonical(p).lexically_proximate(weakly_canonical(base)). The second form returns path() if an error occurs.

+

Throws: As specified in Error reporting.

+
+ +
+

© Copyright Beman Dawes 2015

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/release_history.html b/3rdparty/boost_filesystem/doc/release_history.html new file mode 100644 index 0000000..d84c8d3 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/release_history.html @@ -0,0 +1,680 @@ + + + + + + + +Filesystem Release History + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Release History +
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports   +
+ +

1.83.0

+
    +
  • Added directory_entry::refresh method that updates internal cached file statuses for the directory entry identified by path.
  • +
  • v4: directory_entry constructors and modifiers that initialize or modify the path now automatically call refresh. This may result in errors that were not indicated before and in v3, if querying the filesystem for file statuses fails (e.g. if the file does not exist). This new behavior is similar to std::filesystem.
  • +
  • v4: directory_entry constructors and methods taking file_status parameters are removed. Users are recommended to remove these arguments and rely on directory_entry calling refresh internally.
  • +
  • Added directory_entry member methods for checking the file type of the file, similar to std::filesystem.
  • +
  • Added more methods for testing file status: is_block_file, is_character_file, is_fifo, is_socket and is_reparse_file.
  • +
  • recursive_directory_iterator is now more likely to reuse information about the file type that is obtained during filesystem iteration. This may improve performance. (#288)
  • +
  • File streams defined in boost/filesystem/fstream.hpp are now movable, if the standard library file streams are. (#280)
  • +
  • Added a new header boost/filesystem/cstdio.hpp with a portable fopen overload that takes path as the first argument. This function is equivalent to std::fopen, except that on Windows it uses the native wide character encoding for paths.
  • +
  • Generic path comparison operators are now more restricted to avoid potential ambiguities when user's code contains a using namespace boost::filesystem; directive. (#285)
  • +
  • Fixed potential overload resolution ambiguity in users' code, where path constructors from iterators could interfere with function overloads taking a std::initializer_list argument. (#287)
  • +
  • On Windows, added more workarounds for errors returned by various filesystems when creating a directory iterator. (#284, #286)
  • +
  • On Windows, relaxed access rights needed for querying file times. (#290)
  • +
+ +

1.82.0

+
    +
  • Due to changes in Boost.System and some other libraries used in Boost.Filesystem, the support for C++03 is deprecated. C++11 will become the minimum starting with Boost.Filesystem 1.84.
  • +
  • Fixed compilation errors that could have been caused by path conversion constructors being too permissive on the accepted arguments. (#273)
  • +
  • v4: path::remove_filename now presesrves the trailing directory separator. (#271)
  • +
  • Added path::remove_filename_and_trailing_separators
  • , which removes the filename and directory separators preceding it from the path. This behavior is similar to path::remove_filename in Filesystem v3, but is also usable in v4. +
  • Added path::replace_filename, which replaces filename in a path.
  • +
  • Updated implementation of the library version selection to avoid ODR violations. (#279)
  • +
  • On Windows, added a workaround for querying file attributes for files in SMBv1 shares. Previously, directories in SMBv1 shares could have been reported as regular files. This does not affect SMBv2 or later. (#282)
  • +
+ +

1.81.0

+
    +
  • Deprecated: path construction, assignment and appending from containers of characters, such as std::vector<char> or std::list<wchar_t>, is deprecated in v3 and removed in v4. Please use string types or iterators instead.
  • +
  • Deprecated: boost/filesystem/path_traits.hpp header is deprecated and will be removed in a future release. The header contained implementation details of path and should not be used in user's code.
  • +
  • Previously deprecated APIs will now generate compilation warnings on use. To suppress these warnings, BOOST_FILESYSTEM_ALLOW_DEPRECATED macro can be defined when compiling user's code.
  • +
  • Fixed compilation due to a missing include on POSIX systems that do not support *at APIs. (#250)
  • +
  • On Windows prior to 10, added a workaround for network share filesystem that produces ERROR_INVALID_PARAMETER when constructing directory iterators. (PR#246, #245)
  • +
  • On Windows, fixed weakly_canonical failing with an ERROR_INVALID_FUNCTION error code if the path started with the "\\?\" prefix. (#247)
  • +
  • Added support for std::string_view, boost::string_view and boost::container::string (as well as respective wchar_t counterparts) in path constructors, assignment and appending operations. (#208)
  • +
  • path constructors, assignment and appending operations taking a pair of iterators will no longer accept iterators with value types that are not one of the supported path character types.
  • +
  • On Windows, improved compatibility of directory_iterator with various mounted filesystems and Wine releases prior to 7.21. (#255, #266)
  • +
  • On Windows, deduplicated files are now reported as regular files rather than reparse files. (#262)
  • +
+ +

1.80.0

+
    +
  • On Windows, added a fallback implementation for querying file attributes in case if the file cannot be opened with ERROR_ACCESS_DENIED error. This may allow status and symlink_status to succeed for system files and directories that are not reparse points or symlinks. (#234)
  • +
  • On Windows, added a workaround for FAT/exFAT filesystems that produce ERROR_INVALID_PARAMETER when querying file attributes. This affected status and symlink_status, which reported that files do not exist, and directory iterators, which failed to construct, as well as other dependent operations. (#236, #237)
  • +
  • Worked around a compilation problem on RTEMS. (#240)
  • +
  • On Linux, corrected switching to sendfile copy_file implementation if copy_file_range failed with ENOSYS in runtime. The sendfile fallback implementation used to skip the filesystem type check and could fail for some filesystems.
  • +
  • On POSIX systems supporting openat and related APIs defined in POSIX.1-2008 and on Windows Vista and later, improved protection of remove_all against CVE-2022-21658 that was implemented in the previous release. The previous fix could still result in removing unintended files in certain conditions. Other systems remain vulnerable.
  • +
+ +

1.79.0

+
    +
  • v3: path::replace_extension now works in terms of v3 definition of path::extension rather than v4.
  • +
  • Fixed compilation of path appending and concatenation operators with arguments of types convertible to path or compatible string type. (#223)
  • +
  • On POSIX systems that support fdopendir and O_NOFOLLOW and on Windows, remove_all is now protected against CVE-2022-21658. The vulnerability is a race condition that allows a third party process to replace a directory that is being concurrently processed by remove_all with a directory symlink and cause remove_all to follow the symlink and remove files in the linked directory instead of removing the symlink itself. (#224)
  • +
  • On Windows, in remove and remove_all implementation, use POSIX semantics for file removal, when supported by the OS (Windows 10 1709 and later). When POSIX semantics is supported, the file name is removed from the filesystem namespace as soon as the file is marked for deletion, even if it is still open and in use. With legacy Windows semantics, the file name remains present in the the filesystem namespace until the last file handle to the file is closed, which allows the file marked for deletion to be opened and prevents creating new files with the same name. (#216)
  • +
  • On Windows, remove and remove_all now support deleting read-only directories. Support for removing read-only non-directory files was added previously.
  • +
  • On Windows, directory_iterator internal implementation has been reworked to better utilize modern Windows APIs, which may improve performance while handling symlinks.
  • +
  • On Windows, initialize internal WinAPI function pointers early, if possible, to allow Boost.Filesystem operations to be invoked in global constructors. This is only supported on MSVC, GCC, Clang and compatible compilers.
  • +
  • On Windows, resize_file should no longer fail with an error if the file to be resized is opened.
  • +
  • Disabled use of the statx syscall on Android prior to 11.0 (API version 30). The syscall is blacklisted by seccomp and causes process termination in runtime. (#229)
  • +
  • Deprecated: boost/filesystem/string_file.hpp header is deprecated and will be removed in a future release. The header is no longer included by boost/filesystem.hpp by default. Users are advised to implement the functionality themselves or migrate to other implementations.
  • +
  • Deprecated: Windows CE support is deprecated and will be removed in a future release. Windows CE has been untested for many years and is likely non-functional.
  • +
+ +

1.78.0

+
    +
  • v4: path::filename and path::iterator no longer return an implicit trailing dot (".") element if the path ends with a directory separator. Instead, an empty path is returned, similar to C++17 std::filesystem. This also affects other methods that are defined in terms of iterators or filename, such as path::stem, path::compare or lexicographical_compare. For example, path("a/b/") == path("a/b/.") no longer holds true. (#193)
  • +
  • v4: path::lexically_normal no longer produce a trailing dot (".") element and omits a directory separator after a trailing dot-dot ("..") element in the normalized paths.
  • +
  • v4: path append operations now consider root name and root directory in the appended path. If the appended path is absolute, or root name is present and differs from the source path, the resulting path is equivalent to the appended path. If root directory is present, the result is the root directory and + relative path rebased on top of the root name of the source path. Otherwise, the behavior is similar to v3. (#214)
  • +
  • path::lexically_normal now converts directory separators to preferred separators in the root name of the normalized paths.
  • +
  • Optimized overloads of path::assign, path::append, path::concat and the corresponding operators to avoid unnecessary path copying and reduce the amount of code redundancy.
  • +
  • On POSIX systems, fixed absolute(p, base) returning a path with root name base.root_name() if p starts with a root directory. In such a case p is already an absolute path and should be returned as is.
  • +
  • create_directories no longer reports an error if the input path consists entirely of dot (".") and dot-dot ("..") elements. The implementation is no longer using recursion internally and therefore is better protected from stack overflow on extremely long paths.
  • +
  • On Windows, remove now supports deleting read-only files. The operation will attempt to reset the read-only attribute prior to removal. Note that this introduces a possibility of the read-only attribute being left unset, if the operation fails and the original value of the attribute fails to be restored. This also affects remove_all. (#216)
  • +
  • remove_all now returns static_cast< uintmax_t >(-1) in case of error, similar to C++17 std::filesystem.
  • +
  • Fixed a linking error about unresolved references to Boost.ContainerHash functions when user's code includes boost/filesystem/path.hpp but not boost/container_hash/hash.hpp and the compiler is set to preserve unused inline functions. (#215)
  • +
  • Added a workaround for MSVC and compatible compilers eliminating path globals cleanup in release builds. This could lead to a memory leak if Boost.Filesystem shared library was repeatedly loaded and unloaded in the process. (#217)
  • +
+ +

1.77.0

+
    +
  • Introducing Boost.Filesystem v4. This new version of the library removes all deprecated features of v3 and also makes a number of breaking API changes intended to make Boost.Filesystem more compatible with std::filesystem introduced in C++17. The differences are described in the release notes and documentation using v3 and v4 tags and are also summarised in a separate section. Users can select Boost.Filesystem version by defining BOOST_FILESYSTEM_VERSION macro to either 3 or 4 when compiling their code. There is no need to separately compile Boost.Filesystem for each library version — a single binary supports both v3 and v4. Users should avoid using both v3 and v4 in the same application as this can lead to subtle bugs. Currently, v3 is the default. In a future release v4 will become the default, and eventually v3 will be removed. v4 is functional, but it is still a work in progress and there may be breaking API changes in the future.
  • +
  • v4: path::filename, path::stem and path::extension no longer consider root name or root directory of the path as a filename if the path only consists of those components. For example, on Windows path("C:").filename() used to return "C:" and path("C:\\").filename() used to return "\" and both will return an empty path now. (#88, #194)
  • +
  • v4: path::stem and path::extension no longer treat a filename that starts with a dot and has no other dots as an extension. Filenames starting with a dot are commonly treated as filenames with an empty extension. The leading dot is used to indicate a hidden file on most UNIX-like systems. (#88)
  • +
  • New: Improved support for various path prefixes on Windows. Added support for local device prefix ("\\.\") and experimental support for NT path prefix ("\??\"). The prefixes will be included in the root name of a path. Note that using the prefixes with Boost.Filesystem v3 can lead to surprising results (e.g. path("\\\\.\\").stem() == "\\\\"). It is recommended to use the prefixes only with Boost.Filesystem v4.
  • +
  • Reworked path::lexically_normal implementation to eliminate some cases of duplicate dot (".") elements in the normalized paths.
  • +
  • New: Added runtime detection of the statx and getrandom system calls on Linux. This can be useful if the syscall is present at compile time but fails with ENOSYS at run time (for example, in Docker containers that restrict the syscall, even if available on the host). (#172)
  • +
  • New: Added support for disabling usage of various system APIs at library build time. This can be useful when a certain API is detected as present by the library configuration scripts but must not be used for some reason (for example, when runtime detection does not work on the target system). See the description of configuration macros for more details.
  • +
  • New: Added copy_options::synchronize_data and copy_options::synchronize options for the copy_file operation. These options allow to synchronize the written data and attributes with the permanent storage. These options are expensive in terms of performance, but allow to ensure reliability of the copied data. Note that copy_file performed implicit data synchronization on POSIX systems since Boost.Filesystem 1.74.0. This release adds support for more platforms and disables data synchronization by default while allowing the caller to explicitly request it. (#186)
  • +
  • Added handling of EINTR error code on POSIX systems for some system calls issued internally. In particular, EINTR could have been ignored on close, which on HP-UX would result in a leaked file descriptor.
  • +
  • In the copy_file implementations based on Linux sendfile and copy_file_range system calls, added handling of error codes indicating that a particular filesystem does not support the system call and fall back to the generic read/write loop. This should fix copy_file failing on eCryptFS and possibly other filesystems. (#184)
  • +
  • The copy_file_range system call is now used since Linux kernel 4.5, whereas previously it was only enabled since 5.3. The copy_file implementation will fall back to sendfile or read/write loop if copy_file_range fails to copy a given file across filesystems.
  • +
  • The copy_file implementations based on Linux sendfile and copy_file_range system calls will not be used on filesystems that are known to contain files with generated content. These system calls are incompatible with such files, and copying them would result in zero-sized files. The generic read/write loop will be used instead. Currently, the blacklisted filesystems are: procfs, sysfs, tracefs and debugfs.
  • +
  • In the copy_file implementation based on read/write loop, increased the maximum size of the buffer used for temporary storage and take into account the target filesystem block size for more optimal performance.
  • +
  • On Windows CE, calling current_path to obtain the current path for a process will now fail with an error instead of returning successfully with a root path. This platform does not support current directory. Changing the current path was already failing similarly in previous releases of Boost.Filesystem.
  • +
  • In canonical, fixed the check for a symlink referencing a directory above root, if an earlier symlink was resolved to an absolute path with a different root from the original path.
  • +
  • In canonical, added a limit for the maximum number of symlinks that can be resolved during the call. The limit is currently at least 40 symlinks.
  • +
  • On Windows, canonical and weakly_canonical will now use path::preferred_separator for the root directory separator in the resulting paths. This fixes "file not found" errors caused by Windows API not handling generic separators in UNC paths and paths that start with the Win32 filesystem prefix ("\\?\"). (#87, #187)
  • +
  • New: Added weakly_canonical overloads taking base path as an argument.
  • +
  • On Windows, weakly_canonical no longer fails with an error if the input path contains elements that do not exist in the filesystem but are cancelled by a subsequent dot-dot ("..") element. For example, weakly_canonical("C:\\a\\..") would previously fail if "C:\a" directory did not exist. (#201)
  • +
  • In read_symlink on Windows, corrected reparse point handling. The operation would return an empty path for some mount points (for example, created by Box cloud storage driver) and directory junction points that had empty print names. The new implementation now parses substitute name of the reparse point and attempts to reconstruct a Win32 path from it. (#187)
  • +
  • On Windows, file streams provided in boost/filesystem/fstream.hpp will use wide character paths on libc++ versions 7.0 and higher, when the standard library supports opening files with wide character paths. (#181)
  • +
  • On Windows, creating symlinks should no longer require elevated privileges, if Windows is configured in Developer mode.
  • +
  • With some compilers, global objects used internally in Boost.Filesystem are now destroyed after user's global destructors are called. This allows to call Boost.Filesystem methods during the program termination stage. In particular, this concerns the path locale that is used for character code conversion and can be installed by calling path::imbue. The supported compilers include MSVC, GCC and Clang, as well as other compilers that support customizing program initialization order through #pragma section (for MSVC-compatible compilers) or __attribute__ ((init_priority)) (for GCC-compatible compilers).
  • +
+ +

1.76.0

+
    +
  • Updated compatibility with WASI platform. (PR#169)
  • +
  • Fixed an exception being thrown by path::remove_filename if the path is "////". (#176)
  • +
  • Fixed create_directories disregarding errors from file status query operations issued internally. This could result in incorrect error codes returned by create_directories. (#182)
  • +
+ +

1.75.0

+
    +
  • New: Added creation_time operation, which allows to obtain file creation time. (Inspired by PR#134)
  • +
  • The returned value of last_write_time(p, ec) operation in case of failure has been changed to a minimal value representable by std::time_t instead of -1.
  • +
  • The returned value of hard_link_count(p, ec) operation in case of failure has been changed to static_cast<uintmax_t>(-1) instead of 0.
  • +
  • On POSIX systems, file_size will now indicate error code errc::function_not_supported if the path resolves to a non-regular file. Previously, errc::operation_not_permitted was reported.
  • +
  • On Linux, many operations now use statx system call internally, when possible, which allows to reduce the amount of information queried from the filesystem and potentially improve performance. The statx system call was introduced in Linux kernel 4.11.
  • +
  • Removed const-qualification from return types of some path methods. This could prevent move construction and move assignment at the call site in some cases. (#160)
  • +
  • On OpenBSD 4.4 and newer, use statvfs system call to obtain filesystem space information. (Inspired by PR#162)
  • +
  • On Windows, space now returns with an error if the provided path does not idendify an existing file. (#167)
  • +
+ +

1.74.0

+
    +
  • Removed compile-time checks for support for symlinks and hardlink on Windows. Instead, a runtime check is used. (PR#142)
  • +
  • Fixed handling of reparse points in canonical and read_symlink on Windows. This also affects other algorithms that involve canonical and read_symlink in their implementation. (PR#100, #85, #99, #123, #125)
  • +
  • Fixed that read_symlink on Windows could potentially fail or cause failures elsewhere with a sharing violation error, if the same symlink was opened concurrently. (#138)
  • +
  • Fixed that is_symlink(directory_entry) would always return false, even if the directory entry actually referred to a symlink. (PR#148)
  • +
  • Added missing status inspection operation overloads for directory_entry and error_code (e.g. is_directory(directory_entry, error_code&)). Removed incorrect noexcept specifications for the overloads not taking the error_code arguments.
  • +
  • copy_file implementation has been updated to perform checks on the source and target files, as required by C++20 ([fs.op.copy.file]/4.1). In particular, the operation will fail if the source or target file is not a regular file or the source and target paths identify the same file.
  • +
  • copy_file on POSIX systems will now also copy the source file permissions to the target file, if the target file is overwritten.
  • +
  • New: Added copy_file implementations based on sendfile and copy_file_range system calls on Linux, which may improve file copying performance, especially on network filesystems.
  • +
  • Deprecated: The copy_option enumeration that is used with the copy_file operation is deprecated. As a replacement, the new enum copy_options (note the trailing 's') has been added. The new enum contains values similar to the copy_options enum from C++20. The old enum values are mapped onto the new enum. The old enum will be removed in a future release.
  • +
  • New: Added copy_options::skip_existing option, which allows copy_file operation to succeed without overwriting the target file, if it exists.
  • +
  • New: Added copy_options::update_existing option, which allows copy_file operation to conditionally overwrite the target file, if it exists, if its last write time is older than that of the replacement file.
  • +
  • New: copy_file now returns bool, which indicates whether the file was copied.
  • +
  • New, breaking change: copy operation has been extended and reworked to implement behavior specified in C++20 [fs.op.copy]. This includes support for copy_options::recursive, copy_options::copy_symlinks, copy_options::skip_symlinks, copy_options::directories_only, copy_options::create_symlinks and copy_options::create_hard_links options. The operation performs additional checks based on the specified options. Applying copy to a directory with default copy_options will now also copy files residing in that directory (but not nested directories or files in those directories).
  • +
  • New: Added create_directory overload taking two paths. The second path is a path to an existing directory, which is used as a source of permission attributes to use in the directory to create.
  • +
  • Deprecated: copy_directory operation has been deprecated in favor of the new create_directory overload. Note that the two operations have reversed order of the path arguments.
  • +
  • equivalent on POSIX systems now returns the actual error code from the OS if one of the paths does not resolve to a file. Previously the function would return an error code of 1. (#141)
  • +
  • equivalent no longer considers file size and last modification time in order to test whether the two paths refer to the same file. These checks could result in a false negative if the file was modified during the equivalent call.
  • +
  • New: Added absolute overloads taking error_code argument.
  • +
  • Operations that have current_path() as the default value of their arguments and also have an error_code argument will use the current_path(error_code& ec) overload to obtain the current path, so that its failure is reported via the error_code argument instead of an exception.
  • +
  • space now initializes the space_info structure members to -1 values on error, as required by C++20 ([fs.op.space]/1).
  • +
  • space on Windows now accepts paths referring to arbitrary files, not only directories. This is similar to POSIX systems and corresponds to the operation description in C++20. (#73)
  • +
  • New: Added implementation of temp_directory_path for Windows CE. (PR#25)
  • +
  • New: Improved compatibility with WASI platform. (PR#144)
  • +
  • New: Improved support for Embarcadero compilers. (PR#130)
  • +
  • New: Added implementations of unique_path operation based on getrandom (Linux), arc4random_buf (OpenBSD/FreeBSD/CloudABI) and BCrypt (Windows) system APIs.
  • +
  • Deprecated: Auto-linking against system libraries on Windows with MSVC-compatible compilers is deprecated and will be removed in a future release. This affects users linking against static library of Boost.Filesystem. Users are advised to update their project build systems to either use a shared library of Boost.Filesystem, or explicitly specify the dependencies of Boost.Filesystem in the linker command line. In the future, the dependency information may also be exposed through CMake config files.
  • +
+ +

1.72.0

+
    +
  • Extracted filesystem_error to exception.hpp; file_status and associated enums and functions to file_status.hpp; directory_entry, directory_iterator and recursive_directory_iterator to directory.hpp.
  • +
  • Deprecated: For backward compatibility operations.hpp still includes the new headers exception.hpp, file_status.hpp and directory.hpp, unless BOOST_FILESYSTEM_NO_DEPRECATED macro is defined. These implicit includes are considered deprecated and will be removed in a future release. Users are encouraged to include the new headers directly or include filesystem.hpp.
  • +
  • The filesystem_error exception is now implemented in the compiled library of Boost.Filesystem. Users may need to add linking with Boost.Filesystem library in their projects.
  • +
  • On POSIX.1-2008 platforms, use utimensat instead of utime. utime is declared obsolete in POSIX.1-2008 and can be disabled e.g. in uClibc-ng. (PR#115)
  • +
  • directory_iterator is now left in the end state on memory allocation errors.
  • +
  • In directory_iterator on POSIX systems, support for readdir/readdir_r has been reworked to avoid memory allocations for dirent structures when readdir is used. This reduces memory consumption and eliminates the possibility of buffer overruns in case if readdir produces a very long directory name.
  • +
  • On Windows, use Boost.WinAPI to select the target Windows version.
  • +
  • New: Added directory_options enum, which reflects the same named enum from C++20. The enum is supported in directory_iterator and recursive_directory_iterator to customize iteration behavior. In particular, the iterators now support skipping directories that can't be opened due to insufficient permissions. The symlink_option enum is now deprecated and should be replaced with directory_options.
  • +
  • By default, recursive_directory_iterator is now reset to the end state in case of errors, as required by C++20. (#112)
  • +
  • New: Added directory_options::pop_on_error option, which configures recursive_directory_iterator so that it attempts to recover from iteration errors by repeatedly invoking pop() until it succeeds or the end state is reached. (#113)
  • +
  • New: Added directory_options::skip_dangling_symlinks option, which configures recursive_directory_iterator so that it doesn't follow dangling directory symlinks and continues iteration instead of reporting an error.
  • +
  • Deprecated: The following members of recursive_directory_iterator are now marked as deprecated: level(), no_push_pending(), no_push_request(), no_push(). Users are advised to replace their use with the standard counterparts: depth(), recursion_pending(), disable_recursion_pending(). Note that recursion_pending() has the opposite meaning compared to no_push_pending() and no_push_request(). Deprecated methods will be removed in a future release.
  • +
  • Fixed path::lexically_relative (and any dependent algorithms) to correctly handle empty, dot and dot-dot path elements in its argument. The behavior is made closer to C++17 std::path::lexically_relative in that empty and dot path elements are ignored and dot-dot path elements are accounted by decreasing the number of dot-dot path elements to generate in the resulting relative path. (#76)
  • +
+ +

1.71.0

+
    +
  • New: Added minimal support for CMake. (PR#106)
  • +
  • Fixed incorrect error_code returned from directory iterator increment when readdir_r is used.
  • +
  • For path, fixed rvalue-aware operator/ return type to return an rvalue instead of rvalue reference. This fixes leaving a dangling reference in the user's code if the result of operator/ is bound to a const reference. (#110)
  • +
  • Fixes for better compatibility with Windows CE. (PR#24)
  • +
+ +

1.70.0

+
    +
  • New: Added support for movability to directory iterators.
  • +
  • New: Added file status query overloads for directory_entry. This avoids a relatively expensive OS query when file status is requested for a result of dereferencing a directory iterator. (PR#55)
  • +
  • Fixed a few instances of dereferencing std::string::end() in path implementation.
  • +
  • Fixed program termination in case of out of memory condition in directory iterators constructors and operations accepting a reference to error_code. (#58)
  • +
  • Fixed possible linking errors caused by missing definitions of static members of path. (#12759)
  • +
  • Fixed possible use of uninitialized data in directory iterator increment operation on Linux. (#97)
  • +
  • Reworked current_path and read_symlink implementation to avoid possible memory exhaustion on broken or tampered with filesystems. The functions now have an internal limit of the path size they will accept from the OS, which is currently 16 MiB.
  • +
  • Increased the size of the internal buffer used by copy_file.
  • +
+ +

1.69.0

+
    +
  • Don't use readdir_r on Linux and Android since the readdir function is already thread-safe. (PR#68, + #72)
  • +
  • Fixed crashes in boost::filesystem::copy due to undefined behavior in the implementation. (PR#71)
  • +
  • Fixed undefined behavior in boost::filesystem::directory_iterator implementation. (PR#77)
  • +
  • Fixed compilation errors when using directory iterators with BOOST_FOREACH.
  • +
  • Removed workarounds for older PGI C++ compiler versions to fix compilation on the newer ones. (PR#49)
  • +
  • Fixed MSVC warnings about narrowing conversions. (PR#44)
  • +
+ +

1.67.0

+
    +
  • Fix static initialization issue that caused a crash if path operations were used before main(). (PR#62, + PR#43, PR#50, PR#59)
  • +
+ +

1.66.0

+
    +
  • Clean up some tutorial example code and fix the wording for it in the + tutorial. Thanks to Anmol-Singh-Jaggi for pull request #11.
  • +
+ +

1.64.0

+
    +
  • is_empty()overload with error_code parameter + should not throw on error. Thanks to ldqrk for pull request #42
  • +
  • Fix #10731 and + #9480, Evaluate + path.extension only once. Thanks to Daniel Krügler for pull request #41.
  • +
  • Fix error propagation in space(p, ec). Thanks to cmuellner + for pull request #39.
  • +
  • Add test/config_info.cpp to increase macro state reporting in hopes of + easing debugging on remote machines.
  • +
  • Fix operations_test failure on MinGW: MinGW defines + __MINGW32__ rather than _MSC_VER, so also test for __MINGW32__ to see if + setenv/unsetenv workaround needed.
  • +
+ +

1.63.0

+
    +
  • +

    Deprecated generic() function name: The undocumented experimental class + path member function generic() has been renamed + generic_path(). Fixes + #11855, generic + gives problems in C++/CLI. Unless the macro BOOST_FILESYSTEM_NO_DEPRECATED + is defined, the original generic() will continue to be supplied + as a workaround for existing user code. But generic()is + deprecated. User code should migrate to the new name.

  • +
  • New: Class path adds constexpr constants + separator and dot of the type appropriate for the + platform, and adds query functions + filename_is_dot and + filename_is_dot_dot. + These add convenience and the implementations may be more efficient that user + coded equivalent functions.
  • +
  • Fix #12578, + Make directory iterators able to detect when a copy has advanced to the end. + This bug in directory_iterator and + recursive_directory_iterator equality testing has existed more than a + dozen years. Nowadays test driven development would likely have detected the + problem in early development. Sigh.
  • +
  • Fix #12495, + create_directories() crashes when passed empty string as path, + from Samantha Ritter. Also affected create_directory(). Charles + Olivi submitted a pull request with some particularly helpful test cases.
  • +
  • Fix #7307, + remove_all(dirname,ec) throws on write protected directories. This is a + tough one to test. There are three internal function calls where errors might + arise, and it would take too much time to write tests for each of those cases. + Someday we will have Titus Winter's mock installable file system, but for now + are relying on code inspection rather than testing.
  • +
  • Fix a cygwin warning and a cygwin error. Thanks to thtrummer for pull + request #30.
  • +
  • Fixed two broken links in reference docs. Thanks to tbeu for pull + request #34.
  • +
  • Fix reference doc signatures for path stem(), extension() + member functions. Thanks to faithandbrave for pull request #31
  • +
  • Fix broken link to #7506 in 1.60.0 Release History (Daniel Krügler).
  • +
  • Refactor push_directory()internal logic so it is easier to + reason about.
  • +
+ +

1.60.0

+
    +
  • +

    New: Added functions + lexically_normal, + lexically_relative, + relative, and + weakly_canonical. Many thanks to Jamie Allsop for his help and + perseverance. Resolves tickets + #1976, + #5897, + #6249

  • +
  • New: Class path now has + reverse_iterator, + const_reverse_iterator, rbegin(), and rend().
  • +
  • New: C++11 noexcept supplied as specified in the + Filesystem TS if supported by the compiler.
  • +
  • New: C++11 move constructors and move assignments supplied as + specified in the Filesystem TS if supported by the compiler. Resolves + #10291.
  • +
  • New: Existing functions whose names changed in the Filesystem TS + are now supported under both the old and new names.
  • +
  • New: Added size() + function to class path. Resolves + #6874, Path + should have a size() member function.
  • +
  • Clear several spurious GCC warnings.
  • +
  • Fix #11733, + Missing unistd.h include in boost/libs/filesystem/src/unique_path.cpp by + apply a patch from Idar Tollefsen.
  • +
  • Fix a race condition in unique_path by applying + pull request #15 + from Sebastian Redl. Also fixes + #7506, unique_path Fails on Windows for Temporary User + Profiles.
  • +
  • Fix bug in file_status and + recursive_directory_iterator: C++ turns an explicit constructor + with all arguments except first defaulted into non-explicit single argument + constructor.
  • +
  • Fix #10591, + boost::filesystem does not build on iOS 8, by applying a patch submitted + by Daniel Seither.
  • +
  • Fix #9454, + Boost Filesystem [library build] not compiling when + BOOST_FILESYSTEM_NO_DEPRECATED is defined, by applying a patch submitted + by Makesim.
  • +
  • Fix #11447, + __OpenBSD__ macro name misspelled, by applying a patch submitted by Jasper + Lievisse Adriaanse.
  • +
  • +

    Fix #11288, + A patch to avoid redundant string allocations, + by applying a patch submitted by Yevhen Ivannikov.

  • +
  • Fix #11175, + out-of-date documentation causing users to incorrectly expect that the library + could be used with exceptions disabled.
  • +
  • Resolve #11166 + by mitigating (i.e. reducing the likelihood of) a possible external file + system race in remove().
  • +
  • +

    Fix #7258, + create_directories returns false if the path ends with a slash. + Also fix related issues if path contains dot or dot-dot + elements, and added test cases to the test suite.

  • +
  • +

    Reference docs editorial cleanups: Use same style sheet as the + rest of the documentation. Tweak tab font size. Fix excessively long lines in + tables, synopsis.

  • +
  • Resolve + #10766, parent_path() with redundant separator returns wrong value, + by adding examples and notes to the reference documentation to show why the + returned value is in fact correct, and to provide rationale for that behavior. + See [path.itr], and + [path.decompose] + parent_path() and filename() sections of the reference + docs.
  • +
  • Minor other fixes, including pull requests from Jonathan Wakely and Marcel + Raad.
  • +
  • Closed several tickets as duplicates or otherwise resolved by the + above changes:
      +
    • #7607, path + should not infer an invisible "." at the end of a path that ends with a slash; + #7258, + #10766
    • +
    • #11061, + #11062, + impossible to traverse the path of the reverse iterator, is effectively + resolved by the addition of the class path reverse iteration + feature. The reference documentation has also been updated with + a note warning about the + limitations of class path iterators.
    • +
    + +
  • +
+ +

1.59.0

+
    +
  • Update the Tutorial:
      +
    • Use C++11 in the example programs to improve clarity.
    • +
    • Update the example source code show to match the actual example source + code in the cpp files.
    • +
    • Rerun all the examples and update the output shown in the tutorial + accordingly.
    • +
    • Fix spacing and other HTML presentation issues.
    • +
    +
  • +
  • Fix #11491, + temp_directory_path() doesn't return valid temp path on Android.
  • +
+ +

1.58.0

+
    +
  • Fix #6124, + #6779, and + #10038. Cannot + pass a BOOST_SCOPED_ENUM to a compiled function because it will result in an + undefined reference if the library is compiled with -std=c++0x but the use is + compiled in C++03 mode, or visa versa.
  • +
  • Rewrite Windows implementation of temp_directory_path() to (1) avoid + GetTempPath() failure if path length > 130 (ticket #5300) and (2) provide a + more sensible sequence of directories than provided by GetTempPath(), per + boost list discussion "[filesystem] temp_directory_path() behavior on + Windows". The new sequence is:
      +
    1. %TMP%
    2. +
    3. %TEMP%
    4. +
    5. %LOCALAPPDATA%/Temp
    6. +
    7. %USERPROFILE%/Temp
    8. +
    9. GetWindowsDirectoryW()/Temp
    10. +
    +
  • +
+ +

1.57.0

+
    +
  • Rework class path locale and codecvt implementation for increased reliability. + This change was SVN revision 83021, which should have gone into 1.56.0 but + unfortunately the merge didn't happen until too late.
  • +
  • Fix tickets #8930, #9054, + #9219, + #10228, and + #10641, all + related to locales and codecvt facets.
  • +
  • The net effect of the above changes and fixes should be to eliminate + spurious "locale::facet::_S_create_c_locale name not valid" errors on Linux + and other non-BSD POSIX-like systems. The error will continue to occur, as it + should, when a path encoding conversion char-to-wchar_t or wchar_t-to-char is + attempted in an environment without a valid C locale (for example, if the LANG + environment variable is invalid or not defined).
  • +
  • Fix #6124, + #6779, and + #10038 - an + undefined reference that occurred when the library was compiled for C++03 but + the using program was compiled for C++11, or vice versa. The private library + interface has been changed to use a plain-old C++03 enum. This is the fix + suggested by Andy in 6779.
  • +
  • The Windows implementation now treats NTFS directory junctions (also known + as junctions, also known as mount points) as symlinks. This has the effect of + treating directory junctions as directories, and thus supporting all + operations suitable for directories. This resolves + #9016. Directory + junctions are very similar to symlinks, but may have performance or other + advantages in some situations. They can be created from the command line with + "mklink /j link target". There is no plan for Boost.Filesystem to + be able to create them directly other than by calling std::system().
  • +
+ +

1.56.0

+
    +
  • Reorganize recursive_directory_iterator::increment, adding an + invariant that progress is always made, even if an error is reported by + exception or error_code. Add a manually executed test, + test/issues/recurse_dir_iter_5403.cpp. Adjust regular regression tests + as needed. Thanks to Claudio Bley for the + pull request - the + change was incorporated into the reorganized code. Fixes + #5403 and + #6821.
  • +
  • Fix canonical() to treat parent of root as root. (Christian + Hammerl) Fixes #9683 + and #10187.
  • +
  • Added missing test for __sun macro which is defined on + Solaris 10. (Chris Stylianou)
  • +
  • Minor fixes and code cleanup.
  • +
  • Update IDE projects to Visual Studio 2013.
  • +
  • Remove unused const char colon to clear clang warning. (J?gen + Hunold)
  • +
  • Add BOOST_NOEXCEPT to class filesystem_error.
  • +
  • Change perms::all_all and perms::perms_mask to + absolute values to quiet intellisense warnings, and conform to C++11.
  • +
+ +

1.54.0

+
    +
  • Reimplement path::codecvt() and path::imbue() + with portable code that is intended to be much more robust and maintainable. A + section on path usage concerns has + been added to the reference documentation describing several concerns that + arise in the context of multithreading and path::codecvt().
  • +
+ +

1.52.0

+
    +
  • Fix #7239, Stack + overflow when calling create_directories(":D"). The reported + problem was a symptom of an internal bug that caused path::filename() + and path::parent_path() to fail on Windows for path(":"), + and that in turn caused other functions that depend on filename() + or parent_path() to fail, such as create_directories().
  • +
+ +

1.51.0

+
    +
  • Add begin() and end() non-member functions for directory_iterator and + recursive_directory_iterator so that C++11 range-based for statements work. + Suggested by feature requests + #5896 and + #6521, using the + #5896 approach.
  • +
  • Add range_begin() and range_end() non-member functions for directory_iterator and + recursive_directory_iterator so that + BOOST_FOREACH works.
  • +
  • Fix a Linux fchmodat problem affecting symlink permissions reported during + discussion of #6659.
  • +
  • Fix #6659 and + #7051, fchmodat + supported only on Solaris 11. Fix for both Sun and GCC compilers.
  • +
+ +

1.50.0

+
    +
  • Remove Filesystem Version 2 from the distribution. Version 3 is now the + only distributed version. Those still using V2 are urged to migrate to V3 as + soon as possible.
  • +
  • Add constexpr value_type preferred_separator to class path.
  • +
  • Fix #5118, + replace_extension doesn't work as specified in documentation. The + documentation, implementation, and test cases have all had fixes applied. The + documentation had failed to mention that any existing extension is removed. + The behavior for simple cases has been reverted to the Version 2 behavior, but + with corrections so that complex replacements now work. Two test cases from + #5118 have been added.
  • +
  • Fix #3737, + Boost.Filesystem does not compile on Windows Mobile. On Windows, <sys/stat.h> + is no longer included.
  • +
  • Fix #4065, + Boost Filesystem lexicographic path comparison inconsistent. This required + multiple source code bug fixes and code cleanup, correcting problems not + related to lexicographical issues.
  • +
  • Add class path member function compare for consistency with + std::string.
  • +
  • Tighten BOOST_FILESYSTEM_DYN_LINK and BOOST_FILESYSTEM_STATIC_LINK logic + in filesystem/config.hpp so that one or the other is always defined, and both + being defined is a #error.
  • +
  • Fix #6690 and + #6737, resolving + static linking related problems with VC++ 8 through 11. Note that this fix may + reintroduce codecvt thread safety problems + #4889, + #6320, for these + compilers if static linking is used.
  • +
  • Add path::operator+= and concat functions to tack on things like suffixes + or numbers. Suggested by Ed Smith-Rowland and others.
  • +
  • Fix #6809, + Implementation of filesystem::rename() method for MS Windows is wrong, by + adding MOVEFILE_COPY_ALLOWED to deal with renames across drives, volumes, file + systems. Fix has no effect on non-Windows systems.
  • +
  • Fix #6819, A path operand with a source that was a one character array was + treated as empty, even if it wasn't empty. Such arrays can occur in unions or + in code using C variable length array idioms.
  • +
  • Fix #6932, + create_directories throws exception even if error_code is specified.
  • +
+ +

1.49.0

+
    +
  • Fix #3714, + Added test cases and fixes for class path errors when assignment or append + used self or portion of self as source.
  • +
  • Fix #4889, + #6320, Locale codecvt_facet not thread safe on Windows. Move + Windows, Mac OS X, locale and codecvt facet back to namespace scope. POSIX + except OS X uses local static initialization (IE lazy) to ensure exceptions + are catchable if environmental variables are misconfigured and to avoid use of + locale("") if not actually used.
  • +
  • Fix #5652, + recursive_directory_iterator fails on cyclic symbolic links. Thanks to Daniel Aarno for the patch.
  • +
  • Fix #5653, + recursive_directory_iterator(error_code) can still throw filesystem_error.
  • +
  • Fix #5900, directory_iterator + access violation on Windows if error is thrown. Thanks to Andreas Eckleder for the patch.
  • +
  • Fix #5900 + comment 2, a bug in director_iterator construction with error_code argument that + caused increment to be called without the ec argument being passed.
  • +
  • Fix #5989 by cleaning up test suite path_test.cpp code even + though the ticket itself was not a defect, and clarifying docs; iteration over a path yields + generic format.
  • +
  • Fix #5592, Change Windows codecvt processing from CP_THREAD_ACP to CP_ACP.
  • +
  • Operations function fixes for PGI compiler, thanks to Noel Belcourt.
  • +
  • Relax permissions test to reflect reality, particularly on the Sandia test + platforms.
  • +
+ +

1.48.0

+
    +
  • Added operational function canonical(), + suggested by David Svoboda, who also provided pseudo-code.
  • +
  • Added hash_value() function for + paths. (Daniel James)
  • +
  • Fix path inserter problem (#5764) + reported for QNX6.3.2 host (gcc-3.3.5)
  • +
  • Fix problem of locale("") exception being thrown before main() starts on + poorly configured (e.g. LANG="bad name") POSIX systems. Resolves the most + serious aspect of tickets + #4688, + #5100, + #5289.
  • +
+ +

1.47.0

+
    +
  • Program file_status.cpp added (V3). See boost-root/libs/filesystem/v3/example. + Useful both as an example and to explore how Boost.Filesystem treats various + status errors.  Run "bjam" (NOT "bjam install") in the example directory + to install in example/bin.
  • +
+ +

1.46.1

+ +
    +
  • Fix fstream problem for STLPort masquerading as Dinkumware (#5217).
  • +
+ +

1.46.0

+
    +
  • Version 3 of the library is now the default.
  • +
  • IBM vacpp: Workaround for compiler bug affecting iterator_facade. (#4912)
  • +
  • Verify, clarify, document that <boost/config/user.hpp> can be used to + specify BOOST_FILESYSTEM_VERSION. (#4891)
  • +
  • Replaced C-style assert with BOOST_ASSERT.
  • +
  • Undeprecated unique_path(). Instead, add a note mentioning the workaround + for lack of thread safety and possible change to cwd. unique_path() is just + too convenient to deprecate!
  • +
  • Cleared several GCC warnings.
  • +
  • Changed V2 code to use BOOST_THROW_EXCEPTION.
  • +
  • Windows: Fix status() to report non-symlink reparse point correctly.
  • +
  • Add symlink_option to recursive_directory_iterator, + allowing control over recursion into directory symlinks. Note that the default + is changed to not recurse into directory symlinks.
  • +
  • Reference documentation cleanup, including + fixing missing and broken links, and adding missing functions.
  • +
  • Miscellaneous implementation code cleanup.
  • +
+
+

© Copyright Beman Dawes, 2011

+

© Copyright Andrey Semashev, 2019-2021

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + diff --git a/3rdparty/boost_filesystem/doc/styles.css b/3rdparty/boost_filesystem/doc/styles.css new file mode 100644 index 0000000..3bd5313 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/styles.css @@ -0,0 +1,18 @@ +body +{ + font-family: arial, sans-serif; + max-width: 90%; + margin: 0px auto; +} +ins {background-color: #CCFFCC; text-decoration: none;} +del {background-color: #FFCACA; text-decoration: none;} +pre {background-color: #D7EEFF; font-family: "Courier New", "Courier", monospace;} +code {font-size: 110%; font-family: "Courier New", "Courier", monospace;} +table {font-size: 90%;} + +/* + * (c) Copyright Beman Dawes, 2014 + * (c) Copyright Andrey Semashev, 2021 + * Distributed under the Boost Software License, Version 1.0. + * See www.boost.org/LICENSE_1_0.txt + */ diff --git a/3rdparty/boost_filesystem/doc/tickets.html b/3rdparty/boost_filesystem/doc/tickets.html new file mode 100644 index 0000000..78be923 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/tickets.html @@ -0,0 +1,52 @@ + + + + + + + +Filesystem Tickets + + + + +

 

+

Locale related

+

#3332 +boost::filesystem::path will get trouble in locale Chinese_Taiwan.950 (windows)
+#7211 path_locale +destructor crashes when overloaded operator new and delete are present
+#8388 +windows_file_codecvt should be allocated with _NEW_CRT
+#8642 Global locale +prevents from using Boost.Filesystem in global constructors and destructors
+#8930 +boost::path::root_directory() throws locale::facet::_S_create_c_locale name not +valid
+#9182 +Boost-filesystem std::runtime_error: locale::facet::_S_create_c_locale name not +valid failure on Xamarin.Android
+#9219 path::codecvt() +is called when not required
+#9560 +operations_test_static unit test crashes during static initialization phase on +Mac/10.7/32-bit/darwin-4.2.1
+#10205 FileSystem +runtime error: locale::facet::_S_create_c_locale name not valid
+

+

TR alignment

+

Work has started to bring the library into alignment with the C++ File System +Technical Specification (HTML) +(PDF). +This work is occurring on the +git +ts-develop branch, and is currently very unstable.

+
    +
  • #10291 path + doesn't have move constructor/assignment operator.
  • +
+ + + + diff --git a/3rdparty/boost_filesystem/doc/tutorial.html b/3rdparty/boost_filesystem/doc/tutorial.html new file mode 100644 index 0000000..e6a8689 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/tutorial.html @@ -0,0 +1,1356 @@ + + + + + + + +Filesystem Tutorial + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Tutorial +
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

+ Introduction
+ Preliminaries
+ Reporting the size of a file - (tut1.cpp)
+ Using status queries to determine file existence and type - (tut2.cpp)
+ Directory iteration plus catching + exceptions - (tut3.cpp)
+ Using path decomposition, plus sorting results - (tut4.cpp)
+ Class path: Constructors, including + Unicode - (tut5.cpp)
+ Class path: Generic format vs. Native format
+ Class path: Iterators, observers, composition, decomposition, and query - (path_info.cpp)
+ Error reporting
+

+

Introduction

+ +

This tutorial develops a little command line program to list information +about files and directories - essentially a much simplified version of the POSIX ls or Windows dir +commands. We'll start with the simplest possible version and progress to more +complex functionality. Along the way we'll digress to cover topics you'll need +to know about to understand Boost.Filesystem.

+ +

Source code for each of the tutorial programs is available, and you +are encouraged to compile, test, and experiment with it. To conserve space, we won't +always show boilerplate code here, but the provided source is complete and +ready to build.

+ +

Preliminaries

+ +

Install the Boost distribution if you haven't already done so. See the +Boost Getting +Started docs.

+ +

This tutorial assumes you have bootstrapped Boost.Build and compiled Boost.Filesystem +as described in the Getting Started article. The b2 executable is expected +to be available in PATH.

+ +
+ +
+

Fire up your command line interpreter, and type the following commands:

+ + + + + + + + +
Ubuntu Linux
+
$ cd boost-root/libs/filesystem/example
+
+$ b2 tutorial
+Compiling example programs...
+
+$ ./tut1
+Usage: tut1 path
+
+ +   + + + + + + + + +
Microsoft Windows
+
>cd boost-root\libs\filesystem\example
+
+>b2.exe tutorial
+Compiling example programs...
+
+>tut1
+Usage: tut1 path
+
+ +

If the tut1 command outputs "Usage: tut1 path", all +is well. The tutorial example programs are available in +boost-root/libs/filesystem/example. Should you modify +and experiment with them as the tutorial progresses, just invoke b2 tutorial again +to rebuild.

+ +

If something didn't work right, here are some troubleshooting suggestions:

+ +
    +
  • If the b2 program executable isn't being found, check your path environmental variable + or see + Boost + Getting Started.
  • +
  • Look at Boost bootstrap output to try to spot an indication of the + problem.
  • +
+ +

Reporting the size of a file - (tut1.cpp)

+ +

Let's get started. Our first example program, tut1.cpp, +reports the size of a file:

+ + + + + +
+
#include <iostream>
+#include <boost/filesystem.hpp>
+using namespace boost::filesystem;
+
+int main(int argc, char* argv[])
+{
+  if (argc < 2)
+  {
+    std::cout << "Usage: tut1 path\n";
+    return 1;
+  }
+  std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
+  return 0;
+}
+
+ +

The Boost.Filesystem file_size +function returns a uintmax_t +containing the size of the file named by the argument. The declaration looks +like this:

+ +
+
uintmax_t file_size(const path& p); 
+
+

For now, all you need to know is that class path has constructors that take +const char * and other string types. (If you can't wait to +find out more, skip ahead to the class path section of +the tutorial.)

+

Please take a minute to try out tut1 on your system, using a +file that is known to exist, such as tut1.cpp. Here is what the +results look like on two different operating systems:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut1 tut1.cpp
+tut1.cpp 569
+
$ ls -l tut1.cpp
+-rw-rw-r-- 1 beman beman 569 Jul 26 12:04 tut1.cpp
+
+ +   + + + + + + + + + +
Microsoft Windows
+
>tut1 tut1.cpp
+tut1.cpp 592
+
+>dir tut1.cpp
+...
+07/26/2015 07:20 AM 592 tut1.cpp
+...
+
+ +

So far, so good. The reported Linux and Windows sizes are different because +the Linux tests used "\n" line endings, while the Windows tests +used "\r\n" line endings. The sizes reported may differ +from the above if changes have been made to tut1.cpp.

+

Now try again, but give a path that doesn't exist:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut1 foo
+terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
+what(): boost::filesystem::file_size: No such file or directory: "foo"
+Aborted (core dumped)
+
+ +  + + + + + + + + +
Microsoft Windows
+
>tut1 foo
+

An exception is thrown;
+ the exact form of the response depends on + Windows system options.

+ +

What happens? + There's no file named foo in the current directory, so by default an +exception is thrown. See Error reporting to learn + about error reporting via error codes rather than exceptions.

+

Try this:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut1 .
+terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
+what(): boost::filesystem::file_size: Operation not permitted: "."
+Aborted (core dumped)
+
+ +   + + + + + + + + +
Microsoft Windows
+
>tut1 .
+

An exception is thrown;
+ the exact form of the response depends on Windows system options.

+ +

The current directory exists, but file_size() works on regular + files, not directories, so again an exception is thrown.

+ +

We'll deal with those situations in tut2.cpp.

+ +

Using status queries to determine file existence and type - (tut2.cpp)

+ +

Boost.Filesystem includes status query functions such as +exists, +is_directory, and +is_regular_file. These return +bool's, and will return true if the condition +described by their name is met. Otherwise they return false, +including when any element +of the path argument can't be found.

+ +

tut2.cpp uses several of the status query functions to cope with non-existent +files and with different kinds of files:

+ + + + + +
+
#include <iostream>
+#include <boost/filesystem.hpp>
+using namespace std;
+using namespace boost::filesystem;
+
+int main(int argc, char* argv[])
+{
+  if (argc < 2)
+  {
+    cout << "Usage: tut2 path\n";
+    return 1;
+  }
+
+  path p(argv[1]);  // avoid repeated path construction below
+
+  if (exists(p))    // does path p actually exist?
+  {
+    if (is_regular_file(p))        // is path p a regular file?
+      cout << p << " size is " << file_size(p) << '\n';
+
+    else if (is_directory(p))      // is path p a directory?
+      cout << p << " is a directory\n";
+
+    else
+      cout << p << " exists, but is not a regular file or directory\n";
+  }
+  else
+    cout << p << " does not exist\n";
+
+  return 0;
+}
+
+ +

Give it a try:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut2 tut2.cpp
+"tut2.cpp" size is 997
+
+$ ./tut2 foo
+"foo" does not exist
+
+$ ./tut2 .
+"." is a directory
+
+ +  + + + + + + + + +
Microsoft Windows
+
>tut2 tut2.cpp
+tut2.cpp size is 1039
+
+>tut2 foo
+"foo" does not exist
+
+>tut2 .
+"." is a directory
+
+ +

Although tut2 works OK in these tests, the output is less than satisfactory +for a directory. We'd typically like to see a list of the directory's contents. In tut3.cpp +we will see how to iterate over directories.

+ +

But first, let's try one more test:

+ + + + + + + + +
Ubuntu Linux
+
$ ls /home/jane/foo
+ls: cannot access /home/jane/foo: No such file or directory
+
+$ ./tut2 /home/jane/foo
+terminate called after throwing an instance of 'boost::
+filesystem::filesystem_error>'
+   what(): boost::filesystem::status: Permission denied:
+     "/home/jane/foo"
+Aborted
+
+ +   + + + + + + + + +
Microsoft Windows
+
>dir e:\
+The device is not ready.
+
+>tut2 e:\
+

An exception is thrown;
+ the exact form of the response depends on + Windows system options.

+ +

On the Linux system, the test was being run from an account that did not have +permission to access /home/jane/foo. On the Windows system, +e: was a Compact Disc reader/writer that was not ready. End users +shouldn't have to interpret cryptic exceptions reports, so as we move on to tut3.cpp +we will increase the robustness of the code, too.

+ +

Directory iteration plus catching +exceptions - (tut3.cpp)

+ +

Boost.Filesystem's +directory_iterator class is just what we need here. It follows the +general pattern of the standard library's istream_iterator. Constructed from +a path, it iterates over the contents of the directory. A default constructed directory_iterator +acts as the end iterator.

+ +

The value type of directory_iterator is +directory_entry. A +directory_entry object contains path and file_status +information. A directory_entry object +can be used directly, but can also be passed to path arguments in function calls.

+ +

The other need is increased robustness in the face of the many kinds of +errors that can affect file system operations. We could do that at the level of +each call to a Boost.Filesystem function (see Error +reporting), but for simplicity tut3.cpp +uses an overall try/catch block.

+ + + + + +
+
#include <iostream>
+#include <boost/filesystem.hpp>
+using std::cout;
+using namespace boost::filesystem;
+
+int main(int argc, char* argv[])
+{
+  if (argc < 2)
+  {
+    cout << "Usage: tut3 path\n";
+    return 1;
+  }
+
+  path p (argv[1]);
+
+  try
+  {
+    if (exists(p))
+    {
+      if (is_regular_file(p))
+        cout << p << " size is " << file_size(p) << '\n';
+
+      else if (is_directory(p))
+      {
+        cout << p << " is a directory containing:\n";
+
+        for (directory_entry& x : directory_iterator(p))
+          cout << "    " << x.path() << '\n';
+      }
+      else
+        cout << p << " exists, but is not a regular file or directory\n";
+    }
+    else
+      cout << p << " does not exist\n";
+  }
+
+  catch (const filesystem_error& ex)
+  {
+    cout << ex.what() << '\n';
+  }
+
+  return 0;
+}
+
+ +

Give tut3 a try, passing it a path to a directory as a command line argument. +Here is a run on a checkout of the Boost Git develop branch, followed by a repeat +of the test cases that caused exceptions on Linux and Windows:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut3 ~/boost/develop
+    "/home/beman/boost/develop" is a directory containing:
+    "/home/beman/boost/develop/rst.css"
+    "/home/beman/boost/develop/boost"
+    "/home/beman/boost/develop/boost.png"
+    "/home/beman/boost/develop/libs"
+    "/home/beman/boost/develop/doc"
+    "/home/beman/boost/develop/project-config.jam.2"
+    "/home/beman/boost/develop/.gitmodules"
+    "/home/beman/boost/develop/boostcpp.py"
+    "/home/beman/boost/develop/.travis.yml"
+    "/home/beman/boost/develop/.gitattributes"
+    "/home/beman/boost/develop/index.htm"
+    "/home/beman/boost/develop/index.html"
+    "/home/beman/boost/develop/bjam"
+    "/home/beman/boost/develop/project-config.jam.1"
+    "/home/beman/boost/develop/LICENSE_1_0.txt"
+    "/home/beman/boost/develop/.git"
+    "/home/beman/boost/develop/tools"
+    "/home/beman/boost/develop/stage"
+    "/home/beman/boost/develop/boostcpp.jam"
+    "/home/beman/boost/develop/Jamroot"
+    "/home/beman/boost/develop/.gitignore"
+    "/home/beman/boost/develop/INSTALL"
+    "/home/beman/boost/develop/more"
+    "/home/beman/boost/develop/bin.v2"
+    "/home/beman/boost/develop/project-config.jam"
+    "/home/beman/boost/develop/boost-build.jam"
+    "/home/beman/boost/develop/bootstrap.bat"
+    "/home/beman/boost/develop/bootstrap.sh"
+    "/home/beman/boost/develop/status"
+    "/home/beman/boost/develop/boost.css"
+
+ +   + + + + + + + + + +
Microsoft Windows
+
>tut3 \boost\develop
+"\boost\develop" is a directory containing:
+    "\boost\develop\.git"
+    "\boost\develop\.gitattributes"
+    "\boost\develop\.gitignore"
+    "\boost\develop\.gitmodules"
+    "\boost\develop\.travis.yml"
+    "\boost\develop\bin.v2"
+    "\boost\develop\boost"
+    "\boost\develop\boost-build.jam"
+    "\boost\develop\boost.css"
+    "\boost\develop\boost.png"
+    "\boost\develop\boostcpp.jam"
+    "\boost\develop\boostcpp.py"
+    "\boost\develop\bootstrap.bat"
+    "\boost\develop\bootstrap.sh"
+    "\boost\develop\doc"
+    "\boost\develop\index.htm"
+    "\boost\develop\index.html"
+    "\boost\develop\INSTALL"
+    "\boost\develop\Jamroot"
+    "\boost\develop\libs"
+    "\boost\develop\LICENSE_1_0.txt"
+    "\boost\develop\more"
+    "\boost\develop\project-config.jam"
+    "\boost\develop\rst.css"
+    "\boost\develop\stage"
+    "\boost\develop\status"
+    "\boost\develop\tools"
+
>tut3 e:\
+boost::filesystem::status: The device is not ready: "e:\"
+
+ +

Not bad, but we can make further improvements:

+ +
    +
  • The listing would be much easier to read if only the filename was + displayed, rather than the full path.
  • +
  • The Linux listing isn't sorted. That's because the ordering of + directory iteration is unspecified. Ordering depends on the underlying + operating system API and file system specifics. So we need to sort the + results ourselves.
  • +
+ +

The next sections show how those changes play out, so read on!

+ +

Using path decomposition, plus sorting results - (tut4.cpp)

+ +

For directories, tut4.cpp builds a +std::vector of all the entries and then sorts it before writing to +cout.

+ + + + + +
+
#include <iostream>
+#include <vector>
+#include <algorithm>
+#include <boost/filesystem.hpp>
+using std::cout;
+using namespace boost::filesystem;
+
+int main(int argc, char* argv[])
+{
+  if (argc < 2)
+  {
+    cout << "Usage: tut4 path\n";
+    return 1;
+  }
+
+  path p (argv[1]);
+
+  try
+  {
+    if (exists(p))
+    {
+      if (is_regular_file(p))
+        cout << p << " size is " << file_size(p) << '\n';
+
+      else if (is_directory(p))
+      {
+        cout << p << " is a directory containing:\n";
+
+        std::vector<path> v;
+
+        for (auto&& x : directory_iterator(p))
+          v.push_back(x.path());
+
+        std::sort(v.begin(), v.end());
+
+        for (auto&& x : v)
+          cout << "    " << x.filename() << '\n';
+      }
+      else
+        cout << p << " exists, but is not a regular file or directory\n";
+    }
+    else
+      cout << p << " does not exist\n";
+  }
+
+  catch (const filesystem_error& ex)
+  {
+    cout << ex.what() << '\n';
+  }
+
+  return 0;
+}
+ +
+ +

The only difference between tut3.cpp and tut4.cpp is + what happens for directories. We changed:

+
+
for (const directory_entry& x : directory_iterator(p))
+  cout << " " << x.path() << '\n';
+
+

to:

+
+
std::vector<path> v;
+
+for (auto&& x : directory_iterator(p))
+  v.push_back(x.path());
+
+std::sort(v.begin(), v.end());
+
+for (auto&& x : v)
+  cout << " " << x.filename() << '\n';
+
+
+

+ filename() is one of + several class path decomposition functions. It extracts the + filename portion + from a path (i.e. "index.html" + from "/home/beman/boost/trunk/index.html"). These decomposition functions are + more fully explored in the Path iterators, observers, + composition, decomposition and query portion of this tutorial.

+

The above was written as two lines of code for clarity. It could have + been written more concisely as:

+
+
v.push_back(it->path().filename()); // we only care about the filename
+
+

Here is the output from a test of tut4.cpp:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut4 ~/boost/develop
+"/home/beman/boost/develop" is a directory containing:
+    ".git"
+    ".gitattributes"
+    ".gitignore"
+    ".gitmodules"
+    ".travis.yml"
+    "INSTALL"
+    "Jamroot"
+    "LICENSE_1_0.txt"
+    "bin.v2"
+    "boost"
+    "boost-build.jam"
+    "boost.css"
+    "boost.png"
+    "boostcpp.jam"
+    "boostcpp.py"
+    "bootstrap.bat"
+    "bootstrap.sh"
+    "doc"
+    "index.htm"
+    "index.html"
+    "libs"
+    "more"
+    "project-config.jam"
+    "project-config.jam.1"
+    "project-config.jam.2"
+    "rst.css"
+    "stage"
+    "status"
+    "tools"
+
+ +  + + + + + + + + +
Microsoft Windows
+
>tut4 \boost\develop
+"\boost\develop" is a directory containing:
+    ".git"
+    ".gitattributes"
+    ".gitignore"
+    ".gitmodules"
+    ".travis.yml"
+    "INSTALL"
+    "Jamroot"
+    "LICENSE_1_0.txt"
+    "bin.v2"
+    "boost"
+    "boost-build.jam"
+    "boost.css"
+    "boost.png"
+    "boostcpp.jam"
+    "boostcpp.py"
+    "bootstrap.bat"
+    "bootstrap.sh"
+    "doc"
+    "index.htm"
+    "index.html"
+    "libs"
+    "more"
+    "project-config.jam"
+    "project-config.jam.1"
+    "project-config.jam.2"
+    "rst.css"
+    "stage"
+    "status"
+    "tools"
+
+ +

That completes the main portion of this tutorial. If you haven't already + worked through the Class path sections of this tutorial, dig into them now. + The Error reporting section may also be of + interest, although it can be skipped unless you are deeply concerned about + error handling issues.

+ +

Class path: Constructors, +including Unicode - (tut5.cpp)

+ +

Traditional C interfaces pass paths as const char* arguments. +C++ interfaces may add const std::string& overloads, but adding +overloads becomes untenable if wide characters, containers, and iterator ranges +need to be supported.

+

Passing paths as const path& arguments is far simpler, yet far +more flexible because class path itself is far more flexible:

+
    +
  1. Class path supports multiple character types and encodings, including Unicode, to + ease internationalization.
  2. +
  3. Class path supports multiple source types, such as iterators for null terminated + sequences, iterator ranges, containers (including std::basic_string), + and directory_entry's, + so functions taking paths don't need to provide several overloads.
  4. +
  5. Class path supports both native and generic pathname formats, so programs can be + portable between operating systems yet use native formats where desirable.
  6. +
  7. Class path supplies a full set of iterators, observers, composition, + decomposition, and query functions, making pathname manipulations easy, + convenient, reliable, and portable.
  8. +
+

Here is how (1) and (2) work. Class path constructors, +assignments, and appends have member templates for sources. For example, here +are the constructors that take sources:

+ +
+
template <class Source>
+  path(Source const& source);
+
template <class InputIterator>
+  path(InputIterator begin, InputIterator end);
+
+

Let's look at a little program that shows how comfortable class path is with +both narrow and wide characters in C-style strings, C++ strings, and via C++ +iterators:

+ + + + + +
+
#include <boost/filesystem/fstream.hpp>
+#include <string>
+#include <list>
+namespace fs = boost::filesystem;
+
+int main()
+{
+  // \u263A is "Unicode WHITE SMILING FACE = have a nice day!"
+  std::string narrow_string ("smile2");
+  std::wstring wide_string (L"smile2\u263A");
+  std::list<char> narrow_list;
+  narrow_list.push_back('s');
+  narrow_list.push_back('m');
+  narrow_list.push_back('i');
+  narrow_list.push_back('l');
+  narrow_list.push_back('e');
+  narrow_list.push_back('3');
+  std::list<wchar_t> wide_list;
+  wide_list.push_back(L's');
+  wide_list.push_back(L'm');
+  wide_list.push_back(L'i');
+  wide_list.push_back(L'l');
+  wide_list.push_back(L'e');
+  wide_list.push_back(L'3');
+  wide_list.push_back(L'\u263A');
+
+  { fs::ofstream f("smile"); }
+  { fs::ofstream f(L"smile\u263A"); }
+  { fs::ofstream f(narrow_string); }
+  { fs::ofstream f(wide_string); }
+  { fs::ofstream f(narrow_list); }
+  { fs::ofstream f(wide_list); }
+  narrow_list.pop_back();
+  narrow_list.push_back('4');
+  wide_list.pop_back();
+  wide_list.pop_back();
+  wide_list.push_back(L'4');
+  wide_list.push_back(L'\u263A');
+  { fs::ofstream f(fs::path(narrow_list.begin(), narrow_list.end())); }
+  { fs::ofstream f(fs::path(wide_list.begin(), wide_list.end())); }
+
+  return 0;
+}
+
+ +

Testing tut5:

+ + + + + + + + +
Ubuntu Linux
+
$ ./tut5
+
+$ ls smile*
+smile smile☺ smile2 smile2☺ smile3 smile3☺ smile4 smile4☺
+
+ +  + + + + + + + + +
Microsoft Windows
+
>tut5
+
+>dir /b smile*
+smile
+smile2
+smile2☺
+smile3
+smile3☺
+smile4
+smile4☺
+smile☺
+
+ +

The exact appearance of the smiling face will depend on the font, +font size, and other settings for your command line window. The above tests were +run with out-of-the-box Ubuntu 14.04 and Windows 7, US Edition. If you don't get +the above results, take a look at the boost-root/libs/filesystem/example +directory with your system's GUI file browser, such as Linux Nautilus, Mac OS X +Finder, or Windows Explorer. These tend to be more comfortable with +international character sets than command line interpreters.

+ +

Class path takes care of whatever character type or encoding + conversions are required by the particular operating system. Thus as + tut5 demonstrates, it's no problem to pass a wide character string to a + Boost.Filesystem operational function even if the underlying operating system + uses narrow characters, and visa versa. And the same applies to user supplied + functions that take const path& arguments.

+ +

Class path also provides path syntax that is portable across operating systems, + element iterators, and observer, composition, decomposition, and query + functions to manipulate the elements of a path. The next section of this + tutorial deals with path syntax.

+ +

Class path: Generic format vs. Native format

+ +

Class path deals with two different pathname +formats - generic format and native format. For POSIX-like +file systems, these formats are the same. But for users of Windows and +other non-POSIX file systems, the distinction is important. Even +programmers writing for POSIX-like systems need to understand the distinction if +they want their code to be portable to non-POSIX systems.

+ +

The generic format is the familiar /my_directory/my_file.txt format used by POSIX-like +operating systems such as the Unix variants, Linux, and Mac OS X. Windows also +recognizes the generic format, and it is the basis for the familiar Internet URL +format. The directory +separator character is always one or more slash characters.

+ +

The native format is the format as defined by the particular +operating system. For Windows, either the slash or the backslash can be used as +the directory separator character, so /my_directory\my_file.txt +would work fine. Of course, if you write that in a C++ string literal, it +becomes "/my_directory\\my_file.txt".

+ +

If a drive specifier or a backslash appears +in a pathname on a Windows system, it is always treated as the native format.

+ +

Class path has observer functions that allow you to +obtain the string representation of a path object in either the native format +or the generic format. See the next section +for how that plays out.

+ +

The distinction between generic format and native format is important when + communicating with native C-style API's and with users. Both tend to expect + paths in the native format and may be confused by the generic format. The generic + format is great, however, for writing portable programs that work regardless + of operating system.

+ +

The next section covers class path observers, composition, + decomposition, query, and iteration over the elements of a path.

+ +

Class path: Iterators, observers, composition, decomposition, and query +- (path_info.cpp)

+ +

The path_info.cpp program is handy for learning how class path +iterators, +observers, composition, decomposition, and query functions work on your system.

+ + + + + + +
+
#include <iostream>
+#include <boost/filesystem.hpp>
+using namespace std;
+using namespace boost::filesystem;
+
+const char * say_what(bool b) { return b ? "true" : "false"; }
+
+int main(int argc, char* argv[])
+{
+  if (argc < 2)
+  {
+    cout << "Usage: path_info path-element [path-element...]\n"
+            "Composes a path via operator/= from one or more path-element arguments\n"
+            "Example: path_info foo/bar baz\n"
+#            ifdef BOOST_POSIX_API
+            "         would report info about the composed path foo/bar/baz\n";
+#            else  // BOOST_WINDOWS_API
+            "         would report info about the composed path foo/bar\\baz\n";
+#            endif
+    return 1;
+  }
+
+  path p;
+  for (; argc > 1; --argc, ++argv)
+    p /= argv[1];  // compose path p from the command line arguments
+
+  cout  <<  "\ncomposed path:\n";
+  cout  <<  "  operator<<()---------: " << p << "\n";
+  cout  <<  "  make_preferred()-----: " << p.make_preferred() << "\n";
+
+  cout << "\nelements:\n";
+  for (auto element : p)
+    cout << "  " << element << '\n';
+
+  cout  <<  "\nobservers, native format:" << endl;
+# ifdef BOOST_POSIX_API
+  cout  <<  "  native()-------------: " << p.native() << endl;
+  cout  <<  "  c_str()--------------: " << p.c_str() << endl;
+# else  // BOOST_WINDOWS_API
+  wcout << L"  native()-------------: " << p.native() << endl;
+  wcout << L"  c_str()--------------: " << p.c_str() << endl;
+# endif
+  cout  <<  "  string()-------------: " << p.string() << endl;
+  wcout << L"  wstring()------------: " << p.wstring() << endl;
+
+  cout  <<  "\nobservers, generic format:\n";
+  cout  <<  "  generic_string()-----: " << p.generic_string() << endl;
+  wcout << L"  generic_wstring()----: " << p.generic_wstring() << endl;
+
+  cout  <<  "\ndecomposition:\n";
+  cout  <<  "  root_name()----------: " << p.root_name() << '\n';
+  cout  <<  "  root_directory()-----: " << p.root_directory() << '\n';
+  cout  <<  "  root_path()----------: " << p.root_path() << '\n';
+  cout  <<  "  relative_path()------: " << p.relative_path() << '\n';
+  cout  <<  "  parent_path()--------: " << p.parent_path() << '\n';
+  cout  <<  "  filename()-----------: " << p.filename() << '\n';
+  cout  <<  "  stem()---------------: " << p.stem() << '\n';
+  cout  <<  "  extension()----------: " << p.extension() << '\n';
+
+  cout  <<  "\nquery:\n";
+  cout  <<  "  empty()--------------: " << say_what(p.empty()) << '\n';
+  cout  <<  "  is_absolute()--------: " << say_what(p.is_absolute()) << '\n';
+  cout  <<  "  has_root_name()------: " << say_what(p.has_root_name()) << '\n';
+  cout  <<  "  has_root_directory()-: " << say_what(p.has_root_directory()) << '\n';
+  cout  <<  "  has_root_path()------: " << say_what(p.has_root_path()) << '\n';
+  cout  <<  "  has_relative_path()--: " << say_what(p.has_relative_path()) << '\n';
+  cout  <<  "  has_parent_path()----: " << say_what(p.has_parent_path()) << '\n';
+  cout  <<  "  has_filename()-------: " << say_what(p.has_filename()) << '\n';
+  cout  <<  "  has_stem()-----------: " << say_what(p.has_stem()) << '\n';
+  cout  <<  "  has_extension()------: " << say_what(p.has_extension()) << '\n';
+
+  return 0;
+}
+
+ + +

Run the examples below on your system, and try some different path arguments +as we go along. Here is the invocation we will talk about in detail:

+ + + + + + + + +
Ubuntu Linux
+
$ ./path_info /foo bar baa.txt
+
+composed path:
+  operator<<()---------: "/foo/bar/baa.txt"
+  make_preferred()-----: "/foo/bar/baa.txt"
+
+elements:
+  "/"
+  "foo"
+  "bar"
+  "baa.txt"
+
+observers, native format:
+  native()-------------: /foo/bar/baa.txt
+  c_str()--------------: /foo/bar/baa.txt
+  string()-------------: /foo/bar/baa.txt
+  wstring()------------: /foo/bar/baa.txt
+
+observers, generic format:
+  generic_string()-----: /foo/bar/baa.txt
+  generic_wstring()----: /foo/bar/baa.txt
+
+decomposition:
+  root_name()----------: ""
+  root_directory()-----: "/"
+  root_path()----------: "/"
+  relative_path()------: "foo/bar/baa.txt"
+  parent_path()--------: "/foo/bar"
+  filename()-----------: "baa.txt"
+  stem()---------------: "baa"
+  extension()----------: ".txt"
+
+query:
+  empty()--------------: false
+  is_absolute()--------: true
+  has_root_name()------: false
+  has_root_directory()-: true
+  has_root_path()------: true
+  has_relative_path()--: true
+  has_parent_path()----: true
+  has_filename()-------: true
+  has_stem()-----------: true
+  has_extension()------: true
+
+ +   + + + + + + + + +
Microsoft Windows
+
>path_info \foo bar baa.txt
+
+composed path:
+operator<<()---------: "\foo\bar\baa.txt"
+make_preferred()-----: "\foo\bar\baa.txt"
+
+elements:
+  "/"
+  "foo"
+  "bar"
+  "baa.txt"
+
+observers, native format:
+native()-------------: \foo\bar\baa.txt
+c_str()--------------: \foo\bar\baa.txt
+string()-------------: \foo\bar\baa.txt
+wstring()------------: \foo\bar\baa.txt
+
+observers, generic format:
+generic_string()-----: /foo/bar/baa.txt
+generic_wstring()----: /foo/bar/baa.txt
+
+decomposition:
+root_name()----------: ""
+root_directory()-----: "\"
+root_path()----------: "\"
+relative_path()------: "foo\bar\baa.txt"
+parent_path()--------: "\foo\bar"
+filename()-----------: "baa.txt"
+stem()---------------: "baa"
+extension()----------: ".txt"
+
+query:
+empty()--------------: false
+is_absolute()--------: false
+has_root_name()------: false
+has_root_directory()-: true
+has_root_path()------: true
+has_relative_path()--: true
+has_parent_path()----: true
+has_filename()-------: true
+has_stem()-----------: true
+has_extension()------: true
+
+ +

We will go through the above code in detail to gain a better +understanding of what is going on.

+ +

A common need is to compose a path from its constituent +directories. Class path uses / and /= operators to +append elements. That's a reminder +that these operations append the operating system's preferred directory +separator if needed. The preferred +directory separator is a slash on POSIX-like systems, and a backslash on +Windows-like systems.

+ +

That's what this code does before displaying the resulting +path p using the class path stream inserter:

+ + + + + + +
+
  path p;
+  for (; argc > 1; --argc, ++argv)
+    p /= argv[1];  // compose path p from the command line arguments
+
+  cout  <<  "\ncomposed path:\n";
+  cout  <<  "  operator<<()---------: " << p << "\n";
+  cout  <<  "  make_preferred()-----: " << p.make_preferred() << "\n";
+
+ + +

One abstraction for thinking about a path is as a sequence of elements, where +the elements are directory and file names. To support this abstraction, class +path provides iterators and also begin() +and end() functions.

+ +

Here is the code that produced the list of elements in the above output listing:

+ + + + + +
+
cout << "\nelements:\n";
+for (auto element : p)
+  cout << " " << element << '\n';
+
+ +

Let's look at class path observer functions:

+ + + + + + +
+
  cout  <<  "\nobservers, native format:" << endl;
+# ifdef BOOST_POSIX_API
+  cout  <<  "  native()-------------: " << p.native() << endl;
+  cout  <<  "  c_str()--------------: " << p.c_str() << endl;
+# else  // BOOST_WINDOWS_API
+  wcout << L"  native()-------------: " << p.native() << endl;
+  wcout << L"  c_str()--------------: " << p.c_str() << endl;
+# endif
+  cout  <<  "  string()-------------: " << p.string() << endl;
+  wcout << L"  wstring()------------: " << p.wstring() << endl;
+
+  cout  <<  "\nobservers, generic format:\n";
+  cout  <<  "  generic_string()-----: " << p.generic_string() << endl;
+  wcout << L"  generic_wstring()----: " << p.generic_wstring() << endl;
+
+ + +

Native format observers should be used when interacting with the +operating system or with users; that's what they expect.

+ +

Generic format observers should be used when the results need to be +portable and uniform regardless of the operating system.

+ +

path objects always hold pathnames in the native +format, but otherwise leave them unchanged from their source. The +preferred() function will convert to the +preferred form, if the native format has several forms. Thus on Windows, it will +convert slashes to backslashes.

+ +

Moving on to decomposition:

+ + + + + + +
+
  cout  <<  "\ndecomposition:\n";
+  cout  <<  "  root_name()----------: " << p.root_name() << '\n';
+  cout  <<  "  root_directory()-----: " << p.root_directory() << '\n';
+  cout  <<  "  root_path()----------: " << p.root_path() << '\n';
+  cout  <<  "  relative_path()------: " << p.relative_path() << '\n';
+  cout  <<  "  parent_path()--------: " << p.parent_path() << '\n';
+  cout  <<  "  filename()-----------: " << p.filename() << '\n';
+  cout  <<  "  stem()---------------: " << p.stem() << '\n';
+  cout  <<  "  extension()----------: " << p.extension() << '\n';
+
+ + +

 And, finally, query functions:

+ + + + + + +
+
  cout  <<  "\nquery:\n";
+  cout  <<  "  empty()--------------: " << say_what(p.empty()) << '\n';
+  cout  <<  "  is_absolute()--------: " << say_what(p.is_absolute()) << '\n';
+  cout  <<  "  has_root_name()------: " << say_what(p.has_root_name()) << '\n';
+  cout  <<  "  has_root_directory()-: " << say_what(p.has_root_directory()) << '\n';
+  cout  <<  "  has_root_path()------: " << say_what(p.has_root_path()) << '\n';
+  cout  <<  "  has_relative_path()--: " << say_what(p.has_relative_path()) << '\n';
+  cout  <<  "  has_parent_path()----: " << say_what(p.has_parent_path()) << '\n';
+  cout  <<  "  has_filename()-------: " << say_what(p.has_filename()) << '\n';
+  cout  <<  "  has_stem()-----------: " << say_what(p.has_stem()) << '\n';
+  cout  <<  "  has_extension()------: " << say_what(p.has_extension()) << '\n';
+
+ + +

These are pretty self-evident, but do note the difference in the +result of is_absolute() between Linux and Windows. Because there is +no root name (i.e. drive specifier or network name), a lone slash (or backslash) +is a relative path on Windows but an absolute path on POSIX-like operating +systems.

+ +

Error reporting

+ +

The Boost.Filesystem file_size function, like many of the + operational functions, has two overloads:

+ +
+
uintmax_t file_size(const path& p);
+uintmax_t file_size(const path& p, system::error_code& ec);
+
+

The only significant difference between the two is how they report errors.

+

The + first signature will throw exceptions to report errors. A +filesystem_error exception will be thrown +on an + operational error. filesystem_error is derived from std::runtime_error. +It has a + member function to obtain the +error_code reported by the source + of the error. It also has member functions to obtain the path or paths that caused + the error.

+ +
+ +

Motivation for the second signature: Throwing exceptions on errors was the entire error reporting story for the earliest versions of + Boost.Filesystem, and indeed throwing exceptions on errors works very well for + many applications. But user reports trickled in that some code became so + littered with try and catch blocks as to be unreadable and unmaintainable. In + some applications I/O errors aren't exceptional, and that's the use case for + the second signature.

+ +
+ +

Functions with a system::error_code& argument set that + argument to report operational error status, and so do not throw exceptions when I/O + related errors occur. For a full explanation, see + Error reporting in the reference + documentation.

+ +
+

© Copyright Beman Dawes 2010, 2015

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/v3.html b/3rdparty/boost_filesystem/doc/v3.html new file mode 100644 index 0000000..b266fae --- /dev/null +++ b/3rdparty/boost_filesystem/doc/v3.html @@ -0,0 +1,150 @@ + + + + + + +Filesystem V3 Intro + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem + Version 3
+ Introduction
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

Boost Filesystem Version 3

+ +

Version 3 is a major revision of the Boost Filesystem library. Important +changes include:

+ +
    +
  • A single class path handles all aspects of + internationalization, replacing the previous template and its path + and wpath instantiations. Character types char, + wchar_t, char16_t, and char32_t are + supported. This is a major simplification of the path abstraction, + particularly for functions that take path arguments.
  • +
  • New class path members include:
    + +
  • +
  • New or improved operations functions include:
      +
    • absolute(). This replaces the operations function + complete(), which is now deprecated. Semantics are now provided for a + Windows corner case where the base argument was not an absolute + path. Previously this resulted in an exception being thrown.
    • +
    • create_symlink() now supported on both POSIX and Windows.
    • +
    • read_symlink() function added. Supported on both POSIX and + Windows. Used to read the contents of a symlink itself.
    • +
    • resize_file() function added. Supported on both POSIX and + Windows. Used to shrink or grow a regular file.
    • +
    • unique_path() function added. Supported on both POSIX and + Windows. Used to generate a secure temporary pathname.
    • +
    +
  • +
  • Support for error reporting via error_code is now uniform + throughout the operations functions.
  • +
  • Documentation has been reworked, including re-writes of major portions.
  • +
  • A new Tutorial provides a hopefully much + gentler and more complete introduction for new users. Current users might want + to review the three sections related to class path.
  • +
+ +

Deprecated names and other features

+ +

See the Deprecated Features page for transition +aids that allow much existing code to compile without change using Version 3.

+ +

Breaking changes

+ +

To ease the transition, Versions 2 and 3 both used to be included in the next +several Boost releases. Version 2 was removed in Boost 1.50.0.

+

Class path

+
    +
  • Class template basic_path and its specializations are + replaced by a single class path. Thus any code, such as + overloaded functions, that depends on path and wpath + being two distinct types will fail to compile and must be restructured. + Restructuring may be as simple as removing one of the overloads, but also + might require more complex redesign.
  • +
  • Certain functions now return path objects rather than + string or wstring objects:
      +
    • root_name()
    • +
    • root_directory()
    • +
    • filename()
    • +
    • stem()
    • +
    • extension()
    • +
    +

    Not all uses will fail; if the function is being called in a context that + accepts a path, all is well. If the result is being used in a + context requiring a std::string or std::wstring, + then .string() or .wstring() respectively must be + appended to the function call.

  • +
  •  path::iterator::value_type and  + path::const_iterator::value_type is path rather than + basic_string.
  • +
+

Compiler support

+
    +
  • Compilers and standard libraries that do not fully support wide characters + and wide character strings (std::wstring) are no longer + supported.
  • +
  • Cygwin versions prior to 1.7 are no longer supported because they lack + wide string support. Cygwin now compiles only for the Windows API and path + syntax.
  • +
  • MinGW versions not supporting wide strings are no longer supported.
  • +
  • Microsoft VC++ 7.1 and earlier are no longer supported.
  • +
+ +
+

© Copyright Beman Dawes, 2009

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/v3_design.html b/3rdparty/boost_filesystem/doc/v3_design.html new file mode 100644 index 0000000..e54be27 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/v3_design.html @@ -0,0 +1,198 @@ + + + + + + + +Filesystem V3 Design + + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem Version 3
+ Design
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ + + + + + + + +
+ Contents
+ Introduction
+ Problem
+ Solution
+ Details
+ Other changes
+ Acknowledgements
+ +

Caution: This page documents thinking early in the V3 development +process, and is intended to serve historical purposes. It is not updated to +reflect the current state of the library.

+ +

Introduction

+ +

During the review of Boost.Filesystem.V2 (Internationalization), Peter Dimov +suggested that the basic_path class template was unwieldy, and that a single +path type that accommodated multiple character types and encodings would be more +flexible. Although I wasn't willing to stop development at that time to +explore how this idea might be implemented, or to break from the pattern for +Internationalization used the C++ standard library, I've often thought about +Peter's suggestion. With the advent of C++0x char16_t and char32_t +character +types, the basic_path class template approach becomes even more unwieldy, so it +is time to revisit the problem in light of Peter's suggestion.

+ +

Problem

+ +

With Filesystem.V2, a path argument to a user defined function that is to +accommodate multiple character types and encodings must be written as a +template. Do-the-right-thing overloads or template metaprogramming must be +employed to allow arguments to be written as string literals. Here's what it +looks like:

+ +
+
template<class Path>
+void foo( const Path & p );
+
inline void foo( const path & p )
+{
+  return foo<path>( p );
+}
+inline void foo( const wpath & p )
+{
+  return foo<wpath>( p );
+}
+
+

That's really ugly for such a simple need, and there would be a combinatorial +explosion if the function took multiple Path arguments and each could be either +narrow or wide. It gets even worse if the C++0x char16_t and +char32_t types are to be supported.

+ +

Solution

+ +

Overview:

+ +
    +
  • A single, non-template, class path.
  • +
  • Each member function is a template accommodating the various + applicable character types, including user-defined character types.
  • +
  • Hold the path internally in a string of the type used by the operating + system API; std::string for POSIX, std::wstring for Windows.
  • +
+ +

The signatures presented in Problem collapse to +simply:

+
+
void foo( const path & p );
+
+ +

That's a signification reduction in code complexity. Specification becomes +simpler, too. I believe it will be far easier to teach, and result in much more +flexible user code.

+ +

Other benefits:

+
    +
  • All the polymorphism still occurs at compile time.
  • +
  • Efficiency is increased, in that conversions of the encoding, if required, + only occur once at the time of creation, not each time the path is used.
  • +
  • The size of the implementation code drops approximately in half and + becomes much more readable.
  • +
+

Possible problems:

+
    +
  • The combination of member function templates and implicit constructors can + result in unclear error messages when the user makes simple commonplace coding + errors. This should be much less of a problem with C++ concepts, but in the + meantime work continues to restrict over aggressive templates via enable_if/disable_if.
  • +
+

Details

+ + + + + + + + + + + + + + + + + + + + +
+

Encoding Conversions

+

Host system

+

char string path arguments

+

wide string path arguments

Systems with char as the native API path character type (i.e. + POSIX-like systems)No conversion.Conversion occurs, performed by the current path locale's + codecvt facet.
Systems with wchar_t as the native API path character type + (i.e. Windows-like systems).Conversion occurs, performed by the current path locale's + codecvt facet.No conversion.
+ +

When a class path function argument type matches the operating system's +API argument type for paths, no conversion is performed rather than conversion +to a specified encoding such as one of the Unicode encodings. This avoids +unintended consequences, etc.

+ +

Other changes

+ +

Uniform hybrid error handling: The hybrid error handling idiom has +been consistently applied to all applicable functions.

+ +

Acknowledgements

+ +

Peter Dimov suggested the idea of a single path class that could cope with +multiple character types and encodings. Walter Landry contributed both the design +and implementation of the copy_any, +copy_directory, copy_symlink, and read_symlink functions.

+ +
+ +

© Copyright Beman Dawes, 2008

+

Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/doc/v4.html b/3rdparty/boost_filesystem/doc/v4.html new file mode 100644 index 0000000..41dfa83 --- /dev/null +++ b/3rdparty/boost_filesystem/doc/v4.html @@ -0,0 +1,69 @@ + + + + +Filesystem V4 + + + + + + + + + +
+ +boost.png (6897 bytes) + Filesystem + Version 4
+ + + + +
Home    + Tutorial    + Reference    + FAQ    + Releases    + Portability    + V4    + V3 Intro    + V3 Design    + Deprecated    + Bug Reports    +
+ +

Boost Filesystem Version 4

+ +

Version 4 is a significant revision of the Boost Filesystem library that makes its interface and +behavior closer to std::filesystem that was introduced in C++17 and updated in the later standards. +It removes the features that were deprecated in Version 3 and makes a number of breaking changes.

+ +

Users can select Boost.Filesystem v4 version by defining BOOST_FILESYSTEM_VERSION macro to 4 when compiling their code. There is no need to separately compile Boost.Filesystem for each library version — a single binary supports both v3 and v4. Users should avoid using both v3 and v4 in the same application as this can lead to subtle bugs.

+ +

Breaking changes

+ +
    +
  • path::filename no longer returns root name or root directory if the path contains no + other elements. For example, on Windows path("C:").filename() used to return "C:" and path("C:\").filename() used to return "\" and both will return an empty path now. This also affects path::stem and path::extension methods, as those are based on path::filename.
  • +
  • path::stem and path::extension no longer treat a filename that starts with a dot and has no other dots as an extension. Filenames starting with a dot are commonly treated as filenames with an empty extension. The leading dot is used to indicate a hidden file on most UNIX-like systems.
  • +
  • path::filename and path::iterator no longer return an implicit trailing dot (".") element if the path ends with a directory separator. Instead, an empty path is returned, similar to C++17 std::filesystem. This also affects other methods that are defined in terms of iterators or filename, such as path::stem, path::compare or lexicographical_compare. For example, path("a/b/") == path("a/b/.") no longer holds true.
  • +
  • path::lexically_normal no longer produces a trailing dot (".") element and omits a directory separator after a trailing dot-dot ("..") element in the normalized paths.
  • +
  • path appends consider root name and root directory of the appended path. If the appended path is absolute, or root name is present and differs from the source path, the resulting path is equivalent to the appended path. If root directory is present, the result is the root directory and relative path rebased on top of the root name of the source path. Otherwise, the behavior is similar to v3. This behavior is similar to C++17 std::filesystem.
  • +
  • path no longer supports construction, assignment or appending from containers of characters. Use string types or iterators as the source for these opereations instead.
  • +
  • path::remove_filename preserves the trailing directory separator, so that path::has_filename returns false after a successful call to path::remove_filename.
  • +
  • directory_entry constructors and modifiers that initialize or modify path of the directory entry automatically call directory_entry::refresh instead of clearing cached file statuses. This means that the file identified by the new path needs to be accessible in the filesystem at the point of the call.
  • +
  • directory_entry constructors and modifiers that accept file_status arguments to initialize cached file statuses are removed. The amount of cached data + is an implementation detail of directory_entry, and in the future it may not be limited to just file statuses. Users should rely on automatic refreshes of the cached data.
  • +
+ +
+

© Copyright Andrey Semashev, 2021-2023

+

Distributed under the Boost Software License, Version 1.0. See +www.boost.org/LICENSE_1_0.txt

+ + + + diff --git a/3rdparty/boost_filesystem/example/.gitignore b/3rdparty/boost_filesystem/example/.gitignore new file mode 100644 index 0000000..a72013a --- /dev/null +++ b/3rdparty/boost_filesystem/example/.gitignore @@ -0,0 +1,8 @@ +# Compiled source # +################### +tut1 +tut2 +tut3 +tut4 +tut5 +path_info diff --git a/3rdparty/boost_filesystem/example/Jamfile.v2 b/3rdparty/boost_filesystem/example/Jamfile.v2 new file mode 100644 index 0000000..f047cf3 --- /dev/null +++ b/3rdparty/boost_filesystem/example/Jamfile.v2 @@ -0,0 +1,36 @@ +# Boost Filesystem Library Example Jamfile + +# (C) Copyright Vladimir Prus 2003 + +# Distributed under the Boost Software License, Version 1.0. +# See www.boost.org/LICENSE_1_0.txt + +# Library home page: http://www.boost.org/libs/filesystem + +project + : requirements + /boost/filesystem//boost_filesystem + static + ; + +exe tut0 : tut0.cpp ; +exe tut1 : tut1.cpp ; +exe tut2 : tut2.cpp ; +exe tut3 : tut3.cpp : 11 ; +exe tut4 : tut4.cpp : 11 ; +exe tut5 : tut5.cpp ; +exe path_info : path_info.cpp : 11 ; +exe file_status : file_status.cpp ; +exe file_size : file_size.cpp ; +exe directory_symlink_parent_resolution : directory_symlink_parent_resolution.cpp ; +exe simple_ls : simple_ls.cpp ; + +install tut1-copy : tut1 : . ; +install tut2-copy : tut2 : . ; +install tut3-copy : tut3 : . ; +install tut4-copy : tut4 : . ; +install tut5-copy : tut5 : . ; +install path_info-copy : path_info : . ; + +alias tutorial : tut1-copy tut2-copy tut3-copy tut4-copy tut5-copy path_info-copy ; +explicit tut1-copy tut2-copy tut3-copy tut4-copy tut5-copy path_info-copy tutorial ; diff --git a/3rdparty/boost_filesystem/example/directory_symlink_parent_resolution.cpp b/3rdparty/boost_filesystem/example/directory_symlink_parent_resolution.cpp new file mode 100644 index 0000000..a15bbdb --- /dev/null +++ b/3rdparty/boost_filesystem/example/directory_symlink_parent_resolution.cpp @@ -0,0 +1,42 @@ +// directory_symlink_parent_resolution.cpp -------------------------------------------// + +// Copyright Beman Dawes 2015 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include +#include +#include + +using std::cout; +using std::endl; +using namespace boost::filesystem; + +int cpp_main(int argc, char* argv[]) +{ +#ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API" << endl; +#else + cout << "BOOST_POSIX_API" << endl; +#endif + + path test_dir(current_path() / "dspr_demo"); + + remove_all(test_dir); + create_directories(test_dir / "a/c/d"); + current_path(test_dir / "a"); + create_directory_symlink("c/d", "b"); + save_string_file("name.txt", "Windows"); + save_string_file("c/name.txt", "POSIX"); + current_path(test_dir); + std::string s; + load_string_file("a/b/../name.txt", s); + cout << s << endl; + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/error_demo.cpp b/3rdparty/boost_filesystem/example/error_demo.cpp new file mode 100644 index 0000000..b5db2c8 --- /dev/null +++ b/3rdparty/boost_filesystem/example/error_demo.cpp @@ -0,0 +1,200 @@ +// error_demo.cpp --------------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// +// // +// The purpose of this program is to demonstrate how error reporting works. // +// // +//--------------------------------------------------------------------------------------// + +#include +#include +#include + +using std::cout; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::system::error_code; +using boost::system::system_error; +namespace fs = boost::filesystem; + +namespace { +void report_system_error(const system_error& ex) +{ + cout << " threw system_error:\n" + << " ex.code().value() is " << ex.code().value() << '\n' + << " ex.code().category().name() is " << ex.code().category().name() << '\n' + << " ex.what() is " << ex.what() << '\n'; +} + +void report_filesystem_error(const system_error& ex) +{ + cout << " threw filesystem_error exception:\n" + << " ex.code().value() is " << ex.code().value() << '\n' + << " ex.code().category().name() is " << ex.code().category().name() << '\n' + << " ex.what() is " << ex.what() << '\n'; +} + +void report_status(fs::file_status s) +{ + cout << " file_status::type() is "; + switch (s.type()) + { + case fs::status_error: + cout << "status_error\n"; + break; + case fs::file_not_found: + cout << "file_not_found\n"; + break; + case fs::regular_file: + cout << "regular_file\n"; + break; + case fs::directory_file: + cout << "directory_file\n"; + break; + case fs::symlink_file: + cout << "symlink_file\n"; + break; + case fs::block_file: + cout << "block_file\n"; + break; + case fs::character_file: + cout << "character_file\n"; + break; + case fs::fifo_file: + cout << "fifo_file\n"; + break; + case fs::socket_file: + cout << "socket_file\n"; + break; + case fs::type_unknown: + cout << "type_unknown\n"; + break; + default: + cout << "not a valid enumeration constant\n"; + } +} + +void report_error_code(const error_code& ec) +{ + cout << " ec:\n" + << " value() is " << ec.value() << '\n' + << " category().name() is " << ec.category().name() << '\n' + << " message() is " << ec.message() << '\n'; +} + +bool threw_exception; + +} // namespace + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + cout << "Usage: error_demo path\n"; + return 1; + } + + error_code ec; + + //// construct path - no error_code + + //try { path p1(argv[1]); } + //catch (const system_error& ex) + //{ + // cout << "construct path without error_code"; + // report_system_error(ex); + //} + + //// construct path - with error_code + + path p(argv[1]); + + fs::file_status s; + bool b(false); + fs::directory_iterator di; + + // get status - no error_code + + cout << "\nstatus(\"" << p.string() << "\");\n"; + threw_exception = false; + + try + { + s = fs::status(p); + } + catch (const system_error& ex) + { + report_filesystem_error(ex); + threw_exception = true; + } + if (!threw_exception) + cout << " Did not throw exception\n"; + report_status(s); + + // get status - with error_code + + cout << "\nstatus(\"" << p.string() << "\", ec);\n"; + s = fs::status(p, ec); + report_status(s); + report_error_code(ec); + + // query existence - no error_code + + cout << "\nexists(\"" << p.string() << "\");\n"; + threw_exception = false; + + try + { + b = fs::exists(p); + } + catch (const system_error& ex) + { + report_filesystem_error(ex); + threw_exception = true; + } + if (!threw_exception) + { + cout << " Did not throw exception\n" + << " Returns: " << (b ? "true" : "false") << '\n'; + } + + // query existence - with error_code + + // directory_iterator - no error_code + + cout << "\ndirectory_iterator(\"" << p.string() << "\");\n"; + threw_exception = false; + + try + { + di = fs::directory_iterator(p); + } + catch (const system_error& ex) + { + report_filesystem_error(ex); + threw_exception = true; + } + if (!threw_exception) + { + cout << " Did not throw exception\n" + << (di == fs::directory_iterator() ? " Equal" : " Not equal") + << " to the end iterator\n"; + } + + // directory_iterator - with error_code + + cout << "\ndirectory_iterator(\"" << p.string() << "\", ec);\n"; + di = fs::directory_iterator(p, ec); + cout << (di == fs::directory_iterator() ? " Equal" : " Not equal") + << " to the end iterator\n"; + report_error_code(ec); + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/file_size.cpp b/3rdparty/boost_filesystem/example/file_size.cpp new file mode 100644 index 0000000..ed3957d --- /dev/null +++ b/3rdparty/boost_filesystem/example/file_size.cpp @@ -0,0 +1,44 @@ +// file_size program -------------------------------------------------------// + +// Copyright Beman Dawes, 2004 + +// Use, modification, and distribution is subject to 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) + +// See http://www.boost.org/libs/filesystem for documentation. + +#include +#include + +namespace fs = boost::filesystem; + +int main(int argc, char* argv[]) +{ + + if (argc != 2) + { + std::cout << "Usage: file_size path\n"; + return 1; + } + + std::cout << "sizeof(intmax_t) is " << sizeof(boost::intmax_t) << '\n'; + + fs::path p(argv[1]); + + if (!fs::exists(p)) + { + std::cout << "not found: " << argv[1] << std::endl; + return 1; + } + + if (!fs::is_regular(p)) + { + std::cout << "not a regular file: " << argv[1] << std::endl; + return 1; + } + + std::cout << "size of " << argv[1] << " is " << fs::file_size(p) + << std::endl; + return 0; +} diff --git a/3rdparty/boost_filesystem/example/file_status.cpp b/3rdparty/boost_filesystem/example/file_status.cpp new file mode 100644 index 0000000..7e2463f --- /dev/null +++ b/3rdparty/boost_filesystem/example/file_status.cpp @@ -0,0 +1,116 @@ +// status.cpp ------------------------------------------------------------------------// + +// Copyright Beman Dawes 2011 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include +#include +#include + +using std::cout; +using std::endl; +using namespace boost::filesystem; + +namespace { + +path p; + +void print_boost_macros() +{ + std::cout << "Boost " + << BOOST_VERSION / 100000 << '.' + << BOOST_VERSION / 100 % 1000 << '.' + << BOOST_VERSION % 100 << ", " +#ifndef _WIN64 + << BOOST_COMPILER << ", " +#else + << BOOST_COMPILER << " with _WIN64 defined, " +#endif + << BOOST_STDLIB << ", " + << BOOST_PLATFORM + << std::endl; +} + +const char* file_type_tab[] = { "status_error", "file_not_found", "regular_file", "directory_file", + "symlink_file", "block_file", "character_file", "fifo_file", "socket_file", + "type_unknown" }; + +const char* file_type_c_str(enum file_type t) +{ + return file_type_tab[t]; +} + +void show_status(file_status s, boost::system::error_code ec) +{ + boost::system::error_condition econd; + + if (ec) + { + econd = ec.default_error_condition(); + cout << "sets ec to indicate an error:\n" + << " ec.value() is " << ec.value() << '\n' + << " ec.message() is \"" << ec.message() << "\"\n" + << " ec.default_error_condition().value() is " << econd.value() << '\n' + << " ec.default_error_condition().message() is \"" << econd.message() << "\"\n"; + } + else + cout << "clears ec.\n"; + + cout << "s.type() is " << s.type() + << ", which is defined as \"" << file_type_c_str(s.type()) << "\"\n"; + + cout << "exists(s) is " << (exists(s) ? "true" : "false") << "\n"; + cout << "status_known(s) is " << (status_known(s) ? "true" : "false") << "\n"; + cout << "is_regular_file(s) is " << (is_regular_file(s) ? "true" : "false") << "\n"; + cout << "is_directory(s) is " << (is_directory(s) ? "true" : "false") << "\n"; + cout << "is_other(s) is " << (is_other(s) ? "true" : "false") << "\n"; + cout << "is_symlink(s) is " << (is_symlink(s) ? "true" : "false") << "\n"; +} + +void try_exists() +{ + cout << "\nexists(" << p << ") "; + try + { + bool result = exists(p); + cout << "is " << (result ? "true" : "false") << "\n"; + } + catch (const filesystem_error& ex) + { + cout << "throws a filesystem_error exception: " << ex.what() << "\n"; + } +} + +} // namespace + +int cpp_main(int argc, char* argv[]) +{ + print_boost_macros(); + + if (argc < 2) + { + std::cout << "Usage: file_status \n"; + p = argv[0]; + } + else + p = argv[1]; + + boost::system::error_code ec; + file_status s = status(p, ec); + cout << "\nfile_status s = status(" << p << ", ec) "; + show_status(s, ec); + + s = symlink_status(p, ec); + cout << "\nfile_status s = symlink_status(" << p << ", ec) "; + show_status(s, ec); + + try_exists(); + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/mbcopy.cpp b/3rdparty/boost_filesystem/example/mbcopy.cpp new file mode 100644 index 0000000..75355f1 --- /dev/null +++ b/3rdparty/boost_filesystem/example/mbcopy.cpp @@ -0,0 +1,100 @@ +// Boost.Filesystem mbcopy.cpp ---------------------------------------------// + +// Copyright Beman Dawes 2005 + +// Use, modification, and distribution is subject to 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) + +// Copy the files in a directory, using mbpath to represent the new file names +// See http://../doc/path.htm#mbpath for more information + +// See deprecated_test for tests of deprecated features +#define BOOST_FILESYSTEM_NO_DEPRECATED + +#include +#ifdef BOOST_FILESYSTEM_NARROW_ONLY +#error This compiler or standard library does not support wide-character strings or paths +#endif + +#include "mbpath.hpp" +#include +#include +#include +#include "../src/utf8_codecvt_facet.hpp" + +namespace fs = boost::filesystem; + +namespace { + +// we can't use boost::filesystem::copy_file() because the argument types +// differ, so provide a not-very-smart replacement. +void copy_file(const fs::wpath& from, const user::mbpath& to) +{ + fs::ifstream from_file(from, std::ios_base::in | std::ios_base::binary); + if (!from_file) + { + std::cout << "input open failed\n"; + return; + } + + fs::ofstream to_file(to, std::ios_base::out | std::ios_base::binary); + if (!to_file) + { + std::cout << "output open failed\n"; + return; + } + + char c; + while (from_file.get(c)) + { + to_file.put(c); + if (to_file.fail()) + { + std::cout << "write error\n"; + return; + } + } + + if (!from_file.eof()) + { + std::cout << "read error\n"; + } +} + +} // namespace + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + std::cout << "Copy files in the current directory to a target directory\n" + << "Usage: mbcopy \n"; + return 1; + } + + // For encoding, use Boost UTF-8 codecvt + std::locale global_loc = std::locale(); + std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet); + user::mbpath_traits::imbue(loc); + + std::string target_string(argv[1]); + user::mbpath target_dir(user::mbpath_traits::to_internal(target_string)); + + if (!fs::is_directory(target_dir)) + { + std::cout << "Error: " << argv[1] << " is not a directory\n"; + return 1; + } + + for (fs::wdirectory_iterator it(L"."); + it != fs::wdirectory_iterator(); ++it) + { + if (fs::is_regular_file(it->status())) + { + copy_file(*it, target_dir / it->path().filename()); + } + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/mbpath.cpp b/3rdparty/boost_filesystem/example/mbpath.cpp new file mode 100644 index 0000000..662ce20 --- /dev/null +++ b/3rdparty/boost_filesystem/example/mbpath.cpp @@ -0,0 +1,78 @@ +// Boost.Filesystem mbpath.cpp ---------------------------------------------// + +// (c) Copyright Beman Dawes 2005 + +// Use, modification, and distribution is subject to 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) + +// See Boost.Filesystem home page at http://www.boost.org/libs/filesystem + +#include +#ifdef BOOST_FILESYSTEM_NARROW_ONLY +#error This compiler or standard library does not support wide-character strings or paths +#endif + +#include "mbpath.hpp" +#include +#include + +namespace fs = boost::filesystem; + +namespace { + +// ISO C calls this "the locale-specific native environment": +std::locale loc(""); + +const std::codecvt< wchar_t, char, std::mbstate_t >* + cvt(&std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc)); + +} // namespace + +namespace user { + +mbpath_traits::external_string_type +mbpath_traits::to_external(const mbpath& ph, const internal_string_type& src) +{ + std::size_t work_size(cvt->max_length() * (src.size() + 1)); + boost::scoped_array< char > work(new char[work_size]); + std::mbstate_t state; + const internal_string_type::value_type* from_next; + external_string_type::value_type* to_next; + if (cvt->out( + state, src.c_str(), src.c_str() + src.size(), from_next, work.get(), + work.get() + work_size, to_next) != std::codecvt_base::ok) + boost::throw_exception< fs::basic_filesystem_error< mbpath > >( + fs::basic_filesystem_error< mbpath >( + "user::mbpath::to_external conversion error", + ph, boost::system::error_code(EINVAL, boost::system::errno_ecat))); + *to_next = '\0'; + return external_string_type(work.get()); +} + +mbpath_traits::internal_string_type +mbpath_traits::to_internal(const external_string_type& src) +{ + std::size_t work_size(src.size() + 1); + boost::scoped_array< wchar_t > work(new wchar_t[work_size]); + std::mbstate_t state; + const external_string_type::value_type* from_next; + internal_string_type::value_type* to_next; + if (cvt->in( + state, src.c_str(), src.c_str() + src.size(), from_next, work.get(), + work.get() + work_size, to_next) != std::codecvt_base::ok) + boost::throw_exception< fs::basic_filesystem_error< mbpath > >( + fs::basic_filesystem_error< mbpath >( + "user::mbpath::to_internal conversion error", + boost::system::error_code(EINVAL, boost::system::errno_ecat))); + *to_next = L'\0'; + return internal_string_type(work.get()); +} + +void mbpath_traits::imbue(const std::locale& new_loc) +{ + loc = new_loc; + cvt = &std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc); +} + +} // namespace user diff --git a/3rdparty/boost_filesystem/example/mbpath.hpp b/3rdparty/boost_filesystem/example/mbpath.hpp new file mode 100644 index 0000000..2a79c4f --- /dev/null +++ b/3rdparty/boost_filesystem/example/mbpath.hpp @@ -0,0 +1,47 @@ +// Boost.Filesystem mbpath.hpp ---------------------------------------------// + +// Copyright Beman Dawes 2005 + +// Use, modification, and distribution is subject to 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) + +// Encodes wide character paths as MBCS +// See http://../doc/path.htm#mbpath for more information + +#include +#include // for std::mbstate_t +#include +#include + +namespace user { + +struct mbpath_traits; + +typedef boost::filesystem::basic_path< std::wstring, mbpath_traits > mbpath; + +struct mbpath_traits +{ + typedef std::wstring internal_string_type; + typedef std::string external_string_type; + + static external_string_type to_external(const mbpath& ph, const internal_string_type& src); + + static internal_string_type to_internal(const external_string_type& src); + + static void imbue(const std::locale& loc); +}; + +} // namespace user + +namespace boost { +namespace filesystem { + +template<> +struct is_basic_path< user::mbpath > +{ + static const bool value = true; +}; + +} // namespace filesystem +} // namespace boost diff --git a/3rdparty/boost_filesystem/example/path_info.cpp b/3rdparty/boost_filesystem/example/path_info.cpp new file mode 100644 index 0000000..0f2ed67 --- /dev/null +++ b/3rdparty/boost_filesystem/example/path_info.cpp @@ -0,0 +1,86 @@ +// path_info.cpp ---------------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include + +using namespace std; +using namespace boost::filesystem; + +const char* say_what(bool b) +{ + return b ? "true" : "false"; +} + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + cout << "Usage: path_info path-element [path-element...]\n" + "Composes a path via operator/= from one or more path-element arguments\n" + "Example: path_info foo/bar baz\n" +#ifdef BOOST_POSIX_API + " would report info about the composed path foo/bar/baz\n"; +#else // BOOST_WINDOWS_API + " would report info about the composed path foo/bar\\baz\n"; +#endif + return 1; + } + + path p; + for (; argc > 1; --argc, ++argv) + p /= argv[1]; // compose path p from the command line arguments + + cout << "\ncomposed path:\n"; + cout << " operator<<()---------: " << p << "\n"; + cout << " make_preferred()-----: " << p.make_preferred() << "\n"; + + cout << "\nelements:\n"; + for (auto element : p) + cout << " " << element << '\n'; + + cout << "\nobservers, native format:" << endl; +#ifdef BOOST_POSIX_API + cout << " native()-------------: " << p.native() << endl; + cout << " c_str()--------------: " << p.c_str() << endl; +#else // BOOST_WINDOWS_API + wcout << L" native()-------------: " << p.native() << endl; + wcout << L" c_str()--------------: " << p.c_str() << endl; +#endif + cout << " string()-------------: " << p.string() << endl; + wcout << L" wstring()------------: " << p.wstring() << endl; + + cout << "\nobservers, generic format:\n"; + cout << " generic_string()-----: " << p.generic_string() << endl; + wcout << L" generic_wstring()----: " << p.generic_wstring() << endl; + + cout << "\ndecomposition:\n"; + cout << " root_name()----------: " << p.root_name() << '\n'; + cout << " root_directory()-----: " << p.root_directory() << '\n'; + cout << " root_path()----------: " << p.root_path() << '\n'; + cout << " relative_path()------: " << p.relative_path() << '\n'; + cout << " parent_path()--------: " << p.parent_path() << '\n'; + cout << " filename()-----------: " << p.filename() << '\n'; + cout << " stem()---------------: " << p.stem() << '\n'; + cout << " extension()----------: " << p.extension() << '\n'; + + cout << "\nquery:\n"; + cout << " empty()--------------: " << say_what(p.empty()) << '\n'; + cout << " is_absolute()--------: " << say_what(p.is_absolute()) << '\n'; + cout << " has_root_name()------: " << say_what(p.has_root_name()) << '\n'; + cout << " has_root_directory()-: " << say_what(p.has_root_directory()) << '\n'; + cout << " has_root_path()------: " << say_what(p.has_root_path()) << '\n'; + cout << " has_relative_path()--: " << say_what(p.has_relative_path()) << '\n'; + cout << " has_parent_path()----: " << say_what(p.has_parent_path()) << '\n'; + cout << " has_filename()-------: " << say_what(p.has_filename()) << '\n'; + cout << " has_stem()-----------: " << say_what(p.has_stem()) << '\n'; + cout << " has_extension()------: " << say_what(p.has_extension()) << '\n'; + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/simple_ls.cpp b/3rdparty/boost_filesystem/example/simple_ls.cpp new file mode 100644 index 0000000..8f6d7ea --- /dev/null +++ b/3rdparty/boost_filesystem/example/simple_ls.cpp @@ -0,0 +1,90 @@ +// simple_ls program -------------------------------------------------------// + +// Copyright Jeff Garland and Beman Dawes, 2002 + +// Use, modification, and distribution is subject to 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) + +// See http://www.boost.org/libs/filesystem for documentation. + +// As an example program, we don't want to use any deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include +#include +#include +#include + +namespace fs = boost::filesystem; + +int main(int argc, char* argv[]) +{ + fs::path p(fs::current_path()); + + if (argc > 1) + p = fs::system_complete(argv[1]); + else + std::cout << "\nusage: simple_ls [path]" << std::endl; + + unsigned long file_count = 0; + unsigned long dir_count = 0; + unsigned long other_count = 0; + unsigned long err_count = 0; + + if (!fs::exists(p)) + { + std::cout << "\nNot found: " << p << std::endl; + return 1; + } + + if (fs::is_directory(p)) + { + std::cout << "\nIn directory: " << p << "\n\n"; + fs::directory_iterator end_iter; + for (fs::directory_iterator dir_itr(p); + dir_itr != end_iter; + ++dir_itr) + { + try + { + if (fs::is_directory(dir_itr->status())) + { + ++dir_count; + std::cout << dir_itr->path().filename() << " [directory]\n"; + } + else if (fs::is_regular_file(dir_itr->status())) + { + ++file_count; + std::cout << dir_itr->path().filename() << "\n"; + } + else + { + ++other_count; + std::cout << dir_itr->path().filename() << " [other]\n"; + } + } + catch (const std::exception& ex) + { + ++err_count; + std::cout << dir_itr->path().filename() << " " << ex.what() << std::endl; + } + } + std::cout << "\n" + << file_count << " files\n" + << dir_count << " directories\n" + << other_count << " others\n" + << err_count << " errors\n"; + } + else // must be a file + { + std::cout << "\nFound: " << p << "\n"; + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/stems.cpp b/3rdparty/boost_filesystem/example/stems.cpp new file mode 100644 index 0000000..63f3ffc --- /dev/null +++ b/3rdparty/boost_filesystem/example/stems.cpp @@ -0,0 +1,31 @@ +// filesystem example stems.cpp ------------------------------------------------------// + +// Copyright Beman Dawes 2011 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cout << "Usage: stems \n"; + return 1; + } + + boost::filesystem::path p(argv[1]), name(p.filename()); + + for (;;) + { + std::cout << "filename " << name << " has stem " << name.stem() + << " and extension " << name.extension() << "\n"; + if (name.stem().empty() || name.extension().empty()) + return 0; + name = name.stem(); + } +} diff --git a/3rdparty/boost_filesystem/example/tchar.cpp b/3rdparty/boost_filesystem/example/tchar.cpp new file mode 100644 index 0000000..59e1209 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tchar.cpp @@ -0,0 +1,39 @@ +// Example use of Microsoft TCHAR ----------------------------------------------------// + +// Copyright Beman Dawes 2008 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; + +typedef std::basic_string< TCHAR > tstring; + +void func(fs::path const& p) +{ + assert(fs::exists(p)); +} + +int main() +{ + // get a path that is known to exist + fs::path cp = fs::current_path(); + + // demo: get tstring from the path + tstring cp_as_tstring = cp.string< tstring >(); + + // demo: pass tstring to filesystem function taking path + assert(fs::exists(cp_as_tstring)); + + // demo: pass tstring to user function taking path + func(cp_as_tstring); + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut0.cpp b/3rdparty/boost_filesystem/example/tut0.cpp new file mode 100644 index 0000000..4caa7c1 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut0.cpp @@ -0,0 +1,24 @@ +// filesystem tut0.cpp ---------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include + +namespace fs = boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cout << "Usage: tut0 path\n"; + return 1; + } + std::cout << argv[1] << '\n'; + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut1.cpp b/3rdparty/boost_filesystem/example/tut1.cpp new file mode 100644 index 0000000..d04c4a3 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut1.cpp @@ -0,0 +1,24 @@ +// filesystem tut1.cpp ---------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include + +using namespace boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cout << "Usage: tut1 path\n"; + return 1; + } + std::cout << argv[1] << " " << file_size(argv[1]) << '\n'; + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut2.cpp b/3rdparty/boost_filesystem/example/tut2.cpp new file mode 100644 index 0000000..68b4a03 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut2.cpp @@ -0,0 +1,39 @@ +// filesystem tut2.cpp ---------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include + +using namespace std; +using namespace boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + cout << "Usage: tut2 path\n"; + return 1; + } + + path p(argv[1]); // avoid repeated path construction below + + if (exists(p)) // does path p actually exist? + { + if (is_regular_file(p)) // is path p a regular file? + cout << p << " size is " << file_size(p) << '\n'; + else if (is_directory(p)) // is path p a directory? + cout << p << " is a directory\n"; + else + cout << p << " exists, but is not a regular file or directory\n"; + } + else + cout << p << " does not exist\n"; + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut3.cpp b/3rdparty/boost_filesystem/example/tut3.cpp new file mode 100644 index 0000000..c8a667d --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut3.cpp @@ -0,0 +1,53 @@ +// filesystem tut3.cpp ---------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include + +using std::cout; +using namespace boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + cout << "Usage: tut3 path\n"; + return 1; + } + + path p(argv[1]); + + try + { + if (exists(p)) + { + if (is_regular_file(p)) + { + cout << p << " size is " << file_size(p) << '\n'; + } + else if (is_directory(p)) + { + cout << p << " is a directory containing:\n"; + + for (directory_entry const& x : directory_iterator(p)) + cout << " " << x.path() << '\n'; + } + else + cout << p << " exists, but is not a regular file or directory\n"; + } + else + cout << p << " does not exist\n"; + } + catch (filesystem_error& ex) + { + cout << ex.what() << '\n'; + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut4.cpp b/3rdparty/boost_filesystem/example/tut4.cpp new file mode 100644 index 0000000..3909c62 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut4.cpp @@ -0,0 +1,62 @@ +// filesystem tut4.cpp ---------------------------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include +#include + +using std::cout; +using namespace boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + cout << "Usage: tut4 path\n"; + return 1; + } + + path p(argv[1]); + + try + { + if (exists(p)) + { + if (is_regular_file(p)) + { + cout << p << " size is " << file_size(p) << '\n'; + } + else if (is_directory(p)) + { + cout << p << " is a directory containing:\n"; + + std::vector< path > v; + + for (auto&& x : directory_iterator(p)) + v.push_back(x.path()); + + std::sort(v.begin(), v.end()); + + for (auto&& x : v) + cout << " " << x.filename() << '\n'; + } + else + cout << p << " exists, but is not a regular file or directory\n"; + } + else + cout << p << " does not exist\n"; + } + catch (filesystem_error& ex) + { + cout << ex.what() << '\n'; + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut5.cpp b/3rdparty/boost_filesystem/example/tut5.cpp new file mode 100644 index 0000000..dbef00d --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut5.cpp @@ -0,0 +1,69 @@ +// filesystem tut5.cpp ---------------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include + +namespace fs = boost::filesystem; + +int main() +{ + // \u263A is "Unicode WHITE SMILING FACE = have a nice day!" + std::string narrow_string("smile2"); + std::wstring wide_string(L"smile2\u263A"); + std::list< char > narrow_list; + narrow_list.push_back('s'); + narrow_list.push_back('m'); + narrow_list.push_back('i'); + narrow_list.push_back('l'); + narrow_list.push_back('e'); + narrow_list.push_back('3'); + std::list< wchar_t > wide_list; + wide_list.push_back(L's'); + wide_list.push_back(L'm'); + wide_list.push_back(L'i'); + wide_list.push_back(L'l'); + wide_list.push_back(L'e'); + wide_list.push_back(L'3'); + wide_list.push_back(L'\u263A'); + + { + fs::ofstream f("smile"); + } + { + fs::ofstream f(L"smile\u263A"); + } + { + fs::ofstream f(narrow_string); + } + { + fs::ofstream f(wide_string); + } + { + fs::ofstream f(narrow_list); + } + { + fs::ofstream f(wide_list); + } + narrow_list.pop_back(); + narrow_list.push_back('4'); + wide_list.pop_back(); + wide_list.pop_back(); + wide_list.push_back(L'4'); + wide_list.push_back(L'\u263A'); + { + fs::ofstream f(fs::path(narrow_list.begin(), narrow_list.end())); + } + { + fs::ofstream f(fs::path(wide_list.begin(), wide_list.end())); + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut6a.cpp b/3rdparty/boost_filesystem/example/tut6a.cpp new file mode 100644 index 0000000..4ea05b2 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut6a.cpp @@ -0,0 +1,48 @@ +// filesystem tut6a.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include + +using namespace boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cout << "Usage: tut6a path\n"; + return 1; + } + + try + { + for (recursive_directory_iterator it(argv[1]); + it != recursive_directory_iterator(); + ++it) + { + if (it.level() > 1) + it.pop(); + else + { + for (int i = 0; i <= it.level(); ++i) + std::cout << " "; + + std::cout << it->path() << '\n'; + } + } + } + catch (std::exception& ex) + { + std::cout << "************* exception *****************\n"; + std::cout << ex.what() << '\n'; + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut6b.cpp b/3rdparty/boost_filesystem/example/tut6b.cpp new file mode 100644 index 0000000..88ad320 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut6b.cpp @@ -0,0 +1,52 @@ +// filesystem tut6b.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include + +using namespace boost::filesystem; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cout << "Usage: tut6b path\n"; + return 1; + } + + try + { + for (recursive_directory_iterator it(argv[1]); + it != recursive_directory_iterator();) + { + for (int i = 0; i <= it.level(); ++i) + std::cout << " "; + + std::cout << it->path() << '\n'; + + try + { + ++it; + } + catch (filesystem_error& ex) + { + std::cout << "************* filesystem_error *****************\n"; + std::cout << ex.what() << '\n'; + } + } + } + catch (std::exception& ex) + { + std::cout << "************* exception *****************\n"; + std::cout << ex.what() << '\n'; + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/example/tut6c.cpp b/3rdparty/boost_filesystem/example/tut6c.cpp new file mode 100644 index 0000000..aba6143 --- /dev/null +++ b/3rdparty/boost_filesystem/example/tut6c.cpp @@ -0,0 +1,39 @@ +// filesystem tut6c.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include +#include + +using namespace boost::filesystem; +using namespace boost::system; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cout << "Usage: tut6c path\n"; + return 1; + } + + error_code ec; + for (recursive_directory_iterator it(argv[1], ec); + it != recursive_directory_iterator();) + { + for (int i = 0; i <= it.level(); ++i) + std::cout << " "; + + std::cout << it->path() << '\n'; + + it.increment(ec); + } + + return 0; +} diff --git a/3rdparty/boost_filesystem/include/boost/filesystem.hpp b/3rdparty/boost_filesystem/include/boost/filesystem.hpp new file mode 100644 index 0000000..36bf907 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem.hpp @@ -0,0 +1,26 @@ +// boost/filesystem.hpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_FILESYSTEM_HPP +#define BOOST_FILESYSTEM_FILESYSTEM_HPP + +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_FILESYSTEM_DEPRECATED) +#include +#endif + +#endif // BOOST_FILESYSTEM_FILESYSTEM_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/config.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/config.hpp new file mode 100644 index 0000000..cf7584a --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/config.hpp @@ -0,0 +1,152 @@ +// boost/filesystem/v3/config.hpp ----------------------------------------------------// + +// Copyright Beman Dawes 2003 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_CONFIG_HPP +#define BOOST_FILESYSTEM_CONFIG_HPP + +// This header implements separate compilation features as described in +// http://www.boost.org/more/separate_compilation.html + +#include +#include // for BOOST_POSIX_API or BOOST_WINDOWS_API +#include + +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION != 3 && BOOST_FILESYSTEM_VERSION != 4 +#error Compiling Boost.Filesystem file with BOOST_FILESYSTEM_VERSION defined != 3 or 4 +#endif + +#if defined(BOOST_FILESYSTEM_SOURCE) +#undef BOOST_FILESYSTEM_VERSION +#define BOOST_FILESYSTEM_VERSION 4 +#elif !defined(BOOST_FILESYSTEM_VERSION) +#define BOOST_FILESYSTEM_VERSION 3 +#endif + +#define BOOST_FILESYSTEM_VERSIONED_SYM(sym) BOOST_JOIN(sym, BOOST_JOIN(_v, BOOST_FILESYSTEM_VERSION)) + +#if BOOST_FILESYSTEM_VERSION == 4 +#undef BOOST_FILESYSTEM_DEPRECATED +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#endif + +#define BOOST_FILESYSTEM_I18N // aid users wishing to compile several versions + +// BOOST_FILESYSTEM_DEPRECATED needed for source compiles -----------------------------// + +#ifdef BOOST_FILESYSTEM_SOURCE +#define BOOST_FILESYSTEM_DEPRECATED +#undef BOOST_FILESYSTEM_NO_DEPRECATED // fixes #9454, src bld fails if NO_DEP defined +#endif + +#if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED) +#error Both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined +#endif + +// throw an exception ----------------------------------------------------------------// +// +// Exceptions were originally thrown via boost::throw_exception(). +// As throw_exception() became more complex, it caused user error reporting +// to be harder to interpret, since the exception reported became much more complex. +// The immediate fix was to throw directly, wrapped in a macro to make any later change +// easier. + +#define BOOST_FILESYSTEM_THROW(EX) throw EX + +#if defined(BOOST_NO_STD_WSTRING) +#error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support +#endif + +// Deprecated symbols markup -----------------------------------------------------------// + +#if !defined(BOOST_FILESYSTEM_ALLOW_DEPRECATED) +#define BOOST_FILESYSTEM_DETAIL_DEPRECATED(msg) BOOST_DEPRECATED(msg) +#else +#define BOOST_FILESYSTEM_DETAIL_DEPRECATED(msg) +#endif + + +// This header implements separate compilation features as described in +// http://www.boost.org/more/separate_compilation.html + +// normalize macros ------------------------------------------------------------------// + +#if !defined(BOOST_FILESYSTEM_DYN_LINK) && !defined(BOOST_FILESYSTEM_STATIC_LINK) && !defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_ALL_STATIC_LINK) +#define BOOST_FILESYSTEM_STATIC_LINK +#endif + +#if defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_FILESYSTEM_DYN_LINK) +#define BOOST_FILESYSTEM_DYN_LINK +#elif defined(BOOST_ALL_STATIC_LINK) && !defined(BOOST_FILESYSTEM_STATIC_LINK) +#define BOOST_FILESYSTEM_STATIC_LINK +#endif + +#if defined(BOOST_FILESYSTEM_DYN_LINK) && defined(BOOST_FILESYSTEM_STATIC_LINK) +#error Must not define both BOOST_FILESYSTEM_DYN_LINK and BOOST_FILESYSTEM_STATIC_LINK +#endif + +#if defined(BOOST_ALL_NO_LIB) && !defined(BOOST_FILESYSTEM_NO_LIB) +#define BOOST_FILESYSTEM_NO_LIB +#endif + +// enable dynamic linking ------------------------------------------------------------// + +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_FILESYSTEM_DYN_LINK) +#if defined(BOOST_FILESYSTEM_SOURCE) +#define BOOST_FILESYSTEM_DECL BOOST_SYMBOL_EXPORT +#else +#define BOOST_FILESYSTEM_DECL BOOST_SYMBOL_IMPORT +#endif +#else +#define BOOST_FILESYSTEM_DECL +#endif + +// enable automatic library variant selection ----------------------------------------// + +#if !defined(BOOST_FILESYSTEM_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_FILESYSTEM_NO_LIB) +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_filesystem +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_FILESYSTEM_DYN_LINK) +#define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) ||\ + (defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 50000)) ||\ + (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION < 100)) +// Indicates that the standard library fstream types do not support move constructor/assignment. +#define BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS +#endif + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) && \ + (\ + (defined(BOOST_DINKUMWARE_STDLIB) && defined(_HAS_CXX23) && (_HAS_CXX23 != 0) && defined(_MSVC_STL_UPDATE) && (_MSVC_STL_UPDATE < 202208L)) || \ + (defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 110400 || (BOOST_LIBSTDCXX_VERSION >= 120000 && BOOST_LIBSTDCXX_VERSION < 120200)) && (BOOST_CXX_VERSION > 202002L))\ + ) +// Indicates that std::string_view has implicit constructor from ranges that was present in an early C++23 draft (N4892). +// This was later rectified by marking the constructor explicit (https://wg21.link/p2499). Unfortunately, some compilers +// were released with the constructor being implicit. +#define BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR +#endif + +#endif // BOOST_FILESYSTEM_CONFIG_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/convenience.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/convenience.hpp new file mode 100644 index 0000000..d66add2 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/convenience.hpp @@ -0,0 +1,55 @@ +// boost/filesystem/convenience.hpp ----------------------------------------// + +// Copyright Beman Dawes, 2002-2005 +// Copyright Vladimir Prus, 2002 + +// Use, modification, and distribution is subject to 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) + +// See library home page at http://www.boost.org/libs/filesystem + +//----------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_CONVENIENCE_HPP +#define BOOST_FILESYSTEM_CONVENIENCE_HPP + +#include +#include +#include + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::extension() instead") +inline std::string extension(const path& p) +{ + return p.extension().string(); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::stem() instead") +inline std::string basename(const path& p) +{ + return p.stem().string(); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::replace_extension() instead") +inline path change_extension(const path& p, const path& new_extension) +{ + path new_p(p); + new_p.replace_extension(new_extension); + return new_p; +} + +#endif + +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_CONVENIENCE_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/cstdio.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/cstdio.hpp new file mode 100644 index 0000000..2da3456 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/cstdio.hpp @@ -0,0 +1,87 @@ +// boost/filesystem/cstdio.hpp ------------------------------------------------------// + +// Copyright Andrey Semashev 2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_CSTDIO_HPP +#define BOOST_FILESYSTEM_CSTDIO_HPP + +#include +#include +#include +#if defined(BOOST_WINDOWS_API) +#include +#include +#include +#include +#endif + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +#if defined(BOOST_WINDOWS_API) + +inline std::FILE* fopen(filesystem::path const& p, const char* mode) +{ +#if defined(__CYGWIN__) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__STRICT_ANSI__)) + // Cygwin and MinGW32 in strict ANSI mode do not declare _wfopen + return std::fopen(p.string().c_str(), mode); +#else + // mode should only contain ASCII characters and is likely short + struct small_array + { + wchar_t buf[128u]; + wchar_t* p; + + small_array() BOOST_NOEXCEPT : p(buf) {} + ~small_array() BOOST_NOEXCEPT + { + if (BOOST_UNLIKELY(p != buf)) + std::free(p); + } + } + wmode; + std::size_t wmode_len = std::mbstowcs(wmode.p, mode, sizeof(wmode.buf) / sizeof(wchar_t)); + if (BOOST_UNLIKELY(wmode_len >= (sizeof(wmode.buf) / sizeof(wchar_t)))) + { + wmode_len = std::mbstowcs(NULL, mode, 0u); + // Check for size overflow, including (size_t)-1, which indicates mbstowcs error + if (BOOST_UNLIKELY(wmode_len >= (static_cast< std::size_t >(-1) / sizeof(wchar_t)))) + return NULL; + + wmode.p = static_cast< wchar_t* >(std::malloc((wmode_len + 1u) * sizeof(wchar_t))); + if (BOOST_UNLIKELY(!wmode.p)) + return NULL; + + std::size_t wmode_len2 = std::mbstowcs(wmode.p, mode, wmode_len + 1u); + if (BOOST_UNLIKELY(wmode_len2 > wmode_len)) + return NULL; + } + + return ::_wfopen(p.c_str(), wmode.p); +#endif +} + +#else // defined(BOOST_WINDOWS_API) + +inline std::FILE* fopen(filesystem::path const& p, const char* mode) +{ + return std::fopen(p.c_str(), mode); +} + +#endif // defined(BOOST_WINDOWS_API) + +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_CSTDIO_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/detail/footer.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/detail/footer.hpp new file mode 100644 index 0000000..ce4bc1f --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/detail/footer.hpp @@ -0,0 +1,23 @@ +/* + * Copyright Andrey Semashev 2021. + * 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) + */ + +#if !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS) + +#if defined(_MSC_VER) && !defined(__clang__) + +#pragma warning(pop) + +#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ + && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) + +#pragma GCC diagnostic pop + +#endif + +#endif // !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS) + +#include diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/detail/header.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/detail/header.hpp new file mode 100644 index 0000000..f98b0ab --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/detail/header.hpp @@ -0,0 +1,54 @@ +/* + * Copyright Andrey Semashev 2021. + * 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 !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS) + +#if defined(_MSC_VER) && !defined(__clang__) + +#pragma warning(push, 3) +// 'm_A' : class 'A' needs to have dll-interface to be used by clients of class 'B' +#pragma warning(disable: 4251) +// non dll-interface class 'A' used as base for dll-interface class 'B' +#pragma warning(disable: 4275) +// 'int' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning(disable: 4800) +// unreferenced formal parameter +#pragma warning(disable: 4100) +// conditional expression is constant +#pragma warning(disable: 4127) +// function marked as __forceinline not inlined +#pragma warning(disable: 4714) +// decorated name length exceeded, name was truncated +#pragma warning(disable: 4503) +// 'X': This function or variable may be unsafe. Consider using Y instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. +#pragma warning(disable: 4996) +// qualifier applied to function type has no meaning; ignored +#pragma warning(disable: 4180) +// qualifier applied to reference type; ignored +#pragma warning(disable: 4181) + +#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ + && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) + +// Note: clang-cl goes here as well, as it seems to support gcc-style warning control pragmas. + +#pragma GCC diagnostic push +// unused parameter 'arg' +#pragma GCC diagnostic ignored "-Wunused-parameter" +// unused function 'foo' +#pragma GCC diagnostic ignored "-Wunused-function" + +#if defined(__clang__) +// template argument uses unnamed type +#pragma clang diagnostic ignored "-Wunnamed-type-template-args" +#endif // defined(__clang__) + +#endif + +#endif // !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS) diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/detail/path_traits.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/detail/path_traits.hpp new file mode 100644 index 0000000..562b967 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/detail/path_traits.hpp @@ -0,0 +1,737 @@ +// filesystem path_traits.hpp --------------------------------------------------------// + +// Copyright Beman Dawes 2009 +// Copyright Andrey Semashev 2022 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP +#define BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP + +#include +#include +#include // for strlen +#include // for mbstate_t, wcslen +#include +#include +#include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) +#include +#include +#endif +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 +#include +#include +#endif + +#include // must be the last #include + +namespace boost { + +template< typename, typename > class basic_string_view; + +namespace container { +template< typename, typename, typename > class basic_string; +} // namespace container + +namespace filesystem { + +BOOST_FILESYSTEM_DECL system::error_category const& codecvt_error_category() BOOST_NOEXCEPT; + +class directory_entry; + +namespace detail { +namespace path_traits { + +#if defined(BOOST_WINDOWS_API) +typedef wchar_t path_native_char_type; +#define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE false +#define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE true +#else +typedef char path_native_char_type; +#define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE true +#define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE false +#endif + +typedef std::codecvt< wchar_t, char, std::mbstate_t > codecvt_type; + +struct unknown_type_tag {}; +struct ntcts_type_tag {}; +struct char_ptr_tag : ntcts_type_tag {}; +struct char_array_tag : ntcts_type_tag {}; +struct string_class_tag {}; +struct std_string_tag : string_class_tag {}; +struct boost_container_string_tag : string_class_tag {}; +struct std_string_view_tag : string_class_tag {}; +struct boost_string_view_tag : string_class_tag {}; +struct range_type_tag {}; +struct directory_entry_tag {}; + +//! The traits define a number of properties of a path source +template< typename T > +struct path_source_traits +{ + //! The kind of the path source. Useful for dispatching. + typedef unknown_type_tag tag_type; + //! Character type that the source contains + typedef void char_type; + //! Indicates whether the source is natively supported by \c path::string_type as arguments for constructors/assignment/appending + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct path_source_traits< char* > +{ + typedef char_ptr_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< const char* > +{ + typedef char_ptr_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< wchar_t* > +{ + typedef char_ptr_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< const wchar_t* > +{ + typedef char_ptr_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< char[] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< const char[] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< wchar_t[] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< const wchar_t[] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< char[N] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< const char[N] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< wchar_t[N] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< const wchar_t[N] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< std::string > +{ + typedef std_string_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< std::wstring > +{ + typedef std_string_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< boost::container::basic_string< char, std::char_traits< char >, void > > +{ + typedef boost_container_string_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct path_source_traits< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > > +{ + typedef boost_container_string_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< > +struct path_source_traits< std::string_view > +{ + typedef std_string_view_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< std::wstring_view > +{ + typedef std_string_view_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< > +struct path_source_traits< boost::basic_string_view< char, std::char_traits< char > > > +{ + typedef boost_string_view_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct path_source_traits< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > > +{ + typedef boost_string_view_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::vector< char > > +{ + // Since C++11 this could be string_class_tag as std::vector gained data() member + typedef range_type_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::vector< wchar_t > > +{ + // Since C++11 this could be string_class_tag as std::vector gained data() member + typedef range_type_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::list< char > > +{ + typedef range_type_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::list< wchar_t > > +{ + typedef range_type_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 + +template< > +struct path_source_traits< directory_entry > +{ + typedef directory_entry_tag tag_type; + typedef path_native_char_type char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +#undef BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE +#undef BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE + + +//! The trait tests if the type is a known path Source tag +template< typename Tag > +struct is_known_path_source_tag : + public boost::true_type +{ +}; + +template< > +struct is_known_path_source_tag< unknown_type_tag > : + public boost::false_type +{ +}; + +//! The trait tests if the type is compatible with path Source requirements +template< typename T > +struct is_path_source : + public is_known_path_source_tag< typename path_source_traits< T >::tag_type >::type +{ +}; + + +//! The trait indicates whether the type is a path Source that is natively supported by path::string_type as the source for construction/assignment/appending +template< typename T > +struct is_native_path_source : + public boost::integral_constant< bool, path_source_traits< T >::is_native > +{ +}; + + +//! The trait indicates whether the type is one of the supported path character types +template< typename T > +struct is_path_char_type : + public boost::false_type +{ +}; + +template< > +struct is_path_char_type< char > : + public boost::true_type +{ +}; + +template< > +struct is_path_char_type< wchar_t > : + public boost::true_type +{ +}; + + +template< typename Iterator > +struct is_iterator_to_path_chars : + public is_path_char_type< typename std::iterator_traits< Iterator >::value_type >::type +{ +}; + +//! The trait indicates whether the type is an iterator over a sequence of path characters +template< typename Iterator > +struct is_path_source_iterator : + public boost::conjunction< + boost::iterators::is_iterator< Iterator >, + is_iterator_to_path_chars< Iterator > + >::type +{ +}; + + +//! The trait indicates whether the type is a pointer to a sequence of native path characters +template< typename T > +struct is_native_char_ptr : + public boost::false_type +{ +}; + +template< > +struct is_native_char_ptr< path_native_char_type* > : + public boost::true_type +{ +}; + +template< > +struct is_native_char_ptr< const path_native_char_type* > : + public boost::true_type +{ +}; + + +//! Converts character encoding using the supplied codecvt facet. If \a cvt is \c NULL then \c path::codecvt() will be used. +BOOST_FILESYSTEM_DECL +void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt = NULL); + +//! \overload convert +BOOST_FILESYSTEM_DECL +void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt = NULL); + + +// Source dispatch -----------------------------------------------------------------// + +template< typename Source, typename Callback > +typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt = NULL); + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(const char* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag) +{ + return cb(source, source + std::strlen(source), cvt); +} + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(const wchar_t* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag) +{ + return cb(source, source + std::wcslen(source), cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, string_class_tag) +{ + return cb(source.data(), source.data() + source.size(), cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, range_type_tag) +{ + std::basic_string< typename Source::value_type > src(source.begin(), source.end()); + return cb(src.data(), src.data() + src.size(), cvt); +} + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< char > const& source, Callback cb, const codecvt_type* cvt, range_type_tag) +{ + const char* data = NULL, *data_end = NULL; + if (!source.empty()) + { + data = &source[0]; + data_end = data + source.size(); + } + return cb(data, data_end, cvt); +} + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< wchar_t > const& source, Callback cb, const codecvt_type* cvt, range_type_tag) +{ + const wchar_t* data = NULL, *data_end = NULL; + if (!source.empty()) + { + data = &source[0]; + data_end = data + source.size(); + } + return cb(data, data_end, cvt); +} + +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 + +// Defined in directory.hpp to avoid circular header dependencies +template< typename Callback > +typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag); + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt) +{ + return path_traits::dispatch(source, cb, cvt, + typename path_traits::path_source_traits< typename boost::remove_cv< Source >::type >::tag_type()); +} + + +typedef char yes_type; +struct no_type { char buf[2]; }; + +#if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +namespace is_convertible_to_path_source_impl { + +yes_type check(const char*); +yes_type check(const wchar_t*); +yes_type check(std::string const&); +yes_type check(std::wstring const&); +yes_type check(boost::container::basic_string< char, std::char_traits< char >, void > const&); +yes_type check(boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const&); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +yes_type check(std::string_view const&); +yes_type check(std::wstring_view const&); +#endif +yes_type check(boost::basic_string_view< char, std::char_traits< char > > const&); +yes_type check(boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const&); +#if !defined(BOOST_NO_CXX11_NULLPTR) +no_type check(std::nullptr_t); +#endif +no_type check(...); + +} // namespace is_convertible_to_path_source_impl + +//! The type trait indicates whether the type has a conversion path to one of the path source types +template< typename T > +struct is_convertible_to_path_source : + public boost::integral_constant< + bool, + sizeof(is_convertible_to_path_source_impl::check(boost::declval< T const& >())) == sizeof(yes_type) + > +{ +}; + +#else // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +// Note: We use separate checks for convertibility to std::string_view and other types to avoid ambiguity with an implicit range constructor +// of std::string_view in the early C++23 draft (N4892). If a user's type is convertible to e.g. std::string and also satisfies +// ranges::contiguous_range and ranges::sized_range concepts then the conversion is ambiguous: the type is convertible to std::string +// through the conversion operator in the user's class and is also convertible to std::string_view through the implicit conversion +// constructor in std::string_view. The solution is to check convertibility to std::string_view separately first. + +namespace is_convertible_to_std_string_view_impl { + +yes_type check(std::string_view const&); +yes_type check(std::wstring_view const&); +#if !defined(BOOST_NO_CXX11_NULLPTR) +no_type check(std::nullptr_t); +#endif +no_type check(...); + +} // namespace is_convertible_to_std_string_view_impl + +template< typename T > +struct is_convertible_to_std_string_view : + public boost::integral_constant< + bool, + sizeof(is_convertible_to_std_string_view_impl::check(boost::declval< T const& >())) == sizeof(yes_type) + > +{ +}; + +namespace is_convertible_to_path_source_non_std_string_view_impl { + +yes_type check(const char*); +yes_type check(const wchar_t*); +yes_type check(std::string const&); +yes_type check(std::wstring const&); +yes_type check(boost::container::basic_string< char, std::char_traits< char >, void > const&); +yes_type check(boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const&); +yes_type check(boost::basic_string_view< char, std::char_traits< char > > const&); +yes_type check(boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const&); +#if !defined(BOOST_NO_CXX11_NULLPTR) +no_type check(std::nullptr_t); +#endif +no_type check(...); + +} // namespace is_convertible_to_path_source_non_std_string_view_impl + +template< typename T > +struct is_convertible_to_path_source_non_std_string_view : + public boost::integral_constant< + bool, + sizeof(is_convertible_to_path_source_non_std_string_view_impl::check(boost::declval< T const& >())) == sizeof(yes_type) + > +{ +}; + +//! The type trait indicates whether the type has a conversion path to one of the path source types +template< typename T > +struct is_convertible_to_path_source : + public boost::disjunction< + is_convertible_to_std_string_view< T >, + is_convertible_to_path_source_non_std_string_view< T > + >::type +{ +}; + +#endif // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +//! The type trait makes \a T dependent on the second template argument. Used to delay type resolution and name binding. +template< typename T, typename > +struct make_dependent +{ + typedef T type; +}; + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const char* source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< const char*, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const wchar_t* source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< const wchar_t*, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::string, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::wstring, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::container::basic_string< char, std::char_traits< char >, void > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::container::basic_string< char, std::char_traits< char >, void >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::basic_string_view< char, std::char_traits< char > > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::basic_string_view< char, std::char_traits< char > >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +#if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL) +{ + typedef typename boost::remove_cv< Source >::type source_t; + return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt); +} + +#else // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename boost::disable_if_c< + is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value, + typename Callback::result_type +>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL) +{ + typedef typename boost::remove_cv< Source >::type source_t; + return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename boost::enable_if_c< + is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value, + typename Callback::result_type +>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL) +{ + typedef typename boost::remove_cv< Source >::type source_t; + return path_traits::dispatch_convertible_sv_impl< source_t >(source, cb, cvt); +} + +#endif // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +} // namespace path_traits +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp new file mode 100644 index 0000000..4df9a7c --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu) +// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu). + +// Distributed under the Boost Software License, Version 1.0. +// (See http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_FILESYSTEM_UTF8_CODECVT_FACET_HPP +#define BOOST_FILESYSTEM_UTF8_CODECVT_FACET_HPP + +#include + +#include + +#define BOOST_UTF8_BEGIN_NAMESPACE \ + namespace boost { \ + namespace filesystem { \ + namespace detail { + +#define BOOST_UTF8_END_NAMESPACE \ + } \ + } \ + } +#define BOOST_UTF8_DECL BOOST_FILESYSTEM_DECL + +#include + +#undef BOOST_UTF8_BEGIN_NAMESPACE +#undef BOOST_UTF8_END_NAMESPACE +#undef BOOST_UTF8_DECL + +#include + +#endif // BOOST_FILESYSTEM_UTF8_CODECVT_FACET_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/directory.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/directory.hpp new file mode 100644 index 0000000..2afcfb6 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/directory.hpp @@ -0,0 +1,1113 @@ +// boost/filesystem/directory.hpp ---------------------------------------------------// + +// Copyright Beman Dawes 2002-2009 +// Copyright Jan Langer 2002 +// Copyright Dietmar Kuehl 2001 +// Copyright Vladimir Prus 2002 +// Copyright Andrey Semashev 2019, 2022 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_DIRECTORY_HPP +#define BOOST_FILESYSTEM_DIRECTORY_HPP + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include // must be the last #include + +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +class directory_iterator; + +namespace detail { + +struct directory_iterator_params; + +BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, directory_iterator_params* params, system::error_code* ec); +BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec); + +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// directory_entry // +// // +//--------------------------------------------------------------------------------------// + +// GCC has a problem with a member function named path within a namespace or +// sub-namespace that also has a class named path. The workaround is to always +// fully qualify the name path when it refers to the class name. + +class directory_entry +{ + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, detail::directory_iterator_params* params, system::error_code* ec); + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec); + +public: + typedef boost::filesystem::path::value_type value_type; // enables class path ctor taking directory_entry + + directory_entry() BOOST_NOEXCEPT {} + + explicit directory_entry(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + directory_entry(boost::filesystem::path const& p, system::error_code& ec) : + m_path(p) + { + refresh_impl(&ec); + if (ec) + m_path.clear(); + } +#else + directory_entry(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) : + m_path(p), m_status(st), m_symlink_status(symlink_st) + { + } +#endif + + directory_entry(directory_entry const& rhs) : + m_path(rhs.m_path), m_status(rhs.m_status), m_symlink_status(rhs.m_symlink_status) + { + } + + directory_entry& operator=(directory_entry const& rhs) + { + m_path = rhs.m_path; + m_status = rhs.m_status; + m_symlink_status = rhs.m_symlink_status; + return *this; + } + + // As of October 2015 the interaction between noexcept and =default is so troublesome + // for VC++, GCC, and probably other compilers, that =default is not used with noexcept + // functions. GCC is not even consistent for the same release on different platforms. + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + directory_entry(directory_entry&& rhs) BOOST_NOEXCEPT : + m_path(static_cast< boost::filesystem::path&& >(rhs.m_path)), + m_status(static_cast< file_status&& >(rhs.m_status)), + m_symlink_status(static_cast< file_status&& >(rhs.m_symlink_status)) + { + } + + directory_entry& operator=(directory_entry&& rhs) BOOST_NOEXCEPT + { + m_path = static_cast< boost::filesystem::path&& >(rhs.m_path); + m_status = static_cast< file_status&& >(rhs.m_status); + m_symlink_status = static_cast< file_status&& >(rhs.m_symlink_status); + return *this; + } + + void assign(boost::filesystem::path&& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void assign(boost::filesystem::path&& p, system::error_code& ec) + { + m_path = static_cast< boost::filesystem::path&& >(p); + refresh_impl(&ec); + } +#else + void assign(boost::filesystem::path&& p, file_status st, file_status symlink_st = file_status()) + { + assign_with_status(static_cast< boost::filesystem::path&& >(p), st, symlink_st); + } +#endif +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + void assign(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void assign(boost::filesystem::path const& p, system::error_code& ec) + { + m_path = p; + refresh_impl(&ec); + } +#else + void assign(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) + { + assign_with_status(p, st, symlink_st); + } +#endif + + void replace_filename(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void replace_filename(boost::filesystem::path const& p, system::error_code& ec) + { + m_path.replace_filename(p); + refresh_impl(&ec); + } +#else + void replace_filename(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) + { + replace_filename_with_status(p, st, symlink_st); + } + + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_entry::replace_filename() instead") + void replace_leaf(boost::filesystem::path const& p, file_status st, file_status symlink_st) + { + replace_filename_with_status(p, st, symlink_st); + } +#endif + + boost::filesystem::path const& path() const BOOST_NOEXCEPT { return m_path; } + operator boost::filesystem::path const&() const BOOST_NOEXCEPT { return m_path; } + + void refresh() { refresh_impl(); } + void refresh(system::error_code& ec) BOOST_NOEXCEPT { refresh_impl(&ec); } + + file_status status() const + { + if (!filesystem::status_known(m_status)) + refresh_impl(); + return m_status; + } + + file_status status(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::status_known(m_status)) + refresh_impl(&ec); + return m_status; + } + + file_status symlink_status() const + { + if (!filesystem::status_known(m_symlink_status)) + refresh_impl(); + return m_symlink_status; + } + + file_status symlink_status(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::status_known(m_symlink_status)) + refresh_impl(&ec); + return m_symlink_status; + } + + filesystem::file_type file_type() const + { + if (!filesystem::type_present(m_status)) + refresh_impl(); + return m_status.type(); + } + + filesystem::file_type file_type(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::type_present(m_status)) + refresh_impl(&ec); + return m_status.type(); + } + + filesystem::file_type symlink_file_type() const + { + if (!filesystem::type_present(m_symlink_status)) + refresh_impl(); + return m_symlink_status.type(); + } + + filesystem::file_type symlink_file_type(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::type_present(m_symlink_status)) + refresh_impl(&ec); + return m_symlink_status.type(); + } + + bool exists() const + { + filesystem::file_type ft = this->file_type(); + return ft != filesystem::status_error && ft != filesystem::file_not_found; + } + + bool exists(system::error_code& ec) const BOOST_NOEXCEPT + { + filesystem::file_type ft = this->file_type(ec); + return ft != filesystem::status_error && ft != filesystem::file_not_found; + } + + bool is_regular_file() const + { + return this->file_type() == filesystem::regular_file; + } + + bool is_regular_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::regular_file; + } + + bool is_directory() const + { + return this->file_type() == filesystem::directory_file; + } + + bool is_directory(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::directory_file; + } + + bool is_symlink() const + { + return this->symlink_file_type() == filesystem::symlink_file; + } + + bool is_symlink(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->symlink_file_type(ec) == filesystem::symlink_file; + } + + bool is_block_file() const + { + return this->file_type() == filesystem::block_file; + } + + bool is_block_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::block_file; + } + + bool is_character_file() const + { + return this->file_type() == filesystem::character_file; + } + + bool is_character_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::character_file; + } + + bool is_fifo() const + { + return this->file_type() == filesystem::fifo_file; + } + + bool is_fifo(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::fifo_file; + } + + bool is_socket() const + { + return this->file_type() == filesystem::socket_file; + } + + bool is_socket(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::socket_file; + } + + bool is_reparse_file() const + { + return this->symlink_file_type() == filesystem::reparse_file; + } + + bool is_reparse_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->symlink_file_type(ec) == filesystem::reparse_file; + } + + bool is_other() const + { + filesystem::file_type ft = this->file_type(); + return ft != filesystem::status_error && ft != filesystem::file_not_found && + ft != filesystem::regular_file && ft != filesystem::directory_file; + } + + bool is_other(system::error_code& ec) const BOOST_NOEXCEPT + { + filesystem::file_type ft = this->file_type(ec); + return ft != filesystem::status_error && ft != filesystem::file_not_found && + ft != filesystem::regular_file && ft != filesystem::directory_file; + } + + bool operator==(directory_entry const& rhs) const { return m_path == rhs.m_path; } + bool operator!=(directory_entry const& rhs) const { return m_path != rhs.m_path; } + bool operator<(directory_entry const& rhs) const { return m_path < rhs.m_path; } + bool operator<=(directory_entry const& rhs) const { return m_path <= rhs.m_path; } + bool operator>(directory_entry const& rhs) const { return m_path > rhs.m_path; } + bool operator>=(directory_entry const& rhs) const { return m_path >= rhs.m_path; } + +private: + BOOST_FILESYSTEM_DECL void refresh_impl(system::error_code* ec = NULL) const; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + void assign_with_status(boost::filesystem::path&& p, file_status st, file_status symlink_st) + { + m_path = static_cast< boost::filesystem::path&& >(p); + m_status = static_cast< file_status&& >(st); + m_symlink_status = static_cast< file_status&& >(symlink_st); + } +#endif + + void assign_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st) + { + m_path = p; +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + m_status = static_cast< file_status&& >(st); + m_symlink_status = static_cast< file_status&& >(symlink_st); +#else + m_status = st; + m_symlink_status = symlink_st; +#endif + } + + void replace_filename_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st) + { + m_path.replace_filename(p); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + m_status = static_cast< file_status&& >(st); + m_symlink_status = static_cast< file_status&& >(symlink_st); +#else + m_status = st; + m_symlink_status = symlink_st; +#endif + } + +private: + boost::filesystem::path m_path; + mutable file_status m_status; // stat()-like + mutable file_status m_symlink_status; // lstat()-like +}; + +#if !defined(BOOST_FILESYSTEM_SOURCE) + +inline directory_entry::directory_entry(boost::filesystem::path const& p) : + m_path(p) +{ +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#endif +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +inline void directory_entry::assign(boost::filesystem::path&& p) +{ + m_path = static_cast< boost::filesystem::path&& >(p); +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +inline void directory_entry::assign(boost::filesystem::path const& p) +{ + m_path = p; +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} + +inline void directory_entry::replace_filename(boost::filesystem::path const& p) +{ + m_path.replace_filename(p); +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} + +#endif // !defined(BOOST_FILESYSTEM_SOURCE) + +namespace detail { +namespace path_traits { + +// Dispatch function for integration with path class +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag) +{ + boost::filesystem::path::string_type const& source = de.path().native(); + return cb(source.data(), source.data() + source.size(), cvt); +} + +} // namespace path_traits +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// directory_entry overloads // +// // +//--------------------------------------------------------------------------------------// + +// Without these functions, calling (for example) 'is_directory' with a 'directory_entry' results in: +// - a conversion to 'path' using 'operator boost::filesystem::path const&()', +// - then a call to 'is_directory(path const& p)' which recomputes the status with 'detail::status(p)'. +// +// These functions avoid a costly recomputation of the status if one calls 'is_directory(e)' instead of 'is_directory(e.status())' + +inline file_status status(directory_entry const& e) +{ + return e.status(); +} + +inline file_status status(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.status(ec); +} + +inline file_status symlink_status(directory_entry const& e) +{ + return e.symlink_status(); +} + +inline file_status symlink_status(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.symlink_status(ec); +} + +inline bool type_present(directory_entry const& e) +{ + return e.file_type() != filesystem::status_error; +} + +inline bool type_present(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.file_type(ec) != filesystem::status_error; +} + +inline bool status_known(directory_entry const& e) +{ + return filesystem::status_known(e.status()); +} + +inline bool status_known(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::status_known(e.status(ec)); +} + +inline bool exists(directory_entry const& e) +{ + return e.exists(); +} + +inline bool exists(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.exists(ec); +} + +inline bool is_regular_file(directory_entry const& e) +{ + return e.is_regular_file(); +} + +inline bool is_regular_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_regular_file(ec); +} + +inline bool is_directory(directory_entry const& e) +{ + return e.is_directory(); +} + +inline bool is_directory(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_directory(ec); +} + +inline bool is_symlink(directory_entry const& e) +{ + return e.is_symlink(); +} + +inline bool is_symlink(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_symlink(ec); +} + +inline bool is_block_file(directory_entry const& e) +{ + return e.is_block_file(); +} + +inline bool is_block_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_block_file(ec); +} + +inline bool is_character_file(directory_entry const& e) +{ + return e.is_character_file(); +} + +inline bool is_character_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_character_file(ec); +} + +inline bool is_fifo(directory_entry const& e) +{ + return e.is_fifo(); +} + +inline bool is_fifo(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_fifo(ec); +} + +inline bool is_socket(directory_entry const& e) +{ + return e.is_socket(); +} + +inline bool is_socket(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_socket(ec); +} + +inline bool is_reparse_file(directory_entry const& e) +{ + return e.is_reparse_file(); +} + +inline bool is_reparse_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_reparse_file(ec); +} + +inline bool is_other(directory_entry const& e) +{ + return e.is_other(); +} + +inline bool is_other(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_other(ec); +} + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") +inline bool is_regular(directory_entry const& e) +{ + return filesystem::is_regular_file(e); +} +#endif + +//--------------------------------------------------------------------------------------// +// // +// directory_iterator helpers // +// // +//--------------------------------------------------------------------------------------// + +BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(directory_options, unsigned int) +{ + none = 0u, + skip_permission_denied = 1u, // if a directory cannot be opened because of insufficient permissions, pretend that the directory is empty + follow_directory_symlink = 1u << 1u, // recursive_directory_iterator: follow directory symlinks + skip_dangling_symlinks = 1u << 2u, // non-standard extension for recursive_directory_iterator: don't follow dangling directory symlinks, + pop_on_error = 1u << 3u, // non-standard extension for recursive_directory_iterator: instead of producing an end iterator on errors, + // repeatedly invoke pop() until it succeeds or the iterator becomes equal to end iterator + _detail_no_follow = 1u << 4u, // internal use only + _detail_no_push = 1u << 5u // internal use only +} +BOOST_SCOPED_ENUM_DECLARE_END(directory_options) + +BOOST_BITMASK(BOOST_SCOPED_ENUM_NATIVE(directory_options)) + +namespace detail { + +struct dir_itr_imp : + public boost::intrusive_ref_counter< dir_itr_imp > +{ +#ifdef BOOST_WINDOWS_API + bool close_handle; + unsigned char extra_data_format; + std::size_t current_offset; +#endif + directory_entry dir_entry; + void* handle; + + dir_itr_imp() BOOST_NOEXCEPT : +#ifdef BOOST_WINDOWS_API + close_handle(false), + extra_data_format(0u), + current_offset(0u), +#endif + handle(NULL) + { + } + BOOST_FILESYSTEM_DECL ~dir_itr_imp() BOOST_NOEXCEPT; + + BOOST_FILESYSTEM_DECL static void* operator new(std::size_t class_size, std::size_t extra_size) BOOST_NOEXCEPT; + BOOST_FILESYSTEM_DECL static void operator delete(void* p, std::size_t extra_size) BOOST_NOEXCEPT; + BOOST_FILESYSTEM_DECL static void operator delete(void* p) BOOST_NOEXCEPT; +}; + +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// directory_iterator // +// // +//--------------------------------------------------------------------------------------// + +class directory_iterator : + public boost::iterator_facade< + directory_iterator, + directory_entry, + boost::single_pass_traversal_tag + > +{ + friend class boost::iterator_core_access; + + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, detail::directory_iterator_params* params, system::error_code* ec); + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec); + +public: + directory_iterator() BOOST_NOEXCEPT {} // creates the "end" iterator + + // iterator_facade derived classes don't seem to like implementations in + // separate translation unit dll's, so forward to detail functions + explicit directory_iterator(path const& p, BOOST_SCOPED_ENUM_NATIVE(directory_options) opts = directory_options::none) + { + detail::directory_iterator_construct(*this, p, static_cast< unsigned int >(opts), NULL, NULL); + } + + directory_iterator(path const& p, system::error_code& ec) BOOST_NOEXCEPT + { + detail::directory_iterator_construct(*this, p, static_cast< unsigned int >(directory_options::none), NULL, &ec); + } + + directory_iterator(path const& p, BOOST_SCOPED_ENUM_NATIVE(directory_options) opts, system::error_code& ec) BOOST_NOEXCEPT + { + detail::directory_iterator_construct(*this, p, static_cast< unsigned int >(opts), NULL, &ec); + } + + BOOST_DEFAULTED_FUNCTION(directory_iterator(directory_iterator const& that), : m_imp(that.m_imp) {}) + BOOST_DEFAULTED_FUNCTION(directory_iterator& operator=(directory_iterator const& that), { m_imp = that.m_imp; return *this; }) + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + directory_iterator(directory_iterator&& that) BOOST_NOEXCEPT : + m_imp(static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp)) + { + } + + directory_iterator& operator=(directory_iterator&& that) BOOST_NOEXCEPT + { + m_imp = static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp); + return *this; + } +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + directory_iterator& increment(system::error_code& ec) BOOST_NOEXCEPT + { + detail::directory_iterator_increment(*this, &ec); + return *this; + } + +private: + boost::iterator_facade< + directory_iterator, + directory_entry, + boost::single_pass_traversal_tag + >::reference dereference() const + { + BOOST_ASSERT_MSG(!is_end(), "attempt to dereference end directory iterator"); + return m_imp->dir_entry; + } + + void increment() { detail::directory_iterator_increment(*this, NULL); } + + bool equal(directory_iterator const& rhs) const BOOST_NOEXCEPT + { + return m_imp == rhs.m_imp || (is_end() && rhs.is_end()); + } + + bool is_end() const BOOST_NOEXCEPT + { + // Note: The check for handle is needed because the iterator can be copied and the copy + // can be incremented to end while the original iterator still refers to the same dir_itr_imp. + return !m_imp || !m_imp->handle; + } + +private: + // intrusive_ptr provides the shallow-copy semantics required for single pass iterators + // (i.e. InputIterators). The end iterator is indicated by is_end(). + boost::intrusive_ptr< detail::dir_itr_imp > m_imp; +}; + +// enable directory_iterator C++11 range-based for statement use --------------------// + +// begin() and end() are only used by a range-based for statement in the context of +// auto - thus the top-level const is stripped - so returning const is harmless and +// emphasizes begin() is just a pass through. +inline directory_iterator const& begin(directory_iterator const& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline directory_iterator end(directory_iterator const&) BOOST_NOEXCEPT +{ + return directory_iterator(); +} + +// enable C++14 generic accessors for range const iterators +inline directory_iterator const& cbegin(directory_iterator const& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline directory_iterator cend(directory_iterator const&) BOOST_NOEXCEPT +{ + return directory_iterator(); +} + +// enable directory_iterator BOOST_FOREACH -----------------------------------------// + +inline directory_iterator& range_begin(directory_iterator& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline directory_iterator range_begin(directory_iterator const& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline directory_iterator range_end(directory_iterator&) BOOST_NOEXCEPT +{ + return directory_iterator(); +} + +inline directory_iterator range_end(directory_iterator const&) BOOST_NOEXCEPT +{ + return directory_iterator(); +} + +} // namespace filesystem + +// namespace boost template specializations +template< typename C, typename Enabler > +struct range_mutable_iterator; + +template<> +struct range_mutable_iterator< boost::filesystem::directory_iterator, void > +{ + typedef boost::filesystem::directory_iterator type; +}; + +template< typename C, typename Enabler > +struct range_const_iterator; + +template<> +struct range_const_iterator< boost::filesystem::directory_iterator, void > +{ + typedef boost::filesystem::directory_iterator type; +}; + +namespace filesystem { + +//--------------------------------------------------------------------------------------// +// // +// recursive_directory_iterator helpers // +// // +//--------------------------------------------------------------------------------------// + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +// Deprecated enum, use directory_options instead +BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(symlink_option, unsigned int) +{ + none = static_cast< unsigned int >(directory_options::none), + no_recurse = none, // don't follow directory symlinks (default behavior) + recurse = static_cast< unsigned int >(directory_options::follow_directory_symlink), // follow directory symlinks + _detail_no_push = static_cast< unsigned int >(directory_options::_detail_no_push) // internal use only +} +BOOST_SCOPED_ENUM_DECLARE_END(symlink_option) + +BOOST_BITMASK(BOOST_SCOPED_ENUM_NATIVE(symlink_option)) +#endif // BOOST_FILESYSTEM_NO_DEPRECATED + +class recursive_directory_iterator; + +namespace detail { + +struct recur_dir_itr_imp : + public boost::intrusive_ref_counter< recur_dir_itr_imp > +{ + typedef directory_iterator element_type; + std::vector< element_type > m_stack; + // directory_options values, declared as unsigned int for ABI compatibility + unsigned int m_options; + + explicit recur_dir_itr_imp(unsigned int opts) BOOST_NOEXCEPT : m_options(opts) {} +}; + +BOOST_FILESYSTEM_DECL void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, unsigned int opts, system::error_code* ec); +BOOST_FILESYSTEM_DECL void recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec); +BOOST_FILESYSTEM_DECL void recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec); + +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// recursive_directory_iterator // +// // +//--------------------------------------------------------------------------------------// + +class recursive_directory_iterator : + public boost::iterator_facade< + recursive_directory_iterator, + directory_entry, + boost::single_pass_traversal_tag + > +{ + friend class boost::iterator_core_access; + + friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, unsigned int opts, system::error_code* ec); + friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec); + friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec); + +public: + recursive_directory_iterator() BOOST_NOEXCEPT {} // creates the "end" iterator + + explicit recursive_directory_iterator(path const& dir_path) + { + detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(directory_options::none), NULL); + } + + recursive_directory_iterator(path const& dir_path, system::error_code& ec) + { + detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(directory_options::none), &ec); + } + + recursive_directory_iterator(path const& dir_path, BOOST_SCOPED_ENUM_NATIVE(directory_options) opts) + { + detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(opts), NULL); + } + + recursive_directory_iterator(path const& dir_path, BOOST_SCOPED_ENUM_NATIVE(directory_options) opts, system::error_code& ec) + { + detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(opts), &ec); + } + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + // Deprecated constructors + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_options instead of symlink_option") + recursive_directory_iterator(path const& dir_path, BOOST_SCOPED_ENUM_NATIVE(symlink_option) opts) + { + detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(opts), NULL); + } + + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_options instead of symlink_option") + recursive_directory_iterator(path const& dir_path, BOOST_SCOPED_ENUM_NATIVE(symlink_option) opts, system::error_code& ec) BOOST_NOEXCEPT + { + detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(opts), &ec); + } +#endif // BOOST_FILESYSTEM_NO_DEPRECATED + + BOOST_DEFAULTED_FUNCTION(recursive_directory_iterator(recursive_directory_iterator const& that), : m_imp(that.m_imp) {}) + BOOST_DEFAULTED_FUNCTION(recursive_directory_iterator& operator=(recursive_directory_iterator const& that), { m_imp = that.m_imp; return *this; }) + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + recursive_directory_iterator(recursive_directory_iterator&& that) BOOST_NOEXCEPT : + m_imp(static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp)) + { + } + + recursive_directory_iterator& operator=(recursive_directory_iterator&& that) BOOST_NOEXCEPT + { + m_imp = static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp); + return *this; + } +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + recursive_directory_iterator& increment(system::error_code& ec) BOOST_NOEXCEPT + { + detail::recursive_directory_iterator_increment(*this, &ec); + return *this; + } + + int depth() const BOOST_NOEXCEPT + { + BOOST_ASSERT_MSG(!is_end(), "depth() on end recursive_directory_iterator"); + return static_cast< int >(m_imp->m_stack.size() - 1u); + } + + bool recursion_pending() const BOOST_NOEXCEPT + { + BOOST_ASSERT_MSG(!is_end(), "recursion_pending() on end recursive_directory_iterator"); + return (m_imp->m_options & static_cast< unsigned int >(directory_options::_detail_no_push)) == 0u; + } + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use recursive_directory_iterator::depth() instead") + int level() const BOOST_NOEXCEPT + { + return depth(); + } + bool no_push_pending() const BOOST_NOEXCEPT { return !recursion_pending(); } + bool no_push_request() const BOOST_NOEXCEPT { return !recursion_pending(); } +#endif + + void pop() + { + detail::recursive_directory_iterator_pop(*this, NULL); + } + + void pop(system::error_code& ec) BOOST_NOEXCEPT + { + detail::recursive_directory_iterator_pop(*this, &ec); + } + + void disable_recursion_pending(bool value = true) BOOST_NOEXCEPT + { + BOOST_ASSERT_MSG(!is_end(), "disable_recursion_pending() on end recursive_directory_iterator"); + if (value) + m_imp->m_options |= static_cast< unsigned int >(directory_options::_detail_no_push); + else + m_imp->m_options &= ~static_cast< unsigned int >(directory_options::_detail_no_push); + } + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use recursive_directory_iterator::disable_recursion_pending() instead") + void no_push(bool value = true) BOOST_NOEXCEPT + { + disable_recursion_pending(value); + } +#endif + + file_status status() const + { + BOOST_ASSERT_MSG(!is_end(), "status() on end recursive_directory_iterator"); + return m_imp->m_stack.back()->status(); + } + + file_status symlink_status() const + { + BOOST_ASSERT_MSG(!is_end(), "symlink_status() on end recursive_directory_iterator"); + return m_imp->m_stack.back()->symlink_status(); + } + +private: + boost::iterator_facade< + recursive_directory_iterator, + directory_entry, + boost::single_pass_traversal_tag + >::reference dereference() const + { + BOOST_ASSERT_MSG(!is_end(), "dereference of end recursive_directory_iterator"); + return *m_imp->m_stack.back(); + } + + void increment() { detail::recursive_directory_iterator_increment(*this, NULL); } + + bool equal(recursive_directory_iterator const& rhs) const BOOST_NOEXCEPT + { + return m_imp == rhs.m_imp || (is_end() && rhs.is_end()); + } + + bool is_end() const BOOST_NOEXCEPT + { + // Note: The check for m_stack.empty() is needed because the iterator can be copied and the copy + // can be incremented to end while the original iterator still refers to the same recur_dir_itr_imp. + return !m_imp || m_imp->m_stack.empty(); + } + +private: + // intrusive_ptr provides the shallow-copy semantics required for single pass iterators + // (i.e. InputIterators). The end iterator is indicated by is_end(). + boost::intrusive_ptr< detail::recur_dir_itr_imp > m_imp; +}; + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use recursive_directory_iterator instead") +typedef recursive_directory_iterator wrecursive_directory_iterator; +#endif + +// enable recursive directory iterator C++11 range-base for statement use ----------// + +// begin() and end() are only used by a range-based for statement in the context of +// auto - thus the top-level const is stripped - so returning const is harmless and +// emphasizes begin() is just a pass through. +inline recursive_directory_iterator const& begin(recursive_directory_iterator const& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline recursive_directory_iterator end(recursive_directory_iterator const&) BOOST_NOEXCEPT +{ + return recursive_directory_iterator(); +} + +// enable C++14 generic accessors for range const iterators +inline recursive_directory_iterator const& cbegin(recursive_directory_iterator const& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline recursive_directory_iterator cend(recursive_directory_iterator const&) BOOST_NOEXCEPT +{ + return recursive_directory_iterator(); +} + +// enable recursive directory iterator BOOST_FOREACH -------------------------------// + +inline recursive_directory_iterator& range_begin(recursive_directory_iterator& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline recursive_directory_iterator range_begin(recursive_directory_iterator const& iter) BOOST_NOEXCEPT +{ + return iter; +} + +inline recursive_directory_iterator range_end(recursive_directory_iterator&) BOOST_NOEXCEPT +{ + return recursive_directory_iterator(); +} + +inline recursive_directory_iterator range_end(recursive_directory_iterator const&) BOOST_NOEXCEPT +{ + return recursive_directory_iterator(); +} + +} // namespace filesystem + +// namespace boost template specializations +template<> +struct range_mutable_iterator< boost::filesystem::recursive_directory_iterator, void > +{ + typedef boost::filesystem::recursive_directory_iterator type; +}; + +template<> +struct range_const_iterator< boost::filesystem::recursive_directory_iterator, void > +{ + typedef boost::filesystem::recursive_directory_iterator type; +}; + +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_DIRECTORY_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/exception.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/exception.hpp new file mode 100644 index 0000000..5980776 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/exception.hpp @@ -0,0 +1,92 @@ +// boost/filesystem/exception.hpp -----------------------------------------------------// + +// Copyright Beman Dawes 2003 +// Copyright Andrey Semashev 2019 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_EXCEPTION_HPP +#define BOOST_FILESYSTEM_EXCEPTION_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +//--------------------------------------------------------------------------------------// +// // +// class filesystem_error // +// // +//--------------------------------------------------------------------------------------// + +class BOOST_SYMBOL_VISIBLE filesystem_error : + public system::system_error +{ + // see http://www.boost.org/more/error_handling.html for design rationale + +public: + BOOST_FILESYSTEM_DECL filesystem_error(const char* what_arg, system::error_code ec); + BOOST_FILESYSTEM_DECL filesystem_error(std::string const& what_arg, system::error_code ec); + BOOST_FILESYSTEM_DECL filesystem_error(const char* what_arg, path const& path1_arg, system::error_code ec); + BOOST_FILESYSTEM_DECL filesystem_error(std::string const& what_arg, path const& path1_arg, system::error_code ec); + BOOST_FILESYSTEM_DECL filesystem_error(const char* what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec); + BOOST_FILESYSTEM_DECL filesystem_error(std::string const& what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec); + + BOOST_FILESYSTEM_DECL filesystem_error(filesystem_error const& that); + BOOST_FILESYSTEM_DECL filesystem_error& operator=(filesystem_error const& that); + + BOOST_FILESYSTEM_DECL ~filesystem_error() BOOST_NOEXCEPT_OR_NOTHROW; + + path const& path1() const BOOST_NOEXCEPT + { + return m_imp_ptr.get() ? m_imp_ptr->m_path1 : get_empty_path(); + } + path const& path2() const BOOST_NOEXCEPT + { + return m_imp_ptr.get() ? m_imp_ptr->m_path2 : get_empty_path(); + } + + BOOST_FILESYSTEM_DECL const char* what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE; + +private: + BOOST_FILESYSTEM_DECL static path const& get_empty_path() BOOST_NOEXCEPT; + +private: + struct impl : + public boost::intrusive_ref_counter< impl > + { + path m_path1; // may be empty() + path m_path2; // may be empty() + std::string m_what; // not built until needed + + BOOST_DEFAULTED_FUNCTION(impl(), {}) + explicit impl(path const& path1) : + m_path1(path1) + { + } + impl(path const& path1, path const& path2) : + m_path1(path1), m_path2(path2) + { + } + }; + boost::intrusive_ptr< impl > m_imp_ptr; +}; + +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_EXCEPTION_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/file_status.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/file_status.hpp new file mode 100644 index 0000000..fb36240 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/file_status.hpp @@ -0,0 +1,269 @@ +// boost/filesystem/file_status.hpp --------------------------------------------------// + +// Copyright Beman Dawes 2002-2009 +// Copyright Jan Langer 2002 +// Copyright Dietmar Kuehl 2001 +// Copyright Vladimir Prus 2002 +// Copyright Andrey Semashev 2019 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_FILE_STATUS_HPP +#define BOOST_FILESYSTEM_FILE_STATUS_HPP + +#include +#include + +#include // must be the last #include + +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +//--------------------------------------------------------------------------------------// +// file_type // +//--------------------------------------------------------------------------------------// + +enum file_type +{ + status_error, +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED + status_unknown = status_error, +#endif + file_not_found, + regular_file, + directory_file, + // the following may not apply to some operating systems or file systems + symlink_file, + block_file, + character_file, + fifo_file, + socket_file, + reparse_file, // Windows: FILE_ATTRIBUTE_REPARSE_POINT that is not a symlink + type_unknown // file does exist, but isn't one of the above types or + // we don't have strong enough permission to find its type +}; + +//--------------------------------------------------------------------------------------// +// perms // +//--------------------------------------------------------------------------------------// + +enum perms +{ + no_perms = 0, // file_not_found is no_perms rather than perms_not_known + + // POSIX equivalent macros given in comments. + // Values are from POSIX and are given in octal per the POSIX standard. + + // permission bits + + owner_read = 0400, // S_IRUSR, Read permission, owner + owner_write = 0200, // S_IWUSR, Write permission, owner + owner_exe = 0100, // S_IXUSR, Execute/search permission, owner + owner_all = 0700, // S_IRWXU, Read, write, execute/search by owner + + group_read = 040, // S_IRGRP, Read permission, group + group_write = 020, // S_IWGRP, Write permission, group + group_exe = 010, // S_IXGRP, Execute/search permission, group + group_all = 070, // S_IRWXG, Read, write, execute/search by group + + others_read = 04, // S_IROTH, Read permission, others + others_write = 02, // S_IWOTH, Write permission, others + others_exe = 01, // S_IXOTH, Execute/search permission, others + others_all = 07, // S_IRWXO, Read, write, execute/search by others + + all_all = 0777, // owner_all|group_all|others_all + + // other POSIX bits + + set_uid_on_exe = 04000, // S_ISUID, Set-user-ID on execution + set_gid_on_exe = 02000, // S_ISGID, Set-group-ID on execution + sticky_bit = 01000, // S_ISVTX, + // (POSIX XSI) On directories, restricted deletion flag + // (V7) 'sticky bit': save swapped text even after use + // (SunOS) On non-directories: don't cache this file + // (SVID-v4.2) On directories: restricted deletion flag + // Also see http://en.wikipedia.org/wiki/Sticky_bit + + perms_mask = 07777, // all_all|set_uid_on_exe|set_gid_on_exe|sticky_bit + + perms_not_known = 0xFFFF, // present when directory_entry cache not loaded + + // options for permissions() function + + add_perms = 0x1000, // adds the given permission bits to the current bits + remove_perms = 0x2000, // removes the given permission bits from the current bits; + // choose add_perms or remove_perms, not both; if neither add_perms + // nor remove_perms is given, replace the current bits with + // the given bits. + + symlink_perms = 0x4000, // on POSIX, don't resolve symlinks; implied on Windows + + // BOOST_BITMASK op~ casts to int32_least_t, producing invalid enum values + _detail_extend_perms_32_1 = 0x7fffffff, + _detail_extend_perms_32_2 = -0x7fffffff - 1 +}; + +BOOST_BITMASK(perms) + +//--------------------------------------------------------------------------------------// +// file_status // +//--------------------------------------------------------------------------------------// + +class file_status +{ +public: + BOOST_CONSTEXPR file_status() BOOST_NOEXCEPT : + m_value(status_error), + m_perms(perms_not_known) + { + } + explicit BOOST_CONSTEXPR file_status(file_type v) BOOST_NOEXCEPT : + m_value(v), + m_perms(perms_not_known) + { + } + BOOST_CONSTEXPR file_status(file_type v, perms prms) BOOST_NOEXCEPT : + m_value(v), + m_perms(prms) + { + } + + // As of October 2015 the interaction between noexcept and =default is so troublesome + // for VC++, GCC, and probably other compilers, that =default is not used with noexcept + // functions. GCC is not even consistent for the same release on different platforms. + + BOOST_CONSTEXPR file_status(file_status const& rhs) BOOST_NOEXCEPT : + m_value(rhs.m_value), + m_perms(rhs.m_perms) + { + } + BOOST_CXX14_CONSTEXPR file_status& operator=(file_status const& rhs) BOOST_NOEXCEPT + { + m_value = rhs.m_value; + m_perms = rhs.m_perms; + return *this; + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + // Note: std::move is not constexpr in C++11, that's why we're not using it here + BOOST_CONSTEXPR file_status(file_status&& rhs) BOOST_NOEXCEPT : + m_value(static_cast< file_type&& >(rhs.m_value)), + m_perms(static_cast< perms&& >(rhs.m_perms)) + { + } + BOOST_CXX14_CONSTEXPR file_status& operator=(file_status&& rhs) BOOST_NOEXCEPT + { + m_value = static_cast< file_type&& >(rhs.m_value); + m_perms = static_cast< perms&& >(rhs.m_perms); + return *this; + } +#endif + + // observers + BOOST_CONSTEXPR file_type type() const BOOST_NOEXCEPT { return m_value; } + BOOST_CONSTEXPR perms permissions() const BOOST_NOEXCEPT { return m_perms; } + + // modifiers + BOOST_CXX14_CONSTEXPR void type(file_type v) BOOST_NOEXCEPT { m_value = v; } + BOOST_CXX14_CONSTEXPR void permissions(perms prms) BOOST_NOEXCEPT { m_perms = prms; } + + BOOST_CONSTEXPR bool operator==(file_status const& rhs) const BOOST_NOEXCEPT + { + return type() == rhs.type() && permissions() == rhs.permissions(); + } + BOOST_CONSTEXPR bool operator!=(file_status const& rhs) const BOOST_NOEXCEPT + { + return !(*this == rhs); + } + +private: + file_type m_value; + perms m_perms; +}; + +inline BOOST_CONSTEXPR bool type_present(file_status f) BOOST_NOEXCEPT +{ + return f.type() != filesystem::status_error; +} + +inline BOOST_CONSTEXPR bool permissions_present(file_status f) BOOST_NOEXCEPT +{ + return f.permissions() != filesystem::perms_not_known; +} + +inline BOOST_CONSTEXPR bool status_known(file_status f) BOOST_NOEXCEPT +{ + return filesystem::type_present(f) && filesystem::permissions_present(f); +} + +inline BOOST_CONSTEXPR bool exists(file_status f) BOOST_NOEXCEPT +{ + return f.type() != filesystem::status_error && f.type() != filesystem::file_not_found; +} + +inline BOOST_CONSTEXPR bool is_regular_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::regular_file; +} + +inline BOOST_CONSTEXPR bool is_directory(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::directory_file; +} + +inline BOOST_CONSTEXPR bool is_symlink(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::symlink_file; +} + +inline BOOST_CONSTEXPR bool is_block_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::block_file; +} + +inline BOOST_CONSTEXPR bool is_character_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::character_file; +} + +inline BOOST_CONSTEXPR bool is_fifo(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::fifo_file; +} + +inline BOOST_CONSTEXPR bool is_socket(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::socket_file; +} + +inline BOOST_CONSTEXPR bool is_reparse_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::reparse_file; +} + +inline BOOST_CONSTEXPR bool is_other(file_status f) BOOST_NOEXCEPT +{ + return filesystem::exists(f) && !filesystem::is_regular_file(f) && !filesystem::is_directory(f) && !filesystem::is_symlink(f); +} + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") +inline bool is_regular(file_status f) BOOST_NOEXCEPT +{ + return filesystem::is_regular_file(f); +} +#endif + +} // namespace filesystem +} // namespace boost + +#include // pops abi_prefix.hpp pragmas + +#endif // BOOST_FILESYSTEM_FILE_STATUS_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/fstream.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/fstream.hpp new file mode 100644 index 0000000..3343651 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/fstream.hpp @@ -0,0 +1,269 @@ +// boost/filesystem/fstream.hpp ------------------------------------------------------// + +// Copyright Beman Dawes 2002 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_FSTREAM_HPP +#define BOOST_FILESYSTEM_FSTREAM_HPP + +#include +#include +#include +#include +#include + +#include // must be the last #include + +#if defined(BOOST_WINDOWS_API) +// On Windows, except for standard libaries known to have wchar_t overloads for +// file stream I/O, use path::string() to get a narrow character c_str() +#if (defined(_CPPLIB_VER) && _CPPLIB_VER >= 405 && !defined(_STLPORT_VERSION)) || \ + (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 7000 && defined(_LIBCPP_HAS_OPEN_WITH_WCHAR)) +// Use wide characters directly +// Note: We don't use C++17 std::filesystem::path as a means to pass wide paths +// to file streams because of various problems: +// - std::filesystem is available in gcc 8 but it is broken there (fails to compile path definition +// on Windows). Compilation errors seem to be fixed since gcc 9. +// - In gcc 10.2 and clang 8.0.1 on Cygwin64, the path attempts to convert the wide string to narrow +// and fails in runtime. This may be system locale dependent, and performing character code conversion +// is against the purpose of using std::filesystem::path anyway. +// - Other std::filesystem implementations were not tested, so it is not known if they actually work +// with wide paths. +#define BOOST_FILESYSTEM_C_STR(p) p.c_str() +#else +// Use narrow characters, since wide not available +#define BOOST_FILESYSTEM_C_STR(p) p.string().c_str() +#endif +#endif // defined(BOOST_WINDOWS_API) + +#if !defined(BOOST_FILESYSTEM_C_STR) +#define BOOST_FILESYSTEM_C_STR(p) p.c_str() +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// 'boost::filesystem::basic_fstream' : inherits 'std::basic_istream<_Elem,_Traits>::std::basic_istream<_Elem,_Traits>::_Add_vtordisp1' via dominance +#pragma warning(disable : 4250) +#endif + +namespace boost { +namespace filesystem { + +//--------------------------------------------------------------------------------------// +// basic_filebuf // +//--------------------------------------------------------------------------------------// + +template< class Char, class Traits = std::char_traits< Char > > +class basic_filebuf : + public std::basic_filebuf< Char, Traits > +{ +private: + typedef std::basic_filebuf< Char, Traits > base_type; + +public: + BOOST_DEFAULTED_FUNCTION(basic_filebuf(), {}) + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) +#if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES) + basic_filebuf(basic_filebuf&&) = default; + basic_filebuf& operator= (basic_filebuf&&) = default; +#else + basic_filebuf(basic_filebuf&& that) : + base_type(static_cast< base_type&& >(that)) {} + + basic_filebuf& operator= (basic_filebuf&& that) + { + *static_cast< base_type* >(this) = static_cast< base_type&& >(that); + return *this; + } +#endif +#endif // !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) + + BOOST_DELETED_FUNCTION(basic_filebuf(basic_filebuf const&)) + BOOST_DELETED_FUNCTION(basic_filebuf const& operator= (basic_filebuf const&)) + +public: + basic_filebuf* open(path const& p, std::ios_base::openmode mode) + { + return base_type::open(BOOST_FILESYSTEM_C_STR(p), mode) ? this : NULL; + } +}; + +//--------------------------------------------------------------------------------------// +// basic_ifstream // +//--------------------------------------------------------------------------------------// + +template< class Char, class Traits = std::char_traits< Char > > +class basic_ifstream : + public std::basic_ifstream< Char, Traits > +{ +private: + typedef std::basic_ifstream< Char, Traits > base_type; + +public: + BOOST_DEFAULTED_FUNCTION(basic_ifstream(), {}) + + // use two signatures, rather than one signature with default second + // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416) + + explicit basic_ifstream(path const& p) : + base_type(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in) {} + + basic_ifstream(path const& p, std::ios_base::openmode mode) : + base_type(BOOST_FILESYSTEM_C_STR(p), mode) {} + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) + basic_ifstream(basic_ifstream&& that) : + base_type(static_cast< base_type&& >(that)) {} + + basic_ifstream& operator= (basic_ifstream&& that) + { + *static_cast< base_type* >(this) = static_cast< base_type&& >(that); + return *this; + } +#endif + + BOOST_DELETED_FUNCTION(basic_ifstream(basic_ifstream const&)) + BOOST_DELETED_FUNCTION(basic_ifstream const& operator= (basic_ifstream const&)) + +public: + void open(path const& p) + { + base_type::open(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in); + } + + void open(path const& p, std::ios_base::openmode mode) + { + base_type::open(BOOST_FILESYSTEM_C_STR(p), mode); + } +}; + +//--------------------------------------------------------------------------------------// +// basic_ofstream // +//--------------------------------------------------------------------------------------// + +template< class Char, class Traits = std::char_traits< Char > > +class basic_ofstream : + public std::basic_ofstream< Char, Traits > +{ +private: + typedef std::basic_ofstream< Char, Traits > base_type; + +public: + BOOST_DEFAULTED_FUNCTION(basic_ofstream(), {}) + + // use two signatures, rather than one signature with default second + // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416) + + explicit basic_ofstream(path const& p) : + base_type(BOOST_FILESYSTEM_C_STR(p), std::ios_base::out) {} + + basic_ofstream(path const& p, std::ios_base::openmode mode) : + base_type(BOOST_FILESYSTEM_C_STR(p), mode) {} + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) + basic_ofstream(basic_ofstream&& that) : + base_type(static_cast< base_type&& >(that)) {} + + basic_ofstream& operator= (basic_ofstream&& that) + { + *static_cast< base_type* >(this) = static_cast< base_type&& >(that); + return *this; + } +#endif + + BOOST_DELETED_FUNCTION(basic_ofstream(basic_ofstream const&)) + BOOST_DELETED_FUNCTION(basic_ofstream const& operator= (basic_ofstream const&)) + +public: + void open(path const& p) + { + base_type::open(BOOST_FILESYSTEM_C_STR(p), std::ios_base::out); + } + + void open(path const& p, std::ios_base::openmode mode) + { + base_type::open(BOOST_FILESYSTEM_C_STR(p), mode); + } +}; + +//--------------------------------------------------------------------------------------// +// basic_fstream // +//--------------------------------------------------------------------------------------// + +template< class Char, class Traits = std::char_traits< Char > > +class basic_fstream : + public std::basic_fstream< Char, Traits > +{ +private: + typedef std::basic_fstream< Char, Traits > base_type; + +public: + BOOST_DEFAULTED_FUNCTION(basic_fstream(), {}) + + // use two signatures, rather than one signature with default second + // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416) + + explicit basic_fstream(path const& p) : + base_type(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in | std::ios_base::out) {} + + basic_fstream(path const& p, std::ios_base::openmode mode) : + base_type(BOOST_FILESYSTEM_C_STR(p), mode) {} + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) + basic_fstream(basic_fstream&& that) : + base_type(static_cast< base_type&& >(that)) {} + + basic_fstream& operator= (basic_fstream&& that) + { + *static_cast< base_type* >(this) = static_cast< base_type&& >(that); + return *this; + } +#endif + + BOOST_DELETED_FUNCTION(basic_fstream(basic_fstream const&)) + BOOST_DELETED_FUNCTION(basic_fstream const& operator= (basic_fstream const&)) + +public: + void open(path const& p) + { + base_type::open(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in | std::ios_base::out); + } + + void open(path const& p, std::ios_base::openmode mode) + { + base_type::open(BOOST_FILESYSTEM_C_STR(p), mode); + } +}; + +//--------------------------------------------------------------------------------------// +// typedefs // +//--------------------------------------------------------------------------------------// + +typedef basic_filebuf< char > filebuf; +typedef basic_ifstream< char > ifstream; +typedef basic_ofstream< char > ofstream; +typedef basic_fstream< char > fstream; + +typedef basic_filebuf< wchar_t > wfilebuf; +typedef basic_ifstream< wchar_t > wifstream; +typedef basic_ofstream< wchar_t > wofstream; +typedef basic_fstream< wchar_t > wfstream; + +} // namespace filesystem +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#include + +#endif // BOOST_FILESYSTEM_FSTREAM_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/operations.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/operations.hpp new file mode 100644 index 0000000..0b7f736 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/operations.hpp @@ -0,0 +1,779 @@ +// boost/filesystem/operations.hpp ---------------------------------------------------// + +// Copyright Beman Dawes 2002-2009 +// Copyright Jan Langer 2002 +// Copyright Dietmar Kuehl 2001 +// Copyright Vladimir Prus 2002 +// Copyright Andrey Semashev 2020-2021 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_OPERATIONS_HPP +#define BOOST_FILESYSTEM_OPERATIONS_HPP + +#include +#include +#include + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +// These includes are left for backward compatibility and should be included directly by users, as needed +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include // must be the last #include + +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +struct space_info +{ + // all values are byte counts + boost::uintmax_t capacity; + boost::uintmax_t free; // <= capacity + boost::uintmax_t available; // <= free +}; + +BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(copy_options, unsigned int) +{ + none = 0u, // Default. For copy_file: error if the target file exists. For copy: do not recurse, follow symlinks, copy file contents. + + // copy_file options: + skip_existing = 1u, // Don't overwrite the existing target file, don't report an error + overwrite_existing = 1u << 1, // Overwrite existing file + update_existing = 1u << 2, // Overwrite existing file if its last write time is older than the replacement file + synchronize_data = 1u << 3, // Flush all buffered data written to the target file to permanent storage + synchronize = 1u << 4, // Flush all buffered data and attributes written to the target file to permanent storage + + // copy options: + recursive = 1u << 8, // Recurse into sub-directories + copy_symlinks = 1u << 9, // Copy symlinks as symlinks instead of copying the referenced file + skip_symlinks = 1u << 10, // Don't copy symlinks + directories_only = 1u << 11, // Only copy directory structure, do not copy non-directory files + create_symlinks = 1u << 12, // Create symlinks instead of copying files + create_hard_links = 1u << 13, // Create hard links instead of copying files + _detail_recursing = 1u << 14 // Internal use only, do not use +} +BOOST_SCOPED_ENUM_DECLARE_END(copy_options) + +BOOST_BITMASK(BOOST_SCOPED_ENUM_NATIVE(copy_options)) + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_SCOPED_ENUM_DECLARE_BEGIN(copy_option) +{ + none = static_cast< unsigned int >(copy_options::none), + fail_if_exists = none, + overwrite_if_exists = static_cast< unsigned int >(copy_options::overwrite_existing) +} +BOOST_SCOPED_ENUM_DECLARE_END(copy_option) +#endif + +//--------------------------------------------------------------------------------------// +// implementation details // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_FILESYSTEM_DECL +path absolute(path const& p, path const& base, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +file_status status(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +file_status symlink_status(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +bool is_empty(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path initial_path(system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path canonical(path const& p, path const& base, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void copy(path const& from, path const& to, unsigned int options, system::error_code* ec = NULL); +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DECL +void copy_directory(path const& from, path const& to, system::error_code* ec = NULL); +#endif +BOOST_FILESYSTEM_DECL +bool copy_file(path const& from, path const& to, // See ticket #2925 + unsigned int options, system::error_code* ec = NULL); // see copy_options for options +BOOST_FILESYSTEM_DECL +void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +bool create_directories(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +bool create_directory(path const& p, const path* existing, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void create_directory_symlink(path const& to, path const& from, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void create_hard_link(path const& to, path const& from, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void create_symlink(path const& to, path const& from, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path current_path(system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void current_path(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +bool equivalent(path const& p1, path const& p2, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +boost::uintmax_t file_size(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +boost::uintmax_t hard_link_count(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +std::time_t creation_time(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +std::time_t last_write_time(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void permissions(path const& p, perms prms, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path read_symlink(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path relative(path const& p, path const& base, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +bool remove(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +boost::uintmax_t remove_all(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void rename(path const& old_p, path const& new_p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +void resize_file(path const& p, uintmax_t size, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +space_info space(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path system_complete(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path temp_directory_path(system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path unique_path(path const& p, system::error_code* ec = NULL); +BOOST_FILESYSTEM_DECL +path weakly_canonical(path const& p, path const& base, system::error_code* ec = NULL); + +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// status query functions // +// // +//--------------------------------------------------------------------------------------// + +inline file_status status(path const& p) +{ + return detail::status(p); +} + +inline file_status status(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::status(p, &ec); +} + +inline file_status symlink_status(path const& p) +{ + return detail::symlink_status(p); +} + +inline file_status symlink_status(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::symlink_status(p, &ec); +} + +inline bool exists(path const& p) +{ + return filesystem::exists(detail::status(p)); +} + +inline bool exists(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::exists(detail::status(p, &ec)); +} + +inline bool is_regular_file(path const& p) +{ + return filesystem::is_regular_file(detail::status(p)); +} + +inline bool is_regular_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_regular_file(detail::status(p, &ec)); +} + +inline bool is_directory(path const& p) +{ + return filesystem::is_directory(detail::status(p)); +} + +inline bool is_directory(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_directory(detail::status(p, &ec)); +} + +inline bool is_symlink(path const& p) +{ + return filesystem::is_symlink(detail::symlink_status(p)); +} + +inline bool is_symlink(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_symlink(detail::symlink_status(p, &ec)); +} + +inline bool is_block_file(path const& p) +{ + return filesystem::is_block_file(detail::status(p)); +} + +inline bool is_block_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_block_file(detail::status(p, &ec)); +} + +inline bool is_character_file(path const& p) +{ + return filesystem::is_character_file(detail::status(p)); +} + +inline bool is_character_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_character_file(detail::status(p, &ec)); +} + +inline bool is_fifo(path const& p) +{ + return filesystem::is_fifo(detail::status(p)); +} + +inline bool is_fifo(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_fifo(detail::status(p, &ec)); +} + +inline bool is_socket(path const& p) +{ + return filesystem::is_socket(detail::status(p)); +} + +inline bool is_socket(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_socket(detail::status(p, &ec)); +} + +inline bool is_reparse_file(path const& p) +{ + return filesystem::is_reparse_file(detail::symlink_status(p)); +} + +inline bool is_reparse_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_reparse_file(detail::symlink_status(p, &ec)); +} + +inline bool is_other(path const& p) +{ + return filesystem::is_other(detail::status(p)); +} + +inline bool is_other(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_other(detail::status(p, &ec)); +} + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") +inline bool is_regular(path const& p) +{ + return filesystem::is_regular_file(p); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") +inline bool is_regular(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_regular_file(p, ec); +} +#endif + +inline bool is_empty(path const& p) +{ + return detail::is_empty(p); +} + +inline bool is_empty(path const& p, system::error_code& ec) +{ + return detail::is_empty(p, &ec); +} + +//--------------------------------------------------------------------------------------// +// // +// operational functions // +// // +//--------------------------------------------------------------------------------------// + +inline path initial_path() +{ + return detail::initial_path(); +} + +inline path initial_path(system::error_code& ec) +{ + return detail::initial_path(&ec); +} + +template< class Path > +path initial_path() +{ + return initial_path(); +} +template< class Path > +path initial_path(system::error_code& ec) +{ + return detail::initial_path(&ec); +} + +inline path current_path() +{ + return detail::current_path(); +} + +inline path current_path(system::error_code& ec) +{ + return detail::current_path(&ec); +} + +inline void current_path(path const& p) +{ + detail::current_path(p); +} + +inline void current_path(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::current_path(p, &ec); +} + +inline path absolute(path const& p, path const& base = current_path()) +{ + return detail::absolute(p, base); +} + +inline path absolute(path const& p, system::error_code& ec) +{ + path base = current_path(ec); + if (ec) + return path(); + return detail::absolute(p, base, &ec); +} + +inline path absolute(path const& p, path const& base, system::error_code& ec) +{ + return detail::absolute(p, base, &ec); +} + +inline path canonical(path const& p, path const& base = current_path()) +{ + return detail::canonical(p, base); +} + +inline path canonical(path const& p, system::error_code& ec) +{ + path base = current_path(ec); + if (ec) + return path(); + return detail::canonical(p, base, &ec); +} + +inline path canonical(path const& p, path const& base, system::error_code& ec) +{ + return detail::canonical(p, base, &ec); +} + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use absolute() instead") +inline path complete(path const& p) +{ + return absolute(p, initial_path()); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use absolute() instead") +inline path complete(path const& p, path const& base) +{ + return absolute(p, base); +} +#endif + +inline void copy(path const& from, path const& to) +{ + detail::copy(from, to, static_cast< unsigned int >(copy_options::none)); +} + +inline void copy(path const& from, path const& to, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::copy(from, to, static_cast< unsigned int >(copy_options::none), &ec); +} + +inline void copy(path const& from, path const& to, BOOST_SCOPED_ENUM_NATIVE(copy_options) options) +{ + detail::copy(from, to, static_cast< unsigned int >(options)); +} + +inline void copy(path const& from, path const& to, BOOST_SCOPED_ENUM_NATIVE(copy_options) options, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::copy(from, to, static_cast< unsigned int >(options), &ec); +} + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use create_directory() instead") +inline void copy_directory(path const& from, path const& to) +{ + detail::copy_directory(from, to); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use create_directory() instead") +inline void copy_directory(path const& from, path const& to, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::copy_directory(from, to, &ec); +} +#endif + +inline bool copy_file(path const& from, path const& to) +{ + return detail::copy_file(from, to, static_cast< unsigned int >(copy_options::none)); +} + +inline bool copy_file(path const& from, path const& to, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::copy_file(from, to, static_cast< unsigned int >(copy_options::none), &ec); +} + +inline bool copy_file(path const& from, path const& to, // See ticket #2925 + BOOST_SCOPED_ENUM_NATIVE(copy_options) options) +{ + return detail::copy_file(from, to, static_cast< unsigned int >(options)); +} + +inline bool copy_file(path const& from, path const& to, // See ticket #2925 + BOOST_SCOPED_ENUM_NATIVE(copy_options) options, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::copy_file(from, to, static_cast< unsigned int >(options), &ec); +} + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use copy_options instead of copy_option") +inline bool copy_file(path const& from, path const& to, // See ticket #2925 + BOOST_SCOPED_ENUM_NATIVE(copy_option) options) +{ + return detail::copy_file(from, to, static_cast< unsigned int >(options)); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use copy_options instead of copy_option") +inline bool copy_file(path const& from, path const& to, // See ticket #2925 + BOOST_SCOPED_ENUM_NATIVE(copy_option) options, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::copy_file(from, to, static_cast< unsigned int >(options), &ec); +} +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +inline void copy_symlink(path const& existing_symlink, path const& new_symlink) +{ + detail::copy_symlink(existing_symlink, new_symlink); +} + +inline void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::copy_symlink(existing_symlink, new_symlink, &ec); +} + +inline bool create_directories(path const& p) +{ + return detail::create_directories(p); +} + +inline bool create_directories(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::create_directories(p, &ec); +} + +inline bool create_directory(path const& p) +{ + return detail::create_directory(p, NULL); +} + +inline bool create_directory(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::create_directory(p, NULL, &ec); +} + +inline bool create_directory(path const& p, path const& existing) +{ + return detail::create_directory(p, &existing); +} + +inline bool create_directory(path const& p, path const& existing, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::create_directory(p, &existing, &ec); +} + +inline void create_directory_symlink(path const& to, path const& from) +{ + detail::create_directory_symlink(to, from); +} + +inline void create_directory_symlink(path const& to, path const& from, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::create_directory_symlink(to, from, &ec); +} + +inline void create_hard_link(path const& to, path const& new_hard_link) +{ + detail::create_hard_link(to, new_hard_link); +} + +inline void create_hard_link(path const& to, path const& new_hard_link, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::create_hard_link(to, new_hard_link, &ec); +} + +inline void create_symlink(path const& to, path const& new_symlink) +{ + detail::create_symlink(to, new_symlink); +} + +inline void create_symlink(path const& to, path const& new_symlink, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::create_symlink(to, new_symlink, &ec); +} + +inline bool equivalent(path const& p1, path const& p2) +{ + return detail::equivalent(p1, p2); +} + +inline bool equivalent(path const& p1, path const& p2, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::equivalent(p1, p2, &ec); +} + +inline boost::uintmax_t file_size(path const& p) +{ + return detail::file_size(p); +} + +inline boost::uintmax_t file_size(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::file_size(p, &ec); +} + +inline boost::uintmax_t hard_link_count(path const& p) +{ + return detail::hard_link_count(p); +} + +inline boost::uintmax_t hard_link_count(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::hard_link_count(p, &ec); +} + +inline std::time_t creation_time(path const& p) +{ + return detail::creation_time(p); +} + +inline std::time_t creation_time(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::creation_time(p, &ec); +} + +inline std::time_t last_write_time(path const& p) +{ + return detail::last_write_time(p); +} + +inline std::time_t last_write_time(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::last_write_time(p, &ec); +} + +inline void last_write_time(path const& p, const std::time_t new_time) +{ + detail::last_write_time(p, new_time); +} + +inline void last_write_time(path const& p, const std::time_t new_time, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::last_write_time(p, new_time, &ec); +} + +inline void permissions(path const& p, perms prms) +{ + detail::permissions(p, prms); +} + +inline void permissions(path const& p, perms prms, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::permissions(p, prms, &ec); +} + +inline path read_symlink(path const& p) +{ + return detail::read_symlink(p); +} + +inline path read_symlink(path const& p, system::error_code& ec) +{ + return detail::read_symlink(p, &ec); +} + +inline bool remove(path const& p) +{ + return detail::remove(p); +} + +inline bool remove(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::remove(p, &ec); +} + +inline boost::uintmax_t remove_all(path const& p) +{ + return detail::remove_all(p); +} + +inline boost::uintmax_t remove_all(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::remove_all(p, &ec); +} + +inline void rename(path const& old_p, path const& new_p) +{ + detail::rename(old_p, new_p); +} + +inline void rename(path const& old_p, path const& new_p, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::rename(old_p, new_p, &ec); +} + +// name suggested by Scott McMurray +inline void resize_file(path const& p, uintmax_t size) +{ + detail::resize_file(p, size); +} + +inline void resize_file(path const& p, uintmax_t size, system::error_code& ec) BOOST_NOEXCEPT +{ + detail::resize_file(p, size, &ec); +} + +inline path relative(path const& p, path const& base = current_path()) +{ + return detail::relative(p, base); +} + +inline path relative(path const& p, system::error_code& ec) +{ + path base = current_path(ec); + if (ec) + return path(); + return detail::relative(p, base, &ec); +} + +inline path relative(path const& p, path const& base, system::error_code& ec) +{ + return detail::relative(p, base, &ec); +} + +inline space_info space(path const& p) +{ + return detail::space(p); +} + +inline space_info space(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return detail::space(p, &ec); +} + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_symlink(symlink_status(path)) instead") +inline bool symbolic_link_exists(path const& p) +{ + return is_symlink(filesystem::symlink_status(p)); +} +#endif + +inline path system_complete(path const& p) +{ + return detail::system_complete(p); +} + +inline path system_complete(path const& p, system::error_code& ec) +{ + return detail::system_complete(p, &ec); +} + +inline path temp_directory_path() +{ + return detail::temp_directory_path(); +} + +inline path temp_directory_path(system::error_code& ec) +{ + return detail::temp_directory_path(&ec); +} + +inline path unique_path(path const& p = "%%%%-%%%%-%%%%-%%%%") +{ + return detail::unique_path(p); +} + +inline path unique_path(path const& p, system::error_code& ec) +{ + return detail::unique_path(p, &ec); +} + +inline path weakly_canonical(path const& p, path const& base = current_path()) +{ + return detail::weakly_canonical(p, base); +} + +inline path weakly_canonical(path const& p, system::error_code& ec) +{ + path base = current_path(ec); + if (ec) + return path(); + return detail::weakly_canonical(p, base, &ec); +} + +inline path weakly_canonical(path const& p, path const& base, system::error_code& ec) +{ + return detail::weakly_canonical(p, base, &ec); +} + +// test helper -----------------------------------------------------------------------// + +// Not part of the documented interface since false positives are possible; +// there is no law that says that an OS that has large stat.st_size +// actually supports large file sizes. + +namespace detail { + +BOOST_FILESYSTEM_DECL bool possible_large_file_size_support(); + +} // namespace detail + +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_OPERATIONS_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/path.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/path.hpp new file mode 100644 index 0000000..729e188 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/path.hpp @@ -0,0 +1,1836 @@ +// filesystem path.hpp ---------------------------------------------------------------// + +// Copyright Vladimir Prus 2002 +// Copyright Beman Dawes 2002-2005, 2009 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// path::stem(), extension(), and replace_extension() are based on +// basename(), extension(), and change_extension() from the original +// filesystem/convenience.hpp header by Vladimir Prus. + +#ifndef BOOST_FILESYSTEM_PATH_HPP +#define BOOST_FILESYSTEM_PATH_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +class path; + +namespace path_detail { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants + +template< typename Char, Char Separator, Char PreferredSeparator, Char Dot > +struct path_constants +{ + typedef path_constants< Char, Separator, PreferredSeparator, Dot > path_constants_base; + typedef Char value_type; + static BOOST_CONSTEXPR_OR_CONST value_type separator = Separator; + static BOOST_CONSTEXPR_OR_CONST value_type preferred_separator = PreferredSeparator; + static BOOST_CONSTEXPR_OR_CONST value_type dot = Dot; +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) +template< typename Char, Char Separator, Char PreferredSeparator, Char Dot > +BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSeparator, Dot >::value_type +path_constants< Char, Separator, PreferredSeparator, Dot >::separator; +template< typename Char, Char Separator, Char PreferredSeparator, Char Dot > +BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSeparator, Dot >::value_type +path_constants< Char, Separator, PreferredSeparator, Dot >::preferred_separator; +template< typename Char, Char Separator, Char PreferredSeparator, Char Dot > +BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSeparator, Dot >::value_type +path_constants< Char, Separator, PreferredSeparator, Dot >::dot; +#endif + +class path_iterator; +class path_reverse_iterator; + +} // namespace path_detail + +namespace detail { + +struct path_algorithms +{ + // A struct that denotes a contiguous range of characters in a string. A lightweight alternative to string_view. + struct substring + { + std::size_t pos; + std::size_t size; + }; + + typedef path_traits::path_native_char_type value_type; + typedef std::basic_string< value_type > string_type; + + static bool has_filename_v3(path const& p); + static bool has_filename_v4(path const& p); + BOOST_FILESYSTEM_DECL static path filename_v3(path const& p); + static path filename_v4(path const& p); + + BOOST_FILESYSTEM_DECL static path stem_v3(path const& p); + BOOST_FILESYSTEM_DECL static path stem_v4(path const& p); + BOOST_FILESYSTEM_DECL static path extension_v3(path const& p); + static path extension_v4(path const& p); + + BOOST_FILESYSTEM_DECL static void remove_filename_v3(path& p); + BOOST_FILESYSTEM_DECL static void remove_filename_v4(path& p); + + BOOST_FILESYSTEM_DECL static void replace_extension_v3(path& p, path const& new_extension); + BOOST_FILESYSTEM_DECL static void replace_extension_v4(path& p, path const& new_extension); + + BOOST_FILESYSTEM_DECL static path lexically_normal_v3(path const& p); + BOOST_FILESYSTEM_DECL static path lexically_normal_v4(path const& p); + + BOOST_FILESYSTEM_DECL static int compare_v3(path const& left, path const& right); + BOOST_FILESYSTEM_DECL static int compare_v4(path const& left, path const& right); + + BOOST_FILESYSTEM_DECL static void append_v3(path& p, const value_type* b, const value_type* e); + BOOST_FILESYSTEM_DECL static void append_v4(path& p, const value_type* b, const value_type* e); + static void append_v4(path& left, path const& right); + + // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0. + // Note: An append is never performed if size()==0, so a returned 0 is unambiguous. + BOOST_FILESYSTEM_DECL static string_type::size_type append_separator_if_needed(path& p); + BOOST_FILESYSTEM_DECL static void erase_redundant_separator(path& p, string_type::size_type sep_pos); + + BOOST_FILESYSTEM_DECL static string_type::size_type find_root_name_size(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_root_path_size(path const& p); + BOOST_FILESYSTEM_DECL static substring find_root_directory(path const& p); + BOOST_FILESYSTEM_DECL static substring find_relative_path(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_parent_path_size(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_filename_v4_size(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_extension_v4_size(path const& p); + + BOOST_FILESYSTEM_DECL static int lex_compare_v3 + ( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 + ); + BOOST_FILESYSTEM_DECL static int lex_compare_v4 + ( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 + ); + + BOOST_FILESYSTEM_DECL static void increment_v3(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void increment_v4(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void decrement_v3(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void decrement_v4(path_detail::path_iterator& it); +}; + +} // namespace detail + +//------------------------------------------------------------------------------------// +// // +// class path // +// // +//------------------------------------------------------------------------------------// + +class path : + public filesystem::path_detail::path_constants< +#ifdef BOOST_WINDOWS_API + detail::path_traits::path_native_char_type, L'/', L'\\', L'.' +#else + detail::path_traits::path_native_char_type, '/', '/', '.' +#endif + > +{ + friend class path_detail::path_iterator; + friend class path_detail::path_reverse_iterator; + friend struct detail::path_algorithms; + +public: + // value_type is the character type used by the operating system API to + // represent paths. + + typedef detail::path_algorithms::value_type value_type; + typedef detail::path_algorithms::string_type string_type; + typedef detail::path_traits::codecvt_type codecvt_type; + + // ----- character encoding conversions ----- + + // Following the principle of least astonishment, path input arguments + // passed to or obtained from the operating system via objects of + // class path behave as if they were directly passed to or + // obtained from the O/S API, unless conversion is explicitly requested. + // + // POSIX specfies that path strings are passed unchanged to and from the + // API. Note that this is different from the POSIX command line utilities, + // which convert according to a locale. + // + // Thus for POSIX, char strings do not undergo conversion. wchar_t strings + // are converted to/from char using the path locale or, if a conversion + // argument is given, using a conversion object modeled on + // std::wstring_convert. + // + // The path locale, which is global to the thread, can be changed by the + // imbue() function. It is initialized to an implementation defined locale. + // + // For Windows, wchar_t strings do not undergo conversion. char strings + // are converted using the "ANSI" or "OEM" code pages, as determined by + // the AreFileApisANSI() function, or, if a conversion argument is given, + // using a conversion object modeled on std::wstring_convert. + // + // See m_pathname comments for further important rationale. + + // TODO: rules needed for operating systems that use / or . + // differently, or format directory paths differently from file paths. + // + // ********************************************************************************** + // + // More work needed: How to handle an operating system that may have + // slash characters or dot characters in valid filenames, either because + // it doesn't follow the POSIX standard, or because it allows MBCS + // filename encodings that may contain slash or dot characters. For + // example, ISO/IEC 2022 (JIS) encoding which allows switching to + // JIS x0208-1983 encoding. A valid filename in this set of encodings is + // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU] + // ^^^^ + // Note that 0x2F is the ASCII slash character + // + // ********************************************************************************** + + // Supported source arguments: half-open iterator range, container, c-array, + // and single pointer to null terminated string. + + // All source arguments except pointers to null terminated byte strings support + // multi-byte character strings which may have embedded nulls. Embedded null + // support is required for some Asian languages on Windows. + + // "const codecvt_type& cvt=codecvt()" default arguments are not used because this + // limits the impact of locale("") initialization failures on POSIX systems to programs + // that actually depend on locale(""). It further ensures that exceptions thrown + // as a result of such failues occur after main() has started, so can be caught. + +private: + //! Assignment operation + class assign_op + { + private: + path& m_self; + + public: + typedef void result_type; + + explicit assign_op(path& self) BOOST_NOEXCEPT : m_self(self) {} + + result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const + { + m_self.m_pathname.assign(source, source_end); + } + + template< typename OtherChar > + result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const + { + m_self.m_pathname.clear(); + detail::path_traits::convert(source, source_end, m_self.m_pathname, cvt); + } + }; + + //! Concatenation operation + class concat_op + { + private: + path& m_self; + + public: + typedef void result_type; + + explicit concat_op(path& self) BOOST_NOEXCEPT : m_self(self) {} + + result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const + { + m_self.m_pathname.append(source, source_end); + } + + template< typename OtherChar > + result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const + { + detail::path_traits::convert(source, source_end, m_self.m_pathname, cvt); + } + }; + + //! Path appending operation + class append_op + { + private: + path& m_self; + + public: + typedef void result_type; + + explicit append_op(path& self) BOOST_NOEXCEPT : m_self(self) {} + + BOOST_FORCEINLINE result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const + { + m_self.append(source, source_end); + } + + template< typename OtherChar > + BOOST_FORCEINLINE result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const + { + string_type src; + detail::path_traits::convert(source, source_end, src, cvt); + m_self.append(src.data(), src.data() + src.size()); + } + }; + + //! Path comparison operation + class compare_op + { + private: + path const& m_self; + + public: + typedef int result_type; + + explicit compare_op(path const& self) BOOST_NOEXCEPT : m_self(self) {} + + result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const; + + template< typename OtherChar > + result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const; + }; + +public: + typedef path_detail::path_iterator iterator; + typedef iterator const_iterator; + typedef path_detail::path_reverse_iterator reverse_iterator; + typedef reverse_iterator const_reverse_iterator; + +public: + // ----- constructors ----- + + path() BOOST_NOEXCEPT {} + path(path const& p) : m_pathname(p.m_pathname) {} + path(path const& p, codecvt_type const&) : m_pathname(p.m_pathname) {} + + path(const value_type* s) : m_pathname(s) {} + path(const value_type* s, codecvt_type const&) : m_pathname(s) {} + path(string_type const& s) : m_pathname(s) {} + path(string_type const& s, codecvt_type const&) : m_pathname(s) {} +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + path(std::basic_string_view< value_type > const& s) : m_pathname(s) {} + path(std::basic_string_view< value_type > const& s, codecvt_type const&) : m_pathname(s) {} +#endif + +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename Source, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type + > + path(Source const& source) +#else + template< typename Source > + path(Source const& source, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type* = NULL) +#endif + { + assign(source); + } + +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename Source, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type + > + explicit path(Source const& source, codecvt_type const& cvt) +#else + template< typename Source > + explicit path(Source const& source, codecvt_type const& cvt, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type* = NULL) +#endif + { + assign(source, cvt); + } + + // As of October 2015 the interaction between noexcept and =default is so troublesome + // for VC++, GCC, and probably other compilers, that =default is not used with noexcept + // functions. GCC is not even consistent for the same release on different platforms. + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + path(path&& p) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(p.m_pathname)) + { + } + path(path&& p, codecvt_type const&) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(p.m_pathname)) + { + } + path& operator=(path&& p) BOOST_NOEXCEPT + { + m_pathname = static_cast< string_type&& >(p.m_pathname); + return *this; + } + path& assign(path&& p) BOOST_NOEXCEPT + { + m_pathname = static_cast< string_type&& >(p.m_pathname); + return *this; + } + path& assign(path&& p, codecvt_type const&) BOOST_NOEXCEPT + { + m_pathname = static_cast< string_type&& >(p.m_pathname); + return *this; + } + + path(string_type&& s) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(s)) + { + } + path(string_type&& s, codecvt_type const&) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(s)) + { + } + path& operator=(string_type&& p) BOOST_NOEXCEPT + { + m_pathname = static_cast< string_type&& >(p); + return *this; + } + path& assign(string_type&& p) BOOST_NOEXCEPT + { + m_pathname = static_cast< string_type&& >(p); + return *this; + } + path& assign(string_type&& p, codecvt_type const&) BOOST_NOEXCEPT + { + m_pathname = static_cast< string_type&& >(p); + return *this; + } +#endif + + path(const value_type* begin, const value_type* end) : m_pathname(begin, end) {} + path(const value_type* begin, const value_type* end, codecvt_type const&) : m_pathname(begin, end) {} + +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename InputIterator, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type + > + path(InputIterator begin, InputIterator end) +#else + template< typename InputIterator > + path(InputIterator begin, InputIterator end, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type* = NULL) +#endif + { + if (begin != end) + { + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source)); +#else + assign(source); +#endif + } + } + +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename InputIterator, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type + > + path(InputIterator begin, InputIterator end, codecvt_type const& cvt) +#else + template< typename InputIterator > + path(InputIterator begin, InputIterator end, codecvt_type const& cvt, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type* = NULL) +#endif + { + if (begin != end) + { + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source), cvt); +#else + assign(source, cvt); +#endif + } + } + +#if !defined(BOOST_NO_CXX11_NULLPTR) + BOOST_DELETED_FUNCTION(path(std::nullptr_t)) + BOOST_DELETED_FUNCTION(path& operator= (std::nullptr_t)) +#endif + +public: + // ----- assignments ----- + + // We need to explicitly define copy assignment as otherwise it will be implicitly defined as deleted because there is move assignment + path& operator=(path const& p); + + template< typename Source > + typename boost::enable_if_c< + boost::disjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + path& + >::type operator=(Source const& source) + { + return assign(source); + } + + path& assign(path const& p) + { + m_pathname = p.m_pathname; + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type assign(Source const& source) + { + detail::path_traits::dispatch(source, assign_op(*this)); + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + path& + >::type assign(Source const& source) + { + detail::path_traits::dispatch_convertible(source, assign_op(*this)); + return *this; + } + + path& assign(path const& p, codecvt_type const&) + { + m_pathname = p.m_pathname; + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type assign(Source const& source, codecvt_type const& cvt) + { + detail::path_traits::dispatch(source, assign_op(*this), &cvt); + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + path& + >::type assign(Source const& source, codecvt_type const& cvt) + { + detail::path_traits::dispatch_convertible(source, assign_op(*this), &cvt); + return *this; + } + + path& assign(const value_type* begin, const value_type* end) + { + m_pathname.assign(begin, end); + return *this; + } + + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type assign(InputIterator begin, InputIterator end) + { + m_pathname.clear(); + if (begin != end) + { + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source)); +#else + assign(source); +#endif + } + return *this; + } + + path& assign(const value_type* begin, const value_type* end, codecvt_type const&) + { + m_pathname.assign(begin, end); + return *this; + } + + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type assign(InputIterator begin, InputIterator end, codecvt_type const& cvt) + { + m_pathname.clear(); + if (begin != end) + { + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source), cvt); +#else + assign(source, cvt); +#endif + } + return *this; + } + + // ----- concatenation ----- + + path& operator+=(path const& p); + + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type operator+=(Source const& source) + { + return concat(source); + } + + path& operator+=(value_type c) + { + m_pathname.push_back(c); + return *this; + } + + template< typename CharT > + typename boost::enable_if_c< + detail::path_traits::is_path_char_type< CharT >::value, + path& + >::type operator+=(CharT c) + { + CharT tmp[2]; + tmp[0] = c; + tmp[1] = static_cast< CharT >(0); + concat_op(*this)(tmp, tmp + 1); + return *this; + } + + path& concat(path const& p) + { + m_pathname.append(p.m_pathname); + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type concat(Source const& source) + { + detail::path_traits::dispatch(source, concat_op(*this)); + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + path& + >::type concat(Source const& source) + { + detail::path_traits::dispatch_convertible(source, concat_op(*this)); + return *this; + } + + path& concat(path const& p, codecvt_type const&) + { + m_pathname.append(p.m_pathname); + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type concat(Source const& source, codecvt_type const& cvt) + { + detail::path_traits::dispatch(source, concat_op(*this), &cvt); + return *this; + } + + template< typename Source > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + path& + >::type concat(Source const& source, codecvt_type const& cvt) + { + detail::path_traits::dispatch_convertible(source, concat_op(*this), &cvt); + return *this; + } + + path& concat(const value_type* begin, const value_type* end) + { + m_pathname.append(begin, end); + return *this; + } + + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type concat(InputIterator begin, InputIterator end) + { + if (begin != end) + { + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, concat_op(*this)); + } + return *this; + } + + path& concat(const value_type* begin, const value_type* end, codecvt_type const&) + { + m_pathname.append(begin, end); + return *this; + } + + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type concat(InputIterator begin, InputIterator end, codecvt_type const& cvt) + { + if (begin != end) + { + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, concat_op(*this), &cvt); + } + return *this; + } + + // ----- appends ----- + + // if a separator is added, it is the preferred separator for the platform; + // slash for POSIX, backslash for Windows + + path& operator/=(path const& p); + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type operator/=(Source const& source) + { + return append(source); + } + + path& append(path const& p); + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type append(Source const& source) + { + detail::path_traits::dispatch(source, append_op(*this)); + return *this; + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + path& + >::type append(Source const& source) + { + detail::path_traits::dispatch_convertible(source, append_op(*this)); + return *this; + } + + path& append(path const& p, codecvt_type const&); + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type append(Source const& source, codecvt_type const& cvt) + { + detail::path_traits::dispatch(source, append_op(*this), &cvt); + return *this; + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + path& + >::type append(Source const& source, codecvt_type const& cvt) + { + detail::path_traits::dispatch_convertible(source, append_op(*this), &cvt); + return *this; + } + + path& append(const value_type* begin, const value_type* end); + + template< typename InputIterator > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type append(InputIterator begin, InputIterator end) + { + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, append_op(*this)); + return *this; + } + + path& append(const value_type* begin, const value_type* end, codecvt_type const&); + + template< typename InputIterator > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type append(InputIterator begin, InputIterator end, const codecvt_type& cvt) + { + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, append_op(*this), &cvt); + return *this; + } + + // ----- modifiers ----- + + void clear() BOOST_NOEXCEPT { m_pathname.clear(); } +#ifdef BOOST_POSIX_API + path& make_preferred() + { + // No effect on POSIX + return *this; + } +#else // BOOST_WINDOWS_API + BOOST_FILESYSTEM_DECL path& make_preferred(); // change slashes to backslashes +#endif + path& remove_filename(); + BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators(); + BOOST_FILESYSTEM_DECL path& remove_trailing_separator(); + BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement); + path& replace_extension(path const& new_extension = path()); + + void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); } + + // ----- observers ----- + + // For operating systems that format file paths differently than directory + // paths, return values from observers are formatted as file names unless there + // is a trailing separator, in which case returns are formatted as directory + // paths. POSIX and Windows make no such distinction. + + // Implementations are permitted to return const values or const references. + + // The string or path returned by an observer are specified as being formatted + // as "native" or "generic". + // + // For POSIX, these are all the same format; slashes and backslashes are as input and + // are not modified. + // + // For Windows, native: as input; slashes and backslashes are not modified; + // this is the format of the internally stored string. + // generic: backslashes are converted to slashes + + // ----- native format observers ----- + + string_type const& native() const BOOST_NOEXCEPT { return m_pathname; } + const value_type* c_str() const BOOST_NOEXCEPT { return m_pathname.c_str(); } + string_type::size_type size() const BOOST_NOEXCEPT { return m_pathname.size(); } + + template< typename String > + String string() const; + + template< typename String > + String string(codecvt_type const& cvt) const; + +#ifdef BOOST_WINDOWS_API + std::string string() const + { + std::string tmp; + if (!m_pathname.empty()) + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp); + return tmp; + } + std::string string(codecvt_type const& cvt) const + { + std::string tmp; + if (!m_pathname.empty()) + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt); + return tmp; + } + + // string_type is std::wstring, so there is no conversion + std::wstring const& wstring() const { return m_pathname; } + std::wstring const& wstring(codecvt_type const&) const { return m_pathname; } +#else // BOOST_POSIX_API + // string_type is std::string, so there is no conversion + std::string const& string() const { return m_pathname; } + std::string const& string(codecvt_type const&) const { return m_pathname; } + + std::wstring wstring() const + { + std::wstring tmp; + if (!m_pathname.empty()) + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp); + return tmp; + } + std::wstring wstring(codecvt_type const& cvt) const + { + std::wstring tmp; + if (!m_pathname.empty()) + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt); + return tmp; + } +#endif + + // ----- generic format observers ----- + + // Experimental generic function returning generic formatted path (i.e. separators + // are forward slashes). Motivation: simpler than a family of generic_*string + // functions. +#ifdef BOOST_WINDOWS_API + BOOST_FILESYSTEM_DECL path generic_path() const; +#else + path generic_path() const; +#endif + + template< typename String > + String generic_string() const; + + template< typename String > + String generic_string(codecvt_type const& cvt) const; + +#ifdef BOOST_WINDOWS_API + std::string generic_string() const { return generic_path().string(); } + std::string generic_string(codecvt_type const& cvt) const { return generic_path().string(cvt); } + std::wstring generic_wstring() const { return generic_path().wstring(); } + std::wstring generic_wstring(codecvt_type const&) const { return generic_wstring(); } +#else // BOOST_POSIX_API + // On POSIX-like systems, the generic format is the same as the native format + std::string const& generic_string() const { return m_pathname; } + std::string const& generic_string(codecvt_type const&) const { return m_pathname; } + std::wstring generic_wstring() const { return this->wstring(); } + std::wstring generic_wstring(codecvt_type const& cvt) const { return this->wstring(cvt); } +#endif + + // ----- compare ----- + + int compare(path const& p) const; // generic, lexicographical + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + int + >::type compare(Source const& source) const + { + return detail::path_traits::dispatch(source, compare_op(*this)); + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + int + >::type compare(Source const& source) const + { + return detail::path_traits::dispatch_convertible(source, compare_op(*this)); + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + int + >::type compare(Source const& source, codecvt_type const& cvt) const + { + return detail::path_traits::dispatch(source, compare_op(*this), &cvt); + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + int + >::type compare(Source const& source, codecvt_type const& cvt) const + { + return detail::path_traits::dispatch_convertible(source, compare_op(*this), &cvt); + } + + // ----- decomposition ----- + + path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_path_size(*this)); } + // returns 0 or 1 element path even on POSIX, root_name() is non-empty() for network paths + path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_name_size(*this)); } + + // returns 0 or 1 element path + path root_directory() const + { + detail::path_algorithms::substring root_dir = detail::path_algorithms::find_root_directory(*this); + const value_type* p = m_pathname.c_str() + root_dir.pos; + return path(p, p + root_dir.size); + } + + path relative_path() const + { + detail::path_algorithms::substring rel_path = detail::path_algorithms::find_relative_path(*this); + const value_type* p = m_pathname.c_str() + rel_path.pos; + return path(p, p + rel_path.size); + } + + path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_parent_path_size(*this)); } + + path filename() const; // returns 0 or 1 element path + path stem() const; // returns 0 or 1 element path + path extension() const; // returns 0 or 1 element path + + // ----- query ----- + + bool empty() const BOOST_NOEXCEPT { return m_pathname.empty(); } + bool filename_is_dot() const; + bool filename_is_dot_dot() const; + bool has_root_path() const { return detail::path_algorithms::find_root_path_size(*this) > 0; } + bool has_root_name() const { return detail::path_algorithms::find_root_name_size(*this) > 0; } + bool has_root_directory() const { return detail::path_algorithms::find_root_directory(*this).size > 0; } + bool has_relative_path() const { return detail::path_algorithms::find_relative_path(*this).size > 0; } + bool has_parent_path() const { return detail::path_algorithms::find_parent_path_size(*this) > 0; } + bool has_filename() const; + bool has_stem() const { return !stem().empty(); } + bool has_extension() const { return !extension().empty(); } + bool is_relative() const { return !is_absolute(); } + bool is_absolute() const + { + // Windows CE has no root name (aka drive letters) +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + return has_root_name() && has_root_directory(); +#else + return has_root_directory(); +#endif + } + + // ----- lexical operations ----- + + path lexically_normal() const; + BOOST_FILESYSTEM_DECL path lexically_relative(path const& base) const; + path lexically_proximate(path const& base) const; + + // ----- iterators ----- + + BOOST_FILESYSTEM_DECL iterator begin() const; + BOOST_FILESYSTEM_DECL iterator end() const; + reverse_iterator rbegin() const; + reverse_iterator rend() const; + + // ----- static member functions ----- + + static BOOST_FILESYSTEM_DECL std::locale imbue(std::locale const& loc); + static BOOST_FILESYSTEM_DECL codecvt_type const& codecvt(); + + // ----- deprecated functions ----- + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + // recently deprecated functions supplied by default + path& normalize(); + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::remove_filename() instead") + path& remove_leaf() { return remove_filename(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::filename() instead") + path leaf() const { return filename(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::parent_path() instead") + path branch_path() const { return parent_path(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::generic_path() instead") + path generic() const { return generic_path(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use !path::empty() instead") + bool has_leaf() const { return !m_pathname.empty(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::has_parent_path() instead") + bool has_branch_path() const { return has_parent_path(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::is_absolute() instead") + bool is_complete() const { return is_absolute(); } +#endif + +#if defined(BOOST_FILESYSTEM_DEPRECATED) + // deprecated functions with enough signature or semantic changes that they are + // not supplied by default + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") + std::string file_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") + std::string directory_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") + std::string native_file_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") + std::string native_directory_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::native() instead") + string_type external_file_string() const { return native(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::native() instead") + string_type external_directory_string() const { return native(); } +#endif + + //--------------------------------------------------------------------------------------// + // class path private members // + //--------------------------------------------------------------------------------------// +private: + /* + * m_pathname has the type, encoding, and format required by the native + * operating system. Thus for POSIX and Windows there is no conversion for + * passing m_pathname.c_str() to the O/S API or when obtaining a path from the + * O/S API. POSIX encoding is unspecified other than for dot and slash + * characters; POSIX just treats paths as a sequence of bytes. Windows + * encoding is UCS-2 or UTF-16 depending on the version. + */ + string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes, + // slashes NOT converted to backslashes +}; + +namespace detail { +BOOST_FILESYSTEM_DECL path const& dot_path(); +BOOST_FILESYSTEM_DECL path const& dot_dot_path(); +} // namespace detail + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +typedef path wpath; +#endif + +namespace path_detail { + +//------------------------------------------------------------------------------------// +// class path::iterator // +//------------------------------------------------------------------------------------// + +class path_iterator : + public boost::iterator_facade< + path_iterator, + const path, + boost::bidirectional_traversal_tag + > +{ +private: + friend class boost::iterator_core_access; + friend class boost::filesystem::path; + friend class path_reverse_iterator; + friend struct boost::filesystem::detail::path_algorithms; + + path const& dereference() const { return m_element; } + + bool equal(path_iterator const& rhs) const BOOST_NOEXCEPT + { + return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; + } + + void increment(); + void decrement(); + +private: + // current element + path m_element; + // path being iterated over + const path* m_path_ptr; + // position of m_element in m_path_ptr->m_pathname. + // if m_element is implicit dot, m_pos is the + // position of the last separator in the path. + // end() iterator is indicated by + // m_pos == m_path_ptr->m_pathname.size() + path::string_type::size_type m_pos; +}; + +//------------------------------------------------------------------------------------// +// class path::reverse_iterator // +//------------------------------------------------------------------------------------// + +class path_reverse_iterator : + public boost::iterator_facade< + path_reverse_iterator, + const path, + boost::bidirectional_traversal_tag + > +{ +public: + explicit path_reverse_iterator(path_iterator itr) : + m_itr(itr) + { + if (itr != itr.m_path_ptr->begin()) + m_element = *--itr; + } + +private: + friend class boost::iterator_core_access; + friend class boost::filesystem::path; + + path const& dereference() const { return m_element; } + bool equal(path_reverse_iterator const& rhs) const BOOST_NOEXCEPT { return m_itr == rhs.m_itr; } + + void increment() + { + --m_itr; + if (m_itr != m_itr.m_path_ptr->begin()) + { + path_iterator tmp = m_itr; + m_element = *--tmp; + } + } + + void decrement() + { + m_element = *m_itr; + ++m_itr; + } + +private: + path_iterator m_itr; + path m_element; +}; + +// std::lexicographical_compare would infinitely recurse because path iterators +// yield paths, so provide a path aware version +bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2); + +} // namespace path_detail + +using path_detail::lexicographical_compare; + +//------------------------------------------------------------------------------------// +// // +// non-member functions // +// // +//------------------------------------------------------------------------------------// + +BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs) +{ + return lhs.compare(rhs) == 0; +} + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator==(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) == 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator==(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) == 0; +} + +BOOST_FORCEINLINE bool operator!=(path const& lhs, path const& rhs) +{ + return lhs.compare(rhs) != 0; +} + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator!=(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) != 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator!=(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) != 0; +} + +BOOST_FORCEINLINE bool operator<(path const& lhs, path const& rhs) +{ + return lhs.compare(rhs) < 0; +} + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) < 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) > 0; +} + +BOOST_FORCEINLINE bool operator<=(path const& lhs, path const& rhs) +{ + return lhs.compare(rhs) <= 0; +} + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<=(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) <= 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<=(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) >= 0; +} + +BOOST_FORCEINLINE bool operator>(path const& lhs, path const& rhs) +{ + return lhs.compare(rhs) > 0; +} + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) > 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) < 0; +} + +BOOST_FORCEINLINE bool operator>=(path const& lhs, path const& rhs) +{ + return lhs.compare(rhs) >= 0; +} + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>=(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) >= 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>=(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) <= 0; +} + + +// Note: Declared as a template to delay binding to Boost.ContainerHash functions and make the dependency optional +template< typename Path > +inline typename boost::enable_if_c< + boost::is_same< Path, path >::value, + std::size_t +>::type hash_value(Path const& p) BOOST_NOEXCEPT +{ +#ifdef BOOST_WINDOWS_API + std::size_t seed = 0u; + for (typename Path::value_type const* it = p.c_str(); *it; ++it) + hash_combine(seed, *it == L'/' ? L'\\' : *it); + return seed; +#else // BOOST_POSIX_API + return hash_range(p.native().begin(), p.native().end()); +#endif +} + +inline void swap(path& lhs, path& rhs) BOOST_NOEXCEPT +{ + lhs.swap(rhs); +} + +BOOST_FORCEINLINE path operator/(path lhs, path const& rhs) +{ + lhs.append(rhs); + return lhs; +} + +template< typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value, + path +>::type operator/(path lhs, Source const& rhs) +{ + lhs.append(rhs); + return lhs; +} + +// inserters and extractors +// use boost::io::quoted() to handle spaces in paths +// use '&' as escape character to ease use for Windows paths + +template< typename Char, typename Traits > +inline std::basic_ostream< Char, Traits >& +operator<<(std::basic_ostream< Char, Traits >& os, path const& p) +{ + return os << boost::io::quoted(p.template string< std::basic_string< Char > >(), static_cast< Char >('&')); +} + +template< typename Char, typename Traits > +inline std::basic_istream< Char, Traits >& +operator>>(std::basic_istream< Char, Traits >& is, path& p) +{ + std::basic_string< Char > str; + is >> boost::io::quoted(str, static_cast< Char >('&')); + p = str; + return is; +} + +// name_checks + +// These functions are holdovers from version 1. It isn't clear they have much +// usefulness, or how to generalize them for later versions. + +BOOST_FILESYSTEM_DECL bool portable_posix_name(std::string const& name); +BOOST_FILESYSTEM_DECL bool windows_name(std::string const& name); +BOOST_FILESYSTEM_DECL bool portable_name(std::string const& name); +BOOST_FILESYSTEM_DECL bool portable_directory_name(std::string const& name); +BOOST_FILESYSTEM_DECL bool portable_file_name(std::string const& name); +BOOST_FILESYSTEM_DECL bool native(std::string const& name); + +namespace detail { + +// For POSIX, is_directory_separator() and is_element_separator() are identical since +// a forward slash is the only valid directory separator and also the only valid +// element separator. For Windows, forward slash and back slash are the possible +// directory separators, but colon (example: "c:foo") is also an element separator. +inline bool is_directory_separator(path::value_type c) BOOST_NOEXCEPT +{ + return c == path::separator +#ifdef BOOST_WINDOWS_API + || c == path::preferred_separator +#endif + ; +} + +inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT +{ + return c == path::separator +#ifdef BOOST_WINDOWS_API + || c == path::preferred_separator || c == L':' +#endif + ; +} + +} // namespace detail + +//------------------------------------------------------------------------------------// +// class path miscellaneous function implementations // +//------------------------------------------------------------------------------------// + +namespace detail { + +inline bool path_algorithms::has_filename_v3(path const& p) +{ + return !p.m_pathname.empty(); +} + +inline bool path_algorithms::has_filename_v4(path const& p) +{ + return path_algorithms::find_filename_v4_size(p) > 0; +} + +inline path path_algorithms::filename_v4(path const& p) +{ + string_type::size_type filename_size = path_algorithms::find_filename_v4_size(p); + string_type::size_type pos = p.m_pathname.size() - filename_size; + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +inline path path_algorithms::extension_v4(path const& p) +{ + string_type::size_type extension_size = path_algorithms::find_extension_v4_size(p); + string_type::size_type pos = p.m_pathname.size() - extension_size; + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + extension_size); +} + +inline void path_algorithms::append_v4(path& left, path const& right) +{ + path_algorithms::append_v4(left, right.m_pathname.c_str(), right.m_pathname.c_str() + right.m_pathname.size()); +} + +} // namespace detail + +// Note: Because of the range constructor in C++23 std::string_view that involves a check for contiguous_range concept, +// any non-template function call that requires a check whether the source argument (which may be fs::path) +// is convertible to std::string_view must be made after fs::path::iterator is defined. This includes overload +// resolution and SFINAE checks. Otherwise, the concept check result formally changes between fs::path::iterator +// is not defined and defined, which causes compilation errors with gcc 11 and later. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106808 + +BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const value_type* source, const value_type* source_end, const codecvt_type*) const +{ + path src; + src.m_pathname.assign(source, source_end); + return m_self.compare(src); +} + +template< typename OtherChar > +BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt) const +{ + path src; + detail::path_traits::convert(source, source_end, src.m_pathname, cvt); + return m_self.compare(src); +} + +inline path& path::operator=(path const& p) +{ + return assign(p); +} + +inline path& path::operator+=(path const& p) +{ + return concat(p); +} + +BOOST_FORCEINLINE path& path::operator/=(path const& p) +{ + return append(p); +} + +#if !defined(BOOST_WINDOWS_API) +inline path path::generic_path() const +{ + return path(*this); +} +#endif + +inline path path::lexically_proximate(path const& base) const +{ + path tmp(lexically_relative(base)); + return tmp.empty() ? *this : tmp; +} + +inline path::reverse_iterator path::rbegin() const +{ + return reverse_iterator(end()); +} + +inline path::reverse_iterator path::rend() const +{ + return reverse_iterator(begin()); +} + +inline bool path::filename_is_dot() const +{ + // implicit dot is tricky, so actually call filename(); see path::filename() example + // in reference.html + path p(filename()); + return p.size() == 1 && *p.c_str() == dot; +} + +inline bool path::filename_is_dot_dot() const +{ + return size() >= 2 && m_pathname[size() - 1] == dot && m_pathname[size() - 2] == dot && (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size() - 3])); + // use detail::is_element_separator() rather than detail::is_directory_separator + // to deal with "c:.." edge case on Windows when ':' acts as a separator +} + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::lexically_normal() instead") +BOOST_FORCEINLINE path& path::normalize() +{ + path tmp(lexically_normal()); + m_pathname.swap(tmp.m_pathname); + return *this; +} + +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +// The following functions are defined differently, depending on Boost.Filesystem version in use. +// To avoid ODR violation, these functions are not defined when the library itself is built. +// This makes sure they are not compiled when the library is built, and the only version there is +// is the one in user's code. Users are supposed to consistently use the same Boost.Filesystem version +// in all their translation units. +#if !defined(BOOST_FILESYSTEM_SOURCE) + +BOOST_FORCEINLINE path& path::append(path const& p) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size()); + return *this; +} + +BOOST_FORCEINLINE path& path::append(path const& p, codecvt_type const&) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size()); + return *this; +} + +BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end); + return *this; +} + +BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end, codecvt_type const&) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end); + return *this; +} + +BOOST_FORCEINLINE path& path::remove_filename() +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::remove_filename)(*this); + return *this; +} + +BOOST_FORCEINLINE path& path::replace_extension(path const& new_extension) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::replace_extension)(*this, new_extension); + return *this; +} + +BOOST_FORCEINLINE int path::compare(path const& p) const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::compare)(*this, p); +} + +BOOST_FORCEINLINE path path::filename() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::filename)(*this); +} + +BOOST_FORCEINLINE path path::stem() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::stem)(*this); +} + +BOOST_FORCEINLINE path path::extension() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::extension)(*this); +} + +BOOST_FORCEINLINE bool path::has_filename() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::has_filename)(*this); +} + +BOOST_FORCEINLINE path path::lexically_normal() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lexically_normal)(*this); +} + +namespace path_detail { + +BOOST_FORCEINLINE void path_iterator::increment() +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::increment)(*this); +} + +BOOST_FORCEINLINE void path_iterator::decrement() +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::decrement)(*this); +} + +BOOST_FORCEINLINE bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2) +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lex_compare)(first1, last1, first2, last2) < 0; +} + +} // namespace path_detail + +#endif // !defined(BOOST_FILESYSTEM_SOURCE) + +//--------------------------------------------------------------------------------------// +// class path member template specializations // +//--------------------------------------------------------------------------------------// + +template< > +inline std::string path::string< std::string >() const +{ + return string(); +} + +template< > +inline std::wstring path::string< std::wstring >() const +{ + return wstring(); +} + +template< > +inline std::string path::string< std::string >(codecvt_type const& cvt) const +{ + return string(cvt); +} + +template< > +inline std::wstring path::string< std::wstring >(codecvt_type const& cvt) const +{ + return wstring(cvt); +} + +template< > +inline std::string path::generic_string< std::string >() const +{ + return generic_string(); +} + +template< > +inline std::wstring path::generic_string< std::wstring >() const +{ + return generic_wstring(); +} + +template< > +inline std::string path::generic_string< std::string >(codecvt_type const& cvt) const +{ + return generic_string(cvt); +} + +template< > +inline std::wstring path::generic_string< std::wstring >(codecvt_type const& cvt) const +{ + return generic_wstring(cvt); +} + +} // namespace filesystem +} // namespace boost + +//----------------------------------------------------------------------------// + +#include + +#endif // BOOST_FILESYSTEM_PATH_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/path_traits.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/path_traits.hpp new file mode 100644 index 0000000..da693e6 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/path_traits.hpp @@ -0,0 +1,38 @@ +// filesystem path_traits.hpp --------------------------------------------------------// + +// Copyright Beman Dawes 2009 +// Copyright Andrey Semashev 2022 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_PATH_TRAITS_HPP +#define BOOST_FILESYSTEM_PATH_TRAITS_HPP + +#include + +#if !defined(BOOST_FILESYSTEM_DEPRECATED) && !defined(BOOST_FILESYSTEM_ALLOW_DEPRECATED) +#include +BOOST_HEADER_DEPRECATED("your own implementation") +#endif + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +#include +#include // must be the last #include + +namespace boost { +namespace filesystem { + +namespace path_traits = boost::filesystem::detail::path_traits; + +} // namespace filesystem +} // namespace boost + +#include + +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +#endif // BOOST_FILESYSTEM_PATH_TRAITS_HPP diff --git a/3rdparty/boost_filesystem/include/boost/filesystem/string_file.hpp b/3rdparty/boost_filesystem/include/boost/filesystem/string_file.hpp new file mode 100644 index 0000000..29428c8 --- /dev/null +++ b/3rdparty/boost_filesystem/include/boost/filesystem/string_file.hpp @@ -0,0 +1,70 @@ +// filesystem/string_file.hpp --------------------------------------------------------// + +// Copyright Beman Dawes 2015 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_STRING_FILE_HPP +#define BOOST_FILESYSTEM_STRING_FILE_HPP + +#include + +#if !defined(BOOST_FILESYSTEM_DEPRECATED) && !defined(BOOST_FILESYSTEM_ALLOW_DEPRECATED) +#include +BOOST_HEADER_DEPRECATED("your own implementation") +#endif + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use file IO streams instead") +inline void save_string_file(path const& p, std::string const& str) +{ + filesystem::ofstream file; + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + file.open(p, std::ios_base::binary); + const std::size_t sz = str.size(); + if (BOOST_UNLIKELY(sz > static_cast< boost::uintmax_t >((std::numeric_limits< std::streamsize >::max)()))) + BOOST_FILESYSTEM_THROW(std::length_error("String size exceeds max write size")); + file.write(str.c_str(), static_cast< std::streamsize >(sz)); +} + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use file IO streams instead") +inline void load_string_file(path const& p, std::string& str) +{ + filesystem::ifstream file; + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + file.open(p, std::ios_base::binary); + const boost::uintmax_t sz = filesystem::file_size(p); + if (BOOST_UNLIKELY(sz > static_cast< boost::uintmax_t >((std::numeric_limits< std::streamsize >::max)()))) + BOOST_FILESYSTEM_THROW(std::length_error("File size exceeds max read size")); + str.resize(static_cast< std::size_t >(sz), '\0'); + if (sz > 0u) + file.read(&str[0], static_cast< std::streamsize >(sz)); +} + +} // namespace filesystem +} // namespace boost + +#include + +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +#endif // BOOST_FILESYSTEM_STRING_FILE_HPP diff --git a/3rdparty/boost_filesystem/index.html b/3rdparty/boost_filesystem/index.html new file mode 100644 index 0000000..1803c23 --- /dev/null +++ b/3rdparty/boost_filesystem/index.html @@ -0,0 +1,13 @@ + + + + + +Automatic redirection failed, please go to +doc/index.htm. +
+

© Copyright Beman Dawes, 2003

+

Distributed under the Boost Software License, Version 1.0. +See http://www.boost.org/LICENSE_1_0.txt

+ + diff --git a/3rdparty/boost_filesystem/meta/libraries.json b/3rdparty/boost_filesystem/meta/libraries.json new file mode 100644 index 0000000..5578d3a --- /dev/null +++ b/3rdparty/boost_filesystem/meta/libraries.json @@ -0,0 +1,15 @@ +{ + "key": "filesystem", + "name": "Filesystem", + "authors": [ + "Beman Dawes" + ], + "description": "The Boost Filesystem Library provides portable facilities to query and manipulate paths, files, and directories.", + "category": [ + "System" + ], + "maintainers": [ + "Andrey Semashev " + ], + "cxxstd": "03" +} diff --git a/3rdparty/boost_filesystem/src/atomic_ref.hpp b/3rdparty/boost_filesystem/src/atomic_ref.hpp new file mode 100644 index 0000000..6e8208d --- /dev/null +++ b/3rdparty/boost_filesystem/src/atomic_ref.hpp @@ -0,0 +1,32 @@ +// atomic.hpp ------------------------------------------------------------------------// + +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_SRC_ATOMIC_REF_HPP_ +#define BOOST_FILESYSTEM_SRC_ATOMIC_REF_HPP_ + +#include + +#if !defined(BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF) + +#include + +namespace atomic_ns = std; + +#else // !defined(BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF) + +#include +#include + +namespace atomic_ns = boost; + +#endif // !defined(BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF) + +#endif // BOOST_FILESYSTEM_SRC_ATOMIC_REF_HPP_ diff --git a/3rdparty/boost_filesystem/src/atomic_tools.hpp b/3rdparty/boost_filesystem/src/atomic_tools.hpp new file mode 100644 index 0000000..a60e5d3 --- /dev/null +++ b/3rdparty/boost_filesystem/src/atomic_tools.hpp @@ -0,0 +1,69 @@ +// atomic_tools.hpp ------------------------------------------------------------------// + +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_SRC_ATOMIC_TOOLS_HPP_ +#define BOOST_FILESYSTEM_SRC_ATOMIC_TOOLS_HPP_ + +#include + +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + +#include "atomic_ref.hpp" + +namespace boost { +namespace filesystem { +namespace detail { + +//! Atomically loads the value +template< typename T > +BOOST_FORCEINLINE T atomic_load_relaxed(T& a) +{ + return atomic_ns::atomic_ref< T >(a).load(atomic_ns::memory_order_relaxed); +} + +//! Atomically stores the value +template< typename T > +BOOST_FORCEINLINE void atomic_store_relaxed(T& a, T val) +{ + atomic_ns::atomic_ref< T >(a).store(val, atomic_ns::memory_order_relaxed); +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + +namespace boost { +namespace filesystem { +namespace detail { + +//! Atomically loads the value +template< typename T > +BOOST_FORCEINLINE T atomic_load_relaxed(T const& a) +{ + return a; +} + +//! Atomically stores the value +template< typename T > +BOOST_FORCEINLINE void atomic_store_relaxed(T& a, T val) +{ + a = val; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + +#endif // BOOST_FILESYSTEM_SRC_ATOMIC_TOOLS_HPP_ diff --git a/3rdparty/boost_filesystem/src/codecvt_error_category.cpp b/3rdparty/boost_filesystem/src/codecvt_error_category.cpp new file mode 100644 index 0000000..a8d2a42 --- /dev/null +++ b/3rdparty/boost_filesystem/src/codecvt_error_category.cpp @@ -0,0 +1,120 @@ +// codecvt_error_category implementation file ----------------------------------------// + +// Copyright 2009 Beman Dawes +// Copyright 2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt) + +// Library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "private_config.hpp" + +#include // must be the last #include + +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +namespace { + +#if (defined(BOOST_GCC) && BOOST_GCC >= 40600) || defined(BOOST_CLANG) +#pragma GCC diagnostic push +// '(anonymous namespace)::codecvt_error_cat' has virtual functions but non-virtual destructor +// This is not a problem as instances of codecvt_error_cat are never destroyed through a pointer to base. +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +class codecvt_error_cat BOOST_FINAL : + public boost::system::error_category +{ +public: + // clang up to version 3.8 requires a user-defined default constructor in order to be able to declare a static constant of the error category. + BOOST_SYSTEM_CONSTEXPR codecvt_error_cat() BOOST_NOEXCEPT {} + const char* name() const BOOST_NOEXCEPT BOOST_OVERRIDE; + std::string message(int ev) const BOOST_OVERRIDE; +}; + +const char* codecvt_error_cat::name() const BOOST_NOEXCEPT +{ + return "codecvt"; +} + +std::string codecvt_error_cat::message(int ev) const +{ + std::string str; + switch (ev) + { + case std::codecvt_base::ok: + str = "ok"; + break; + case std::codecvt_base::partial: + str = "partial"; + break; + case std::codecvt_base::error: + str = "error"; + break; + case std::codecvt_base::noconv: + str = "noconv"; + break; + default: + str = "unknown error"; + break; + } + return str; +} + +#if (defined(BOOST_GCC) && BOOST_GCC >= 40600) || defined(BOOST_CLANG) +#pragma GCC diagnostic pop +#endif + +} // unnamed namespace + +BOOST_FILESYSTEM_DECL boost::system::error_category const& codecvt_error_category() BOOST_NOEXCEPT +{ + static +#if defined(BOOST_SYSTEM_HAS_CONSTEXPR) + constexpr +#else + const +#endif + codecvt_error_cat codecvt_error_cat_const; + return codecvt_error_cat_const; +} + +// Try to initialize the error category instance as early as possible to make sure it is +// available during global deinitialization stage. For MSVC, codecvt_error_category() will +// be called early by MSVC-specific initialization routine in path.cpp. +#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) && !defined(_MSC_VER) + +namespace { + +struct codecvt_error_category_initializer +{ + codecvt_error_category_initializer() { boost::filesystem::codecvt_error_category(); } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const codecvt_error_category_initializer g_codecvt_error_category_initializer; + +} // namespace + +#endif // !defined(BOOST_SYSTEM_HAS_CONSTEXPR) && !defined(_MSC_VER) + +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/directory.cpp b/3rdparty/boost_filesystem/src/directory.cpp new file mode 100644 index 0000000..f769f8f --- /dev/null +++ b/3rdparty/boost_filesystem/src/directory.cpp @@ -0,0 +1,1510 @@ +// directory.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// Copyright 2019, 2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // std::malloc, std::free +#include // std::nothrow, std::bad_alloc +#include +#include +#include // std::move +#include +#include +#include + +#ifdef BOOST_POSIX_API + +#include +#include +#include +#include +#include + +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS >= 0) && defined(_SC_THREAD_SAFE_FUNCTIONS) && \ + !defined(__CYGWIN__) && \ + !(defined(linux) || defined(__linux) || defined(__linux__)) && \ + !defined(__ANDROID__) && \ + (!defined(__hpux) || defined(_REENTRANT)) && \ + (!defined(_AIX) || defined(__THREAD_SAFE)) && \ + !defined(__wasm) +#define BOOST_FILESYSTEM_USE_READDIR_R +#endif + +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#define BOOST_FILESYSTEM_NO_O_CLOEXEC +#endif + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +#include +#include +#include // NTSTATUS_ + +#include "windows_tools.hpp" + +#endif // BOOST_WINDOWS_API + +#include "atomic_tools.hpp" +#include "error_handling.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; +using boost::system::error_code; +using boost::system::system_category; + +namespace boost { +namespace filesystem { + +//--------------------------------------------------------------------------------------// +// // +// directory_entry // +// // +//--------------------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void directory_entry::refresh_impl(system::error_code* ec) const +{ + system::error_code local_ec; + m_symlink_status = detail::symlink_status(m_path, &local_ec); + + if (!filesystem::is_symlink(m_symlink_status)) + { + // Also works if symlink_status fails - set m_status to status_error as well + m_status = m_symlink_status; + + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_entry::refresh", m_path, local_ec)); + + *ec = local_ec; + return; + } + + if (ec) + ec->clear(); + } + else + { + m_status = detail::status(m_path, ec); + } +} + +//--------------------------------------------------------------------------------------// +// // +// directory_iterator // +// // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_imp_extra_data_alignment = 16u; + +BOOST_FILESYSTEM_DECL void* dir_itr_imp::operator new(std::size_t class_size, std::size_t extra_size) BOOST_NOEXCEPT +{ + if (extra_size > 0) + class_size = (class_size + dir_itr_imp_extra_data_alignment - 1u) & ~(dir_itr_imp_extra_data_alignment - 1u); + std::size_t total_size = class_size + extra_size; + + // Return NULL on OOM + void* p = std::malloc(total_size); + if (BOOST_LIKELY(p != NULL)) + std::memset(p, 0, total_size); + return p; +} + +BOOST_FILESYSTEM_DECL void dir_itr_imp::operator delete(void* p, std::size_t extra_size) BOOST_NOEXCEPT +{ + std::free(p); +} + +BOOST_FILESYSTEM_DECL void dir_itr_imp::operator delete(void* p) BOOST_NOEXCEPT +{ + std::free(p); +} + +namespace { + +inline void* get_dir_itr_imp_extra_data(dir_itr_imp* imp) BOOST_NOEXCEPT +{ + BOOST_CONSTEXPR_OR_CONST std::size_t extra_data_offset = (sizeof(dir_itr_imp) + dir_itr_imp_extra_data_alignment - 1u) & ~(dir_itr_imp_extra_data_alignment - 1u); + return reinterpret_cast< unsigned char* >(imp) + extra_data_offset; +} + +#ifdef BOOST_POSIX_API + +inline system::error_code dir_itr_close(dir_itr_imp& imp) BOOST_NOEXCEPT +{ + if (imp.handle != NULL) + { + DIR* h = static_cast< DIR* >(imp.handle); + imp.handle = NULL; + int err = 0; + if (BOOST_UNLIKELY(::closedir(h) != 0)) + { + err = errno; + return error_code(err, system_category()); + } + } + + return error_code(); +} + +#if defined(BOOST_FILESYSTEM_USE_READDIR_R) + +// Obtains maximum length of a path, not including the terminating zero +inline std::size_t get_path_max() +{ + // this code is based on Stevens and Rago, Advanced Programming in the + // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49 + std::size_t max = 0; + errno = 0; + long res = ::pathconf("/", _PC_PATH_MAX); + if (res < 0) + { +#if defined(PATH_MAX) + max = PATH_MAX; +#else + max = 4096; +#endif + } + else + { + max = static_cast< std::size_t >(res); // relative root +#if defined(PATH_MAX) + if (max < PATH_MAX) + max = PATH_MAX; +#endif + } + + if ((max + 1) < sizeof(dirent().d_name)) + max = sizeof(dirent().d_name) - 1; + + return max; +} + +// Returns maximum length of a path, not including the terminating zero +inline std::size_t path_max() +{ + static const std::size_t max = get_path_max(); + return max; +} + +#endif // BOOST_FILESYSTEM_USE_READDIR_R + +// *result set to NULL on end of directory +#if !defined(BOOST_FILESYSTEM_USE_READDIR_R) +inline +#endif +int readdir_impl(dir_itr_imp& imp, struct dirent** result) +{ + errno = 0; + + struct dirent* p = ::readdir(static_cast< DIR* >(imp.handle)); + *result = p; + if (!p) + return errno; + return 0; +} + +#if !defined(BOOST_FILESYSTEM_USE_READDIR_R) + +inline int invoke_readdir(dir_itr_imp& imp, struct dirent** result) +{ + return readdir_impl(imp, result); +} + +#else // !defined(BOOST_FILESYSTEM_USE_READDIR_R) + +int readdir_r_impl(dir_itr_imp& imp, struct dirent** result) +{ + return ::readdir_r + ( + static_cast< DIR* >(imp.handle), + static_cast< struct dirent* >(get_dir_itr_imp_extra_data(&imp)), + result + ); +} + +int readdir_select_impl(dir_itr_imp& imp, struct dirent** result); + +typedef int readdir_impl_t(dir_itr_imp& imp, struct dirent** result); + +//! Pointer to the actual implementation of the copy_file_data implementation +readdir_impl_t* readdir_impl_ptr = &readdir_select_impl; + +void init_readdir_impl() +{ + readdir_impl_t* impl = &readdir_impl; + if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS) >= 0) + impl = &readdir_r_impl; + + filesystem::detail::atomic_store_relaxed(readdir_impl_ptr, impl); +} + +struct readdir_initializer +{ + readdir_initializer() + { + init_readdir_impl(); + } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const readdir_initializer readdir_init; + +int readdir_select_impl(dir_itr_imp& imp, struct dirent** result) +{ + init_readdir_impl(); + return filesystem::detail::atomic_load_relaxed(readdir_impl_ptr)(imp, result); +} + +inline int invoke_readdir(dir_itr_imp& imp, struct dirent** result) +{ + return filesystem::detail::atomic_load_relaxed(readdir_impl_ptr)(imp, result); +} + +#endif // !defined(BOOST_FILESYSTEM_USE_READDIR_R) + +error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf) +{ + dirent* result = NULL; + int err = invoke_readdir(imp, &result); + if (BOOST_UNLIKELY(err != 0)) + return error_code(err, system_category()); + if (result == NULL) + return dir_itr_close(imp); + + filename = result->d_name; + +#if defined(BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE) + if (result->d_type == DT_UNKNOWN) // filesystem does not supply d_type value + { + sf = symlink_sf = fs::file_status(fs::status_error); + } + else // filesystem supplies d_type value + { + if (result->d_type == DT_REG) + sf = symlink_sf = fs::file_status(fs::regular_file); + else if (result->d_type == DT_DIR) + sf = symlink_sf = fs::file_status(fs::directory_file); + else if (result->d_type == DT_LNK) + { + sf = fs::file_status(fs::status_error); + symlink_sf = fs::file_status(fs::symlink_file); + } + else + { + switch (result->d_type) + { + case DT_SOCK: + sf = symlink_sf = fs::file_status(fs::socket_file); + break; + case DT_FIFO: + sf = symlink_sf = fs::file_status(fs::fifo_file); + break; + case DT_BLK: + sf = symlink_sf = fs::file_status(fs::block_file); + break; + case DT_CHR: + sf = symlink_sf = fs::file_status(fs::character_file); + break; + default: + sf = symlink_sf = fs::file_status(fs::status_error); + break; + } + } + } +#else + sf = symlink_sf = fs::file_status(fs::status_error); +#endif + return error_code(); +} + +error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, unsigned int opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status&, fs::file_status&) +{ + std::size_t extra_size = 0u; +#if defined(BOOST_FILESYSTEM_USE_READDIR_R) + { + readdir_impl_t* rdimpl = filesystem::detail::atomic_load_relaxed(readdir_impl_ptr); + if (BOOST_UNLIKELY(rdimpl == &readdir_select_impl)) + { + init_readdir_impl(); + rdimpl = filesystem::detail::atomic_load_relaxed(readdir_impl_ptr); + } + + if (rdimpl == &readdir_r_impl) + { + // According to readdir description, there's no reliable way to predict the length of the d_name string. + // It may exceed NAME_MAX and pathconf(_PC_NAME_MAX) limits. We are being conservative here and allocate + // buffer that is enough for PATH_MAX as the directory name. Still, this doesn't guarantee there won't be + // a buffer overrun. The readdir_r API is fundamentally flawed and we should avoid it as much as possible + // in favor of readdir. + extra_size = (sizeof(dirent) - sizeof(dirent().d_name)) + path_max() + 1u; // + 1 for "\0" + } + } +#endif // defined(BOOST_FILESYSTEM_USE_READDIR_R) + + boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (extra_size) detail::dir_itr_imp()); + if (BOOST_UNLIKELY(!pimpl)) + return make_error_code(system::errc::not_enough_memory); + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + int flags = O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC; + if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u) + flags |= O_NOFOLLOW; + +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + int fd = ::openat(params ? params->basedir_fd : AT_FDCWD, dir.c_str(), flags); +#else + int fd = ::open(dir.c_str(), flags); +#endif + if (BOOST_UNLIKELY(fd < 0)) + { + const int err = errno; + return error_code(err, system_category()); + } + +#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC) + int res = ::fcntl(fd, F_SETFD, FD_CLOEXEC); + if (BOOST_UNLIKELY(res < 0)) + { + const int err = errno; + close_fd(fd); + return error_code(err, system_category()); + } +#endif + + pimpl->handle = ::fdopendir(fd); + if (BOOST_UNLIKELY(!pimpl->handle)) + { + const int err = errno; + close_fd(fd); + return error_code(err, system_category()); + } +#else // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + pimpl->handle = ::opendir(dir.c_str()); + if (BOOST_UNLIKELY(!pimpl->handle)) + { + const int err = errno; + return error_code(err, system_category()); + } +#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + + // Force initial readdir call by the caller. This will initialize the actual first filename and statuses. + first_filename.assign("."); + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + if (params) + params->iterator_fd = fd; +#endif + + imp.swap(pimpl); + return error_code(); +} + +BOOST_CONSTEXPR_OR_CONST err_t not_found_error_code = ENOENT; + +#else // BOOST_WINDOWS_API + +inline void set_file_statuses(DWORD attrs, const ULONG* reparse_point_tag, fs::path const& filename, fs::file_status& sf, fs::file_status& symlink_sf) +{ + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + // Reparse points are complex, so don't try to resolve them here; instead just mark + // them as status_error which causes directory_entry caching to call status() + // and symlink_status() which do handle reparse points fully + if (reparse_point_tag) + { + // If we have a reparse point tag we can at least populate the symlink status, + // consistent with symlink_status() behavior + symlink_sf.type(is_reparse_point_tag_a_symlink(*reparse_point_tag) ? fs::symlink_file : fs::reparse_file); + symlink_sf.permissions(make_permissions(filename, attrs)); + } + else + { + symlink_sf.type(fs::status_error); + } + + sf.type(fs::status_error); + } + else + { + if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + sf.type(fs::directory_file); + symlink_sf.type(fs::directory_file); + } + else + { + sf.type(fs::regular_file); + symlink_sf.type(fs::regular_file); + } + + sf.permissions(make_permissions(filename, attrs)); + symlink_sf.permissions(sf.permissions()); + } +} + +#if !defined(UNDER_CE) + +//! FILE_ID_128 definition from Windows SDK +struct file_id_128 +{ + BYTE Identifier[16]; +}; + +//! FILE_DIRECTORY_INFORMATION definition from Windows DDK. Used by NtQueryDirectoryFile, supported since Windows NT 4.0 (probably). +struct file_directory_information +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +}; + +//! FILE_ID_BOTH_DIR_INFO definition from Windows SDK. Basic support for directory iteration using GetFileInformationByHandleEx, supported since Windows Vista. +struct file_id_both_dir_info +{ + DWORD NextEntryOffset; + DWORD FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + DWORD FileAttributes; + DWORD FileNameLength; + DWORD EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +}; + +//! FILE_FULL_DIR_INFO definition from Windows SDK. More lightweight than FILE_ID_BOTH_DIR_INFO, supported since Windows 8. +struct file_full_dir_info +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +}; + +//! FILE_ID_EXTD_DIR_INFO definition from Windows SDK. Provides reparse point tag, which saves us querying it with a few separate syscalls. Supported since Windows 8. +struct file_id_extd_dir_info +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + file_id_128 FileId; + WCHAR FileName[1]; +}; + +//! Indicates format of the extra data in the directory iterator +enum extra_data_format +{ + file_directory_information_format, + file_id_both_dir_info_format, + file_full_dir_info_format, + file_id_extd_dir_info_format +}; + +//! Indicates extra data format that should be used by directory iterator by default +extra_data_format g_extra_data_format = file_directory_information_format; + +/*! + * \brief Extra buffer size for GetFileInformationByHandleEx-based or NtQueryDirectoryFile-based directory iterator. + * + * Must be large enough to accommodate at least one FILE_DIRECTORY_INFORMATION or *_DIR_INFO struct and one filename. + * NTFS, VFAT, exFAT and ReFS support filenames up to 255 UTF-16/UCS-2 characters. (For ReFS, there is no information + * on the on-disk format, and it is possible that it supports longer filenames, up to 32768 UTF-16/UCS-2 characters.) + * The buffer cannot be larger than 64k, because up to Windows 8.1, NtQueryDirectoryFile and GetFileInformationByHandleEx + * fail with ERROR_INVALID_PARAMETER when trying to retrieve the filenames from a network share. + */ +BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_extra_size = 65536u; + +inline system::error_code dir_itr_close(dir_itr_imp& imp) BOOST_NOEXCEPT +{ + imp.extra_data_format = 0u; + imp.current_offset = 0u; + + if (imp.handle != NULL) + { + if (BOOST_LIKELY(imp.close_handle)) + ::CloseHandle(imp.handle); + imp.handle = NULL; + } + + return error_code(); +} + +error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf) +{ + void* extra_data = get_dir_itr_imp_extra_data(&imp); + const void* current_data = static_cast< const unsigned char* >(extra_data) + imp.current_offset; + switch (imp.extra_data_format) + { + case file_id_extd_dir_info_format: + { + const file_id_extd_dir_info* data = static_cast< const file_id_extd_dir_info* >(current_data); + if (data->NextEntryOffset == 0u) + { + if (!filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api)(imp.handle, file_id_extd_directory_info_class, extra_data, dir_itr_extra_size)) + { + DWORD error = ::GetLastError(); + + dir_itr_close(imp); + if (error == ERROR_NO_MORE_FILES) + goto done; + + return error_code(error, system_category()); + } + + imp.current_offset = 0u; + data = static_cast< const file_id_extd_dir_info* >(extra_data); + } + else + { + imp.current_offset += data->NextEntryOffset; + data = reinterpret_cast< const file_id_extd_dir_info* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset); + } + + filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + set_file_statuses(data->FileAttributes, &data->ReparsePointTag, filename, sf, symlink_sf); + } + break; + + case file_full_dir_info_format: + { + const file_full_dir_info* data = static_cast< const file_full_dir_info* >(current_data); + if (data->NextEntryOffset == 0u) + { + if (!filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api)(imp.handle, file_full_directory_info_class, extra_data, dir_itr_extra_size)) + { + DWORD error = ::GetLastError(); + + dir_itr_close(imp); + if (error == ERROR_NO_MORE_FILES) + goto done; + + return error_code(error, system_category()); + } + + imp.current_offset = 0u; + data = static_cast< const file_full_dir_info* >(extra_data); + } + else + { + imp.current_offset += data->NextEntryOffset; + data = reinterpret_cast< const file_full_dir_info* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset); + } + + filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + set_file_statuses(data->FileAttributes, NULL, filename, sf, symlink_sf); + } + break; + + case file_id_both_dir_info_format: + { + const file_id_both_dir_info* data = static_cast< const file_id_both_dir_info* >(current_data); + if (data->NextEntryOffset == 0u) + { + if (!filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api)(imp.handle, file_id_both_directory_info_class, extra_data, dir_itr_extra_size)) + { + DWORD error = ::GetLastError(); + + dir_itr_close(imp); + if (error == ERROR_NO_MORE_FILES) + goto done; + + return error_code(error, system_category()); + } + + imp.current_offset = 0u; + data = static_cast< const file_id_both_dir_info* >(extra_data); + } + else + { + imp.current_offset += data->NextEntryOffset; + data = reinterpret_cast< const file_id_both_dir_info* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset); + } + + filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + set_file_statuses(data->FileAttributes, NULL, filename, sf, symlink_sf); + } + break; + + default: + { + const file_directory_information* data = static_cast< const file_directory_information* >(current_data); + if (data->NextEntryOffset == 0u) + { + io_status_block iosb; + boost::winapi::NTSTATUS_ status = filesystem::detail::atomic_load_relaxed(nt_query_directory_file_api) + ( + imp.handle, + NULL, // Event + NULL, // ApcRoutine + NULL, // ApcContext + &iosb, + extra_data, + dir_itr_extra_size, + file_directory_information_class, + FALSE, // ReturnSingleEntry + NULL, // FileName + FALSE // RestartScan + ); + + if (!NT_SUCCESS(status)) + { + dir_itr_close(imp); + if (status == STATUS_NO_MORE_FILES) + goto done; + + return error_code(translate_ntstatus(status), system_category()); + } + + imp.current_offset = 0u; + data = static_cast< const file_directory_information* >(extra_data); + } + else + { + imp.current_offset += data->NextEntryOffset; + data = reinterpret_cast< const file_directory_information* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset); + } + + filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + set_file_statuses(data->FileAttributes, NULL, filename, sf, symlink_sf); + } + break; + } + +done: + return error_code(); +} + +//! Returns \c true if the error code indicates that the OS or the filesystem does not support a particular directory info class +inline bool is_dir_info_class_not_supported(DWORD error) +{ + // Some mounted filesystems may not support FILE_ID_128 identifiers, which will cause + // GetFileInformationByHandleEx(FileIdExtdDirectoryRestartInfo) return ERROR_INVALID_PARAMETER, + // even though in general the operation is supported by the kernel. SMBv1 returns a special error + // code ERROR_INVALID_LEVEL in this case. + // Some other filesystems also don't implement other info classes and return ERROR_INVALID_PARAMETER + // (e.g. see https://github.com/boostorg/filesystem/issues/266), ERROR_GEN_FAILURE, ERROR_INVALID_FUNCTION + // or ERROR_INTERNAL_ERROR (https://github.com/boostorg/filesystem/issues/286). Treat these error codes + // as "non-permanent", even though ERROR_INVALID_PARAMETER is also returned if GetFileInformationByHandleEx + // in general does not support a certain info class. Worst case, we will make extra syscalls on directory + // iterator construction. + // Also note that Wine returns ERROR_CALL_NOT_IMPLEMENTED for unimplemented info classes, and + // up until 7.21 it didn't implement FileIdExtdDirectoryRestartInfo and FileFullDirectoryRestartInfo. + // (https://bugs.winehq.org/show_bug.cgi?id=53590) + return error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER || + error == ERROR_INVALID_LEVEL || error == ERROR_CALL_NOT_IMPLEMENTED || + error == ERROR_GEN_FAILURE || error == ERROR_INVALID_FUNCTION || + error == ERROR_INTERNAL_ERROR; +} + +error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, unsigned int opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status& sf, fs::file_status& symlink_sf) +{ + boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (dir_itr_extra_size) detail::dir_itr_imp()); + if (BOOST_UNLIKELY(!pimpl)) + return make_error_code(system::errc::not_enough_memory); + + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + + handle_wrapper h; + HANDLE iterator_handle; + bool close_handle = true; + if (params != NULL && params->use_handle != INVALID_HANDLE_VALUE) + { + // Operate on externally provided handle, which must be a directory handle + iterator_handle = params->use_handle; + close_handle = params->close_handle; + } + else + { + DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; + if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u) + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + + iterator_handle = h.handle = create_file_handle(dir, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, flags); + if (BOOST_UNLIKELY(iterator_handle == INVALID_HANDLE_VALUE)) + { + return_last_error: + DWORD error = ::GetLastError(); + return error_code(error, system_category()); + } + + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL res = get_file_information_by_handle_ex(iterator_handle, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!res)) + { + // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. See the comment in symlink_status. + DWORD error = ::GetLastError(); + if (error == ERROR_INVALID_PARAMETER || error == ERROR_NOT_SUPPORTED) + goto use_get_file_information_by_handle; + + return error_code(error, system_category()); + } + + if (BOOST_UNLIKELY((info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u)) + return make_error_code(system::errc::not_a_directory); + + if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u) + { + if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u && is_reparse_point_tag_a_symlink(info.ReparseTag)) + return make_error_code(system::errc::too_many_symbolic_link_levels); + } + } + else + { + use_get_file_information_by_handle: + BY_HANDLE_FILE_INFORMATION info; + BOOL res = ::GetFileInformationByHandle(iterator_handle, &info); + if (BOOST_UNLIKELY(!res)) + goto return_last_error; + + if (BOOST_UNLIKELY((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u)) + return make_error_code(system::errc::not_a_directory); + + if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u && (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + error_code ec; + const ULONG reparse_point_tag = detail::get_reparse_point_tag_ioctl(h.handle, dir, &ec); + if (BOOST_UNLIKELY(!!ec)) + return ec; + + if (detail::is_reparse_point_tag_a_symlink(reparse_point_tag)) + return make_error_code(system::errc::too_many_symbolic_link_levels); + } + } + } + + void* extra_data = get_dir_itr_imp_extra_data(pimpl.get()); + switch (filesystem::detail::atomic_load_relaxed(g_extra_data_format)) + { + case file_id_extd_dir_info_format: + { + if (!get_file_information_by_handle_ex(iterator_handle, file_id_extd_directory_restart_info_class, extra_data, dir_itr_extra_size)) + { + DWORD error = ::GetLastError(); + + if (is_dir_info_class_not_supported(error)) + { + // Fall back to file_full_dir_info_format. + if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED) + filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_full_dir_info_format); + goto fallback_to_file_full_dir_info_format; + } + + if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND) + goto done; + + return error_code(error, system_category()); + } + + pimpl->extra_data_format = file_id_extd_dir_info_format; + + const file_id_extd_dir_info* data = static_cast< const file_id_extd_dir_info* >(extra_data); + first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + + set_file_statuses(data->FileAttributes, &data->ReparsePointTag, first_filename, sf, symlink_sf); + } + break; + + case file_full_dir_info_format: + fallback_to_file_full_dir_info_format: + { + if (!get_file_information_by_handle_ex(iterator_handle, file_full_directory_restart_info_class, extra_data, dir_itr_extra_size)) + { + DWORD error = ::GetLastError(); + + if (is_dir_info_class_not_supported(error)) + { + // Fall back to file_id_both_dir_info + if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED) + filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_both_dir_info_format); + goto fallback_to_file_id_both_dir_info_format; + } + + if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND) + goto done; + + return error_code(error, system_category()); + } + + pimpl->extra_data_format = file_full_dir_info_format; + + const file_full_dir_info* data = static_cast< const file_full_dir_info* >(extra_data); + first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + + set_file_statuses(data->FileAttributes, NULL, first_filename, sf, symlink_sf); + } + break; + + case file_id_both_dir_info_format: + fallback_to_file_id_both_dir_info_format: + { + if (!get_file_information_by_handle_ex(iterator_handle, file_id_both_directory_restart_info_class, extra_data, dir_itr_extra_size)) + { + DWORD error = ::GetLastError(); + + if (is_dir_info_class_not_supported(error)) + { + // Fall back to file_directory_information + if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED) + filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_directory_information_format); + goto fallback_to_file_directory_information_format; + } + + if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND) + goto done; + + return error_code(error, system_category()); + } + + pimpl->extra_data_format = file_id_both_dir_info_format; + + const file_id_both_dir_info* data = static_cast< const file_id_both_dir_info* >(extra_data); + first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + + set_file_statuses(data->FileAttributes, NULL, first_filename, sf, symlink_sf); + } + break; + + default: + fallback_to_file_directory_information_format: + { + NtQueryDirectoryFile_t* nt_query_directory_file = filesystem::detail::atomic_load_relaxed(boost::filesystem::detail::nt_query_directory_file_api); + if (BOOST_UNLIKELY(!nt_query_directory_file)) + return error_code(ERROR_NOT_SUPPORTED, system_category()); + + io_status_block iosb; + boost::winapi::NTSTATUS_ status = nt_query_directory_file + ( + iterator_handle, + NULL, // Event + NULL, // ApcRoutine + NULL, // ApcContext + &iosb, + extra_data, + dir_itr_extra_size, + file_directory_information_class, + FALSE, // ReturnSingleEntry + NULL, // FileName + TRUE // RestartScan + ); + + if (!NT_SUCCESS(status)) + { + // Note: an empty root directory has no "." or ".." entries, so this + // causes a ERROR_FILE_NOT_FOUND error returned from FindFirstFileW + // (which is presumably equivalent to STATUS_NO_SUCH_FILE) which we + // do not consider an error. It is treated as eof instead. + if (status == STATUS_NO_MORE_FILES || status == STATUS_NO_SUCH_FILE) + goto done; + + return error_code(translate_ntstatus(status), system_category()); + } + + pimpl->extra_data_format = file_directory_information_format; + + const file_directory_information* data = static_cast< const file_directory_information* >(extra_data); + first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR)); + + set_file_statuses(data->FileAttributes, NULL, first_filename, sf, symlink_sf); + } + break; + } + + + pimpl->handle = iterator_handle; + h.handle = INVALID_HANDLE_VALUE; + pimpl->close_handle = close_handle; + +done: + imp.swap(pimpl); + return error_code(); +} + +#else // !defined(UNDER_CE) + +inline system::error_code dir_itr_close(dir_itr_imp& imp) BOOST_NOEXCEPT +{ + if (imp.handle != NULL) + { + if (BOOST_LIKELY(imp.close_handle)) + ::FindClose(imp.handle); + imp.handle = NULL; + } + + return error_code(); +} + +error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf) +{ + WIN32_FIND_DATAW data; + if (::FindNextFileW(imp.handle, &data) == 0) // fails + { + DWORD error = ::GetLastError(); + dir_itr_close(imp); + if (error == ERROR_NO_MORE_FILES) + goto done; + return error_code(error, system_category()); + } + + filename = data.cFileName; + set_file_statuses(data.dwFileAttributes, NULL, filename, sf, symlink_sf); + +done: + return error_code(); +} + +error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, unsigned int opts, directory_iterator_params*, fs::path& first_filename, fs::file_status& sf, fs::file_status& symlink_sf) +{ + boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (static_cast< std::size_t >(0u)) detail::dir_itr_imp()); + if (BOOST_UNLIKELY(!pimpl)) + return make_error_code(system::errc::not_enough_memory); + + // use a form of search Sebastian Martel reports will work with Win98 + fs::path dirpath(dir); + dirpath.make_preferred(); + dirpath /= L"*"; + + WIN32_FIND_DATAW data; + pimpl->handle = ::FindFirstFileW(dirpath.c_str(), &data); + if (BOOST_UNLIKELY(pimpl->handle == INVALID_HANDLE_VALUE)) + { + pimpl->handle = NULL; // signal eof + + // Note: an empty root directory has no "." or ".." entries, so this + // causes a ERROR_FILE_NOT_FOUND error which we do not consider an + // error. It is treated as eof instead. + // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551 + DWORD error = ::GetLastError(); + if (error == ERROR_FILE_NOT_FOUND || error == ERROR_NO_MORE_FILES) + goto done; + + return error_code(error, system_category()); + } + + pimpl->close_handle = true; + + first_filename = data.cFileName; + set_file_statuses(data.dwFileAttributes, NULL, first_filename, sf, symlink_sf); + +done: + imp.swap(pimpl); + return error_code(); +} + +#endif // !defined(UNDER_CE) + +BOOST_CONSTEXPR_OR_CONST err_t not_found_error_code = ERROR_PATH_NOT_FOUND; + +#endif // BOOST_WINDOWS_API + +} // namespace + +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + +//! Initializes directory iterator implementation +void init_directory_iterator_impl() BOOST_NOEXCEPT +{ + if (filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api) != NULL) + { + // Enable the latest format we support. It will get downgraded, if needed, as we attempt + // to create the directory iterator the first time. + filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_extd_dir_info_format); + } +} + +#endif // defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + +BOOST_FILESYSTEM_DECL +dir_itr_imp::~dir_itr_imp() BOOST_NOEXCEPT +{ + dir_itr_close(*this); +} + +BOOST_FILESYSTEM_DECL +void directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, directory_iterator_params* params, system::error_code* ec) +{ + if (BOOST_UNLIKELY(p.empty())) + { + emit_error(not_found_error_code, p, ec, "boost::filesystem::directory_iterator::construct"); + return; + } + + if (ec) + ec->clear(); + + try + { + boost::intrusive_ptr< detail::dir_itr_imp > imp; + path filename; + file_status file_stat, symlink_file_stat; + system::error_code result = dir_itr_create(imp, p, opts, params, filename, file_stat, symlink_file_stat); + + while (true) + { + if (result) + { + if (result != make_error_condition(system::errc::permission_denied) || + (opts & static_cast< unsigned int >(directory_options::skip_permission_denied)) == 0u) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_iterator::construct", p, result)); + *ec = result; + } + + return; + } + + if (imp->handle == NULL) // eof, make end + return; + + // Not eof + const path::string_type::value_type* filename_str = filename.c_str(); + if (!(filename_str[0] == path::dot // dot or dot-dot + && (filename_str[1] == static_cast< path::string_type::value_type >('\0') || + (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0'))))) + { + path full_path(p); + path_algorithms::append_v4(full_path, filename); + imp->dir_entry.assign_with_status + ( +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + static_cast< path&& >(full_path), +#else + full_path, +#endif + file_stat, + symlink_file_stat + ); + it.m_imp.swap(imp); + return; + } + + // If dot or dot-dot name produced by the underlying API, skip it until the first actual file + result = dir_itr_increment(*imp, filename, file_stat, symlink_file_stat); + } + } + catch (std::bad_alloc&) + { + if (!ec) + throw; + + *ec = make_error_code(system::errc::not_enough_memory); + it.m_imp.reset(); + } +} + +BOOST_FILESYSTEM_DECL +void directory_iterator_increment(directory_iterator& it, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!it.is_end(), "attempt to increment end iterator"); + + if (ec) + ec->clear(); + + try + { + path filename; + file_status file_stat, symlink_file_stat; + system::error_code increment_ec; + + while (true) + { + increment_ec = dir_itr_increment(*it.m_imp, filename, file_stat, symlink_file_stat); + + if (BOOST_UNLIKELY(!!increment_ec)) // happens if filesystem is corrupt, such as on a damaged optical disc + { + boost::intrusive_ptr< detail::dir_itr_imp > imp; + imp.swap(it.m_imp); + path error_path(imp->dir_entry.path().parent_path()); // fix ticket #5900 + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_iterator::operator++", error_path, increment_ec)); + + *ec = increment_ec; + return; + } + + if (it.m_imp->handle == NULL) // eof, make end + { + it.m_imp.reset(); + return; + } + + const path::string_type::value_type* filename_str = filename.c_str(); + if (!(filename_str[0] == path::dot // !(dot or dot-dot) + && (filename_str[1] == static_cast< path::string_type::value_type >('\0') || + (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0'))))) + { + it.m_imp->dir_entry.replace_filename_with_status(filename, file_stat, symlink_file_stat); + return; + } + } + } + catch (std::bad_alloc&) + { + if (!ec) + throw; + + it.m_imp.reset(); + *ec = make_error_code(system::errc::not_enough_memory); + } +} + +//--------------------------------------------------------------------------------------// +// // +// recursive_directory_iterator // +// // +//--------------------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL +void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, unsigned int opts, system::error_code* ec) +{ + if (ec) + ec->clear(); + + directory_iterator dir_it; + detail::directory_iterator_construct(dir_it, dir_path, opts, NULL, ec); + if ((ec && *ec) || dir_it == directory_iterator()) + return; + + boost::intrusive_ptr< detail::recur_dir_itr_imp > imp; + if (!ec) + { + imp = new detail::recur_dir_itr_imp(opts); + } + else + { + imp = new (std::nothrow) detail::recur_dir_itr_imp(opts); + if (BOOST_UNLIKELY(!imp)) + { + *ec = make_error_code(system::errc::not_enough_memory); + return; + } + } + + try + { +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + imp->m_stack.push_back(std::move(dir_it)); +#else + imp->m_stack.push_back(dir_it); +#endif + + it.m_imp.swap(imp); + } + catch (std::bad_alloc&) + { + if (ec) + { + *ec = make_error_code(system::errc::not_enough_memory); + return; + } + + throw; + } +} + +namespace { + +void recursive_directory_iterator_pop_on_error(detail::recur_dir_itr_imp* imp) +{ + imp->m_stack.pop_back(); + + while (!imp->m_stack.empty()) + { + directory_iterator& dir_it = imp->m_stack.back(); + system::error_code increment_ec; + detail::directory_iterator_increment(dir_it, &increment_ec); + if (!increment_ec && dir_it != directory_iterator()) + break; + + imp->m_stack.pop_back(); + } +} + +} // namespace + +BOOST_FILESYSTEM_DECL +void recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!it.is_end(), "pop() on end recursive_directory_iterator"); + detail::recur_dir_itr_imp* const imp = it.m_imp.get(); + + if (ec) + ec->clear(); + + imp->m_stack.pop_back(); + + while (true) + { + if (imp->m_stack.empty()) + { + it.m_imp.reset(); // done, so make end iterator + break; + } + + directory_iterator& dir_it = imp->m_stack.back(); + system::error_code increment_ec; + detail::directory_iterator_increment(dir_it, &increment_ec); + if (BOOST_UNLIKELY(!!increment_ec)) + { + if ((imp->m_options & static_cast< unsigned int >(directory_options::pop_on_error)) == 0u) + { + // Make an end iterator on errors + it.m_imp.reset(); + } + else + { + recursive_directory_iterator_pop_on_error(imp); + + if (imp->m_stack.empty()) + it.m_imp.reset(); // done, so make end iterator + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::recursive_directory_iterator::pop", increment_ec)); + + *ec = increment_ec; + return; + } + + if (dir_it != directory_iterator()) + break; + + imp->m_stack.pop_back(); + } +} + +namespace { + +enum push_directory_result +{ + directory_not_pushed = 0u, + directory_pushed = 1u, + keep_depth = 1u << 1 +}; + +// Returns: true if push occurs, otherwise false. Always returns false on error. +inline push_directory_result recursive_directory_iterator_push_directory(detail::recur_dir_itr_imp* imp, system::error_code& ec) BOOST_NOEXCEPT +{ + push_directory_result result = directory_not_pushed; + try + { + // Discover if the iterator is for a directory that needs to be recursed into, + // taking symlinks and options into account. + + if ((imp->m_options & static_cast< unsigned int >(directory_options::_detail_no_push)) != 0u) + { + imp->m_options &= ~static_cast< unsigned int >(directory_options::_detail_no_push); + return result; + } + + file_type symlink_ft = status_error; + + // If we are not recursing into symlinks, we are going to have to know if the + // stack top is a symlink, so get symlink_status and verify no error occurred. + if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) == 0u || + (imp->m_options & static_cast< unsigned int >(directory_options::skip_dangling_symlinks)) != 0u) + { + symlink_ft = imp->m_stack.back()->symlink_file_type(ec); + if (ec) + return result; + } + + // Logic for following predicate was contributed by Daniel Aarno to handle cyclic + // symlinks correctly and efficiently, fixing ticket #5652. + // if (((m_options & directory_options::follow_directory_symlink) == directory_options::follow_directory_symlink + // || !is_symlink(m_stack.back()->symlink_status())) + // && is_directory(m_stack.back()->status())) ... + // The predicate code has since been rewritten to pass error_code arguments, + // per ticket #5653. + + if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) != 0u || symlink_ft != symlink_file) + { + file_type ft = imp->m_stack.back()->file_type(ec); + if (BOOST_UNLIKELY(!!ec)) + { + if (ec == make_error_condition(system::errc::no_such_file_or_directory) && symlink_ft == symlink_file && + (imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) == static_cast< unsigned int >(directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) + { + // Skip dangling symlink and continue iteration on the current depth level + ec = error_code(); + } + + return result; + } + + if (ft != directory_file) + return result; + + if (BOOST_UNLIKELY((imp->m_stack.size() - 1u) >= static_cast< std::size_t >((std::numeric_limits< int >::max)()))) + { + // We cannot let depth to overflow + ec = make_error_code(system::errc::value_too_large); + // When depth overflow happens, avoid popping the current directory iterator + // and attempt to continue iteration on the current depth. + result = keep_depth; + return result; + } + + directory_iterator next(imp->m_stack.back()->path(), static_cast< BOOST_SCOPED_ENUM_NATIVE(directory_options) >(imp->m_options), ec); + if (!ec && next != directory_iterator()) + { +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + imp->m_stack.push_back(std::move(next)); // may throw +#else + imp->m_stack.push_back(next); // may throw +#endif + return directory_pushed; + } + } + } + catch (std::bad_alloc&) + { + ec = make_error_code(system::errc::not_enough_memory); + } + + return result; +} + +} // namespace + +BOOST_FILESYSTEM_DECL +void recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!it.is_end(), "increment() on end recursive_directory_iterator"); + detail::recur_dir_itr_imp* const imp = it.m_imp.get(); + + if (ec) + ec->clear(); + + system::error_code local_ec; + + // if various conditions are met, push a directory_iterator into the iterator stack + push_directory_result push_result = recursive_directory_iterator_push_directory(imp, local_ec); + if (push_result == directory_pushed) + return; + + // report errors if any + if (BOOST_UNLIKELY(!!local_ec)) + { + on_error: + if ((imp->m_options & static_cast< unsigned int >(directory_options::pop_on_error)) == 0u) + { + // Make an end iterator on errors + it.m_imp.reset(); + } + else + { + if ((push_result & keep_depth) != 0u) + { + system::error_code increment_ec; + directory_iterator& dir_it = imp->m_stack.back(); + detail::directory_iterator_increment(dir_it, &increment_ec); + if (!increment_ec && dir_it != directory_iterator()) + goto on_error_return; + } + + recursive_directory_iterator_pop_on_error(imp); + + if (imp->m_stack.empty()) + it.m_imp.reset(); // done, so make end iterator + } + + on_error_return: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("filesystem::recursive_directory_iterator increment error", local_ec)); + + *ec = local_ec; + return; + } + + // Do the actual increment operation on the top iterator in the iterator + // stack, popping the stack if necessary, until either the stack is empty or a + // non-end iterator is reached. + while (true) + { + if (imp->m_stack.empty()) + { + it.m_imp.reset(); // done, so make end iterator + break; + } + + directory_iterator& dir_it = imp->m_stack.back(); + detail::directory_iterator_increment(dir_it, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + goto on_error; + + if (dir_it != directory_iterator()) + break; + + imp->m_stack.pop_back(); + } +} + +} // namespace detail + +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/error_handling.hpp b/3rdparty/boost_filesystem/src/error_handling.hpp new file mode 100644 index 0000000..97590a8 --- /dev/null +++ b/3rdparty/boost_filesystem/src/error_handling.hpp @@ -0,0 +1,220 @@ +// error_handling.hpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2019 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_SRC_ERROR_HANDLING_HPP_ +#define BOOST_FILESYSTEM_SRC_ERROR_HANDLING_HPP_ + +#include +#include +#include +#include + +#if defined(BOOST_WINDOWS_API) +#include +#include +#include +#endif + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +#if defined(BOOST_POSIX_API) + +typedef int err_t; + +// POSIX uses a 0 return to indicate success +#define BOOST_ERRNO errno + +#define BOOST_ERROR_FILE_NOT_FOUND ENOENT +#define BOOST_ERROR_ALREADY_EXISTS EEXIST +#define BOOST_ERROR_NOT_SUPPORTED ENOSYS + +#else + +typedef boost::winapi::DWORD_ err_t; + +// Windows uses a non-0 return to indicate success +#define BOOST_ERRNO boost::winapi::GetLastError() + +#define BOOST_ERROR_FILE_NOT_FOUND boost::winapi::ERROR_FILE_NOT_FOUND_ +#define BOOST_ERROR_ALREADY_EXISTS boost::winapi::ERROR_ALREADY_EXISTS_ +#define BOOST_ERROR_NOT_SUPPORTED boost::winapi::ERROR_NOT_SUPPORTED_ + +// Note: Legacy MinGW doesn't have ntstatus.h and doesn't define NTSTATUS error codes other than STATUS_SUCCESS. +#if !defined(NT_SUCCESS) +#define NT_SUCCESS(Status) (((boost::winapi::NTSTATUS_)(Status)) >= 0) +#endif +#if !defined(STATUS_SUCCESS) +#define STATUS_SUCCESS ((boost::winapi::NTSTATUS_)0x00000000l) +#endif +#if !defined(STATUS_NOT_IMPLEMENTED) +#define STATUS_NOT_IMPLEMENTED ((boost::winapi::NTSTATUS_)0xC0000002l) +#endif +#if !defined(STATUS_INVALID_INFO_CLASS) +#define STATUS_INVALID_INFO_CLASS ((boost::winapi::NTSTATUS_)0xC0000003l) +#endif +#if !defined(STATUS_INVALID_HANDLE) +#define STATUS_INVALID_HANDLE ((boost::winapi::NTSTATUS_)0xC0000008l) +#endif +#if !defined(STATUS_INVALID_PARAMETER) +#define STATUS_INVALID_PARAMETER ((boost::winapi::NTSTATUS_)0xC000000Dl) +#endif +#if !defined(STATUS_NO_SUCH_DEVICE) +#define STATUS_NO_SUCH_DEVICE ((boost::winapi::NTSTATUS_)0xC000000El) +#endif +#if !defined(STATUS_NO_SUCH_FILE) +#define STATUS_NO_SUCH_FILE ((boost::winapi::NTSTATUS_)0xC000000Fl) +#endif +#if !defined(STATUS_NO_MORE_FILES) +#define STATUS_NO_MORE_FILES ((boost::winapi::NTSTATUS_)0x80000006l) +#endif +#if !defined(STATUS_BUFFER_OVERFLOW) +#define STATUS_BUFFER_OVERFLOW ((boost::winapi::NTSTATUS_)0x80000005l) +#endif +#if !defined(STATUS_NO_MEMORY) +#define STATUS_NO_MEMORY ((boost::winapi::NTSTATUS_)0xC0000017l) +#endif +#if !defined(STATUS_ACCESS_DENIED) +#define STATUS_ACCESS_DENIED ((boost::winapi::NTSTATUS_)0xC0000022l) +#endif +#if !defined(STATUS_OBJECT_NAME_NOT_FOUND) +#define STATUS_OBJECT_NAME_NOT_FOUND ((boost::winapi::NTSTATUS_)0xC0000034l) +#endif +#if !defined(STATUS_OBJECT_PATH_NOT_FOUND) +#define STATUS_OBJECT_PATH_NOT_FOUND ((boost::winapi::NTSTATUS_)0xC000003Al) +#endif +#if !defined(STATUS_NOT_SUPPORTED) +#define STATUS_NOT_SUPPORTED ((boost::winapi::NTSTATUS_)0xC00000BBl) +#endif +#if !defined(STATUS_BAD_NETWORK_PATH) +#define STATUS_BAD_NETWORK_PATH ((boost::winapi::NTSTATUS_)0xC00000BEl) +#endif +#if !defined(STATUS_DEVICE_DOES_NOT_EXIST) +#define STATUS_DEVICE_DOES_NOT_EXIST ((boost::winapi::NTSTATUS_)0xC00000C0l) +#endif +#if !defined(STATUS_BAD_NETWORK_NAME) +#define STATUS_BAD_NETWORK_NAME ((boost::winapi::NTSTATUS_)0xC00000CCl) +#endif +#if !defined(STATUS_DIRECTORY_NOT_EMPTY) +#define STATUS_DIRECTORY_NOT_EMPTY ((boost::winapi::NTSTATUS_)0xC0000101l) +#endif +#if !defined(STATUS_NOT_A_DIRECTORY) +#define STATUS_NOT_A_DIRECTORY ((boost::winapi::NTSTATUS_)0xC0000103l) +#endif +#if !defined(STATUS_NOT_FOUND) +#define STATUS_NOT_FOUND ((boost::winapi::NTSTATUS_)0xC0000225l) +#endif + +//! Converts NTSTATUS error codes to Win32 error codes for reporting +inline boost::winapi::DWORD_ translate_ntstatus(boost::winapi::NTSTATUS_ status) +{ + // We have to cast to unsigned integral type to avoid signed overflow and narrowing conversion in the constants. + switch (static_cast< boost::winapi::ULONG_ >(status)) + { + case static_cast< boost::winapi::ULONG_ >(STATUS_NO_MEMORY): + return boost::winapi::ERROR_OUTOFMEMORY_; + case static_cast< boost::winapi::ULONG_ >(STATUS_BUFFER_OVERFLOW): + return boost::winapi::ERROR_BUFFER_OVERFLOW_; + case static_cast< boost::winapi::ULONG_ >(STATUS_INVALID_HANDLE): + return boost::winapi::ERROR_INVALID_HANDLE_; + case static_cast< boost::winapi::ULONG_ >(STATUS_INVALID_PARAMETER): + return boost::winapi::ERROR_INVALID_PARAMETER_; + case static_cast< boost::winapi::ULONG_ >(STATUS_NO_MORE_FILES): + return boost::winapi::ERROR_NO_MORE_FILES_; + case static_cast< boost::winapi::ULONG_ >(STATUS_NO_SUCH_DEVICE): + case static_cast< boost::winapi::ULONG_ >(STATUS_DEVICE_DOES_NOT_EXIST): + return boost::winapi::ERROR_DEV_NOT_EXIST_; + case static_cast< boost::winapi::ULONG_ >(STATUS_NO_SUCH_FILE): + case static_cast< boost::winapi::ULONG_ >(STATUS_OBJECT_NAME_NOT_FOUND): + case static_cast< boost::winapi::ULONG_ >(STATUS_OBJECT_PATH_NOT_FOUND): + return boost::winapi::ERROR_FILE_NOT_FOUND_; + case static_cast< boost::winapi::ULONG_ >(STATUS_ACCESS_DENIED): + return boost::winapi::ERROR_ACCESS_DENIED_; + case static_cast< boost::winapi::ULONG_ >(STATUS_BAD_NETWORK_PATH): + return boost::winapi::ERROR_BAD_NETPATH_; + case static_cast< boost::winapi::ULONG_ >(STATUS_BAD_NETWORK_NAME): + return boost::winapi::ERROR_BAD_NET_NAME_; + case static_cast< boost::winapi::ULONG_ >(STATUS_DIRECTORY_NOT_EMPTY): + return boost::winapi::ERROR_DIR_NOT_EMPTY_; + case static_cast< boost::winapi::ULONG_ >(STATUS_NOT_A_DIRECTORY): + return boost::winapi::ERROR_DIRECTORY_; // The directory name is invalid + case static_cast< boost::winapi::ULONG_ >(STATUS_NOT_FOUND): + return boost::winapi::ERROR_NOT_FOUND_; + // map "invalid info class" to "not supported" as this error likely indicates that the kernel does not support what we request + case static_cast< boost::winapi::ULONG_ >(STATUS_INVALID_INFO_CLASS): + default: + return boost::winapi::ERROR_NOT_SUPPORTED_; + } +} + +#endif + +// error handling helpers ----------------------------------------------------------// + +// Implemented in exception.cpp +void emit_error(err_t error_num, system::error_code* ec, const char* message); +void emit_error(err_t error_num, path const& p, system::error_code* ec, const char* message); +void emit_error(err_t error_num, path const& p1, path const& p2, system::error_code* ec, const char* message); + +inline bool error(err_t error_num, system::error_code* ec, const char* message) +{ + if (BOOST_LIKELY(!error_num)) + { + if (ec) + ec->clear(); + return false; + } + else + { // error + filesystem::emit_error(error_num, ec, message); + return true; + } +} + +inline bool error(err_t error_num, path const& p, system::error_code* ec, const char* message) +{ + if (BOOST_LIKELY(!error_num)) + { + if (ec) + ec->clear(); + return false; + } + else + { // error + filesystem::emit_error(error_num, p, ec, message); + return true; + } +} + +inline bool error(err_t error_num, path const& p1, path const& p2, system::error_code* ec, const char* message) +{ + if (BOOST_LIKELY(!error_num)) + { + if (ec) + ec->clear(); + return false; + } + else + { // error + filesystem::emit_error(error_num, p1, p2, ec, message); + return true; + } +} + +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_SRC_ERROR_HANDLING_HPP_ diff --git a/3rdparty/boost_filesystem/src/exception.cpp b/3rdparty/boost_filesystem/src/exception.cpp new file mode 100644 index 0000000..91ee1c9 --- /dev/null +++ b/3rdparty/boost_filesystem/src/exception.cpp @@ -0,0 +1,188 @@ +// boost/filesystem/exception.hpp -----------------------------------------------------// + +// Copyright Beman Dawes 2003 +// Copyright Andrey Semashev 2019 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include + +#include "error_handling.hpp" + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(const char* what_arg, system::error_code ec) : + system::system_error(ec, what_arg) +{ + try + { + m_imp_ptr.reset(new impl()); + } + catch (...) + { + m_imp_ptr.reset(); + } +} + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(std::string const& what_arg, system::error_code ec) : + system::system_error(ec, what_arg) +{ + try + { + m_imp_ptr.reset(new impl()); + } + catch (...) + { + m_imp_ptr.reset(); + } +} + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(const char* what_arg, path const& path1_arg, system::error_code ec) : + system::system_error(ec, what_arg) +{ + try + { + m_imp_ptr.reset(new impl(path1_arg)); + } + catch (...) + { + m_imp_ptr.reset(); + } +} + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(std::string const& what_arg, path const& path1_arg, system::error_code ec) : + system::system_error(ec, what_arg) +{ + try + { + m_imp_ptr.reset(new impl(path1_arg)); + } + catch (...) + { + m_imp_ptr.reset(); + } +} + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(const char* what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec) : + system::system_error(ec, what_arg) +{ + try + { + m_imp_ptr.reset(new impl(path1_arg, path2_arg)); + } + catch (...) + { + m_imp_ptr.reset(); + } +} + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(std::string const& what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec) : + system::system_error(ec, what_arg) +{ + try + { + m_imp_ptr.reset(new impl(path1_arg, path2_arg)); + } + catch (...) + { + m_imp_ptr.reset(); + } +} + +BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(filesystem_error const& that) : + system::system_error(static_cast< system::system_error const& >(that)), + m_imp_ptr(that.m_imp_ptr) +{ +} + +BOOST_FILESYSTEM_DECL filesystem_error& filesystem_error::operator=(filesystem_error const& that) +{ + static_cast< system::system_error& >(*this) = static_cast< system::system_error const& >(that); + m_imp_ptr = that.m_imp_ptr; + return *this; +} + +BOOST_FILESYSTEM_DECL filesystem_error::~filesystem_error() BOOST_NOEXCEPT_OR_NOTHROW +{ +} + +BOOST_FILESYSTEM_DECL const char* filesystem_error::what() const BOOST_NOEXCEPT_OR_NOTHROW +{ + if (m_imp_ptr.get()) try + { + if (m_imp_ptr->m_what.empty()) + { + m_imp_ptr->m_what = system::system_error::what(); + if (!m_imp_ptr->m_path1.empty()) + { + m_imp_ptr->m_what += ": \""; + m_imp_ptr->m_what += m_imp_ptr->m_path1.string(); + m_imp_ptr->m_what += "\""; + } + if (!m_imp_ptr->m_path2.empty()) + { + m_imp_ptr->m_what += ", \""; + m_imp_ptr->m_what += m_imp_ptr->m_path2.string(); + m_imp_ptr->m_what += "\""; + } + } + + return m_imp_ptr->m_what.c_str(); + } + catch (...) + { + m_imp_ptr->m_what.clear(); + } + + return system::system_error::what(); +} + +BOOST_FILESYSTEM_DECL path const& filesystem_error::get_empty_path() BOOST_NOEXCEPT +{ + static const path empty_path; + return empty_path; +} + +// error handling helpers declared in error_handling.hpp -----------------------------------------------------// + +void emit_error(err_t error_num, system::error_code* ec, const char* message) +{ + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error(message, system::error_code(error_num, system::system_category()))); + else + ec->assign(error_num, system::system_category()); +} + +void emit_error(err_t error_num, path const& p, system::error_code* ec, const char* message) +{ + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error(message, p, system::error_code(error_num, system::system_category()))); + else + ec->assign(error_num, system::system_category()); +} + +void emit_error(err_t error_num, path const& p1, path const& p2, system::error_code* ec, const char* message) +{ + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error(message, p1, p2, system::error_code(error_num, system::system_category()))); + else + ec->assign(error_num, system::system_category()); +} + +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/operations.cpp b/3rdparty/boost_filesystem/src/operations.cpp new file mode 100644 index 0000000..c7808d5 --- /dev/null +++ b/3rdparty/boost_filesystem/src/operations.cpp @@ -0,0 +1,4614 @@ +// operations.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// Copyright 2018-2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::bad_alloc, std::nothrow +#include +#include +#include +#include // for malloc, free +#include +#include +#include // for rename + +// Default to POSIX under Emscripten +// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead +#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI)) +#define BOOST_FILESYSTEM_USE_WASI +#endif + +#ifdef BOOST_POSIX_API + +#include +#include + +#if defined(BOOST_FILESYSTEM_USE_WASI) +// WASI does not have statfs or statvfs. +#elif !defined(__APPLE__) && \ + (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \ + !defined(__ANDROID__) && \ + !defined(__VXWORKS__) +#include +#define BOOST_STATVFS statvfs +#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include +#elif defined(__ANDROID__) +#include +#endif +#if !defined(__VXWORKS__) +#include +#endif +#define BOOST_STATVFS statfs +#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize) +#endif // BOOST_STATVFS definition + +#include +#include +#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +#include +#endif +#include + +#if defined(linux) || defined(__linux) || defined(__linux__) + +#include +#include +#include +#include +#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#include +#define BOOST_FILESYSTEM_USE_SENDFILE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +#include +#endif +#define BOOST_FILESYSTEM_USE_STATX +#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) + +#if defined(__has_include) +#if __has_include() +// This header was introduced in Linux kernel 2.6.19 +#include +#endif +#endif + +// Some filesystem type magic constants are not defined in older kernel headers +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) +#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec +#endif + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +#include // get_proc_address, GetModuleHandleW +#include +#include +#include +#include +#if defined(__BORLANDC__) || defined(__MWERKS__) +#if defined(BOOST_BORLANDC) +using std::time_t; +#endif +#include +#else +#include +#endif + +#include "windows_tools.hpp" + +#endif // BOOST_WINDOWS_API + +#include "atomic_tools.hpp" +#include "error_handling.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::filesystem::perms; +using boost::system::error_code; +using boost::system::system_category; + +#if defined(BOOST_POSIX_API) + +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +#define BOOST_FILESYSTEM_HAS_FDATASYNC +#endif + +#else // defined(BOOST_POSIX_API) + +#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif + +#ifndef SYMLINK_FLAG_RELATIVE +#define SYMLINK_FLAG_RELATIVE 1 +#endif + +// Fallback for MinGW/Cygwin +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 +#endif + +#endif // defined(BOOST_POSIX_API) + +// POSIX/Windows macros ----------------------------------------------------// + +// Portions of the POSIX and Windows API's are very similar, except for name, +// order of arguments, and meaning of zero/non-zero returns. The macros below +// abstract away those differences. They follow Windows naming and order of +// arguments, and return true to indicate no error occurred. [POSIX naming, +// order of arguments, and meaning of return were followed initially, but +// found to be less clear and cause more coding errors.] + +#if defined(BOOST_POSIX_API) + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) +#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) + +#else // BOOST_WINDOWS_API + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) +#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0) + +#endif + +namespace boost { +namespace filesystem { +namespace detail { + +#if defined(linux) || defined(__linux) || defined(__linux__) +//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp. +void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver); +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) +//! Initializes directory iterator implementation. Implemented in directory.cpp. +void init_directory_iterator_impl() BOOST_NOEXCEPT; +#endif // defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + +//--------------------------------------------------------------------------------------// +// // +// helpers (all operating systems) // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file +BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u; + +#if defined(BOOST_POSIX_API) + +// Size of a small buffer for a path that can be placed on stack, in character code units +BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u; + +// Absolute maximum path length, in character code units, that we're willing to accept from various system calls. +// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion +// in some of the algorithms below in case of some corrupted or maliciously broken filesystem. +// A few examples of path size limits: +// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs. +// - Linux: 4096 bytes +// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes +// - GNU/Hurd: no hard limit +BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u; + +#endif // defined(BOOST_POSIX_API) + +// Maximum number of resolved symlinks before we register a loop +BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max = +#if defined(SYMLOOP_MAX) + SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX +#else + 40 +#endif +; + +// general helpers -----------------------------------------------------------------// + +bool is_empty_directory(path const& p, error_code* ec) +{ + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::none), NULL, ec); + return itr == fs::directory_iterator(); +} + +bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration + +#ifdef BOOST_POSIX_API + +//--------------------------------------------------------------------------------------// +// // +// POSIX-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +struct fd_wrapper +{ + int fd; + + fd_wrapper() BOOST_NOEXCEPT : fd(-1) {} + explicit fd_wrapper(int fd) BOOST_NOEXCEPT : fd(fd) {} + ~fd_wrapper() BOOST_NOEXCEPT + { + if (fd >= 0) + close_fd(fd); + } + BOOST_DELETED_FUNCTION(fd_wrapper(fd_wrapper const&)) + BOOST_DELETED_FUNCTION(fd_wrapper& operator=(fd_wrapper const&)) +}; + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ENOENT || errval == ENOTDIR; +} + +#if defined(BOOST_FILESYSTEM_HAS_STATX) + +//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + return ::statx(dirfd, path, flags, mask, stx); +} + +#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + +//! statx emulation through fstatat +int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + struct ::stat st; + flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int res = ::fstatat(dirfd, path, &st, flags); + if (BOOST_LIKELY(res == 0)) + { + std::memset(stx, 0, sizeof(*stx)); + stx->stx_mask = STATX_BASIC_STATS; + stx->stx_blksize = st.st_blksize; + stx->stx_nlink = st.st_nlink; + stx->stx_uid = st.st_uid; + stx->stx_gid = st.st_gid; + stx->stx_mode = st.st_mode; + stx->stx_ino = st.st_ino; + stx->stx_size = st.st_size; + stx->stx_blocks = st.st_blocks; + stx->stx_atime.tv_sec = st.st_atim.tv_sec; + stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; + stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; + stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; + stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; + stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; + stx->stx_rdev_major = major(st.st_rdev); + stx->stx_rdev_minor = minor(st.st_rdev); + stx->stx_dev_major = major(st.st_dev); + stx->stx_dev_minor = minor(st.st_dev); + } + + return res; +} + +typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx); + +//! Pointer to the actual implementation of the statx implementation +statx_t* statx_ptr = &statx_fstatat; + +inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) BOOST_NOEXCEPT +{ + return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx); +} + +//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx); + if (res < 0) + { + const int err = errno; + if (BOOST_UNLIKELY(err == ENOSYS)) + { + filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat); + return statx_fstatat(dirfd, path, flags, mask, stx); + } + } + + return res; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_STATX) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes statx implementation pointer +inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + statx_t* stx = &statx_fstatat; + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u)) + stx = &statx_syscall; + + filesystem::detail::atomic_store_relaxed(statx_ptr, stx); +#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c statx structures refer to the same file +inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) BOOST_NOEXCEPT +{ + return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino; +} + +//! Returns file type/access mode from \c statx structure +inline mode_t get_mode(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_mode; +} + +//! Returns file size from \c statx structure +inline uintmax_t get_size(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_size; +} + +//! Returns optimal block size from \c statx structure +inline std::size_t get_blksize(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_blksize; +} + +#else // defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c stat structures refer to the same file +inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) BOOST_NOEXCEPT +{ + // According to the POSIX stat specs, "The st_ino and st_dev fields + // taken together uniquely identify the file within the system." + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; +} + +//! Returns file type/access mode from \c stat structure +inline mode_t get_mode(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_mode; +} + +//! Returns file size from \c stat structure +inline uintmax_t get_size(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_size; +} + +//! Returns optimal block size from \c stat structure +inline std::size_t get_blksize(struct ::stat const& st) BOOST_NOEXCEPT +{ +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) + return st.st_blksize; +#else + return 4096u; // a suitable default used on most modern SSDs/HDDs +#endif +} + +#endif // defined(BOOST_FILESYSTEM_USE_STATX) + +//! status() implementation +file_status status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::stat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! symlink_status() implementation +file_status symlink_status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::lstat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) // these are not errors + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISLNK(mode)) + return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! Flushes buffered data and attributes written to the file to permanent storage +inline int full_sync(int fd) +{ + while (true) + { +#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC) + // Mac OS does not flush data to physical storage with fsync() + int err = ::fcntl(fd, F_FULLFSYNC); +#else + int err = ::fsync(fd); +#endif + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +} + +//! Flushes buffered data written to the file to permanent storage +inline int data_sync(int fd) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)) + while (true) + { + int err = ::fdatasync(fd); + if (BOOST_UNLIKELY(err != 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // It doesn't say so for fdatasync, but it is reasonable to expect it as well. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +#else + return full_sync(fd); +#endif +} + +// Min and max buffer sizes are selected to minimize the overhead from system calls. +// The values are picked based on coreutils cp(1) benchmarking data described here: +// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72 +BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u; +BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u; + +//! copy_file read/write loop implementation +int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size) +{ +#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE) + ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + + // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs, + // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data + // as we can read from the input file. + while (true) + { + ssize_t sz_read = ::read(infile, buf, buf_size); + if (sz_read == 0) + break; + if (BOOST_UNLIKELY(sz_read < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + for (ssize_t sz_wrote = 0; sz_wrote < sz_read;) + { + ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote)); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + sz_wrote += sz; + } + } + + return 0; +} + +//! copy_file implementation that uses read/write loop (fallback using a stack buffer) +int copy_file_data_read_write_stack_buf(int infile, int outfile) +{ + char stack_buf[min_read_write_buf_size]; + return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf)); +} + +//! copy_file implementation that uses read/write loop +int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + uintmax_t buf_sz = size; + // Prefer the buffer to be larger than the file size so that we don't have + // to perform an extra read if the file fits in the buffer exactly. + buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u)); + if (buf_sz < blksize) + buf_sz = blksize; + if (buf_sz < min_read_write_buf_size) + buf_sz = min_read_write_buf_size; + if (buf_sz > max_read_write_buf_size) + buf_sz = max_read_write_buf_size; + const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz))); + boost::scoped_array< char > buf(new (std::nothrow) char[buf_size]); + if (BOOST_LIKELY(!!buf.get())) + return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size); + } + + return copy_file_data_read_write_stack_buf(infile, outfile); +} + +typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize); + +//! Pointer to the actual implementation of the copy_file_data implementation +copy_file_data_t* copy_file_data = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize); + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + +struct copy_file_data_sendfile +{ + //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // sendfile will not send more than this amount of data in one call + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + ssize_t sz = ::sendfile(outfile, infile, NULL, size_to_copy); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // sendfile may fail with EINVAL if the underlying filesystem does not support it + if (err == EINVAL) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == ENOSYS) + { + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +struct copy_file_data_copy_file_range +{ + //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee + // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t. + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27. + // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33). + loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)NULL, outfile, (loff_t*)NULL, size_to_copy, (unsigned int)0u); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // copy_file_range may fail with EINVAL if the underlying filesystem does not support it. + // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP + // if the remote server does not support COPY, despite that it is not a documented error code. + // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/ + // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554. + if (err == EINVAL || err == EOPNOTSUPP) + { +#if !defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_read_write: +#endif + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == EXDEV) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_sendfile: + return copy_file_data_sendfile::impl(infile, outfile, size, blksize); +#else + goto fallback_to_read_write; +#endif + } + + if (err == ENOSYS) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_sendfile >); + goto fallback_to_sendfile; +#else + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; +#endif + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero, + // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files, + // so we must use a read/write loop to handle them. + // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/ + struct statfs sfs; + while (true) + { + int err = ::fstatfs(infile, &sfs); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + if (err == EINTR) + continue; + + goto fallback_to_read_write; + } + + break; + } + + if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC || + sfs.f_type == SYSFS_MAGIC || + sfs.f_type == TRACEFS_MAGIC || + sfs.f_type == DEBUGFS_MAGIC)) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + } + + return CopyFileData::impl(infile, outfile, size, blksize); +} + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes copy_file_data implementation pointer +inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + copy_file_data_t* cfd = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + // sendfile started accepting file descriptors as the target in Linux 2.6.33 + if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u)))) + cfd = &check_fs_type< copy_file_data_sendfile >; +#endif + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3. + // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV. + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u)) + cfd = &check_fs_type< copy_file_data_copy_file_range >; +#endif + + filesystem::detail::atomic_store_relaxed(copy_file_data, cfd); +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +struct syscall_initializer +{ + syscall_initializer() + { + struct ::utsname system_info; + if (BOOST_UNLIKELY(::uname(&system_info) < 0)) + return; + + unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u; + int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver); + if (BOOST_UNLIKELY(count < 3)) + return; + + init_statx_impl(major_ver, minor_ver, patch_ver); + init_copy_file_data_impl(major_ver, minor_ver, patch_ver); + init_fill_random_impl(major_ver, minor_ver, patch_ver); + } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const syscall_initializer syscall_init; + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +//! remove() implementation +inline bool remove_impl +( + path const& p, + fs::file_type type, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ + if (type == fs::file_not_found) + return false; + + int res; +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0); +#else + if (type == fs::directory_file) + res = ::rmdir(p.c_str()); + else + res = ::unlink(p.c_str()); +#endif + + if (res != 0) + { + int err = errno; + if (BOOST_UNLIKELY(!not_found_error(err))) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + // Since POSIX remove() is specified to work with either files or directories, in a + // perfect world it could just be called. But some important real-world operating + // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So + // we have to distinguish between files and directories and call corresponding APIs + // to remove them. + + error_code local_ec; + fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type(); + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec)); + + *ec = local_ec; + return false; + } + + return fs::detail::remove_impl(p, type, ec); +} + +//! remove_all() implementation +uintmax_t remove_all_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + fs::detail::directory_iterator_params params; + params.basedir_fd = basedir_fd; + params.iterator_fd = -1; +#endif + + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + fs::file_type type; + { + error_code local_ec; + type = fs::detail::symlink_status_impl + ( + p, + &local_ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ).type(); + + if (type == fs::file_not_found) + return 0u; + + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + } + + uintmax_t count = 0u; + if (type == fs::directory_file) // but not a directory symlink + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct + ( + itr, + p, + static_cast< unsigned int >(directory_options::_detail_no_follow), +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + ¶ms, +#else + NULL, +#endif + &dit_create_ec + ); + + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == error_code(ENOTDIR, system_category())) + continue; + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop + // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above + // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call + // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink). + if (dit_create_ec == error_code(ELOOP, system_category())) + continue; +#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_impl + ( +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + path_algorithms::filename_v4(itr->path()), +#else + itr->path(), +#endif + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , params.iterator_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_impl + ( + p, + type, + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +#else // defined(BOOST_POSIX_API) + +//--------------------------------------------------------------------------------------// +// // +// Windows-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +//! FILE_BASIC_INFO definition from Windows SDK +struct file_basic_info +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +}; + +//! FILE_DISPOSITION_INFO definition from Windows SDK +struct file_disposition_info +{ + BOOLEAN DeleteFile; +}; + +//! FILE_DISPOSITION_INFO_EX definition from Windows SDK +struct file_disposition_info_ex +{ + DWORD Flags; +}; + +#ifndef FILE_DISPOSITION_FLAG_DELETE +#define FILE_DISPOSITION_FLAG_DELETE 0x00000001 +#endif +// Available since Windows 10 1709 +#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS +#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002 +#endif +// Available since Windows 10 1809 +#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010 +#endif + +// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the +// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided +// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx +struct reparse_data_buffer +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + /* + * In SymbolicLink and MountPoint reparse points, there are two names. + * SubstituteName is the effective replacement path for the reparse point. + * This is what should be used for path traversal. + * PrintName is intended for presentation to the user and may omit some + * elements of the path or be absent entirely. + * + * Examples of substitute and print names: + * mklink /D ldrive c:\ + * SubstituteName: "\??\c:\" + * PrintName: "c:\" + * + * mklink /J ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "c:\" + * + * junction ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "" + * + * box.com mounted cloud storage + * SubstituteName: "\??\Volume{}\" + * PrintName: "" + */ + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +}; + +// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it +union reparse_data_buffer_with_storage +{ + reparse_data_buffer rdb; + unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; +}; + +// Windows kernel32.dll functions that may or may not be present +// must be accessed through pointers + +typedef BOOL (WINAPI CreateHardLinkW_t)( + /*__in*/ LPCWSTR lpFileName, + /*__in*/ LPCWSTR lpExistingFileName, + /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +CreateHardLinkW_t* create_hard_link_api = NULL; + +typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + +CreateSymbolicLinkW_t* create_symbolic_link_api = NULL; + +//! SetFileInformationByHandle signature. Available since Windows Vista. +typedef BOOL (WINAPI SetFileInformationByHandle_t)( + /*_In_*/ HANDLE hFile, + /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum + /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation, + /*_In_*/ DWORD dwBufferSize); + +SetFileInformationByHandle_t* set_file_information_by_handle_api = NULL; + +} // unnamed namespace + +GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = NULL; + +#if !defined(UNDER_CE) +NtCreateFile_t* nt_create_file_api = NULL; +NtQueryDirectoryFile_t* nt_query_directory_file_api = NULL; +#endif // !defined(UNDER_CE) + +namespace { + +//! remove() implementation type +enum remove_impl_type +{ + remove_nt5, //!< Use Windows XP API + remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later) + remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS + remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +}; + +remove_impl_type g_remove_impl_type = remove_nt5; + +//! Initializes WinAPI function pointers +BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs() +{ + boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll"); + if (BOOST_LIKELY(!!h)) + { + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx"); + filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex); + SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle"); + filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle); + filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW")); + filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW")); + + if (get_file_information_by_handle_ex && set_file_information_by_handle) + { + // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle. + // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly. + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly); + } + } + +#if !defined(UNDER_CE) + h = boost::winapi::GetModuleHandleW(L"ntdll.dll"); + if (BOOST_LIKELY(!!h)) + { + filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile")); + filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile")); + } + + init_directory_iterator_impl(); +#endif // !defined(UNDER_CE) + + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if defined(_MSC_VER) + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCL", long, read) +__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCL") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs; + + globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; } +}; +BOOST_ATTRIBUTE_UNUSED +const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +//! Invokes WinAPI function pointers initialization +struct winapi_func_ptrs_initializer +{ + winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const winapi_func_ptrs_initializer winapi_func_ptrs_init; + +#endif // defined(_MSC_VER) + + +// Windows CE has no environment variables +#if !defined(UNDER_CE) +inline std::wstring wgetenv(const wchar_t* name) +{ + // use a separate buffer since C++03 basic_string is not required to be contiguous + const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0); + if (size > 0) + { + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0)) + return std::wstring(buf.get()); + } + + return std::wstring(); +} +#endif // !defined(UNDER_CE) + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" + || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64 + || errval == ERROR_BAD_NETPATH // "//no-host" on Win32 + || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64 +} + +// these constants come from inspecting some Microsoft sample code +inline std::time_t to_time_t(FILETIME const& ft) BOOST_NOEXCEPT +{ + uint64_t t = (static_cast< uint64_t >(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + t -= 116444736000000000ull; + t /= 10000000u; + return static_cast< std::time_t >(t); +} + +inline void to_FILETIME(std::time_t t, FILETIME& ft) BOOST_NOEXCEPT +{ + uint64_t temp = t; + temp *= 10000000u; + temp += 116444736000000000ull; + ft.dwLowDateTime = static_cast< DWORD >(temp); + ft.dwHighDateTime = static_cast< DWORD >(temp >> 32); +} + +} // unnamed namespace + +#if !defined(UNDER_CE) + +//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel +static bool g_no_obj_dont_reparse = false; + +//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. +boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions) +{ + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + if (BOOST_UNLIKELY(!nt_create_file)) + return STATUS_NOT_IMPLEMENTED; + + unicode_string obj_name = {}; + obj_name.Buffer = const_cast< wchar_t* >(p.c_str()); + obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t)); + + object_attributes obj_attrs = {}; + obj_attrs.Length = sizeof(obj_attrs); + obj_attrs.RootDirectory = basedir_handle; + obj_attrs.ObjectName = &obj_name; + + obj_attrs.Attributes = OBJ_CASE_INSENSITIVE; + if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse)) + obj_attrs.Attributes |= OBJ_DONT_REPARSE; + + io_status_block iosb; + boost::winapi::NTSTATUS_ status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + + if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u)) + { + // OBJ_DONT_REPARSE is supported since Windows 10, retry without it + filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true); + obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE); + + status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + } + + return status; +} + +#endif // !defined(UNDER_CE) + +ULONG get_reparse_point_tag_ioctl(HANDLE h, path const& p, error_code* ec) +{ + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new (std::nothrow) reparse_data_buffer_with_storage); + if (BOOST_UNLIKELY(!buf.get())) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("Cannot allocate memory to query reparse point", p, make_error_code(system::errc::not_enough_memory))); + + *ec = make_error_code(system::errc::not_enough_memory); + return 0u; + } + + // Query the reparse data + DWORD dwRetLen = 0u; + BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL); + if (BOOST_UNLIKELY(!result)) + { + DWORD err = ::GetLastError(); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("Failed to query reparse point", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + return 0u; + } + + return buf->rdb.ReparseTag; +} + +namespace { + +inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) +{ + return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); +} + +inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec) +{ + if (ec) // always report errval, even though some + ec->assign(errval, system_category()); // errval values are not status_errors + + if (not_found_error(errval)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + else if (errval == ERROR_SHARING_VIOLATION) + { + return fs::file_status(fs::type_unknown); + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category()))); + + return fs::file_status(fs::status_error); +} + +inline fs::file_status process_status_failure(path const& p, error_code* ec) +{ + return process_status_failure(::GetLastError(), p, ec); +} + +//! (symlink_)status() by handle implementation +fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) +{ + fs::file_type ftype; + DWORD attrs; + ULONG reparse_tag = 0u; + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!res)) + { + // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. + // Presumably, this is because these filesystems don't support reparse points, so ReparseTag + // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy + // code path in this case. + DWORD err = ::GetLastError(); + if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED) + goto use_get_file_information_by_handle; + + return process_status_failure(err, p, ec); + } + + attrs = info.FileAttributes; + reparse_tag = info.ReparseTag; + } + else + { + use_get_file_information_by_handle: + BY_HANDLE_FILE_INFORMATION info; + BOOL res = ::GetFileInformationByHandle(h, &info); + if (BOOST_UNLIKELY(!res)) + return process_status_failure(p, ec); + + attrs = info.dwFileAttributes; + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + reparse_tag = get_reparse_point_tag_ioctl(h, p, ec); + if (ec) + { + if (BOOST_UNLIKELY(!!ec)) + return fs::file_status(fs::status_error); + } + } + } + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + if (reparse_tag == IO_REPARSE_TAG_DEDUP) + ftype = fs::regular_file; + else if (is_reparse_point_tag_a_symlink(reparse_tag)) + ftype = fs::symlink_file; + else + ftype = fs::reparse_file; + } + else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + ftype = fs::directory_file; + } + else + { + ftype = fs::regular_file; + } + + return fs::file_status(ftype, make_permissions(p, attrs)); +} + +//! symlink_status() implementation +fs::file_status symlink_status_impl(path const& p, error_code* ec) +{ + // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect + // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL + // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. + // https://github.com/boostorg/filesystem/issues/282 + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (h.handle == INVALID_HANDLE_VALUE) + { + // For some system files and folders like "System Volume Information" CreateFileW fails + // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that. + // Though this will only help if the file is not a reparse point (symlink or not). + DWORD err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs)); + } + else + { + err = ::GetLastError(); + } + } + + return process_status_failure(err, p, ec); + } + + return detail::status_by_handle(h.handle, p, ec); +} + +//! status() implementation +fs::file_status status_impl(path const& p, error_code* ec) +{ + // We should first test if the file is a symlink or a reparse point. Resolving some reparse + // points by opening the file may fail, and status() should return file_status(reparse_file) in this case. + // Which is what symlink_status() returns. + fs::file_status st(detail::symlink_status_impl(p, ec)); + if (st.type() == symlink_file) + { + // Resolve the symlink + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (h.handle == INVALID_HANDLE_VALUE) + return process_status_failure(p, ec); + + st = detail::status_by_handle(h.handle, p, ec); + } + + return st; +} + +//! remove() implementation for Windows XP and older +bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec) +{ + const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; + const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0; + if (is_read_only) + { + // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute + DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY; + BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs); + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + } + + BOOL res; + if (!is_directory) + { + // DeleteFileW works for file symlinks by removing the symlink, not the target. + res = ::DeleteFileW(p.c_str()); + } + else + { + // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target, + // even if the target directory is not empty. + // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW + // will fail if the directory is not empty. + res = ::RemoveDirectoryW(p.c_str()); + } + + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + { + if (is_read_only) + { + // Try to restore the read-only attribute + ::SetFileAttributesW(p.c_str(), attrs); + } + + emit_error(err, p, ec, "boost::filesystem::remove"); + } + + return false; + } + + return true; +} + +//! remove() by handle implementation for Windows Vista and newer +DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) +{ + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api); + DWORD err = 0u; + switch (impl) + { + case remove_disp_ex_flag_ignore_readonly: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + break; + + err = ::GetLastError(); + if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp_ex_flag_posix_semantics; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + case remove_disp_ex_flag_posix_semantics: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + + break; + } + else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + default: + { + file_disposition_info info; + info.DeleteFile = true; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + } + + break; + } + } + + return err; +} + +//! remove() implementation for Windows Vista and newer +inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec) +{ + handle_wrapper h(create_file_handle( + p, + DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + DWORD err = 0u; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + err = ::GetLastError(); + + return_error: + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + err = fs::detail::remove_nt6_by_handle(h.handle, impl); + if (BOOST_UNLIKELY(err != 0u)) + goto return_error; + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + return fs::detail::remove_nt6_impl(p, impl, ec); + } + else + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return fs::detail::remove_nt5_impl(p, attrs, ec); + } +} + +#if !defined(UNDER_CE) + +//! remove_all() by handle implementation for Windows Vista and newer +uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) +{ + error_code local_ec; + fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec)); + if (BOOST_UNLIKELY(st.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + uintmax_t count = 0u; + if (st.type() == fs::directory_file) + { + local_ec.clear(); + + fs::directory_iterator itr; + directory_iterator_params params; + params.use_handle = h; + params.close_handle = false; // the caller will close the handle + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), ¶ms, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + fs::path nested_path(itr->path()); + handle_wrapper hh; + if (BOOST_LIKELY(nt_create_file != NULL)) + { + // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't. + // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED. + boost::winapi::NTSTATUS_ status = nt_create_file_handle_at + ( + hh.handle, + h, + path_algorithms::filename_v4(nested_path), + 0u, // FileAttributes + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT + ); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_NO_SUCH_FILE || + status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_PATH_NOT_FOUND || + status == STATUS_BAD_NETWORK_PATH || + status == STATUS_BAD_NETWORK_NAME) + { + goto next_entry; + } + + DWORD err = translate_ntstatus(status); + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + else + { + hh.handle = create_file_handle( + nested_path, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); + + if (BOOST_UNLIKELY(hh.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + goto next_entry; + + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_all_nt6_by_handle(hh.handle, nested_path, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + next_entry: + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type)); + if (BOOST_UNLIKELY(err != 0u)) + { + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + ++count; + return count; +} + +#endif // !defined(UNDER_CE) + +//! remove_all() implementation for Windows XP and older +uintmax_t remove_all_nt5_impl(path const& p, error_code* ec) +{ + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + // Recurse into directories, but not into junctions or directory symlinks + const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + uintmax_t count = 0u; + if (recurse) + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), NULL, &dit_create_ec); + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == make_error_condition(system::errc::not_a_directory) || + dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels)) + { + continue; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_nt5_impl(itr->path(), ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + bool removed = fs::detail::remove_nt5_impl(p, attrs, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + count += removed; + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +//! remove_all() implementation +inline uintmax_t remove_all_impl(path const& p, error_code* ec) +{ +#if !defined(UNDER_CE) + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + handle_wrapper h(create_file_handle( + p, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + return fs::detail::remove_all_nt6_by_handle(h.handle, p, ec); + } +#endif // !defined(UNDER_CE) + + return fs::detail::remove_all_nt5_impl(p, ec); +} + +inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size) +{ + handle_wrapper h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + LARGE_INTEGER sz; + sz.QuadPart = size; + return h.handle != INVALID_HANDLE_VALUE && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.handle); +} + +//! Converts NT path to a Win32 path +inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // + // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc. + // The path starts with a leading backslash and consists of one or more path elements separated with backslashes. + // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically, + // any character except the backslash is allowed. Path elements are case-insensitive. + // + // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix + // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]". + // + // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows + // the system logon directory, so that when the referenced object is not found in the user's namespace, + // system logon is looked up instead. + // + // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global" + // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects, + // even if shadowed by the current user's logon object. + // + // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via + // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon + // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent + // to "\\host\share". + // + // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting + // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell + // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths, + // we should normally avoid exposing NT paths to users that expect Win32 paths. + // + // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points, + // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\" + // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks. + // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible + // to create a junction to an directory using a different way of identifying the filesystem (e.g. + // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory"). + // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that + // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known + // if reparse points that refer to a UNC path are considered valid. + // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted + // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\", + // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\". + // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or + // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far. + + path win32_path; + std::size_t pos = 0u; + bool global_namespace = false; + + // Check for the "\??\" prefix + if (size >= 4u && + nt_path[0] == path::preferred_separator && + nt_path[1] == questionmark && + nt_path[2] == questionmark && + nt_path[3] == path::preferred_separator) + { + pos = 4u; + + // Check "Global" + if ((size - pos) >= 6u && + (nt_path[pos] == L'G' || nt_path[pos] == L'g') && + (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') && + (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') && + (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') && + (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') && + (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L')) + { + if ((size - pos) == 6u) + { + pos += 6u; + global_namespace = true; + } + else if (detail::is_directory_separator(nt_path[pos + 6u])) + { + pos += 7u; + global_namespace = true; + } + } + } + // Check for the "\Global??\" prefix + else if (size >= 10u && + nt_path[0] == path::preferred_separator && + (nt_path[1] == L'G' || nt_path[1] == L'g') && + (nt_path[2] == L'l' || nt_path[2] == L'L') && + (nt_path[3] == L'o' || nt_path[3] == L'O') && + (nt_path[4] == L'b' || nt_path[4] == L'B') && + (nt_path[5] == L'a' || nt_path[5] == L'A') && + (nt_path[6] == L'l' || nt_path[6] == L'L') && + nt_path[7] == questionmark && + nt_path[8] == questionmark && + nt_path[9] == path::preferred_separator) + { + pos = 10u; + global_namespace = true; + } + + if (pos > 0u) + { + if ((size - pos) >= 2u && + ( + // Check if the following is a drive letter + ( + detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon && + ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u])) + ) || + // Check for an "incorrect" syntax for UNC path junction points + ( + detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) && + ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u])) + ) + )) + { + // Strip the NT path prefix + goto done; + } + + static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator }; + + // Check for a UNC path + if ((size - pos) >= 4u && + (nt_path[pos] == L'U' || nt_path[pos] == L'u') && + (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') && + (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') && + nt_path[pos + 3] == path::preferred_separator) + { + win32_path.assign(win32_path_prefix, win32_path_prefix + 2); + pos += 4u; + goto done; + } + + // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\". + win32_path.assign(win32_path_prefix, win32_path_prefix + 4); + if (global_namespace) + { + static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator }; + win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7); + } + } + +done: + win32_path.concat(nt_path + pos, nt_path + size); + return win32_path; +} + +#endif // defined(BOOST_POSIX_API) + +} // unnamed namespace +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// operations functions declared in operations.hpp // +// // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() +{ +#ifdef BOOST_POSIX_API + typedef struct stat struct_stat; + return sizeof(struct_stat().st_size) > 4; +#else + return true; +#endif +} + +BOOST_FILESYSTEM_DECL +path absolute(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + if (p.is_absolute()) + return p; + + // recursively calling absolute is sub-optimal, but is sure and simple + path abs_base = base; + if (!base.is_absolute()) + { + if (ec) + { + abs_base = absolute(base, *ec); + if (*ec) + return path(); + } + else + { + abs_base = absolute(base); + } + } + + if (p.empty()) + return abs_base; + + path res; + if (p.has_root_name()) + res = p.root_name(); + else + res = abs_base.root_name(); + + if (p.has_root_directory()) + { + res.concat(p.root_directory()); + } + else + { + res.concat(abs_base.root_directory()); + path_algorithms::append_v4(res, abs_base.relative_path()); + } + + path p_relative_path(p.relative_path()); + if (!p_relative_path.empty()) + path_algorithms::append_v4(res, p_relative_path); + + return res; +} + +BOOST_FILESYSTEM_DECL +path canonical(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path source(p); + if (!p.is_absolute()) + { + source = detail::absolute(p, base, ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + } + + system::error_code local_ec; + file_status st(detail::status_impl(source, &local_ec)); + + if (st.type() == fs::file_not_found) + { + local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); + goto fail_local_ec; + } + else if (local_ec) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + path root(source.root_path()); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + unsigned int symlinks_allowed = symloop_max; + path result; + while (true) + { + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) == 0) + continue; + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) + { + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); + continue; + } + + if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) + { + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. This is important on Windows, as in some cases, + // like paths for network shares and cloud storage mount points GetFileAttributesW + // will return "file not found" if the path contains forward slashes. + result += path::preferred_separator; + // We don't need to check for a symlink after adding a separator. + continue; + } + + path_algorithms::append_v4(result, *itr); + + // If we don't have an absolute path yet then don't check symlink status. + // This avoids checking "C:" which is "the current directory on drive C" + // and hence not what we want to check/resolve here. + if (!result.is_absolute()) + continue; + + st = detail::symlink_status_impl(result, ec); + if (ec && *ec) + goto return_empty_path; + + if (is_symlink(st)) + { + if (symlinks_allowed == 0) + { + local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); + goto fail_local_ec; + } + + --symlinks_allowed; + + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + goto return_empty_path; + result.remove_filename_and_trailing_separators(); + + if (link.is_absolute()) + { + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); + } + source = link; + root = source.root_path(); + } + else // link is relative + { + link.remove_trailing_separator(); + if (path_algorithms::compare_v4(link, dot_p) == 0) + continue; + + path new_source(result); + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); + } + source = new_source; + } + + // symlink causes scan to be restarted + goto restart_scan; + } + } + + break; + + restart_scan: + result.clear(); + } + + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; +} + +BOOST_FILESYSTEM_DECL +void copy(path const& from, path const& to, unsigned int options, system::error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::copy_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u)) <= 1); + + if (ec) + ec->clear(); + + file_status from_stat; + if ((options & (static_cast< unsigned int >(copy_options::copy_symlinks) | + static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + from_stat = detail::symlink_status_impl(from, ec); + } + else + { + from_stat = detail::status_impl(from, ec); + } + + if (ec && *ec) + return; + + if (!exists(from_stat)) + { + emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy"); + return; + } + + if (is_symlink(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::copy_symlinks)) == 0u) + goto fail; + + detail::copy_symlink(from, to, ec); + } + else if (is_regular_file(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + const path* pfrom = &from; + path relative_from; + if (!from.is_absolute()) + { + // Try to generate a relative path from the target location to the original file + path cur_dir = detail::current_path(ec); + if (ec && *ec) + return; + path abs_from = detail::absolute(from.parent_path(), cur_dir, ec); + if (ec && *ec) + return; + path abs_to = to.parent_path(); + if (!abs_to.is_absolute()) + { + abs_to = detail::absolute(abs_to, cur_dir, ec); + if (ec && *ec) + return; + } + relative_from = detail::relative(abs_from, abs_to, ec); + if (ec && *ec) + return; + if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) + path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); + else + relative_from = path_algorithms::filename_v4(from); + pfrom = &relative_from; + } + detail::create_symlink(*pfrom, to, ec); + return; + } + + if ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u) + { + detail::create_hard_link(from, to, ec); + return; + } + + error_code local_ec; + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (is_directory(to_stat)) + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); + detail::copy_file(from, target, options, ec); + } + else + detail::copy_file(from, to, options, ec); + } + else if (is_directory(from_stat)) + { + error_code local_ec; + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + local_ec = make_error_code(system::errc::is_a_directory); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (!exists(to_stat)) + { + detail::create_directory(to, &from, ec); + if (ec && *ec) + return; + } + + if ((options & static_cast< unsigned int >(copy_options::recursive)) != 0u || options == 0u) + { + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, from, static_cast< unsigned int >(directory_options::none), NULL, ec); + if (ec && *ec) + return; + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + path const& p = itr->path(); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); + // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none + detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); + } + if (ec && *ec) + return; + + detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return; + } + } + } + else + { + fail: + emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy"); + } +} + +BOOST_FILESYSTEM_DECL +bool copy_file(path const& from, path const& to, unsigned int options, error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + int err = 0; + + // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors + fd_wrapper infile, outfile; + + while (true) + { + infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC); + if (BOOST_UNLIKELY(infile.fd < 0)) + { + err = errno; + if (err == EINTR) + continue; + + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + break; + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE; + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + statx_data_mask |= STATX_MTIME; + + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(infile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0)) + { + fail_errno: + err = errno; + goto fail; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0)) + { + fail_errno: + err = errno; + goto fail; + } +#endif + + const mode_t from_mode = get_mode(from_stat); + if (BOOST_UNLIKELY(!S_ISREG(from_mode))) + { + err = ENOSYS; + goto fail; + } + + mode_t to_mode = from_mode; +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // Enable writing for the newly created files. Having write permission set is important e.g. for NFS, + // which checks the file permission on the server, even if the client's file descriptor supports writing. + to_mode |= S_IWUSR; +#endif + int oflag = O_WRONLY | O_CLOEXEC; + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Try opening the existing file without truncation to test the modification time later + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == ENOENT) + goto create_outfile; + + goto fail; + } + + break; + } + } + else + { + create_outfile: + oflag |= O_CREAT | O_TRUNC; + if (((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) && + (options & static_cast< unsigned int >(copy_options::update_existing)) == 0u) + { + oflag |= O_EXCL; + } + + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == EEXIST && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + goto fail; + } + + break; + } + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO; + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + statx_data_mask |= STATX_MTIME; + } + + struct ::statx to_stat; + if (BOOST_UNLIKELY(invoke_statx(outfile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0)) + goto fail_errno; + + if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat to_stat; + if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0)) + goto fail_errno; +#endif + + to_mode = get_mode(to_stat); + if (BOOST_UNLIKELY(!S_ISREG(to_mode))) + { + err = ENOSYS; + goto fail; + } + + if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat))) + { + err = EEXIST; + goto fail; + } + + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + // We need to check the last write times. +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec)) + return false; +#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC) + // Modify time is available with nanosecond precision. + if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)) + return false; +#else + if (from_stat.st_mtime <= to_stat.st_mtime) + return false; +#endif + + if (BOOST_UNLIKELY(::ftruncate(outfile.fd, 0) != 0)) + goto fail_errno; + } + + // Note: Use block size of the target file since it is most important for writing performance. + err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.fd, outfile.fd, get_size(from_stat), get_blksize(to_stat)); + if (BOOST_UNLIKELY(err != 0)) + goto fail; // err already contains the error code + +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // If we created a new file with an explicitly added S_IWUSR permission, + // we may need to update its mode bits to match the source file. + if (to_mode != from_mode) + { + if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_mode) != 0)) + goto fail_errno; + } +#endif + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + if ((options & static_cast< unsigned int >(copy_options::synchronize)) != 0u) + err = full_sync(outfile.fd); + else + err = data_sync(outfile.fd); + + if (BOOST_UNLIKELY(err != 0)) + goto fail; + } + + // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate + // a failure of a prior write operation. + err = close_fd(outfile.fd); + outfile.fd = -1; + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200. + if (err != EINTR && err != EINPROGRESS) + goto fail; + } + + return true; + +#else // defined(BOOST_POSIX_API) + + DWORD copy_flags = 0u; + if ((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + { + copy_flags |= COPY_FILE_FAIL_IF_EXISTS; + } + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError + handle_wrapper hw_from, hw_to; + + // See the comment in last_write_time regarding access rights used here for GetFileTime. + hw_from.handle = create_file_handle( + from.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); + + FILETIME lwt_from; + if (hw_from.handle == INVALID_HANDLE_VALUE) + { + fail_last_error: + DWORD err = ::GetLastError(); + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from)) + goto fail_last_error; + + hw_to.handle = create_file_handle( + to.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); + + if (hw_to.handle != INVALID_HANDLE_VALUE) + { + FILETIME lwt_to; + if (!::GetFileTime(hw_to.handle, NULL, NULL, &lwt_to)) + goto fail_last_error; + + ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime); + ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime); + if (tfrom <= tto) + return false; + } + + copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS); + } + + struct callback_context + { + DWORD flush_error; + }; + + struct local + { + //! Callback that is called to report progress of \c CopyFileExW + static DWORD WINAPI on_copy_file_progress( + LARGE_INTEGER total_file_size, + LARGE_INTEGER total_bytes_transferred, + LARGE_INTEGER stream_size, + LARGE_INTEGER stream_bytes_transferred, + DWORD stream_number, + DWORD callback_reason, + HANDLE from_handle, + HANDLE to_handle, + LPVOID ctx) + { + // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately. + if (stream_bytes_transferred.QuadPart == stream_size.QuadPart) + { + BOOL res = ::FlushFileBuffers(to_handle); + if (BOOST_UNLIKELY(!res)) + { + callback_context* context = static_cast< callback_context* >(ctx); + if (BOOST_LIKELY(context->flush_error == 0u)) + context->flush_error = ::GetLastError(); + } + } + + return PROGRESS_CONTINUE; + } + }; + + callback_context cb_context = {}; + LPPROGRESS_ROUTINE cb = NULL; + LPVOID cb_ctx = NULL; + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + cb = &local::on_copy_file_progress; + cb_ctx = &cb_context; + } + + BOOL cancelled = FALSE; + BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags); + DWORD err; + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + copy_failed: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (BOOST_UNLIKELY(cb_context.flush_error != 0u)) + { + err = cb_context.flush_error; + goto copy_failed; + } + + return true; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec) +{ + path p(read_symlink(existing_symlink, ec)); + if (ec && *ec) + return; + create_symlink(p, new_symlink, ec); +} + +BOOST_FILESYSTEM_DECL +bool create_directories(path const& p, system::error_code* ec) +{ + if (p.empty()) + { + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", p, + system::errc::make_error_code(system::errc::invalid_argument))); + } + ec->assign(system::errc::invalid_argument, system::generic_category()); + return false; + } + + if (ec) + ec->clear(); + + path::const_iterator e(p.end()), it(e); + path parent(p); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + error_code local_ec; + + // Find the initial part of the path that exists + for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) + { + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + file_status existing_status = detail::status_impl(parent, &local_ec); + + if (existing_status.type() == directory_file) + { + break; + } + else if (BOOST_UNLIKELY(existing_status.type() == status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + + path_algorithms::decrement_v4(it); + parent.remove_filename_and_trailing_separators(); + } + + // Create missing directories + bool created = false; + for (; it != e; path_algorithms::increment_v4(it)) + { + path const& fname = *it; + path_algorithms::append_v4(parent, fname); + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + created = detail::create_directory(parent, NULL, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + } + + return created; +} + +BOOST_FILESYSTEM_DECL +bool create_directory(path const& p, const path* existing, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + if (existing) + { +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx existing_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0)) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#else + struct ::stat existing_stat; + if (::stat(existing->c_str(), &existing_stat) < 0) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#endif + + const mode_t existing_mode = get_mode(existing_stat); + if (!S_ISDIR(existing_mode)) + { + emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + mode = existing_mode; + } + + if (::mkdir(p.c_str(), mode) == 0) + return true; + +#else // defined(BOOST_POSIX_API) + + BOOL res; + if (existing) + res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), NULL); + else + res = ::CreateDirectoryW(p.c_str(), NULL); + + if (res) + return true; + +#endif // defined(BOOST_POSIX_API) + + // attempt to create directory failed + err_t errval = BOOST_ERRNO; // save reason for failure + error_code dummy; + + if (is_directory(p, dummy)) + return false; + + // attempt to create directory failed && it doesn't already exist + emit_error(errval, p, ec, "boost::filesystem::create_directory"); + return false; +} + +// Deprecated, to be removed in a future release +BOOST_FILESYSTEM_DECL +void copy_directory(path const& from, path const& to, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + int err; + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, from.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &from_stat) < 0)) + { + fail_errno: + err = errno; + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_directory"); + return; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + err = BOOST_ERROR_NOT_SUPPORTED; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::stat(from.c_str(), &from_stat) < 0)) + { + fail_errno: + emit_error(errno, from, to, ec, "boost::filesystem::copy_directory"); + return; + } +#endif + + if (BOOST_UNLIKELY(::mkdir(to.c_str(), get_mode(from_stat)) < 0)) + goto fail_errno; + +#else // defined(BOOST_POSIX_API) + + if (BOOST_UNLIKELY(!::CreateDirectoryExW(from.c_str(), to.c_str(), 0))) + emit_error(BOOST_ERRNO, from, to, ec, "boost::filesystem::copy_directory"); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void create_directory_symlink(path const& to, path const& from, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#else + // see if actually supported by Windows runtime dll + if (!create_symbolic_link_api) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink"); + return; + } + + if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_hard_link(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::link(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_hard_link"); + } +#else + // see if actually supported by Windows runtime dll + CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api); + if (BOOST_UNLIKELY(!chl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link"); + return; + } + + if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), NULL))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_symlink(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_symlink"); + } +#else + // see if actually supported by Windows runtime dll + CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api); + if (BOOST_UNLIKELY(!csl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink"); + return; + } + + if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +path current_path(error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + // Windows CE has no current directory, so everything's relative to the root of the directory tree. + // WASI also does not support current path. + emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path"); + return path(); +#elif defined(BOOST_POSIX_API) + struct local + { + static bool getcwd_error(error_code* ec) + { + const int err = errno; + return error((err != ERANGE +#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) + // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set + && err != 0 +#endif + ) ? err : 0, + ec, "boost::filesystem::current_path"); + } + }; + + path cur; + char small_buf[small_path_size]; + const char* p = ::getcwd(small_buf, sizeof(small_buf)); + if (BOOST_LIKELY(!!p)) + { + cur = p; + if (ec) + ec->clear(); + } + else if (BOOST_LIKELY(!local::getcwd_error(ec))) + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path"); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + p = ::getcwd(buf.get(), path_max); + if (BOOST_LIKELY(!!p)) + { + cur = buf.get(); + if (ec) + ec->clear(); + break; + } + else if (BOOST_UNLIKELY(local::getcwd_error(ec))) + { + break; + } + } + } + + return cur; +#else + DWORD sz; + if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0) + sz = 1; + boost::scoped_array< path::value_type > buf(new path::value_type[sz]); + error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path"); + return path(buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +void current_path(path const& p, system::error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path"); +#else + error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path"); +#endif +} + +BOOST_FILESYSTEM_DECL +bool equivalent(path const& p1, path const& p2, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + + // p2 is done first, so any error reported is for p1 +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx s2; + int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); + if (BOOST_LIKELY(e2 == 0)) + { + if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + } + + struct ::statx s1; + int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); + if (BOOST_LIKELY(e1 == 0)) + { + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + goto fail_unsupported; + } +#else + struct ::stat s2; + int e2 = ::stat(p2.c_str(), &s2); + struct ::stat s1; + int e1 = ::stat(p1.c_str(), &s1); +#endif + + if (BOOST_UNLIKELY(e1 != 0 || e2 != 0)) + { + // if one is invalid and the other isn't then they aren't equivalent, + // but if both are invalid then it is an error + if (e1 != 0 && e2 != 0) + emit_error(errno, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + return equivalent_stat(s1, s2); + +#else // Windows + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + + // Note well: Physical location on external media is part of the + // equivalence criteria. If there are no open handles, physical location + // can change due to defragmentation or other relocations. Thus handles + // must be held open until location information for both paths has + // been retrieved. + + // p2 is done first, so any error reported is for p1 + handle_wrapper h2(create_file_handle( + p2.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + handle_wrapper h1(create_file_handle( + p1.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h1.handle == INVALID_HANDLE_VALUE || h2.handle == INVALID_HANDLE_VALUE)) + { + // if one is invalid and the other isn't, then they aren't equivalent, + // but if both are invalid then it is an error + if (h1.handle == INVALID_HANDLE_VALUE && h2.handle == INVALID_HANDLE_VALUE) + error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + // at this point, both handles are known to be valid + + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + // In theory, volume serial numbers are sufficient to distinguish between + // devices, but in practice VSN's are sometimes duplicated, so last write + // time and file size are also checked. + return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow && + info1.nFileSizeHigh == info2.nFileSizeHigh && + info1.nFileSizeLow == info2.nFileSizeLow && + info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && + info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; + +#endif +} + +BOOST_FILESYSTEM_DECL +uintmax_t file_size(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#endif + + return get_size(path_stat); + +#else // defined(BOOST_POSIX_API) + + // assume uintmax_t is 64-bits on all Windows compilers + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) + { + emit_error(ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + return (static_cast< uintmax_t >(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow) * 8u)) | + fad.nFileSizeLow; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +uintmax_t hard_link_count(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.stx_nlink); +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.st_nlink); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + fail_errno: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + // Link count info is only available through GetFileInformationByHandle + BY_HANDLE_FILE_INFORMATION info; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.handle, &info))) + goto fail_errno; + + return static_cast< uintmax_t >(info.nNumberOfLinks); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +path initial_path(error_code* ec) +{ + static path init_path; + if (init_path.empty()) + init_path = current_path(ec); + else if (ec) + ec->clear(); + return init_path; +} + +BOOST_FILESYSTEM_DECL +bool is_empty(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_TYPE) != STATX_TYPE)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (S_ISDIR(get_mode(path_stat))) + return is_empty_directory(p, ec); + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_SIZE) != STATX_SIZE)) + goto fail_unsupported; + + return get_size(path_stat) == 0u; +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return S_ISDIR(get_mode(path_stat)) ? is_empty_directory(p, ec) : get_size(path_stat) == 0u; +#endif + +#else // defined(BOOST_POSIX_API) + + WIN32_FILE_ATTRIBUTE_DATA fad; + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? is_empty_directory(p, ec) : (!fad.nFileSizeHigh && !fad.nFileSizeLow); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t creation_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_btime.tv_sec; +#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC) + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME; +#else + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); +#endif + +#else // defined(BOOST_POSIX_API) + + // See the comment in last_write_time regarding access rights used here for GetFileTime. + handle_wrapper hw(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME ct; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL))) + goto fail; + + return to_time_t(ct); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t last_write_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_mtime.tv_sec; +#else + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.st_mtime; +#endif + +#else // defined(BOOST_POSIX_API) + + // GetFileTime is documented to require GENERIC_READ access right, but this causes problems if the file + // is opened by another process without FILE_SHARE_READ. In practice, FILE_READ_ATTRIBUTES works, and + // FILE_READ_EA is also added for good measure, in case if it matters for SMBv1. + handle_wrapper hw(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME lwt; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + + return to_time_t(lwt); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct timespec times[2] = {}; + + // Keep the last access time unchanged + times[0].tv_nsec = UTIME_OMIT; + + times[1].tv_sec = new_time; + + if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + +#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + ::utimbuf buf; + buf.actime = st.st_atime; // utime() updates access time too :-( + buf.modtime = new_time; + if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0)) + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + +#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + FILETIME lwt; + to_FILETIME(new_time, lwt); + + if (BOOST_UNLIKELY(!::SetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + +#endif // defined(BOOST_POSIX_API) +} + +#ifdef BOOST_POSIX_API +const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); +inline mode_t mode_cast(perms prms) +{ + return prms & active_bits; +} +#endif + +BOOST_FILESYSTEM_DECL +void permissions(path const& p, perms prms, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive"); + + if ((prms & add_perms) && (prms & remove_perms)) // precondition failed + return; + +#if defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions"); +#elif defined(BOOST_POSIX_API) + error_code local_ec; + file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec)); + if (local_ec) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec)); + + *ec = local_ec; + return; + } + + if (prms & add_perms) + prms |= current_status.permissions(); + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + + // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to + // support them in the future. The chmod() code is thus more practical, + // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. + // - See the 3rd paragraph of + // "Symbolic link ownership, permissions, and timestamps" at: + // "http://man7.org/linux/man-pages/man7/symlink.7.html" + // - See the fchmodat() Linux man page: + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \ + !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \ + !(defined(linux) || defined(__linux) || defined(__linux__)) && \ + !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \ + !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \ + !(defined(__rtems__)) && \ + !(defined(__QNX__) && (_NTO_VERSION <= 700)) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) +#else // fallback if fchmodat() not supported + if (::chmod(p.c_str(), mode_cast(prms))) +#endif + { + const int err = errno; + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, error_code(err, system::generic_category()))); + } + + ec->assign(err, system::generic_category()); + } + +#else // Windows + + // if not going to alter FILE_ATTRIBUTE_READONLY, just return + if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write)))) + return; + + DWORD attr = ::GetFileAttributesW(p.c_str()); + + if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) + return; + + if (prms & add_perms) + attr &= ~FILE_ATTRIBUTE_READONLY; + else if (prms & remove_perms) + attr |= FILE_ATTRIBUTE_READONLY; + else if (prms & (owner_write | group_write | others_write)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"); +#endif +} + +BOOST_FILESYSTEM_DECL +path read_symlink(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path symlink_path; + +#ifdef BOOST_POSIX_API + const char* const path_str = p.c_str(); + char small_buf[small_path_size]; + ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf)); + if (BOOST_UNLIKELY(result < 0)) + { + fail: + const int err = errno; + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf))) + { + symlink_path.assign(small_buf, small_buf + result); + } + else + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category()))); + + ec->assign(ENAMETOOLONG, system_category()); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + result = ::readlink(path_str, buf.get(), path_max); + if (BOOST_UNLIKELY(result < 0)) + { + goto fail; + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max)) + { + symlink_path.assign(buf.get(), buf.get() + result); + break; + } + } + } + +#else + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + DWORD error; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + return_last_error: + error = ::GetLastError(); + emit_error(error, p, ec, "boost::filesystem::read_symlink"); + return symlink_path; + } + + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + DWORD sz = 0u; + if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL))) + goto return_last_error; + + const wchar_t* buffer; + std::size_t offset, len; + switch (buf->rdb.ReparseTag) + { + case IO_REPARSE_TAG_MOUNT_POINT: + buffer = buf->rdb.MountPointReparseBuffer.PathBuffer; + offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset; + len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength; + break; + + case IO_REPARSE_TAG_SYMLINK: + buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer; + offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset; + len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength; + // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE + // -> resulting path is relative to the source + break; + + default: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink"); + return symlink_path; + } + + symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t)); +#endif + + return symlink_path; +} + +BOOST_FILESYSTEM_DECL +path relative(path const& p, path const& base, error_code* ec) +{ + if (ec) + ec->clear(); + + error_code local_ec; + path cur_path; + if (!p.is_absolute() || !base.is_absolute()) + { + cur_path = detail::current_path(&local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec)); + + *ec = local_ec; + return path(); + } + } + + path wc_base(detail::weakly_canonical(base, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + path wc_p(detail::weakly_canonical(p, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + return wc_p.lexically_relative(wc_base); +} + +BOOST_FILESYSTEM_DECL +bool remove(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +uintmax_t remove_all(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_all_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +void rename(path const& old_p, path const& new_p, error_code* ec) +{ + error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename"); +} + +BOOST_FILESYSTEM_DECL +void resize_file(path const& p, uintmax_t size, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) + { + emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); + return; + } +#endif + error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file"); +} + +BOOST_FILESYSTEM_DECL +space_info space(path const& p, error_code* ec) +{ + space_info info; + // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error + info.capacity = static_cast< uintmax_t >(-1); + info.free = static_cast< uintmax_t >(-1); + info.available = static_cast< uintmax_t >(-1); + + if (ec) + ec->clear(); + +#if defined(BOOST_FILESYSTEM_USE_WASI) + + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space"); + +#elif defined(BOOST_POSIX_API) + + struct BOOST_STATVFS vfs; + if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; + info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; + info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; + } + +#else + + // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file. + // To work around this, test if the path refers to a directory and use the parent directory if not. + error_code local_ec; + file_status status = detail::status_impl(p, &local_ec); + if (status.type() == fs::status_error || status.type() == fs::file_not_found) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec)); + *ec = local_ec; + return info; + } + + path dir_path = p; + if (!is_directory(status)) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + return info; + + status = detail::symlink_status_impl(p, &local_ec); + if (status.type() == fs::status_error) + goto fail_local_ec; + if (is_symlink(status)) + { + // We need to resolve the symlink so that we report the space for the symlink target + dir_path = detail::canonical(p, cur_path, ec); + if (ec && *ec) + return info; + } + + dir_path = dir_path.parent_path(); + if (dir_path.empty()) + { + // The original path was just a filename, which is a relative path wrt. current directory + dir_path = cur_path; + } + } + + // For UNC names, the path must also include a trailing slash. + path::string_type str = dir_path.native(); + if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1))) + str.push_back(path::preferred_separator); + + ULARGE_INTEGER avail, total, free; + if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(total.QuadPart); + info.free = static_cast< uintmax_t >(free.QuadPart); + info.available = static_cast< uintmax_t >(avail.QuadPart); + } + +#endif + + return info; +} + +BOOST_FILESYSTEM_DECL +file_status status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::status_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +file_status symlink_status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::symlink_status_impl(p, ec); +} + +// contributed by Jeff Flinn +BOOST_FILESYSTEM_DECL +path temp_directory_path(system::error_code* ec) +{ + if (ec) + ec->clear(); + +#ifdef BOOST_POSIX_API + const char* val = NULL; + + (val = std::getenv("TMPDIR")) || + (val = std::getenv("TMP")) || + (val = std::getenv("TEMP")) || + (val = std::getenv("TEMPDIR")); + +#ifdef __ANDROID__ + const char* default_tmp = "/data/local/tmp"; +#else + const char* default_tmp = "/tmp"; +#endif + path p((val != NULL) ? val : default_tmp); + + if (BOOST_UNLIKELY(p.empty())) + { + fail_not_dir: + error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); + return p; + } + + file_status status = detail::status_impl(p, ec); + if (BOOST_UNLIKELY(ec && *ec)) + return path(); + if (BOOST_UNLIKELY(!is_directory(status))) + goto fail_not_dir; + + return p; + +#else // Windows +#if !defined(UNDER_CE) + + static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; + static const wchar_t temp_dir[] = L"Temp"; + + path p; + for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) + { + std::wstring env = wgetenv(env_list[i]); + if (!env.empty()) + { + p = env; + if (i >= 2) + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + error_code lcl_ec; + if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) + break; + p.clear(); + } + } + + if (p.empty()) + { + // use a separate buffer since in C++03 a string is not required to be contiguous + const UINT size = ::GetWindowsDirectoryW(NULL, 0); + if (BOOST_UNLIKELY(size == 0)) + { + getwindir_error: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0)) + goto getwindir_error; + + p = buf.get(); // do not depend on initial buf size, see ticket #10388 + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + } + + return p; + +#else // Windows CE + + // Windows CE has no environment variables, so the same code as used for + // regular Windows, above, doesn't work. + + DWORD size = ::GetTempPathW(0, NULL); + if (size == 0u) + { + fail: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (::GetTempPathW(size, buf.get()) == 0) + goto fail; + + path p(buf.get()); + p.remove_trailing_separator(); + + file_status status = detail::status_impl(p, ec); + if (ec && *ec) + return path(); + if (!is_directory(status)) + { + error(ERROR_PATH_NOT_FOUND, p, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + return p; + +#endif // !defined(UNDER_CE) +#endif +} + +BOOST_FILESYSTEM_DECL +path system_complete(path const& p, system::error_code* ec) +{ +#ifdef BOOST_POSIX_API + + if (p.empty() || p.is_absolute()) + return p; + + path res(current_path()); + path_algorithms::append_v4(res, p); + return res; + +#else + if (p.empty()) + { + if (ec) + ec->clear(); + return p; + } + + BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u; + wchar_t buf[buf_size]; + wchar_t* pfn; + std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); + + if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) + return path(); + + if (len < buf_size) // len does not include null termination character + return path(&buf[0]); + + boost::scoped_array< wchar_t > big_buf(new wchar_t[len]); + + return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +path weakly_canonical(path const& p, path const& base, system::error_code* ec) +{ + system::error_code local_ec; + const path::iterator p_end(p.end()); + +#if defined(BOOST_POSIX_API) + + path::iterator itr(p_end); + path head(p); + for (; !head.empty(); path_algorithms::decrement_v4(itr)) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() != fs::file_not_found) + break; + + head.remove_filename_and_trailing_separators(); + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + +#else + + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. + path::iterator itr(p.begin()); + path head; + if (p.has_root_name()) + { + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + // If the root path does not exist then no path element exists + return path_algorithms::lexically_normal_v4(p); + } + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); + + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + head.remove_filename_and_trailing_separators(); + break; + } + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + +#endif + + path tail; + bool tail_has_dots = false; + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& tail_elem = *itr; + path_algorithms::append_v4(tail, tail_elem); + // for a later optimization, track if any dot or dot-dot elements are present + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) + tail_has_dots = true; + } + + head = detail::canonical(head, base, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (BOOST_LIKELY(!tail.empty())) + { + path_algorithms::append_v4(head, tail); + + // optimization: only normalize if tail had dot or dot-dot element + if (tail_has_dots) + return path_algorithms::lexically_normal_v4(head); + } + + return head; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/path.cpp b/3rdparty/boost_filesystem/src/path.cpp new file mode 100644 index 0000000..1d9748c --- /dev/null +++ b/3rdparty/boost_filesystem/src/path.cpp @@ -0,0 +1,1633 @@ +// filesystem path.cpp ------------------------------------------------------------- // + +// Copyright Beman Dawes 2008 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include // codecvt_error_category() +#include +#include // for BOOST_SYSTEM_HAS_CONSTEXPR +#include +#include +#include +#include +#include +#include +#include +#include // std::atexit + +#ifdef BOOST_WINDOWS_API +#include "windows_file_codecvt.hpp" +#include "windows_tools.hpp" +#include +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#include +#endif + +#ifdef BOOST_FILESYSTEM_DEBUG +#include +#include +#endif + +#include "atomic_tools.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; + +using boost::filesystem::path; + +//--------------------------------------------------------------------------------------// +// // +// class path helpers // +// // +//--------------------------------------------------------------------------------------// + +namespace { +//------------------------------------------------------------------------------------// +// miscellaneous class path helpers // +//------------------------------------------------------------------------------------// + +typedef path::value_type value_type; +typedef path::string_type string_type; +typedef string_type::size_type size_type; + +#ifdef BOOST_WINDOWS_API + +const wchar_t dot_path_literal[] = L"."; +const wchar_t dot_dot_path_literal[] = L".."; +const wchar_t separators[] = L"/\\"; +using boost::filesystem::detail::colon; +using boost::filesystem::detail::questionmark; + +inline bool is_alnum(wchar_t c) +{ + return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9'); +} + +inline bool is_device_name_char(wchar_t c) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // Device names are: + // + // - PRN + // - AUX + // - NUL + // - CON + // - LPT[1-9] + // - COM[1-9] + // - CONIN$ + // - CONOUT$ + return is_alnum(c) || c == L'$'; +} + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const wchar_t* p, size_type size) BOOST_NOEXCEPT +{ + size_type pos = 0u; + for (; pos < size; ++pos) + { + const wchar_t c = p[pos]; + if (boost::filesystem::detail::is_directory_separator(c)) + break; + } + return pos; +} + +#else // BOOST_WINDOWS_API + +const char dot_path_literal[] = "."; +const char dot_dot_path_literal[] = ".."; +const char separators[] = "/"; + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const char* p, size_type size) BOOST_NOEXCEPT +{ + const char* sep = static_cast< const char* >(std::memchr(p, '/', size)); + size_type pos = size; + if (BOOST_LIKELY(!!sep)) + pos = sep - p; + return pos; +} + +#endif // BOOST_WINDOWS_API + +// pos is position of the separator +bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos); + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos); + +// Returns: starting position of root directory or size if not found. Sets root_name_size to length +// of the root name if the characters before the returned position (if any) are considered a root name. +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size); + +// Finds position and size of the first element of the path +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size); + +// Finds position and size of the first element of the path +inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size) +{ + first_element(src, element_pos, element_size, src.size()); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// class path implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { +namespace detail { + +// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier +// standard libraries didn't, so provide this needed functionality. +inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) +{ + for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) + { + path_algorithms::increment_v4(it1); + path_algorithms::increment_v4(it2); + } + return std::make_pair(it1, it2); +} + +// normal --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + bool last_element_was_dot = false; + while (true) + { + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + last_element_was_dot = false; + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + break; + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing dot element + goto append_trailing_dot; + } + } + + if (normal.empty() || last_element_was_dot) + { + append_trailing_dot: + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.push_back(path::dot); + } + } + + return normal; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + while (true) + { + bool last_element_was_dot = false; + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + { + // If a path ends with a trailing dot after a directory element, add a trailing separator + if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + + break; + } + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing separator + if (!normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + break; + } + } + + // If the original path was not empty and normalized ended up being empty, make it a dot + if (normal.empty()) + normal.m_pathname.push_back(path::dot); + } + + return normal; +} + +// append --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + if (!detail::is_directory_separator(*begin)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(begin, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); + } + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + const size_type that_size = end - begin; + size_type that_root_name_size = 0; + size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size); + + // if (p.is_absolute()) + if + ( +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + that_root_name_size > 0 && +#endif + that_root_dir_pos < that_size + ) + { + return_assign: + p.assign(begin, end); + return; + } + + size_type this_root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); + + if + ( + that_root_name_size > 0 && + (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) + ) + { + goto return_assign; + } + + if (that_root_dir_pos < that_size) + { + // Remove root directory (if any) and relative path to replace with those from p + p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); + } + + const value_type* const that_path = begin + that_root_name_size; + if (!detail::is_directory_separator(*that_path)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(that_path, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); + } + } + else if (path_algorithms::has_filename_v4(p)) + { + p.m_pathname.push_back(path::preferred_separator); + } +} + +// compare -------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v3(first1); + path_algorithms::increment_v3(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v4(first1); + path_algorithms::increment_v4(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); +} + +// append_separator_if_needed ------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) +{ + if (!p.m_pathname.empty() && +#ifdef BOOST_WINDOWS_API + *(p.m_pathname.end() - 1) != colon && +#endif + !detail::is_directory_separator(*(p.m_pathname.end() - 1))) + { + string_type::size_type tmp(p.m_pathname.size()); + p.m_pathname.push_back(path::preferred_separator); + return tmp; + } + return 0; +} + +// erase_redundant_separator -------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) +{ + if (sep_pos // a separator was added + && sep_pos < p.m_pathname.size() // and something was appended + && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator +#ifdef BOOST_WINDOWS_API + || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator +#endif + )) + { + p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator + } +} + +// modifiers -----------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) +{ + p.remove_filename_and_trailing_separators(); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) +{ + size_type filename_size = path_algorithms::find_filename_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +// decomposition -------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) +{ + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + return root_name_size; +} + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + size = root_dir_pos + 1; + + return size; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) +{ + substring root_dir; + size_type root_name_size = 0; + root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); + return root_dir; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + // Skip root name, root directory and any duplicate separators + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + { + size = root_dir_pos + 1; + + for (size_type n = p.m_pathname.size(); size < n; ++size) + { + if (!detail::is_directory_separator(p.m_pathname[size])) + break; + } + } + + substring rel_path; + rel_path.pos = size; + rel_path.size = p.m_pathname.size() - size; + + return rel_path; +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type end_pos = size - filename_size; + while (true) + { + if (end_pos <= root_name_size) + { + // Keep the root name as the parent path if there was a filename + if (filename_size == 0) + end_pos = 0u; + break; + } + + --end_pos; + + if (!detail::is_directory_separator(p.m_pathname[end_pos])) + { + ++end_pos; + break; + } + + if (end_pos == root_dir_pos) + { + // Keep the trailing root directory if there was a filename + end_pos += filename_size > 0; + break; + } + } + + return end_pos; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size, pos; + if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) + { + // Return root directory + pos = root_dir_pos; + filename_size = 1u; + } + else if (root_name_size == size) + { + // Return root name + pos = 0u; + filename_size = root_name_size; + } + else + { + filename_size = find_filename_size(p.m_pathname, root_name_size, size); + pos = size - filename_size; + if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) + return detail::dot_path(); + } + + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + return find_filename_size(p.m_pathname, root_name_size, size); +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) +{ + path name(path_algorithms::filename_v4(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != 0 && pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) + return path(); + size_type pos(name.m_pathname.rfind(path::dot)); + return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type filename_pos = size - filename_size; + if + ( + filename_size > 0u && + // Check for "." and ".." filenames + !(p.m_pathname[filename_pos] == path::dot && + (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) + ) + { + size_type ext_pos = size; + while (ext_pos > filename_pos) + { + --ext_pos; + if (p.m_pathname[ext_pos] == path::dot) + break; + } + + if (ext_pos > filename_pos) + return size - ext_pos; + } + + return 0u; +} + +} // namespace detail + +BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() +{ + size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); + m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() +{ + if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.end() - 1); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) +{ + detail::path_algorithms::remove_filename_v4(*this); + detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); + return *this; +} + +// lexical operations --------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const +{ + path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end(); + std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e); + if (mm.first == b && mm.second == base_b) + return path(); + if (mm.first == e && mm.second == base_e) + return detail::dot_path(); + + std::ptrdiff_t n = 0; + for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) + { + path const& p = *mm.second; + if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) + --n; + else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) + ++n; + } + if (n < 0) + return path(); + if (n == 0 && (mm.first == e || mm.first->empty())) + return detail::dot_path(); + + path tmp; + for (; n > 0; --n) + detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); + for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) + detail::path_algorithms::append_v4(tmp, *mm.first); + return tmp; +} + +#if defined(BOOST_WINDOWS_API) + +BOOST_FILESYSTEM_DECL path path::generic_path() const +{ + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp; +} + +BOOST_FILESYSTEM_DECL path& path::make_preferred() +{ + std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); + return *this; +} + +#endif // defined(BOOST_WINDOWS_API) + +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// class path helpers implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// is_root_separator ---------------------------------------------------------------// + +// pos is position of the separator +inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos) +{ + BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation"); + + // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir + while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1])) + --pos; + + return pos == root_dir_pos; +} + +// find_filename_size --------------------------------------------------------------// + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos) +{ + size_type pos = end_pos; + while (pos > root_name_size) + { + --pos; + + if (fs::detail::is_directory_separator(str[pos])) + { + ++pos; // filename starts past the separator + break; + } + } + + return end_pos - pos; +} + +// find_root_directory_start -------------------------------------------------------// + +// Returns: starting position of root directory or size if not found +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size) +{ + root_name_size = 0; + if (size == 0) + return 0; + + bool parsing_root_name = false; + size_type pos = 0; + + // case "//", possibly followed by more characters + if (fs::detail::is_directory_separator(path[0])) + { + if (size >= 2 && fs::detail::is_directory_separator(path[1])) + { + if (size == 2) + { + // The whole path is just a pair of separators + root_name_size = 2; + return 2; + } +#ifdef BOOST_WINDOWS_API + // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + // cases "\\?\" and "\\.\" + else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else if (fs::detail::is_directory_separator(path[2])) + { + // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators + return 0; + } + else + { + // case "//net {/}" + parsing_root_name = true; + pos += 2; + goto find_next_separator; + } + } +#ifdef BOOST_WINDOWS_API + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // case "\??\" (NT path prefix) + else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else + { + // The path starts with a separator, possibly followed by a non-separator character + return 0; + } + } + +#ifdef BOOST_WINDOWS_API + // case "c:" or "prn:" + // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:, + // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we. + if ((size - pos) >= 2 && fs::detail::is_letter(path[pos])) + { + size_type i = pos + 1; + for (; i < size; ++i) + { + if (!is_device_name_char(path[i])) + break; + } + + if (i < size && path[i] == colon) + { + pos = i + 1; + root_name_size = pos; + parsing_root_name = false; + + if (pos < size && fs::detail::is_directory_separator(path[pos])) + return pos; + } + } +#endif + + if (!parsing_root_name) + return size; + +find_next_separator: + pos += find_separator(path + pos, size - pos); + if (parsing_root_name) + root_name_size = pos; + + return pos; +} + +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + +// first_element ----------------------------------------------------------------------// + +// sets pos and len of first element, excluding extra separators +// if src.empty(), sets pos,len, to 0,0. +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size) +{ + element_pos = 0; + element_size = 0; + if (src.empty()) + return; + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size); + + // First element is the root name, if there is one + if (root_name_size > 0) + { + element_size = root_name_size; + return; + } + + // Otherwise, the root directory + if (root_dir_pos < size) + { + element_pos = root_dir_pos; + element_size = 1u; + return; + } + + // Otherwise, the first filename or directory name in a relative path + size_type end_pos = src.find_first_of(separators); + if (end_pos == string_type::npos) + end_pos = src.size(); + element_size = end_pos; +} + +} // unnamed namespace + +namespace boost { +namespace filesystem { +namespace detail { + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator, and treat it as ".", per POSIX spec + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); + + if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + // The iterator was pointing to the last empty element of the path; set to end. + it.m_pos = size; + return; + } + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing non-root '/', return "." + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing '/', return "" + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +} // namespace detail + +// path iterators ------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path::iterator path::begin() const +{ + iterator itr; + itr.m_path_ptr = this; + + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + + if (element_size > 0) + { + itr.m_element = m_pathname.substr(itr.m_pos, element_size); +#ifdef BOOST_WINDOWS_API + if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) + itr.m_element.m_pathname[0] = path::separator; +#endif + } + + return itr; +} + +BOOST_FILESYSTEM_DECL path::iterator path::end() const +{ + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; +} + +} // namespace filesystem +} // namespace boost + +namespace { + +//------------------------------------------------------------------------------------// +// locale helpers // +//------------------------------------------------------------------------------------// + +// Prior versions of these locale and codecvt implementations tried to take advantage +// of static initialization where possible, kept a local copy of the current codecvt +// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading +// safe (again for efficiency). +// +// This was error prone, and required different implementation techniques depending +// on the compiler and also whether static or dynamic linking was used. Furthermore, +// users could not easily provide their multi-threading safe wrappers because the +// path interface requires the implementation itself to call codecvt() to obtain the +// default facet, and the initialization of the static within path_locale() could race. +// +// The code below is portable to all platforms, is much simpler, and hopefully will be +// much more robust. Timing tests (on Windows, using a Visual C++ release build) +// indicated the current code is roughly 9% slower than the previous code, and that +// seems a small price to pay for better code that is easier to use. + +std::locale default_locale() +{ +#if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html + // + // "The kernel will reject any filename that is not a valid UTF-8 string, and it will + // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. + // The right way to deal with it would be to always convert the filename to UTF-8 + // before trying to open/create a file." See + // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html + // + // "How a file name looks at the API level depends on the API. Current Carbon APIs + // handle file names as an array of UTF-16 characters; POSIX ones handle them as an + // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk + // depends on the disk format; HFS+ uses UTF-16, but that's not important in most + // cases." See + // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html + // + // Many thanks to Peter Dimov for digging out the above references! + + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet()); +#else // Other POSIX + // ISO C calls std::locale("") "the locale-specific native environment", and this + // locale is the default for many POSIX-based operating systems such as Linux. + return std::locale(""); +#endif +} + +std::locale* g_path_locale = NULL; + +void schedule_path_locale_cleanup() BOOST_NOEXCEPT; + +// std::locale("") construction, needed on non-Apple POSIX systems, can throw +// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so +// get_path_locale() provides lazy initialization to ensure that any +// exceptions occur after main() starts and so can be caught. Furthermore, +// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves +// actually called, ensuring that an exception will only be thrown if std::locale("") +// is really needed. +inline std::locale& get_path_locale() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< std::locale* > a(g_path_locale); + std::locale* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + std::locale* new_p = new std::locale(default_locale()); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + { + p = new_p; + schedule_path_locale_cleanup(); + } + else + { + delete new_p; + } + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = g_path_locale; + if (BOOST_UNLIKELY(!p)) + { + g_path_locale = p = new std::locale(default_locale()); + schedule_path_locale_cleanup(); + } + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline std::locale* replace_path_locale(std::locale const& loc) +{ + std::locale* new_p = new std::locale(loc); +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel); +#else + std::locale* p = g_path_locale; + g_path_locale = new_p; +#endif + if (!p) + schedule_path_locale_cleanup(); + return p; +} + +#if defined(_MSC_VER) + +const boost::filesystem::path* g_dot_path = NULL; +const boost::filesystem::path* g_dot_dot_path = NULL; + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_path = p = new boost::filesystem::path(dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +void __cdecl destroy_path_globals() +{ + delete g_dot_dot_path; + g_dot_dot_path = NULL; + delete g_dot_path; + g_dot_path = NULL; + delete g_path_locale; + g_path_locale = NULL; +} + +BOOST_FILESYSTEM_INIT_FUNC init_path_globals() +{ +#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) + // codecvt_error_category needs to be called early to dynamic-initialize the error category instance + boost::filesystem::codecvt_error_category(); +#endif + std::atexit(&destroy_path_globals); + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCM", long, read) +__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCM") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_path_globals; + + globals_retainer() { m_p_init_path_globals = &p_init_path_globals; } +}; +BOOST_ATTRIBUTE_UNUSED +static const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +struct path_locale_deleter +{ + ~path_locale_deleter() + { + delete g_path_locale; + g_path_locale = NULL; + } +}; + +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED +const path_locale_deleter g_path_locale_deleter = {}; +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_path(dot_path_literal); +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + return g_dot_dot_path; +} + +#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ + BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter; +} + +inline boost::filesystem::path const& get_dot_path() +{ + static const boost::filesystem::path g_dot_path(dot_path_literal); + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + return g_dot_dot_path; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +#endif // defined(_MSC_VER) + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path::codecvt() and path::imbue() implementation // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt() +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::codecvt() called" << std::endl; +#endif + return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale()); +} + +BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc) +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::imbue() called" << std::endl; +#endif + std::locale* p = replace_path_locale(loc); + if (BOOST_LIKELY(p != NULL)) + { + // Note: copying/moving std::locale does not throw +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + std::locale temp(std::move(*p)); +#else + std::locale temp(*p); +#endif + delete p; + return temp; + } + + return default_locale(); +} + +namespace detail { + +BOOST_FILESYSTEM_DECL path const& dot_path() +{ + return get_dot_path(); +} + +BOOST_FILESYSTEM_DECL path const& dot_dot_path() +{ + return get_dot_dot_path(); +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/path_traits.cpp b/3rdparty/boost_filesystem/src/path_traits.cpp new file mode 100644 index 0000000..baed387 --- /dev/null +++ b/3rdparty/boost_filesystem/src/path_traits.cpp @@ -0,0 +1,187 @@ +// filesystem path_traits.cpp --------------------------------------------------------// + +// Copyright Beman Dawes 2008, 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include // for codecvt_base::result +#include // for mbstate_t +#include + +#include // must be the last #include + +namespace pt = boost::filesystem::detail::path_traits; +namespace fs = boost::filesystem; +namespace bs = boost::system; + +//--------------------------------------------------------------------------------------// +// configuration // +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE +#define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256 +#endif + +namespace { + +BOOST_CONSTEXPR_OR_CONST std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE; + +//--------------------------------------------------------------------------------------// +// // +// The public convert() functions do buffer management, and then forward to the // +// convert_aux() functions for the actual call to the codecvt facet. // +// // +//--------------------------------------------------------------------------------------// + +//--------------------------------------------------------------------------------------// +// convert_aux const char* to wstring // +//--------------------------------------------------------------------------------------// + +void convert_aux(const char* from, const char* from_end, wchar_t* to, wchar_t* to_end, std::wstring& target, pt::codecvt_type const& cvt) +{ + //std::cout << std::hex + // << " from=" << std::size_t(from) + // << " from_end=" << std::size_t(from_end) + // << " to=" << std::size_t(to) + // << " to_end=" << std::size_t(to_end) + // << std::endl; + + std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports + const char* from_next; + wchar_t* to_next; + + std::codecvt_base::result res; + + if ((res = cvt.in(state, from, from_end, from_next, to, to_end, to_next)) != std::codecvt_base::ok) + { + //std::cout << " result is " << static_cast(res) << std::endl; + BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), "boost::filesystem::path codecvt to wstring")); + } + target.append(to, to_next); +} + +//--------------------------------------------------------------------------------------// +// convert_aux const wchar_t* to string // +//--------------------------------------------------------------------------------------// + +void convert_aux(const wchar_t* from, const wchar_t* from_end, char* to, char* to_end, std::string& target, pt::codecvt_type const& cvt) +{ + //std::cout << std::hex + // << " from=" << std::size_t(from) + // << " from_end=" << std::size_t(from_end) + // << " to=" << std::size_t(to) + // << " to_end=" << std::size_t(to_end) + // << std::endl; + + std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports + const wchar_t* from_next; + char* to_next; + + std::codecvt_base::result res; + + if ((res = cvt.out(state, from, from_end, from_next, to, to_end, to_next)) != std::codecvt_base::ok) + { + //std::cout << " result is " << static_cast(res) << std::endl; + BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), "boost::filesystem::path codecvt to string")); + } + target.append(to, to_next); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path_traits // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { +namespace detail { +namespace path_traits { + +//--------------------------------------------------------------------------------------// +// convert const char* to wstring // +//--------------------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL +void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt) +{ + if (from == from_end) + return; + + BOOST_ASSERT(from != NULL); + BOOST_ASSERT(from_end != NULL); + + if (!cvt) + cvt = &fs::path::codecvt(); + + std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK + + // dynamically allocate a buffer only if source is unusually large + if (buf_size > default_codecvt_buf_size) + { + boost::scoped_array< wchar_t > buf(new wchar_t[buf_size]); + convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt); + } + else + { + wchar_t buf[default_codecvt_buf_size]; + convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt); + } +} + +//--------------------------------------------------------------------------------------// +// convert const wchar_t* to string // +//--------------------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL +void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt) +{ + if (from == from_end) + return; + + BOOST_ASSERT(from != NULL); + BOOST_ASSERT(from_end != NULL); + + if (!cvt) + cvt = &fs::path::codecvt(); + + // The codecvt length functions may not be implemented, and I don't really + // understand them either. Thus this code is just a guess; if it turns + // out the buffer is too small then an error will be reported and the code + // will have to be fixed. + std::size_t buf_size = (from_end - from) * 4; // perhaps too large, but that's OK + buf_size += 4; // encodings like shift-JIS need some prefix space + + // dynamically allocate a buffer only if source is unusually large + if (buf_size > default_codecvt_buf_size) + { + boost::scoped_array< char > buf(new char[buf_size]); + convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt); + } + else + { + char buf[default_codecvt_buf_size]; + convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt); + } +} + +} // namespace path_traits +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/platform_config.hpp b/3rdparty/boost_filesystem/src/platform_config.hpp new file mode 100644 index 0000000..941338b --- /dev/null +++ b/3rdparty/boost_filesystem/src/platform_config.hpp @@ -0,0 +1,83 @@ +// platform_config.hpp --------------------------------------------------------------------// + +// Copyright 2020 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_PLATFORM_CONFIG_HPP_ +#define BOOST_FILESYSTEM_PLATFORM_CONFIG_HPP_ + +// define 64-bit offset macros BEFORE including boost/config.hpp (see ticket #5355) +#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24 +// Android fully supports 64-bit file offsets only for API 24 and above. +// +// Trying to define _FILE_OFFSET_BITS=64 for APIs below 24 +// leads to compilation failure for one or another reason, +// depending on target Android API level, Android NDK version, +// used STL, order of include paths and more. +// For more information, please see: +// - https://github.com/boostorg/filesystem/issues/65 +// - https://github.com/boostorg/filesystem/pull/69 +// +// Android NDK developers consider it the expected behavior. +// See their official position here: +// - https://github.com/android-ndk/ndk/issues/501#issuecomment-326447479 +// - https://android.googlesource.com/platform/bionic/+/a34817457feee026e8702a1d2dffe9e92b51d7d1/docs/32-bit-abi.md#32_bit-abi-bugs +// +// Thus we do not define _FILE_OFFSET_BITS in such case. +#else +// Defining _FILE_OFFSET_BITS=64 should kick in 64-bit off_t's +// (and thus st_size) on 32-bit systems that provide the Large File +// Support (LFS) interface, such as Linux, Solaris, and IRIX. +// +// At the time of this comment writing (March 2018), on most systems +// _FILE_OFFSET_BITS=64 definition is harmless: +// either the definition is supported and enables 64-bit off_t, +// or the definition is not supported and is ignored, in which case +// off_t does not change its default size for the target system +// (which may be 32-bit or 64-bit already). +// Thus it makes sense to have _FILE_OFFSET_BITS=64 defined by default, +// instead of listing every system that supports the definition. +// Those few systems, on which _FILE_OFFSET_BITS=64 is harmful, +// for example this definition causes compilation failure on those systems, +// should be exempt from defining _FILE_OFFSET_BITS by adding +// an appropriate #elif block above with the appropriate comment. +// +// _FILE_OFFSET_BITS must be defined before any headers are included +// to ensure that the definition is available to all included headers. +// That is required at least on Solaris, and possibly on other +// systems as well. +#define _FILE_OFFSET_BITS 64 +#endif + +#if defined(__APPLE__) || defined(__MACH__) +// Enable newer ABI on Mac OS 10.5 and later, which is needed for struct stat to have birthtime members +#define _DARWIN_USE_64_BIT_INODE 1 +#endif + +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r() needs this +#endif + +#if !defined(_INCLUDE_STDCSOURCE_199901) && (defined(hpux) || defined(_hpux) || defined(__hpux)) +// For HP-UX, request that WCHAR_MAX and WCHAR_MIN be defined as macros, +// not casts. See ticket 5048 +#define _INCLUDE_STDCSOURCE_199901 +#endif + +#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) || \ + defined(__CYGWIN__) +// Define target Windows version macros before including any other headers +#include +#endif + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include + +#endif // BOOST_FILESYSTEM_PLATFORM_CONFIG_HPP_ diff --git a/3rdparty/boost_filesystem/src/portability.cpp b/3rdparty/boost_filesystem/src/portability.cpp new file mode 100644 index 0000000..8e0e2e5 --- /dev/null +++ b/3rdparty/boost_filesystem/src/portability.cpp @@ -0,0 +1,83 @@ +// portability.cpp -------------------------------------------------------------------// + +// Copyright 2002-2005 Beman Dawes +// Use, modification, and distribution is subject to 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) + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include + +#include // SGI MIPSpro compilers need this +#include + +#include // must be the last #include + +namespace boost { +namespace filesystem { + +namespace { + +BOOST_CONSTEXPR_OR_CONST char windows_invalid_chars[] = + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + "<>:\"/\\|"; + +BOOST_CONSTEXPR_OR_CONST char posix_valid_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"; + +} // unnamed namespace + +// name_check functions ----------------------------------------------// + +#ifdef BOOST_WINDOWS +BOOST_FILESYSTEM_DECL bool native(std::string const& name) +{ + return windows_name(name); +} +#else +BOOST_FILESYSTEM_DECL bool native(std::string const& name) +{ + return !name.empty() && name[0] != ' ' && name.find('/') == std::string::npos; +} +#endif + +BOOST_FILESYSTEM_DECL bool portable_posix_name(std::string const& name) +{ + return !name.empty() && name.find_first_not_of(posix_valid_chars, 0, sizeof(posix_valid_chars) - 1) == std::string::npos; +} + +BOOST_FILESYSTEM_DECL bool windows_name(std::string const& name) +{ + // note that the terminating '\0' is part of the string - thus the size below + // is sizeof(windows_invalid_chars) rather than sizeof(windows_invalid_chars)-1. + return !name.empty() && name[0] != ' ' && name.find_first_of(windows_invalid_chars, 0, sizeof(windows_invalid_chars)) == std::string::npos + && *(name.end() - 1) != ' ' && (*(name.end() - 1) != '.' || name.size() == 1 || name == ".."); +} + +BOOST_FILESYSTEM_DECL bool portable_name(std::string const& name) +{ + return !name.empty() && (name == "." || name == ".." || (windows_name(name) && portable_posix_name(name) && name[0] != '.' && name[0] != '-')); +} + +BOOST_FILESYSTEM_DECL bool portable_directory_name(std::string const& name) +{ + return name == "." || name == ".." || (portable_name(name) && name.find('.') == std::string::npos); +} + +BOOST_FILESYSTEM_DECL bool portable_file_name(std::string const& name) +{ + std::string::size_type pos; + return portable_name(name) && name != "." && name != ".." && ((pos = name.find('.')) == std::string::npos || (name.find('.', pos + 1) == std::string::npos && (pos + 5) > name.size())); +} + +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/posix_tools.hpp b/3rdparty/boost_filesystem/src/posix_tools.hpp new file mode 100644 index 0000000..52cd87b --- /dev/null +++ b/3rdparty/boost_filesystem/src/posix_tools.hpp @@ -0,0 +1,81 @@ +// posix_tools.hpp -------------------------------------------------------------------// + +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_ +#define BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_ + +#include "platform_config.hpp" +#include +#include +#ifdef BOOST_HAS_UNISTD_H +#include +#endif + +#include // must be the last #include + +namespace boost { +namespace filesystem { +namespace detail { + +//! Platform-specific parameters for directory iterator construction +struct directory_iterator_params +{ +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + //! File descriptor of the base directory relative to which to interpret relative paths + int basedir_fd; +#endif +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + //! File descriptor of the directory over which the iterator iterates + int iterator_fd; +#endif +}; + +/*! + * Closes a file descriptor and returns the result, similar to close(2). Unlike close(2), guarantees that the file descriptor is closed even if EINTR error happens. + * + * Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR. + * Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it + * again could close a different file descriptor that was opened by a different thread. This function hides this difference in behavior. + * + * Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529) + * and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2) + * behaves differently between systems. + */ +inline int close_fd(int fd) +{ +#if defined(hpux) || defined(_hpux) || defined(__hpux) + int res; + while (true) + { + res = ::close(fd); + if (BOOST_UNLIKELY(res < 0)) + { + int err = errno; + if (err == EINTR) + continue; + } + + break; + } + + return res; +#else + return ::close(fd); +#endif +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_ diff --git a/3rdparty/boost_filesystem/src/private_config.hpp b/3rdparty/boost_filesystem/src/private_config.hpp new file mode 100644 index 0000000..c58d245 --- /dev/null +++ b/3rdparty/boost_filesystem/src/private_config.hpp @@ -0,0 +1,74 @@ +// private_config.hpp ----------------------------------------------------------------// + +// Copyright 2021 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_SRC_PRIVATE_CONFIG_HPP_ +#define BOOST_FILESYSTEM_SRC_PRIVATE_CONFIG_HPP_ + +#include + +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) +#define BOOST_FILESYSTEM_INIT_PRIORITY(n) __attribute__ ((init_priority(n))) +#else +#define BOOST_FILESYSTEM_INIT_PRIORITY(n) +#endif + +// According to https://gcc.gnu.org/bugzilla//show_bug.cgi?id=65115, +// the default C++ object initializers priority is 65535. We would like to +// initialize function pointers earlier than that (with lower priority values), +// before the other global objects initializers are run. Other than this, +// these priority values are arbitrary. +#define BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY 32767 + +// Path globals initialization priority +#define BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY 32768 + +#if defined(__has_feature) && defined(__has_attribute) +#if __has_feature(memory_sanitizer) && __has_attribute(no_sanitize) +#define BOOST_FILESYSTEM_NO_SANITIZE_MEMORY __attribute__ ((no_sanitize("memory"))) +#endif +#endif // defined(__has_feature) && defined(__has_attribute) + +#ifndef BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +#define BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +#endif + +#if defined(_MSC_VER) +#if _MSC_VER < 1300 || _MSC_VER > 1900 // 1300 == VC++ 7.0, 1900 == VC++ 14.0 +typedef void (__cdecl* init_func_ptr_t)(); +#define BOOST_FILESYSTEM_INITRETSUCCESS_V +#define BOOST_FILESYSTEM_INIT_FUNC void __cdecl +#else +typedef int (__cdecl* init_func_ptr_t)(); +#define BOOST_FILESYSTEM_INITRETSUCCESS_V 0 +#define BOOST_FILESYSTEM_INIT_FUNC int __cdecl +#endif +#else // defined(_MSC_VER) +typedef void (*init_func_ptr_t)(); +#define BOOST_FILESYSTEM_INITRETSUCCESS_V +#define BOOST_FILESYSTEM_INIT_FUNC void +#endif // defined(_MSC_VER) + +#if defined(__has_attribute) +#if __has_attribute(__used__) +#define BOOST_FILESYSTEM_ATTRIBUTE_RETAIN __attribute__ ((__used__)) +#endif +#endif + +#if !defined(BOOST_FILESYSTEM_ATTRIBUTE_RETAIN) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 402 +#define BOOST_FILESYSTEM_ATTRIBUTE_RETAIN __attribute__ ((__used__)) +#endif + +#if !defined(BOOST_FILESYSTEM_ATTRIBUTE_RETAIN) +#define BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN +#define BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +#endif + +#endif // BOOST_FILESYSTEM_SRC_PRIVATE_CONFIG_HPP_ diff --git a/3rdparty/boost_filesystem/src/unique_path.cpp b/3rdparty/boost_filesystem/src/unique_path.cpp new file mode 100644 index 0000000..f0bc605 --- /dev/null +++ b/3rdparty/boost_filesystem/src/unique_path.cpp @@ -0,0 +1,331 @@ +// filesystem unique_path.cpp --------------------------------------------------------// + +// Copyright Beman Dawes 2010 +// Copyright Andrey Semashev 2020 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include + +#ifdef BOOST_POSIX_API + +#include +#include +#include +#ifdef BOOST_HAS_UNISTD_H +#include +#endif + +#if !defined(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM) +#if BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(2, 1, 0) || \ + BOOST_OS_BSD_FREE >= BOOST_VERSION_NUMBER(8, 0, 0) || \ + BOOST_LIB_C_CLOUDABI +#include +#define BOOST_FILESYSTEM_HAS_ARC4RANDOM +#endif +#endif // !defined(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM) + +#if !defined(BOOST_FILESYSTEM_DISABLE_GETRANDOM) +#if (defined(__linux__) || defined(__linux) || defined(linux)) && \ + (!defined(__ANDROID__) || __ANDROID_API__ >= 28) +#include +#if defined(SYS_getrandom) +#define BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL +#endif // defined(SYS_getrandom) +#if defined(__has_include) +#if __has_include() +#define BOOST_FILESYSTEM_HAS_GETRANDOM +#endif +#elif defined(__GLIBC__) +#if __GLIBC_PREREQ(2, 25) +#define BOOST_FILESYSTEM_HAS_GETRANDOM +#endif +#endif // BOOST_FILESYSTEM_HAS_GETRANDOM definition +#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM) +#include +#endif +#endif // (defined(__linux__) || defined(__linux) || defined(linux)) && (!defined(__ANDROID__) || __ANDROID_API__ >= 28) +#endif // !defined(BOOST_FILESYSTEM_DISABLE_GETRANDOM) + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +// We use auto-linking below to help users of static builds of Boost.Filesystem to link to whatever Windows SDK library we selected. +// The dependency information is currently not exposed in CMake config files generated by Boost.Build (https://github.com/boostorg/boost_install/issues/18), +// which makes it non-trivial for users to discover the libraries they need. This feature is deprecated and may be removed in the future, +// when the situation with CMake config files improves. +// Note that the library build system is the principal source of linking the library, which must work regardless of auto-linking. +#include +#include + +#if defined(BOOST_FILESYSTEM_HAS_BCRYPT) // defined on the command line by the project +#include +#include +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER) +#pragma comment(lib, "bcrypt.lib") +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER) +#else // defined(BOOST_FILESYSTEM_HAS_BCRYPT) +#include +#include +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER) +#if !defined(_WIN32_WCE) +#pragma comment(lib, "advapi32.lib") +#else +#pragma comment(lib, "coredll.lib") +#endif +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER) +#endif // defined(BOOST_FILESYSTEM_HAS_BCRYPT) + +#endif // BOOST_POSIX_API + +#include +#include +#include +#include "private_config.hpp" +#include "atomic_tools.hpp" +#include "error_handling.hpp" + +#include // must be the last #include + +#if defined(BOOST_POSIX_API) +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif +#endif // defined(BOOST_POSIX_API) + +namespace boost { +namespace filesystem { +namespace detail { + +namespace { + +#if defined(BOOST_POSIX_API) && !defined(BOOST_FILESYSTEM_HAS_ARC4RANDOM) + +//! Fills buffer with cryptographically random data obtained from /dev/(u)random +int fill_random_dev_random(void* buf, std::size_t len) +{ + int file = ::open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (file == -1) + { + file = ::open("/dev/random", O_RDONLY | O_CLOEXEC); + if (file == -1) + return errno; + } + + std::size_t bytes_read = 0u; + while (bytes_read < len) + { + ssize_t n = ::read(file, buf, len - bytes_read); + if (BOOST_UNLIKELY(n == -1)) + { + int err = errno; + if (err == EINTR) + continue; + close_fd(file); + return err; + } + bytes_read += n; + buf = static_cast< char* >(buf) + n; + } + + close_fd(file); + return 0; +} + +#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL) + +typedef int fill_random_t(void* buf, std::size_t len); + +//! Pointer to the implementation of fill_random. +fill_random_t* fill_random = &fill_random_dev_random; + +//! Fills buffer with cryptographically random data obtained from getrandom() +int fill_random_getrandom(void* buf, std::size_t len) +{ + std::size_t bytes_read = 0u; + while (bytes_read < len) + { +#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM) + ssize_t n = ::getrandom(buf, len - bytes_read, 0u); +#else + ssize_t n = ::syscall(SYS_getrandom, buf, len - bytes_read, 0u); +#endif + if (BOOST_UNLIKELY(n < 0)) + { + const int err = errno; + if (err == EINTR) + continue; + + if (err == ENOSYS && bytes_read == 0u) + { + filesystem::detail::atomic_store_relaxed(fill_random, &fill_random_dev_random); + return fill_random_dev_random(buf, len); + } + + return err; + } + + bytes_read += n; + buf = static_cast< char* >(buf) + n; + } + + return 0; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL) + +#endif // defined(BOOST_POSIX_API) && !defined(BOOST_FILESYSTEM_HAS_ARC4RANDOM) + +void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL) + + int err = filesystem::detail::atomic_load_relaxed(fill_random)(buf, len); + if (BOOST_UNLIKELY(err != 0)) + emit_error(err, ec, "boost::filesystem::unique_path"); + +#elif defined(BOOST_FILESYSTEM_HAS_ARC4RANDOM) + + arc4random_buf(buf, len); + +#else + + int err = fill_random_dev_random(buf, len); + if (BOOST_UNLIKELY(err != 0)) + emit_error(err, ec, "boost::filesystem::unique_path"); + +#endif + +#else // defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_BCRYPT) + + boost::winapi::BCRYPT_ALG_HANDLE_ handle; + boost::winapi::NTSTATUS_ status = boost::winapi::BCryptOpenAlgorithmProvider(&handle, boost::winapi::BCRYPT_RNG_ALGORITHM_, NULL, 0); + if (BOOST_UNLIKELY(status != 0)) + { + fail: + emit_error(translate_ntstatus(status), ec, "boost::filesystem::unique_path"); + return; + } + + status = boost::winapi::BCryptGenRandom(handle, static_cast< boost::winapi::PUCHAR_ >(buf), static_cast< boost::winapi::ULONG_ >(len), 0); + + boost::winapi::BCryptCloseAlgorithmProvider(handle, 0); + + if (BOOST_UNLIKELY(status != 0)) + goto fail; + +#else // defined(BOOST_FILESYSTEM_HAS_BCRYPT) + + boost::winapi::HCRYPTPROV_ handle; + boost::winapi::DWORD_ err = 0u; + if (BOOST_UNLIKELY(!boost::winapi::CryptAcquireContextW(&handle, NULL, NULL, boost::winapi::PROV_RSA_FULL_, boost::winapi::CRYPT_VERIFYCONTEXT_ | boost::winapi::CRYPT_SILENT_))) + { + err = boost::winapi::GetLastError(); + + fail: + emit_error(err, ec, "boost::filesystem::unique_path"); + return; + } + + boost::winapi::BOOL_ gen_ok = boost::winapi::CryptGenRandom(handle, static_cast< boost::winapi::DWORD_ >(len), static_cast< boost::winapi::BYTE_* >(buf)); + + if (BOOST_UNLIKELY(!gen_ok)) + err = boost::winapi::GetLastError(); + + boost::winapi::CryptReleaseContext(handle, 0); + + if (BOOST_UNLIKELY(!gen_ok)) + goto fail; + +#endif // defined(BOOST_FILESYSTEM_HAS_BCRYPT) + +#endif // defined(BOOST_POSIX_API) +} + +#ifdef BOOST_WINDOWS_API +BOOST_CONSTEXPR_OR_CONST wchar_t hex[] = L"0123456789abcdef"; +BOOST_CONSTEXPR_OR_CONST wchar_t percent = L'%'; +#else +BOOST_CONSTEXPR_OR_CONST char hex[] = "0123456789abcdef"; +BOOST_CONSTEXPR_OR_CONST char percent = '%'; +#endif + +} // unnamed namespace + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes fill_random implementation pointer +void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) && \ + (defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL)) + fill_random_t* fr = &fill_random_dev_random; + + if (major_ver > 3u || (major_ver == 3u && minor_ver >= 17u)) + fr = &fill_random_getrandom; + + filesystem::detail::atomic_store_relaxed(fill_random, fr); +#endif +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +BOOST_FILESYSTEM_DECL +path unique_path(path const& model, system::error_code* ec) +{ + // This function used wstring for fear of misidentifying + // a part of a multibyte character as a percent sign. + // However, double byte encodings only have 80-FF as lead + // bytes and 40-7F as trailing bytes, whereas % is 25. + // So, use string on POSIX and avoid conversions. + + path::string_type s(model.native()); + + char ran[16] = {}; // init to avoid clang static analyzer message + // see ticket #8954 + BOOST_CONSTEXPR_OR_CONST unsigned int max_nibbles = 2u * sizeof(ran); // 4-bits per nibble + + unsigned int nibbles_used = max_nibbles; + for (path::string_type::size_type i = 0, n = s.size(); i < n; ++i) + { + if (s[i] == percent) // digit request + { + if (nibbles_used == max_nibbles) + { + system_crypt_random(ran, sizeof(ran), ec); + if (ec && *ec) + return path(); + nibbles_used = 0; + } + unsigned int c = ran[nibbles_used / 2u]; + c >>= 4u * (nibbles_used++ & 1u); // if odd, shift right 1 nibble + s[i] = hex[c & 0xf]; // convert to hex digit and replace + } + } + + if (ec) + ec->clear(); + + return s; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff --git a/3rdparty/boost_filesystem/src/utf8_codecvt_facet.cpp b/3rdparty/boost_filesystem/src/utf8_codecvt_facet.cpp new file mode 100644 index 0000000..7e5939b --- /dev/null +++ b/3rdparty/boost_filesystem/src/utf8_codecvt_facet.cpp @@ -0,0 +1,29 @@ +// Copyright Vladimir Prus 2004. +// 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 "platform_config.hpp" + +#include + +#include + +#define BOOST_UTF8_BEGIN_NAMESPACE \ + namespace boost { \ + namespace filesystem { \ + namespace detail { + +#define BOOST_UTF8_END_NAMESPACE \ + } \ + } \ + } +#define BOOST_UTF8_DECL BOOST_FILESYSTEM_DECL + +#include + +#undef BOOST_UTF8_BEGIN_NAMESPACE +#undef BOOST_UTF8_END_NAMESPACE +#undef BOOST_UTF8_DECL + +#include diff --git a/3rdparty/boost_filesystem/src/windows_file_codecvt.cpp b/3rdparty/boost_filesystem/src/windows_file_codecvt.cpp new file mode 100644 index 0000000..f86ba51 --- /dev/null +++ b/3rdparty/boost_filesystem/src/windows_file_codecvt.cpp @@ -0,0 +1,72 @@ +// filesystem windows_file_codecvt.cpp -----------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include // for mbstate_t + +#ifdef BOOST_WINDOWS_API + +#include "windows_file_codecvt.hpp" + +#include + +#include // must be the last #include + +namespace boost { +namespace filesystem { +namespace detail { + +std::codecvt_base::result windows_file_codecvt::do_in( + std::mbstate_t&, + const char* from, const char* from_end, const char*& from_next, + wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const +{ + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + int count; + if ((count = ::MultiByteToWideChar(codepage, MB_PRECOMPOSED, from, static_cast< int >(from_end - from), to, static_cast< int >(to_end - to))) == 0) + { + return error; // conversion failed + } + + from_next = from_end; + to_next = to + count; + *to_next = L'\0'; + return ok; +} + +std::codecvt_base::result windows_file_codecvt::do_out( + std::mbstate_t&, + const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, + char* to, char* to_end, char*& to_next) const +{ + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + int count; + if ((count = ::WideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, from, static_cast< int >(from_end - from), to, static_cast< int >(to_end - to), 0, 0)) == 0) + { + return error; // conversion failed + } + + from_next = from_end; + to_next = to + count; + *to_next = '\0'; + return ok; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_WINDOWS_API diff --git a/3rdparty/boost_filesystem/src/windows_file_codecvt.hpp b/3rdparty/boost_filesystem/src/windows_file_codecvt.hpp new file mode 100644 index 0000000..917dc21 --- /dev/null +++ b/3rdparty/boost_filesystem/src/windows_file_codecvt.hpp @@ -0,0 +1,72 @@ +// filesystem windows_file_codecvt.hpp -----------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_WINDOWS_FILE_CODECVT_HPP +#define BOOST_FILESYSTEM_WINDOWS_FILE_CODECVT_HPP + +#include + +#ifdef BOOST_WINDOWS_API + +#include +#include +#include // std::mbstate_t +#include + +#include // must be the last #include + +namespace boost { +namespace filesystem { +namespace detail { + +//------------------------------------------------------------------------------------// +// // +// class windows_file_codecvt // +// // +// Warning: partial implementation; even do_in and do_out only partially meet the // +// standard library specifications as the "to" buffer must hold the entire result. // +// // +//------------------------------------------------------------------------------------// + +class BOOST_SYMBOL_VISIBLE windows_file_codecvt BOOST_FINAL : + public std::codecvt< wchar_t, char, std::mbstate_t > +{ +public: + explicit windows_file_codecvt(std::size_t refs = 0) : + std::codecvt< wchar_t, char, std::mbstate_t >(refs) + { + } + +protected: + bool do_always_noconv() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE { return false; } + + // seems safest to assume variable number of characters since we don't + // actually know what codepage is active + int do_encoding() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE { return 0; } + std::codecvt_base::result do_in(std::mbstate_t& state, const char* from, const char* from_end, const char*& from_next, wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const BOOST_OVERRIDE; + std::codecvt_base::result do_out(std::mbstate_t& state, const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, char* to, char* to_end, char*& to_next) const BOOST_OVERRIDE; + std::codecvt_base::result do_unshift(std::mbstate_t&, char* /*from*/, char* /*to*/, char*& /*next*/) const BOOST_OVERRIDE { return ok; } + int do_length(std::mbstate_t&, const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const +#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) + throw() +#endif + BOOST_OVERRIDE + { return 0; } + int do_max_length() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE { return 0; } +}; + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_WINDOWS_API + +#endif // BOOST_FILESYSTEM_WINDOWS_FILE_CODECVT_HPP diff --git a/3rdparty/boost_filesystem/src/windows_tools.hpp b/3rdparty/boost_filesystem/src/windows_tools.hpp new file mode 100644 index 0000000..ca62bfb --- /dev/null +++ b/3rdparty/boost_filesystem/src/windows_tools.hpp @@ -0,0 +1,281 @@ +// windows_tools.hpp -----------------------------------------------------------------// + +// Copyright 2001 Dietmar Kuehl +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2021-2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_ +#define BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_ + +#include +#include +#include +#include +#include // NTSTATUS_ + +#include + +#include // must be the last #include + +#ifndef IO_REPARSE_TAG_DEDUP +#define IO_REPARSE_TAG_DEDUP (0x80000013L) +#endif + +#ifndef IO_REPARSE_TAG_MOUNT_POINT +#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#endif + +#ifndef IO_REPARSE_TAG_SYMLINK +#define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#endif + +namespace boost { +namespace filesystem { +namespace detail { + +BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST wchar_t colon = L':'; +BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST wchar_t questionmark = L'?'; + +inline bool is_letter(wchar_t c) +{ + return (c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z'); +} + +inline bool equal_extension(wchar_t const* p, wchar_t const (&x1)[5], wchar_t const (&x2)[5]) +{ + return (p[0] == x1[0] || p[0] == x2[0]) && + (p[1] == x1[1] || p[1] == x2[1]) && + (p[2] == x1[2] || p[2] == x2[2]) && + (p[3] == x1[3] || p[3] == x2[3]) && + p[4] == 0; +} + +inline boost::filesystem::perms make_permissions(boost::filesystem::path const& p, DWORD attr) +{ + boost::filesystem::perms prms = boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read; + if ((attr & FILE_ATTRIBUTE_READONLY) == 0u) + prms |= boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write; + boost::filesystem::path ext = detail::path_algorithms::extension_v4(p); + wchar_t const* q = ext.c_str(); + if (equal_extension(q, L".exe", L".EXE") || equal_extension(q, L".com", L".COM") || equal_extension(q, L".bat", L".BAT") || equal_extension(q, L".cmd", L".CMD")) + prms |= boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe; + return prms; +} + +ULONG get_reparse_point_tag_ioctl(HANDLE h, boost::filesystem::path const& p, boost::system::error_code* ec); + +inline bool is_reparse_point_tag_a_symlink(ULONG reparse_point_tag) +{ + return reparse_point_tag == IO_REPARSE_TAG_SYMLINK + // Issue 9016 asked that NTFS directory junctions be recognized as directories. + // That is equivalent to recognizing them as symlinks, and then the normal symlink + // mechanism will take care of recognizing them as directories. + // + // Directory junctions are very similar to symlinks, but have some performance + // and other advantages over symlinks. They can be created from the command line + // with "mklink /J junction-name target-path". + // + // Note that mounted filesystems also have the same repartse point tag, which makes + // them look like directory symlinks in terms of Boost.Filesystem. read_symlink() + // may return a volume path or NT path for such symlinks. + || reparse_point_tag == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction" +} + +#if !defined(UNDER_CE) + +//! Platform-specific parameters for directory iterator construction +struct directory_iterator_params +{ + //! Handle of the directory to iterate over. If not \c INVALID_HANDLE_VALUE, the directory path is ignored. + HANDLE use_handle; + /*! + * If \c use_handle is not \c INVALID_HANDLE_VALUE, specifies whether the directory iterator should close the handle upon destruction. + * If \c false, the handle must remain valid for the lifetime of the iterator. + */ + bool close_handle; +}; + +//! IO_STATUS_BLOCK definition from Windows SDK. +struct io_status_block +{ + union + { + boost::winapi::NTSTATUS_ Status; + PVOID Pointer; + }; + ULONG_PTR Information; +}; + +//! UNICODE_STRING definition from Windows SDK +struct unicode_string +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +}; + +//! OBJECT_ATTRIBUTES definition from Windows SDK +struct object_attributes +{ + ULONG Length; + HANDLE RootDirectory; + unicode_string* ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +}; + +#ifndef OBJ_CASE_INSENSITIVE +#define OBJ_CASE_INSENSITIVE 0x00000040 +#endif +#ifndef OBJ_DONT_REPARSE +#define OBJ_DONT_REPARSE 0x00001000 +#endif + +#ifndef FILE_SUPERSEDE +#define FILE_SUPERSEDE 0x00000000 +#endif +#ifndef FILE_OPEN +#define FILE_OPEN 0x00000001 +#endif +#ifndef FILE_CREATE +#define FILE_CREATE 0x00000002 +#endif +#ifndef FILE_OPEN_IF +#define FILE_OPEN_IF 0x00000003 +#endif +#ifndef FILE_OVERWRITE +#define FILE_OVERWRITE 0x00000004 +#endif +#ifndef FILE_OVERWRITE_IF +#define FILE_OVERWRITE_IF 0x00000005 +#endif + +#ifndef FILE_DIRECTORY_FILE +#define FILE_DIRECTORY_FILE 0x00000001 +#endif +#ifndef FILE_SYNCHRONOUS_IO_NONALERT +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#endif +#ifndef FILE_OPEN_FOR_BACKUP_INTENT +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#endif +#ifndef FILE_OPEN_REPARSE_POINT +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#endif + +//! NtCreateFile signature. Available since Windows 2000 (probably). +typedef boost::winapi::NTSTATUS_ (NTAPI NtCreateFile_t)( + /*out*/ PHANDLE FileHandle, + /*in*/ ACCESS_MASK DesiredAccess, + /*in*/ object_attributes* ObjectAttributes, + /*out*/ io_status_block* IoStatusBlock, + /*in, optional*/ PLARGE_INTEGER AllocationSize, + /*in*/ ULONG FileAttributes, + /*in*/ ULONG ShareAccess, + /*in*/ ULONG CreateDisposition, + /*in*/ ULONG CreateOptions, + /*in, optional*/ PVOID EaBuffer, + /*in*/ ULONG EaLength); + +extern NtCreateFile_t* nt_create_file_api; + +//! PIO_APC_ROUTINE definition from Windows SDK +typedef VOID (NTAPI* pio_apc_routine) (PVOID ApcContext, io_status_block* IoStatusBlock, ULONG Reserved); + +//! FILE_INFORMATION_CLASS enum entries +enum file_information_class +{ + file_directory_information_class = 1 +}; + +//! NtQueryDirectoryFile signature. Available since Windows NT 4.0 (probably). +typedef boost::winapi::NTSTATUS_ (NTAPI NtQueryDirectoryFile_t)( + /*in*/ HANDLE FileHandle, + /*in, optional*/ HANDLE Event, + /*in, optional*/ pio_apc_routine ApcRoutine, + /*in, optional*/ PVOID ApcContext, + /*out*/ io_status_block* IoStatusBlock, + /*out*/ PVOID FileInformation, + /*in*/ ULONG Length, + /*in*/ file_information_class FileInformationClass, + /*in*/ BOOLEAN ReturnSingleEntry, + /*in, optional*/ unicode_string* FileName, + /*in*/ BOOLEAN RestartScan); + +extern NtQueryDirectoryFile_t* nt_query_directory_file_api; + +#endif // !defined(UNDER_CE) + +//! FILE_INFO_BY_HANDLE_CLASS enum entries +enum file_info_by_handle_class +{ + file_basic_info_class = 0, + file_disposition_info_class = 4, + file_attribute_tag_info_class = 9, + file_id_both_directory_info_class = 10, + file_id_both_directory_restart_info_class = 11, + file_full_directory_info_class = 14, + file_full_directory_restart_info_class = 15, + file_id_extd_directory_info_class = 19, + file_id_extd_directory_restart_info_class = 20, + file_disposition_info_ex_class = 21 +}; + +//! FILE_ATTRIBUTE_TAG_INFO definition from Windows SDK +struct file_attribute_tag_info +{ + DWORD FileAttributes; + DWORD ReparseTag; +}; + +//! GetFileInformationByHandleEx signature. Available since Windows Vista. +typedef BOOL (WINAPI GetFileInformationByHandleEx_t)( + /*__in*/ HANDLE hFile, + /*__in*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum + /*__out_bcount(dwBufferSize)*/ LPVOID lpFileInformation, + /*__in*/ DWORD dwBufferSize); + +extern GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api; + +//! HANDLE wrapper that automatically closes the handle +struct handle_wrapper +{ + HANDLE handle; + + handle_wrapper() BOOST_NOEXCEPT : handle(INVALID_HANDLE_VALUE) {} + explicit handle_wrapper(HANDLE h) BOOST_NOEXCEPT : handle(h) {} + ~handle_wrapper() BOOST_NOEXCEPT + { + if (handle != INVALID_HANDLE_VALUE) + ::CloseHandle(handle); + } + BOOST_DELETED_FUNCTION(handle_wrapper(handle_wrapper const&)) + BOOST_DELETED_FUNCTION(handle_wrapper& operator=(handle_wrapper const&)) +}; + +//! Creates a file handle +inline HANDLE create_file_handle(boost::filesystem::path const& p, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile = NULL) +{ + return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); +} + +#if !defined(UNDER_CE) +//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. +boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions); +#endif // !defined(UNDER_CE) + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include + +#endif // BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_ diff --git a/3rdparty/boost_filesystem/test/Jamfile.v2 b/3rdparty/boost_filesystem/test/Jamfile.v2 new file mode 100644 index 0000000..0abe6e4 --- /dev/null +++ b/3rdparty/boost_filesystem/test/Jamfile.v2 @@ -0,0 +1,114 @@ +# Boost Filesystem Library test Jamfile + +# (C) Copyright Beman Dawes 2002-2006 +# (C) Copyright Andrey Semashev 2020 +# Distributed under the Boost Software License, Version 1.0. +# See www.boost.org/LICENSE_1_0.txt + +import testing ; +import os ; + +# The rule checks we're running on Windows that supports mklink command (Vista and later) +rule check-mklink ( properties * ) +{ + local result ; + + if windows in $(properties) + { + # mklink is a builtin shell command, so we can't check if an executable exists. + # Testing the exit status of the mklink command (in the hope that it will be different + # when the command is not supported) is inconclusive as for some reason Windows 8.1 shell + # always returns exit code of 1. We have to match the output of the command. :( + # Note that the output may be localized, so pick some part that is likely to be stable regardless + # of localization. + local output = [ SHELL "mklink /?" : exit-status ] ; + if [ MATCH (MKLINK) : $(output[1]) ] + { + result = BOOST_FILESYSTEM_HAS_MKLINK ; + + if ! $(.annouced-mklink) + { + ECHO " - Boost.Filesystem: mklink found" ; + .annouced-mklink = 1 ; + } + } + else + { + if ! $(.annouced-mklink) + { + ECHO " - Boost.Filesystem: mklink not found" ; + .annouced-mklink = 1 ; + } + } + } + + #ECHO Result: $(result) ; + return $(result) ; +} + +project + : requirements + . + windows:_SCL_SECURE_NO_WARNINGS + windows:_SCL_SECURE_NO_DEPRECATE + windows:_CRT_SECURE_NO_WARNINGS + windows:_CRT_SECURE_NO_DEPRECATE + /boost/filesystem//boost_filesystem + @check-mklink + ; + +# Some tests are run both statically and as shared libraries since Filesystem +# has a history of bugs that appear only in one type of build or the other. + +path-constant HERE : . ; + +local VIS ; + +if [ os.environ UBSAN ] +{ + VIS = global + -/boost/filesystem//boost_filesystem + /boost/filesystem//boost_filesystem/global ; +} + +run config_info.cpp : : : shared always_show_run_output ; +run config_info.cpp : : : static always_show_run_output : config_info_static ; +run convenience_test.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +compile macro_default_test.cpp ; +run odr1_test.cpp odr2_test.cpp ; +run deprecated_test.cpp : : : BOOST_FILESYSTEM_VERSION=3 ; +run fstream_test.cpp : : : $(VIS) BOOST_FILESYSTEM_VERSION=4 ; +run cstdio_test.cpp : : : $(VIS) BOOST_FILESYSTEM_VERSION=4 ; +run large_file_support_test.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +run locale_info.cpp : : : BOOST_FILESYSTEM_VERSION=4 always_show_run_output ; +run operations_test.cpp : : : shared BOOST_FILESYSTEM_VERSION=4 always_show_run_output ; +run operations_test.cpp : : : static BOOST_FILESYSTEM_VERSION=4 : operations_test_static ; +run operations_unit_test.cpp : $(HERE) : : shared BOOST_FILESYSTEM_VERSION=4 always_show_run_output ; +run copy_test.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +compile-fail cf_path_nullptr_test.cpp ; +compile path_iter_ctor_overload_test.cpp ; +compile path_operator_ambiguity.cpp : gcc:on ; +run path_test.cpp : : : shared BOOST_FILESYSTEM_VERSION=4 ; +run path_test.cpp : : : static BOOST_FILESYSTEM_VERSION=4 : path_test_static ; +run path_test.cpp : : : shared BOOST_FILESYSTEM_VERSION=3 : path_test_v3 ; +run path_unit_test.cpp : : : shared $(VIS) BOOST_FILESYSTEM_VERSION=4 ; +run path_unit_test.cpp : : : static $(VIS) BOOST_FILESYSTEM_VERSION=4 : path_unit_test_static ; +run path_unit_test.cpp : : : shared $(VIS) BOOST_FILESYSTEM_VERSION=3 : path_unit_test_v3 ; +run relative_test.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +run ../example/simple_ls.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +run ../example/file_status.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +run foreach_test.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; + +# `quick` target (for CI) +run quick.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; + +# Tests for specific issues +run issues/70-71-copy.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; + +run issues/99_canonical_with_junction_point.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; +run issues/reparse_tag_file_placeholder.cpp : : : BOOST_FILESYSTEM_VERSION=4 ; + +if [ os.environ BOOST_FILESYSTEM_TEST_WITH_EXAMPLES ] +{ + build-project ../example ; +} diff --git a/3rdparty/boost_filesystem/test/cf_path_nullptr_test.cpp b/3rdparty/boost_filesystem/test/cf_path_nullptr_test.cpp new file mode 100644 index 0000000..09ac56d --- /dev/null +++ b/3rdparty/boost_filesystem/test/cf_path_nullptr_test.cpp @@ -0,0 +1,19 @@ +// Copyright 2023 Andrey Semashev. +// +// 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 +#include + +#if defined(BOOST_NO_CXX11_NULLPTR) +#error "This test requires support for C++11 nullptr" +#endif + +int main() +{ + boost::filesystem::path p(nullptr); + p = nullptr; +} diff --git a/3rdparty/boost_filesystem/test/config_info.cpp b/3rdparty/boost_filesystem/test/config_info.cpp new file mode 100644 index 0000000..aa36774 --- /dev/null +++ b/3rdparty/boost_filesystem/test/config_info.cpp @@ -0,0 +1,50 @@ +// boost/libs/filesystem/test/config_info.cpp ----------------------------------------// + +// Copyright Beman Dawes 2017 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include +#include +#include "macro_value.hpp" + +using std::cout; +using std::endl; + +int main() +{ + cout << "Verify macro reporting works correctly\n"; + cout << " NOSUCHMACRO: " << BOOST_MACRO_VALUE(NOSUCHMACRO) << endl; +#define SUCHAMACRO + cout << " SUCHAMACRO: " << BOOST_MACRO_VALUE(SUCHAMACRO) << endl; + cout << " BOOST_VERSION: " << BOOST_MACRO_VALUE(BOOST_VERSION) << endl; + + cout << "Report macro values that may be useful in debugging various test programs\n"; + cout << " BOOST_VERSION: " << BOOST_MACRO_VALUE(BOOST_VERSION) << endl; + cout << " BOOST_FILESYSTEM_VERSION: " << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_VERSION) << endl; + cout << " BOOST_FILESYSTEM_DEPRECATED: " << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_DEPRECATED) << endl; + cout << " BOOST_FILESYSTEM_SOURCE: " << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_SOURCE) << endl; + cout << " BOOST_FILESYSTEM_DYN_LINK: " << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_DYN_LINK) << endl; + cout << " BOOST_FILESYSTEM_STATIC_LINK: " << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_STATIC_LINK) << endl; + cout << " BOOST_ALL_NO_LIB: " << BOOST_MACRO_VALUE(BOOST_ALL_NO_LIB) << endl; + cout << " BOOST_FILESYSTEM_NO_LIB: " << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_NO_LIB) << endl; + cout << " BOOST_LIB_NAME: " << BOOST_MACRO_VALUE(BOOST_LIB_NAME) << endl; + cout << " BOOST_POSIX_API: " << BOOST_MACRO_VALUE(BOOST_POSIX_API) << endl; + cout << " BOOST_WINDOWS_API: " << BOOST_MACRO_VALUE(BOOST_WINDOWS_API) << endl; + cout << " _MSC_VER: " << BOOST_MACRO_VALUE(_MSC_VER) << endl; + cout << " __MINGW32__: " << BOOST_MACRO_VALUE(__MINGW32__) << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + //cout << " : " << BOOST_MACRO_VALUE() << endl; + + return 0; +} diff --git a/3rdparty/boost_filesystem/test/convenience_test.cpp b/3rdparty/boost_filesystem/test/convenience_test.cpp new file mode 100644 index 0000000..67de427 --- /dev/null +++ b/3rdparty/boost_filesystem/test/convenience_test.cpp @@ -0,0 +1,178 @@ +// libs/filesystem/test/convenience_test.cpp -----------------------------------------// + +// Copyright Beman Dawes, 2002 +// Copyright Vladimir Prus, 2002 +// Use, modification, and distribution is subject to 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) + +// See library home page at http://www.boost.org/libs/filesystem + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; +using fs::path; +namespace sys = boost::system; + +namespace { +template< typename F > +bool throws_fs_error(F func) +{ + try + { + func(); + } + + catch (const fs::filesystem_error&) + { + return true; + } + return false; +} + +void create_recursive_iterator(const fs::path& ph) +{ + fs::recursive_directory_iterator it(ph); +} +} // namespace + +// ------------------------------------------------------------------------------------// + +int cpp_main(int, char*[]) +{ + + // create_directories() tests --------------------------------------------------------// + + BOOST_TEST(!fs::create_directories("/")); // should be harmless + + path unique_dir = fs::unique_path(); // unique name in case tests running in parallel + path unique_yy = unique_dir / "yy"; + path unique_yya = unique_dir / "yya"; + path unique_yy_zz = unique_dir / "yy" / "zz"; + + fs::remove_all(unique_dir); // make sure slate is blank + BOOST_TEST(!fs::exists(unique_dir)); // reality check + + BOOST_TEST(fs::create_directories(unique_dir)); + BOOST_TEST(fs::exists(unique_dir)); + BOOST_TEST(fs::is_directory(unique_dir)); + + BOOST_TEST(fs::create_directories(unique_yy_zz)); + BOOST_TEST(fs::exists(unique_dir)); + BOOST_TEST(fs::exists(unique_yy)); + BOOST_TEST(fs::exists(unique_yy_zz)); + BOOST_TEST(fs::is_directory(unique_dir)); + BOOST_TEST(fs::is_directory(unique_yy)); + BOOST_TEST(fs::is_directory(unique_yy_zz)); + + path is_a_file(unique_dir / "uu"); + { + std::ofstream f(is_a_file.string().c_str()); + BOOST_TEST(!!f); + } + BOOST_TEST(throws_fs_error( + boost::bind(fs::create_directories, is_a_file))); + BOOST_TEST(throws_fs_error( + boost::bind(fs::create_directories, is_a_file / "aa"))); + + // recursive_directory_iterator tests ----------------------------------------// + + sys::error_code ec; + fs::recursive_directory_iterator it("/no-such-path", ec); + BOOST_TEST(ec); + + BOOST_TEST(throws_fs_error( + boost::bind(create_recursive_iterator, "/no-such-path"))); + + fs::remove(unique_dir / "uu"); + +#ifdef BOOST_WINDOWS_API + // These tests depends on ordering of directory entries, and that's guaranteed + // on Windows but not necessarily on other operating systems + { + std::ofstream f(unique_yya.string().c_str()); + BOOST_TEST(!!f); + } + + for (it = fs::recursive_directory_iterator(unique_dir); + it != fs::recursive_directory_iterator(); ++it) + { + std::cout << it->path() << '\n'; + } + + it = fs::recursive_directory_iterator(unique_dir); + BOOST_TEST(it->path() == unique_yy); + BOOST_TEST(it.depth() == 0); + ++it; + BOOST_TEST(it->path() == unique_yy_zz); + BOOST_TEST(it.depth() == 1); + it.pop(); + BOOST_TEST(it->path() == unique_yya); + BOOST_TEST(it.depth() == 0); + it++; + BOOST_TEST(it == fs::recursive_directory_iterator()); + + it = fs::recursive_directory_iterator(unique_dir); + BOOST_TEST(it->path() == unique_yy); + it.disable_recursion_pending(); + ++it; + BOOST_TEST(it->path() == unique_yya); + ++it; + BOOST_TEST(it == fs::recursive_directory_iterator()); + + fs::remove(unique_yya); +#endif + + it = fs::recursive_directory_iterator(unique_yy_zz); + BOOST_TEST(it == fs::recursive_directory_iterator()); + + it = fs::recursive_directory_iterator(unique_dir); + BOOST_TEST(it->path() == unique_yy); + BOOST_TEST(it.depth() == 0); + ++it; + BOOST_TEST(it->path() == unique_yy_zz); + BOOST_TEST(it.depth() == 1); + it++; + BOOST_TEST(it == fs::recursive_directory_iterator()); + + it = fs::recursive_directory_iterator(unique_dir); + BOOST_TEST(it->path() == unique_yy); + it.disable_recursion_pending(); + ++it; + BOOST_TEST(it == fs::recursive_directory_iterator()); + + it = fs::recursive_directory_iterator(unique_dir); + BOOST_TEST(it->path() == unique_yy); + ++it; + it.pop(); + BOOST_TEST(it == fs::recursive_directory_iterator()); + + ec.clear(); + BOOST_TEST(!ec); + // check that two argument failed constructor creates the end iterator + BOOST_TEST(fs::recursive_directory_iterator("nosuchdir", ec) == fs::recursive_directory_iterator()); + BOOST_TEST(ec); + + fs::remove_all(unique_dir); // clean up behind ourselves + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/copy_test.cpp b/3rdparty/boost_filesystem/test/copy_test.cpp new file mode 100644 index 0000000..af9a35c --- /dev/null +++ b/3rdparty/boost_filesystem/test/copy_test.cpp @@ -0,0 +1,340 @@ +// Copyright Andrey Semashev 2020. + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// This test verifies copy operation behavior. + +#include +#include +#include +#include +#include // for BOOST_FILESYSTEM_C_STR +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace fs = boost::filesystem; + +namespace { + +void create_file(fs::path const& ph, std::string const& contents = std::string()) +{ + std::ofstream f(BOOST_FILESYSTEM_C_STR(ph), std::ios_base::out | std::ios_base::trunc); + if (!f) + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create file: " + ph.string())); + if (!contents.empty()) + f << contents; +} + +void verify_file(fs::path const& ph, std::string const& expected) +{ + std::ifstream f(BOOST_FILESYSTEM_C_STR(ph)); + if (!f) + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open file: " + ph.string())); + std::string contents; + f >> contents; + BOOST_TEST_EQ(contents, expected); + if (contents != expected) + { + BOOST_THROW_EXCEPTION(std::runtime_error("verify_file failed: contents \"" + contents + "\" != \"" + expected + "\" in " + ph.string())); + } +} + +fs::path create_tree() +{ + fs::path root_dir = fs::unique_path(); + + fs::create_directory(root_dir); + create_file(root_dir / "f1", "f1"); + create_file(root_dir / "f2", "f2"); + + fs::create_directory(root_dir / "d1"); + create_file(root_dir / "d1/f1", "d1f1"); + + fs::create_directory(root_dir / "d1/d1"); + create_file(root_dir / "d1/d1/f1", "d1d1f1"); + + fs::create_directory(root_dir / "d1/d2"); + + fs::create_directory(root_dir / "d2"); + create_file(root_dir / "d2/f1", "d2f1"); + + return root_dir; +} + +typedef std::set< fs::path > directory_tree; + +directory_tree collect_directory_tree(fs::path const& root_dir) +{ + std::cout << "Collecting directory tree in: " << root_dir << '\n'; + + directory_tree tree; + fs::recursive_directory_iterator it(root_dir, fs::directory_options::skip_permission_denied | + fs::directory_options::follow_directory_symlink | fs::directory_options::skip_dangling_symlinks); + fs::recursive_directory_iterator end; + while (it != end) + { + fs::path p = fs::relative(it->path(), root_dir); + std::cout << p << '\n'; + tree.insert(p); + ++it; + } + + std::cout << "done." << std::endl; + + return tree; +} + +void test_copy_file_default(fs::path const& root_dir) +{ + std::cout << "test_copy_file_default" << std::endl; + + fs::path target_dir = fs::unique_path(); + fs::create_directory(target_dir); + + fs::copy(root_dir / "f1", target_dir); + fs::copy(root_dir / "f2", target_dir / "f3"); + + directory_tree tree = collect_directory_tree(target_dir); + + BOOST_TEST_EQ(tree.size(), 2u); + BOOST_TEST(tree.find("f1") != tree.end()); + BOOST_TEST(tree.find("f3") != tree.end()); + + verify_file(target_dir / "f1", "f1"); + verify_file(target_dir / "f3", "f2"); + + fs::remove_all(target_dir); +} + +void test_copy_dir_default(fs::path const& root_dir, bool with_symlinks) +{ + std::cout << "test_copy_dir_default" << std::endl; + + fs::path target_dir = fs::unique_path(); + + fs::copy(root_dir, target_dir); + + directory_tree tree = collect_directory_tree(target_dir); + + BOOST_TEST_EQ(tree.size(), 4u + with_symlinks); + BOOST_TEST(tree.find("f1") != tree.end()); + BOOST_TEST(tree.find("f2") != tree.end()); + BOOST_TEST(tree.find("d1") != tree.end()); + BOOST_TEST(tree.find("d2") != tree.end()); + if (with_symlinks) + { + BOOST_TEST(tree.find("s1") != tree.end()); + } + + verify_file(target_dir / "f1", "f1"); + verify_file(target_dir / "f2", "f2"); + + fs::remove_all(target_dir); +} + +void test_copy_dir_default_ec(fs::path const& root_dir, bool with_symlinks) +{ + // This test is similar to test_copy_dir_default, but uses an error_code overload of the operation. + // Tests for https://github.com/boostorg/filesystem/issues/152 fix. + + std::cout << "test_copy_dir_default_ec" << std::endl; + + fs::path target_dir = fs::unique_path(); + + boost::system::error_code ec; + fs::copy(root_dir, target_dir, ec); + BOOST_TEST(!ec); + + directory_tree tree = collect_directory_tree(target_dir); + + BOOST_TEST_EQ(tree.size(), 4u + with_symlinks); + BOOST_TEST(tree.find("f1") != tree.end()); + BOOST_TEST(tree.find("f2") != tree.end()); + BOOST_TEST(tree.find("d1") != tree.end()); + BOOST_TEST(tree.find("d2") != tree.end()); + if (with_symlinks) + { + BOOST_TEST(tree.find("s1") != tree.end()); + } + + verify_file(target_dir / "f1", "f1"); + verify_file(target_dir / "f2", "f2"); + + fs::remove_all(target_dir); +} + +void test_copy_dir_recursive(fs::path const& root_dir) +{ + std::cout << "test_copy_dir_recursive" << std::endl; + + fs::path target_dir = fs::unique_path(); + + fs::copy(root_dir, target_dir, fs::copy_options::recursive); + + directory_tree tree = collect_directory_tree(target_dir); + + BOOST_TEST_EQ(tree.size(), 9u); + BOOST_TEST(tree.find("f1") != tree.end()); + BOOST_TEST(tree.find("f2") != tree.end()); + BOOST_TEST(tree.find("d1") != tree.end()); + BOOST_TEST(tree.find(fs::path("d1") / "f1") != tree.end()); + BOOST_TEST(tree.find(fs::path("d1") / "d1") != tree.end()); + BOOST_TEST(tree.find(fs::path("d1") / "d1" / "f1") != tree.end()); + BOOST_TEST(tree.find(fs::path("d1") / "d2") != tree.end()); + BOOST_TEST(tree.find("d2") != tree.end()); + BOOST_TEST(tree.find(fs::path("d2") / "f1") != tree.end()); + + verify_file(target_dir / "f1", "f1"); + verify_file(target_dir / "f2", "f2"); + verify_file(target_dir / "d1/f1", "d1f1"); + verify_file(target_dir / "d1/d1/f1", "d1d1f1"); + verify_file(target_dir / "d2/f1", "d2f1"); + + fs::remove_all(target_dir); +} + +void test_copy_dir_recursive_tree(fs::path const& root_dir) +{ + std::cout << "test_copy_dir_recursive_tree" << std::endl; + + fs::path target_dir = fs::unique_path(); + + fs::copy(root_dir, target_dir, fs::copy_options::recursive | fs::copy_options::directories_only); + + directory_tree tree = collect_directory_tree(target_dir); + + BOOST_TEST_EQ(tree.size(), 4u); + BOOST_TEST(tree.find("d1") != tree.end()); + BOOST_TEST(tree.find(fs::path("d1") / "d1") != tree.end()); + BOOST_TEST(tree.find(fs::path("d1") / "d2") != tree.end()); + BOOST_TEST(tree.find("d2") != tree.end()); + + fs::remove_all(target_dir); +} + +void test_copy_file_symlinks(fs::path const& root_dir) +{ + std::cout << "test_copy_file_symlinks" << std::endl; + + fs::path target_dir = fs::unique_path(); + fs::create_directory(target_dir); + + fs::copy(root_dir / "f1", target_dir); + + fs::path prev_cur_dir = fs::current_path(); + fs::current_path(target_dir); + fs::copy(".." / root_dir / "f2", "f2", fs::copy_options::create_symlinks); + fs::current_path(prev_cur_dir); + + // Copying from a relative path with copy_options::create_symlinks to a directory other than current directory is a non-standard extension + fs::copy(target_dir / "f1", target_dir / "f3", fs::copy_options::create_symlinks); + + verify_file(target_dir / "f1", "f1"); + + fs::path link_target = fs::read_symlink(target_dir / "f2"); + if (link_target != (".." / root_dir / "f2")) + { + BOOST_ERROR("Incorrect f2 symlink in test_copy_file_symlinks"); + std::cout << (target_dir / "f2") << " => " << link_target << std::endl; + } + + link_target = fs::read_symlink(target_dir / "f3"); + if (link_target != "f1" && link_target != (fs::path(".") / "f1")) + { + BOOST_ERROR("Incorrect f3 symlink in test_copy_file_symlinks"); + std::cout << (target_dir / "f3") << " => " << link_target << std::endl; + } + + fs::remove_all(target_dir); +} + +void test_copy_errors(fs::path const& root_dir, bool symlinks_supported) +{ + std::cout << "test_copy_errors" << std::endl; + + fs::path target_dir = fs::unique_path(); + fs::create_directory(target_dir); + + BOOST_TEST_THROWS(fs::copy(root_dir / "non-existing", target_dir), fs::filesystem_error); + + create_file(target_dir / "f1"); + + BOOST_TEST_THROWS(fs::copy(root_dir / "f1", target_dir), fs::filesystem_error); + BOOST_TEST_THROWS(fs::copy(root_dir / "f1", target_dir / "f1"), fs::filesystem_error); + BOOST_TEST_THROWS(fs::copy(root_dir / "d1", target_dir / "f1"), fs::filesystem_error); + + BOOST_TEST_THROWS(fs::copy(target_dir, target_dir), fs::filesystem_error); + BOOST_TEST_THROWS(fs::copy(target_dir / "f1", target_dir / "f1"), fs::filesystem_error); + + if (symlinks_supported) + { + // Should fail with is_a_directory error code + BOOST_TEST_THROWS(fs::copy(root_dir, target_dir, fs::copy_options::create_symlinks), fs::filesystem_error); + } + + fs::remove_all(target_dir); +} + +} // namespace + +int main() +{ + try + { + fs::path root_dir = create_tree(); + + test_copy_file_default(root_dir); + test_copy_dir_default(root_dir, false); + test_copy_dir_default_ec(root_dir, false); + test_copy_dir_recursive(root_dir); + test_copy_dir_recursive_tree(root_dir); + + bool symlinks_supported = false; + try + { + fs::create_symlink("f1", root_dir / "s1"); + symlinks_supported = true; + std::cout << " *** For information only ***\n" + " create_symlink() attempt succeeded" + << std::endl; + } + catch (fs::filesystem_error& e) + { + std::cout << " *** For information only ***\n" + " create_symlink() attempt failed\n" + " filesystem_error.what() reports: " + << e.what() << "\n" + " create_symlink() may not be supported on this operating system or file system" + << std::endl; + } + + if (symlinks_supported) + { + test_copy_dir_default(root_dir, true); + test_copy_file_symlinks(root_dir); + } + + test_copy_errors(root_dir, symlinks_supported); + + fs::remove_all(root_dir); + + return boost::report_errors(); + } + catch (std::exception& e) + { + std::cout << "FAIL, exception caught: " << boost::diagnostic_information(e) << std::endl; + return 1; + } +} diff --git a/3rdparty/boost_filesystem/test/cstdio_test.cpp b/3rdparty/boost_filesystem/test/cstdio_test.cpp new file mode 100644 index 0000000..c260180 --- /dev/null +++ b/3rdparty/boost_filesystem/test/cstdio_test.cpp @@ -0,0 +1,101 @@ +// cstdio_test.cpp ------------------------------------------------------------------// + +// Copyright Andrey Semashev 2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +#include +#include +#include +#include +#include +#include +#include // for std::fclose + +#include + +#include +#include + +namespace fs = boost::filesystem; + +namespace { + +bool cleanup = true; + +class auto_fclose +{ +private: + std::FILE* m_file; + +public: + auto_fclose() BOOST_NOEXCEPT : m_file(NULL) {} + explicit auto_fclose(std::FILE* file) BOOST_NOEXCEPT : m_file(file) {} + ~auto_fclose() BOOST_NOEXCEPT + { + if (m_file) + std::fclose(m_file); + } + + std::FILE* get() const BOOST_NOEXCEPT { return m_file; } + + BOOST_DELETED_FUNCTION(auto_fclose(auto_fclose const&)) + BOOST_DELETED_FUNCTION(auto_fclose& operator=(auto_fclose const&)) +}; + +void test(fs::path const& p) +{ + fs::remove(p); + { + std::cout << " in test 1\n"; + auto_fclose file(fs::fopen(p, "w")); + BOOST_TEST(file.get() != NULL); + } + { + std::cout << " in test 2\n"; + auto_fclose file(fs::fopen(p, "r")); + BOOST_TEST(file.get() != NULL); + } + { + std::cout << " in test 3\n"; + auto_fclose file(fs::fopen(p / p.filename(), "w")); // should fail + BOOST_TEST(file.get() == NULL); + } + + if (cleanup) + fs::remove(p); +} + +} // namespace + +int cpp_main(int argc, char*[]) +{ + if (argc > 1) + cleanup = false; + + // test narrow characters + std::cout << "narrow character tests:\n"; + test("narrow_fopen_test"); + + // So that tests are run with known encoding, use Boost UTF-8 codecvt + std::locale global_loc = std::locale(); + std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet()); + fs::path::imbue(loc); + + // test with some wide characters + // \u2780 is circled 1 against white background == e2 9e 80 in UTF-8 + // \u2781 is circled 2 against white background == e2 9e 81 in UTF-8 + // \u263A is a white smiling face + std::cout << "\nwide character tests:\n"; + std::wstring ws(L"wide_fopen_test_"); + ws.push_back(static_cast< wchar_t >(0x2780)); + ws.push_back(static_cast< wchar_t >(0x263A)); + test(ws); + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/deprecated_test.cpp b/3rdparty/boost_filesystem/test/deprecated_test.cpp new file mode 100644 index 0000000..7b11496 --- /dev/null +++ b/3rdparty/boost_filesystem/test/deprecated_test.cpp @@ -0,0 +1,334 @@ +// deprecated_test program --------------------------------------------------// + +// Copyright Beman Dawes 2002 +// Copyright Vladimir Prus 2002 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// This test verifies that various deprecated names still work. This is +// important to preserve existing code that uses the old names. + +#define BOOST_FILESYSTEM_DEPRECATED +#define BOOST_FILESYSTEM_ALLOW_DEPRECATED + +#include +#include + +#include +#include + +#include +#include + +namespace fs = boost::filesystem; +using boost::filesystem::path; + +#define PATH_CHECK(a, b) check(a, b, __LINE__) + +namespace { +std::string platform(BOOST_PLATFORM); + +std::list< char > l; // see main() for initialization to s, t, r, i, n, g +std::list< wchar_t > wl; // see main() for initialization to w, s, t, r, i, n, g +std::vector< char > v; // see main() for initialization to f, u, z +std::vector< wchar_t > wv; // see main() for initialization to w, f, u, z + +void check(const fs::path& source, const std::string& expected, int line) +{ + if (source.generic_string() == expected) + return; + + ++::boost::detail::test_errors(); + + std::cout << __FILE__ << '(' << line << ") source.string(): \"" << source.string() + << "\" != expected: \"" << expected + << "\"" << std::endl; +} + +void normalize_test() +{ + PATH_CHECK(path("").normalize(), ""); + PATH_CHECK(path("/").normalize(), "/"); + PATH_CHECK(path("//").normalize(), "//"); + PATH_CHECK(path("///").normalize(), "/"); + PATH_CHECK(path("f").normalize(), "f"); + PATH_CHECK(path("foo").normalize(), "foo"); + PATH_CHECK(path("foo/").normalize(), "foo/."); + PATH_CHECK(path("f/").normalize(), "f/."); + PATH_CHECK(path("/foo").normalize(), "/foo"); + PATH_CHECK(path("foo/bar").normalize(), "foo/bar"); + PATH_CHECK(path("..").normalize(), ".."); + PATH_CHECK(path("../..").normalize(), "../.."); + PATH_CHECK(path("/..").normalize(), "/.."); + PATH_CHECK(path("/../..").normalize(), "/../.."); + PATH_CHECK(path("../foo").normalize(), "../foo"); + PATH_CHECK(path("foo/..").normalize(), "."); + PATH_CHECK(path("foo/../").normalize(), "."); + PATH_CHECK((path("foo") / "..").normalize(), "."); + PATH_CHECK(path("foo/...").normalize(), "foo/..."); + PATH_CHECK(path("foo/.../").normalize(), "foo/.../."); + PATH_CHECK(path("foo/..bar").normalize(), "foo/..bar"); + PATH_CHECK(path("../f").normalize(), "../f"); + PATH_CHECK(path("/../f").normalize(), "/../f"); + PATH_CHECK(path("f/..").normalize(), "."); + PATH_CHECK((path("f") / "..").normalize(), "."); + PATH_CHECK(path("foo/../..").normalize(), ".."); + PATH_CHECK(path("foo/../../").normalize(), "../."); + PATH_CHECK(path("foo/../../..").normalize(), "../.."); + PATH_CHECK(path("foo/../../../").normalize(), "../../."); + PATH_CHECK(path("foo/../bar").normalize(), "bar"); + PATH_CHECK(path("foo/../bar/").normalize(), "bar/."); + PATH_CHECK(path("foo/bar/..").normalize(), "foo"); + PATH_CHECK(path("foo/bar/../").normalize(), "foo/."); + PATH_CHECK(path("foo/bar/../..").normalize(), "."); + PATH_CHECK(path("foo/bar/../../").normalize(), "."); + PATH_CHECK(path("foo/bar/../blah").normalize(), "foo/blah"); + PATH_CHECK(path("f/../b").normalize(), "b"); + PATH_CHECK(path("f/b/..").normalize(), "f"); + PATH_CHECK(path("f/b/../").normalize(), "f/."); + PATH_CHECK(path("f/b/../a").normalize(), "f/a"); + PATH_CHECK(path("foo/bar/blah/../..").normalize(), "foo"); + PATH_CHECK(path("foo/bar/blah/../../bletch").normalize(), "foo/bletch"); + PATH_CHECK(path("//net").normalize(), "//net"); + PATH_CHECK(path("//net/").normalize(), "//net/"); + PATH_CHECK(path("//..net").normalize(), "//..net"); + PATH_CHECK(path("//net/..").normalize(), "//net/.."); + PATH_CHECK(path("//net/foo").normalize(), "//net/foo"); + PATH_CHECK(path("//net/foo/").normalize(), "//net/foo/."); + PATH_CHECK(path("//net/foo/..").normalize(), "//net/"); + PATH_CHECK(path("//net/foo/../").normalize(), "//net/."); + + PATH_CHECK(path("/net/foo/bar").normalize(), "/net/foo/bar"); + PATH_CHECK(path("/net/foo/bar/").normalize(), "/net/foo/bar/."); + PATH_CHECK(path("/net/foo/..").normalize(), "/net"); + PATH_CHECK(path("/net/foo/../").normalize(), "/net/."); + + PATH_CHECK(path("//net//foo//bar").normalize(), "//net/foo/bar"); + PATH_CHECK(path("//net//foo//bar//").normalize(), "//net/foo/bar/."); + PATH_CHECK(path("//net//foo//..").normalize(), "//net/"); + PATH_CHECK(path("//net//foo//..//").normalize(), "//net/."); + + PATH_CHECK(path("///net///foo///bar").normalize(), "/net/foo/bar"); + PATH_CHECK(path("///net///foo///bar///").normalize(), "/net/foo/bar/."); + PATH_CHECK(path("///net///foo///..").normalize(), "/net"); + PATH_CHECK(path("///net///foo///..///").normalize(), "/net/."); + + if (platform == "Windows") + { + PATH_CHECK(path("c:..").normalize(), "c:.."); + PATH_CHECK(path("c:foo/..").normalize(), "c:"); + + PATH_CHECK(path("c:foo/../").normalize(), "c:."); + + PATH_CHECK(path("c:/foo/..").normalize(), "c:/"); + PATH_CHECK(path("c:/foo/../").normalize(), "c:/."); + PATH_CHECK(path("c:/..").normalize(), "c:/.."); + PATH_CHECK(path("c:/../").normalize(), "c:/../."); + PATH_CHECK(path("c:/../..").normalize(), "c:/../.."); + PATH_CHECK(path("c:/../../").normalize(), "c:/../../."); + PATH_CHECK(path("c:/../foo").normalize(), "c:/../foo"); + PATH_CHECK(path("c:/../foo/").normalize(), "c:/../foo/."); + PATH_CHECK(path("c:/../../foo").normalize(), "c:/../../foo"); + PATH_CHECK(path("c:/../../foo/").normalize(), "c:/../../foo/."); + PATH_CHECK(path("c:/..foo").normalize(), "c:/..foo"); + } + else // POSIX + { + PATH_CHECK(path("c:..").normalize(), "c:.."); + PATH_CHECK(path("c:foo/..").normalize(), "."); + PATH_CHECK(path("c:foo/../").normalize(), "."); + PATH_CHECK(path("c:/foo/..").normalize(), "c:"); + PATH_CHECK(path("c:/foo/../").normalize(), "c:/."); + PATH_CHECK(path("c:/..").normalize(), "."); + PATH_CHECK(path("c:/../").normalize(), "."); + PATH_CHECK(path("c:/../..").normalize(), ".."); + PATH_CHECK(path("c:/../../").normalize(), "../."); + PATH_CHECK(path("c:/../foo").normalize(), "foo"); + PATH_CHECK(path("c:/../foo/").normalize(), "foo/."); + PATH_CHECK(path("c:/../../foo").normalize(), "../foo"); + PATH_CHECK(path("c:/../../foo/").normalize(), "../foo/."); + PATH_CHECK(path("c:/..foo").normalize(), "c:/..foo"); + } +} + +// misc_test ------------------------------------------------------------------------// + +void misc_test() +{ + fs::path p; + + fs::initial_path< fs::path >(); + fs::initial_path< fs::wpath >(); + + p.file_string(); + p.directory_string(); +} + +// path_container_ctor_test ---------------------------------------------------------// + +void path_container_ctor_test() +{ + path x4v(v); // std::vector + PATH_CHECK(x4v, "fuz"); + BOOST_TEST_EQ(x4v.native().size(), 3U); + + path x5v(wv); // std::vector + PATH_CHECK(x5v, "wfuz"); + BOOST_TEST_EQ(x5v.native().size(), 4U); + + // non-contiguous containers + path x10(l); // std::list + PATH_CHECK(x10, "string"); + BOOST_TEST_EQ(x10.native().size(), 6U); + + path xll(wl); // std::list + PATH_CHECK(xll, "wstring"); + BOOST_TEST_EQ(xll.native().size(), 7U); +} + + +// path_rename_test -----------------------------------------------------------------// + +void path_rename_test() +{ + fs::path p("foo/bar/blah"); + + BOOST_TEST_EQ(path("foo/bar/blah").remove_leaf(), "foo/bar"); + BOOST_TEST_EQ(p.leaf(), "blah"); + BOOST_TEST_EQ(p.branch_path(), "foo/bar"); + BOOST_TEST(p.has_leaf()); + BOOST_TEST(p.has_branch_path()); + BOOST_TEST(!p.is_complete()); + + if (platform == "Windows") + { + BOOST_TEST_EQ(path("foo\\bar\\blah").remove_leaf(), "foo\\bar"); + p = "foo\\bar\\blah"; + BOOST_TEST_EQ(p.branch_path(), "foo\\bar"); + } +} + +// string_file_tests ---------------------------------------------------------------// + +void string_file_tests(const fs::path& temp_dir) +{ + std::cout << "string_file_tests..." << std::endl; + std::string contents("0123456789"); + fs::path p(temp_dir / "string_file"); + save_string_file(p, contents); + save_string_file(p, contents); + BOOST_TEST_EQ(file_size(p), 10u); + std::string round_trip; + load_string_file(p, round_trip); + BOOST_TEST_EQ(contents, round_trip); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// + +int cpp_main(int /*argc*/, char* /*argv*/[]) +{ + // The choice of platform is make at runtime rather than compile-time + // so that compile errors for all platforms will be detected even though + // only the current platform is runtime tested. + platform = (platform == "Win32" || platform == "Win64" || platform == "Cygwin") ? "Windows" : "POSIX"; + std::cout << "Platform is " << platform << '\n'; + + l.push_back('s'); + l.push_back('t'); + l.push_back('r'); + l.push_back('i'); + l.push_back('n'); + l.push_back('g'); + + wl.push_back(L'w'); + wl.push_back(L's'); + wl.push_back(L't'); + wl.push_back(L'r'); + wl.push_back(L'i'); + wl.push_back(L'n'); + wl.push_back(L'g'); + + v.push_back('f'); + v.push_back('u'); + v.push_back('z'); + + wv.push_back(L'w'); + wv.push_back(L'f'); + wv.push_back(L'u'); + wv.push_back(L'z'); + + BOOST_TEST(fs::initial_path() == fs::current_path()); + + //path::default_name_check(fs::no_check); + + fs::directory_entry de("foo.bar", fs::file_status(fs::regular_file, fs::owner_all), fs::file_status(fs::directory_file, fs::group_all)); + + BOOST_TEST(de.path() == "foo.bar"); + BOOST_TEST(de.status() == fs::file_status(fs::regular_file, fs::owner_all)); + BOOST_TEST(de.symlink_status() == fs::file_status(fs::directory_file, fs::group_all)); + BOOST_TEST(de < fs::directory_entry("goo.bar", fs::file_status(), fs::file_status())); + BOOST_TEST(de == fs::directory_entry("foo.bar", fs::file_status(), fs::file_status())); + BOOST_TEST(de != fs::directory_entry("goo.bar", fs::file_status(), fs::file_status())); + de.replace_filename("bar.foo", fs::file_status(), fs::file_status()); + BOOST_TEST(de.path() == "bar.foo"); + + de.replace_leaf("", fs::file_status(), fs::file_status()); + + //de.leaf(); + //de.string(); + + fs::path ng(" no-way, Jose"); + BOOST_TEST(!fs::is_regular(ng)); // verify deprecated name still works + BOOST_TEST(!fs::symbolic_link_exists("nosuchfileordirectory")); + + const fs::path temp_dir(fs::current_path() / ".." / fs::unique_path("deprecated_test-%%%%-%%%%-%%%%")); + std::cout << "temp_dir is " << temp_dir.string() << std::endl; + + fs::create_directory(temp_dir); + + misc_test(); + path_container_ctor_test(); + path_rename_test(); + normalize_test(); + string_file_tests(temp_dir); + + BOOST_TEST(fs::path("foo/bar").generic() == fs::path("foo/bar")); + + // extension() tests ---------------------------------------------------------// + + BOOST_TEST(fs::extension("a/b") == ""); + BOOST_TEST(fs::extension("a/b.txt") == ".txt"); + BOOST_TEST(fs::extension("a/b.") == "."); + BOOST_TEST(fs::extension("a.b.c") == ".c"); + BOOST_TEST(fs::extension("a.b.c.") == "."); + BOOST_TEST(fs::extension("") == ""); + BOOST_TEST(fs::extension("a/") == ""); + + // basename() tests ----------------------------------------------------------// + + BOOST_TEST(fs::basename("b") == "b"); + BOOST_TEST(fs::basename("a/b.txt") == "b"); + BOOST_TEST(fs::basename("a/b.") == "b"); + BOOST_TEST(fs::basename("a.b.c") == "a.b"); + BOOST_TEST(fs::basename("a.b.c.") == "a.b.c"); + BOOST_TEST(fs::basename("") == ""); + + // change_extension tests ---------------------------------------------------// + + BOOST_TEST(fs::change_extension("a.txt", ".tex").string() == "a.tex"); + BOOST_TEST(fs::change_extension("a.", ".tex").string() == "a.tex"); + BOOST_TEST(fs::change_extension("a", ".txt").string() == "a.txt"); + BOOST_TEST(fs::change_extension("a.b.txt", ".tex").string() == "a.b.tex"); + // see the rationale in html docs for explanation why this works + BOOST_TEST(fs::change_extension("", ".png").string() == ".png"); + + std::cout << "post-test removal of " << temp_dir << std::endl; + BOOST_TEST(fs::remove_all(temp_dir) != 0); + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/design_use_cases.cpp b/3rdparty/boost_filesystem/test/design_use_cases.cpp new file mode 100644 index 0000000..dbbf3ed --- /dev/null +++ b/3rdparty/boost_filesystem/test/design_use_cases.cpp @@ -0,0 +1,81 @@ +#include +#include + +// Minimal class path + +class path +{ +public: + path(const char*) + { + std::cout << "path( const char * )\n"; + } + path(const std::string&) + { + std::cout << "path( std::string & )\n"; + } + +// for maximum efficiency, either signature must work +#ifdef BY_VALUE + operator const std::string() const +#else + operator const std::string&() const +#endif + { + std::cout << "operator string\n"; + return m_path; + } + +#ifdef NAMED_CONVERSION + std::string string() const + { + std::cout << "std::string string() const\n"; + return m_path; + } +#endif + +private: + std::string m_path; +}; + +bool operator==(const path&, const path&) +{ + std::cout << "operator==( const path &, const path & )\n"; + return true; +} + +// These are the critical use cases. If any of these don't compile, usability +// is unacceptably degraded. + +void f(const path&) +{ + std::cout << "f( const path & )\n"; +} + +int main() +{ + f("foo"); + f(std::string("foo")); + f(path("foo")); + + std::cout << '\n'; + + std::string s1(path("foo")); + std::string s2 = path("foo"); + s2 = path("foo"); + +#ifdef NAMED_CONVERSION + s2 = path("foo").string(); +#endif + + std::cout << '\n'; + + // these must call bool path( const path &, const path & ); + path("foo") == path("foo"); + path("foo") == "foo"; + path("foo") == std::string("foo"); + "foo" == path("foo"); + std::string("foo") == path("foo"); + + return 0; +} diff --git a/3rdparty/boost_filesystem/test/equivalent.cpp b/3rdparty/boost_filesystem/test/equivalent.cpp new file mode 100644 index 0000000..92875a7 --- /dev/null +++ b/3rdparty/boost_filesystem/test/equivalent.cpp @@ -0,0 +1,39 @@ +// equivalent program -------------------------------------------------------// + +// Copyright (c) 2004 Beman Dawes + +// Use, modification, and distribution is subject to 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) + +// See library home page at http://www.boost.org/libs/filesystem + +//----------------------------------------------------------------------------// + +#include +#include +#include + +int main(int argc, char* argv[]) +{ + boost::filesystem::path::default_name_check(boost::filesystem::native); + if (argc != 3) + { + std::cout << "Usage: equivalent path1 path2\n"; + return 2; + } + + bool eq; + try + { + eq = boost::filesystem::equivalent(argv[1], argv[2]); + } + catch (const std::exception& ex) + { + std::cout << ex.what() << "\n"; + return 3; + } + + std::cout << (eq ? "Paths are equivalent\n" : "Paths are not equivalent\n"); + return !eq; +} diff --git a/3rdparty/boost_filesystem/test/foreach_test.cpp b/3rdparty/boost_filesystem/test/foreach_test.cpp new file mode 100644 index 0000000..50a86c7 --- /dev/null +++ b/3rdparty/boost_filesystem/test/foreach_test.cpp @@ -0,0 +1,62 @@ + +// Copyright 2018 Peter Dimov. +// +// 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 + +// See library home page at http://www.boost.org/libs/filesystem + +#include +#include +#include + +namespace fs = boost::filesystem; + +int main() +{ + { + fs::directory_iterator const it; + + BOOST_FOREACH(fs::path const& p, it) + { + p.string(); + } + } + +#if !defined(BOOST_NO_CXX11_RANGE_BASED_FOR) + + { + fs::directory_iterator const it; + + for (fs::path const& p : it) + { + p.string(); + } + } + +#endif + + { + fs::recursive_directory_iterator it; + + BOOST_FOREACH(fs::path const& p, it) + { + p.string(); + } + } + +#if !defined(BOOST_NO_CXX11_RANGE_BASED_FOR) + + { + fs::recursive_directory_iterator const it; + + for (fs::path const& p : it) + { + p.string(); + } + } + +#endif +} diff --git a/3rdparty/boost_filesystem/test/fstream_test.cpp b/3rdparty/boost_filesystem/test/fstream_test.cpp new file mode 100644 index 0000000..7064418 --- /dev/null +++ b/3rdparty/boost_filesystem/test/fstream_test.cpp @@ -0,0 +1,198 @@ +// fstream_test.cpp ------------------------------------------------------------------// + +// Copyright Beman Dawes 2002 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include +#include +#include +#include +#include // for std::remove + +#include + +namespace fs = boost::filesystem; + +#include +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { +using ::remove; +} +#endif + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include +#endif + +#include +#include + +namespace { + +bool cleanup = true; + +void test(const fs::path& p) +{ + fs::remove(p); + { + std::cout << " in test 1\n"; + fs::filebuf fb1; + fb1.open(p, std::ios_base::out); + BOOST_TEST(fb1.is_open()); + } + { + std::cout << " in test 2\n"; + fs::filebuf fb2; + fb2.open(p, std::ios_base::in); + BOOST_TEST(fb2.is_open()); + } + { + std::cout << " in test 3\n"; + fs::ifstream tfs(p); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 4\n"; + fs::ifstream tfs(p / p.filename()); // should fail + BOOST_TEST(!tfs.is_open()); + } + { + std::cout << " in test 5\n"; + fs::ifstream tfs(p, std::ios_base::in); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 6\n"; + fs::ifstream tfs; + tfs.open(p); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 7\n"; + fs::ifstream tfs; + tfs.open(p, std::ios_base::in); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 8\n"; + fs::ofstream tfs(p); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 9\n"; + fs::ofstream tfs(p, std::ios_base::out); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 10\n"; + fs::ofstream tfs; + tfs.open(p); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 11\n"; + fs::ofstream tfs; + tfs.open(p, std::ios_base::out); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 12\n"; + fs::fstream tfs(p); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 13\n"; + fs::fstream tfs(p, std::ios_base::in | std::ios_base::out); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 14\n"; + fs::fstream tfs; + tfs.open(p); + BOOST_TEST(tfs.is_open()); + } + { + std::cout << " in test 15\n"; + fs::fstream tfs; + tfs.open(p, std::ios_base::in | std::ios_base::out); + BOOST_TEST(tfs.is_open()); + } + + if (cleanup) + fs::remove(p); +} + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +void test_movable() +{ + BOOST_TEST_EQ(std::is_move_constructible< fs::filebuf >::value, std::is_move_constructible< std::filebuf >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::filebuf >::value, std::is_move_assignable< std::filebuf >::value); + BOOST_TEST_EQ(std::is_move_constructible< fs::wfilebuf >::value, std::is_move_constructible< std::wfilebuf >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::wfilebuf >::value, std::is_move_assignable< std::wfilebuf >::value); + + BOOST_TEST_EQ(std::is_move_constructible< fs::ifstream >::value, std::is_move_constructible< std::ifstream >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::ifstream >::value, std::is_move_assignable< std::ifstream >::value); + BOOST_TEST_EQ(std::is_move_constructible< fs::wifstream >::value, std::is_move_constructible< std::wifstream >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::wifstream >::value, std::is_move_assignable< std::wifstream >::value); + + BOOST_TEST_EQ(std::is_move_constructible< fs::ofstream >::value, std::is_move_constructible< std::ofstream >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::ofstream >::value, std::is_move_assignable< std::ofstream >::value); + BOOST_TEST_EQ(std::is_move_constructible< fs::wofstream >::value, std::is_move_constructible< std::wofstream >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::wofstream >::value, std::is_move_assignable< std::wofstream >::value); + + BOOST_TEST_EQ(std::is_move_constructible< fs::fstream >::value, std::is_move_constructible< std::fstream >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::fstream >::value, std::is_move_assignable< std::fstream >::value); + BOOST_TEST_EQ(std::is_move_constructible< fs::wfstream >::value, std::is_move_constructible< std::wfstream >::value); + BOOST_TEST_EQ(std::is_move_assignable< fs::wfstream >::value, std::is_move_assignable< std::wfstream >::value); +} +#endif // !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +} // namespace + +int cpp_main(int argc, char*[]) +{ + if (argc > 1) + cleanup = false; + + std::cout << "BOOST_FILESYSTEM_C_STR(p) defined as \"" + << BOOST_STRINGIZE(BOOST_FILESYSTEM_C_STR(p)) << "\"\n"; + + // test narrow characters + std::cout << "narrow character tests:\n"; + test("narrow_fstream_test"); + + // So that tests are run with known encoding, use Boost UTF-8 codecvt + std::locale global_loc = std::locale(); + std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet()); + fs::path::imbue(loc); + + // test with some wide characters + // \u2780 is circled 1 against white background == e2 9e 80 in UTF-8 + // \u2781 is circled 2 against white background == e2 9e 81 in UTF-8 + // \u263A is a white smiling face + std::cout << "\nwide character tests:\n"; + std::wstring ws(L"wide_fstream_test_"); + ws.push_back(static_cast< wchar_t >(0x2780)); + ws.push_back(static_cast< wchar_t >(0x263A)); + test(ws); + +#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + test_movable(); +#endif + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/issues/10038.cpp b/3rdparty/boost_filesystem/test/issues/10038.cpp new file mode 100644 index 0000000..15b5005 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/10038.cpp @@ -0,0 +1,7 @@ +#include + +int main(void) +{ + boost::filesystem::copy_file("a", "b"); + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/10205.cpp b/3rdparty/boost_filesystem/test/issues/10205.cpp new file mode 100644 index 0000000..966d5d6 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/10205.cpp @@ -0,0 +1,17 @@ +// Linux test; before running: export LANG=foo + +#include +#include +#include +#include + +int main() +{ + std::string pathname = "/some/filesystem/path/%%%%"; + + boost::filesystem::path path(pathname); + + std::wcout << path.wstring() << std::endl; + + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/10485.cpp b/3rdparty/boost_filesystem/test/issues/10485.cpp new file mode 100644 index 0000000..aa9a03b --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/10485.cpp @@ -0,0 +1,14 @@ +// Copyright iamvfx@gmail.com 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +int main() +{ + boost::filesystem::path dir("/"); + for (char c : dir.filename().string()) + printf("%c\n", c); +} diff --git a/3rdparty/boost_filesystem/test/issues/10641.cpp b/3rdparty/boost_filesystem/test/issues/10641.cpp new file mode 100644 index 0000000..2107396 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/10641.cpp @@ -0,0 +1,22 @@ +#include +#include +using namespace std; +namespace fs = boost::filesystem; +int main(int argc, char** argv) +{ + + try + { + fs::path my_path("test/test.txt"); + cout << "current path is " << my_path << endl; + cout << "parent path is " << my_path.parent_path() << endl; + } + catch (std::exception& e) + { + cerr << endl + << "Error during execution: " << e.what() << endl + << endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/3rdparty/boost_filesystem/test/issues/11166-remove-race.cpp b/3rdparty/boost_filesystem/test/issues/11166-remove-race.cpp new file mode 100644 index 0000000..a871ad7 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/11166-remove-race.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +boost::condition_variable cond; +boost::mutex mut; + +#define FNAME ("remove-test") +void remover() +{ + while (1) + { + boost::filesystem::remove(FNAME); + } +} + +void creater() +{ + for (int i = 0; i < 100000; i++) + std::fstream(FNAME, std::fstream::out); +} + +int main() +{ + boost::filesystem::remove(FNAME); + boost::filesystem::remove(FNAME); + + std::cout << "If you got this far, it's OK to remove a file that doesn't exist\n" + "Now trying with one creator thread and two remover threads.\n" + "This is likely to crash after just a few seconds at most." + << std::endl; + + boost::thread c(creater), r1(remover), r2(remover); + + c.join(); + r1.interrupt(); + r1.join(); + r2.interrupt(); + r2.join(); +} diff --git a/3rdparty/boost_filesystem/test/issues/11228--filtered-recursive_directory_iterator-range.cpp b/3rdparty/boost_filesystem/test/issues/11228--filtered-recursive_directory_iterator-range.cpp new file mode 100644 index 0000000..4e12bb7 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/11228--filtered-recursive_directory_iterator-range.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; +using namespace boost::adaptors; + +int main() +{ + fs::recursive_directory_iterator beg("."), end; + + auto fileFilter = [](fs::path const& path) { + return is_regular_file(path); + }; + + std::vector< fs::path > paths; + copy(boost::make_iterator_range(beg, end) | filtered(fileFilter), std::back_inserter(paths)); + + for (auto& p : paths) + std::cout << p << "\n"; +} \ No newline at end of file diff --git a/3rdparty/boost_filesystem/test/issues/3332/test.cpp b/3rdparty/boost_filesystem/test/issues/3332/test.cpp new file mode 100644 index 0000000..f43acdc --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/3332/test.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; + +int main(void) +{ + + std::locale global_loc = std::locale(); + std::locale loc(global_loc, new stdext::cvt::codecvt_cp950< wchar_t >); + fs::path::imbue(loc); + + std::cout << "HEADS UP! PIPE OUTPUT TO FILE AND INSPECT WITH HEX OR CP950 EDITOR.\n" + "WINDOWS COMMAND PROMPT FONTS DON'T SUPPORT CHINESE,\n" + "EVEN WITH CODEPAGE SET AND EVEN AS OF WIN 10 TECH PREVIEW." + << std::endl; + + fs::recursive_directory_iterator end; + fs::recursive_directory_iterator iter("C:/boost/test-files/utf-8"); + + while (iter != end) + { + if (fs::is_directory(*iter)) + { + std::cout << "[directory] " << iter->path().generic_string() << std::endl; + } + else if (fs::is_regular(*iter)) + { + std::cout << " [file] " << iter->path().generic_string() << std::endl; + } + ++iter; + } + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/4329.-basename.cpp b/3rdparty/boost_filesystem/test/issues/4329.-basename.cpp new file mode 100644 index 0000000..80ba03c --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/4329.-basename.cpp @@ -0,0 +1,18 @@ +#include +#include +using boost::filesystem::path; + +int main() +{ + std::cout << path("a").stem() << std::endl; + std::cout << path("a/").stem() << std::endl; + std::cout << path("a/b").stem() << std::endl; + std::cout << path("a/b/").stem() << std::endl; + std::cout << path("a/b/c").stem() << std::endl; + std::cout << path("a/b/c/").stem() << std::endl; + std::cout << path("a/b/c/d").stem() << std::endl; + std::cout << path("a/b/c/d/").stem() << std::endl; + std::cout << path("a/b/c/d/e").stem() << std::endl; + std::cout << path("a/b/c/d/e/").stem() << std::endl; + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/5300-temp-dir-path-130.cpp b/3rdparty/boost_filesystem/test/issues/5300-temp-dir-path-130.cpp new file mode 100644 index 0000000..e69de29 diff --git a/3rdparty/boost_filesystem/test/issues/6638-global-init-fails-3.cpp b/3rdparty/boost_filesystem/test/issues/6638-global-init-fails-3.cpp new file mode 100644 index 0000000..2bedbcd --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/6638-global-init-fails-3.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +using namespace boost::filesystem; + +// The original bug report was that this broke: +// path p(L"C:\\TEMP\\"); +// path r(p / "narrow"); +// That code now works, but ... + +// Nils Gladitz has provided this example ... + +class Test +{ +public: + ~Test() + { + path p(L"C:\\TEMP\\"); + path r(p / "narrow"); + } +}; + +// path p("narrow"); + +// fails if static linked and Test object is global variable, but does not fail if +// path p("narrow") line above is not commented out, and also does not fail if the +// Test test2 line below is commented out. + +Test test1; +Test test2; + +int cpp_main(int, char*[]) +{ + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/70-71-copy.cpp b/3rdparty/boost_filesystem/test/issues/70-71-copy.cpp new file mode 100644 index 0000000..98e621b --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/70-71-copy.cpp @@ -0,0 +1,20 @@ + +// Copyright 2018 Peter Dimov. +// +// 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 + +// See library home page at http://www.boost.org/libs/filesystem + +#include +#include + +namespace fs = boost::filesystem; + +int main() +{ + BOOST_TEST_THROWS(fs::copy("/tmp/non-existent-a", "/tmp/non-existent-b"), std::exception); + return boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/issues/8930.cpp b/3rdparty/boost_filesystem/test/issues/8930.cpp new file mode 100644 index 0000000..1c3c252 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/8930.cpp @@ -0,0 +1,7 @@ +// Before running this test: export LANG=foo + +#include +int main() +{ + boost::filesystem::path("/abc").root_directory(); +} diff --git a/3rdparty/boost_filesystem/test/issues/9054_static_const_codecvt_segfault_pre_main.cpp b/3rdparty/boost_filesystem/test/issues/9054_static_const_codecvt_segfault_pre_main.cpp new file mode 100644 index 0000000..53234b4 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/9054_static_const_codecvt_segfault_pre_main.cpp @@ -0,0 +1,9 @@ +#include "boost/filesystem.hpp" + +static const boost::filesystem::path::codecvt_type& dummy = + boost::filesystem::path::codecvt(); + +int main() +{ + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/9219.cpp b/3rdparty/boost_filesystem/test/issues/9219.cpp new file mode 100644 index 0000000..7da6488 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/9219.cpp @@ -0,0 +1,40 @@ +// Boost 9219.cpp --------------------------------------------------------------------// + +// Copyright Beman Dawes 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// +// // +// In researching filesystem issues it is convenient to have a program that can be // +// quickly modified to test reported problems. That's the purpose of this file and // +// its associated Visual Studio and Boost.Build infrastructure. // +// // +//--------------------------------------------------------------------------------------// + +#include + +#include + +#include +#include +#include + +using std::cout; +using std::endl; +namespace fs = boost::filesystem; + +//------------------------------------ cpp_main --------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ + cout << "Hello, 9219" << endl; + cout << "This is a test for non-Windows systems" << endl; + + BOOST_TEST(fs::exists(const_cast< char* >("."))); + + return ::boost::report_errors(); +} // cpp_main diff --git a/3rdparty/boost_filesystem/test/issues/99_canonical_with_junction_point.cpp b/3rdparty/boost_filesystem/test/issues/99_canonical_with_junction_point.cpp new file mode 100644 index 0000000..38e3bc0 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/99_canonical_with_junction_point.cpp @@ -0,0 +1,85 @@ +// Boost operations_test.cpp ---------------------------------------------------------// + +// Copyright Alexander Grund 2020 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +#if defined(BOOST_FILESYSTEM_HAS_MKLINK) + +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; + +struct TmpDir +{ + fs::path path; + TmpDir(const fs::path& base) : + path(fs::absolute(base) / fs::unique_path()) + { + fs::create_directories(path); + } + ~TmpDir() + { + boost::system::error_code ec; + fs::remove_all(path, ec); + } +}; + +// Test fs::canonical for various path in a Windows directory junction point +// This failed before due to broken handling of absolute paths and ignored ReparseTag +int main() +{ + + const fs::path cwd = fs::current_path(); + const TmpDir tmp(cwd); + const fs::path junction = tmp.path / "junction"; + const fs::path real = tmp.path / "real"; + const fs::path subDir = "sub"; + fs::create_directories(real / subDir); + fs::current_path(tmp.path); + BOOST_TEST(std::system("mklink /J junction real") == 0); + BOOST_TEST(fs::exists(junction)); + + // Due to a bug there was a dependency on the current path so try the below for all: + std::vector< fs::path > paths; + paths.push_back(cwd); + paths.push_back(junction); + paths.push_back(real); + paths.push_back(junction / subDir); + paths.push_back(real / subDir); + for (std::vector< fs::path >::iterator it = paths.begin(); it != paths.end(); ++it) + { + std::cout << "Testing in " << *it << std::endl; + fs::current_path(*it); + + // Used by canonical, must work too + BOOST_TEST(fs::read_symlink(junction) == real); + + BOOST_TEST(fs::canonical(junction) == real); + BOOST_TEST(fs::canonical(junction / subDir) == real / subDir); + } + + // Restore the original current directory so that temp directory can be removed + fs::current_path(cwd); + + return boost::report_errors(); +} + +#else // defined(BOOST_FILESYSTEM_HAS_MKLINK) + +int main() +{ + std::cout << "Skipping test as the target system does not support mklink." << std::endl; + return 0; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_MKLINK) diff --git a/3rdparty/boost_filesystem/test/issues/Jamfile.v2 b/3rdparty/boost_filesystem/test/issues/Jamfile.v2 new file mode 100644 index 0000000..47fce40 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/Jamfile.v2 @@ -0,0 +1,38 @@ +# Boost Filesystem test/issues Jamfile + +# Copyright Beman Dawes 2014 + +# Distributed under the Boost Software License, Version 1.0. +# See www.boost.org/LICENSE_1_0.txt + +# Library home page: http://www.boost.org/libs/filesystem + +project + : requirements + /boost/filesystem//boost_filesystem + static + ; + + test-suite "filesystem-issues" : +# [ run 9054_static_const_codecvt_segfault_pre_main.cpp +# : : : shared : 9054_shared ] +# [ run 9054_static_const_codecvt_segfault_pre_main.cpp +# : : : static : 9054_static ] +# [ run hello_filesystem.cpp +# : : : shared : hello_shared ] +# [ run hello_filesystem.cpp +# : : : static : hello_static ] +# [ run 9219.cpp +# : : : shared : 9219_shared ] +# [ run 9219.cpp +# : : : static : 9219_static ] +# [ run 10485.cpp +# : : : shared always_show_run_output ] +# [ run copy_file-compilation-error-2015-05-04.cpp ] + [ run 6638-convert_aux-fails-init-global.cpp + : : : shared : 6638_shared ] + [ run 6638-convert_aux-fails-init-global.cpp + : : : static : 6638_static ] + + ; + diff --git a/3rdparty/boost_filesystem/test/issues/boost-no-inspect b/3rdparty/boost_filesystem/test/issues/boost-no-inspect new file mode 100644 index 0000000..e69de29 diff --git a/3rdparty/boost_filesystem/test/issues/copy_file-compilation-error-2015-05-04.cpp b/3rdparty/boost_filesystem/test/issues/copy_file-compilation-error-2015-05-04.cpp new file mode 100644 index 0000000..8c2ea39 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/copy_file-compilation-error-2015-05-04.cpp @@ -0,0 +1,14 @@ +// Rob Conde reports this fails +// to compile for Boost 1.58 with g++ 4.4.7 but is OK with FC++ 2013 + +#include "boost/filesystem/operations.hpp" + +void myFunc() +{ + using namespace boost::filesystem; + + copy_options opt(copy_options::overwrite_existing); + + copy_file(path("p1"), path("p2"), copy_options::overwrite_existing); + // copy_file(path("p1"),path("p2"),opt); +} \ No newline at end of file diff --git a/3rdparty/boost_filesystem/test/issues/fchmodat_AT_SYMLINK_NOFOLLOW_6659.cpp b/3rdparty/boost_filesystem/test/issues/fchmodat_AT_SYMLINK_NOFOLLOW_6659.cpp new file mode 100644 index 0000000..ea5a619 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/fchmodat_AT_SYMLINK_NOFOLLOW_6659.cpp @@ -0,0 +1,41 @@ +// Test program to demonstrate that Linux does not support AT_SYMLINK_NOFOLLOW + +// Copyright Duncan Exon Smith 2012 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Test this by running: +// +// rm -rf data && mkdir data && g++ -otest-fchmodat fchmodat_AT_SYMLINK_NOFOLLOW_6659.cpp && (cd data && ../test-fchmodat) +// +// If no assertions go off, then it looks like fchmodat is supported, +// but AT_SYMLINK_NOFOLLOW is not supported. + +#include +#include +#include +#include +#include + +#ifdef NDEBUG +#error This program depends on assert() so makes no sense if NDEBUG is defined +#endif + +int main(int argc, char* argv[]) +{ + { + std::ofstream file("out"); + file << "contents"; + } + + assert(!::symlink("out", "sym")); + + assert(!::fchmodat(AT_FDCWD, "out", S_IRUSR | S_IWUSR | S_IXUSR, 0)); + assert(!::fchmodat(AT_FDCWD, "sym", S_IRUSR | S_IWUSR | S_IXUSR, 0)); + + assert(::fchmodat(AT_FDCWD, "sym", S_IRUSR | S_IWUSR | S_IXUSR, AT_SYMLINK_NOFOLLOW) == -1); + assert(errno == ENOTSUP); + + return 0; +} diff --git a/3rdparty/boost_filesystem/test/issues/hello_filesystem.cpp b/3rdparty/boost_filesystem/test/issues/hello_filesystem.cpp new file mode 100644 index 0000000..69124e5 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/hello_filesystem.cpp @@ -0,0 +1,39 @@ +// Boost hello_filesystem.cpp --------------------------------------------------------// + +// Copyright Beman Dawes 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// +// // +// In researching filesystem issues it is convenient to have a program that can be // +// quickly modified to test reported problems. That's the purpose of this file and // +// its associated Visual Studio and Boost.Build infrastructure. // +// // +//--------------------------------------------------------------------------------------// + +#include + +#include + +#include +#include +#include + +using std::cout; +using std::endl; +namespace fs = boost::filesystem; + +//------------------------------------ cpp_main --------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ + cout << "Hello, filesystem world" << endl; + + BOOST_TEST(fs::exists(".")); + + return ::boost::report_errors(); +} // cpp_main diff --git a/3rdparty/boost_filesystem/test/issues/readme.txt b/3rdparty/boost_filesystem/test/issues/readme.txt new file mode 100644 index 0000000..cf8198e --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/readme.txt @@ -0,0 +1,9 @@ +This directory contains tests related to specific issues. + +The names are intended to indicate both the function or condition being tested +and the issue number. + +----- +Copyright Beman Dawes 2012 +Distributed under the Boost Software License, Version 1.0. +See http://www.boost.org/LICENSE_1_0.txt diff --git a/3rdparty/boost_filesystem/test/issues/recurse_dir_iter_5403.cpp b/3rdparty/boost_filesystem/test/issues/recurse_dir_iter_5403.cpp new file mode 100644 index 0000000..ef6d0f4 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/recurse_dir_iter_5403.cpp @@ -0,0 +1,116 @@ +// Boost Filesystem recurse_dir_iter_test.cpp ----------------------------------------// + +// Copyright Beman Dawes 2014. + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include + +#include +#include +#include +#include + +namespace fs = boost::filesystem; +using boost::system::error_code; + +#include + +using std::cout; +using std::endl; + +namespace { +typedef int errno_t; +std::string platform(BOOST_PLATFORM); +bool report_throws = false; +bool cleanup = true; +bool skip_long_windows_tests = false; + +} // unnamed namespace + +//------------------------------------------------------------------------------------// +// // +// main // +// // +//------------------------------------------------------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ + // document state of critical macros +#ifdef BOOST_POSIX_API + cout << "BOOST_POSIX_API is defined\n"; +#endif +#ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API is defined\n"; +#endif + + for (; argc > 1; --argc, ++argv) + { + //if (*argv[1]=='-' && *(argv[1]+1)=='t') + // report_throws = true; + //else if (*argv[1]=='-' && *(argv[1]+1)=='x') + // cleanup = false; + //else if (*argv[1]=='-' && *(argv[1]+1)=='w') + // skip_long_windows_tests = true; + } + + // The choice of platform to test is made at runtime rather than compile-time + // so that compile errors for all platforms will be detected even though + // only the current platform is runtime tested. +#if defined(BOOST_POSIX_API) + platform = "POSIX"; +#elif defined(BOOST_WINDOWS_API) + platform = "Windows"; +#else +#error neither BOOST_POSIX_API nor BOOST_WINDOWS_API is defined. See boost/system/api_config.hpp +#endif + cout << "API is " << platform << endl; + cout << "initial_path() is " << fs::initial_path() << endl; + fs::path ip = fs::initial_path(); + + for (fs::path::const_iterator it = ip.begin(); it != ip.end(); ++it) + { + if (it != ip.begin()) + cout << ", "; + cout << *it; + } + cout << endl; + + // From the root, walk the directory tree looking for a permissions error + + fs::recursive_directory_iterator it("/"); + fs::recursive_directory_iterator end_it; + + // The increment function has an invarient that it always makes progress, + // so even if an error occurs this loop will eventually terminate. + + while (it != end_it) + { + error_code ec; + fs::path init_path = it->path(); + it.increment(ec); + if (ec) + { + cout << "initial path: " << init_path << endl; + cout << "error_code: " << ec.value() << " with msg: " << ec.message() << endl; + if (it != end_it) + cout << "post-increment path: " << it->path() << endl; + } + } + + cout << "returning from main()" << endl; + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/issues/reparse_tag_file_placeholder.cpp b/3rdparty/boost_filesystem/test/issues/reparse_tag_file_placeholder.cpp new file mode 100644 index 0000000..6c423a4 --- /dev/null +++ b/3rdparty/boost_filesystem/test/issues/reparse_tag_file_placeholder.cpp @@ -0,0 +1,169 @@ +// Boost reparse_tag_file_placeholder.cpp ---------------------------------------------------------// + +// Copyright Roman Savchenko 2020 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +#if defined(BOOST_FILESYSTEM_HAS_MKLINK) + +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef _MSC_VER +#pragma comment(lib, "Advapi32.lib") +#endif + +// Test correct boost::filesystem::status when reparse point ReparseTag set to IO_REPARSE_TAG_FILE_PLACEHOLDER +// https://docs.microsoft.com/en-us/windows/compatibility/placeholder-files?redirectedfrom=MSDN + +#if !defined(__MINGW32__) || defined(__MINGW64__) +typedef struct _REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + +#ifndef IO_REPARSE_TAG_FILE_PLACEHOLDER +#define IO_REPARSE_TAG_FILE_PLACEHOLDER (0x80000015L) +#endif + +#ifndef FSCTL_SET_REPARSE_POINT +#define FSCTL_SET_REPARSE_POINT (0x000900a4) +#endif + +#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE +#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) +#endif + +bool obtain_restore_privilege() +{ + HANDLE hToken; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + DWORD err = GetLastError(); + std::cout << "OpenProcessToken() failed with: " << err << std::endl; + return false; + } + + TOKEN_PRIVILEGES tp; + if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid)) + { + DWORD err = GetLastError(); + CloseHandle(hToken); + std::cout << "LookupPrivilegeValue() failed with: " << err << std::endl; + return false; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) + { + DWORD err = GetLastError(); + CloseHandle(hToken); + std::cout << "AdjustTokenPrivileges() failed with: " << err << std::endl; + return false; + } + + CloseHandle(hToken); + return true; +} + +bool create_io_reparse_file_placeholder(const wchar_t* name) +{ + if (!obtain_restore_privilege()) + { + return false; + } + + HANDLE hHandle = CreateFileW(name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_FLAG_OPEN_REPARSE_POINT, 0); + if (hHandle == INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError(); + std::cout << "CreateFile() failed with: " << err << std::endl; + return false; + } + + PREPARSE_DATA_BUFFER pReparse = reinterpret_cast< PREPARSE_DATA_BUFFER >(GlobalAlloc(GPTR, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)); + if (!pReparse) + { + DWORD err = GetLastError(); + CloseHandle(hHandle); + std::cout << "GlobalAlloc() failed with: " << err << std::endl; + return false; + } + //note: IO_REPARSE_TAG_FILE_PLACEHOLDER - just to show that reparse point could be not only symlink or junction + pReparse->ReparseTag = IO_REPARSE_TAG_FILE_PLACEHOLDER; + + DWORD dwLen; + bool ret = !!DeviceIoControl(hHandle, FSCTL_SET_REPARSE_POINT, pReparse, pReparse->ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwLen, NULL); + if (!ret) + { + DWORD err = GetLastError(); + std::cout << "DeviceIoControl() failed with: " << err << std::endl; + } + + CloseHandle(hHandle); + GlobalFree(pReparse); + return ret; +} + +int main() +{ + boost::filesystem::path rpt = boost::filesystem::temp_directory_path() / "reparse_point_test.txt"; + + BOOST_TEST(create_io_reparse_file_placeholder(rpt.native().c_str())); + std::cout << "Created file placeholder reparse point: " << rpt.string() << std::endl; + BOOST_TEST_NO_THROW(BOOST_TEST(boost::filesystem::status(rpt).type() == boost::filesystem::reparse_file)); + BOOST_TEST_NO_THROW(BOOST_TEST(boost::filesystem::remove(rpt))); + + return boost::report_errors(); +} + +#else // defined(BOOST_FILESYSTEM_HAS_MKLINK) + +int main() +{ + std::cout << "Skipping test as the target system does not support mklink." << std::endl; + return 0; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_MKLINK) diff --git a/3rdparty/boost_filesystem/test/large_file_support_test.cpp b/3rdparty/boost_filesystem/test/large_file_support_test.cpp new file mode 100644 index 0000000..75f4133 --- /dev/null +++ b/3rdparty/boost_filesystem/test/large_file_support_test.cpp @@ -0,0 +1,36 @@ +// Boost large_file_support_test.cpp ---------------------------------------// + +// Copyright Beman Dawes 2004. +// Use, modification, and distribution is subject to 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) + +// See library home page at http://www.boost.org/libs/filesystem + +// See deprecated_test for tests of deprecated features +#define BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED + +#include +#include + +namespace fs = boost::filesystem; + +int main() +{ + if (fs::detail::possible_large_file_size_support()) + { + std::cout << "It appears that file sizes greater that 2 gigabytes are possible\n" + "for this configuration on this platform since the operating system\n" + "does use a large enough integer type to report large file sizes.\n\n" + "Whether or not such support is actually present depends on the OS\n"; + return 0; + } + std::cout << "The operating system is using an integer type to report file sizes\n" + "that can not represent file sizes greater that 2 gigabytes (31-bits).\n" + "Thus the Filesystem Library will not correctly deal with such large\n" + "files. If you think that this operatiing system should be able to\n" + "support large files, please report the problem to the Boost developers\n" + "mailing list.\n"; + return 1; +} diff --git a/3rdparty/boost_filesystem/test/locale_info.cpp b/3rdparty/boost_filesystem/test/locale_info.cpp new file mode 100644 index 0000000..e9a8147 --- /dev/null +++ b/3rdparty/boost_filesystem/test/locale_info.cpp @@ -0,0 +1,85 @@ +// locale_info.cpp ---------------------------------------------------------// + +// Copyright Beman Dawes 2011 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +using namespace std; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) // ... Function call with parameters that may be unsafe +#endif + +namespace { +void facet_info(const locale& loc, const char* msg) +{ + cout << "has_facet >(" + << msg << ") is " + << (has_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc) ? "true\n" : "false\n"); +} + +void default_info() +{ + try + { + locale loc; + cout << "\nlocale default construction OK" << endl; + facet_info(loc, "locale()"); + } + catch (const exception& ex) + { + cout << "\nlocale default construction threw: " << ex.what() << endl; + } +} + +void null_string_info() +{ + try + { + locale loc(""); + cout << "\nlocale(\"\") construction OK" << endl; + facet_info(loc, "locale(\"\")"); + } + catch (const exception& ex) + { + cout << "\nlocale(\"\") construction threw: " << ex.what() << endl; + } +} + +void classic_info() +{ + try + { + locale loc(locale::classic()); + cout << "\nlocale(locale::classic()) copy construction OK" << endl; + facet_info(loc, "locale::classic()"); + } + catch (const exception& ex) + { + cout << "\nlocale(locale::clasic()) copy construction threw: " << ex.what() << endl; + } +} +} // namespace + +int main() +{ + const char* lang = getenv("LANG"); + cout << "\nLANG environmental variable is " + << (lang ? lang : "not present") << endl; + + default_info(); + null_string_info(); + classic_info(); + + return 0; +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/3rdparty/boost_filesystem/test/long_path_test.cpp b/3rdparty/boost_filesystem/test/long_path_test.cpp new file mode 100644 index 0000000..2503bb3 --- /dev/null +++ b/3rdparty/boost_filesystem/test/long_path_test.cpp @@ -0,0 +1,57 @@ +// long_path_test.cpp ----------------------------------------------------------------// + +// Copyright Beman Dawes 2011 + +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/btree for documentation. + +// See http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx + +#include + +#include +#include +#include + +using namespace boost::filesystem; + +#include +#include + +namespace { +} // unnamed namespace + +int cpp_main(int, char*[]) +{ + + std::string prefix("d:\\temp\\"); + std::cout << "prefix is " << prefix << '\n'; + + const std::size_t safe_size = 260 - prefix.size() - 100; // Windows MAX_PATH is 260 + + std::string safe_x_string(safe_size, 'x'); + std::string safe_y_string(safe_size, 'y'); + std::string path_escape("\\\\?\\"); + + path x_p(prefix + safe_x_string); + path y_p(path_escape + prefix + safe_x_string + "\\" + safe_y_string); + + std::cout << "x_p.native().size() is " << x_p.native().size() << '\n'; + std::cout << "y_p.native().size() is " << y_p.native().size() << '\n'; + + create_directory(x_p); + BOOST_TEST(exists(x_p)); + create_directory(y_p); + BOOST_TEST(exists(y_p)); + + //std::cout << "directory x.../y... ready for testing, where ... is " << safe_size + // << " repeats of x and y, respectively\n"; + + BOOST_TEST(exists(x_p)); + + //remove_all(x_p); + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/macro_default_test.cpp b/3rdparty/boost_filesystem/test/macro_default_test.cpp new file mode 100644 index 0000000..96d9cf9 --- /dev/null +++ b/3rdparty/boost_filesystem/test/macro_default_test.cpp @@ -0,0 +1,35 @@ +// macro_default_test program --------------------------------------------------------// + +// Copyright Beman Dawes 2012 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#undef BOOST_ALL_DYN_LINK +#undef BOOST_ALL_STATIC_LINK +#undef BOOST_FILESYSTEM_DYN_LINK +#undef BOOST_FILESYSTEM_STATIC_LINK +#undef BOOST_SYSTEM_DYN_LINK +#undef BOOST_SYSTEM_STATIC_LINK + +#ifndef BOOST_ALL_NO_LIB +#define BOOST_ALL_NO_LIB +#endif + +#include +#include + +#ifndef BOOST_FILESYSTEM_STATIC_LINK +#error BOOST_FILESYSTEM_STATIC_LINK not set by default +#endif + +#ifndef BOOST_SYSTEM_STATIC_LINK +#error BOOST_SYSTEM_STATIC_LINK not set by default +#endif + +int main() +{ + return 0; +} diff --git a/3rdparty/boost_filesystem/test/macro_value.hpp b/3rdparty/boost_filesystem/test/macro_value.hpp new file mode 100644 index 0000000..de012d1 --- /dev/null +++ b/3rdparty/boost_filesystem/test/macro_value.hpp @@ -0,0 +1,42 @@ +// boost/filesystem/detail/macro_value.hpp -------------------------------------------// + +// (C) Copyright John Maddock 2001 - 2003 +// (C) Copyright Jens Maurer 2001 +// (C) Copyright Peter Dimov 2001 +// (C) Copyright Darin Adler 2001 +// (C) Copyright Beman Dawes 2002 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_MACRO_VALUE_HPP +#define BOOST_FILESYSTEM_MACRO_VALUE_HPP + +#include +#include +#include + +namespace boost { +namespace detail { + +inline const char* macro_value(const char* name, const char* value) +{ + static const char* no_value = "[no value]"; + static const char* not_defined = "[not defined]"; + + BOOST_ASSERT_MSG(name, "name argument must not be a null pointer"); + BOOST_ASSERT_MSG(value, "value argument must not be a null pointer"); + + return strcmp(name, value + 1) ? ((*value && *(value + 1)) ? (value + 1) : no_value) : not_defined; // name == value+1 so the macro is not defined +} + +} // namespace detail +} // namespace boost + +#define BOOST_MACRO_VALUE(X) boost::detail::macro_value(#X, BOOST_STRINGIZE(=X)) + +#endif // BOOST_FILESYSTEM_MACRO_VALUE_HPP diff --git a/3rdparty/boost_filesystem/test/odr1_test.cpp b/3rdparty/boost_filesystem/test/odr1_test.cpp new file mode 100644 index 0000000..460df12 --- /dev/null +++ b/3rdparty/boost_filesystem/test/odr1_test.cpp @@ -0,0 +1,22 @@ +// Boost Filesystem odr1_test.cpp ----------------------------------------------------// + +// Copyright Beman Dawes 2014. + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +namespace boost { +namespace filesystem { +void tu2(); +} +} // namespace boost + +int main() +{ + boost::filesystem::tu2(); + return 0; +} diff --git a/3rdparty/boost_filesystem/test/odr2_test.cpp b/3rdparty/boost_filesystem/test/odr2_test.cpp new file mode 100644 index 0000000..b016382 --- /dev/null +++ b/3rdparty/boost_filesystem/test/odr2_test.cpp @@ -0,0 +1,20 @@ +// Boost Filesystem odr2_test.cpp ----------------------------------------------------// + +// Copyright Beman Dawes 2014. + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +namespace boost { +namespace filesystem { + +void tu2() +{ +} + +} // namespace filesystem +} // namespace boost diff --git a/3rdparty/boost_filesystem/test/operations_test.cpp b/3rdparty/boost_filesystem/test/operations_test.cpp new file mode 100644 index 0000000..65858a4 --- /dev/null +++ b/3rdparty/boost_filesystem/test/operations_test.cpp @@ -0,0 +1,2845 @@ +// Boost operations_test.cpp ---------------------------------------------------------// + +// Copyright Beman Dawes 2002, 2009. + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include +#include +#include +#include +#include // for BOOST_FILESYSTEM_C_STR + +#include +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; +using boost::system::error_code; +using boost::system::system_category; +using boost::system::system_error; + +#include +#include + +using std::cout; +using std::endl; + +#include +#include +#include +#include // for strncmp, etc. +#include +#include // for system(), getenv(), etc. +#ifdef BOOST_POSIX_API +#include +#endif + +#ifdef BOOST_WINDOWS_API +#include + +inline std::wstring convert(const char* c) +{ + std::string s(c); + + return std::wstring(s.begin(), s.end()); +} + +// Note: these three setenv* functions are not general solutions for the missing +// setenv* problem on VC++. See Microsoft's _putenv for that need, and ticker #7018 +// for discussion and rationale for returning void for this test program, which needs +// to work for both the MSVC Runtime and the Windows Runtime (which does not support +// _putenv). + +inline void setenv_(const char* name, const fs::path::value_type* val, int) +{ + SetEnvironmentVariableW(convert(name).c_str(), val); +} + +inline void setenv_(const char* name, const char* val, int) +{ + SetEnvironmentVariableW(convert(name).c_str(), convert(val).c_str()); +} + +inline void unsetenv_(const char* name) +{ + SetEnvironmentVariableW(convert(name).c_str(), 0); +} + +//! Sets read-only attribute on a file +inline void set_read_only(fs::path const& p) +{ + DWORD attrs = GetFileAttributesW(p.c_str()); + if (attrs == INVALID_FILE_ATTRIBUTES) + { + DWORD err = GetLastError(); + throw fs::filesystem_error("operations_test set_read_only: failed to get file attributes", p, error_code(err, system_category())); + } + + attrs |= FILE_ATTRIBUTE_READONLY; + if (!SetFileAttributesW(p.c_str(), attrs)) + { + DWORD err = GetLastError(); + throw fs::filesystem_error("operations_test set_read_only: failed to set file attributes", p, error_code(err, system_category())); + } +} + +//! Converts path to a Windows long path +inline fs::path make_long_path(fs::path const& p) +{ + fs::path lp; + // Long paths must be absolute, use preferred separators and not contain dot and dot-dot elements. + // Also, UNC paths must use the "\\?\UNC\" prefix. + fs::path np = p.lexically_normal(); + np.make_preferred(); + std::wstring rp = np.root_path().wstring(); + if (rp.size() > 4u && rp[0] == L'\\' && rp[1] == '\\' && (rp[2] == L'?' || rp[2] == L'.') && rp[3] == '\\') + lp = rp; + else if (rp.size() > 2u && rp[0] == L'\\' && rp[1] == '\\') + lp = L"\\\\?\\UNC\\" + rp.substr(2); + else + lp = L"\\\\?\\" + rp; + + lp /= np.relative_path(); + + return lp; +} + +#else + +#include // sleep +#include // allow unqualifed calls to env funcs on SunOS + +inline void setenv_(const char* name, const char* val, int ovw) +{ + setenv(name, val, ovw); +} + +inline void unsetenv_(const char* name) +{ + unsetenv(name); +} + +#endif + +#define CHECK_EXCEPTION(Functor, Expect) throws_fs_error(Functor, Expect, __LINE__) + +namespace { +typedef int errno_t; +std::string platform(BOOST_PLATFORM); +bool report_throws = false; +bool cleanup = true; +bool skip_long_windows_tests = false; + +fs::directory_iterator end_itr; +fs::path dir; +fs::path d1; +fs::path d2; +fs::path f0; +fs::path f1; +fs::path d1f1; + +bool create_symlink_ok(true); + +fs::path ng(" no-way, Jose"); + +const fs::path temp_dir(fs::unique_path("op-test-%%%%-%%%%")); + +void create_file(const fs::path& ph, const std::string& contents = std::string()) +{ + std::ofstream f(BOOST_FILESYSTEM_C_STR(ph)); + if (!f) + throw fs::filesystem_error("operations_test create_file", ph, error_code(errno, system_category())); + if (!contents.empty()) + f << contents; +} + +void verify_file(const fs::path& ph, const std::string& expected) +{ + std::ifstream f(BOOST_FILESYSTEM_C_STR(ph)); + if (!f) + throw fs::filesystem_error("operations_test verify_file", ph, error_code(errno, system_category())); + std::string contents; + f >> contents; + if (contents != expected) + throw fs::filesystem_error("operations_test verify_file contents \"" + contents + "\" != \"" + expected + "\"", ph, error_code()); +} + +template< typename F > +bool throws_fs_error(F func, errno_t en, int line) +{ + try + { + func(); + } + catch (const fs::filesystem_error& ex) + { + if (report_throws) + { + // use the what() convenience function to display exceptions + cout << "\n" + << ex.what() << "\n"; + } + if (en == 0 || en == ex.code().default_error_condition().value()) + return true; + cout + << "\nWarning: line " << line + << " exception reports default_error_condition().value() " + << ex.code().default_error_condition().value() + << ", should be " << en + << "\n value() is " << ex.code().value() + << endl; + return true; + } + return false; +} + +struct poison_category_impl : public boost::system::error_category +{ + char const* name() const BOOST_NOEXCEPT { return "poison"; } + std::string message(int) const { return "poison_category::message"; } +}; + +boost::system::error_category& poison_category() +{ + static poison_category_impl instance; + return instance; +} + +// compile-only two argument "do-the-right-thing" tests +// verifies that all overload combinations compile without error +void do_the_right_thing_tests(bool call_ = false) +{ + if (call_) + { + fs::path p; + std::string s; + const char* a = 0; + fs::copy_file(p, p); + fs::copy_file(s, p); + fs::copy_file(a, p); + fs::copy_file(p, s); + fs::copy_file(p, a); + fs::copy_file(s, s); + fs::copy_file(a, s); + fs::copy_file(s, a); + fs::copy_file(a, a); + } +} + +void bad_file_size() +{ + fs::file_size(" No way, Jose"); +} + +void bad_directory_size() +{ + fs::file_size(fs::current_path()); +} + +fs::path bad_create_directory_path; +void bad_create_directory() +{ + fs::create_directory(bad_create_directory_path); +} + +void bad_equivalent() +{ + fs::equivalent("no-such-path", "another-not-present-path"); +} + +fs::path bad_remove_dir; +void bad_remove() +{ + fs::remove(bad_remove_dir); +} + +void bad_space() +{ + fs::space("no-such-path"); +} + +class renamer +{ +public: + renamer(const fs::path& p1, const fs::path& p2) : + from(p1), to(p2) {} + void operator()() + { + fs::rename(from, to); + } + +private: + fs::path from; + fs::path to; +}; + +//------------------------------ debugging aids --------------------------------------// + +//std::ostream& operator<<(std::ostream& os, const fs::file_status& s) +//{ +// if (s.type() == fs::status_error) { os << "status_error"; } +// else if (s.type() == fs::file_not_found) { os << "file_not_found"; } +// else if (s.type() == fs::regular_file) { os << "regular_file"; } +// else if (s.type() == fs::directory_file) { os << "directory_file"; } +// else if (s.type() == fs::symlink_file) { os << "symlink_file"; } +// else if (s.type() == fs::block_file) { os << "block_file"; } +// else if (s.type() == fs::character_file) { os << "character_file"; } +// else if (s.type() == fs::fifo_file) { os << "fifo_file"; } +// else if (s.type() == fs::socket_file) { os << "socket_file"; } +// else if (s.type() == fs::reparse_file) { os << "reparse_file"; } +// else { os << "type_unknown"; } +// return os; +//} + +//void dump_tree(const fs::path & root) +//{ +// cout << "dumping tree rooted at " << root << endl; +// for (fs::recursive_directory_iterator it (root, fs::directory_options::follow_directory_symlink); +// it != fs::recursive_directory_iterator(); +// ++it) +// { +// for (int i = 0; i <= it.level(); ++i) +// cout << " "; + +// cout << it->path(); +// if (fs::is_symlink(it->path())) +// { +// cout << " [symlink]" << endl; +// } +// else +// cout << endl; +// } +//} + +// exception_tests() ---------------------------------------------------------------// + +#if defined(BOOST_GCC) && BOOST_GCC >= 80000 +#pragma GCC diagnostic push +// catching polymorphic type "X" by value - that's the intention of the test +#pragma GCC diagnostic ignored "-Wcatch-value" +#endif + +void exception_tests() +{ + cout << "exception_tests..." << endl; + bool exception_thrown; + + // catch runtime_error by value + + cout << " catch runtime_error by value" << endl; + exception_thrown = false; + try + { + fs::create_directory("no-such-dir/foo/bar"); + } + catch (std::runtime_error x) + { + exception_thrown = true; + cout << " x.what() returns \"" << x.what() << "\"" << endl; + } + BOOST_TEST(exception_thrown); + + // catch system_error by value + + cout << " catch system_error by value" << endl; + exception_thrown = false; + try + { + fs::create_directory("no-such-dir/foo/bar"); + } + catch (system_error x) + { + exception_thrown = true; + cout << " x.what() returns \"" << x.what() << "\"" << endl; + } + BOOST_TEST(exception_thrown); + + // catch filesystem_error by value + + cout << " catch filesystem_error by value" << endl; + exception_thrown = false; + try + { + fs::create_directory("no-such-dir/foo/bar"); + } + catch (fs::filesystem_error x) + { + exception_thrown = true; + cout << " x.what() returns \"" << x.what() << "\"" << endl; + } + BOOST_TEST(exception_thrown); + + // catch filesystem_error by const reference + + cout << " catch filesystem_error by const reference" << endl; + exception_thrown = false; + try + { + fs::create_directory("no-such-dir/foo/bar"); + } + catch (const fs::filesystem_error& x) + { + exception_thrown = true; + cout << " x.what() returns \"" << x.what() << "\"" << endl; + } + BOOST_TEST(exception_thrown); + + // the bound functions should throw, so CHECK_EXCEPTION() should return true + + BOOST_TEST(CHECK_EXCEPTION(bad_file_size, ENOENT)); + + if (platform == "Windows") + BOOST_TEST(CHECK_EXCEPTION(bad_directory_size, ENOENT)); + else + BOOST_TEST(CHECK_EXCEPTION(bad_directory_size, 0)); + + // test path::exception members + try + { + fs::file_size(ng); // will throw + } + catch (fs::filesystem_error& ex) + { + BOOST_TEST(ex.path1().string() == " no-way, Jose"); + } + + cout << " exception_tests complete" << endl; +} + +#if defined(BOOST_GCC) && BOOST_GCC >= 80000 +#pragma GCC diagnostic pop +#endif + +// create a directory tree that can be used by subsequent tests ---------------------// +// +// dir +// d1 +// d1f1 // an empty file +// f0 // an empty file +// f1 // a file containing "file-f1" + +void create_tree() +{ + cout << "creating test directories and files in " << dir << endl; + + // create directory d1 + BOOST_TEST(!fs::create_directory(dir)); + BOOST_TEST(!fs::is_symlink(dir)); + BOOST_TEST(!fs::is_symlink("nosuchfileordirectory")); + d1 = dir / "d1"; + BOOST_TEST(fs::create_directory(d1)); + BOOST_TEST(fs::exists(d1)); + BOOST_TEST(fs::is_directory(d1)); + BOOST_TEST(fs::is_empty(d1)); + + // create an empty file named "d1f1" + d1f1 = d1 / "d1f1"; + create_file(d1f1, ""); + BOOST_TEST(fs::exists(d1f1)); + BOOST_TEST(!fs::is_directory(d1f1)); + BOOST_TEST(fs::is_regular_file(d1f1)); + BOOST_TEST(fs::is_empty(d1f1)); + BOOST_TEST(fs::file_size(d1f1) == 0); + BOOST_TEST(fs::hard_link_count(d1f1) == 1); + + // create an empty file named "f0" + f0 = dir / "f0"; + create_file(f0, ""); + BOOST_TEST(fs::exists(f0)); + BOOST_TEST(!fs::is_directory(f0)); + BOOST_TEST(fs::is_regular_file(f0)); + BOOST_TEST(fs::is_empty(f0)); + BOOST_TEST(fs::file_size(f0) == 0); + BOOST_TEST(fs::hard_link_count(f0) == 1); + + // create a file named "f1" + f1 = dir / "f1"; + create_file(f1, "file-f1"); + BOOST_TEST(fs::exists(f1)); + BOOST_TEST(!fs::is_directory(f1)); + BOOST_TEST(fs::is_regular_file(f1)); + BOOST_TEST(fs::file_size(f1) == 7); + verify_file(f1, "file-f1"); +} + +// directory_iterator_tests --------------------------------------------------------// + +void directory_iterator_tests() +{ + cout << "directory_iterator_tests..." << endl; + + bool dir_itr_exception(false); + try + { + fs::directory_iterator it(""); + } + catch (const fs::filesystem_error&) + { + dir_itr_exception = true; + } + BOOST_TEST(dir_itr_exception); + + error_code ec; + + BOOST_TEST(!ec); + fs::directory_iterator it("", ec); + BOOST_TEST(ec); + + dir_itr_exception = false; + try + { + fs::directory_iterator itx("nosuchdirectory"); + } + catch (const fs::filesystem_error&) + { + dir_itr_exception = true; + } + BOOST_TEST(dir_itr_exception); + + ec.clear(); + fs::directory_iterator it2x("nosuchdirectory", ec); + BOOST_TEST(ec); + + dir_itr_exception = false; + try + { + error_code ecx; + fs::directory_iterator itx("nosuchdirectory", ecx); + BOOST_TEST(ecx); + BOOST_TEST(ecx == boost::system::errc::no_such_file_or_directory); + } + catch (const fs::filesystem_error&) + { + dir_itr_exception = true; + } + BOOST_TEST(!dir_itr_exception); + + // create a second directory named d2 + d2 = dir / "d2"; + fs::create_directory(d2); + BOOST_TEST(fs::exists(d2)); + BOOST_TEST(fs::is_directory(d2)); + + // test the basic operation of directory_iterators, and test that + // stepping one iterator doesn't affect a different iterator. + { + typedef std::vector< fs::directory_entry > vec_type; + vec_type vec; + + fs::directory_iterator it1(dir); + BOOST_TEST(it1 != fs::directory_iterator()); + BOOST_TEST(fs::exists(it1->status())); + vec.push_back(*it1); + BOOST_TEST(*it1 == vec[0]); + + fs::directory_iterator it2(dir); + BOOST_TEST(it2 != fs::directory_iterator()); + BOOST_TEST(*it1 == *it2); + + ++it1; + BOOST_TEST(it1 != fs::directory_iterator()); + BOOST_TEST(fs::exists(it1->status())); + BOOST_TEST(it1 != it2); + BOOST_TEST(*it1 != vec[0]); + BOOST_TEST(*it2 == vec[0]); + vec.push_back(*it1); + + ++it1; + BOOST_TEST(it1 != fs::directory_iterator()); + BOOST_TEST(fs::exists(it1->status())); + BOOST_TEST(it1 != it2); + BOOST_TEST(*it2 == vec[0]); + vec.push_back(*it1); + + ++it1; + BOOST_TEST(it1 != fs::directory_iterator()); + BOOST_TEST(fs::exists(it1->status())); + BOOST_TEST(it1 != it2); + BOOST_TEST(*it2 == vec[0]); + vec.push_back(*it1); + + ++it1; + BOOST_TEST(it1 == fs::directory_iterator()); + + BOOST_TEST(*it2 == vec[0]); + ec.clear(); + it2.increment(ec); + BOOST_TEST(!ec); + BOOST_TEST(it2 != fs::directory_iterator()); + BOOST_TEST(it1 == fs::directory_iterator()); + BOOST_TEST(*it2 == vec[1]); + ++it2; + BOOST_TEST(*it2 == vec[2]); + BOOST_TEST(it1 == fs::directory_iterator()); + ++it2; + BOOST_TEST(*it2 == vec[3]); + ++it2; + BOOST_TEST(it1 == fs::directory_iterator()); + BOOST_TEST(it2 == fs::directory_iterator()); + + // sort vec and check that the right directory entries were found + std::sort(vec.begin(), vec.end()); + + BOOST_TEST_EQ(vec[0].path().filename().string(), std::string("d1")); + BOOST_TEST_EQ(vec[1].path().filename().string(), std::string("d2")); + BOOST_TEST_EQ(vec[2].path().filename().string(), std::string("f0")); + BOOST_TEST_EQ(vec[3].path().filename().string(), std::string("f1")); + } + + { // *i++ must meet the standard's InputIterator requirements + fs::directory_iterator dir_itr(dir); + BOOST_TEST(dir_itr != fs::directory_iterator()); + fs::path p = dir_itr->path(); + BOOST_TEST((*dir_itr++).path() == p); + BOOST_TEST(dir_itr != fs::directory_iterator()); + BOOST_TEST(dir_itr->path() != p); + + // test case reported in comment to SourceForge bug tracker [937606] + // augmented to test single pass semantics of a copied iterator [#12578] + fs::directory_iterator itx(dir); + fs::directory_iterator itx2(itx); + BOOST_TEST(itx == itx2); + const fs::path p1 = (*itx++).path(); + BOOST_TEST(itx == itx2); + BOOST_TEST(itx != fs::directory_iterator()); + const fs::path p2 = (*itx++).path(); + BOOST_TEST(itx == itx2); + BOOST_TEST(p1 != p2); + ++itx; + BOOST_TEST(itx == itx2); + ++itx; + BOOST_TEST(itx == itx2); + BOOST_TEST(itx == fs::directory_iterator()); + BOOST_TEST(itx2 == fs::directory_iterator()); + } + + // Windows has a tricky special case when just the root-name is given, + // causing the rest of the path to default to the current directory. + // Reported as S/F bug [ 1259176 ] + if (platform == "Windows") + { + fs::path root_name_path(fs::current_path().root_name()); + fs::directory_iterator itx(root_name_path); + BOOST_TEST(itx != fs::directory_iterator()); + // BOOST_TEST(fs::exists((*itx).path())); + BOOST_TEST(fs::exists(itx->path())); + BOOST_TEST(itx->path().parent_path() == root_name_path); + bool found(false); + do + { + if (itx->path().filename() == temp_dir.filename()) + found = true; + } while (++itx != fs::directory_iterator()); + BOOST_TEST(found); + } + + // there was an inital bug in directory_iterator that caused premature + // close of an OS handle. This block will detect regression. + { + fs::directory_iterator di; + { + di = fs::directory_iterator(dir); + } + BOOST_TEST(++di != fs::directory_iterator()); + } + + cout << " directory_iterator_tests complete" << endl; +} + +// recursive_directory_iterator_tests ----------------------------------------------// + +int walk_tree(bool recursive) +{ + //cout << " walk_tree" << endl; + error_code ec; + int d1f1_count = 0; + for (fs::recursive_directory_iterator it(dir, recursive ? (fs::directory_options::follow_directory_symlink | fs::directory_options::skip_dangling_symlinks) : fs::directory_options::none); + it != fs::recursive_directory_iterator(); + it.increment(ec)) + { + //cout << " " << it->path() << " : " << ec << endl; + if (it->path().filename() == "d1f1") + ++d1f1_count; + } + //cout << " last error : " << ec << endl; + return d1f1_count; +} + +void recursive_directory_iterator_tests() +{ + cout << "recursive_directory_iterator_tests..." << endl; + BOOST_TEST_EQ(walk_tree(false), 1); + if (create_symlink_ok) + BOOST_TEST(walk_tree(true) > 1); + + // test iterator increment with error_code argument + cout << " with error_code argument" << endl; + boost::system::error_code ec; + int d1f1_count = 0; + fs::recursive_directory_iterator it(dir, fs::directory_options::none); + fs::recursive_directory_iterator it2(it); // test single pass shallow copy semantics + for (; + it != fs::recursive_directory_iterator(); + it.increment(ec)) + { + if (it->path().filename() == "d1f1") + ++d1f1_count; + BOOST_TEST(it == it2); // verify single pass shallow copy semantics + } + BOOST_TEST(!ec); + BOOST_TEST_EQ(d1f1_count, 1); + BOOST_TEST(it == it2); // verify single pass shallow copy semantics + + cout << " recursive_directory_iterator_tests complete" << endl; +} + +// iterator_status_tests -----------------------------------------------------------// + +void iterator_status_tests() +{ + cout << "iterator_status_tests..." << endl; + + error_code ec; + // harmless if these fail: + fs::create_symlink(dir / "f0", dir / "f0_symlink", ec); + fs::create_symlink(dir / "no such file", dir / "dangling_symlink", ec); + fs::create_directory_symlink(dir / "d1", dir / "d1_symlink", ec); + fs::create_directory_symlink(dir / "no such directory", dir / "dangling_directory_symlink", ec); + + for (fs::directory_iterator it(dir); + it != fs::directory_iterator(); ++it) + { + BOOST_TEST(fs::status(it->path()).type() == it->status().type()); + BOOST_TEST(fs::symlink_status(it->path()).type() == it->symlink_status().type()); + if (it->path().filename() == "d1") + { + BOOST_TEST(fs::is_directory(it->status())); + BOOST_TEST(fs::is_directory(it->symlink_status())); + } + else if (it->path().filename() == "d2") + { + BOOST_TEST(fs::is_directory(it->status())); + BOOST_TEST(fs::is_directory(it->symlink_status())); + } + else if (it->path().filename() == "f0") + { + BOOST_TEST(fs::is_regular_file(it->status())); + BOOST_TEST(fs::is_regular_file(it->symlink_status())); + } + else if (it->path().filename() == "f1") + { + BOOST_TEST(fs::is_regular_file(it->status())); + BOOST_TEST(fs::is_regular_file(it->symlink_status())); + } + else if (it->path().filename() == "f0_symlink") + { + BOOST_TEST(fs::is_regular_file(it->status())); + BOOST_TEST(fs::is_symlink(it->symlink_status())); + BOOST_TEST(fs::is_symlink(*it)); + } + else if (it->path().filename() == "dangling_symlink") + { + BOOST_TEST(it->status().type() == fs::file_not_found); + BOOST_TEST(fs::is_symlink(it->symlink_status())); + } + else if (it->path().filename() == "d1_symlink") + { + BOOST_TEST(fs::is_directory(it->status())); + BOOST_TEST(fs::is_symlink(it->symlink_status())); + } + else if (it->path().filename() == "dangling_directory_symlink") + { + BOOST_TEST(it->status().type() == fs::file_not_found); + BOOST_TEST(fs::is_symlink(it->symlink_status())); + } + //else + // cout << " Note: unexpected directory entry " << it->path().filename() << endl; + } +} + +// recursive_iterator_status_tests -------------------------------------------------// + +void recursive_iterator_status_tests() +{ + cout << "recursive_iterator_status_tests..." << endl; + for (fs::recursive_directory_iterator it(dir); + it != fs::recursive_directory_iterator(); + ++it) + { + BOOST_TEST(fs::status(it->path()).type() == it->status().type()); + BOOST_TEST(fs::symlink_status(it->path()).type() == it->symlink_status().type()); + } +} + +// create_hard_link_tests ----------------------------------------------------------// + +void create_hard_link_tests() +{ + cout << "create_hard_link_tests..." << endl; + + fs::path from_ph(dir / "f3"); + fs::path f1x(dir / "f1"); + + BOOST_TEST(!fs::exists(from_ph)); + BOOST_TEST(fs::exists(f1x)); + bool create_hard_link_ok(true); + try + { + fs::create_hard_link(f1x, from_ph); + } + catch (const fs::filesystem_error& ex) + { + create_hard_link_ok = false; + cout + << " *** For information only ***\n" + " create_hard_link() attempt failed\n" + " filesystem_error.what() reports: " + << ex.what() << "\n" + " create_hard_link() may not be supported on this file system\n"; + } + + if (create_hard_link_ok) + { + cout + << " *** For information only ***\n" + " create_hard_link() succeeded\n"; + BOOST_TEST(fs::exists(from_ph)); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(fs::equivalent(from_ph, f1x)); + BOOST_TEST(fs::hard_link_count(from_ph) == 2); + BOOST_TEST(fs::hard_link_count(f1x) == 2); + } + + // Although tests may be running on a FAT or other file system that does + // not support hard links, that is unusual enough that it is considered + // a test failure. + BOOST_TEST(create_hard_link_ok); + + error_code ec; + fs::create_hard_link(fs::path("doesnotexist"), fs::path("shouldnotwork"), ec); + BOOST_TEST(ec); +} + +// create_symlink_tests ------------------------------------------------------------// + +void create_symlink_tests() +{ + cout << "create_symlink_tests..." << endl; + + fs::path from_ph(dir / "f4"); + fs::path f1x(dir / "f1"); + BOOST_TEST(!fs::exists(from_ph)); + BOOST_TEST(fs::exists(f1x)); + try + { + fs::create_symlink(f1x, from_ph); + } + catch (const fs::filesystem_error& ex) + { + create_symlink_ok = false; + cout + << " *** For information only ***\n" + " create_symlink() attempt failed\n" + " filesystem_error.what() reports: " + << ex.what() << "\n" + " create_symlink() may not be supported on this operating system or file system\n"; + } + + if (create_symlink_ok) + { + cout + << " *** For information only ***\n" + " create_symlink() succeeded\n"; + BOOST_TEST(fs::exists(from_ph)); + BOOST_TEST(fs::is_symlink(from_ph)); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(fs::equivalent(from_ph, f1x)); + BOOST_TEST(fs::read_symlink(from_ph) == f1x); + + fs::file_status stat = fs::symlink_status(from_ph); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(!fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(fs::is_symlink(stat)); + + stat = fs::status(from_ph); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(!fs::is_directory(stat)); + BOOST_TEST(fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); + + // since create_symlink worked, copy_symlink should also work + fs::path symlink2_ph(dir / "symlink2"); + fs::copy_symlink(from_ph, symlink2_ph); + stat = fs::symlink_status(symlink2_ph); + BOOST_TEST(fs::is_symlink(stat)); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(!fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + } + + error_code ec = error_code(); + fs::create_symlink("doesnotexist", "", ec); + BOOST_TEST(ec); +} + +// permissions_tests ---------------------------------------------------------------// + +void permissions_tests() +{ + cout << "permissions_tests..." << endl; + + fs::path p(dir / "permissions.txt"); + create_file(p); + + if (platform == "POSIX") + { + cout << " fs::status(p).permissions() " << std::oct << fs::status(p).permissions() + << std::dec << endl; + BOOST_TEST((fs::status(p).permissions() & 0600) == 0600); // 0644, 0664 sometimes returned + + fs::permissions(p, fs::owner_all); + BOOST_TEST(fs::status(p).permissions() == fs::owner_all); + + fs::permissions(p, fs::add_perms | fs::group_all); + BOOST_TEST(fs::status(p).permissions() == (fs::owner_all | fs::group_all)); + + fs::permissions(p, fs::remove_perms | fs::group_all); + BOOST_TEST(fs::status(p).permissions() == fs::owner_all); + + // some POSIX platforms cache permissions during directory iteration, some don't + // so test that iteration finds the correct permissions + for (fs::directory_iterator itr(dir); itr != fs::directory_iterator(); ++itr) + if (itr->path().filename() == fs::path("permissions.txt")) + BOOST_TEST(itr->status().permissions() == fs::owner_all); + + if (create_symlink_ok) // only if symlinks supported + { + BOOST_TEST(fs::status(p).permissions() == fs::owner_all); + fs::path p2(dir / "permissions-symlink.txt"); + fs::create_symlink(p, p2); + cout << std::oct; + cout << " status(p).permissions() " << fs::status(p).permissions() << endl; + cout << " status(p2).permissions() " << fs::status(p).permissions() << endl; + fs::permissions(p2, fs::add_perms | fs::others_read); + cout << " status(p).permissions(): " << fs::status(p).permissions() << endl; + cout << " status(p2).permissions(): " << fs::status(p2).permissions() << endl; + cout << std::dec; + } + } + else // Windows + { + BOOST_TEST(fs::status(p).permissions() == 0666); + fs::permissions(p, fs::remove_perms | fs::group_write); + BOOST_TEST(fs::status(p).permissions() == 0444); + fs::permissions(p, fs::add_perms | fs::group_write); + BOOST_TEST(fs::status(p).permissions() == 0666); + } +} + +// rename_tests --------------------------------------------------------------------// + +void rename_tests() +{ + cout << "rename_tests..." << endl; + + fs::path f1x(dir / "f1"); + BOOST_TEST(fs::exists(f1x)); + + // error: rename a non-existent old file + BOOST_TEST(!fs::exists(d1 / "f99")); + BOOST_TEST(!fs::exists(d1 / "f98")); + renamer n1a(d1 / "f99", d1 / "f98"); + BOOST_TEST(CHECK_EXCEPTION(n1a, ENOENT)); + renamer n1b(fs::path(""), d1 / "f98"); + BOOST_TEST(CHECK_EXCEPTION(n1b, ENOENT)); + + // error: rename an existing file to "" + renamer n2(f1x, ""); + BOOST_TEST(CHECK_EXCEPTION(n2, ENOENT)); + + // rename an existing file to an existent file + create_file(dir / "ff1", "ff1"); + create_file(dir / "ff2", "ff2"); + fs::rename(dir / "ff2", dir / "ff1"); + BOOST_TEST(fs::exists(dir / "ff1")); + verify_file(dir / "ff1", "ff2"); + BOOST_TEST(!fs::exists(dir / "ff2")); + + // rename an existing file to itself + BOOST_TEST(fs::exists(dir / "f1")); + fs::rename(dir / "f1", dir / "f1"); + BOOST_TEST(fs::exists(dir / "f1")); + + // error: rename an existing directory to an existing non-empty directory + BOOST_TEST(fs::exists(dir / "f1")); + BOOST_TEST(fs::exists(d1 / "f2")); + // several POSIX implementations (cygwin, openBSD) report ENOENT instead of EEXIST, + // so we don't verify error type on the following test. + renamer n3b(dir, d1); + BOOST_TEST(CHECK_EXCEPTION(n3b, 0)); + + // error: move existing file to a nonexistent parent directory + BOOST_TEST(!fs::is_directory(dir / "f1")); + BOOST_TEST(!fs::exists(dir / "d3/f3")); + renamer n4a(dir / "f1", dir / "d3/f3"); + BOOST_TEST(CHECK_EXCEPTION(n4a, ENOENT)); + + // rename existing file in same directory + BOOST_TEST(fs::exists(d1 / "f2")); + BOOST_TEST(!fs::exists(d1 / "f50")); + fs::rename(d1 / "f2", d1 / "f50"); + BOOST_TEST(!fs::exists(d1 / "f2")); + BOOST_TEST(fs::exists(d1 / "f50")); + fs::rename(d1 / "f50", d1 / "f2"); + BOOST_TEST(fs::exists(d1 / "f2")); + BOOST_TEST(!fs::exists(d1 / "f50")); + + // move and rename an existing file to a different directory + fs::rename(d1 / "f2", d2 / "f3"); + BOOST_TEST(!fs::exists(d1 / "f2")); + BOOST_TEST(!fs::exists(d2 / "f2")); + BOOST_TEST(fs::exists(d2 / "f3")); + BOOST_TEST(!fs::is_directory(d2 / "f3")); + verify_file(d2 / "f3", "file-f1"); + fs::rename(d2 / "f3", d1 / "f2"); + BOOST_TEST(fs::exists(d1 / "f2")); + + // error: move existing directory to nonexistent parent directory + BOOST_TEST(fs::exists(d1)); + BOOST_TEST(!fs::exists(dir / "d3/d5")); + BOOST_TEST(!fs::exists(dir / "d3")); + renamer n5a(d1, dir / "d3/d5"); + BOOST_TEST(CHECK_EXCEPTION(n5a, ENOENT)); + + // rename existing directory + fs::path d3(dir / "d3"); + BOOST_TEST(fs::exists(d1)); + BOOST_TEST(fs::exists(d1 / "f2")); + BOOST_TEST(!fs::exists(d3)); + fs::rename(d1, d3); + BOOST_TEST(!fs::exists(d1)); + BOOST_TEST(fs::exists(d3)); + BOOST_TEST(fs::is_directory(d3)); + BOOST_TEST(!fs::exists(d1 / "f2")); + BOOST_TEST(fs::exists(d3 / "f2")); + fs::rename(d3, d1); + BOOST_TEST(fs::exists(d1)); + BOOST_TEST(fs::exists(d1 / "f2")); + BOOST_TEST(!fs::exists(d3)); + + // rename and move d1 to d2 / "d20" + BOOST_TEST(fs::exists(d1)); + BOOST_TEST(!fs::exists(d2 / "d20")); + BOOST_TEST(fs::exists(d1 / "f2")); + fs::rename(d1, d2 / "d20"); + BOOST_TEST(!fs::exists(d1)); + BOOST_TEST(fs::exists(d2 / "d20")); + BOOST_TEST(fs::exists(d2 / "d20" / "f2")); + fs::rename(d2 / "d20", d1); + BOOST_TEST(fs::exists(d1)); + BOOST_TEST(!fs::exists(d2 / "d20")); + BOOST_TEST(fs::exists(d1 / "f2")); +} + +// predicate_and_status_tests ------------------------------------------------------// + +void predicate_and_status_tests() +{ + cout << "predicate_and_status_tests..." << endl; + + BOOST_TEST(!fs::exists(ng)); + BOOST_TEST(!fs::is_directory(ng)); + BOOST_TEST(!fs::is_regular_file(ng)); + BOOST_TEST(!fs::is_symlink(ng)); + fs::file_status stat(fs::status(ng)); + BOOST_TEST(fs::type_present(stat)); + BOOST_TEST(fs::permissions_present(stat)); + BOOST_TEST(fs::status_known(stat)); + BOOST_TEST(!fs::exists(stat)); + BOOST_TEST(!fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); + stat = fs::status(""); + BOOST_TEST(fs::type_present(stat)); + BOOST_TEST(fs::permissions_present(stat)); + BOOST_TEST(fs::status_known(stat)); + BOOST_TEST(!fs::exists(stat)); + BOOST_TEST(!fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); + +#ifdef BOOST_WINDOWS_API + stat = fs::status(L"\\System Volume Information"); + BOOST_TEST(fs::type_present(stat)); + BOOST_TEST(fs::permissions_present(stat)); + BOOST_TEST(fs::status_known(stat)); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); +#endif // BOOST_WINDOWS_API +} + +// create_directory_tests ----------------------------------------------------------// + +void create_directory_tests() +{ + cout << "create_directory_tests..." << endl; + + error_code ec; + BOOST_TEST(!fs::create_directory("", ec)); + BOOST_TEST(ec); + +#ifdef BOOST_WINDOWS_API + ec.clear(); + BOOST_TEST(!fs::create_directory(" ", ec)); // OK on Linux + BOOST_TEST(ec); +#endif + + ec.clear(); + BOOST_TEST(!fs::create_directory("/", ec)); + BOOST_TEST(!ec); + BOOST_TEST(fs::is_directory("/")); // this is a post-condition + + ec.clear(); + BOOST_TEST(!fs::create_directory(".", ec)); + BOOST_TEST(!ec); + + ec.clear(); + BOOST_TEST(!fs::create_directory("..", ec)); + BOOST_TEST(!ec); + + // create a directory, then check it for consistency + // take extra care to report problems, since if this fails + // many subsequent tests will fail + try + { + fs::create_directory(dir); + } + + catch (const fs::filesystem_error& x) + { + cout << x.what() << "\n\n" + "***** Creating directory " + << dir << " failed. *****\n" + "***** This is a serious error that will prevent further tests *****\n" + "***** from returning useful results. Further testing is aborted. *****\n\n"; + std::exit(1); + } + + catch (...) + { + cout << "\n\n" + "***** Creating directory " + << dir << " failed. *****\n" + "***** This is a serious error that will prevent further tests *****\n" + "***** from returning useful results. Further testing is aborted. *****\n\n"; + std::exit(1); + } + + BOOST_TEST(fs::exists(dir)); + BOOST_TEST(fs::is_empty(dir)); + BOOST_TEST(fs::is_directory(dir)); + BOOST_TEST(!fs::is_regular_file(dir)); + BOOST_TEST(!fs::is_other(dir)); + BOOST_TEST(!fs::is_symlink(dir)); + fs::file_status stat = fs::status(dir); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); + + cout << " create_directory_tests complete" << endl; +} + +// current_directory_tests ---------------------------------------------------------// + +void current_directory_tests() +{ + cout << "current_directory_tests..." << endl; + + // set the current directory, then check it for consistency + fs::path original_dir = fs::current_path(); + BOOST_TEST(dir != original_dir); + fs::current_path(dir); + BOOST_TEST(fs::current_path() == dir); + BOOST_TEST(fs::current_path() != original_dir); + fs::current_path(original_dir); + BOOST_TEST(fs::current_path() == original_dir); + BOOST_TEST(fs::current_path() != dir); + + // make sure the overloads work + fs::current_path(dir.c_str()); + BOOST_TEST(fs::current_path() == dir); + BOOST_TEST(fs::current_path() != original_dir); + fs::current_path(original_dir.string()); + BOOST_TEST(fs::current_path() == original_dir); + BOOST_TEST(fs::current_path() != dir); +} + +// create_directories_tests --------------------------------------------------------// + +void create_directories_tests() +{ + cout << "create_directories_tests..." << endl; + + error_code ec; + BOOST_TEST(!fs::create_directories("", ec)); + BOOST_TEST(ec); + +#ifdef BOOST_WINDOWS_API + // Windows only test, since " " is OK on Linux as a directory name + ec.clear(); + BOOST_TEST(!fs::create_directories(" ", ec)); + BOOST_TEST(ec); +#endif + + ec.clear(); + BOOST_TEST(!fs::create_directories("/", ec)); + BOOST_TEST(!ec); + + ec.clear(); + BOOST_TEST(!fs::create_directories(".", ec)); + BOOST_TEST(!ec); + + ec.clear(); + BOOST_TEST(!fs::create_directories("..", ec)); + BOOST_TEST(!ec); + +#ifdef BOOST_POSIX_API + if (access("/", W_OK) != 0) + { + ec.clear(); + BOOST_TEST(!fs::create_directories("/foo", ec)); // may be OK on Windows + // but unlikely to be OK on POSIX, unless running as root + BOOST_TEST(ec); + } +#endif + + fs::path p = dir / "level1/." / "level2/./.." / "level3/"; + // trailing "/.", "/./..", and "/" in the above elements test ticket #7258 and + // related issues + + cout << " p is " << p << endl; + BOOST_TEST(!fs::exists(p)); + BOOST_TEST(fs::create_directories(p)); + BOOST_TEST(fs::exists(p)); + BOOST_TEST(fs::is_directory(p)); + + if (fs::exists("/permissions_test")) + { + BOOST_TEST(!fs::create_directories("/permissions_test", ec)); + BOOST_TEST(!fs::create_directories("/permissions_test/another_directory", ec)); + BOOST_TEST(ec); + } +} + +// resize_file_tests ---------------------------------------------------------------// + +void resize_file_tests() +{ + cout << "resize_file_tests..." << endl; + + fs::path p(dir / "resize_file_test.txt"); + + fs::remove(p); + create_file(p, "1234567890"); + + BOOST_TEST(fs::exists(p)); + BOOST_TEST_EQ(fs::file_size(p), 10U); + fs::resize_file(p, 5); + BOOST_TEST(fs::exists(p)); + BOOST_TEST_EQ(fs::file_size(p), 5U); + fs::resize_file(p, 15); + BOOST_TEST(fs::exists(p)); + BOOST_TEST_EQ(fs::file_size(p), 15U); + + error_code ec; + fs::resize_file("no such file", 15, ec); + BOOST_TEST(ec); +} + +// status_of_nonexistent_tests -----------------------------------------------------// + +void status_of_nonexistent_tests() +{ + cout << "status_of_nonexistent_tests..." << endl; + fs::path p("nosuch"); + BOOST_TEST(!fs::exists(p)); + BOOST_TEST(!fs::is_regular_file(p)); + BOOST_TEST(!fs::is_directory(p)); + BOOST_TEST(!fs::is_symlink(p)); + BOOST_TEST(!fs::is_other(p)); + + fs::file_status s = fs::status(p); + BOOST_TEST(!fs::exists(s)); + BOOST_TEST_EQ(s.type(), fs::file_not_found); + BOOST_TEST(fs::type_present(s)); + BOOST_TEST(!fs::is_regular_file(s)); + BOOST_TEST(!fs::is_directory(s)); + BOOST_TEST(!fs::is_symlink(s)); + BOOST_TEST(!fs::is_other(s)); + + // ticket #12574 was just user confusion, but are the tests are worth keeping + error_code ec; + BOOST_TEST(!fs::is_directory(dir / "no-such-directory", ec)); + BOOST_TEST(ec); + //cout << "error_code value: " << ec.value() << endl; + ec.clear(); + BOOST_TEST(!fs::is_directory(dir / "no-such-directory" / "bar", ec)); + BOOST_TEST(ec); + //cout << "error_code value: " << ec.value() << endl; +} + +// status_error_reporting_tests ----------------------------------------------------// + +void status_error_reporting_tests() +{ + cout << "status_error_reporting_tests..." << endl; + + error_code ec; + + // test status, ec, for existing file + ec.assign(-1, poison_category()); + BOOST_TEST(ec.value() == -1); + BOOST_TEST(&ec.category() == &poison_category()); + fs::file_status s = fs::status(".", ec); + BOOST_TEST(ec.value() == 0); + BOOST_TEST(ec.category() == system_category()); + BOOST_TEST(fs::exists(s)); + BOOST_TEST(fs::is_directory(s)); + + // test status, ec, for non-existing file + fs::path p("nosuch"); + ec.assign(-1, poison_category()); + s = fs::status(p, ec); + BOOST_TEST(ec.value() != 0); + BOOST_TEST(ec.category() == system_category()); + + BOOST_TEST(!fs::exists(s)); + BOOST_TEST_EQ(s.type(), fs::file_not_found); + BOOST_TEST(fs::type_present(s)); + BOOST_TEST(!fs::is_regular_file(s)); + BOOST_TEST(!fs::is_directory(s)); + BOOST_TEST(!fs::is_symlink(s)); + BOOST_TEST(!fs::is_other(s)); + + // test queries, ec, for existing file + ec.assign(-1, poison_category()); + BOOST_TEST(fs::exists(".", ec)); + BOOST_TEST(ec.value() == 0); + BOOST_TEST(ec.category() == system_category()); + ec.assign(-1, poison_category()); + BOOST_TEST(!fs::is_regular_file(".", ec)); + BOOST_TEST(ec.value() == 0); + BOOST_TEST(ec.category() == system_category()); + ec.assign(-1, poison_category()); + BOOST_TEST(fs::is_directory(".", ec)); + BOOST_TEST(ec.value() == 0); + BOOST_TEST(ec.category() == system_category()); + + // test queries, ec, for non-existing file + ec.assign(-1, poison_category()); + BOOST_TEST(!fs::exists(p, ec)); + BOOST_TEST(ec.value() != 0); + BOOST_TEST(ec.category() == system_category()); + ec.assign(-1, poison_category()); + BOOST_TEST(!fs::is_regular_file(p, ec)); + BOOST_TEST(ec.value() != 0); + BOOST_TEST(ec.category() == system_category()); + ec.assign(-1, poison_category()); + BOOST_TEST(!fs::is_directory(p, ec)); + BOOST_TEST(ec.value() != 0); + BOOST_TEST(ec.category() == system_category()); +} + +// remove_tests --------------------------------------------------------------------// + +void remove_tests(const fs::path& dirx) +{ + cout << "remove_tests..." << endl; + + // remove() file + fs::path f1x = dirx / "shortlife"; + BOOST_TEST(!fs::exists(f1x)); + create_file(f1x, ""); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + BOOST_TEST(fs::remove(f1x)); + BOOST_TEST(!fs::exists(f1x)); + BOOST_TEST(!fs::remove("no-such-file")); + BOOST_TEST(!fs::remove("no-such-directory/no-such-file")); + +#if defined(BOOST_WINDOWS_API) + // remove() read-only file + BOOST_TEST(!fs::exists(f1x)); + create_file(f1x, ""); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + set_read_only(f1x); + BOOST_TEST(fs::remove(f1x)); + BOOST_TEST(!fs::exists(f1x)); +#endif // defined(BOOST_WINDOWS_API) + + // remove() directory + fs::path d1x = dirx / "shortlife_dir"; + BOOST_TEST(!fs::exists(d1x)); + fs::create_directory(d1x); + BOOST_TEST(fs::exists(d1x)); + BOOST_TEST(fs::is_directory(d1x)); + BOOST_TEST(fs::is_empty(d1x)); + bad_remove_dir = dirx; + BOOST_TEST(CHECK_EXCEPTION(bad_remove, ENOTEMPTY)); + BOOST_TEST(fs::remove(d1x)); + BOOST_TEST(!fs::exists(d1x)); +} + +// remove_symlink_tests ------------------------------------------------------------// + +void remove_symlink_tests() +{ + cout << "remove_symlink_tests..." << endl; + + // remove() dangling symbolic link + fs::path link = dir / "dangling_link"; + fs::remove(link); // remove any residue from past tests + BOOST_TEST(!fs::is_symlink(link)); + BOOST_TEST(!fs::exists(link)); + fs::create_symlink("nowhere", link); + BOOST_TEST(!fs::exists(link)); + BOOST_TEST(fs::is_symlink(link)); + BOOST_TEST(fs::remove(link)); + BOOST_TEST(!fs::is_symlink(link)); + + // remove() self-refering symbolic link + link = dir / "link_to_self"; + fs::remove(link); // remove any residue from past tests + BOOST_TEST(!fs::is_symlink(link)); + BOOST_TEST(!fs::exists(link)); + fs::create_symlink(link, link); + BOOST_TEST(fs::remove(link)); + BOOST_TEST(!fs::exists(link)); + BOOST_TEST(!fs::is_symlink(link)); + + // remove() cyclic symbolic link + link = dir / "link_to_a"; + fs::path link2 = dir / "link_to_b"; + fs::remove(link); // remove any residue from past tests + fs::remove(link2); // remove any residue from past tests + BOOST_TEST(!fs::is_symlink(link)); + BOOST_TEST(!fs::exists(link)); + fs::create_symlink(link, link2); + fs::create_symlink(link2, link); + BOOST_TEST(fs::remove(link)); + BOOST_TEST(fs::remove(link2)); + BOOST_TEST(!fs::exists(link)); + BOOST_TEST(!fs::exists(link2)); + BOOST_TEST(!fs::is_symlink(link)); + + // remove() symbolic link to file + fs::path f1x = dir / "link_target"; + fs::remove(f1x); // remove any residue from past tests + BOOST_TEST(!fs::exists(f1x)); + create_file(f1x, ""); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + BOOST_TEST(fs::is_regular_file(f1x)); + link = dir / "non_dangling_link"; + fs::create_symlink(f1x, link); + BOOST_TEST(fs::exists(link)); + BOOST_TEST(!fs::is_directory(link)); + BOOST_TEST(fs::is_regular_file(link)); + BOOST_TEST(fs::is_symlink(link)); + BOOST_TEST(fs::remove(link)); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::exists(link)); + BOOST_TEST(!fs::is_symlink(link)); + BOOST_TEST(fs::remove(f1x)); + BOOST_TEST(!fs::exists(f1x)); +} + +// remove_all_tests ----------------------------------------------------------------// + +void remove_all_tests(const fs::path& dirx) +{ + cout << "remove_all_tests..." << endl; + + // remove_all() file + { + fs::path f1x = dirx / "shortlife"; + BOOST_TEST(!fs::exists(f1x)); + create_file(f1x, ""); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + BOOST_TEST_EQ(fs::remove_all(f1x), 1u); + BOOST_TEST(!fs::exists(f1x)); + BOOST_TEST_EQ(fs::remove_all("no-such-file"), 0u); + BOOST_TEST_EQ(fs::remove_all("no-such-directory/no-such-file"), 0u); + } + + // remove_all() directory tree + { + unsigned int created_count = 0u; + fs::path d1x = dirx / "shortlife_dir"; + BOOST_TEST(!fs::exists(d1x)); + fs::create_directory(d1x); + ++created_count; + BOOST_TEST(fs::exists(d1x)); + BOOST_TEST(fs::is_directory(d1x)); + + fs::path d2x = d1x / "nested_dir"; + BOOST_TEST(!fs::exists(d2x)); + fs::create_directory(d2x); + ++created_count; + BOOST_TEST(fs::exists(d2x)); + BOOST_TEST(fs::is_directory(d2x)); + + fs::path f1x = d1x / "shortlife"; + BOOST_TEST(!fs::exists(f1x)); + create_file(f1x, ""); + ++created_count; + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + +#if defined(BOOST_WINDOWS_API) + // read-only file + fs::path f2x = d1x / "shortlife_ro"; + BOOST_TEST(!fs::exists(f2x)); + create_file(f2x, ""); + ++created_count; + BOOST_TEST(fs::exists(f2x)); + BOOST_TEST(!fs::is_directory(f2x)); + set_read_only(f2x); +#endif // defined(BOOST_WINDOWS_API) + + boost::uintmax_t removed_count = fs::remove_all(d1x); + BOOST_TEST_EQ(removed_count, created_count); + + BOOST_TEST(!fs::exists(d1x)); + } +} + +// remove_all_symlink_tests --------------------------------------------------------// + +void remove_all_symlink_tests(const fs::path& dirx) +{ + cout << "remove_all_symlink_tests..." << endl; + + // External directory tree + fs::path d1x = dirx / "shortlife_dir1"; + BOOST_TEST(!fs::exists(d1x)); + fs::create_directory(d1x); + BOOST_TEST(fs::exists(d1x)); + BOOST_TEST(fs::is_directory(d1x)); + + fs::path f1x = d1x / "shortlife1"; + BOOST_TEST(!fs::exists(f1x)); + create_file(f1x, ""); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + + fs::path f2x = d1x / "shortlife2"; + BOOST_TEST(!fs::exists(f2x)); + create_file(f2x, ""); + BOOST_TEST(fs::exists(f2x)); + BOOST_TEST(!fs::is_directory(f2x)); + + // remove_all() directory tree that has symlinks to external directories + unsigned int created_count = 0u; + fs::path d2x = dirx / "shortlife_dir2"; + BOOST_TEST(!fs::exists(d2x)); + fs::create_directory(d2x); + ++created_count; + BOOST_TEST(fs::exists(d2x)); + BOOST_TEST(fs::is_directory(d2x)); + + fs::path f3x = d2x / "shortlife"; + BOOST_TEST(!fs::exists(f3x)); + create_file(f3x, ""); + ++created_count; + BOOST_TEST(fs::exists(f3x)); + BOOST_TEST(!fs::is_directory(f3x)); + + fs::path d3x = d2x / "symlink_dir"; + BOOST_TEST(!fs::exists(d3x)); + fs::create_directory_symlink(d1x, d3x); + ++created_count; + BOOST_TEST(fs::exists(d3x)); + BOOST_TEST(fs::is_symlink(d3x)); + +#if defined(BOOST_FILESYSTEM_HAS_MKLINK) + fs::path junc = d2x / "junc"; + fs::path cur_path(fs::current_path()); + fs::current_path(d2x); + BOOST_TEST(std::system("mklink /J junc ..\\shortlife_dir1") == 0); + fs::current_path(cur_path); + ++created_count; + BOOST_TEST(fs::exists(junc)); +#endif + + fs::path f4x = d2x / "symlink"; + BOOST_TEST(!fs::exists(f4x)); + fs::create_symlink(f1x, f4x); + ++created_count; + BOOST_TEST(fs::exists(f4x)); + BOOST_TEST(fs::is_symlink(f4x)); + + fs::path f5x = d2x / "hardlink"; + BOOST_TEST(!fs::exists(f5x)); + fs::create_hard_link(f2x, f5x); + ++created_count; + BOOST_TEST(fs::exists(f5x)); + BOOST_TEST(!fs::is_directory(f5x)); + + boost::uintmax_t removed_count = fs::remove_all(d2x); + BOOST_TEST_EQ(removed_count, created_count); + + BOOST_TEST(!fs::exists(d2x)); + + // Check that external directory and file are intact + BOOST_TEST(fs::exists(d1x)); + BOOST_TEST(fs::is_directory(d1x)); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + BOOST_TEST(fs::exists(f2x)); + BOOST_TEST(!fs::is_directory(f2x)); + + // Cleanup + fs::remove_all(d1x); +} + +// absolute_tests -----------------------------------------------------------------// + +void absolute_tests() +{ + cout << "absolute_tests..." << endl; + + BOOST_TEST_EQ(fs::absolute(""), fs::current_path()); + BOOST_TEST_EQ(fs::absolute("", ""), fs::current_path()); + BOOST_TEST_EQ(fs::absolute(fs::current_path() / "foo/bar"), fs::current_path() / "foo/bar"); + BOOST_TEST_EQ(fs::absolute("foo"), fs::current_path() / "foo"); + BOOST_TEST_EQ(fs::absolute("foo", fs::current_path()), fs::current_path() / "foo"); + BOOST_TEST_EQ(fs::absolute("bar", "foo"), fs::current_path() / "foo" / "bar"); + BOOST_TEST_EQ(fs::absolute("/foo"), fs::current_path().root_path().string() + "foo"); + +#ifdef BOOST_WINDOWS_API + BOOST_TEST_EQ(fs::absolute("a:foo", "b:/bar"), fs::path(L"a:/bar/foo")); +#endif + + // these tests were moved from elsewhere, so may duplicate some of the above tests + + // p.empty() + BOOST_TEST_EQ(fs::absolute(fs::path(), "//foo/bar"), fs::path("//foo/bar")); + if (platform == "Windows") + { + BOOST_TEST_EQ(fs::absolute(fs::path(), "a:/bar"), fs::path("a:/bar")); + } + + // p.has_root_name() + // p.has_root_directory() + BOOST_TEST_EQ(fs::absolute(fs::path("//foo/bar"), "//uvw/xyz"), fs::path("//foo/bar")); + if (platform == "Windows") + { + BOOST_TEST_EQ(fs::absolute(fs::path("a:/bar"), "b:/xyz"), fs::path("a:/bar")); + } + // !p.has_root_directory() + BOOST_TEST_EQ(fs::absolute(fs::path("//net"), "//xyz/"), fs::path("//net/")); + BOOST_TEST_EQ(fs::absolute(fs::path("//net"), "//xyz/abc"), fs::path("//net/abc")); + BOOST_TEST_EQ(fs::absolute(fs::path("//net"), "//xyz/abc/def"), fs::path("//net/abc/def")); + if (platform == "Windows") + { + BOOST_TEST_EQ(fs::absolute(fs::path("a:"), "b:/"), fs::path("a:/")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:"), "b:/abc"), fs::path("a:/abc")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:"), "b:/abc/def"), fs::path("a:/abc/def")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:foo"), "b:/"), fs::path("a:/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:foo"), "b:/abc"), fs::path("a:/abc/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:foo"), "b:/abc/def"), fs::path("a:/abc/def/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:foo/bar"), "b:/"), fs::path("a:/foo/bar")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:foo/bar"), "b:/abc"), fs::path("a:/abc/foo/bar")); + BOOST_TEST_EQ(fs::absolute(fs::path("a:foo/bar"), "b:/abc/def"), fs::path("a:/abc/def/foo/bar")); + BOOST_TEST_EQ(fs::absolute(fs::path("\\\\net\\share\\folder"), "c:\\"), fs::path("\\\\net\\share\\folder")); + } + // !p.has_root_name() + // p.has_root_directory() +#ifdef BOOST_WINDOWS_API + BOOST_TEST_EQ(fs::absolute(fs::path("/"), "//xyz/"), fs::path("//xyz/")); + BOOST_TEST_EQ(fs::absolute(fs::path("/"), "//xyz/abc"), fs::path("//xyz/")); + BOOST_TEST_EQ(fs::absolute(fs::path("/foo"), "//xyz/"), fs::path("//xyz/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("/foo"), "//xyz/abc"), fs::path("//xyz/foo")); +#else + BOOST_TEST_EQ(fs::absolute(fs::path("/"), "//xyz/"), fs::path("/")); + BOOST_TEST_EQ(fs::absolute(fs::path("/"), "//xyz/abc"), fs::path("/")); + BOOST_TEST_EQ(fs::absolute(fs::path("/foo"), "//xyz/"), fs::path("/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("/foo"), "//xyz/abc"), fs::path("/foo")); +#endif + // !p.has_root_directory() + BOOST_TEST_EQ(fs::absolute(fs::path("foo"), "//xyz/abc"), fs::path("//xyz/abc/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("foo/bar"), "//xyz/abc"), fs::path("//xyz/abc/foo/bar")); + BOOST_TEST_EQ(fs::absolute(fs::path("."), "//xyz/abc"), fs::path("//xyz/abc/.")); + BOOST_TEST_EQ(fs::absolute(fs::path(".."), "//xyz/abc"), fs::path("//xyz/abc/..")); + BOOST_TEST_EQ(fs::absolute(fs::path("./foo"), "//xyz/abc"), fs::path("//xyz/abc/./foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("../foo"), "//xyz/abc"), fs::path("//xyz/abc/../foo")); + if (platform == "POSIX") + { + BOOST_TEST_EQ(fs::absolute(fs::path("foo"), "/abc"), fs::path("/abc/foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("foo/bar"), "/abc"), fs::path("/abc/foo/bar")); + BOOST_TEST_EQ(fs::absolute(fs::path("."), "/abc"), fs::path("/abc/.")); + BOOST_TEST_EQ(fs::absolute(fs::path(".."), "/abc"), fs::path("/abc/..")); + BOOST_TEST_EQ(fs::absolute(fs::path("./foo"), "/abc"), fs::path("/abc/./foo")); + BOOST_TEST_EQ(fs::absolute(fs::path("../foo"), "/abc"), fs::path("/abc/../foo")); + } +} + +// canonical_basic_tests -----------------------------------------------------------// + +void canonical_basic_tests() +{ + cout << "canonical_basic_tests..." << endl; + + // error handling + error_code ec; + ec.clear(); + fs::canonical("no-such-file", ec); + BOOST_TEST(ec); + ec.clear(); + fs::canonical("no-such-file", "x", ec); + BOOST_TEST(ec); + bool ok(false); + try + { + fs::canonical("no-such-file"); + } + catch (const fs::filesystem_error&) + { + ok = true; + } + BOOST_TEST(ok); + + // non-symlink tests; also see canonical_symlink_tests() + BOOST_TEST_EQ(fs::canonical(""), fs::current_path()); + BOOST_TEST_EQ(fs::canonical("", fs::current_path()), fs::current_path()); + BOOST_TEST_EQ(fs::canonical("", ""), fs::current_path()); + BOOST_TEST_EQ(fs::canonical(fs::current_path()), fs::current_path()); + BOOST_TEST_EQ(fs::canonical(fs::current_path(), ""), fs::current_path()); + BOOST_TEST_EQ(fs::canonical(fs::current_path(), "no-such-file"), fs::current_path()); + + BOOST_TEST_EQ(fs::canonical("."), fs::current_path()); + BOOST_TEST_EQ(fs::canonical(".."), fs::current_path().parent_path()); + BOOST_TEST_EQ(fs::canonical("/"), fs::current_path().root_path()); + + fs::path relative_dir(dir.filename()); + BOOST_TEST_EQ(fs::canonical(dir), dir); + BOOST_TEST_EQ(fs::canonical(relative_dir), dir); + BOOST_TEST_EQ(fs::canonical(dir / "f0"), dir / "f0"); + BOOST_TEST_EQ(fs::canonical(relative_dir / "f0"), dir / "f0"); + BOOST_TEST_EQ(fs::canonical(relative_dir / "./f0"), dir / "f0"); + BOOST_TEST_EQ(fs::canonical(relative_dir / "d1/../f0"), dir / "f0"); + + // treat parent of root as itself on both POSIX and Windows + fs::path init(fs::initial_path()); + fs::path root(init.root_path()); + fs::path::const_iterator it(init.begin()); + fs::path first; // relative first non-root directory +#ifdef BOOST_WINDOWS_API + if (!init.empty()) + ++it; +#endif + if (++it != init.end()) + first = *it; + fs::path expected(root / first); + + cout << " init: " << init << endl; + cout << " root: " << root << endl; + cout << " first: " << first << endl; + cout << " expected: " << expected << endl; + + // ticket 10187 tests + BOOST_TEST_EQ(fs::canonical(root / "../.." / first), expected); + BOOST_TEST_EQ(fs::canonical(fs::path("../..") / first, root), expected); + BOOST_TEST_EQ(fs::canonical(fs::path("/../..") / first, fs::current_path().root_name()), expected); + + // ticket 9683 test + BOOST_TEST_EQ(fs::canonical(root / first / "../../../../.."), root); + +#ifdef BOOST_WINDOWS_API + // Test Windows long paths + fs::path long_path = make_long_path(dir / L"f0"); + BOOST_TEST_EQ(fs::canonical(long_path), long_path); +#endif +} + +// canonical_symlink_tests -----------------------------------------------------------// + +void canonical_symlink_tests() +{ + cout << "canonical_symlink_tests..." << endl; + + fs::path relative_dir(dir.filename()); + BOOST_TEST_EQ(fs::canonical(dir / "sym-d1/f2"), d1 / "f2"); + BOOST_TEST_EQ(fs::canonical(relative_dir / "sym-d1/f2"), d1 / "f2"); +} + +// copy_file_tests ------------------------------------------------------------------// + +void copy_file_tests(const fs::path& f1x, const fs::path& d1x) +{ + cout << "copy_file_tests..." << endl; + + BOOST_TEST(fs::exists(f1x)); + fs::remove(d1x / "f2"); // remove possible residue from prior testing + BOOST_TEST(fs::exists(d1x)); + BOOST_TEST(!fs::exists(d1x / "f2")); + cout << " copy " << f1x << " to " << d1x / "f2" << endl; + bool file_copied = fs::copy_file(f1x, d1x / "f2"); + cout << " copy complete" << endl; + BOOST_TEST(file_copied); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(fs::exists(d1x / "f2")); + BOOST_TEST(!fs::is_directory(d1x / "f2")); + verify_file(d1x / "f2", "file-f1"); + + bool copy_ex_ok = false; + file_copied = false; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2"); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = true; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(!file_copied); + + file_copied = false; + copy_ex_ok = false; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2", fs::copy_options::none); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = true; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(!file_copied); + + fs::remove(d1x / "f2"); + create_file(d1x / "f2", "1234567890"); + BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 10U); + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2", fs::copy_options::skip_existing); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(!file_copied); + BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 10U); + verify_file(d1x / "f2", "1234567890"); + + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2-non-existing", fs::copy_options::skip_existing); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + BOOST_TEST_EQ(fs::file_size(d1x / "f2-non-existing"), 7U); + verify_file(d1x / "f2-non-existing", "file-f1"); + fs::remove(d1x / "f2-non-existing"); + + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2", fs::copy_options::update_existing); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(!file_copied); + BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 10U); + verify_file(d1x / "f2", "1234567890"); + + // Sleep for a while so that the last modify time is more recent for new files +#if defined(BOOST_POSIX_API) + sleep(2); +#else + Sleep(2000); +#endif + + create_file(d1x / "f2-more-recent", "x"); + BOOST_TEST_EQ(fs::file_size(d1x / "f2-more-recent"), 1U); + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(d1x / "f2-more-recent", d1x / "f2", fs::copy_options::update_existing); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 1U); + verify_file(d1x / "f2", "x"); + fs::remove(d1x / "f2-more-recent"); + + fs::remove(d1x / "f2"); + create_file(d1x / "f2", "1234567890"); + BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 10U); + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2", fs::copy_options::overwrite_existing); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 7U); + verify_file(d1x / "f2", "file-f1"); + + fs::remove(d1x / "f2"); + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2", fs::copy_options::synchronize_data); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + verify_file(d1x / "f2", "file-f1"); + + fs::remove(d1x / "f2"); + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file(f1x, d1x / "f2", fs::copy_options::synchronize); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + verify_file(d1x / "f2", "file-f1"); + + // Test copy_file with special files with generated content. Such files have zero size, + // but have contents. + if (fs::is_regular_file("/proc/self/cmdline")) + { + file_copied = false; + copy_ex_ok = true; + try + { + file_copied = fs::copy_file("/proc/self/cmdline", d1x / "cmdline"); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + BOOST_TEST_GT(fs::file_size(d1x / "cmdline"), 0u); + } + +#ifdef BOOST_WINDOWS_API + // Test copying files with multiple NTFS streams + fs::path multi_stream_path = d1x / "multi-stream"; + fs::path multi_stream_alt_path = d1x / "multi-stream:alt-stream"; + fs::path multi_stream_copy_path = d1x / "multi-stream-copy"; + fs::path multi_stream_alt_copy_path = d1x / "multi-stream-copy:alt-stream"; + create_file(multi_stream_path, "multi-stream:default"); + try + { + // Check that the filesystem supports alternate streams + create_file(multi_stream_alt_path, "multi-stream:alternate"); + verify_file(multi_stream_alt_path, "multi-stream:alternate"); + + fs::remove(multi_stream_copy_path); + copy_ex_ok = true; + file_copied = false; + try + { + file_copied = fs::copy_file(multi_stream_path, multi_stream_copy_path); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + verify_file(multi_stream_copy_path, "multi-stream:default"); + verify_file(multi_stream_alt_copy_path, "multi-stream:alternate"); + + fs::remove(multi_stream_copy_path); + copy_ex_ok = true; + file_copied = false; + try + { + file_copied = fs::copy_file(multi_stream_path, multi_stream_copy_path, fs::copy_options::synchronize_data); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + verify_file(multi_stream_copy_path, "multi-stream:default"); + verify_file(multi_stream_alt_copy_path, "multi-stream:alternate"); + + fs::remove(multi_stream_copy_path); + copy_ex_ok = true; + file_copied = false; + try + { + file_copied = fs::copy_file(multi_stream_path, multi_stream_copy_path, fs::copy_options::synchronize); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = false; + } + BOOST_TEST(copy_ex_ok); + BOOST_TEST(file_copied); + verify_file(multi_stream_copy_path, "multi-stream:default"); + verify_file(multi_stream_alt_copy_path, "multi-stream:alternate"); + + fs::remove(multi_stream_copy_path); + } + catch (const fs::filesystem_error& e) + { + cout << "Multiple streams per file are not supported: " << e.what() << "\nSkipping multi-stream tests..." << endl; + } +#endif // BOOST_WINDOWS_API +} + +// symlink_status_tests -------------------------------------------------------------// + +void symlink_status_tests() +{ + cout << "symlink_status_tests..." << endl; + + boost::system::error_code ec; + + fs::path dangling_sym(dir / "dangling-sym"); + fs::path dangling_directory_sym(dir / "dangling-directory-sym"); + fs::path sym_d1(dir / "sym-d1"); + fs::path symsym_d1(dir / "symsym-d1"); + fs::path sym_f1(dir / "sym-f1"); + fs::path symsym_f1(dir / "symsym-f1"); + fs::create_symlink("does not exist", dangling_sym); + fs::create_directory_symlink("does not exist", dangling_directory_sym); + fs::create_directory_symlink(d1, sym_d1); + fs::create_directory_symlink(sym_d1, symsym_d1); + fs::create_symlink(f1, sym_f1); + fs::create_symlink(sym_f1, symsym_f1); + + // verify all cases detected as symlinks + BOOST_TEST_EQ(fs::symlink_status(dangling_sym, ec).type(), fs::symlink_file); + BOOST_TEST_EQ(fs::symlink_status(dangling_directory_sym, ec).type(), fs::symlink_file); + BOOST_TEST_EQ(fs::symlink_status(sym_d1, ec).type(), fs::symlink_file); + BOOST_TEST_EQ(fs::symlink_status(symsym_d1, ec).type(), fs::symlink_file); + BOOST_TEST_EQ(fs::symlink_status(sym_f1, ec).type(), fs::symlink_file); + BOOST_TEST_EQ(fs::symlink_status(symsym_f1, ec).type(), fs::symlink_file); + + // verify all cases resolve to the (possibly recursive) symlink target + BOOST_TEST_EQ(fs::status(dangling_sym, ec).type(), fs::file_not_found); + BOOST_TEST_EQ(fs::status(dangling_directory_sym, ec).type(), fs::file_not_found); + + BOOST_TEST_EQ(fs::status(sym_d1, ec).type(), fs::directory_file); + BOOST_TEST_EQ(fs::status(sym_d1 / "d1f1", ec).type(), fs::regular_file); + BOOST_TEST_EQ(fs::status(symsym_d1, ec).type(), fs::directory_file); + BOOST_TEST_EQ(fs::status(symsym_d1 / "d1f1", ec).type(), fs::regular_file); + BOOST_TEST_EQ(fs::status(sym_f1, ec).type(), fs::regular_file); + BOOST_TEST_EQ(fs::status(symsym_f1, ec).type(), fs::regular_file); + +#ifdef BOOST_WINDOWS_API + + // On Windows, telling if a filesystem entry is a symlink (or junction which is + // treated as a symlink), rather than some other kind of reparse point, requires some + // baroque code. See ticket #4663, filesystem objects falsely identified as symlinks. + // This test checks two directory entries created by Windows itself to verify + // is_symlink() works correctly. Try "dir /A %HOMEPATH%\.." from the command line to + // verify this test is valid on your version of Windows. It only works on Vista and + // later. + + fs::path users(getenv("HOMEDRIVE")); + BOOST_TEST(!users.empty()); + users /= "\\Users"; + BOOST_TEST(fs::exists(users)); + BOOST_TEST(fs::exists(users / "All Users")); + BOOST_TEST(fs::exists(users / "Default User")); + BOOST_TEST(fs::is_symlink(users / "All Users")); // dir /A reports + BOOST_TEST(fs::is_symlink(users / "Default User")); // dir /A reports + + fs::file_status stat(fs::symlink_status(L"\\System Volume Information")); + BOOST_TEST(fs::type_present(stat)); + BOOST_TEST(fs::permissions_present(stat)); + BOOST_TEST(fs::status_known(stat)); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(fs::is_directory(stat)); + BOOST_TEST(!fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); + +#endif +} + +// copy_symlink_tests ---------------------------------------------------------------// + +void copy_symlink_tests(const fs::path& f1x, const fs::path& d1x) +{ + cout << "copy_symlink_tests..." << endl; + + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(fs::exists(d1x)); + fs::path sym1(d1x / "symlink1"); + fs::remove(sym1); // remove possible residue from prior testing + fs::create_symlink(f1x, sym1); + BOOST_TEST(fs::exists(sym1)); + BOOST_TEST(fs::is_symlink(sym1)); + fs::path sym2(d1x / "symlink2"); + fs::copy_symlink(sym1, sym2); + BOOST_TEST(fs::exists(sym2)); + BOOST_TEST(fs::is_symlink(sym2)); + //fs::path sym3(d1x / "symlink3"); + //fs::copy(sym1, sym3); + //BOOST_TEST(fs::exists(sym3)); + //BOOST_TEST(fs::is_symlink(sym3)); + + bool copy_ex_ok = false; + try + { + fs::copy_symlink("no-such-file", "new-symlink1"); + } + catch (const fs::filesystem_error&) + { + copy_ex_ok = true; + } + BOOST_TEST(copy_ex_ok); + + copy_ex_ok = false; + try + { + fs::copy_symlink(f1x, "new-symlink2"); + } // should fail; f1x not symlink + catch (const fs::filesystem_error&) + { + copy_ex_ok = true; + } + BOOST_TEST(copy_ex_ok); +} + +// creation_time_tests -------------------------------------------------------------// + +void creation_time_tests(const fs::path& dirx) +{ + cout << "creation_time_tests..." << endl; + + fs::path f1x = dirx / "creation_time_file"; + + std::time_t start = std::time(NULL); + + // These pauses are inserted because the test spuriously fails on Windows, presumably because of + // different converting FILETIME to seconds in time() and Boost.Filesystem or some sort of quirk + // in the Windows implementation of filesystem API. +#if defined(BOOST_POSIX_API) + sleep(1); +#else + Sleep(1000); +#endif + create_file(f1x, "creation_time_file"); + BOOST_TEST(fs::is_regular_file(f1x)); + try + { + std::time_t ft = fs::creation_time(f1x); +#if defined(BOOST_POSIX_API) + sleep(1); +#else + Sleep(1000); +#endif + std::time_t finish = std::time(NULL); + cout << " start time: " << start << ", file creation time: " << ft << ", finish time: " << finish << endl; + + BOOST_TEST(ft >= start && ft <= finish); + } + catch (fs::filesystem_error& e) + { + if (e.code() == make_error_condition(boost::system::errc::function_not_supported)) + { + cout << "creation_time is not supported by the current system" << endl; + } + else + { + cout << "creation_time failed: " << e.what() << endl; + BOOST_TEST(false); + } + } + + fs::remove(f1x); +} + +// write_time_tests ----------------------------------------------------------------// + +void write_time_tests(const fs::path& dirx) +{ + cout << "write_time_tests..." << endl; + + fs::path f1x = dirx / "foobar2"; + create_file(f1x, "foobar2"); + BOOST_TEST(fs::exists(f1x)); + BOOST_TEST(!fs::is_directory(f1x)); + BOOST_TEST(fs::is_regular_file(f1x)); + BOOST_TEST(fs::file_size(f1x) == 7); + verify_file(f1x, "foobar2"); + + // Some file system report last write time as local (FAT), while + // others (NTFS) report it as UTC. The C standard does not specify + // if time_t is local or UTC. + + std::time_t ft = fs::last_write_time(f1x); + cout << "\n UTC last_write_time() for a file just created is " + << std::asctime(std::gmtime(&ft)) << endl; + + std::tm* tmp = std::localtime(&ft); + cout << "\n Year is " << tmp->tm_year << endl; + --tmp->tm_year; + cout << " Change year to " << tmp->tm_year << endl; + fs::last_write_time(f1x, std::mktime(tmp)); + std::time_t ft2 = fs::last_write_time(f1x); + cout << " last_write_time() for the file is now " + << std::asctime(std::gmtime(&ft2)) << endl; + BOOST_TEST(ft != fs::last_write_time(f1x)); + + cout << "\n Reset to current time" << endl; + fs::last_write_time(f1x, ft); + double time_diff = std::difftime(ft, fs::last_write_time(f1x)); + cout + << " original last_write_time() - current last_write_time() is " + << time_diff << " seconds" << endl; + BOOST_TEST(time_diff >= -60.0 && time_diff <= 60.0); +} + +// platform_specific_tests ---------------------------------------------------------// + +void platform_specific_tests() +{ + // Windows only tests + if (platform == "Windows") + { + cout << "Windows specific tests..." << endl; + if (!skip_long_windows_tests) + { + cout << " (may take several seconds)" << endl; + + BOOST_TEST(!fs::exists(fs::path("//share-not"))); + BOOST_TEST(!fs::exists(fs::path("//share-not/"))); + BOOST_TEST(!fs::exists(fs::path("//share-not/foo"))); + } + cout << endl; + + BOOST_TEST(!fs::exists("tools/jam/src/:sys:stat.h")); // !exists() if ERROR_INVALID_NAME + BOOST_TEST(!fs::exists(":sys:stat.h")); // !exists() if ERROR_INVALID_PARAMETER + BOOST_TEST(dir.string().size() > 1 && dir.string()[1] == ':'); // verify path includes drive + + BOOST_TEST(fs::system_complete("").empty()); + BOOST_TEST(fs::system_complete("/") == fs::initial_path().root_path()); + BOOST_TEST(fs::system_complete("foo") == fs::initial_path() / "foo"); + + fs::path p1(fs::system_complete("/foo")); + BOOST_TEST_EQ(p1.string().size(), 6U); // this failed during v3 development due to bug + std::string s1(p1.string()); + std::string s2(fs::initial_path().root_path().string() + "foo"); + BOOST_TEST_EQ(s1, s2); + + BOOST_TEST(fs::system_complete(fs::path(fs::initial_path().root_name())) == fs::initial_path()); + BOOST_TEST(fs::system_complete(fs::path(fs::initial_path().root_name().string() + "foo")).string() == fs::initial_path() / "foo"); + BOOST_TEST(fs::system_complete(fs::path("c:/")).generic_string() == "c:/"); + BOOST_TEST(fs::system_complete(fs::path("c:/foo")).generic_string() == "c:/foo"); + BOOST_TEST(fs::system_complete(fs::path("//share")).generic_string() == "//share"); + +#if defined(BOOST_FILESYSTEM_HAS_MKLINK) + // Issue 9016 asked that NTFS directory junctions be recognized as directories. + // That is equivalent to recognizing them as symlinks, and then the normal symlink + // mechanism takes care of recognizing them as directories. + // + // Directory junctions are very similar to symlinks, but have some performance + // and other advantages over symlinks. They can be created from the command line + // with "mklink /J junction-name target-path". + + { + cout << " directory junction tests..." << endl; + BOOST_TEST(fs::exists(dir)); + BOOST_TEST(fs::exists(dir / "d1/d1f1")); + fs::path junc(dir / "junc"); + if (fs::exists(junc)) + fs::remove(junc); + fs::path new_junc(dir / "new-junc"); + if (fs::exists(new_junc)) + fs::remove(new_junc); + + //cout << " dir is " << dir << endl; + //cout << " junc is " << junc << endl; + //cout << " new_junc is " << new_junc << endl; + //cout << " current_path() is " << fs::current_path() << endl; + + fs::path cur_path(fs::current_path()); + fs::current_path(dir); + //cout << " current_path() is " << fs::current_path() << endl; + BOOST_TEST(std::system("mklink /J junc d1") == 0); + //std::system("dir"); + fs::current_path(cur_path); + //cout << " current_path() is " << fs::current_path() << endl; + + BOOST_TEST(fs::exists(junc)); + BOOST_TEST(fs::is_symlink(junc)); + BOOST_TEST(fs::is_directory(junc)); + BOOST_TEST(!fs::is_regular_file(junc)); + BOOST_TEST(fs::exists(junc / "d1f1")); + BOOST_TEST(fs::is_regular_file(junc / "d1f1")); + + int count = 0; + for (fs::directory_iterator itr(junc); itr != fs::directory_iterator(); ++itr) + { + //cout << itr->path() << endl; + ++count; + } + cout << " iteration count is " << count << endl; + BOOST_TEST(count > 0); + + fs::rename(junc, new_junc); + BOOST_TEST(!fs::exists(junc)); + BOOST_TEST(fs::exists(new_junc)); + BOOST_TEST(fs::is_symlink(new_junc)); + BOOST_TEST(fs::is_directory(new_junc)); + BOOST_TEST(!fs::is_regular_file(new_junc)); + BOOST_TEST(fs::exists(new_junc / "d1f1")); + BOOST_TEST(fs::is_regular_file(new_junc / "d1f1")); + + fs::remove(new_junc); + BOOST_TEST(!fs::exists(new_junc / "d1f1")); + BOOST_TEST(!fs::exists(new_junc)); + BOOST_TEST(fs::exists(dir)); + BOOST_TEST(fs::exists(dir / "d1/d1f1")); + } +#endif // defined(BOOST_FILESYSTEM_HAS_MKLINK) + } // Windows + + else if (platform == "POSIX") + { + cout << "POSIX specific tests..." << endl; + BOOST_TEST(fs::system_complete("").empty()); + BOOST_TEST(fs::initial_path().root_path().string() == "/"); + BOOST_TEST(fs::system_complete("/").string() == "/"); + BOOST_TEST(fs::system_complete("foo").string() == fs::initial_path().string() + "/foo"); + BOOST_TEST(fs::system_complete("/foo").string() == fs::initial_path().root_path().string() + "foo"); + } // POSIX +} + +// initial_tests -------------------------------------------------------------------// + +void initial_tests() +{ + cout << "initial_tests..." << endl; + + cout << " current_path().string() is\n \"" + << fs::initial_path().string() + << "\"\n\n"; + BOOST_TEST(fs::initial_path() == fs::current_path()); + BOOST_TEST(fs::initial_path().is_absolute()); + BOOST_TEST(fs::current_path().is_absolute()); + BOOST_TEST(fs::initial_path().string() == fs::current_path().string()); +} + +// space_tests ---------------------------------------------------------------------// + +void space_tests() +{ + cout << "space_tests..." << endl; + + // make some reasonable assuptions for testing purposes + fs::space_info spi(fs::space(dir)); + BOOST_TEST(spi.capacity > 1000000); + BOOST_TEST(spi.free > 1000); + BOOST_TEST(spi.capacity > spi.free); + BOOST_TEST(spi.free >= spi.available); + + // it is convenient to display space, but older VC++ versions choke +#if !defined(BOOST_MSVC) || _MSC_VER >= 1300 // 1300 == VC++ 7.0 + cout << " capacity = " << spi.capacity << '\n'; + cout << " free = " << spi.free << '\n'; + cout << " available = " << spi.available << '\n'; +#endif + + // Test that we can specify path to file + fs::path file = dir / "file"; + create_file(file); + + fs::space_info spi_file(fs::space(file)); + BOOST_TEST_EQ(spi_file.capacity, spi.capacity); + + fs::remove(file); + + // Test that an error is indicated if a path to a non-existing file is passed + BOOST_TEST(CHECK_EXCEPTION(bad_space, ENOENT)); +} + +// equivalent_tests ----------------------------------------------------------------// + +void equivalent_tests(const fs::path& f1x) +{ + cout << "equivalent_tests..." << endl; + + BOOST_TEST(CHECK_EXCEPTION(bad_equivalent, ENOENT)); + BOOST_TEST(fs::equivalent(f1x, dir / "f1")); + BOOST_TEST(fs::equivalent(dir, d1 / "..")); + BOOST_TEST(!fs::equivalent(f1x, dir)); + BOOST_TEST(!fs::equivalent(dir, f1x)); + BOOST_TEST(!fs::equivalent(d1, d2)); + BOOST_TEST(!fs::equivalent(dir, ng)); + BOOST_TEST(!fs::equivalent(ng, dir)); + BOOST_TEST(!fs::equivalent(f1x, ng)); + BOOST_TEST(!fs::equivalent(ng, f1x)); +} + +// temp_directory_path_tests -------------------------------------------------------// +// contributed by Jeff Flinn + +struct guarded_env_var +{ + struct previous_value + { + std::string m_name; + std::string m_string; + bool m_empty; + + previous_value(const char* name) : + m_name(name), m_empty(true) + { + if (const char* value = getenv(name)) + { + m_string.assign(value); + m_empty = false; + } + else + { + m_empty = true; + } + } + ~previous_value() + { + m_empty ? unsetenv_(m_name.c_str()) : setenv_(m_name.c_str(), m_string.c_str(), 1); + } + }; + + previous_value m_previous_value; + + guarded_env_var(const char* name, const char* value) : + m_previous_value(name) + { + // std::cout << name << " old value is \"" << getenv(name) << "\"" << std::endl; + value ? setenv_(name, value, 1) : unsetenv_(name); + // std::cout << name << " new value is \"" << getenv(name) << "\"" << std::endl; + } +}; + +void temp_directory_path_tests() +{ + { + cout << "temp_directory_path_tests..." << endl; + cout << " temp_directory_path() is " << fs::temp_directory_path() << endl; + +#if defined(BOOST_WINDOWS_API) + + //**************************************************************************************// + // Bug in GCC 4.9 getenv() when !defined(__GXX_EXPERIMENTAL_CXX0X__) makes these + // tests meaningless, so skip them + //**************************************************************************************// + +#if defined(__CYGWIN__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 + cout << "Bug in GCC 4.9 getenv() when !defined(__GXX_EXPERIMENTAL_CXX0X__) makes these" + "tests meaningless, so skip them" + << endl; + return; +#endif + // Test ticket #5300, temp_directory_path failure on Windows with path length > 130. + // (This test failed prior to the fix being applied.) + { + const wchar_t long_name[] = + L"12345678901234567890123456789012345678901234567890" + L"12345678901234567890123456789012345678901234567890" + L"12345678901234567890123456789012345678901234567890#" // total 151 chars + ; + fs::path p(temp_dir); + p /= long_name; + fs::create_directory(p); + + guarded_env_var tmp_guard("TMP", p.string().c_str()); + error_code ec; + fs::path tmp_path = fs::temp_directory_path(ec); + BOOST_TEST(!ec); + BOOST_TEST_EQ(p, tmp_path); + fs::remove(p); + } + + // Test ticket #10388, null character at end of filesystem::temp_directory_path path + { + guarded_env_var tmp_guard("TMP", fs::initial_path().string().c_str()); + + error_code ec; + fs::path tmp_path = fs::temp_directory_path(ec); + BOOST_TEST_EQ(tmp_path, fs::initial_path()); + } + +#endif + BOOST_TEST(!fs::temp_directory_path().empty()); + BOOST_TEST(exists(fs::temp_directory_path())); + fs::path ph = fs::temp_directory_path() / fs::unique_path("temp_directory_path_test_%%%%_%%%%.txt"); + { + if (exists(ph)) + remove(ph); + std::ofstream f(BOOST_FILESYSTEM_C_STR(ph)); + f << "passed"; + } + BOOST_TEST(exists(ph)); + { + std::ifstream f(BOOST_FILESYSTEM_C_STR(ph)); + std::string s; + f >> s; + BOOST_TEST(s == "passed"); + } + remove(ph); + BOOST_TEST(!exists(ph)); + } + + fs::path test_temp_dir = temp_dir; + +#if defined(BOOST_POSIX_API) + { + struct guarded_tmp_vars + { + guarded_env_var m_tmpdir; + guarded_env_var m_tmp; + guarded_env_var m_temp; + guarded_env_var m_tempdir; + + guarded_tmp_vars(const fs::path::value_type* tmpdir, const fs::path::value_type* tmp, const fs::path::value_type* temp, const fs::path::value_type* tempdir) : + m_tmpdir("TMPDIR", tmpdir), m_tmp("TMP", tmp), m_temp("TEMP", temp), m_tempdir("TEMPDIR", tempdir) + { + } + }; + + { + guarded_tmp_vars vars(test_temp_dir.c_str(), 0, 0, 0); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, test_temp_dir.c_str(), 0, 0); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, 0, test_temp_dir.c_str(), 0); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, 0, 0, test_temp_dir.c_str()); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + } +#endif + +#if defined(BOOST_WINDOWS_API) + + struct guarded_tmp_vars + { + guarded_env_var m_tmp; + guarded_env_var m_temp; + guarded_env_var m_localappdata; + guarded_env_var m_userprofile; + + guarded_tmp_vars(const char* tmp, const char* temp, const char* localappdata, const char* userprofile) : + m_tmp("TMP", tmp), m_temp("TEMP", temp), m_localappdata("LOCALAPPDATA", localappdata), m_userprofile("USERPROFILE", userprofile) + { + } + }; + + // test the GetWindowsDirectoryW()/Temp fallback + { + guarded_tmp_vars vars(0, 0, 0, 0); + error_code ec; + fs::path ph = fs::temp_directory_path(ec); + BOOST_TEST(!ec); + cout << "Fallback test, temp_directory_path() returned " << ph << endl; + } + + { + guarded_tmp_vars vars(test_temp_dir.string().c_str(), 0, 0, 0); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, test_temp_dir.string().c_str(), 0, 0); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + + fs::create_directory(test_temp_dir / L"Temp"); + { + guarded_tmp_vars vars(0, 0, test_temp_dir.string().c_str(), 0); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir / L"Temp", ph)); + cout << "temp_directory_path() returned " << ph << endl; + } + { + guarded_tmp_vars vars(0, 0, 0, test_temp_dir.string().c_str()); + fs::path ph = fs::temp_directory_path(); + BOOST_TEST(equivalent(test_temp_dir / L"Temp", ph)); + cout << "temp_directory_path() returned " << ph << endl; + } +#endif +} + +// weakly_canonical_basic_tests ----------------------------------------------------// + +void weakly_canonical_basic_tests() +{ + cout << "weakly_canonical_basic_tests..." << endl; + cout << " dir is " << dir << endl; + + BOOST_TEST_EQ(fs::weakly_canonical("no-such/foo/bar"), fs::path("no-such/foo/bar")); + BOOST_TEST_EQ(fs::weakly_canonical("no-such/foo/../bar"), fs::path("no-such/bar")); + BOOST_TEST_EQ(fs::weakly_canonical(dir), dir); + BOOST_TEST_EQ(fs::weakly_canonical(dir / "no-such/foo/bar"), dir / "no-such/foo/bar"); + BOOST_TEST_EQ(fs::weakly_canonical(dir / "no-such/foo/../bar"), dir / "no-such/bar"); + BOOST_TEST_EQ(fs::weakly_canonical(dir / "../no-such/foo/../bar"), dir.parent_path() / "no-such/bar"); + BOOST_TEST_EQ(fs::weakly_canonical(dir / "no-such/../f0"), dir / "f0"); // dir / "f0" exists, dir / "no-such" does not + BOOST_TEST_EQ(fs::weakly_canonical("c:/no-such/foo/bar"), fs::path("c:/no-such/foo/bar")); + +#ifdef BOOST_WINDOWS_API + // Test Windows long paths + fs::path long_path = make_long_path(dir / L"f0"); + BOOST_TEST_EQ(fs::weakly_canonical(long_path), long_path); + + long_path = make_long_path(dir / L"no-such/foo/bar"); + BOOST_TEST_EQ(fs::weakly_canonical(long_path), long_path); +#endif +} + +// weakly_canonical_symlink_tests --------------------------------------------------// + +void weakly_canonical_symlink_tests() +{ + cout << "weakly_canonical_symlink_tests..." << endl; + cout << " dir is " << dir << endl; + + fs::create_directory_symlink(dir / "d1", dir / "sld1"); + BOOST_TEST_EQ(fs::weakly_canonical(dir / "sld1/foo/bar"), dir / "d1/foo/bar"); + + BOOST_TEST_EQ(relative(dir / "sld1/foo/bar/baz", dir / "d1/foo"), fs::path("bar/baz")); +} + +// _tests --------------------------------------------------------------------------// + +//void _tests() +//{ +// cout << "_tests..." << endl; +//} + +} // unnamed namespace + +//------------------------------------------------------------------------------------// +// // +// main // +// // +//------------------------------------------------------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ +// document state of critical macros +#ifdef BOOST_POSIX_API + cout << "BOOST_POSIX_API is defined\n"; +#endif +#ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API is defined\n"; +#endif + + for (; argc > 1; --argc, ++argv) + { + if (*argv[1] == '-' && *(argv[1] + 1) == 't') + report_throws = true; + else if (*argv[1] == '-' && *(argv[1] + 1) == 'x') + cleanup = false; + else if (*argv[1] == '-' && *(argv[1] + 1) == 'w') + skip_long_windows_tests = true; + } + + // The choice of platform to test is made at runtime rather than compile-time + // so that compile errors for all platforms will be detected even though + // only the current platform is runtime tested. +#if defined(BOOST_POSIX_API) + platform = "POSIX"; +#elif defined(BOOST_WINDOWS_API) + platform = "Windows"; +#else +#error neither BOOST_POSIX_API nor BOOST_WINDOWS_API is defined. See boost/system/api_config.hpp +#endif + cout << "API is " << platform << endl; + cout << "initial_path() is " << fs::initial_path() << endl; + fs::path ip = fs::initial_path(); + do_the_right_thing_tests(); // compile-only tests, but call anyhow to suppress warnings + + for (fs::path::const_iterator it = ip.begin(); it != ip.end(); ++it) + { + if (it != ip.begin()) + cout << ", "; + cout << *it; + } + cout << endl; + + dir = fs::initial_path() / temp_dir; + + if (fs::exists(dir)) + { + cout << "remove residue from prior failed tests..." << endl; + fs::remove_all(dir); + } + BOOST_TEST(!fs::exists(dir)); + + // several functions give unreasonable results if uintmax_t isn't 64-bits + cout << "sizeof(boost::uintmax_t) = " << sizeof(boost::uintmax_t) << '\n'; + BOOST_TEST(sizeof(boost::uintmax_t) >= 8); + + initial_tests(); + predicate_and_status_tests(); + exception_tests(); + create_directory_tests(); + current_directory_tests(); + space_tests(); + + // create a directory tree that can be used by subsequent tests + // + // dir + // d1 + // d1f1 // an empty file + // f0 // an empty file + // f1 // a file containing "file f1" + // + create_tree(); + + status_of_nonexistent_tests(); + status_error_reporting_tests(); + directory_iterator_tests(); + create_directories_tests(); // must run AFTER directory_iterator_tests + + bad_create_directory_path = f1; + BOOST_TEST(CHECK_EXCEPTION(bad_create_directory, EEXIST)); + fs::file_status stat = fs::status(f1); + BOOST_TEST(fs::status_known(stat)); + BOOST_TEST(fs::exists(stat)); + BOOST_TEST(!fs::is_directory(stat)); + BOOST_TEST(fs::is_regular_file(stat)); + BOOST_TEST(!fs::is_other(stat)); + BOOST_TEST(!fs::is_symlink(stat)); + + equivalent_tests(f1); + create_hard_link_tests(); + create_symlink_tests(); + resize_file_tests(); + absolute_tests(); + canonical_basic_tests(); + weakly_canonical_basic_tests(); + permissions_tests(); + copy_file_tests(f1, d1); + if (create_symlink_ok) // only if symlinks supported + { + symlink_status_tests(); + copy_symlink_tests(f1, d1); + canonical_symlink_tests(); + weakly_canonical_symlink_tests(); + } + iterator_status_tests(); // lots of cases by now, so a good time to test + // dump_tree(dir); + recursive_directory_iterator_tests(); + recursive_iterator_status_tests(); // lots of cases by now, so a good time to test + rename_tests(); + remove_tests(dir); + remove_all_tests(dir); + if (create_symlink_ok) // only if symlinks supported + { + remove_symlink_tests(); + remove_all_symlink_tests(dir); + } + creation_time_tests(dir); + write_time_tests(dir); + temp_directory_path_tests(); + + platform_specific_tests(); // do these last since they take a lot of time on Windows, + // and that's a pain during manual testing + + cout << "testing complete" << endl; + + // post-test cleanup + if (cleanup) + { + cout << "post-test removal of " << dir << endl; + BOOST_TEST(fs::remove_all(dir) != 0); + // above was added just to simplify testing, but it ended up detecting + // a bug (failure to close an internal search handle). + cout << "post-test removal complete" << endl; + // BOOST_TEST(!fs::exists(dir)); // nice test, but doesn't play well with TortoiseGit cache + } + + cout << "returning from main()" << endl; + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/operations_unit_test.cpp b/3rdparty/boost_filesystem/test/operations_unit_test.cpp new file mode 100644 index 0000000..e5c3c62 --- /dev/null +++ b/3rdparty/boost_filesystem/test/operations_unit_test.cpp @@ -0,0 +1,405 @@ +// operations_unit_test.cpp ----------------------------------------------------------// + +// Copyright Beman Dawes 2008, 2009, 2015 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// ------------------------------------------------------------------------------------// + +// This program is misnamed - it is really a smoke test rather than a unit test + +// ------------------------------------------------------------------------------------// + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include // make sure filesystem.hpp works +#include // for BOOST_FILESYSTEM_C_STR + +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::filesystem; +using namespace boost::system; +using std::cout; +using std::endl; +using std::string; + +#define CHECK(x) check(x, __FILE__, __LINE__) + +namespace { +bool cleanup = true; + +void create_file(const path& ph, const std::string& contents = std::string()) +{ + std::ofstream f(BOOST_FILESYSTEM_C_STR(ph)); + if (!f) + throw filesystem_error("operations_test create_file", ph, error_code(errno, system_category())); + if (!contents.empty()) + f << contents; +} + +void check(bool ok, const char* file, int line) +{ + if (ok) + return; + + ++::boost::detail::test_errors(); + + cout << file << '(' << line << "): test failed\n"; +} + +// file_status_test ----------------------------------------------------------------// + +void file_status_test() +{ + cout << "file_status test..." << endl; + + file_status s = status("."); + int v = s.permissions(); + cout << " status(\".\") permissions are " + << std::oct << (v & 0777) << std::dec << endl; + CHECK((v & 0400) == 0400); + + s = symlink_status("."); + v = s.permissions(); + cout << " symlink_status(\".\") permissions are " + << std::oct << (v & 0777) << std::dec << endl; + CHECK((v & 0400) == 0400); +} + +// query_test ----------------------------------------------------------------------// + +void query_test() +{ + cout << "query test..." << endl; + + error_code ec; + + CHECK(file_size("no-such-file", ec) == static_cast< boost::uintmax_t >(-1)); + CHECK(ec == errc::no_such_file_or_directory); + + CHECK(status("no-such-file") == file_status(file_not_found, no_perms)); + + CHECK(exists("/")); + CHECK(is_directory("/")); + CHECK(!exists("no-such-file")); + + exists("/", ec); + if (ec) + { + cout << "exists(\"/\", ec) resulted in non-zero ec.value()" << endl; + cout << "ec value: " << ec.value() << ", message: " << ec.message() << endl; + } + CHECK(!ec); + + CHECK(exists("/")); + CHECK(is_directory("/")); + CHECK(!is_regular_file("/")); + CHECK(!boost::filesystem::is_empty("/")); + CHECK(!is_other("/")); +} + +// directory_iterator_test -----------------------------------------------// + +void directory_iterator_test() +{ + cout << "directory_iterator_test..." << endl; + + directory_iterator end; + + directory_iterator it("."); + + CHECK(!it->path().empty()); + + if (is_regular_file(it->status())) + { + CHECK(is_regular_file(it->symlink_status())); + CHECK(!is_directory(it->status())); + CHECK(!is_symlink(it->status())); + CHECK(!is_directory(it->symlink_status())); + CHECK(!is_symlink(it->symlink_status())); + } + else + { + CHECK(is_directory(it->status())); + CHECK(is_directory(it->symlink_status())); + CHECK(!is_regular_file(it->status())); + CHECK(!is_regular_file(it->symlink_status())); + CHECK(!is_symlink(it->status())); + CHECK(!is_symlink(it->symlink_status())); + } + + for (; it != end; ++it) + { + //cout << " " << it->path() << "\n"; + } + + CHECK(directory_iterator(".") != directory_iterator()); + CHECK(directory_iterator() == end); + +#ifndef BOOST_NO_CXX11_RANGE_BASED_FOR + for (directory_entry& x : directory_iterator(".")) + { + CHECK(!x.path().empty()); + //cout << " " << x.path() << "\n"; + } + const directory_iterator dir_itr("."); + for (directory_entry& x : dir_itr) + { + CHECK(!x.path().empty()); + //cout << " " << x.path() << "\n"; + } +#endif + + for (directory_iterator itr("."); itr != directory_iterator(); ++itr) + { + CHECK(!itr->path().empty()); + //cout << " " << itr->path() << "\n"; + } + + cout << "directory_iterator_test complete" << endl; +} + +// recursive_directory_iterator_test -----------------------------------------------// + +void recursive_directory_iterator_test() +{ + cout << "recursive_directory_iterator_test..." << endl; + + recursive_directory_iterator end; + + recursive_directory_iterator it("."); + + CHECK(!it->path().empty()); + + if (is_regular_file(it->status())) + { + CHECK(is_regular_file(it->symlink_status())); + CHECK(!is_directory(it->status())); + CHECK(!is_symlink(it->status())); + CHECK(!is_directory(it->symlink_status())); + CHECK(!is_symlink(it->symlink_status())); + } + else + { + CHECK(is_directory(it->status())); + CHECK(is_directory(it->symlink_status())); + CHECK(!is_regular_file(it->status())); + CHECK(!is_regular_file(it->symlink_status())); + CHECK(!is_symlink(it->status())); + CHECK(!is_symlink(it->symlink_status())); + } + + for (; it != end; ++it) + { + //cout << " " << it->path() << "\n"; + } + + CHECK(recursive_directory_iterator(".") != recursive_directory_iterator()); + CHECK(recursive_directory_iterator() == end); + +#ifndef BOOST_NO_CXX11_RANGE_BASED_FOR + for (directory_entry& x : recursive_directory_iterator(".")) + { + CHECK(!x.path().empty()); + //cout << " " << x.path() << "\n"; + } + const recursive_directory_iterator dir_itr("."); + for (directory_entry& x : dir_itr) + { + CHECK(!x.path().empty()); + //cout << " " << x.path() << "\n"; + } +#endif + + for (recursive_directory_iterator itr("."); + itr != recursive_directory_iterator(); ++itr) + { + CHECK(!itr->path().empty()); + //cout << " " << itr->path() << "\n"; + } + + cout << "recursive_directory_iterator_test complete" << endl; +} + +// operations_test -------------------------------------------------------// + +void operations_test() +{ + cout << "operations test..." << endl; + + error_code ec; + + CHECK(!create_directory("/", ec)); + + CHECK(!boost::filesystem::remove("no-such-file-or-directory")); + CHECK(!remove_all("no-such-file-or-directory")); + + space_info info = space("/"); + + CHECK(info.available <= info.capacity); + + CHECK(equivalent("/", "/")); + CHECK(!equivalent("/", ".")); + + std::time_t ft = last_write_time("."); + ft = -1; + last_write_time(".", ft, ec); +} + +// directory_entry_test ------------------------------------------------------------// + +void directory_entry_test(path const& temp_dir) +{ + cout << "directory_entry test..." << endl; + + create_file(temp_dir / "foo.bar"); + create_file(temp_dir / "goo.bar"); + create_directory(temp_dir / "bar.foo"); + + directory_entry de(temp_dir / "foo.bar"); + + CHECK(de.path() == temp_dir / "foo.bar"); + CHECK(de.status().type() == regular_file); + CHECK(de.symlink_status().type() == regular_file); + CHECK(de.is_regular_file()); + CHECK(de < directory_entry(temp_dir / "goo.bar")); + CHECK(de == directory_entry(temp_dir / "foo.bar")); + CHECK(de != directory_entry(temp_dir / "goo.bar")); + de.replace_filename("bar.foo"); + CHECK(de.path() == temp_dir / "bar.foo"); + CHECK(de.is_directory()); + CHECK(de.status().type() == directory_file); + CHECK(de.symlink_status().type() == directory_file); + + boost::filesystem::remove(temp_dir / "bar.foo"); + boost::filesystem::remove(temp_dir / "goo.bar"); + boost::filesystem::remove(temp_dir / "foo.bar"); +} + +// directory_entry_overload_test ---------------------------------------------------// + +void directory_entry_overload_test() +{ + cout << "directory_entry overload test..." << endl; + + directory_iterator it("."); + path p(*it); +} + +// error_handling_test -------------------------------------------------------------// + +void error_handling_test() +{ + cout << "error handling test..." << endl; + + bool threw(false); + try + { + file_size("no-such-file"); + } + catch (const boost::filesystem::filesystem_error& ex) + { + threw = true; + cout << "\nas expected, attempt to get size of non-existent file threw a filesystem_error\n" + "what() returns " + << ex.what() << "\n"; + } + catch (...) + { + cout << "\nunexpected exception type caught" << endl; + } + + CHECK(threw); + + error_code ec; + CHECK(!create_directory("/", ec)); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// main // +// // +//--------------------------------------------------------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ +// document state of critical macros +#ifdef BOOST_POSIX_API + cout << "BOOST_POSIX_API is defined\n"; +#endif +#ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API is defined\n"; +#endif + cout << "BOOST_FILESYSTEM_DECL" << BOOST_STRINGIZE(=BOOST_FILESYSTEM_DECL) << "\n"; + cout << "BOOST_SYMBOL_VISIBLE" << BOOST_STRINGIZE(=BOOST_SYMBOL_VISIBLE) << "\n"; + + cout << "current_path() is " << current_path().string() << endl; + + if (argc >= 2) + { + cout << "argv[1] is '" << argv[1] << "', changing current_path() to it" << endl; + + error_code ec; + current_path(argv[1], ec); + + if (ec) + { + cout << "current_path('" << argv[1] << "') failed: " << ec << ": " << ec.message() << endl; + } + + cout << "current_path() is " << current_path().string() << endl; + } + + const path temp_dir(current_path() / ".." / unique_path("op-unit_test-%%%%-%%%%-%%%%")); + cout << "temp_dir is " << temp_dir.string() << endl; + + create_directory(temp_dir); + + file_status_test(); + query_test(); + directory_iterator_test(); + recursive_directory_iterator_test(); + operations_test(); + directory_entry_test(temp_dir); + directory_entry_overload_test(); + error_handling_test(); + + cout << unique_path() << endl; + cout << unique_path("foo-%%%%%-%%%%%-bar") << endl; + cout << unique_path("foo-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-%%%%-bar") << endl; + cout << unique_path("foo-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-%%%%%-bar") << endl; + + cout << "testing complete" << endl; + + // post-test cleanup + if (cleanup) + { + cout << "post-test removal of " << temp_dir << endl; + BOOST_TEST(remove_all(temp_dir) != 0); + // above was added just to simplify testing, but it ended up detecting + // a bug (failure to close an internal search handle). + cout << "post-test removal complete" << endl; + // BOOST_TEST(!fs::exists(dir)); // nice test, but doesn't play well with TortoiseGit cache + } + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/path_iter_ctor_overload_test.cpp b/3rdparty/boost_filesystem/test/path_iter_ctor_overload_test.cpp new file mode 100644 index 0000000..d217895 --- /dev/null +++ b/3rdparty/boost_filesystem/test/path_iter_ctor_overload_test.cpp @@ -0,0 +1,40 @@ +// Copyright 2023 Andrey Semashev. +// +// 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 +// +// The test verifies that \c boost::filesystem::path constructors +// from iterators don't interfere with initializer list constructor. +// +// https://github.com/boostorg/filesystem/issues/287 + +#include +#include + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +#include + +void test(std::initializer_list< boost::filesystem::path > paths) +{ +} + +void test(boost::filesystem::path const& path) +{ +} + +int main() +{ + boost::filesystem::path a, b; + test({a, b}); +} + +#else // !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +int main() +{ +} + +#endif // !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/3rdparty/boost_filesystem/test/path_operator_ambiguity.cpp b/3rdparty/boost_filesystem/test/path_operator_ambiguity.cpp new file mode 100644 index 0000000..5a43a63 --- /dev/null +++ b/3rdparty/boost_filesystem/test/path_operator_ambiguity.cpp @@ -0,0 +1,53 @@ +// Copyright Andrey Semashev 2023 +// +// Use, modification, and distribution is subject to 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) +// +// See library home page at http://www.boost.org/libs/filesystem +// +// This test verifies that a using directive does not introduce operator +// ambiguity with the standard library. +// https://github.com/boostorg/filesystem/issues/285 + +#include +#include + +using namespace boost::filesystem; + +bool test_eq(char* arg) +{ + return std::string("abc") == arg; +} + +bool test_ne(char* arg) +{ + return std::string("def") != arg; +} + +bool test_lt(char* arg) +{ + return std::string("ghi") < arg; +} + +bool test_gt(char* arg) +{ + return std::string("jkl") > arg; +} + +bool test_le(char* arg) +{ + return std::string("mno") <= arg; +} + +bool test_ge(char* arg) +{ + return std::string("pqr") >= arg; +} + +int main(int, char* argv[]) +{ + return test_eq(argv[0]) + test_ne(argv[0]) + + test_lt(argv[0]) + test_gt(argv[0]) + + test_le(argv[0]) + test_ge(argv[0]); +} diff --git a/3rdparty/boost_filesystem/test/path_test.cpp b/3rdparty/boost_filesystem/test/path_test.cpp new file mode 100644 index 0000000..cd35037 --- /dev/null +++ b/3rdparty/boost_filesystem/test/path_test.cpp @@ -0,0 +1,2933 @@ +// path_test program -----------------------------------------------------------------// + +// Copyright Beman Dawes 2002, 2008 +// Copyright Vladimir Prus 2002 + +// Use, modification, and distribution is subject to 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) + +// See library home page at http://www.boost.org/libs/filesystem + +// basic_path's stem(), extension(), and replace_extension() tests are based +// on basename(), extension(), and change_extension() tests from the original +// convenience_test.cpp by Vladimir Prus. + +//--------------------------------------------------------------------------------------// +// // +// Caution // +// // +// The class path relational operators (==, !=, <, etc.) on Windows treat slash and // +// backslash as equal. Thus any tests on Windows where the difference between slash // +// and backslash is significant should compare strings rather than paths. // +// // +// BOOST_TEST(path == path) // '\\' and '/' are equal // +// BOOST_TEST(path == convertable to string) // '\\' and '/' are equal // +// PATH_TEST_EQ(path, path) // '\\' and '/' are equal // +// // +// BOOST_TEST(path.string() == path.string()) // '\\' and '/' are not equal // +// BOOST_TEST(path.string() == // +// convertable to string) // '\\' and '/' are not equal // +// PATH_TEST_EQ(path.string(), // +// convertable to string) // '\\' and '/' are not equal // +// // +// The last of these is often what is needed, so the PATH_TEST_EQ macro is provided. // +// It converts its first argument to a path, and then performs a .string() on it, // +// eliminating much boilerplate .string() or even path(...).string() code. // +// // +// PATH_TEST_EQ(path, convertable to string) // '\\' and '/' are not equal // +// // +//--------------------------------------------------------------------------------------// + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif +#include +#include + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::next; +using boost::prior; + +#ifdef BOOST_WINDOWS_API +#define BOOST_DIR_SEP "\\" +#else +#define BOOST_DIR_SEP "/" +#endif + +#if BOOST_FILESYSTEM_VERSION == 3 +#define BOOST_FILESYSTEM_V3_TRAILING_DOT "." +#else +#define BOOST_FILESYSTEM_V3_TRAILING_DOT "" +#endif + +#define PATH_TEST_EQ(a, b) check(a, b, __FILE__, __LINE__) + +namespace { + +class derived_from_path : + public fs::path +{ +public: + derived_from_path() {} + derived_from_path(derived_from_path const& that) : fs::path(static_cast< fs::path const& >(that)) {} + template< typename T > + derived_from_path(T const& that) : fs::path(that) {} + + derived_from_path& operator= (derived_from_path const& that) + { + *static_cast< fs::path* >(this) = that; + return *this; + } + template< typename T > + derived_from_path& operator= (T const& that) + { + *static_cast< fs::path* >(this) = that; + return *this; + } +}; + +class convertible_to_path +{ +private: + fs::path m_path; + +public: + convertible_to_path() {} + convertible_to_path(convertible_to_path const& that) : m_path(that.m_path) {} + template< typename T > + convertible_to_path(T const& that) : m_path(that) {} + + convertible_to_path& operator= (convertible_to_path const& that) + { + m_path = that.m_path; + return *this; + } + template< typename T > + convertible_to_path& operator= (T const& that) + { + m_path = that; + return *this; + } + + operator fs::path() const { return m_path; } +}; + +template< typename Char > +class basic_custom_string +{ +public: + typedef std::basic_string< Char > string_type; + typedef typename string_type::size_type size_type; + typedef typename string_type::difference_type difference_type; + typedef typename string_type::value_type value_type; + typedef typename string_type::reference reference; + typedef typename string_type::const_reference const_reference; + typedef typename string_type::pointer pointer; + typedef typename string_type::const_pointer const_pointer; + typedef typename string_type::iterator iterator; + typedef typename string_type::const_iterator const_iterator; + +private: + string_type m_str; + +public: + basic_custom_string() {} + explicit basic_custom_string(const_pointer str) : m_str(str) {} + explicit basic_custom_string(string_type const& str) : m_str(str) {} + template< typename OtherChar > + explicit basic_custom_string(const OtherChar* str) + { + // Do a simple character code conversion; only valid for ASCII characters + while (*str != static_cast< OtherChar >(0)) + { + m_str.push_back(static_cast< value_type >(*str)); + ++str; + } + } + + bool empty() const { return m_str.empty(); } + size_type size() const { return m_str.size(); } + + const_pointer data() const { return m_str.data(); } + const_pointer c_str() const { return m_str.c_str(); } + + iterator begin() { return m_str.begin(); } + const_iterator begin() const { return m_str.begin(); } + iterator end() { return m_str.end(); } + const_iterator end() const { return m_str.end(); } + + operator string_type() const { return m_str; } +}; + +typedef basic_custom_string< char > custom_string; +typedef basic_custom_string< wchar_t > wcustom_string; +typedef basic_custom_string< fs::path::value_type > pcustom_string; + +#if defined(__clang__) +#pragma clang diagnostic push +// unused function 'to_string' +#pragma clang diagnostic ignored "-Wunused-function" +#endif // defined(__clang__) + +inline std::string const& to_string(std::string const& s) +{ + return s; +} + +inline std::string to_string(fs::path const& p) +{ + return p.string(); +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // defined(__clang__) + +std::string platform(BOOST_PLATFORM); + +void check(const fs::path& source, const std::string& expected, const char* file, int line) +{ + if (source.string() == expected) + return; + + std::cout << file + << '(' << line << "): source: \"" << source.string() + << "\" != expected: \"" << expected + << "\"" << std::endl; + + ++::boost::detail::test_errors(); +} + +path p1("fe/fi/fo/fum"); +path p2(p1); +path p3; +path p4("foobar"); +path p5; + +// exception_tests -----------------------------------------------------------------// + +void exception_tests() +{ + std::cout << "exception_tests..." << std::endl; + const std::string str_1("string-1"); + boost::system::error_code ec(12345, boost::system::system_category()); + try + { + throw fs::filesystem_error(str_1, ec); + } + catch (const fs::filesystem_error& ex) + { + //std::cout << ex.what() << "*" << std::endl; + //BOOST_TEST(std::strcmp(ex.what(), + // "string-1: Unknown error") == 0); + BOOST_TEST(ex.code() == ec); + } + + try + { + throw fs::filesystem_error(str_1, "p1", "p2", ec); + } + catch (const fs::filesystem_error& ex) + { + //std::cout << ex.what() << "*" << std::endl; + //BOOST_TEST(std::strcmp(ex.what(), + // "string-1: Unknown error: \"p1\", \"p2\"") == 0); + BOOST_TEST(ex.code() == ec); + BOOST_TEST(ex.path1() == "p1"); + BOOST_TEST(ex.path2() == "p2"); + } +} + +// overload_tests ------------------------------------------------------------------// + +// These verify various overloads don't cause compiler errors +// They pre-date operations_unit_test.cpp + +void overload_tests() +{ + std::cout << "overload_tests..." << std::endl; + + fs::exists(p1); + fs::exists("foo"); + fs::exists(std::string("foo")); + + fs::exists(p1 / path("foo")); + fs::exists(p1 / "foo"); + fs::exists(p1 / std::string("foo")); + + fs::exists("foo" / p1); + fs::exists(std::string("foo") / p1); + + p4 /= path("foo"); + p4 /= "foo"; + p4 /= std::string("foo"); +} + +// iterator_tests ------------------------------------------------------------------// + +void iterator_tests() +{ + std::cout << "iterator_tests..." << std::endl; + + path itr_ck = ""; + path::const_iterator itr = itr_ck.begin(); + BOOST_TEST(itr == itr_ck.end()); + + itr_ck = "/"; + itr = itr_ck.begin(); + BOOST_TEST(itr->string() == "/"); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST((--itr)->string() == "/"); + + itr_ck = "foo"; + BOOST_TEST(*itr_ck.begin() == std::string("foo")); + BOOST_TEST(boost::next(itr_ck.begin()) == itr_ck.end()); + BOOST_TEST(*boost::prior(itr_ck.end()) == std::string("foo")); + BOOST_TEST(boost::prior(itr_ck.end()) == itr_ck.begin()); + + itr_ck = path("/foo"); + BOOST_TEST((itr_ck.begin())->string() == "/"); + BOOST_TEST(*boost::next(itr_ck.begin()) == std::string("foo")); + BOOST_TEST(boost::next(boost::next(itr_ck.begin())) == itr_ck.end()); + BOOST_TEST(boost::next(itr_ck.begin()) == boost::prior(itr_ck.end())); + BOOST_TEST(*boost::prior(itr_ck.end()) == std::string("foo")); + BOOST_TEST(*boost::prior(boost::prior(itr_ck.end())) == std::string("/")); + BOOST_TEST(boost::prior(boost::prior(itr_ck.end())) == itr_ck.begin()); + + itr_ck = "/foo/bar"; + itr = itr_ck.begin(); + path::const_iterator itr_begin = itr; + BOOST_TEST(itr->string() == "/"); + BOOST_TEST(*++itr == std::string("foo")); + BOOST_TEST(*++itr == std::string("bar")); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "bar"); + PATH_TEST_EQ(*--itr, "foo"); + PATH_TEST_EQ(*--itr, "/"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "../f"; // previously failed due to short name bug + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), ".."); + PATH_TEST_EQ(*++itr, "f"); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "f"); + PATH_TEST_EQ(*--itr, ".."); + BOOST_TEST(itr == itr_begin); + + // POSIX says treat "/foo/bar/" as "/foo/bar/." + itr_ck = "/foo/bar/"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "/"); + PATH_TEST_EQ(*++itr, "foo"); + BOOST_TEST(itr != itr_ck.end()); + PATH_TEST_EQ(*++itr, "bar"); + BOOST_TEST(itr != itr_ck.end()); + PATH_TEST_EQ(*++itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + BOOST_TEST(itr != itr_ck.end()); // verify the . isn't also seen as end() + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(*--itr, "bar"); + PATH_TEST_EQ(*--itr, "foo"); + PATH_TEST_EQ(*--itr, "/"); + BOOST_TEST(itr == itr_begin); + + // POSIX says treat "/f/b/" as "/f/b/." + itr_ck = "/f/b/"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "/"); + PATH_TEST_EQ(*++itr, "f"); + PATH_TEST_EQ(*++itr, "b"); + PATH_TEST_EQ(*++itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + BOOST_TEST(itr != itr_ck.end()); // verify the . isn't also seen as end() + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(*--itr, "b"); + PATH_TEST_EQ(*--itr, "f"); + PATH_TEST_EQ(*--itr, "/"); + BOOST_TEST(itr == itr_begin); + + // POSIX says treat "a/b/" as "a/b/." + // Although similar to the prior test case, this failed the ". isn't end" test due to + // a bug while the prior case did not fail. + itr_ck = "a/b/"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(*itr, "a"); + PATH_TEST_EQ(*++itr, "b"); + PATH_TEST_EQ(*++itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + BOOST_TEST(itr != itr_ck.end()); // verify the . isn't also seen as end() + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(*--itr, "b"); + PATH_TEST_EQ(*--itr, "a"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "//net"; + itr_begin = itr = itr_ck.begin(); + // two leading slashes are permitted by POSIX (as implementation defined), + // while for Windows it is always well defined (as a network name) + PATH_TEST_EQ(itr->string(), "//net"); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "//net"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "//net/"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "//net"); + PATH_TEST_EQ(*++itr, "/"); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "/"); + PATH_TEST_EQ(*--itr, "//net"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "//foo///bar///"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "//foo"); + PATH_TEST_EQ(*++itr, "/"); + PATH_TEST_EQ(*++itr, "bar"); + PATH_TEST_EQ(*++itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(*--itr, "bar"); + PATH_TEST_EQ(*--itr, "/"); + PATH_TEST_EQ(*--itr, "//foo"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "///foo///bar///"; + itr_begin = itr = itr_ck.begin(); + // three or more leading slashes are to be treated as a single slash + PATH_TEST_EQ(itr->string(), "/"); + PATH_TEST_EQ(*++itr, "foo"); + PATH_TEST_EQ(*++itr, "bar"); + PATH_TEST_EQ(*++itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(*--itr, "bar"); + PATH_TEST_EQ(*--itr, "foo"); + PATH_TEST_EQ(*--itr, "/"); + BOOST_TEST(itr == itr_begin); + + if (platform == "Windows") + { + itr_ck = "c:/"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "c:"); + PATH_TEST_EQ(*++itr, std::string("/")); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "/"); + PATH_TEST_EQ(*--itr, "c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "c:\\"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "c:"); + PATH_TEST_EQ(*++itr, "/"); // test that iteration returns generic format + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "/"); // test that iteration returns generic format + PATH_TEST_EQ(*--itr, "c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "c:/foo"; + itr_begin = itr = itr_ck.begin(); + PATH_TEST_EQ(*itr, "c:"); + PATH_TEST_EQ(*++itr, "/"); + PATH_TEST_EQ(*++itr, "foo"); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, "foo"); + PATH_TEST_EQ(*--itr, "/"); + PATH_TEST_EQ(*--itr, "c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "c:\\foo"; + itr_begin = itr = itr_ck.begin(); + BOOST_TEST_EQ(*itr, "c:"); + BOOST_TEST_EQ(*++itr, "\\"); + BOOST_TEST_EQ(*++itr, "foo"); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST_EQ(*--itr, "foo"); + BOOST_TEST_EQ(*--itr, "\\"); + BOOST_TEST_EQ(*--itr, "c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "\\\\?\\c:\\foo"; + itr_begin = itr = itr_ck.begin(); + BOOST_TEST_EQ(*itr, "\\\\?\\c:"); + BOOST_TEST_EQ(*++itr, "\\"); + BOOST_TEST_EQ(*++itr, "foo"); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST_EQ(*--itr, "foo"); + BOOST_TEST_EQ(*--itr, "\\"); + BOOST_TEST_EQ(*--itr, "\\\\?\\c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "\\\\.\\c:\\foo"; + itr_begin = itr = itr_ck.begin(); + BOOST_TEST_EQ(*itr, "\\\\.\\c:"); + BOOST_TEST_EQ(*++itr, "\\"); + BOOST_TEST_EQ(*++itr, "foo"); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST_EQ(*--itr, "foo"); + BOOST_TEST_EQ(*--itr, "\\"); + BOOST_TEST_EQ(*--itr, "\\\\.\\c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "\\??\\c:\\foo"; + itr_begin = itr = itr_ck.begin(); + BOOST_TEST_EQ(*itr, "\\??\\c:"); + BOOST_TEST_EQ(*++itr, "\\"); + BOOST_TEST_EQ(*++itr, "foo"); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST_EQ(*--itr, "foo"); + BOOST_TEST_EQ(*--itr, "\\"); + BOOST_TEST_EQ(*--itr, "\\??\\c:"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "\\\\\\foo\\\\\\bar\\\\\\"; + itr_begin = itr = itr_ck.begin(); + // three or more leading slashes are to be treated as a single slash + PATH_TEST_EQ(itr->string(), "/"); + PATH_TEST_EQ(*++itr, "foo"); + PATH_TEST_EQ(*++itr, "bar"); + PATH_TEST_EQ(*++itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + BOOST_TEST(++itr == itr_ck.end()); + PATH_TEST_EQ(*--itr, BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(*--itr, "bar"); + PATH_TEST_EQ(*--itr, "foo"); + PATH_TEST_EQ(*--itr, "/"); + BOOST_TEST(itr == itr_begin); + + itr_ck = "c:foo"; + itr_begin = itr = itr_ck.begin(); + BOOST_TEST(*itr == std::string("c:")); + BOOST_TEST(*++itr == std::string("foo")); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST(*--itr == std::string("foo")); + BOOST_TEST(*--itr == std::string("c:")); + BOOST_TEST(itr == itr_begin); + + itr_ck = "c:foo/"; + itr_begin = itr = itr_ck.begin(); + BOOST_TEST(*itr == std::string("c:")); + BOOST_TEST(*++itr == std::string("foo")); + BOOST_TEST(*++itr == std::string(BOOST_FILESYSTEM_V3_TRAILING_DOT)); + BOOST_TEST(++itr == itr_ck.end()); + BOOST_TEST(*--itr == std::string(BOOST_FILESYSTEM_V3_TRAILING_DOT)); + BOOST_TEST(*--itr == std::string("foo")); + BOOST_TEST(*--itr == std::string("c:")); + BOOST_TEST(itr == itr_begin); + + itr_ck = path("c:"); + BOOST_TEST(*itr_ck.begin() == std::string("c:")); + BOOST_TEST(next(itr_ck.begin()) == itr_ck.end()); + BOOST_TEST(prior(itr_ck.end()) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("c:")); + + itr_ck = path("c:/"); + BOOST_TEST(*itr_ck.begin() == std::string("c:")); + BOOST_TEST(*next(itr_ck.begin()) == std::string("/")); + BOOST_TEST(next(next(itr_ck.begin())) == itr_ck.end()); + BOOST_TEST(prior(prior(itr_ck.end())) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("/")); + BOOST_TEST(*prior(prior(itr_ck.end())) == std::string("c:")); + + itr_ck = path("c:foo"); + BOOST_TEST(*itr_ck.begin() == std::string("c:")); + BOOST_TEST(*next(itr_ck.begin()) == std::string("foo")); + BOOST_TEST(next(next(itr_ck.begin())) == itr_ck.end()); + BOOST_TEST(prior(prior(itr_ck.end())) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("foo")); + BOOST_TEST(*prior(prior(itr_ck.end())) == std::string("c:")); + + itr_ck = path("c:/foo"); + BOOST_TEST(*itr_ck.begin() == std::string("c:")); + BOOST_TEST(*next(itr_ck.begin()) == std::string("/")); + BOOST_TEST(*next(next(itr_ck.begin())) == std::string("foo")); + BOOST_TEST(next(next(next(itr_ck.begin()))) == itr_ck.end()); + BOOST_TEST(prior(prior(prior(itr_ck.end()))) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("foo")); + BOOST_TEST(*prior(prior(itr_ck.end())) == std::string("/")); + BOOST_TEST(*prior(prior(prior(itr_ck.end()))) == std::string("c:")); + + itr_ck = path("//net"); + BOOST_TEST(*itr_ck.begin() == std::string("//net")); + BOOST_TEST(next(itr_ck.begin()) == itr_ck.end()); + BOOST_TEST(prior(itr_ck.end()) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("//net")); + + itr_ck = path("//net/"); + PATH_TEST_EQ(itr_ck.begin()->string(), "//net"); + PATH_TEST_EQ(next(itr_ck.begin())->string(), "/"); + BOOST_TEST(next(next(itr_ck.begin())) == itr_ck.end()); + BOOST_TEST(prior(prior(itr_ck.end())) == itr_ck.begin()); + PATH_TEST_EQ(prior(itr_ck.end())->string(), "/"); + PATH_TEST_EQ(prior(prior(itr_ck.end()))->string(), "//net"); + + itr_ck = path("//net/foo"); + BOOST_TEST(*itr_ck.begin() == std::string("//net")); + BOOST_TEST(*next(itr_ck.begin()) == std::string("/")); + BOOST_TEST(*next(next(itr_ck.begin())) == std::string("foo")); + BOOST_TEST(next(next(next(itr_ck.begin()))) == itr_ck.end()); + BOOST_TEST(prior(prior(prior(itr_ck.end()))) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("foo")); + BOOST_TEST(*prior(prior(itr_ck.end())) == std::string("/")); + BOOST_TEST(*prior(prior(prior(itr_ck.end()))) == std::string("//net")); + + itr_ck = path("prn:"); + BOOST_TEST(*itr_ck.begin() == std::string("prn:")); + BOOST_TEST(next(itr_ck.begin()) == itr_ck.end()); + BOOST_TEST(prior(itr_ck.end()) == itr_ck.begin()); + BOOST_TEST(*prior(itr_ck.end()) == std::string("prn:")); + } + else + { + itr_ck = "///"; + itr = itr_ck.begin(); + PATH_TEST_EQ(itr->string(), "/"); + BOOST_TEST(++itr == itr_ck.end()); + } +} + +// non_member_tests ----------------------------------------------------------------// + +void non_member_tests() +{ + std::cout << "non_member_tests..." << std::endl; + + // test non-member functions, particularly operator overloads + + path e, e2; + std::string es, es2; + char ecs[] = ""; + char ecs2[] = ""; + + char acs[] = "a"; + std::string as(acs); + path a(as); + + char acs2[] = "a"; + std::string as2(acs2); + path a2(as2); + + char bcs[] = "b"; + std::string bs(bcs); + path b(bs); + + // swap + a.swap(b); + BOOST_TEST(a.string() == "b"); + BOOST_TEST(b.string() == "a"); + fs::swap(a, b); + BOOST_TEST(a.string() == "a"); + BOOST_TEST(b.string() == "b"); + + // probe operator / + PATH_TEST_EQ(path("") / ".", "."); + PATH_TEST_EQ(path("") / "..", ".."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("/") / "/", "//"); + PATH_TEST_EQ(path("/") / "/foo", "//foo"); + PATH_TEST_EQ(path("/foo") / "/bar", "/foo/bar"); +#else + PATH_TEST_EQ(path("/") / "/", "/"); + PATH_TEST_EQ(path("/") / "/foo", "/foo"); + PATH_TEST_EQ(path("/foo") / "/bar", "/bar"); +#endif + + if (platform == "Windows") + { + BOOST_TEST(path("foo\\bar") == "foo/bar"); + BOOST_TEST((b / a).native() == path("b\\a").native()); + BOOST_TEST((bs / a).native() == path("b\\a").native()); + BOOST_TEST((bcs / a).native() == path("b\\a").native()); + BOOST_TEST((b / as).native() == path("b\\a").native()); + BOOST_TEST((b / acs).native() == path("b\\a").native()); + PATH_TEST_EQ(path("a") / "b", "a\\b"); + PATH_TEST_EQ(path("foo") / path("bar"), "foo\\bar"); // path arg + PATH_TEST_EQ(path("foo") / "bar", "foo\\bar"); // const char* arg + PATH_TEST_EQ(path("foo") / path("woo/bar").filename(), "foo\\bar"); // const std::string & arg + PATH_TEST_EQ("foo" / path("bar"), "foo\\bar"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("..") / "", ".."); +#else + PATH_TEST_EQ(path("..") / "", "..\\"); +#endif + PATH_TEST_EQ(path("..") / "..", "..\\.."); + PATH_TEST_EQ(path("/") / "..", "/.."); + PATH_TEST_EQ(path("/..") / "..", "/..\\.."); + PATH_TEST_EQ(path("..") / "foo", "..\\foo"); + PATH_TEST_EQ(path("foo") / "..", "foo\\.."); + PATH_TEST_EQ(path("..") / "f", "..\\f"); + PATH_TEST_EQ(path("/..") / "f", "/..\\f"); + PATH_TEST_EQ(path("f") / "..", "f\\.."); + PATH_TEST_EQ(path("foo") / ".." / "..", "foo\\..\\.."); + PATH_TEST_EQ(path("foo") / ".." / ".." / "..", "foo\\..\\..\\.."); + PATH_TEST_EQ(path("f") / ".." / "b", "f\\..\\b"); + PATH_TEST_EQ(path("foo") / ".." / "bar", "foo\\..\\bar"); + PATH_TEST_EQ(path("foo") / "bar" / "..", "foo\\bar\\.."); + PATH_TEST_EQ(path("foo") / "bar" / ".." / "..", "foo\\bar\\..\\.."); + PATH_TEST_EQ(path("foo") / "bar" / ".." / "blah", "foo\\bar\\..\\blah"); + PATH_TEST_EQ(path("f") / "b" / "..", "f\\b\\.."); + PATH_TEST_EQ(path("f") / "b" / ".." / "a", "f\\b\\..\\a"); + PATH_TEST_EQ(path("foo") / "bar" / "blah" / ".." / "..", "foo\\bar\\blah\\..\\.."); + PATH_TEST_EQ(path("foo") / "bar" / "blah" / ".." / ".." / "bletch", "foo\\bar\\blah\\..\\..\\bletch"); + + PATH_TEST_EQ(path(".") / "foo", ".\\foo"); + PATH_TEST_EQ(path(".") / "..", ".\\.."); + PATH_TEST_EQ(path("foo") / ".", "foo\\."); + PATH_TEST_EQ(path("..") / ".", "..\\."); + PATH_TEST_EQ(path(".") / ".", ".\\."); + PATH_TEST_EQ(path(".") / "." / ".", ".\\.\\."); + PATH_TEST_EQ(path(".") / "foo" / ".", ".\\foo\\."); + PATH_TEST_EQ(path("foo") / "." / "bar", "foo\\.\\bar"); + PATH_TEST_EQ(path("foo") / "." / ".", "foo\\.\\."); + PATH_TEST_EQ(path("foo") / "." / "..", "foo\\.\\.."); + PATH_TEST_EQ(path(".") / "." / "..", ".\\.\\.."); + PATH_TEST_EQ(path(".") / ".." / ".", ".\\..\\."); + PATH_TEST_EQ(path("..") / "." / ".", "..\\.\\."); + +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("\\\\net1\\foo") / "\\\\net2\\bar", "\\\\net1\\foo\\\\net2\\bar"); + PATH_TEST_EQ(path("\\\\net1\\foo") / "\\bar", "\\\\net1\\foo\\bar"); + PATH_TEST_EQ(path("c:\\foo") / "d:\\bar", "c:\\foo\\d:\\bar"); + PATH_TEST_EQ(path("c:\\foo") / "\\bar", "c:\\foo\\bar"); + PATH_TEST_EQ(path("c:foo") / "\\bar", "c:foo\\bar"); +#else + PATH_TEST_EQ(path("\\\\net1\\foo") / "\\\\net2\\bar", "\\\\net2\\bar"); + PATH_TEST_EQ(path("\\\\net1\\foo") / "\\bar", "\\\\net1\\bar"); + PATH_TEST_EQ(path("c:\\foo") / "d:\\bar", "d:\\bar"); + PATH_TEST_EQ(path("c:\\foo") / "\\bar", "c:\\bar"); + PATH_TEST_EQ(path("c:foo") / "\\bar", "c:\\bar"); +#endif + PATH_TEST_EQ(path("c:foo") / "bar", "c:foo\\bar"); + } + else // POSIX + { + PATH_TEST_EQ(b / a, "b/a"); + PATH_TEST_EQ(bs / a, "b/a"); + PATH_TEST_EQ(bcs / a, "b/a"); + PATH_TEST_EQ(b / as, "b/a"); + PATH_TEST_EQ(b / acs, "b/a"); + PATH_TEST_EQ(path("a") / "b", "a/b"); + PATH_TEST_EQ(path("") / "..", ".."); + PATH_TEST_EQ(path("foo") / path("bar"), "foo/bar"); // path arg + PATH_TEST_EQ(path("foo") / "bar", "foo/bar"); // const char* arg + PATH_TEST_EQ(path("foo") / path("woo/bar").filename(), "foo/bar"); // const std::string & arg + PATH_TEST_EQ("foo" / path("bar"), "foo/bar"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("..") / "", ".."); +#else + PATH_TEST_EQ(path("..") / "", "../"); +#endif + PATH_TEST_EQ(path("..") / "..", "../.."); + PATH_TEST_EQ(path("/") / "..", "/.."); + PATH_TEST_EQ(path("/..") / "..", "/../.."); + PATH_TEST_EQ(path("..") / "foo", "../foo"); + PATH_TEST_EQ(path("foo") / "..", "foo/.."); + PATH_TEST_EQ(path("..") / "f", "../f"); + PATH_TEST_EQ(path("/..") / "f", "/../f"); + PATH_TEST_EQ(path("f") / "..", "f/.."); + PATH_TEST_EQ(path("foo") / ".." / "..", "foo/../.."); + PATH_TEST_EQ(path("foo") / ".." / ".." / "..", "foo/../../.."); + PATH_TEST_EQ(path("f") / ".." / "b", "f/../b"); + PATH_TEST_EQ(path("foo") / ".." / "bar", "foo/../bar"); + PATH_TEST_EQ(path("foo") / "bar" / "..", "foo/bar/.."); + PATH_TEST_EQ(path("foo") / "bar" / ".." / "..", "foo/bar/../.."); + PATH_TEST_EQ(path("foo") / "bar" / ".." / "blah", "foo/bar/../blah"); + PATH_TEST_EQ(path("f") / "b" / "..", "f/b/.."); + PATH_TEST_EQ(path("f") / "b" / ".." / "a", "f/b/../a"); + PATH_TEST_EQ(path("foo") / "bar" / "blah" / ".." / "..", "foo/bar/blah/../.."); + PATH_TEST_EQ(path("foo") / "bar" / "blah" / ".." / ".." / "bletch", "foo/bar/blah/../../bletch"); + + PATH_TEST_EQ(path(".") / "foo", "./foo"); + PATH_TEST_EQ(path(".") / "..", "./.."); + PATH_TEST_EQ(path("foo") / ".", "foo/."); + PATH_TEST_EQ(path("..") / ".", "../."); + PATH_TEST_EQ(path(".") / ".", "./."); + PATH_TEST_EQ(path(".") / "." / ".", "././."); + PATH_TEST_EQ(path(".") / "foo" / ".", "./foo/."); + PATH_TEST_EQ(path("foo") / "." / "bar", "foo/./bar"); + PATH_TEST_EQ(path("foo") / "." / ".", "foo/./."); + PATH_TEST_EQ(path("foo") / "." / "..", "foo/./.."); + PATH_TEST_EQ(path(".") / "." / "..", "././.."); + PATH_TEST_EQ(path(".") / ".." / ".", "./../."); + PATH_TEST_EQ(path("..") / "." / ".", ".././."); + +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("//net1/foo") / "//net2/bar", "//net1/foo//net2/bar"); + PATH_TEST_EQ(path("//net1/foo") / "/bar", "//net1/foo/bar"); +#else + PATH_TEST_EQ(path("//net1/foo") / "//net2/bar", "//net2/bar"); + PATH_TEST_EQ(path("//net1/foo") / "/bar", "/bar"); +#endif + PATH_TEST_EQ(path("//net1/foo") / "bar", "//net1/foo/bar"); + } + + // probe operator < + BOOST_TEST(!(e < e2)); + BOOST_TEST(!(es < e2)); + BOOST_TEST(!(ecs < e2)); + BOOST_TEST(!(e < es2)); + BOOST_TEST(!(e < ecs2)); + + BOOST_TEST(e < a); + BOOST_TEST(es < a); + BOOST_TEST(ecs < a); + BOOST_TEST(e < as); + BOOST_TEST(e < acs); + + BOOST_TEST(a < b); + BOOST_TEST(as < b); + BOOST_TEST(acs < b); + BOOST_TEST(a < bs); + BOOST_TEST(a < bcs); + + BOOST_TEST(!(a < a2)); + BOOST_TEST(!(as < a2)); + BOOST_TEST(!(acs < a2)); + BOOST_TEST(!(a < as2)); + BOOST_TEST(!(a < acs2)); + + // make sure basic_path overloads don't conflict with std::string overloads + + BOOST_TEST(!(as < as)); + BOOST_TEST(!(as < acs)); + BOOST_TEST(!(acs < as)); + + // character set reality check before lexicographical tests + BOOST_TEST(std::string("a.b") < std::string("a/b")); + // verify compare is actually lexicographical + BOOST_TEST(path("a/b") < path("a.b")); + BOOST_TEST(path("a/b") == path("a///b")); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(path("a/b/") == path("a/b/.")); +#else + BOOST_TEST(path("a/b/") != path("a/b/.")); +#endif + BOOST_TEST(path("a/b") != path("a/b/")); + + // make sure the derivative operators also work + + BOOST_TEST(b > a); + BOOST_TEST(b > as); + BOOST_TEST(b > acs); + BOOST_TEST(bs > a); + BOOST_TEST(bcs > a); + + BOOST_TEST(!(a2 > a)); + BOOST_TEST(!(a2 > as)); + BOOST_TEST(!(a2 > acs)); + BOOST_TEST(!(as2 > a)); + BOOST_TEST(!(acs2 > a)); + + BOOST_TEST(a <= b); + BOOST_TEST(as <= b); + BOOST_TEST(acs <= b); + BOOST_TEST(a <= bs); + BOOST_TEST(a <= bcs); + + BOOST_TEST(a <= a2); + BOOST_TEST(as <= a2); + BOOST_TEST(acs <= a2); + BOOST_TEST(a <= as2); + BOOST_TEST(a <= acs2); + + BOOST_TEST(b >= a); + BOOST_TEST(bs >= a); + BOOST_TEST(bcs >= a); + BOOST_TEST(b >= as); + BOOST_TEST(b >= acs); + + BOOST_TEST(a2 >= a); + BOOST_TEST(as2 >= a); + BOOST_TEST(acs2 >= a); + BOOST_TEST(a2 >= as); + BOOST_TEST(a2 >= acs); + + // operator == and != are implemented separately, so test separately + + path p101("fe/fi/fo/fum"); + path p102(p101); + path p103("fe/fi/fo/fumm"); + BOOST_TEST(p101.string() != p103.string()); + + // check each overload + BOOST_TEST(p101 != p103); + BOOST_TEST(p101 != p103.string()); + BOOST_TEST(p101 != p103.string().c_str()); + BOOST_TEST(p101.string() != p103); + BOOST_TEST(p101.string().c_str() != p103); + + p103 = p102; + BOOST_TEST(p101.string() == p103.string()); + + // check each overload + BOOST_TEST(p101 == p103); + BOOST_TEST(p101 == p103.string()); + BOOST_TEST(p101 == p103.string().c_str()); + BOOST_TEST(p101.string() == p103); + BOOST_TEST(p101.string().c_str() == p103); + + if (platform == "Windows") + { + std::cout << " Windows relational tests..." << std::endl; + path p10("c:\\file"); + path p11("c:/file"); + // check each overload + BOOST_TEST(p10.generic_string() == p11.generic_string()); + BOOST_TEST(p10 == p11); + BOOST_TEST(p10 == p11.string()); + BOOST_TEST(p10 == p11.string().c_str()); + BOOST_TEST(p10.string() == p11); + BOOST_TEST(p10.string().c_str() == p11); + BOOST_TEST(p10 == L"c:\\file"); + BOOST_TEST(p10 == L"c:/file"); + BOOST_TEST(p11 == L"c:\\file"); + BOOST_TEST(p11 == L"c:/file"); + BOOST_TEST(L"c:\\file" == p10); + BOOST_TEST(L"c:/file" == p10); + BOOST_TEST(L"c:\\file" == p11); + BOOST_TEST(L"c:/file" == p11); + + BOOST_TEST(!(p10.generic_string() != p11.generic_string())); + BOOST_TEST(!(p10 != p11)); + BOOST_TEST(!(p10 != p11.string())); + BOOST_TEST(!(p10 != p11.string().c_str())); + BOOST_TEST(!(p10.string() != p11)); + BOOST_TEST(!(p10.string().c_str() != p11)); + BOOST_TEST(!(p10 != L"c:\\file")); + BOOST_TEST(!(p10 != L"c:/file")); + BOOST_TEST(!(p11 != L"c:\\file")); + BOOST_TEST(!(p11 != L"c:/file")); + BOOST_TEST(!(L"c:\\file" != p10)); + BOOST_TEST(!(L"c:/file" != p10)); + BOOST_TEST(!(L"c:\\file" != p11)); + BOOST_TEST(!(L"c:/file" != p11)); + + BOOST_TEST(!(p10.string() < p11.string())); + BOOST_TEST(!(p10 < p11)); + BOOST_TEST(!(p10 < p11.string())); + BOOST_TEST(!(p10 < p11.string().c_str())); + BOOST_TEST(!(p10.string() < p11)); + BOOST_TEST(!(p10.string().c_str() < p11)); + BOOST_TEST(!(p10 < L"c:\\file")); + BOOST_TEST(!(p10 < L"c:/file")); + BOOST_TEST(!(p11 < L"c:\\file")); + BOOST_TEST(!(p11 < L"c:/file")); + BOOST_TEST(!(L"c:\\file" < p10)); + BOOST_TEST(!(L"c:/file" < p10)); + BOOST_TEST(!(L"c:\\file" < p11)); + BOOST_TEST(!(L"c:/file" < p11)); + + BOOST_TEST(!(p10.generic_string() > p11.generic_string())); + BOOST_TEST(!(p10 > p11)); + BOOST_TEST(!(p10 > p11.string())); + BOOST_TEST(!(p10 > p11.string().c_str())); + BOOST_TEST(!(p10.string() > p11)); + BOOST_TEST(!(p10.string().c_str() > p11)); + BOOST_TEST(!(p10 > L"c:\\file")); + BOOST_TEST(!(p10 > L"c:/file")); + BOOST_TEST(!(p11 > L"c:\\file")); + BOOST_TEST(!(p11 > L"c:/file")); + BOOST_TEST(!(L"c:\\file" > p10)); + BOOST_TEST(!(L"c:/file" > p10)); + BOOST_TEST(!(L"c:\\file" > p11)); + BOOST_TEST(!(L"c:/file" > p11)); + } + + // relative + + BOOST_TEST(fs::relative("/abc/def", "/abc") == path("def")); + BOOST_TEST(fs::relative("abc/def", "abc") == path("def")); + BOOST_TEST(fs::relative("/abc/xyz/def", "/abc") == path("xyz/def")); + BOOST_TEST(fs::relative("abc/xyz/def", "abc") == path("xyz/def")); + + if (platform == "Windows") + { + std::cout << " Windows relatie tests..." << std::endl; + BOOST_TEST(fs::relative("\\abc\\xyz\\def", "/abc") == path("xyz/def")); + std::cout << " fs::relative(\"/abc/xyz/def\", \"/abc\") is " + << fs::relative("/abc/xyz/def", "/abc") << std::endl; + BOOST_TEST(fs::relative("abc\\xyz\\def", "abc") == path("xyz/def")); + } +} + +// query_and_decomposition_tests ---------------------------------------------------// +// +// remove_filename() is also tested here, because its specification depends on +// a decomposition function. + +void query_and_decomposition_tests() +{ + std::cout << "query_and_decomposition_tests..." << std::endl; + + // these are the examples given in reference docs, so check they work + BOOST_TEST(path("/foo/bar.txt").parent_path() == "/foo"); + BOOST_TEST(path("/foo/bar").parent_path() == "/foo"); + BOOST_TEST(path("/foo/bar/").parent_path() == "/foo/bar"); + BOOST_TEST(path("/").parent_path() == ""); + BOOST_TEST(path(".").parent_path() == ""); + BOOST_TEST(path("..").parent_path() == ""); + BOOST_TEST(path("/foo/bar.txt").filename() == "bar.txt"); + BOOST_TEST(path("/foo/bar").filename() == "bar"); + BOOST_TEST(path("/foo/bar/").filename() == BOOST_FILESYSTEM_V3_TRAILING_DOT); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(path("/").filename() == "/"); +#else + BOOST_TEST(path("/").filename() == ""); +#endif + BOOST_TEST(path(".").filename() == "."); + BOOST_TEST(path("..").filename() == ".."); + + // stem() tests not otherwise covered + BOOST_TEST(path(".").stem() == "."); + BOOST_TEST(path("..").stem() == ".."); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(path(".a").stem() == ""); +#else + BOOST_TEST(path(".a").stem() == ".a"); +#endif + BOOST_TEST(path("b").stem() == "b"); + BOOST_TEST(path("a/b.txt").stem() == "b"); + BOOST_TEST(path("a/b.").stem() == "b"); + BOOST_TEST(path("a.b.c").stem() == "a.b"); + BOOST_TEST(path("a.b.c.").stem() == "a.b.c"); + + // extension() tests not otherwise covered + BOOST_TEST(path(".").extension() == ""); + BOOST_TEST(path("..").extension() == ""); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(path(".a").extension() == ".a"); +#else + BOOST_TEST(path(".a").extension() == ""); +#endif + BOOST_TEST(path("a/b").extension() == ""); + BOOST_TEST(path("a.b/c").extension() == ""); + BOOST_TEST(path("a/b.txt").extension() == ".txt"); + BOOST_TEST(path("a/b.").extension() == "."); + BOOST_TEST(path("a.b.c").extension() == ".c"); + BOOST_TEST(path("a.b.c.").extension() == "."); + BOOST_TEST(path("a/").extension() == ""); + + // main q & d test sequence + path p; + path q; + + p = q = ""; + BOOST_TEST(p.relative_path().string() == ""); + BOOST_TEST(p.parent_path().string() == ""); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == ""); + BOOST_TEST(p.stem() == ""); + BOOST_TEST(p.extension() == ""); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == ""); + BOOST_TEST(p.root_path().string() == ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "/"; + BOOST_TEST(p.relative_path().string() == ""); + BOOST_TEST(p.parent_path().string() == ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == "/"); + BOOST_TEST(p.stem() == "/"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + BOOST_TEST(p.filename() == ""); + BOOST_TEST(p.stem() == ""); +#endif + BOOST_TEST(p.extension() == ""); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == "/"); + BOOST_TEST(p.root_path().string() == "/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); +#endif + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + if (platform == "POSIX") + BOOST_TEST(p.is_absolute()); + else + BOOST_TEST(!p.is_absolute()); + + p = q = "//"; + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "//"); + PATH_TEST_EQ(p.stem(), "//"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); + PATH_TEST_EQ(p.stem(), ""); +#endif + PATH_TEST_EQ(p.extension(), ""); + PATH_TEST_EQ(p.root_name(), "//"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "//"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); +#endif + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "///"; + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "/"); + PATH_TEST_EQ(p.stem(), "/"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); + PATH_TEST_EQ(p.stem(), ""); +#endif + PATH_TEST_EQ(p.extension(), ""); + PATH_TEST_EQ(p.root_name(), ""); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); +#endif + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + if (platform == "POSIX") + BOOST_TEST(p.is_absolute()); + else + BOOST_TEST(!p.is_absolute()); + + p = q = "."; + BOOST_TEST(p.relative_path().string() == "."); + BOOST_TEST(p.parent_path().string() == ""); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == "."); + BOOST_TEST(p.stem() == "."); + BOOST_TEST(p.extension() == ""); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == ""); + BOOST_TEST(p.root_path().string() == ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = ".."; + BOOST_TEST(p.relative_path().string() == ".."); + BOOST_TEST(p.parent_path().string() == ""); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == ".."); + BOOST_TEST(p.stem() == ".."); + BOOST_TEST(p.extension() == ""); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == ""); + BOOST_TEST(p.root_path().string() == ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "foo"; + BOOST_TEST(p.relative_path().string() == "foo"); + BOOST_TEST(p.parent_path().string() == ""); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == "foo"); + BOOST_TEST(p.stem() == "foo"); + BOOST_TEST(p.extension() == ""); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == ""); + BOOST_TEST(p.root_path().string() == ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "/foo"; + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "/"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.stem(), "foo"); + PATH_TEST_EQ(p.extension(), ""); + PATH_TEST_EQ(p.root_name(), ""); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); + BOOST_TEST(!p.has_extension()); + BOOST_TEST(p.has_parent_path()); + if (platform == "POSIX") + BOOST_TEST(p.is_absolute()); + else + BOOST_TEST(!p.is_absolute()); + + p = q = "/foo/"; + PATH_TEST_EQ(p.relative_path().string(), "foo/"); + PATH_TEST_EQ(p.parent_path().string(), "/foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); +#endif + PATH_TEST_EQ(p.filename(), BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(p.stem(), BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(p.extension(), ""); + PATH_TEST_EQ(p.root_name(), ""); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); +#endif + BOOST_TEST(!p.has_extension()); + BOOST_TEST(p.has_parent_path()); + if (platform == "POSIX") + BOOST_TEST(p.is_absolute()); + else + BOOST_TEST(!p.is_absolute()); + + p = q = "///foo"; + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "/"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "///"); +#endif + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), ""); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + if (platform == "POSIX") + BOOST_TEST(p.is_absolute()); + else + BOOST_TEST(!p.is_absolute()); + + p = q = "foo/bar"; + BOOST_TEST(p.relative_path().string() == "foo/bar"); + BOOST_TEST(p.parent_path().string() == "foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "foo/"); +#endif + BOOST_TEST(p.filename() == "bar"); + BOOST_TEST(p.stem() == "bar"); + BOOST_TEST(p.extension() == ""); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == ""); + BOOST_TEST(p.root_path().string() == ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); + BOOST_TEST(!p.has_extension()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "../foo"; + BOOST_TEST(p.relative_path().string() == "../foo"); + BOOST_TEST(p.parent_path().string() == ".."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "../"); +#endif + BOOST_TEST(p.filename() == "foo"); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == ""); + BOOST_TEST(p.root_path().string() == ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "..///foo"; + PATH_TEST_EQ(p.relative_path().string(), "..///foo"); + PATH_TEST_EQ(p.parent_path().string(), ".."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "..///"); +#endif + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), ""); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), ""); + BOOST_TEST(!p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = "/foo/bar"; + BOOST_TEST(p.relative_path().string() == "foo/bar"); + BOOST_TEST(p.parent_path().string() == "/foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "/foo/"); +#endif + BOOST_TEST(p.filename() == "bar"); + BOOST_TEST(p.root_name() == ""); + BOOST_TEST(p.root_directory() == "/"); + BOOST_TEST(p.root_path().string() == "/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(!p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + if (platform == "POSIX") + BOOST_TEST(p.is_absolute()); + else + BOOST_TEST(!p.is_absolute()); + + // Both POSIX and Windows allow two leading slashs + // (POSIX meaning is implementation defined) + PATH_TEST_EQ(path("//resource"), "//resource"); + PATH_TEST_EQ(path("//resource/"), "//resource/"); + PATH_TEST_EQ(path("//resource/foo"), "//resource/foo"); + + p = q = path("//net"); + PATH_TEST_EQ(p.string(), "//net"); + PATH_TEST_EQ(p.relative_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); +#endif + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(p.filename(), "//net"); +#else + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "//net"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "//net"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("//net/"); + BOOST_TEST(p.relative_path().string() == ""); + BOOST_TEST(p.parent_path().string() == "//net"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == "/"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + BOOST_TEST(p.filename() == ""); +#endif + BOOST_TEST(p.root_name() == "//net"); + BOOST_TEST(p.root_directory() == "/"); + BOOST_TEST(p.root_path().string() == "//net/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("//net/foo"); + BOOST_TEST(p.relative_path().string() == "foo"); + BOOST_TEST(p.parent_path().string() == "//net/"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + BOOST_TEST(p.filename() == "foo"); + BOOST_TEST(p.root_name() == "//net"); + BOOST_TEST(p.root_directory() == "/"); + BOOST_TEST(p.root_path().string() == "//net/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("//net///foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "//net/"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "//net///"); +#endif + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "//net"); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "//net/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + // ticket 2739, infinite recursion leading to stack overflow, was caused + // by failure to handle this case correctly on Windows. + p = path(":"); + PATH_TEST_EQ(p.parent_path().string(), ""); + PATH_TEST_EQ(p.filename(), ":"); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(p.has_filename()); + + + // Windows specific tests + if (platform == "Windows") + { + p = q = path("\\\\?\\"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\\\?\\"); + PATH_TEST_EQ(p.stem(), "\\\\?\\"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); + PATH_TEST_EQ(p.stem(), ""); +#endif + PATH_TEST_EQ(p.extension(), ""); + PATH_TEST_EQ(p.root_name(), "\\\\?\\"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\\\?\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); +#endif + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\\\.\\"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\\\.\\"); + PATH_TEST_EQ(p.stem(), "\\\\"); + PATH_TEST_EQ(p.extension(), ".\\"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); + PATH_TEST_EQ(p.stem(), ""); + PATH_TEST_EQ(p.extension(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\\\.\\"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\\\.\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); + BOOST_TEST(p.has_extension()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); + BOOST_TEST(!p.has_extension()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\??\\"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\??\\"); + PATH_TEST_EQ(p.stem(), "\\??\\"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); + PATH_TEST_EQ(p.stem(), ""); +#endif + PATH_TEST_EQ(p.extension(), ""); + PATH_TEST_EQ(p.root_name(), "\\??\\"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\??\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_stem()); +#else + BOOST_TEST(!p.has_filename()); + BOOST_TEST(!p.has_stem()); +#endif + BOOST_TEST(!p.has_extension()); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("c:"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "c:"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\\\?\\c:"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\\\?\\c:"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\\\?\\c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\\\?\\c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\\\.\\c:"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\\\.\\c:"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\\\.\\c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\\\.\\c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\??\\c:"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\??\\c:"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\??\\c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\??\\c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("c:foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "c:"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\\\?\\c:foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "\\\\?\\c:"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "\\\\?\\c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\\\?\\c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\\\.\\c:foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "\\\\.\\c:"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "\\\\.\\c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\\\.\\c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\??\\c:foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "\\??\\c:"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "\\??\\c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "\\??\\c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("c:/"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), "c:"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "/"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "c:/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("\\\\?\\c:\\"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), "\\\\?\\c:"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\\\?\\c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\\\?\\c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("\\\\.\\c:\\"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), "\\\\.\\c:"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\\\.\\c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\\\.\\c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("\\??\\c:\\"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), "\\??\\c:"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "\\"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "\\??\\c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\??\\c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("c:.."); + PATH_TEST_EQ(p.relative_path().string(), ".."); + PATH_TEST_EQ(p.parent_path().string(), "c:"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), ".."); + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "c:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("c:/foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "c:/"); + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "c:/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("c://foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "c:/"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "c://"); +#endif + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), "/"); + PATH_TEST_EQ(p.root_path().string(), "c:/"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("c:\\foo\\bar"); + PATH_TEST_EQ(p.relative_path().string(), "foo\\bar"); + PATH_TEST_EQ(p.parent_path().string(), "c:\\foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "c:\\foo\\"); +#endif + PATH_TEST_EQ(p.filename(), "bar"); + PATH_TEST_EQ(p.root_name(), "c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("\\\\?\\c:\\foo\\bar"); + PATH_TEST_EQ(p.relative_path().string(), "foo\\bar"); + PATH_TEST_EQ(p.parent_path().string(), "\\\\?\\c:\\foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "\\\\?\\c:\\foo\\"); +#endif + PATH_TEST_EQ(p.filename(), "bar"); + PATH_TEST_EQ(p.root_name(), "\\\\?\\c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\\\?\\c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("\\\\.\\c:\\foo\\bar"); + PATH_TEST_EQ(p.relative_path().string(), "foo\\bar"); + PATH_TEST_EQ(p.parent_path().string(), "\\\\.\\c:\\foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "\\\\.\\c:\\foo\\"); +#endif + PATH_TEST_EQ(p.filename(), "bar"); + PATH_TEST_EQ(p.root_name(), "\\\\.\\c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\\\.\\c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("\\??\\c:\\foo\\bar"); + PATH_TEST_EQ(p.relative_path().string(), "foo\\bar"); + PATH_TEST_EQ(p.parent_path().string(), "\\??\\c:\\foo"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "\\??\\c:\\foo\\"); +#endif + PATH_TEST_EQ(p.filename(), "bar"); + PATH_TEST_EQ(p.root_name(), "\\??\\c:"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\??\\c:\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + + p = q = path("prn:"); + PATH_TEST_EQ(p.relative_path().string(), ""); + PATH_TEST_EQ(p.parent_path().string(), ""); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); + PATH_TEST_EQ(p.filename(), "prn:"); +#else + PATH_TEST_EQ(q.remove_filename().string(), p.string()); + PATH_TEST_EQ(p.filename(), ""); +#endif + PATH_TEST_EQ(p.root_name(), "prn:"); + PATH_TEST_EQ(p.root_directory(), ""); + PATH_TEST_EQ(p.root_path().string(), "prn:"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(!p.has_root_directory()); + BOOST_TEST(!p.has_relative_path()); +#if BOOST_FILESYSTEM_VERSION == 3 + BOOST_TEST(p.has_filename()); +#else + BOOST_TEST(!p.has_filename()); +#endif + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(!p.is_absolute()); + + p = q = path("\\\\net\\\\\\foo"); + PATH_TEST_EQ(p.relative_path().string(), "foo"); + PATH_TEST_EQ(p.parent_path().string(), "\\\\net\\"); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(q.remove_filename().string(), p.parent_path().string()); +#else + PATH_TEST_EQ(q.remove_filename().string(), "\\\\net\\\\\\"); +#endif + PATH_TEST_EQ(p.filename(), "foo"); + PATH_TEST_EQ(p.root_name(), "\\\\net"); + PATH_TEST_EQ(p.root_directory(), "\\"); + PATH_TEST_EQ(p.root_path().string(), "\\\\net\\"); + BOOST_TEST(p.has_root_path()); + BOOST_TEST(p.has_root_name()); + BOOST_TEST(p.has_root_directory()); + BOOST_TEST(p.has_relative_path()); + BOOST_TEST(p.has_filename()); + BOOST_TEST(p.has_parent_path()); + BOOST_TEST(p.is_absolute()); + } // Windows + + else + { // POSIX + p = path("c:"); + PATH_TEST_EQ(p.parent_path().string(), ""); + PATH_TEST_EQ(p.filename(), "c:"); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(p.has_filename()); + + p = path("cc:"); + PATH_TEST_EQ(p.parent_path().string(), ""); + PATH_TEST_EQ(p.filename(), "cc:"); + BOOST_TEST(!p.has_parent_path()); + BOOST_TEST(p.has_filename()); + + PATH_TEST_EQ(path("/foo/bar/"), "/foo/bar/"); + PATH_TEST_EQ(path("//foo//bar//"), "//foo//bar//"); + PATH_TEST_EQ(path("///foo///bar///"), "///foo///bar///"); + + p = path("/usr/local/bin:/usr/bin:/bin"); + BOOST_TEST(p.string() == "/usr/local/bin:/usr/bin:/bin"); + } // POSIX +} + +// composition_tests ----------------------------------------------------------------// + +void composition_tests() +{ + std::cout << "composition_tests..." << std::endl; +} + +// construction_tests ---------------------------------------------------------------// + +void construction_tests() +{ + std::cout << "construction_tests..." << std::endl; + + PATH_TEST_EQ("", ""); + + PATH_TEST_EQ("foo", "foo"); + PATH_TEST_EQ("f", "f"); + + PATH_TEST_EQ("foo/", "foo/"); + PATH_TEST_EQ("f/", "f/"); + PATH_TEST_EQ("foo/..", "foo/.."); + PATH_TEST_EQ("foo/../", "foo/../"); + PATH_TEST_EQ("foo/bar/../..", "foo/bar/../.."); + PATH_TEST_EQ("foo/bar/../../", "foo/bar/../../"); + PATH_TEST_EQ("/", "/"); + PATH_TEST_EQ("/f", "/f"); + + PATH_TEST_EQ("/foo", "/foo"); + PATH_TEST_EQ("/foo/bar/", "/foo/bar/"); + PATH_TEST_EQ("//foo//bar//", "//foo//bar//"); + PATH_TEST_EQ("///foo///bar///", "///foo///bar///"); + PATH_TEST_EQ("\\/foo\\/bar\\/", "\\/foo\\/bar\\/"); + PATH_TEST_EQ("\\//foo\\//bar\\//", "\\//foo\\//bar\\//"); + + if (platform == "Windows") + { + PATH_TEST_EQ(path("c:") / "foo", "c:foo"); + PATH_TEST_EQ(path("c:") / "/foo", "c:/foo"); + + PATH_TEST_EQ("\\foo\\bar\\", "\\foo\\bar\\"); + PATH_TEST_EQ("\\\\foo\\\\bar\\\\", "\\\\foo\\\\bar\\\\"); + PATH_TEST_EQ("\\\\\\foo\\\\\\bar\\\\\\", "\\\\\\foo\\\\\\bar\\\\\\"); + + PATH_TEST_EQ("\\", "\\"); + PATH_TEST_EQ("\\f", "\\f"); + PATH_TEST_EQ("\\foo", "\\foo"); + PATH_TEST_EQ("foo\\bar", "foo\\bar"); + PATH_TEST_EQ("foo bar", "foo bar"); + PATH_TEST_EQ("c:", "c:"); + PATH_TEST_EQ("c:/", "c:/"); + PATH_TEST_EQ("c:.", "c:."); + PATH_TEST_EQ("c:./foo", "c:./foo"); + PATH_TEST_EQ("c:.\\foo", "c:.\\foo"); + PATH_TEST_EQ("c:..", "c:.."); + PATH_TEST_EQ("c:/.", "c:/."); + PATH_TEST_EQ("c:/..", "c:/.."); + PATH_TEST_EQ("c:/../", "c:/../"); + PATH_TEST_EQ("c:\\..\\", "c:\\..\\"); + PATH_TEST_EQ("c:/../..", "c:/../.."); + PATH_TEST_EQ("c:/../foo", "c:/../foo"); + PATH_TEST_EQ("c:\\..\\foo", "c:\\..\\foo"); + PATH_TEST_EQ("c:../foo", "c:../foo"); + PATH_TEST_EQ("c:..\\foo", "c:..\\foo"); + PATH_TEST_EQ("c:/../../foo", "c:/../../foo"); + PATH_TEST_EQ("c:\\..\\..\\foo", "c:\\..\\..\\foo"); + PATH_TEST_EQ("c:foo/..", "c:foo/.."); + PATH_TEST_EQ("c:/foo/..", "c:/foo/.."); + PATH_TEST_EQ("c:/..foo", "c:/..foo"); + PATH_TEST_EQ("c:foo", "c:foo"); + PATH_TEST_EQ("c:/foo", "c:/foo"); + PATH_TEST_EQ("\\\\netname", "\\\\netname"); + PATH_TEST_EQ("\\\\netname\\", "\\\\netname\\"); + PATH_TEST_EQ("\\\\netname\\foo", "\\\\netname\\foo"); + PATH_TEST_EQ("c:/foo", "c:/foo"); + PATH_TEST_EQ("prn:", "prn:"); + } + else + { + } + + PATH_TEST_EQ("foo/bar", "foo/bar"); + PATH_TEST_EQ("a/b", "a/b"); // probe for length effects + PATH_TEST_EQ("..", ".."); + PATH_TEST_EQ("../..", "../.."); + PATH_TEST_EQ("/..", "/.."); + PATH_TEST_EQ("/../..", "/../.."); + PATH_TEST_EQ("../foo", "../foo"); + PATH_TEST_EQ("foo/..", "foo/.."); + PATH_TEST_EQ("foo/..bar", "foo/..bar"); + PATH_TEST_EQ("../f", "../f"); + PATH_TEST_EQ("/../f", "/../f"); + PATH_TEST_EQ("f/..", "f/.."); + PATH_TEST_EQ("foo/../..", "foo/../.."); + PATH_TEST_EQ("foo/../../..", "foo/../../.."); + PATH_TEST_EQ("foo/../bar", "foo/../bar"); + PATH_TEST_EQ("foo/bar/..", "foo/bar/.."); + PATH_TEST_EQ("foo/bar/../..", "foo/bar/../.."); + PATH_TEST_EQ("foo/bar/../blah", "foo/bar/../blah"); + PATH_TEST_EQ("f/../b", "f/../b"); + PATH_TEST_EQ("f/b/..", "f/b/.."); + PATH_TEST_EQ("f/b/../a", "f/b/../a"); + PATH_TEST_EQ("foo/bar/blah/../..", "foo/bar/blah/../.."); + PATH_TEST_EQ("foo/bar/blah/../../bletch", "foo/bar/blah/../../bletch"); + PATH_TEST_EQ("...", "..."); + PATH_TEST_EQ("....", "...."); + PATH_TEST_EQ("foo/...", "foo/..."); + PATH_TEST_EQ("abc.", "abc."); + PATH_TEST_EQ("abc..", "abc.."); + PATH_TEST_EQ("foo/abc.", "foo/abc."); + PATH_TEST_EQ("foo/abc..", "foo/abc.."); + + PATH_TEST_EQ(".abc", ".abc"); + PATH_TEST_EQ("a.c", "a.c"); + PATH_TEST_EQ("..abc", "..abc"); + PATH_TEST_EQ("a..c", "a..c"); + PATH_TEST_EQ("foo/.abc", "foo/.abc"); + PATH_TEST_EQ("foo/a.c", "foo/a.c"); + PATH_TEST_EQ("foo/..abc", "foo/..abc"); + PATH_TEST_EQ("foo/a..c", "foo/a..c"); + + PATH_TEST_EQ(".", "."); + PATH_TEST_EQ("./foo", "./foo"); + PATH_TEST_EQ("./..", "./.."); + PATH_TEST_EQ("./../foo", "./../foo"); + PATH_TEST_EQ("foo/.", "foo/."); + PATH_TEST_EQ("../.", "../."); + PATH_TEST_EQ("./.", "./."); + PATH_TEST_EQ("././.", "././."); + PATH_TEST_EQ("./foo/.", "./foo/."); + PATH_TEST_EQ("foo/./bar", "foo/./bar"); + PATH_TEST_EQ("foo/./.", "foo/./."); + PATH_TEST_EQ("foo/./..", "foo/./.."); + PATH_TEST_EQ("foo/./../bar", "foo/./../bar"); + PATH_TEST_EQ("foo/../.", "foo/../."); + PATH_TEST_EQ("././..", "././.."); + PATH_TEST_EQ("./../.", "./../."); + PATH_TEST_EQ(".././.", ".././."); + + PATH_TEST_EQ(derived_from_path("foo"), "foo"); + PATH_TEST_EQ(convertible_to_path("foo"), "foo"); + PATH_TEST_EQ(fs::path(pcustom_string("foo")), "foo"); + PATH_TEST_EQ(boost::string_view("foo"), "foo"); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + PATH_TEST_EQ(std::string_view("foo"), "foo"); +#endif + + // Check that path constructors don't cause ambiguity for to_string calls + // https://github.com/boostorg/filesystem/issues/273 + custom_string c("test"); + BOOST_TEST_EQ(to_string(c), std::string("test")); +} + +// append_tests --------------------------------------------------------------------// + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#define APPEND_TEST_STD_STRING_VIEW(appnd, expected)\ + path p6(p);\ + p6 /= std::string_view(appnd);\ + PATH_TEST_EQ(p6, expected); +#else +#define APPEND_TEST_STD_STRING_VIEW(appnd, expected) +#endif + +#define APPEND_TEST(pth, appnd, expected)\ + {\ + const path p(pth);\ + const std::string s(appnd);\ + PATH_TEST_EQ(p / appnd, expected);\ + PATH_TEST_EQ((p / path(s)).string(), expected);\ + PATH_TEST_EQ((p / s.c_str()).string(), expected);\ + PATH_TEST_EQ((p / s).string(), expected);\ + path p1(p);\ + p1 /= appnd;\ + PATH_TEST_EQ(p1, expected);\ + path p2(p);\ + p2 /= derived_from_path(appnd);\ + PATH_TEST_EQ(p2, expected);\ + path p3(p);\ + p3 /= convertible_to_path(appnd);\ + PATH_TEST_EQ(p3, expected);\ + path p4(p);\ + p4 /= pcustom_string(appnd);\ + PATH_TEST_EQ(p4, expected);\ + path p5(p);\ + p5 /= boost::string_view(appnd);\ + PATH_TEST_EQ(p5, expected);\ + APPEND_TEST_STD_STRING_VIEW(appnd, expected)\ + path p7(p);\ + p7.append(s.begin(), s.end());\ + PATH_TEST_EQ(p7.string(), expected);\ + } + +void append_tests() +{ + std::cout << "append_tests..." << std::endl; + + // There are many control paths to be exercised, since empty paths and arguments, + // paths with trailing separators, arguments with leading separators, with or without + // other characters being present, are all separate cases that need to be tested. + // Furthermore, some of the code to be tested is specific to argument categories, + // so that results in further permutations to be tested. + + //// code to generate test cases + //// + //// expected results must be checked by hand + //// "foo\bar" expected result must be edited by hand and moved for Windows/POSIX + //// + //const char* x[] = { "", "/", "foo", "foo/" }; + //const char* y[] = { "", "/", "bar", "/bar" }; + + //for (int i = 0; i < sizeof(x)/sizeof(char*); ++i) + // for (int j = 0; j < sizeof(y)/sizeof(char*); ++j) + // { + // std::cout << " APPEND_TEST(\"" << x[i] << "\", \"" << y[j] << "\", \"" + // << path(x[i]) / y[j] << "\");\n"; + // } + + APPEND_TEST("", "", ""); + APPEND_TEST("", "/", "/"); + APPEND_TEST("", "bar", "bar"); + APPEND_TEST("", "/bar", "/bar"); + + APPEND_TEST("/", "", "/"); +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("/", "/", "//"); +#else + APPEND_TEST("/", "/", "/"); +#endif + APPEND_TEST("/", "bar", "/bar"); +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("/", "/bar", "//bar"); +#else + APPEND_TEST("/", "/bar", "/bar"); +#endif + +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("foo", "/", "foo/"); +#else + APPEND_TEST("foo", "/", "/"); +#endif +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("foo", "/bar", "foo/bar"); +#else + APPEND_TEST("foo", "/bar", "/bar"); +#endif + + APPEND_TEST("foo/", "", "foo/"); +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("foo/", "/", "foo//"); +#else + APPEND_TEST("foo/", "/", "/"); +#endif + APPEND_TEST("foo/", "bar", "foo/bar"); + + if (platform == "Windows") + { +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("foo", "", "foo"); +#else + APPEND_TEST("foo", "", "foo\\"); +#endif + APPEND_TEST("foo", "bar", "foo\\bar"); + +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("foo\\", "\\bar", "foo\\\\bar"); +#else + APPEND_TEST("foo\\", "\\bar", "\\bar"); +#endif + + // hand created test case specific to Windows + APPEND_TEST("c:", "bar", "c:bar"); + } + else + { +#if BOOST_FILESYSTEM_VERSION == 3 + APPEND_TEST("foo", "", "foo"); +#else + APPEND_TEST("foo", "", "foo/"); +#endif + APPEND_TEST("foo", "bar", "foo/bar"); + } + + // ticket #6819 + union + { + char a[1]; + char b[3]; + } u; + + u.b[0] = 'a'; + u.b[1] = 'b'; + u.b[2] = '\0'; + + path p6819; + p6819 /= u.a; + BOOST_TEST_EQ(p6819, path("ab")); +} + +// concat_tests --------------------------------------------------------------------// + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#define CONCAT_TEST_STD_STRING_VIEW(appnd, expected)\ + path p9(p);\ + p9 += std::string_view(appnd);\ + PATH_TEST_EQ(p9, expected); +#else +#define CONCAT_TEST_STD_STRING_VIEW(appnd, expected) +#endif + +#define CONCAT_TEST(pth, appnd, expected)\ + {\ + const path p(pth);\ + const std::string s(appnd);\ + path p1(p);\ + p1 += appnd;\ + PATH_TEST_EQ(p1.string(), expected);\ + path p2(p);\ + p2 += path(appnd);\ + PATH_TEST_EQ(p2.string(), expected);\ + path p3(p);\ + p3 += s;\ + PATH_TEST_EQ(p3.string(), expected);\ + path p4(p);\ + p4 += s.c_str();\ + PATH_TEST_EQ(p4.string(), expected);\ + path p5(p);\ + p5 += derived_from_path(appnd);\ + PATH_TEST_EQ(p5, expected);\ + path p6(p);\ + p6 += convertible_to_path(appnd);\ + PATH_TEST_EQ(p6, expected);\ + path p7(p);\ + p7 += pcustom_string(appnd);\ + PATH_TEST_EQ(p7, expected);\ + path p8(p);\ + p8 += boost::string_view(appnd);\ + PATH_TEST_EQ(p8, expected);\ + CONCAT_TEST_STD_STRING_VIEW(appnd, expected)\ + path p10(p);\ + p10.concat(s.begin(), s.end());\ + PATH_TEST_EQ(p10.string(), expected);\ + } + +void concat_tests() +{ + std::cout << "concat_tests..." << std::endl; + + CONCAT_TEST("", "", ""); + CONCAT_TEST("", "/", "/"); + CONCAT_TEST("", "bar", "bar"); + CONCAT_TEST("", "/bar", "/bar"); + + CONCAT_TEST("/", "", "/"); + CONCAT_TEST("/", "/", "//"); + CONCAT_TEST("/", "bar", "/bar"); + CONCAT_TEST("/", "/bar", "//bar"); + + CONCAT_TEST("foo", "/", "foo/"); + CONCAT_TEST("foo", "/bar", "foo/bar"); + + CONCAT_TEST("foo/", "", "foo/"); + CONCAT_TEST("foo/", "/", "foo//"); + CONCAT_TEST("foo/", "bar", "foo/bar"); + + CONCAT_TEST("foo", "", "foo"); + CONCAT_TEST("foo", "bar", "foobar"); + CONCAT_TEST("foo\\", "\\bar", "foo\\\\bar"); + CONCAT_TEST("c:", "bar", "c:bar"); +} + +// self_assign_append_concat_tests -------------------------------------------------// + +#if defined(__clang__) && defined(__has_warning) +#if __has_warning("-Wself-assign-overloaded") +#pragma clang diagnostic push +// explicitly assigning value of variable of type 'boost::filesystem::path' to itself +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#endif +#endif + +void self_assign_append_concat_tests() +{ + std::cout << "self_assign_append_concat_tests..." << std::endl; + + path p; + + p = "snafubar"; + PATH_TEST_EQ(p = p, "snafubar"); + + p = "snafubar"; + p = p.c_str(); + PATH_TEST_EQ(p, "snafubar"); + + p = "snafubar"; + p.assign(p.c_str(), path::codecvt()); + PATH_TEST_EQ(p, "snafubar"); + + p = "snafubar"; + PATH_TEST_EQ(p = p.c_str() + 5, "bar"); + + p = "snafubar"; + PATH_TEST_EQ(p.assign(p.c_str() + 5, p.c_str() + 7), "ba"); + + p = "snafubar"; + p /= p; + PATH_TEST_EQ(p, "snafubar" BOOST_DIR_SEP "snafubar"); + + p = "snafubar"; + p /= p.c_str(); + PATH_TEST_EQ(p, "snafubar" BOOST_DIR_SEP "snafubar"); + + p = "snafubar"; + p.append(p.c_str(), path::codecvt()); + PATH_TEST_EQ(p, "snafubar" BOOST_DIR_SEP "snafubar"); + + p = "snafubar"; + PATH_TEST_EQ(p.append(p.c_str() + 5, p.c_str() + 7), "snafubar" BOOST_DIR_SEP "ba"); + + p = "snafubar"; + p += p; + PATH_TEST_EQ(p, "snafubarsnafubar"); + + p = "snafubar"; + p += p.c_str(); + PATH_TEST_EQ(p, "snafubarsnafubar"); + + p = "snafubar"; + p.concat(p.c_str(), path::codecvt()); + PATH_TEST_EQ(p, "snafubarsnafubar"); + + p = "snafubar"; + PATH_TEST_EQ(p.concat(p.c_str() + 5, p.c_str() + 7), "snafubarba"); +} + +#if defined(__clang__) && defined(__has_warning) +#if __has_warning("-Wself-assign-overloaded") +#pragma clang diagnostic pop +#endif +#endif + +// name_function_tests -------------------------------------------------------------// + +void name_function_tests() +{ + std::cout << "name_function_tests..." << std::endl; + + BOOST_TEST(fs::portable_posix_name(std::string("x"))); + BOOST_TEST(fs::windows_name(std::string("x"))); + BOOST_TEST(fs::portable_name(std::string("x"))); + BOOST_TEST(fs::portable_directory_name(std::string("x"))); + BOOST_TEST(fs::portable_file_name(std::string("x"))); + + BOOST_TEST(fs::portable_posix_name(std::string("."))); + BOOST_TEST(fs::windows_name(std::string("."))); + BOOST_TEST(fs::portable_name(std::string("."))); + BOOST_TEST(fs::portable_directory_name(std::string("."))); + BOOST_TEST(!fs::portable_file_name(std::string("."))); + + BOOST_TEST(fs::portable_posix_name(std::string(".."))); + BOOST_TEST(fs::windows_name(std::string(".."))); + BOOST_TEST(fs::portable_name(std::string(".."))); + BOOST_TEST(fs::portable_directory_name(std::string(".."))); + BOOST_TEST(!fs::portable_file_name(std::string(".."))); + + BOOST_TEST(!fs::native(std::string(""))); + BOOST_TEST(!fs::portable_posix_name(std::string(""))); + BOOST_TEST(!fs::windows_name(std::string(""))); + BOOST_TEST(!fs::portable_name(std::string(""))); + BOOST_TEST(!fs::portable_directory_name(std::string(""))); + BOOST_TEST(!fs::portable_file_name(std::string(""))); + + BOOST_TEST(!fs::native(std::string(" "))); + BOOST_TEST(!fs::portable_posix_name(std::string(" "))); + BOOST_TEST(!fs::windows_name(std::string(" "))); + BOOST_TEST(!fs::portable_name(std::string(" "))); + BOOST_TEST(!fs::portable_directory_name(std::string(" "))); + BOOST_TEST(!fs::portable_file_name(std::string(" "))); + + BOOST_TEST(!fs::portable_posix_name(std::string(":"))); + BOOST_TEST(!fs::windows_name(std::string(":"))); + BOOST_TEST(!fs::portable_name(std::string(":"))); + BOOST_TEST(!fs::portable_directory_name(std::string(":"))); + BOOST_TEST(!fs::portable_file_name(std::string(":"))); + + BOOST_TEST(fs::portable_posix_name(std::string("-"))); + BOOST_TEST(fs::windows_name(std::string("-"))); + BOOST_TEST(!fs::portable_name(std::string("-"))); + BOOST_TEST(!fs::portable_directory_name(std::string("-"))); + BOOST_TEST(!fs::portable_file_name(std::string("-"))); + + BOOST_TEST(!fs::portable_posix_name(std::string("foo bar"))); + BOOST_TEST(fs::windows_name(std::string("foo bar"))); + BOOST_TEST(!fs::windows_name(std::string(" bar"))); + BOOST_TEST(!fs::windows_name(std::string("foo "))); + BOOST_TEST(!fs::portable_name(std::string("foo bar"))); + BOOST_TEST(!fs::portable_directory_name(std::string("foo bar"))); + BOOST_TEST(!fs::portable_file_name(std::string("foo bar"))); + + BOOST_TEST(fs::portable_posix_name(std::string("foo.bar"))); + BOOST_TEST(fs::windows_name(std::string("foo.bar"))); + BOOST_TEST(fs::portable_name(std::string("foo.bar"))); + BOOST_TEST(!fs::portable_directory_name(std::string("foo.bar"))); + BOOST_TEST(fs::portable_file_name(std::string("foo.bar"))); + + BOOST_TEST(fs::portable_posix_name(std::string("foo.barf"))); + BOOST_TEST(fs::windows_name(std::string("foo.barf"))); + BOOST_TEST(fs::portable_name(std::string("foo.barf"))); + BOOST_TEST(!fs::portable_directory_name(std::string("foo.barf"))); + BOOST_TEST(!fs::portable_file_name(std::string("foo.barf"))); + + BOOST_TEST(fs::portable_posix_name(std::string(".foo"))); + BOOST_TEST(fs::windows_name(std::string(".foo"))); + BOOST_TEST(!fs::portable_name(std::string(".foo"))); + BOOST_TEST(!fs::portable_directory_name(std::string(".foo"))); + BOOST_TEST(!fs::portable_file_name(std::string(".foo"))); + + BOOST_TEST(fs::portable_posix_name(std::string("foo."))); + BOOST_TEST(!fs::windows_name(std::string("foo."))); + BOOST_TEST(!fs::portable_name(std::string("foo."))); + BOOST_TEST(!fs::portable_directory_name(std::string("foo."))); + BOOST_TEST(!fs::portable_file_name(std::string("foo."))); +} + +// replace_extension_tests ---------------------------------------------------------// + +void replace_extension_tests() +{ + std::cout << "replace_extension_tests..." << std::endl; + + BOOST_TEST(path().replace_extension().empty()); + BOOST_TEST(path().replace_extension("a") == ".a"); + BOOST_TEST(path().replace_extension("a.") == ".a."); + BOOST_TEST(path().replace_extension(".a") == ".a"); + BOOST_TEST(path().replace_extension("a.txt") == ".a.txt"); + // see the rationale in html docs for explanation why this works: + BOOST_TEST(path().replace_extension(".txt") == ".txt"); + + BOOST_TEST(path("a.txt").replace_extension() == "a"); + BOOST_TEST(path("a.txt").replace_extension("") == "a"); + BOOST_TEST(path("a.txt").replace_extension(".") == "a."); + BOOST_TEST(path("a.txt").replace_extension(".tex") == "a.tex"); + BOOST_TEST(path("a.txt").replace_extension("tex") == "a.tex"); + BOOST_TEST(path("a.").replace_extension(".tex") == "a.tex"); + BOOST_TEST(path("a.").replace_extension("tex") == "a.tex"); + BOOST_TEST(path("a").replace_extension(".txt") == "a.txt"); + BOOST_TEST(path("a").replace_extension("txt") == "a.txt"); + BOOST_TEST(path("a.b.txt").replace_extension(".tex") == "a.b.tex"); + BOOST_TEST(path("a.b.txt").replace_extension("tex") == "a.b.tex"); + BOOST_TEST(path("a/b").replace_extension(".c") == "a/b.c"); + PATH_TEST_EQ(path("a.txt/b").replace_extension(".c"), "a.txt/b.c"); // ticket 4702 + BOOST_TEST(path("foo.txt").replace_extension("exe") == "foo.exe"); // ticket 5118 + BOOST_TEST(path("foo.txt").replace_extension(".tar.bz2") == "foo.tar.bz2"); // ticket 5118 +} + +// make_preferred_tests ------------------------------------------------------------// + +void make_preferred_tests() +{ + std::cout << "make_preferred_tests..." << std::endl; + + if (platform == "Windows") + { + BOOST_TEST(path("//abc\\def/ghi").make_preferred().native() == path("\\\\abc\\def\\ghi").native()); + } + else + { + BOOST_TEST(path("//abc\\def/ghi").make_preferred().native() == path("//abc\\def/ghi").native()); + } +} + +// lexically_normal_tests ----------------------------------------------------------// + +void lexically_normal_tests() +{ + std::cout << "lexically_normal_tests..." << std::endl; + + // Note: lexically_normal() uses /= to build up some results, so these results will + // have the platform's preferred separator. Since that is immaterial to the correct + // functioning of lexically_normal(), the test results are converted to generic form, + // and the expected results are also given in generic form. Otherwise many of the + // tests would incorrectly be reported as failing on Windows. + + PATH_TEST_EQ(path("").lexically_normal().generic_path(), ""); + PATH_TEST_EQ(path("/").lexically_normal().generic_path(), "/"); + PATH_TEST_EQ(path("//").lexically_normal().generic_path(), "//"); + PATH_TEST_EQ(path("///").lexically_normal().generic_path(), "/"); + PATH_TEST_EQ(path("f").lexically_normal().generic_path(), "f"); + PATH_TEST_EQ(path("foo").lexically_normal().generic_path(), "foo"); + PATH_TEST_EQ(path("foo/").lexically_normal().generic_path(), "foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("f/").lexically_normal().generic_path(), "f/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("/foo").lexically_normal().generic_path(), "/foo"); + PATH_TEST_EQ(path("/./foo").lexically_normal().generic_path(), "/foo"); + PATH_TEST_EQ(path("/./foo/.").lexically_normal().generic_path(), "/foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("foo/bar").lexically_normal().generic_path(), "foo/bar"); + PATH_TEST_EQ(path("..").lexically_normal().generic_path(), ".."); + PATH_TEST_EQ(path("../..").lexically_normal().generic_path(), "../.."); + PATH_TEST_EQ(path("/..").lexically_normal().generic_path(), "/.."); + PATH_TEST_EQ(path("/../..").lexically_normal().generic_path(), "/../.."); + PATH_TEST_EQ(path("../foo").lexically_normal().generic_path(), "../foo"); + PATH_TEST_EQ(path("foo/..").lexically_normal().generic_path(), "."); + PATH_TEST_EQ(path("foo/../").lexically_normal().generic_path(), "."); + PATH_TEST_EQ((path("foo") / "..").lexically_normal().generic_path(), "."); + PATH_TEST_EQ(path("foo/...").lexically_normal().generic_path(), "foo/..."); + PATH_TEST_EQ(path("foo/.../").lexically_normal().generic_path(), "foo/.../" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("foo/..bar").lexically_normal().generic_path(), "foo/..bar"); + PATH_TEST_EQ(path("../f").lexically_normal().generic_path(), "../f"); + PATH_TEST_EQ(path("/../f").lexically_normal().generic_path(), "/../f"); + PATH_TEST_EQ(path("f/..").lexically_normal().generic_path(), "."); + PATH_TEST_EQ((path("f") / "..").lexically_normal().generic_path(), "."); + PATH_TEST_EQ(path("foo/../..").lexically_normal().generic_path(), ".."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("foo/../../").lexically_normal().generic_path(), "../."); +#else + PATH_TEST_EQ(path("foo/../../").lexically_normal().generic_path(), ".."); +#endif + PATH_TEST_EQ(path("foo/../../..").lexically_normal().generic_path(), "../.."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("foo/../../../").lexically_normal().generic_path(), "../../."); +#else + PATH_TEST_EQ(path("foo/../../../").lexically_normal().generic_path(), "../.."); +#endif + PATH_TEST_EQ(path("foo/../bar").lexically_normal().generic_path(), "bar"); + PATH_TEST_EQ(path("foo/../bar/").lexically_normal().generic_path(), "bar/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("foo/bar/..").lexically_normal().generic_path(), "foo"); + PATH_TEST_EQ(path("foo/./bar/..").lexically_normal().generic_path(), "foo"); + std::cout << path("foo/./bar/..").lexically_normal() << std::endl; // outputs "foo" + PATH_TEST_EQ(path("foo/bar/../").lexically_normal().generic_path(), "foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("foo/./bar/../").lexically_normal().generic_path(), "foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + std::cout << path("foo/./bar/../").lexically_normal() << std::endl; // POSIX: "foo/", Windows: "foo\" (with a trailing dot for v3) + PATH_TEST_EQ(path("foo/bar/../..").lexically_normal().generic_path(), "."); + PATH_TEST_EQ(path("foo/bar/../../").lexically_normal().generic_path(), "."); + PATH_TEST_EQ(path("foo/bar/../blah").lexically_normal().generic_path(), "foo/blah"); + PATH_TEST_EQ(path("f/../b").lexically_normal().generic_path(), "b"); + PATH_TEST_EQ(path("f/b/..").lexically_normal().generic_path(), "f"); + PATH_TEST_EQ(path("f/b/../").lexically_normal().generic_path(), "f/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("f/b/../a").lexically_normal().generic_path(), "f/a"); + PATH_TEST_EQ(path("foo/bar/blah/../..").lexically_normal().generic_path(), "foo"); + PATH_TEST_EQ(path("foo/bar/blah/../../bletch").lexically_normal().generic_path(), "foo/bletch"); + PATH_TEST_EQ(path("//net").lexically_normal().generic_path(), "//net"); + PATH_TEST_EQ(path("//net/").lexically_normal().generic_path(), "//net/"); + PATH_TEST_EQ(path("//..net").lexically_normal().generic_path(), "//..net"); + PATH_TEST_EQ(path("//net/..").lexically_normal().generic_path(), "//net/.."); + PATH_TEST_EQ(path("//net/foo").lexically_normal().generic_path(), "//net/foo"); + PATH_TEST_EQ(path("//net/foo/").lexically_normal().generic_path(), "//net/foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("//net/foo/..").lexically_normal().generic_path(), "//net/"); + PATH_TEST_EQ(path("//net/foo/../").lexically_normal().generic_path(), "//net/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + + PATH_TEST_EQ(path("/net/foo/bar").lexically_normal().generic_path(), "/net/foo/bar"); + PATH_TEST_EQ(path("/net/foo/bar/").lexically_normal().generic_path(), "/net/foo/bar/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("/net/foo/..").lexically_normal().generic_path(), "/net"); + PATH_TEST_EQ(path("/net/foo/../").lexically_normal().generic_path(), "/net/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + + PATH_TEST_EQ(path("//net//foo//bar").lexically_normal().generic_path(), "//net/foo/bar"); + PATH_TEST_EQ(path("//net//foo//bar//").lexically_normal().generic_path(), "//net/foo/bar/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("//net//foo//..").lexically_normal().generic_path(), "//net/"); + PATH_TEST_EQ(path("//net//foo//..//").lexically_normal().generic_path(), "//net/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + + PATH_TEST_EQ(path("///net///foo///bar").lexically_normal().generic_path(), "/net/foo/bar"); + PATH_TEST_EQ(path("///net///foo///bar///").lexically_normal().generic_path(), "/net/foo/bar/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("///net///foo///..").lexically_normal().generic_path(), "/net"); + PATH_TEST_EQ(path("///net///foo///..///").lexically_normal().generic_path(), "/net/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + + if (platform == "Windows") + { + BOOST_TEST_EQ(path("c:/foo/bar").lexically_normal().string(), "c:\\foo\\bar"); + + PATH_TEST_EQ(path("c:foo").lexically_normal().generic_path(), "c:foo"); + PATH_TEST_EQ(path("c:..").lexically_normal().generic_path(), "c:.."); + PATH_TEST_EQ(path("c:foo/..").lexically_normal().generic_path(), "c:"); + + PATH_TEST_EQ(path("c:foo/../").lexically_normal().generic_path(), "c:" BOOST_FILESYSTEM_V3_TRAILING_DOT); + + PATH_TEST_EQ(path("c:/foo/..").lexically_normal().generic_path(), "c:/"); + PATH_TEST_EQ(path("c:/foo/../").lexically_normal().generic_path(), "c:/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("c:/..").lexically_normal().generic_path(), "c:/.."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("c:/../").lexically_normal().generic_path(), "c:/../."); +#else + PATH_TEST_EQ(path("c:/../").lexically_normal().generic_path(), "c:/.."); +#endif + PATH_TEST_EQ(path("c:/../..").lexically_normal().generic_path(), "c:/../.."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("c:/../../").lexically_normal().generic_path(), "c:/../../."); +#else + PATH_TEST_EQ(path("c:/../../").lexically_normal().generic_path(), "c:/../.."); +#endif + PATH_TEST_EQ(path("c:/../foo").lexically_normal().generic_path(), "c:/../foo"); + PATH_TEST_EQ(path("c:/../foo/").lexically_normal().generic_path(), "c:/../foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("c:/../../foo").lexically_normal().generic_path(), "c:/../../foo"); + PATH_TEST_EQ(path("c:/../../foo/").lexically_normal().generic_path(), "c:/../../foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("c:/..foo").lexically_normal().generic_path(), "c:/..foo"); + } + else // POSIX + { + PATH_TEST_EQ(path("c:..").lexically_normal(), "c:.."); + PATH_TEST_EQ(path("c:foo/..").lexically_normal(), "."); + PATH_TEST_EQ(path("c:foo/../").lexically_normal(), "."); + PATH_TEST_EQ(path("c:/foo/..").lexically_normal(), "c:"); + PATH_TEST_EQ(path("c:/foo/../").lexically_normal(), "c:/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("c:/..").lexically_normal(), "."); + PATH_TEST_EQ(path("c:/../").lexically_normal(), "."); + PATH_TEST_EQ(path("c:/../..").lexically_normal(), ".."); +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_TEST_EQ(path("c:/../../").lexically_normal(), "../."); +#else + PATH_TEST_EQ(path("c:/../../").lexically_normal(), ".."); +#endif + PATH_TEST_EQ(path("c:/../foo").lexically_normal(), "foo"); + PATH_TEST_EQ(path("c:/../foo/").lexically_normal(), "foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("c:/../../foo").lexically_normal(), "../foo"); + PATH_TEST_EQ(path("c:/../../foo/").lexically_normal(), "../foo/" BOOST_FILESYSTEM_V3_TRAILING_DOT); + PATH_TEST_EQ(path("c:/..foo").lexically_normal(), "c:/..foo"); + } +} + +// compare_tests -------------------------------------------------------------------// + +#define COMPARE_TEST(pth1, pth2)\ + {\ + BOOST_TEST_EQ(fs::path(pth1).compare(pth1), 0);\ + BOOST_TEST_LT(fs::path(pth1).compare(pth2), 0);\ + BOOST_TEST_GT(fs::path(pth2).compare(pth1), 0);\ + BOOST_TEST(fs::path(pth1) == pth1);\ + BOOST_TEST(pth1 == fs::path(pth1));\ + BOOST_TEST(fs::path(pth1) != pth2);\ + BOOST_TEST(pth1 != fs::path(pth2));\ + BOOST_TEST(fs::path(pth1) < pth2);\ + BOOST_TEST(pth1 < fs::path(pth2));\ + BOOST_TEST(fs::path(pth2) > pth1);\ + BOOST_TEST(pth2 > fs::path(pth1));\ + BOOST_TEST(fs::path(pth1) <= pth1);\ + BOOST_TEST(pth1 <= fs::path(pth2));\ + BOOST_TEST(fs::path(pth1) >= pth1);\ + BOOST_TEST(pth2 >= fs::path(pth1));\ + } + +void compare_tests() +{ + COMPARE_TEST(fs::path("foo"), fs::path("zoo")) + COMPARE_TEST("foo", "zoo") + COMPARE_TEST(std::string("foo"), std::string("zoo")) + COMPARE_TEST(derived_from_path("foo"), derived_from_path("zoo")) + COMPARE_TEST(pcustom_string("foo"), pcustom_string("zoo")) + COMPARE_TEST(boost::string_view("foo"), boost::string_view("zoo")) +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + COMPARE_TEST(std::string_view("foo"), std::string_view("zoo")) +#endif + + COMPARE_TEST("/foo", "foo") + COMPARE_TEST("/a/b", "foo") + COMPARE_TEST("/foo", "/zoo") + COMPARE_TEST("/foo", "/foo/bar") + + if (platform == "Windows") + { + COMPARE_TEST("c:\\foo", "d:\\foo") + COMPARE_TEST("c:\\foo", "c:\\zoo") + } +} + +inline void odr_use(const path::value_type& c) +{ + static const path::value_type dummy = '\0'; + BOOST_TEST(&c != &dummy); +} + +} // unnamed namespace + +static boost::filesystem::path ticket_6737 = "FilePath"; // #6737 reported this crashed + // on VC++ debug mode build +const boost::filesystem::path ticket_6690("test"); // #6690 another V++ static init crash + +//--------------------------------------------------------------------------------------// +// // +// main // +// // +//--------------------------------------------------------------------------------------// + +#if defined(__clang__) && defined(__has_warning) +#if __has_warning("-Wself-assign-overloaded") +#pragma clang diagnostic push +// explicitly assigning value of variable of type 'boost::filesystem::path' to itself +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#endif +#endif + +int cpp_main(int, char*[]) +{ + // The choice of platform is make at runtime rather than compile-time + // so that compile errors for all platforms will be detected even though + // only the current platform is runtime tested. + platform = (platform == "Win32" || platform == "Win64" || platform == "Cygwin") ? "Windows" : "POSIX"; + std::cout << "Platform is " << platform << '\n'; + + BOOST_TEST(p1.string() != p3.string()); + p3 = p2; + BOOST_TEST(p1.string() == p3.string()); + + path p04("foobar"); + BOOST_TEST(p04.string() == "foobar"); + p04 = p04; // self-assignment + BOOST_TEST(p04.string() == "foobar"); + + construction_tests(); + append_tests(); + concat_tests(); + self_assign_append_concat_tests(); + overload_tests(); + query_and_decomposition_tests(); + composition_tests(); + iterator_tests(); + non_member_tests(); + exception_tests(); + name_function_tests(); + replace_extension_tests(); + make_preferred_tests(); + lexically_normal_tests(); + compare_tests(); + + // verify deprecated names still available + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED + + p1.branch_path(); + p1.leaf(); + path p_remove_leaf; + p_remove_leaf.remove_leaf(); + +#endif + + std::string s1("//:somestring"); // this used to be treated specially + + // check the path member templates + p5.assign(s1.begin(), s1.end()); + + PATH_TEST_EQ(p5.string(), "//:somestring"); + p5 = s1; + PATH_TEST_EQ(p5.string(), "//:somestring"); + + // this code, courtesy of David Whetstone, detects a now fixed bug that + // derefereced the end iterator (assuming debug build with checked itors) + std::vector< char > v1; + p5.assign(v1.begin(), v1.end()); + std::string s2(v1.begin(), v1.end()); + PATH_TEST_EQ(p5.string(), s2); + p5.assign(s1.begin(), s1.begin() + 1); + PATH_TEST_EQ(p5.string(), "/"); + + BOOST_TEST(p1 != p4); + BOOST_TEST(p1.string() == p2.string()); + BOOST_TEST(p1.string() == p3.string()); + BOOST_TEST(path("foo").filename() == "foo"); + BOOST_TEST(path("foo").parent_path().string() == ""); + BOOST_TEST(p1.filename() == "fum"); + BOOST_TEST(p1.parent_path().string() == "fe/fi/fo"); + BOOST_TEST(path("").empty() == true); + BOOST_TEST(path("foo").empty() == false); + + // inserter and extractor tests +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 // bypass VC++ 7.0 and earlier + std::cout << "\nInserter and extractor test..."; + std::stringstream ss; + ss << fs::path("foo/bar") << std::endl; + fs::path round_trip; + ss >> round_trip; + BOOST_TEST(round_trip.string() == "foo/bar"); + std::cout << round_trip.string() << "..." << round_trip << " complete\n"; +#endif + + // Check that path constants have definitions + // https://svn.boost.org/trac10/ticket/12759 + odr_use(path::separator); + odr_use(path::preferred_separator); + odr_use(path::dot); + + return ::boost::report_errors(); +} + +#if defined(__clang__) && defined(__has_warning) +#if __has_warning("-Wself-assign-overloaded") +#pragma clang diagnostic pop +#endif +#endif diff --git a/3rdparty/boost_filesystem/test/path_times.cpp b/3rdparty/boost_filesystem/test/path_times.cpp new file mode 100644 index 0000000..8d9a032 --- /dev/null +++ b/3rdparty/boost_filesystem/test/path_times.cpp @@ -0,0 +1,97 @@ +// Boost Filesystem path_times.cpp ---------------------------------------------------// + +// Copyright Beman Dawes 2013 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include + +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include +#include +#include + +#include + +namespace fs = boost::filesystem; +using namespace boost::timer; + +#include +#include + +using std::cout; +using std::endl; + +namespace { +boost::int64_t max_cycles; + +template< class STD_STRING > +nanosecond_type time_ctor(const STD_STRING& s) +{ + boost::timer::auto_cpu_timer tmr; + boost::int64_t count = 0; + do + { + fs::path p(s); + ++count; + } while (count < max_cycles); + + boost::timer::cpu_times elapsed = tmr.elapsed(); + return elapsed.user + elapsed.system; +} + +nanosecond_type time_loop() +{ + boost::timer::auto_cpu_timer tmr; + boost::int64_t count = 0; + do + { + ++count; + } while (count < max_cycles); + + boost::timer::cpu_times elapsed = tmr.elapsed(); + return elapsed.user + elapsed.system; +} +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// main // +//--------------------------------------------------------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ + if (argc != 2) + { + cout << "Usage: path_times \n"; + return 1; + } + + max_cycles = std::atoi(argv[1]) * 1000000LL; + cout << "testing " << std::atoi(argv[1]) << " million cycles" << endl; + + cout << "time_loop" << endl; + nanosecond_type x = time_loop(); + + cout << "time_ctor with string" << endl; + nanosecond_type s = time_ctor(std::string("/foo/bar/baz")); + + cout << "time_ctor with wstring" << endl; + nanosecond_type w = time_ctor(std::wstring(L"/foo/bar/baz")); + + if (s > w) + cout << "narrow/wide CPU-time ratio = " << long double(s) / w << endl; + else + cout << "wide/narrow CPU-time ratio = " << long double(w) / s << endl; + + cout << "returning from main()" << endl; + return 0; +} diff --git a/3rdparty/boost_filesystem/test/path_unit_test.cpp b/3rdparty/boost_filesystem/test/path_unit_test.cpp new file mode 100644 index 0000000..a6fc069 --- /dev/null +++ b/3rdparty/boost_filesystem/test/path_unit_test.cpp @@ -0,0 +1,1239 @@ +// filesystem path_unit_test.cpp --------------------------------------------------- // + +// Copyright Beman Dawes 2008, 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// ---------------------------------------------------------------------------------- // +// +// The purpose of this test is to ensure that each function in the public +// interface can be called with arguments of the appropriate types. It does +// not attempt to verify that the full range of values for each argument +// are processed correctly. +// +// For full functionality tests, including probes with many different argument +// values, see path_test.cpp and other test programs. +// +// ---------------------------------------------------------------------------------- // + +#include + +// See deprecated_test for tests of deprecated features +#ifndef BOOST_FILESYSTEM_NO_DEPRECATED +#define BOOST_FILESYSTEM_NO_DEPRECATED +#endif +#ifndef BOOST_SYSTEM_NO_DEPRECATED +#define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include + +#include // for imbue tests +#include "test_codecvt.hpp" // for codecvt arg tests +#include +#include // used constructor tests +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; +namespace bs = boost::system; +using boost::filesystem::path; +using std::cout; +using std::endl; +using std::string; +using std::wstring; + +#define CHECK(x) check(x, __FILE__, __LINE__) +#define PATH_IS(a, b) check_path(a, b, __FILE__, __LINE__) +#define NATIVE_IS(p, s, ws) check_native(p, s, ws, __FILE__, __LINE__) +#define IS(a, b) check_equal(a, b, __FILE__, __LINE__) + +#if defined(_MSC_VER) +#pragma warning(push) // Save warning settings. +#pragma warning(disable : 4428) // Disable universal-character-name encountered in source warning. +#endif + +namespace { + +std::string platform(BOOST_PLATFORM); + +void check_path(const path& source, const wstring& expected, const char* file, int line) +{ + if (source == expected) + return; + + ++::boost::detail::test_errors(); + + std::cout << file; + std::wcout << L'(' << line << L"): source.wstring(): \"" + << source.wstring() + << L"\" != expected: \"" << expected + << L"\"\n"; +} + +#ifdef BOOST_WINDOWS_API +void check_native(const path& p, const string&, const wstring& expected, const char* file, int line) +#else +void check_native(const path& p, const string& expected, const wstring&, const char* file, int line) +#endif +{ + if (p.native() == expected) + return; + + ++::boost::detail::test_errors(); + + std::cout << file << '(' << line << "): native() is not equal expected\n" + " native---: " + << std::hex; + path::string_type nat(p.native()); + for (path::string_type::const_iterator it = nat.begin(); it != nat.end(); ++it) + std::cout << long(*it) << ' '; + std::cout << "\n expected-: "; + for (path::string_type::const_iterator it = expected.begin(); it != expected.end(); ++it) + std::cout << long(*it) << ' '; + std::cout << std::dec << std::endl; +} + +template< class T1, class T2 > +void check_equal(const T1& value, const T2& expected, const char* file, int line) +{ + if (value == expected) + return; + + ++::boost::detail::test_errors(); + + std::cout << file; + + std::wcout << L'(' << line << L"): value: \"" << value + << L"\" != expected: \"" << expected + << L"\"\n"; +} + +void check(bool ok_, const char* file, int line) +{ + if (ok_) + return; + + ++::boost::detail::test_errors(); + + std::cout << file << '(' << line << "): test failed\n"; +} + +string s("string"); +wstring ws(L"wstring"); +std::list< char > l; // see main() for initialization to s, t, r, i, n, g +std::list< wchar_t > wl; // see main() for initialization to w, s, t, r, i, n, g +std::vector< char > v; // see main() for initialization to f, u, z +std::vector< wchar_t > wv; // see main() for initialization to w, f, u, z + +class Base +{ +}; +class Derived : public Base +{ +}; +void fun(const boost::shared_ptr< Base >&) +{ +} + +// test_constructors ---------------------------------------------------------------// + +void test_constructors() +{ + std::cout << "testing constructors..." << std::endl; + + path x0; // default constructor + PATH_IS(x0, L""); + BOOST_TEST_EQ(x0.native().size(), 0U); + + path x1(l.begin(), l.end()); // iterator range char + PATH_IS(x1, L"string"); + BOOST_TEST_EQ(x1.native().size(), 6U); + + path x2(x1); // copy constructor + PATH_IS(x2, L"string"); + BOOST_TEST_EQ(x2.native().size(), 6U); + + path x3(wl.begin(), wl.end()); // iterator range wchar_t + PATH_IS(x3, L"wstring"); + BOOST_TEST_EQ(x3.native().size(), 7U); + + // contiguous containers + path x4(string("std::string")); // std::string + PATH_IS(x4, L"std::string"); + BOOST_TEST_EQ(x4.native().size(), 11U); + + path x5(wstring(L"std::wstring")); // std::wstring + PATH_IS(x5, L"std::wstring"); + BOOST_TEST_EQ(x5.native().size(), 12U); + + path x6("array char"); // array char + PATH_IS(x6, L"array char"); + BOOST_TEST_EQ(x6.native().size(), 10U); + + path x7(L"array wchar_t"); // array wchar_t + PATH_IS(x7, L"array wchar_t"); + BOOST_TEST_EQ(x7.native().size(), 13U); + + char char_array[100]; + std::strcpy(char_array, "big array char"); + path x6o(char_array); // array char, only partially full + PATH_IS(x6o, L"big array char"); + BOOST_TEST_EQ(x6o.native().size(), 14U); + + wchar_t wchar_array[100]; + std::wcscpy(wchar_array, L"big array wchar_t"); + path x7o(wchar_array); // array char, only partially full + PATH_IS(x7o, L"big array wchar_t"); + BOOST_TEST_EQ(x7o.native().size(), 17U); + + path x8(s.c_str()); // const char* null terminated + PATH_IS(x8, L"string"); + BOOST_TEST_EQ(x8.native().size(), 6U); + + path x9(ws.c_str()); // const wchar_t* null terminated + PATH_IS(x9, L"wstring"); + BOOST_TEST_EQ(x9.native().size(), 7U); + + path x8nc(const_cast< char* >(s.c_str())); // char* null terminated + PATH_IS(x8nc, L"string"); + BOOST_TEST_EQ(x8nc.native().size(), 6U); + + path x9nc(const_cast< wchar_t* >(ws.c_str())); // wchar_t* null terminated + PATH_IS(x9nc, L"wstring"); + BOOST_TEST_EQ(x9nc.native().size(), 7U); + + // easy-to-make coding errors + // path e1(x0, path::codecvt()); // fails to compile, and that is OK + + boost::shared_ptr< Derived > pDerived(new Derived()); + fun(pDerived); // tests constructor member template enable_if working correctly; + // will fail to compile if enable_if not taking path off the table +} + +path x; +path y; + +#if defined(__clang__) && defined(__has_warning) +#if __has_warning("-Wself-assign-overloaded") +#pragma clang diagnostic push +// explicitly assigning value of variable of type 'boost::filesystem::path' to itself +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#endif +#endif + +// test_assignments ----------------------------------------------------------------// + +void test_assignments() +{ + std::cout << "testing assignments..." << std::endl; + + x = path("yet another path"); // another path + PATH_IS(x, L"yet another path"); + BOOST_TEST_EQ(x.native().size(), 16U); + + x = x; // self-assignment + PATH_IS(x, L"yet another path"); + BOOST_TEST_EQ(x.native().size(), 16U); + + x.assign(l.begin(), l.end()); // iterator range char + PATH_IS(x, L"string"); + + x.assign(wl.begin(), wl.end()); // iterator range wchar_t + PATH_IS(x, L"wstring"); + + x = string("std::string"); // container char + PATH_IS(x, L"std::string"); + + x = wstring(L"std::wstring"); // container wchar_t + PATH_IS(x, L"std::wstring"); + + x = "array char"; // array char + PATH_IS(x, L"array char"); + + x = L"array wchar"; // array wchar_t + PATH_IS(x, L"array wchar"); + + x = s.c_str(); // const char* null terminated + PATH_IS(x, L"string"); + + x = ws.c_str(); // const wchar_t* null terminated + PATH_IS(x, L"wstring"); +} + +// test_move_construction_and_assignment -------------------------------------------// + +void test_move_construction_and_assignment() +{ + std::cout << "testing move_construction_and_assignment..." << std::endl; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + path from("long enough to avoid small object optimization"); + path to(std::move(from)); + BOOST_TEST(to == "long enough to avoid small object optimization"); + if (!from.empty()) + cout << "Note: move construction did not result in empty source path" << endl; + + path from2("long enough to avoid small object optimization"); + path to2; + to2 = std::move(from2); + BOOST_TEST(to2 == "long enough to avoid small object optimization"); + if (!from2.empty()) + cout << "Note: move assignment did not result in empty rhs path" << endl; +#else + std::cout << "Test skipped because compiler does not support move semantics" << std::endl; +#endif +} + +// test_appends --------------------------------------------------------------------// + +void test_appends() +{ + std::cout << "testing appends..." << std::endl; + +#ifdef BOOST_WINDOWS_API +#define BOOST_FS_FOO L"/foo\\" +#else // POSIX paths +#define BOOST_FS_FOO L"/foo/" +#endif + + x = "/foo"; + x /= path(""); // empty path +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_IS(x, L"/foo"); +#else + PATH_IS(x, L"/foo/"); +#endif + + x = "/foo"; + x /= path("/"); // slash path +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_IS(x, L"/foo/"); +#else + PATH_IS(x, L"/"); +#endif + + x = "/foo"; + x /= path("/boo"); // slash path +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_IS(x, L"/foo/boo"); +#else + PATH_IS(x, L"/boo"); +#endif + + x = "/foo"; + x /= x; // self-append +#if BOOST_FILESYSTEM_VERSION == 3 + PATH_IS(x, L"/foo/foo"); +#else + PATH_IS(x, L"/foo"); +#endif + + x = "/foo"; + x /= path("yet another path"); // another path + PATH_IS(x, BOOST_FS_FOO L"yet another path"); + + x = "/foo"; + x.append(l.begin(), l.end()); // iterator range char + PATH_IS(x, BOOST_FS_FOO L"string"); + + x = "/foo"; + x.append(wl.begin(), wl.end()); // iterator range wchar_t + PATH_IS(x, BOOST_FS_FOO L"wstring"); + + x = "/foo"; + x /= string("std_string"); // container char + PATH_IS(x, BOOST_FS_FOO L"std_string"); + + x = "/foo"; + x /= wstring(L"std_wstring"); // container wchar_t + PATH_IS(x, BOOST_FS_FOO L"std_wstring"); + + x = "/foo"; + x /= "array char"; // array char + PATH_IS(x, BOOST_FS_FOO L"array char"); + + x = "/foo"; + x /= L"array wchar"; // array wchar_t + PATH_IS(x, BOOST_FS_FOO L"array wchar"); + + x = "/foo"; + x /= s.c_str(); // const char* null terminated + PATH_IS(x, BOOST_FS_FOO L"string"); + + x = "/foo"; + x /= ws.c_str(); // const wchar_t* null terminated + PATH_IS(x, BOOST_FS_FOO L"wstring"); +} + +// test_concats --------------------------------------------------------------------// + +void test_concats() +{ + std::cout << "testing concats..." << std::endl; + + x = "/foo"; + x += path(""); // empty path + PATH_IS(x, L"/foo"); + + x = "/foo"; + x += path("/"); // slash path + PATH_IS(x, L"/foo/"); + + x = "/foo"; + x += path("boo"); // slash path + PATH_IS(x, L"/fooboo"); + + x = "foo"; + x += x; // self-append + PATH_IS(x, L"foofoo"); + + x = "foo-"; + x += path("yet another path"); // another path + PATH_IS(x, L"foo-yet another path"); + + x = "foo-"; + x.concat(l.begin(), l.end()); // iterator range char + PATH_IS(x, L"foo-string"); + + x = "foo-"; + x.concat(wl.begin(), wl.end()); // iterator range wchar_t + PATH_IS(x, L"foo-wstring"); + + x = "foo-"; + x += string("std::string"); // container char + PATH_IS(x, L"foo-std::string"); + + x = "foo-"; + x += wstring(L"std::wstring"); // container wchar_t + PATH_IS(x, L"foo-std::wstring"); + + x = "foo-"; + x += "array char"; // array char + PATH_IS(x, L"foo-array char"); + + x = "foo-"; + x += L"array wchar"; // array wchar_t + PATH_IS(x, L"foo-array wchar"); + + x = "foo-"; + x += s.c_str(); // const char* null terminated + PATH_IS(x, L"foo-string"); + + x = "foo-"; + x += ws.c_str(); // const wchar_t* null terminated + PATH_IS(x, L"foo-wstring"); + + x = "foo-"; + x += 'x'; // char + PATH_IS(x, L"foo-x"); + + x = "foo-"; + x += L'x'; // wchar + PATH_IS(x, L"foo-x"); +} + +#if defined(__clang__) && defined(__has_warning) +#if __has_warning("-Wself-assign-overloaded") +#pragma clang diagnostic pop +#endif +#endif + +// test_observers ------------------------------------------------------------------// + +void test_observers() +{ + std::cout << "testing observers..." << std::endl; + + path p0("abc"); + + CHECK(p0.native().size() == 3); + CHECK(p0.size() == 3); + CHECK(p0.string() == "abc"); + CHECK(p0.string().size() == 3); + CHECK(p0.wstring() == L"abc"); + CHECK(p0.wstring().size() == 3); + + p0 = ""; + CHECK(p0.native().size() == 0); + CHECK(p0.size() == 0); + +#ifdef BOOST_WINDOWS_API + + path p("abc\\def/ghi"); + + CHECK(std::wstring(p.c_str()) == L"abc\\def/ghi"); + + CHECK(p.string() == "abc\\def/ghi"); + CHECK(p.wstring() == L"abc\\def/ghi"); + + CHECK(p.generic_path().string() == "abc/def/ghi"); + CHECK(p.generic_string() == "abc/def/ghi"); + CHECK(p.generic_wstring() == L"abc/def/ghi"); + + CHECK(p.generic_string< string >() == "abc/def/ghi"); + CHECK(p.generic_string< wstring >() == L"abc/def/ghi"); + CHECK(p.generic_string< path::string_type >() == L"abc/def/ghi"); + +#else // BOOST_POSIX_API + + path p("abc\\def/ghi"); + + CHECK(string(p.c_str()) == "abc\\def/ghi"); + + CHECK(p.string() == "abc\\def/ghi"); + CHECK(p.wstring() == L"abc\\def/ghi"); + + CHECK(p.generic_path().string() == "abc\\def/ghi"); + CHECK(p.generic_string() == "abc\\def/ghi"); + CHECK(p.generic_wstring() == L"abc\\def/ghi"); + + CHECK(p.generic_string< string >() == "abc\\def/ghi"); + CHECK(p.generic_string< wstring >() == L"abc\\def/ghi"); + CHECK(p.generic_string< path::string_type >() == "abc\\def/ghi"); + +#endif +} + +// test_relationals ----------------------------------------------------------------// + +void test_relationals() +{ + std::cout << "testing relationals..." << std::endl; + + boost::hash< path > hash; + +#ifdef BOOST_WINDOWS_API + // this is a critical use case to meet user expectations + CHECK(path("c:\\abc") == path("c:/abc")); + CHECK(hash(path("c:\\abc")) == hash(path("c:/abc"))); +#endif + + const path p("bar"); + const path p2("baz"); + + CHECK(!(p < p)); + CHECK(p < p2); + CHECK(!(p2 < p)); + CHECK(p < "baz"); + CHECK(p < string("baz")); + CHECK(p < L"baz"); + CHECK(p < wstring(L"baz")); + CHECK(!("baz" < p)); + CHECK(!(string("baz") < p)); + CHECK(!(L"baz" < p)); + CHECK(!(wstring(L"baz") < p)); + + CHECK(p == p); + CHECK(!(p == p2)); + CHECK(!(p2 == p)); + CHECK(p2 == "baz"); + CHECK(p2 == string("baz")); + CHECK(p2 == L"baz"); + CHECK(p2 == wstring(L"baz")); + CHECK("baz" == p2); + CHECK(string("baz") == p2); + CHECK(L"baz" == p2); + CHECK(wstring(L"baz") == p2); + + CHECK(hash(p) == hash(p)); + CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable + + CHECK(!(p != p)); + CHECK(p != p2); + CHECK(p2 != p); + + CHECK(p <= p); + CHECK(p <= p2); + CHECK(!(p2 <= p)); + + CHECK(!(p > p)); + CHECK(!(p > p2)); + CHECK(p2 > p); + + CHECK(p >= p); + CHECK(!(p >= p2)); + CHECK(p2 >= p); +} + +// test_inserter_and_extractor -----------------------------------------------------// + +void test_inserter_and_extractor() +{ + std::cout << "testing inserter and extractor..." << std::endl; + + path p1("foo bar"); // verify space in path roundtrips per ticket #3863 + path p2; + + std::stringstream ss; + + CHECK(p1 != p2); + ss << p1; + ss >> p2; + CHECK(p1 == p2); + + path wp1(L"foo bar"); + path wp2; + + std::wstringstream wss; + + CHECK(wp1 != wp2); + wss << wp1; + wss >> wp2; + CHECK(wp1 == wp2); +} + +// test_other_non_members ----------------------------------------------------------// + +void test_other_non_members() +{ + std::cout << "testing other_non_members..." << std::endl; + + path p1("foo"); + path p2("bar"); + + // operator / + + CHECK(p1 / p2 == path("foo/bar").make_preferred()); + CHECK("foo" / p2 == path("foo/bar").make_preferred()); + CHECK(L"foo" / p2 == path("foo/bar").make_preferred()); + CHECK(string("foo") / p2 == path("foo/bar").make_preferred()); + CHECK(wstring(L"foo") / p2 == path("foo/bar").make_preferred()); + CHECK(p1 / "bar" == path("foo/bar").make_preferred()); + CHECK(p1 / L"bar" == path("foo/bar").make_preferred()); + CHECK(p1 / string("bar") == path("foo/bar").make_preferred()); + CHECK(p1 / wstring(L"bar") == path("foo/bar").make_preferred()); + + swap(p1, p2); + + CHECK(p1 == "bar"); + CHECK(p2 == "foo"); + + CHECK(!path("").filename_is_dot()); + CHECK(!path("").filename_is_dot_dot()); + CHECK(!path("..").filename_is_dot()); + CHECK(!path(".").filename_is_dot_dot()); + CHECK(!path("...").filename_is_dot_dot()); + CHECK(path(".").filename_is_dot()); + CHECK(path("..").filename_is_dot_dot()); + CHECK(path("/.").filename_is_dot()); + CHECK(path("/..").filename_is_dot_dot()); + CHECK(!path("a.").filename_is_dot()); + CHECK(!path("a..").filename_is_dot_dot()); + + // edge cases +#if BOOST_FILESYSTEM_VERSION == 3 + CHECK(path("foo/").filename() == path(".")); + CHECK(path("foo/").filename_is_dot()); +#else + CHECK(path("foo/").filename() == path("")); + CHECK(!path("foo/").filename_is_dot()); +#endif +#if BOOST_FILESYSTEM_VERSION == 3 + CHECK(path("/").filename() == path("/")); +#else + CHECK(path("/").filename() == path("")); +#endif + CHECK(!path("/").filename_is_dot()); +#ifdef BOOST_WINDOWS_API + CHECK(path("c:.").filename() == path(".")); + CHECK(path("c:.").filename_is_dot()); +#if BOOST_FILESYSTEM_VERSION == 3 + CHECK(path("c:/").filename() == path("/")); +#else + CHECK(path("c:/").filename() == path("")); +#endif + CHECK(!path("c:\\").filename_is_dot()); +#else // BOOST_WINDOWS_API + CHECK(path("c:.").filename() == path("c:.")); + CHECK(!path("c:.").filename_is_dot()); +#if BOOST_FILESYSTEM_VERSION == 3 + CHECK(path("c:/").filename() == path(".")); + CHECK(path("c:/").filename_is_dot()); +#else + CHECK(path("c:/").filename() == path("")); + CHECK(!path("c:/").filename_is_dot()); +#endif +#endif // BOOST_WINDOWS_API + + // check that the implementation code to make the edge cases above work right + // doesn't cause some non-edge cases to fail + CHECK(path("c:").filename() != path(".")); + CHECK(!path("c:").filename_is_dot()); + + // examples from reference.html + std::cout << path(".").filename_is_dot(); // outputs 1 + std::cout << path("/.").filename_is_dot(); // outputs 1 + std::cout << path("foo/.").filename_is_dot(); // outputs 1 + std::cout << path("foo/").filename_is_dot(); // outputs 1 + std::cout << path("/").filename_is_dot(); // outputs 0 + std::cout << path("/foo").filename_is_dot(); // outputs 0 + std::cout << path("/foo.").filename_is_dot(); // outputs 0 + std::cout << path("..").filename_is_dot(); // outputs 0 + cout << std::endl; +} + +// // test_modifiers ------------------------------------------------------------------// +// +// void test_modifiers() +// { +// std::cout << "testing modifiers..." << std::endl; +// +// } + +// test_iterators ------------------------------------------------------------------// + +void test_iterators() +{ + std::cout << "testing iterators..." << std::endl; + + path p1; + CHECK(p1.begin() == p1.end()); + + path p2("/"); + CHECK(p2.begin() != p2.end()); + CHECK(*p2.begin() == "/"); + CHECK(++p2.begin() == p2.end()); + + path p3("foo/bar/baz"); + + path::iterator it(p3.begin()); + CHECK(p3.begin() != p3.end()); + CHECK(*it == "foo"); + CHECK(*++it == "bar"); + CHECK(*++it == "baz"); + CHECK(*--it == "bar"); + CHECK(*--it == "foo"); + CHECK(*++it == "bar"); + CHECK(*++it == "baz"); + CHECK(++it == p3.end()); +} + +// test_reverse_iterators ----------------------------------------------------------// + +void test_reverse_iterators() +{ + std::cout << "testing reverse_iterators..." << std::endl; + + path p1; + CHECK(p1.rbegin() == p1.rend()); + + path p2("/"); + CHECK(p2.rbegin() != p2.rend()); + CHECK(*p2.rbegin() == "/"); + CHECK(++p2.rbegin() == p2.rend()); + + path p3("foo/bar/baz"); + + path::reverse_iterator it(p3.rbegin()); + CHECK(p3.rbegin() != p3.rend()); + CHECK(*it == "baz"); + CHECK(*++it == "bar"); + CHECK(*++it == "foo"); + CHECK(*--it == "bar"); + CHECK(*--it == "baz"); + CHECK(*++it == "bar"); + CHECK(*++it == "foo"); + CHECK(++it == p3.rend()); +} + +// test_modifiers ------------------------------------------------------------------// + +void test_modifiers() +{ + std::cout << "testing modifiers..." << std::endl; + + CHECK(path("").remove_filename() == ""); + CHECK(path("foo").remove_filename() == ""); + CHECK(path("/foo").remove_filename() == "/"); + + BOOST_TEST_EQ(path(".").remove_filename(), path("")); + BOOST_TEST_EQ(path("/.").remove_filename(), path("/")); + BOOST_TEST_EQ(path("..").remove_filename(), path("")); + BOOST_TEST_EQ(path("/..").remove_filename(), path("/")); + +#if BOOST_FILESYSTEM_VERSION == 3 + CHECK(path("foo/bar").remove_filename() == "foo"); + BOOST_TEST_EQ(path("foo/bar/").remove_filename(), path("foo/bar")); + BOOST_TEST_EQ(path("./.").remove_filename(), path(".")); + BOOST_TEST_EQ(path("../..").remove_filename(), path("..")); + BOOST_TEST_EQ(path("//").remove_filename(), path("")); + BOOST_TEST_EQ(path("////").remove_filename(), path("")); +#else + CHECK(path("foo/bar").remove_filename() == "foo/"); + BOOST_TEST_EQ(path("foo/bar/").remove_filename(), path("foo/bar/")); + BOOST_TEST_EQ(path("./.").remove_filename(), path("./")); + BOOST_TEST_EQ(path("../..").remove_filename(), path("../")); + BOOST_TEST_EQ(path("//").remove_filename(), path("//")); + BOOST_TEST_EQ(path("////").remove_filename(), path("////")); +#endif + + BOOST_TEST_EQ(path("foo/bar").remove_filename_and_trailing_separators(), path("foo")); + BOOST_TEST_EQ(path("foo/bar/").remove_filename_and_trailing_separators(), path("foo/bar")); + BOOST_TEST_EQ(path("foo///bar").remove_filename_and_trailing_separators(), path("foo")); + BOOST_TEST_EQ(path("foo/bar///").remove_filename_and_trailing_separators(), path("foo/bar")); + + BOOST_TEST_EQ(path("foo/bar").replace_filename("zoo"), path("foo/zoo")); + BOOST_TEST_EQ(path("foo/bar/").replace_filename("zoo"), path("foo/bar/zoo")); +} + +// test_decompositions -------------------------------------------------------------// + +void test_decompositions() +{ + std::cout << "testing decompositions..." << std::endl; + + CHECK(path("").root_name().string() == ""); + CHECK(path("foo").root_name().string() == ""); + CHECK(path("/").root_name().string() == ""); + CHECK(path("/foo").root_name().string() == ""); + CHECK(path("//netname").root_name().string() == "//netname"); + CHECK(path("//netname/foo").root_name().string() == "//netname"); + + CHECK(path("").root_directory().string() == ""); + CHECK(path("foo").root_directory().string() == ""); + CHECK(path("/").root_directory().string() == "/"); + CHECK(path("/foo").root_directory().string() == "/"); + CHECK(path("//netname").root_directory().string() == ""); + CHECK(path("//netname/foo").root_directory().string() == "/"); + + CHECK(path("").root_path().string() == ""); + CHECK(path("/").root_path().string() == "/"); + CHECK(path("/foo").root_path().string() == "/"); + CHECK(path("//netname").root_path().string() == "//netname"); + CHECK(path("//netname/foo").root_path().string() == "//netname/"); + +#ifdef BOOST_WINDOWS_API + CHECK(path("c:/foo").root_path().string() == "c:/"); +#endif + + CHECK(path("").relative_path().string() == ""); + CHECK(path("/").relative_path().string() == ""); + CHECK(path("/foo").relative_path().string() == "foo"); + + CHECK(path("").parent_path().string() == ""); + CHECK(path("/").parent_path().string() == ""); + CHECK(path("/foo").parent_path().string() == "/"); + CHECK(path("/foo/bar").parent_path().string() == "/foo"); + + CHECK(path("/foo/bar/baz.zoo").filename().string() == "baz.zoo"); + + CHECK(path("/foo/bar/baz.zoo").stem().string() == "baz"); + CHECK(path("/foo/bar.woo/baz").stem().string() == "baz"); + + CHECK(path("foo.bar.baz.tar.bz2").extension().string() == ".bz2"); + CHECK(path("/foo/bar/baz.zoo").extension().string() == ".zoo"); + CHECK(path("/foo/bar.woo/baz").extension().string() == ""); +} + +// test_queries --------------------------------------------------------------------// + +void test_queries() +{ + std::cout << "testing queries..." << std::endl; + + path p1(""); + path p2("//netname/foo.doo"); + + CHECK(p1.empty()); + CHECK(!p1.has_root_path()); + CHECK(!p1.has_root_name()); + CHECK(!p1.has_root_directory()); + CHECK(!p1.has_relative_path()); + CHECK(!p1.has_parent_path()); + CHECK(!p1.has_filename()); + CHECK(!p1.has_stem()); + CHECK(!p1.has_extension()); + CHECK(!p1.is_absolute()); + CHECK(p1.is_relative()); + + CHECK(!p2.empty()); + CHECK(p2.has_root_path()); + CHECK(p2.has_root_name()); + CHECK(p2.has_root_directory()); + CHECK(p2.has_relative_path()); + CHECK(p2.has_parent_path()); + CHECK(p2.has_filename()); + CHECK(p2.has_stem()); + CHECK(p2.has_extension()); + CHECK(p2.is_absolute()); + CHECK(!p2.is_relative()); +} + +// test_imbue_locale ---------------------------------------------------------------// + +void test_imbue_locale() +{ + std::cout << "testing imbue locale..." << std::endl; + + // weak test case for before/after states since we don't know what characters the + // default locale accepts. + path before("abc"); + + // So that tests are run with known encoding, use Boost UTF-8 codecvt + // \u2722 and \xE2\x9C\xA2 are UTF-16 and UTF-8 FOUR TEARDROP-SPOKED ASTERISK + + std::locale global_loc = std::locale(); + std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet); + std::cout << " imbuing locale ..." << std::endl; + std::locale old_loc = path::imbue(loc); + + std::cout << " testing with the imbued locale ..." << std::endl; + path p2("\xE2\x9C\xA2"); + CHECK(p2.wstring().size() == 1); + CHECK(p2.wstring()[0] == 0x2722); + + std::cout << " imbuing the original locale ..." << std::endl; + path::imbue(old_loc); + + std::cout << " testing with the original locale ..." << std::endl; + path after("abc"); + CHECK(before == after); + + std::cout << " locale testing complete" << std::endl; +} + +// test_codecvt_argument -----------------------------------------------------------// + +void test_codecvt_argument() +{ + std::cout << "testing codecvt arguments..." << std::endl; + + const char* c1 = "a1"; + const std::string s1(c1); + const std::wstring ws1(L"b2"); // off-by-one mimics test_codecvt + const std::string s2("y8"); + const std::wstring ws2(L"z9"); + + test_codecvt cvt; // produces off-by-one values that will always differ from + // the system's default locale codecvt facet + + int t = 0; + + // constructors + std::cout << " constructors test " << ++t << std::endl; + path p(c1, cvt); + NATIVE_IS(p, s1, ws1); + + std::cout << " test " << ++t << std::endl; + path p1(s1.begin(), s1.end(), cvt); + NATIVE_IS(p1, s1, ws1); + + std::cout << " test " << ++t << std::endl; + path p2(ws2, cvt); + NATIVE_IS(p2, s2, ws2); + + std::cout << " test " << ++t << std::endl; + path p3(ws2.begin(), ws2.end(), cvt); + NATIVE_IS(p3, s2, ws2); + + // path p2(p1, cvt); // fails to compile, and that is OK + + // assigns + p1.clear(); + std::cout << " assigns test " << ++t << std::endl; + p1.assign(s1, cvt); + NATIVE_IS(p1, s1, ws1); + p1.clear(); + std::cout << " test " << ++t << std::endl; + p1.assign(s1.begin(), s1.end(), cvt); + NATIVE_IS(p1, s1, ws1); + // p1.assign(p, cvt); // fails to compile, and that is OK + + // appends + p1.clear(); + std::cout << " appends test " << ++t << std::endl; + p1.append(s1, cvt); + NATIVE_IS(p1, s1, ws1); + p1.clear(); + std::cout << " test " << ++t << std::endl; + p1.append(s1.begin(), s1.end(), cvt); + NATIVE_IS(p1, s1, ws1); + // p1.append(p, cvt); // fails to compile, and that is OK + + // native observers + std::cout << " native observers test " << ++t << std::endl; + CHECK(p.string< std::string >(cvt) == s1); + std::cout << " test " << ++t << std::endl; + CHECK(p.string(cvt) == s1); + std::cout << " test " << ++t << std::endl; + CHECK(p.string< std::wstring >(cvt) == ws1); + std::cout << " test " << ++t << std::endl; + CHECK(p.wstring(cvt) == ws1); + + // generic observers + std::cout << " generic observers test " << ++t << std::endl; + CHECK(p.generic_string< std::string >(cvt) == s1); + std::cout << " test " << ++t << std::endl; + CHECK(p.generic_string(cvt) == s1); + std::cout << " test " << ++t << std::endl; + CHECK(p.generic_string< std::wstring >(cvt) == ws1); + std::cout << " test " << ++t << std::endl; + CHECK(p.generic_wstring(cvt) == ws1); + + std::cout << " codecvt arguments testing complete" << std::endl; +} + +// test_overloads ------------------------------------------------------------------// + +void test_overloads() +{ + std::cout << "testing overloads..." << std::endl; + std::string sto("hello"); + const char a[] = "goodbye"; + path p1(sto); + path p2(sto.c_str()); + path p3(a); + path p4("foo"); + + std::wstring wsto(L"hello"); + const wchar_t wa[] = L"goodbye"; + path wp1(wsto); + path wp2(wsto.c_str()); + path wp3(wa); + path wp4(L"foo"); +} + +// test_error_handling -------------------------------------------------------------// + +class error_codecvt : + public std::codecvt< wchar_t, char, std::mbstate_t > +{ +public: + explicit error_codecvt() : + std::codecvt< wchar_t, char, std::mbstate_t >() + { + } + +protected: + virtual bool do_always_noconv() const throw() { return false; } + virtual int do_encoding() const throw() { return 0; } + + virtual std::codecvt_base::result do_in(std::mbstate_t&, const char*, const char*, const char*&, wchar_t*, wchar_t*, wchar_t*&) const + { + static std::codecvt_base::result r = std::codecvt_base::noconv; + if (r == std::codecvt_base::partial) + r = std::codecvt_base::error; + else if (r == std::codecvt_base::error) + r = std::codecvt_base::noconv; + else + r = std::codecvt_base::partial; + return r; + } + + virtual std::codecvt_base::result do_out(std::mbstate_t&, const wchar_t*, const wchar_t*, const wchar_t*&, char*, char*, char*&) const + { + static std::codecvt_base::result r = std::codecvt_base::noconv; + if (r == std::codecvt_base::partial) + r = std::codecvt_base::error; + else if (r == std::codecvt_base::error) + r = std::codecvt_base::noconv; + else + r = std::codecvt_base::partial; + return r; + } + + virtual std::codecvt_base::result do_unshift(std::mbstate_t&, char*, char*, char*&) const { return ok; } + virtual int do_length(std::mbstate_t&, const char*, const char*, std::size_t) const { return 0; } + virtual int do_max_length() const throw() { return 0; } +}; + +void test_error_handling() +{ + std::cout << "testing error handling..." << std::endl; + + std::locale global_loc = std::locale(); + std::locale loc(global_loc, new error_codecvt); + std::cout << " imbuing error locale ..." << std::endl; + std::locale old_loc = path::imbue(loc); + + // These tests rely on a path constructor that fails in the locale conversion. + // Thus construction has to call codecvt. Force that by using a narrow string + // for Windows, and a wide string for POSIX. +#ifdef BOOST_WINDOWS_API +#define STRING_FOO_ "foo" +#else +#define STRING_FOO_ L"foo" +#endif + + { + std::cout << " testing std::codecvt_base::partial error..." << std::endl; + bool exception_thrown(false); + try + { + path(STRING_FOO_); + } + catch (const bs::system_error& ex) + { + exception_thrown = true; + BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::partial, fs::codecvt_error_category())); + } + catch (...) + { + std::cout << "***** unexpected exception type *****" << std::endl; + } + BOOST_TEST(exception_thrown); + } + + { + std::cout << " testing std::codecvt_base::error error..." << std::endl; + bool exception_thrown(false); + try + { + path(STRING_FOO_); + } + catch (const bs::system_error& ex) + { + exception_thrown = true; + BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::error, fs::codecvt_error_category())); + } + catch (...) + { + std::cout << "***** unexpected exception type *****" << std::endl; + } + BOOST_TEST(exception_thrown); + } + + { + std::cout << " testing std::codecvt_base::noconv error..." << std::endl; + bool exception_thrown(false); + try + { + path(STRING_FOO_); + } + catch (const bs::system_error& ex) + { + exception_thrown = true; + BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::noconv, fs::codecvt_error_category())); + } + catch (...) + { + std::cout << "***** unexpected exception type *****" << std::endl; + } + BOOST_TEST(exception_thrown); + } + + std::cout << " restoring original locale ..." << std::endl; + path::imbue(old_loc); + std::cout << " testing error handling complete" << std::endl; +} + + +inline const char* macro_value(const char* name, const char* value) +{ + static const char* no_value = "[no value]"; + static const char* not_defined = "[not defined]"; + + //if (0 != strcmp(name, value + 1)) // macro is defined + //{ + // if (value[1]) + // return value; + // else + // return no_value; + //} + //return not_defined; + + return 0 == strcmp(name, value + 1) ? not_defined : (value[1] ? value : no_value); +} + +#define BOOST_MACRO_VALUE(X) macro_value(#X, BOOST_STRINGIZE(=X)) + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// main // +// // +//--------------------------------------------------------------------------------------// + +int test_main(int, char*[]) +{ +// document state of critical macros +#ifdef BOOST_POSIX_API + cout << "BOOST_POSIX_API" << endl; + BOOST_TEST(path::preferred_separator == '/'); +#endif +#ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API" << endl; + BOOST_TEST(path::preferred_separator == '\\'); +#endif + + cout << "BOOST_FILESYSTEM_DECL " + << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_DECL) << endl; + + //#ifdef BOOST_FILESYSTEM_DECL + // cout << "BOOST_FILESYSTEM_DECL is defined as " + // << BOOST_STRINGIZE(BOOST_FILESYSTEM_DECL) << endl; + //#else + // cout << "BOOST_FILESYSTEM_DECL is not defined" << endl; + //#endif + + l.push_back('s'); + l.push_back('t'); + l.push_back('r'); + l.push_back('i'); + l.push_back('n'); + l.push_back('g'); + + wl.push_back(L'w'); + wl.push_back(L's'); + wl.push_back(L't'); + wl.push_back(L'r'); + wl.push_back(L'i'); + wl.push_back(L'n'); + wl.push_back(L'g'); + + v.push_back('f'); + v.push_back('u'); + v.push_back('z'); + + wv.push_back(L'w'); + wv.push_back(L'f'); + wv.push_back(L'u'); + wv.push_back(L'z'); + + test_overloads(); + test_constructors(); + test_assignments(); + test_move_construction_and_assignment(); + test_appends(); + test_concats(); + test_modifiers(); + test_observers(); + test_relationals(); + test_inserter_and_extractor(); + test_other_non_members(); + test_iterators(); + test_reverse_iterators(); + test_decompositions(); + test_queries(); + test_imbue_locale(); + test_codecvt_argument(); + test_error_handling(); + +#if 0 + test_user_supplied_type(); +#endif + + std::string foo("\\abc"); + const char* bar = "/abc"; + + if (foo == bar) + cout << "unintended consequence\n"; + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/quick.cpp b/3rdparty/boost_filesystem/test/quick.cpp new file mode 100644 index 0000000..b38ac4b --- /dev/null +++ b/3rdparty/boost_filesystem/test/quick.cpp @@ -0,0 +1,24 @@ + +// Copyright 2017 Peter Dimov. +// +// 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 + +// See library home page at http://www.boost.org/libs/system + +#include +#include + +namespace fs = boost::filesystem; + +int main() +{ + fs::path p1("a"); + fs::path p2 = p1 / "b"; + + BOOST_TEST_EQ(p2, "a/b"); + + return boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/relative_test.cpp b/3rdparty/boost_filesystem/test/relative_test.cpp new file mode 100644 index 0000000..e2d7b13 --- /dev/null +++ b/3rdparty/boost_filesystem/test/relative_test.cpp @@ -0,0 +1,119 @@ +// filesystem relative_test.cpp ---------------------------------------------------- // + +// Copyright Beman Dawes 2015 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// ---------------------------------------------------------------------------------- // +// +// At least initially, development is easier if these tests are in a separate file. +// +// ---------------------------------------------------------------------------------- // + +#include +#include +#include +#include + +using boost::filesystem::path; +using std::cout; +using std::endl; + +namespace { + +void lexically_relative_test() +{ + cout << "lexically_relative_test..." << endl; + + BOOST_TEST(path("").lexically_relative("") == ""); + BOOST_TEST(path("").lexically_relative("/foo") == ""); + BOOST_TEST(path("/foo").lexically_relative("") == ""); + BOOST_TEST(path("/foo").lexically_relative("/foo") == "."); + BOOST_TEST(path("").lexically_relative("foo") == ""); + BOOST_TEST(path("foo").lexically_relative("") == ""); + BOOST_TEST(path("foo").lexically_relative("foo") == "."); + + BOOST_TEST(path("a/b/c").lexically_relative("a") == "b/c"); + BOOST_TEST(path("a//b//c").lexically_relative("a") == "b/c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b") == "c"); + BOOST_TEST(path("a///b//c").lexically_relative("a//b") == "c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/c") == "."); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/c/x") == ".."); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); + BOOST_TEST(path("a/b/c").lexically_relative("a/x") == "../b/c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/x") == "../c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/x/y") == "../../b/c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/x/y") == "../../c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/c/x/y/z") == "../../.."); + BOOST_TEST(path("a/b/c").lexically_relative("a/") == "b/c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/.") == "b/c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/./") == "b/c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/..") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/../") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/d/..") == "c"); + BOOST_TEST(path("a/b/c").lexically_relative("a/b/d/../") == "c"); + + // paths unrelated except first element, and first element is root directory + BOOST_TEST(path("/a/b/c").lexically_relative("/x") == "../a/b/c"); + BOOST_TEST(path("/a/b/c").lexically_relative("/x/y") == "../../a/b/c"); + BOOST_TEST(path("/a/b/c").lexically_relative("/x/y/z") == "../../../a/b/c"); + + // paths unrelated + BOOST_TEST(path("a/b/c").lexically_relative("x") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("x/y") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("x/y/z") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("/x") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("/x/y") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("/x/y/z") == ""); + BOOST_TEST(path("a/b/c").lexically_relative("/a/b/c") == ""); + + // TODO: add some Windows-only test cases that probe presence or absence of + // drive specifier-and root-directory + + // Some tests from Jamie Allsop's paper + BOOST_TEST(path("/a/d").lexically_relative("/a/b/c") == "../../d"); + BOOST_TEST(path("/a/b/c").lexically_relative("/a/d") == "../b/c"); +#ifdef BOOST_WINDOWS_API + BOOST_TEST(path("c:\\y").lexically_relative("c:\\x") == "../y"); +#else + BOOST_TEST(path("c:\\y").lexically_relative("c:\\x") == ""); +#endif + BOOST_TEST(path("d:\\y").lexically_relative("c:\\x") == ""); + + // From issue #1976 + BOOST_TEST(path("/foo/new").lexically_relative("/foo/bar") == "../new"); +} + +void lexically_proximate_test() +{ + cout << "lexically_proximate_test..." << endl; + // paths unrelated + BOOST_TEST(path("a/b/c").lexically_proximate("x") == "a/b/c"); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// main // +// // +//--------------------------------------------------------------------------------------// + +int test_main(int, char*[]) +{ +// document state of critical macros +#ifdef BOOST_POSIX_API + cout << "BOOST_POSIX_API" << endl; +#endif +#ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API" << endl; +#endif + + lexically_relative_test(); + lexically_proximate_test(); + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/sample_test.cpp b/3rdparty/boost_filesystem/test/sample_test.cpp new file mode 100644 index 0000000..a014d6c --- /dev/null +++ b/3rdparty/boost_filesystem/test/sample_test.cpp @@ -0,0 +1,62 @@ +// filesystem sample_test.cpp ----------------------------------------------// + +// Copyright Beman Dawes 2012 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// --------------------------------------------------------------------------// +// +// This program provides a template for bug reporting test cases. +// +// --------------------------------------------------------------------------// + +#include +#include +#include +#include +#include +#include +#ifndef BOOST_LIGHTWEIGHT_MAIN +#include +#else +#include +#endif + +namespace fs = boost::filesystem; +using fs::path; +using std::cout; +using std::endl; +using std::string; +using std::wstring; + +namespace { +bool cleanup = true; +} + +// cpp_main ----------------------------------------------------------------// + +int cpp_main(int argc, char* argv[]) +{ + if (argc > 1 && std::strcmp(argv[1], "--no-cleanup") == 0) + cleanup = false; + + // Test cases go after this block of comments + // Use test case macros from boost/core/lightweight_test.hpp: + // + // BOOST_TEST(predicate); // test passes if predicate evaluates to true + // BOOST_TEST_EQ(x, y); // test passes if x == y + // BOOST_TEST_NE(x, y); // test passes if x != y + // BOOST_ERROR(msg); // test fails, outputs msg + // Examples: + // BOOST_TEST(path("f00").size() == 3); // test passes + // BOOST_TEST_EQ(path("f00").size(), 3); // test passes + // BOOST_MSG("Oops!"); // test fails, outputs "Oops!" + + if (cleanup) + { + // Remove any test files or directories here + } + + return ::boost::report_errors(); +} diff --git a/3rdparty/boost_filesystem/test/test_cmake/CMakeLists.txt b/3rdparty/boost_filesystem/test/test_cmake/CMakeLists.txt new file mode 100644 index 0000000..71e88c7 --- /dev/null +++ b/3rdparty/boost_filesystem/test/test_cmake/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2020 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +# +# NOTE: This does NOT run the unit tests for Boost.Filesystem. +# It only tests, if the CMakeLists.txt file in it's root works as expected + +cmake_minimum_required(VERSION 3.5) + +project(BoostFilesystemCMakeSelfTest) + +# Use experimental superproject to pull library dependencies recursively +set(BOOST_ENABLE_CMAKE 1) +add_subdirectory(../../../.. "${CMAKE_CURRENT_BINARY_DIR}/boost_superproject") + +add_definitions(-DBOOST_ALL_NO_LIB) + +add_executable(boost_filesystem_cmake_self_test main.cpp) +target_link_libraries(boost_filesystem_cmake_self_test Boost::filesystem) diff --git a/3rdparty/boost_filesystem/test/test_cmake/main.cpp b/3rdparty/boost_filesystem/test/test_cmake/main.cpp new file mode 100644 index 0000000..ea18dee --- /dev/null +++ b/3rdparty/boost_filesystem/test/test_cmake/main.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2020 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include + +int main() +{ + boost::filesystem::path p("."); + boost::filesystem::is_directory(p); +} diff --git a/3rdparty/boost_filesystem/test/test_codecvt.hpp b/3rdparty/boost_filesystem/test/test_codecvt.hpp new file mode 100644 index 0000000..d5fc617 --- /dev/null +++ b/3rdparty/boost_filesystem/test/test_codecvt.hpp @@ -0,0 +1,72 @@ +// test_codecvt.hpp ------------------------------------------------------------------// + +// Copyright Beman Dawes 2009, 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_TEST_CODECVT_HPP +#define BOOST_FILESYSTEM_TEST_CODECVT_HPP + +#include +#include +#include // for mbstate_t + +//------------------------------------------------------------------------------------// +// // +// class test_codecvt // +// // +// Warning: partial implementation; even do_in and do_out only partially meet the // +// standard library specifications as the "to" buffer must hold the entire result. // +// // +// The value of a wide character is the value of the corresponding narrow character // +// plus 1. This ensures that compares against expected values will fail if the // +// code conversion did not occur as expected. // +// // +//------------------------------------------------------------------------------------// + +class test_codecvt : + public std::codecvt< wchar_t, char, std::mbstate_t > +{ +public: + explicit test_codecvt() : + std::codecvt< wchar_t, char, std::mbstate_t >() + { + } + +protected: + virtual bool do_always_noconv() const throw() { return false; } + virtual int do_encoding() const throw() { return 0; } + + virtual std::codecvt_base::result do_in(std::mbstate_t&, const char* from, const char* from_end, const char*& from_next, wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const + { + for (; from != from_end && to != to_end; ++from, ++to) + *to = wchar_t(*from + 1); + if (to == to_end) + return error; + *to = L'\0'; + from_next = from; + to_next = to; + return ok; + } + + virtual std::codecvt_base::result do_out(std::mbstate_t&, const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, char* to, char* to_end, char*& to_next) const + { + for (; from != from_end && to != to_end; ++from, ++to) + *to = static_cast< char >(*from - 1); + if (to == to_end) + return error; + *to = '\0'; + from_next = from; + to_next = to; + return ok; + } + + virtual std::codecvt_base::result do_unshift(std::mbstate_t&, char* /*from*/, char* /*to*/, char*& /*next*/) const { return ok; } + virtual int do_length(std::mbstate_t&, const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const { return 0; } + virtual int do_max_length() const throw() { return 0; } +}; + +#endif // BOOST_FILESYSTEM_TEST_CODECVT_HPP diff --git a/3rdparty/boost_filesystem/test/windows_attributes.cpp b/3rdparty/boost_filesystem/test/windows_attributes.cpp new file mode 100644 index 0000000..cdca535 --- /dev/null +++ b/3rdparty/boost_filesystem/test/windows_attributes.cpp @@ -0,0 +1,106 @@ +// windows_attributes ----------------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +// Useful for debugging status related issues // + +//--------------------------------------------------------------------------------------// + +#include +#include +#include +#include +#include +#include +#include + +using std::make_pair; +namespace fs = boost::filesystem; + +int cpp_main(int argc, char* argv[]) +{ + typedef std::map< DWORD, std::string > decode_type; + decode_type table; + + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_ARCHIVE, "FILE_ATTRIBUTE_ARCHIVE")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_COMPRESSED, "FILE_ATTRIBUTE_COMPRESSED")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_DEVICE, "FILE_ATTRIBUTE_DEVICE")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_DIRECTORY, "FILE_ATTRIBUTE_DIRECTORY")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_ENCRYPTED, "FILE_ATTRIBUTE_ENCRYPTED")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_HIDDEN, "FILE_ATTRIBUTE_HIDDEN")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_OFFLINE, "FILE_ATTRIBUTE_OFFLINE")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_READONLY, "FILE_ATTRIBUTE_READONLY")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_REPARSE_POINT, "FILE_ATTRIBUTE_REPARSE_POINT")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_SPARSE_FILE, "FILE_ATTRIBUTE_SPARSE_FILE")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_SYSTEM, "FILE_ATTRIBUTE_SYSTEM")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_TEMPORARY, "FILE_ATTRIBUTE_TEMPORARY")); + table.insert(make_pair< DWORD, std::string >(FILE_ATTRIBUTE_VIRTUAL, "FILE_ATTRIBUTE_VIRTUAL")); + + if (argc < 2) + { + std::cout << "Usage: windows_attributes path\n"; + return 1; + } + + // report Win32 ::GetFileAttributesA() + + DWORD at(::GetFileAttributesA(argv[1])); + if (at == INVALID_FILE_ATTRIBUTES) + { + std::cout << "GetFileAttributes(\"" << argv[1] + << "\") returned INVALID_FILE_ATTRIBUTES\n"; + return 0; + } + + std::cout << "GetFileAttributes(\"" << argv[1] + << "\") returned "; + + bool bar = false; + for (decode_type::iterator it = table.begin(); it != table.end(); ++it) + { + if (!(it->first & at)) + continue; + if (bar) + std::cout << " | "; + bar = true; + std::cout << it->second; + at &= ~it->first; + } + std::cout << std::endl; + + if (at) + std::cout << "plus unknown attributes " << at << std::endl; + + // report Boost Filesystem file_type + + fs::file_status stat = fs::status(argv[1]); + + const char* types[] = + { + "status_error", + "file_not_found", + "regular_file", + "directory_file", + // the following may not apply to some operating systems or file systems + "symlink_file", + "block_file", + "character_file", + "fifo_file", + "socket_file", + "reparse_file", // Windows: FILE_ATTRIBUTE_REPARSE_POINT that is not a symlink + "type_unknown" // file does exist", but isn't one of the above types or + // we don't have strong enough permission to find its type + }; + + std::cout << "boost::filesystem::status().type() is " << types[stat.type()] << std::endl; + + return 0; +} diff --git a/CustomImGuiFileDialogConfig.h b/CustomImGuiFileDialogConfig.h index ce30c37..56a0957 100644 --- a/CustomImGuiFileDialogConfig.h +++ b/CustomImGuiFileDialogConfig.h @@ -7,7 +7,7 @@ //this options need c++17 // in this app its defined in CMakeLists.txt -#define USE_STD_FILESYSTEM +//#define USE_STD_FILESYSTEM //#define MAX_FILE_DIALOG_NAME_BUFFER 1024 //#define MAX_PATH_BUFFER_SIZE 1024 diff --git a/ImGuiFileDialog b/ImGuiFileDialog index ee18f0b..cbb5cf6 160000 --- a/ImGuiFileDialog +++ b/ImGuiFileDialog @@ -1 +1 @@ -Subproject commit ee18f0ba4d1343551068bad61f9971bbce9a9d61 +Subproject commit cbb5cf6d6e32c658ac649dc74d31e478f0abd194