Replace cppbackport with ghc-filesystem

From https://github.com/gulrak/filesystem which is more up-to-date and
looks better maintained than cppbackport.
pull/952/head
Jason Rhinelander 5 years ago
parent 9c7355ff9c
commit 8d2c22fc72

@ -238,10 +238,6 @@ if(WITH_TESTS)
endif()
add_subdirectory(${ABSEIL_DIR})
if (FS_LIB STREQUAL "cppbackport")
add_subdirectory(vendor)
endif()
if(ANDROID)
list(APPEND LIBS log)
add_definitions(-DANDROID)

@ -29,15 +29,20 @@ if(EMBEDDED_CFG OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
link_libatomic()
endif()
function(use_vendored_filesystem)
include_directories("${CMAKE_CURRENT_LIST_DIR}/../vendor/ghc-filesystem/include")
add_definitions(-DLOKINET_USE_GHC_FILESYSTEM)
set(FS_LIB "" PARENT_SCOPE)
message(STATUS "Using vendored ghc::filesystem")
endfunction()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(FS_LIB stdc++fs)
list(APPEND LIBTUNTAP_SRC ${TT_ROOT}/tuntap-unix-linux.c)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android")
find_library(FS_LIB NAMES c++fs c++experimental stdc++fs)
if(FS_LIB STREQUAL FS_LIB-NOTFOUND)
include_directories("${CMAKE_CURRENT_LIST_DIR}/../vendor/cppbackport-master/lib")
add_definitions(-DLOKINET_USE_CPPBACKPORT)
set(FS_LIB cppbackport)
use_vendored_filesystem()
endif()
list(APPEND LIBTUNTAP_SRC ${TT_ROOT}/tuntap-unix-linux.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
@ -50,9 +55,7 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
find_library(FS_LIB NAMES c++fs c++experimental stdc++fs)
if(FS_LIB STREQUAL FS_LIB-NOTFOUND)
include_directories("${CMAKE_CURRENT_LIST_DIR}/../vendor/cppbackport-master/lib")
add_definitions(-DLOKINET_USE_CPPBACKPORT)
set(FS_LIB cppbackport)
use_vendored_filesystem()
endif()
list(APPEND LIBTUNTAP_SRC ${TT_ROOT}/tuntap-unix-darwin.c ${TT_ROOT}/tuntap-unix-bsd.c)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
@ -63,9 +66,7 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
link_libraries(-lkstat -lsendfile)
endif()
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
include_directories("${CMAKE_CURRENT_LIST_DIR}/../vendor/cppbackport-master/lib")
add_definitions(-DLOKINET_USE_CPPBACKPORT)
set(FS_LIB cppbackport)
use_vendored_filesystem()
else()
set(FS_LIB stdc++fs)
endif()
@ -73,6 +74,9 @@ else()
message(FATAL_ERROR "Your operating system - ${CMAKE_SYSTEM_NAME} is not supported yet")
endif()
if(FS_LIB AND USE_VENDORED_FILESYSTEM)
use_vendored_filesystem()
endif()
set(EXE_LIBS ${STATIC_LIB})

@ -9,9 +9,9 @@
#define PATH_SEP "/"
#endif
#if defined(LOKINET_USE_CPPBACKPORT)
#include <filesystem.h>
namespace fs = cpp17::filesystem;
#if defined(LOKINET_USE_GHC_FILESYSTEM)
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#elif __cplusplus >= 201703L && !defined(_MSC_VER)
#include <filesystem>
namespace fs = std::filesystem;

@ -1,21 +0,0 @@
set(CXX_COMPAT_SRC
cppbackport-master/lib/fs/rename.cpp
cppbackport-master/lib/fs/filestatus.cpp
cppbackport-master/lib/fs/filetype.cpp
cppbackport-master/lib/fs/cleanpath.cpp
cppbackport-master/lib/fs/perms.cpp
cppbackport-master/lib/fs/equivalent.cpp
cppbackport-master/lib/fs/current_path.cpp
cppbackport-master/lib/fs/basename.cpp
cppbackport-master/lib/fs/tempdir.cpp
cppbackport-master/lib/fs/create_directory.cpp
cppbackport-master/lib/fs/path.cpp
cppbackport-master/lib/fs/remove.cpp
cppbackport-master/lib/fs/diriter.cpp
cppbackport-master/lib/fs/copyfile.cpp
cppbackport-master/lib/fs/absolute.cpp
cppbackport-master/lib/fs/direntry.cpp
)
add_library(cppbackport STATIC ${CXX_COMPAT_SRC})
target_include_directories(cppbackport PUBLIC cppbackport-master/lib)

@ -1,27 +0,0 @@
Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of cppbackport nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -1,60 +0,0 @@
This is a backport of the current C++ standard library to C++03/11/14. Obviously not everything
can be backported, but quite a bit can.
Quick Start
===========
There are a couple of small examples to give you an idea of usage. If you have make and g++
you can build things quickly enough:
- clone the repo to /some/place/cppbackport
- make a temp dir /wherever/you/wanna/build
- cd /wherever/you/wanna/build
- make -f /some/place/cppbackport/examples/Makefile
The examples are all setup to compile the cppbackport files as a static library (libcppbackport.a),
and then link it with one of the main example files (ex., gibberish.cpp).
Installation
============
I recommend copying the lib directory into your project, and calling the included Makefile
to create libcppbackport.a. Link that into your project, and add the appropriate include
flags (ex., -iquotecppbackport).
Usage
=====
Basically, #include "filesystem.h" or similar. Then use cpp namespace in place of std namespace.
The headers are all named after their official counterparts, with the addition of the .h
extension.
FAQ
===
**Who is this library suitable for?**
Anyone, really. There are a few use cases:
- The primary use case is to provide some newer features to people who are stuck with/choose to use an older compiler
- Another use would be to soften the requirements of your own project (i.e., so your users can use an older compiler)
- In some cases, this project may provide usable code before compilers support a standard. For example, C++17 at the moment isn't even standardized, *but* we basically know what's in it so we can start supporting it.
**What's the license?**
BSD 3-clause. Use it. Contribute if you like. Don't blame us for things.
**What compiler(s)/platforms are supported**
The development environment is Fedora 24 with GCC 6.1.1. I've used it with earlier versions
of GCC (4.7.4, I think), and a semi-recent version of Clang. I've not tested under Windows, yet.
**Will this use C++11/14/17 if available?**
Yes. Based on the value of the __cplusplus define, the files will simply #include the
system header (as appropriate).
**Why not header-only?**
I actually like the interface/implementation distinction. Header-only implementations (IMO)
get way too large and the files are difficult to navigate. Also, save the compiler some work.
Also, installing a lib isn't really that hard.
**Does it work on Windows?**
Sorry, POSIX mostly. Would love for some Windows devs to help.
**Why not use Boost?**
There's some overlap, but there are differences, too. And none of these things, *individually*
are that big.

@ -1,2 +0,0 @@
// Add predefined macros for your project here. For example:
// #define THE_ANSWER 42

@ -1,144 +0,0 @@
examples/any.cpp
examples/clock.cpp
examples/directory_listing.cpp
examples/fbind.cpp
examples/gibberish.cpp
examples/hash.cpp
examples/histogram.cpp
examples/lshere.cpp
examples/mathfns.cpp
examples/maxalign.cpp
examples/multithreading.cpp
examples/multitype.cpp
examples/now.cpp
examples/optional.cpp
examples/pathiter.cpp
examples/singlell.cpp
examples/smartptr.cpp
examples/tempdir.cpp
examples/testtraits.cpp
examples/two_threads.cpp
lib/algorithm.h
lib/any.h
lib/array.h
lib/atomic.h
lib/chrono.cpp
lib/chrono.h
lib/cmath.cpp
lib/cmath.h
lib/condition_variable.cpp
lib/condition_variable.h
lib/config/arch.h
lib/config/os.h
lib/cstdarg.h
lib/cstddef.h
lib/cstdint.h
lib/cstdlib.h
lib/filesystem.h
lib/forward_list.h
lib/fs/absolute.cpp
lib/fs/absolute.h
lib/fs/basename.cpp
lib/fs/basename.h
lib/fs/cleanpath.cpp
lib/fs/cleanpath.h
lib/fs/copyfile.cpp
lib/fs/copyfile.h
lib/fs/create_directory.cpp
lib/fs/create_directory.h
lib/fs/current_path.cpp
lib/fs/current_path.h
lib/fs/direntry.cpp
lib/fs/direntry.h
lib/fs/diriter.cpp
lib/fs/diriter.h
lib/fs/equivalent.cpp
lib/fs/equivalent.h
lib/fs/filestatus.cpp
lib/fs/filestatus.h
lib/fs/filetype.cpp
lib/fs/filetype.h
lib/fs/path.cpp
lib/fs/path.h
lib/fs/perms.cpp
lib/fs/perms.h
lib/fs/remove.cpp
lib/fs/remove.h
lib/fs/rename.cpp
lib/fs/rename.h
lib/fs/tempdir.cpp
lib/fs/tempdir.h
lib/functional.h
lib/future.h
lib/iterator.h
lib/locale.h
lib/memory.h
lib/mutex.cpp
lib/mutex.h
lib/numeric.h
lib/optional.h
lib/random.cpp
lib/random.h
lib/ratio.h
lib/rvalueref.h
lib/shared_mutex.cpp
lib/shared_mutex.h
lib/string.h
lib/string_view.h
lib/system_error.h
lib/thread.cpp
lib/thread.h
lib/traits/add_cv.h
lib/traits/add_pointer.h
lib/traits/add_reference.h
lib/traits/alignment.h
lib/traits/common_type.h
lib/traits/conditional.h
lib/traits/decay.h
lib/traits/declval.h
lib/traits/enable_if.h
lib/traits/extent.h
lib/traits/integral_constant.h
lib/traits/is_arithmetic.h
lib/traits/is_array.h
lib/traits/is_base_of.h
lib/traits/is_class_or_union.h
lib/traits/is_compound.h
lib/traits/is_const.h
lib/traits/is_convertible.h
lib/traits/is_enum.h
lib/traits/is_floating_point.h
lib/traits/is_function.h
lib/traits/is_fundamental.h
lib/traits/is_integral.h
lib/traits/is_member_pointer.h
lib/traits/is_null_pointer.h
lib/traits/is_object.h
lib/traits/is_pointer.h
lib/traits/is_reference.h
lib/traits/is_same.h
lib/traits/is_scalar.h
lib/traits/is_signed.h
lib/traits/is_unsigned.h
lib/traits/is_void.h
lib/traits/is_volatile.h
lib/traits/make_signed.h
lib/traits/make_unsigned.h
lib/traits/rank.h
lib/traits/remove_cv.h
lib/traits/remove_extent.h
lib/traits/remove_pointer.h
lib/traits/remove_reference.h
lib/traits/result_of.h
lib/traits/underlying_type.h
lib/traits/void_t.h
lib/traits/yesno.h
lib/tuple.h
lib/type_traits.h
lib/unordered_map.h
lib/unordered_set.h
lib/utility.h
lib/variant.h
lib/version.h
LICENSE
README.md

@ -1,56 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CONFIG_ARCH_H
#define PBL_CONFIG_ARCH_H
#include <climits>
/* Whether or not the compiler supports long long and unsigned long long
*/
#ifndef HAS_LONG_LONG
#if __cplusplus >= 201103L
#define HAS_LONG_LONG
#else
#ifdef __GNUG__
#ifdef __SIZEOF_LONG_LONG__
#define HAS_LONG_LONG
#endif
#endif
#endif
#endif
/* The character type that char matches (i.e., signed or unsigned)
*/
#if CHAR_MIN < 0
typedef signed char underlying_char_type;
#else
typedef unsigned char underlying_char_type;
#endif
#endif // PBL_CONFIG_ARCH_H

@ -1,131 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** Provide types, macros, and functions for the operating system
*
* This file provides a stable way to work with the OS. It provides
* - namespaces and typedefs that can be used portably between OS's
* - feature macros for enabling specific operating system capabilities
*
* @todo May want to rethink OS_POSIX as feature test macros since posix can
* sorta be in Windows (ex., Cygwin)
*/
#ifndef PBL_CONFIG_OS_H
#define PBL_CONFIG_OS_H
// =============================================================================
// Determine the platform. Ex., Windows or POSIX. Define feature macros
#if ( defined( __unix__ ) || defined( __unix ) || ( defined( __APPLE__ ) && defined( __MACH__ ) ) )
#include <unistd.h>
#ifdef _POSIX_VERSION
// ISO POSIX.1 aka IEEE 1003.1
/// OS_POSIX - unistd.h is included and _POSIX_VERSION is defined
#define OS_POSIX
#if _POSIX_VERSION >= 199506L
// ISO POSIX.1-1996 aka IEEE 1003.1-1996
#define POSIX_THREADS
#if ( _POSIX_VERSION >= 200112L )
// ISO POSIX.1-2001 aka IEEE 1003.1-2001, aka Issue 6, aka SUSv3
#define POSIX_ISSUE_6
#if ( _POSIX_VERSION >= 200809L )
// ISO POSIX.1-2008, aka IEEE 1003.1-2008, aka Issue 7, aka SUSv4
#define POSIX_ISSUE_7
#endif // 2008
#endif // 2001
#endif // 1996
#endif // ifdef _POSIX_VERSION
#endif // if ( defined( __unix__ ) || defined( __unix ) || ( defined( __APPLE__ ) && defined( __MACH__ )))
#if defined( _WIN64 ) || defined( _WIN32 )
#include <windows.h> /* MS Windows operating systems */
#define OS_WINDOWS
#endif
// =============================================================================
// Determine basic types
#ifdef OS_POSIX
#include <sys/types.h>
namespace pbl
{
namespace os
{
// Identifies a user
typedef uid_t user_id_type;
// Identifies a process
typedef pid_t pid_type;
}
}
#else
#ifdef OS_WINDOWS
namespace pbl
{
namespace os
{
typedef DWORD pid_type;
}
}
#endif // Windows
#endif // ifdef OS_POSIX
// =============================================================================
// Determine multithreading types
#ifdef POSIX_THREADS
#include <pthread.h>
namespace pbl
{
namespace os
{
typedef pthread_t thread_type;
typedef pthread_mutex_t mutex_type;
typedef pthread_rwlock_t shared_mutex_type;
typedef pthread_cond_t condition_variable_type;
}
}
#else
#ifdef OS_WINDOWS
namespace pbl
{
namespace os
{
typedef HANDLE thread_type;
typedef CRITICAL_SECTION mutex_type;
}
}
#endif
#endif // ifdef POSIX_THREADS
#endif // PBL_CONFIG_OS_H

@ -1,116 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @file version.h
* @brief namespaces for C++11 and C++14
*/
#ifndef PBL_CPP_VERSION_H
#define PBL_CPP_VERSION_H
#include <cstddef>
/// @todo Value may not be correct, because as of writing C++17 isn't official
#if __cplusplus >= 201703L
#define CPP17
#endif
#if __cplusplus >= 201402L
#define CPP14
#endif
#if __cplusplus >= 201103L
#define CPP11
#endif
/* Namespace macros. It's sometimes necessary to put something into the "std"
* namespace. For example, a specialization of std::hash. These macros can be
* used to put the code in the correct namespace.
*/
#ifdef CPP17
#define CPP17_NAMESPACE std
#else
#define CPP17_NAMESPACE cpp17
#endif
#ifdef CPP14
#define CPP14_NAMESPACE std
#else
#define CPP14_NAMESPACE cpp14
#endif
#ifdef CPP11
#define CPP11_NAMESPACE std
#else
#define CPP11_NAMESPACE cpp11
#endif
namespace cpp11
{
}
#ifndef CPP11
namespace cpp11
{
class nullptr_t
{
public:
template< class T >
operator T*() const
{
return 0;
}
template< class C, class T >
operator T C::*( ) const
{
return 0;
}
private:
void operator&() const;
};
}
const cpp11::nullptr_t nullptr = {};
#endif // ifndef CPP11
namespace cpp14
{
}
namespace cpp17
{
}
/* cpp points to either std or cpp11/14/17 as appropriate
*/
namespace cpp
{
using namespace ::std;
using namespace ::cpp11;
using namespace ::cpp14;
using namespace ::cpp17;
}
#endif // PBL_CPP_VERSION_H

@ -1,58 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FILESYSTEM_H
#define PBL_CPP_FILESYSTEM_H
#include "cppbackport_version.h"
#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM)
#include <experimental/filesystem>
#else
// OpenBSD needs this
// MacOS llvm 3.8 needs this
#include "fs/absolute.h"
#include "fs/basename.h"
#include "fs/cleanpath.h"
#include "fs/copyfile.h"
#include "fs/create_directory.h"
#include "fs/current_path.h"
#include "fs/direntry.h"
#include "fs/diriter.h"
#include "fs/equivalent.h"
#include "fs/filestatus.h"
#include "fs/filetype.h"
#include "fs/path.h"
#include "fs/perms.h"
#include "fs/remove.h"
#include "fs/rename.h"
#include "fs/tempdir.h"
#endif // if not cpp17 and not openbsd
#endif // PBL_CPP_FILESYSTEM_H

@ -1,96 +0,0 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "absolute.h"
#include <climits>
#include <cstdlib>
#include "../config/os.h"
namespace cpp17
{
namespace filesystem
{
path
absolute(const path& filename)
{
if(!filename.empty())
{
#if((defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809l) \
|| defined(__GLIBC__)) \
|| defined(ANDROID)
// Preferred - POSIX-2008 and glibc will allocate the path buffer
char* res = ::realpath(filename.c_str(), NULL);
if(res)
{
path s = res;
::free(res);
return s;
}
#else
#ifdef _GNU_SOURCE
// Maybe we can rely on the GNU extension
char* res = ::canonicalize_file_name(filename.c_str());
if(res)
{
std::string s = res;
::free(res);
return s;
}
#elif(((defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
|| (defined(_XOPEN_VERSION) && _XOPEN_VERSION >= 500)) \
&& defined(PATH_MAX))
/// @todo PATH_MAX may be huge or -1, according to man pages for
/// realpath
char resolved[PATH_MAX + 1];
char* res = ::realpath(filename.c_str(), resolved);
if(res)
{
return resolved;
}
#else
#error "No way to get absolute file path!"
#endif // if 1
#endif // if ( defined( _POSIX_VERSION ) && _POSIX_VERSION >= 200809l )
}
return path();
}
} // namespace filesystem
} // namespace cpp17

@ -1,50 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_ABSOLUTE_H
#define PBL_CPP_FS_ABSOLUTE_H
#include "path.h"
namespace cpp17
{
namespace filesystem
{
/** Get an absolute path of a file
*
* @param filepath The path of an (existing) file
* @returns An absolute path that corresponds to the same file as filepath, or
* an empty string if there is an error.
*/
path absolute(const path& filepath);
}
}
#endif // PBL_CPP_FS_ABSOLUTE_H

@ -1,207 +0,0 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "basename.h"
#include "../config/os.h"
#include "cleanpath.h"
namespace
{
// the position following the previous occurrence of c (relative to position
// j), or 0 if not. In this file, the first letter of a path component.
std::size_t
after_last(const std::string& s, char c, std::size_t j)
{
std::size_t i = s.find_last_of(c, j);
return i == std::string::npos ? 0 : i + 1;
}
// (first character, length) of last path component in s or (0,0) for "."
// or (npos, 0) if error
std::pair< std::size_t, std::size_t >
locate_last_path_component(const std::string& s)
{
if(s.empty())
{
// error
return std::pair< std::size_t, std::size_t >(std::string::npos, 0);
}
// j points to the last character in a component
std::size_t j = s.find_last_not_of('/');
unsigned depth = 0;
while(j != std::string::npos)
{
// i points to first character of a component
// i <= j, because j never points to a '/'
const std::size_t i = after_last(s, '/', j);
if(j - i + 1 == 1 && s[i] == '.')
{
// component is ".", basically ignore this component
}
else if(j - i + 1 == 2 && s[i] == '.' && s[i + 1] == '.')
{
// component is "..", ignore the next component
++depth;
}
else
{
// found a "normal" path component
if(depth == 0)
{
return std::pair< std::size_t, std::size_t >(i, j - i + 1);
}
// ..but we're ignoring it
--depth;
}
if(i == 0)
{
if(depth == 0)
{
// "."
return std::pair< std::size_t, std::size_t >(0, 0);
}
else
{
// error, path is malformed
return std::pair< std::size_t, std::size_t >(std::string::npos, 0);
}
}
j = s.find_last_not_of('/', i - 1);
}
// all slashes
return std::pair< std::size_t, std::size_t >(0, 1);
}
std::string
basename_posix(const std::string& s)
{
const std::pair< std::size_t, std::size_t > range =
locate_last_path_component(s);
if(range.first == std::string::npos)
{
return std::string();
}
if(range.first == 0 && range.second == 0)
{
return ".";
}
return s.substr(range.first, range.second);
}
std::string
dirname_posix(const std::string& s)
{
const std::pair< std::size_t, std::size_t > range =
locate_last_path_component(s);
// path was malformed
if(range.first == std::string::npos)
{
return std::string();
}
if(range.first == 0)
{
if(range.second == 0)
{
return "..";
}
// could be '/', or could be a unpathed filename
if(s[0] == '/')
{
return "/";
}
return ".";
}
else
{
// leading directory
return s.substr(0, range.first);
}
}
} // namespace
namespace cpp17
{
namespace filesystem
{
// Calls the basename_xxx appropriate for this platform
std::string
basename(const std::string& s)
{
#ifdef OS_POSIX
return basename_posix(s);
#else
std::string t;
char fname[_MAX_FNAME], ext[_MAX_EXT];
_splitpath(s.c_str(), nullptr, nullptr, fname, ext);
t = fname;
t += ext;
return t;
#endif
}
std::string
dirname(const std::string& s)
{
#ifdef OS_POSIX
const std::string& t = dirname_posix(s);
if(t == ".")
{
return t;
}
return cleanpath(t);
#else
std::string t;
char _dirname[_MAX_DIR];
_splitpath(s.c_str(), nullptr, _dirname, nullptr, nullptr);
t = _dirname;
return t;
#endif
}
} // namespace filesystem
} // namespace cpp17

@ -1,85 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_BASENAME_H
#define PBL_CPP_FS_BASENAME_H
#include <string>
namespace cpp17
{
namespace filesystem
{
/** Return the name of the file system component indicated by path
*
* @param path A file path
* @returns The name of the directory or file that the path points to, or the
* empty string if there's an error
*
* The exact behavior of this function is platform dependent, because paths are.
* However, whatever the platform, it should return the name of the file or
* directory pathed. Ex., on POSIX platforms it should return "readme.txt" for
* "/home/user/documents/readme.txt"; similarly it should return "readme.txt"
* for "C:\Windows\readme.txt" on Windows platforms.
*
* This function does not access the file system. It merely parses the string.
* In particular, it does not check if the path is valid and/or accessible. It
* also does not check that the component before "." or ".." is, in fact, a
* directory.
*
* If the last component cannot be determined for whatever reason, the string is
* considered malformed and the empty string is returned.
*
* @note Although the empty string is considered a malformed path, "." (and
* anything equivalent) will return ".".
*/
std::string basename(const std::string& path);
/** Return the directory which has the last path component
*
* @param path A file path
*
* Determines the last path component as in basename, then returns directory
* which contains that file system object. Ex., the dirname of
* "/home/user/documents/readme.txt" is "/home/user/documents".
*
* As special cases, the dirname of a bare filename is "."; the dirname of
* "." (or equivalent) is ".."; the dirname of the root directory is still the
* root.
*
* If the path is malformed, the empty string is returned.
*
* @sa basename
*/
std::string dirname(const std::string& path);
}
}
#endif // PBL_FS_BASENAME_H

@ -1,144 +0,0 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "cleanpath.h"
#include <algorithm>
#if defined(_WIN32) && !defined(NOMINMAX)
#define NOMINMAX
#endif
namespace cpp17
{
namespace filesystem
{
/// @todo Probably belongs in path.cpp
std::string
cleanpath(const std::string& s)
{
std::string t;
if(s.empty())
{
// error
return t;
}
const std::size_t n = s.length();
for(std::size_t i = 0; i < n;)
{
if(s[i] == '/')
{
// directory separator
t.push_back('/');
i = s.find_first_not_of('/', i);
}
else
{
// path component
const std::size_t j = std::min(s.find('/', i), n);
if(s.compare(i, j - i, ".", 1) == 0)
{
// handle dot
if(j < n)
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
else if(s.compare(i, j - i, "..", 2) == 0)
{
// handle dot-dot
const std::size_t l = t.length();
if(l == 0)
{
// no previous component (ex., "../src")
t.assign("..", 2);
i = j;
}
else
{
// remove previously copied component (unless root)
if(l >= 2)
{
const std::size_t k = t.find_last_of('/', l - 2);
if(k == std::string::npos)
{
t.clear();
}
else
{
t.resize(k + 1);
}
}
if(j < n)
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
}
else
{
// append path component
t.append(s, i, j - i);
i = j;
}
}
}
if(t.empty())
{
return ".";
}
// drop trailing slashes
const std::size_t i = t.find_last_not_of('/');
if(i != std::string::npos)
{
t.resize(i + 1);
}
return t;
}
} // namespace filesystem
} // namespace cpp17

@ -1,64 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_CLEANPATH_H
#define PBL_CPP_FS_CLEANPATH_H
#include <string>
namespace cpp17
{
namespace filesystem
{
/** Return a simplified version of path
*
* @param path A file system path
*
* Collapses multiple path separators (ex., as in "/home//user"); replaces
* "name/." with "name" and "parent/child/.." with "parent"; removes
* trailing slashes.
*
* The returned path is equivalent to the original path in the sense that it
* identifies the same file system object. Specifically, relative paths are
* preserved (ex., no simplification is done to the dot-dot in "../here").
*
* If the path is malformed, the empty string is returned. For this
* function, really only the empty string itself is "malformed".
*
* @note This is a textual operation. It does not validate the string
* against the file system or otherwise touch the file system.
* @bug foo/bar/../baz may not point to /foo/baz if bar symlinks to
* flip/flop
*/
std::string
cleanpath(const std::string& path);
} // namespace filesystem
} // namespace cpp17
#endif // PBL_FS_CLEANPATH_H

@ -1,174 +0,0 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "copyfile.h"
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace cpp17
{
namespace filesystem
{
/** Try to do copy the file as safely as possible (esp., gracefully handle
* errors, avoid race conditions).
*
* @bug If there's an error while overwriting a file, the original is lost
*/
bool copy_file(
const path& source,
const path& dest,
copy_options opt
)
{
const int in = ::open(source.c_str(), O_RDONLY | O_CLOEXEC);
if ( in != -1 )
{
struct stat instat;
if ( ::fstat(in, &instat) == 0 && ( S_ISREG(instat.st_mode) || S_ISLNK(instat.st_mode) ) )
{
// Get the destination file
int out = ::open(dest.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, S_IWUSR);
if ( out == -1 && errno == EEXIST )
{
// File already exists -- maybe we will overwrite it
out = ::open(dest.c_str(), O_WRONLY | O_CLOEXEC);
if ( out != -1 )
{
bool err = false;
struct stat outstat;
if ( ( ::fstat(out, &outstat) != 0 ) || ( instat.st_dev == outstat.st_dev && instat.st_ino == outstat.st_ino ) || ( ( opt & 7 ) == 0 ) )
{
// Couldn't stat, Same file, or bad copy_options
err = true;
}
else
{
// Replace file or not, depending on flags
if ( (opt& copy_options::overwrite_existing) || ( (opt& copy_options::update_existing) && ( instat.st_mtime > outstat.st_mtime ) ) )
{
// replace the existing file
if ( ::ftruncate(out, 0) != 0 )
{
err = true;
}
}
else
{
// do nothing
::close(out);
::close(in);
return false;
}
}
if ( err )
{
::close(out);
out = -1;
}
}
}
// Do we have a destination file?
if ( out != -1 )
{
bool err = false;
while ( !err )
{
char buf[4096];
const ssize_t n = ::read( in, buf, sizeof( buf ) );
if ( n == -1 )
{
err = true;
}
else if ( n == 0 )
{
// EOF - copy has been successful
::fchmod(out, instat.st_mode & 0777);
::close(out);
::close(in);
return true;
}
else
{
const char* p = buf;
while ( p - buf < n )
{
const ssize_t m = ::write( out, p, static_cast< std::size_t >( n - ( p - buf ) ) );
if ( m == -1 )
{
err = true;
break;
}
p += m;
}
}
}
// Remove the incomplete file
::unlink( dest.c_str() );
::close(out);
}
}
::close(in);
}
return false;
}
bool copy_file(
const path& source,
const path& dest
)
{
return copy_file(source, dest, ::copy_options::none);
}
}
}

@ -1,81 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_COPYFILE_H
#define PBL_CPP_FS_COPYFILE_H
#include "path.h"
namespace copy_options
{
enum copy_options
{
none = 0,
skip_existing = 1,
overwrite_existing = 2,
update_existing = 4,
recursive = 8,
copy_symlinks = 16,
skip_symlinks = 32,
directories_only = 64,
create_symlinks = 128,
create_hard_links = 256
};
}
namespace cpp17
{
namespace filesystem
{
typedef ::copy_options::copy_options copy_options;
/** Copy the file at source to dest
*
* @param source A file to copy
* @param dest A file (including name) of the file to create
* @returns true iff dest exists and is a copy of source
*
* If source does not exist or is not a file, the copy will fail.
*
* If dest exists, it will be overwritten. Dest will have the same file
* permissions of source, if possible (subject to umask).
*
* This function copies the source file "safely". That is, in the event of an
* error, dest is unaltered (or, if it didn't exist, continues to not exist).
*
* @todo The std::experimental::fs namespace defines copy and copy_file. This
* function should be renamed accordingly.
*/
bool copy_file(const path &source, const path &dest, copy_options);
bool copy_file(const path& source, const path& dest);
}
}
#endif // PBL_CPP_FS_COPYFILE_H

@ -1,77 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "create_directory.h"
#include <sys/stat.h>
#include "perms.h"
#include "filestatus.h"
#ifdef _WIN32
#include <direct.h>
#define mkdir(x, y) mkdir(x)
#endif
namespace cpp17
{
namespace filesystem
{
bool
create_directory(const path& s, __attribute__((unused)) std::error_code& ec)
{
if(s.empty())
{
return false;
}
return ::mkdir(s.c_str(), static_cast< int >(perms::all)) == 0;
}
bool
create_directories(const path& s,
__attribute__((unused)) std::error_code& ec)
{
path p = s.parent_path();
if(!p.empty())
{
std::error_code ec, ec2;
if(!exists(p, ec) && !create_directories(p, ec2))
{
return false;
}
}
std::error_code ec3;
return create_directory(s, ec3);
}
} // namespace filesystem
} // namespace cpp17

@ -1,45 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_CREATE_DIRECTORY_H
#define PBL_CPP_FS_CREATE_DIRECTORY_H
#include "path.h"
#include <system_error>
namespace cpp17
{
namespace filesystem
{
bool create_directory(const path&, std::error_code&);
bool create_directories(const path&, std::error_code&);
}
}
#endif // PBL_CPP_FS_CREATE_DIRECTORY_H

@ -1,83 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "current_path.h"
#include <cerrno>
#include <unistd.h>
namespace cpp17
{
namespace filesystem
{
path
current_path()
{
char buf[4096];
if(::getcwd(buf, sizeof(buf)))
{
return buf;
}
// Dynamically allocate larger buffers until cwd fits
std::size_t size = 2 * sizeof(buf);
while(true)
{
char* q = new char[size];
if(::getcwd(q, size))
{
path p = q;
delete[] q;
return p;
}
else
{
if(errno == ERANGE)
{
delete[] q;
size *= 2;
}
else
{
delete[] q;
break;
}
}
}
return path();
}
} // namespace filesystem
} // namespace cpp17

@ -1,42 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_CURRENT_PATH_H
#define PBL_CPP_FS_CURRENT_PATH_H
#include "path.h"
namespace cpp17
{
namespace filesystem
{
path current_path();
}
}
#endif // PBL_CPP_FS_CURRENT_PATH_H

@ -1,137 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "direntry.h"
namespace cpp17
{
namespace filesystem
{
directory_entry::directory_entry()
{
}
directory_entry::directory_entry(const directory_entry& e)
: path_(e.path_)
{
}
directory_entry::directory_entry(const ::cpp17::filesystem::path& p)
: path_(p)
{
}
directory_entry& directory_entry::operator=(const directory_entry& e)
{
path_ = e.path_;
return *this;
}
void directory_entry::assign(const ::cpp17::filesystem::path& p)
{
path_ = p;
}
void directory_entry::replace_filename(const ::cpp17::filesystem::path& p)
{
path_ = path_.parent_path() / p;
}
const path& directory_entry::path() const
{
return path_;
}
directory_entry::operator const ::cpp17::filesystem::path&() const
{
return path_;
}
file_status directory_entry::status() const
{
return ::cpp17::filesystem::status(path_);
}
file_status directory_entry::symlink_status() const
{
return ::cpp17::filesystem::symlink_status(path_);
}
bool operator==(
const directory_entry& a,
const directory_entry& b
)
{
return a.path() == b.path();
}
bool operator!=(
const directory_entry& a,
const directory_entry& b
)
{
return a.path() != b.path();
}
bool operator<(
const directory_entry& a,
const directory_entry& b
)
{
return a.path() < b.path();
}
bool operator<=(
const directory_entry& a,
const directory_entry& b
)
{
return a.path() <= b.path();
}
bool operator>(
const directory_entry& a,
const directory_entry& b
)
{
return a.path() > b.path();
}
bool operator>=(
const directory_entry& a,
const directory_entry& b
)
{
return a.path() >= b.path();
}
}
}

@ -1,71 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_DIRENTRY_H
#define PBL_CPP_FS_DIRENTRY_H
#include <iosfwd>
#include "path.h"
#include "filestatus.h"
namespace cpp17
{
namespace filesystem
{
/** Reperesents a file system object
*/
class directory_entry
{
public:
directory_entry();
directory_entry(const directory_entry&);
explicit directory_entry(const path&);
directory_entry& operator=(const directory_entry&);
void assign(const path&);
void replace_filename(const path&);
const ::cpp17::filesystem::path& path() const;
operator const ::cpp17::filesystem::path&() const;
file_status status() const;
file_status symlink_status() const;
private:
::cpp17::filesystem::path path_;
};
bool operator==(const directory_entry&, const directory_entry&);
bool operator!=(const directory_entry&, const directory_entry&);
bool operator<(const directory_entry&, const directory_entry&);
bool operator<=(const directory_entry&, const directory_entry&);
bool operator>(const directory_entry&, const directory_entry&);
bool operator>=(const directory_entry&, const directory_entry&);
}
}
#endif // PBL_FS_DIRENTRY_H

@ -1,502 +0,0 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "diriter.h"
#include <cstdlib>
#include <cstring>
#include <climits>
#include <dirent.h>
#ifdef _WIN32
#include <io.h>
#endif
#include "direntry.h"
#include "path.h"
namespace cpp17
{
namespace filesystem
{
/// @todo Could save the malloc/free (of e) if we mark end-of-directory
class directory_iterator::impl
{
public:
impl() : p(), d(0), e(0), info(), valid_info(false)
{
// printf("directory_iterator::impl::cstr\n");
pos = 0;
}
explicit impl(const path& path_)
: p(path_), d(0), e(0), info(), valid_info(false)
{
// printf("directory_iterator::impl::cstr path[%s]\n", path_.c_str());
this->cPath = path_;
d = ::opendir(path_.c_str());
if(d)
{
e = acquire();
next();
}
}
~impl()
{
// printf("directory_iterator::impl::dstr [%s]\n", this->cPath.c_str());
if(d)
{
release(); // free e
::closedir(d);
d = 0;
}
}
void
rewind()
{
// printf("directory_iterator::impl::rewind\n");
if(d)
{
release();
::closedir(d);
}
d = ::opendir(this->cPath.c_str());
pos = 0;
if(d)
{
e = acquire();
next();
}
}
void
seek(size_t seekPos)
{
// printf("directory_iterator::impl::seek\n");
this->rewind();
for(size_t i = 0; i < seekPos; i++)
{
this->next();
}
}
/** Test if this is an end iterator
*/
bool
is_end() const
{
// printf("directory_iterator::impl::is_end\n");
return !e;
}
bool
next()
{
// printf("directory_iterator::impl::next\n");
if(d)
{
valid_info = false;
do
{
dirent* ptr = 0;
const int res = ::readdir_r(d, e, &ptr);
if(res != 0 || ptr == 0)
{
// error, or end of directory
pos = 0;
release();
return false;
}
} while(std::strcmp(e->d_name, ".") == 0
|| std::strcmp(e->d_name, "..") == 0);
pos++;
return true;
}
return false;
}
path
get_path() const
{
// printf("directory_iterator::impl::get_path\n");
return e ? (p / e->d_name) : path();
}
file_type
type() const
{
// printf("directory_iterator::impl::type\n");
if(e)
{
#ifdef DT_BLK
switch(e->d_type)
{
case DT_FIFO:
return file_type::fifo;
case DT_CHR:
return file_type::character;
case DT_DIR:
return file_type::directory;
case DT_BLK:
return file_type::block;
case DT_REG:
return file_type::regular;
case DT_LNK:
return file_type::symlink;
case DT_SOCK:
return file_type::socket;
default:
break;
} // switch
#endif
}
return file_type::unknown;
}
const directory_entry&
get_reference()
{
// printf("directory_iterator::impl::get_reference\n");
update();
return info;
}
const directory_entry*
get_pointer()
{
// printf("directory_iterator::impl::get_pointer\n");
update();
return &info;
}
/// Position
size_t pos;
// Path to directory
path p;
private:
void
update()
{
// printf("directory_iterator::impl::update\n");
if(!valid_info && e)
{
const path q = p / e->d_name;
info.assign(q);
valid_info = true;
}
}
static dirent*
acquire()
{
// printf("directory_iterator::impl::acquire\n");
/* dirent::d_name is required to be at least NAME_MAX + 1 bytes.
* However, some implementations use the struct hack and make d_name
* 1 byte. Watch for this scenario and adjust accordingly.
*/
if(sizeof(static_cast< dirent* >(0)->d_name) < NAME_MAX + 1)
{
return static_cast< dirent* >(
::malloc(sizeof(dirent) + NAME_MAX + 1));
}
else
{
return static_cast< dirent* >(::malloc(sizeof(dirent)));
}
}
void
release()
{
// printf("directory_iterator::impl::release\n");
::free(e);
e = 0;
}
// constructor path
path cPath;
/// Platform information
DIR* d;
/// Platform information
dirent* e;
directory_entry info;
bool valid_info; // info has been populated
};
directory_iterator::directory_iterator() : pimpl(new impl)
{
}
directory_iterator::directory_iterator(const path& path_)
: pimpl(new impl(path_))
{
}
// is this right
directory_iterator::directory_iterator(directory_iterator const& src)
: pimpl(new impl(src.pimpl->p.c_str()))
{
pimpl->seek(src.pimpl->pos);
}
directory_iterator::~directory_iterator()
{
delete pimpl;
}
directory_iterator::directory_iterator(directory_iterator const& src,
int pos)
{
// printf("directory_iterator::directory_iterator copy at pos - pimpl[%x]
// from[%s]\n", pimpl, src->path().c_str());
pimpl = new impl(src.pimpl->p.c_str());
pimpl->seek(pos);
}
bool
directory_iterator::operator==(const directory_iterator& i) const
{
// only equal if both are end iterators
return pimpl->is_end() && i.pimpl->is_end();
}
bool
directory_iterator::operator!=(const directory_iterator& i) const
{
return !(pimpl->is_end() && i.pimpl->is_end());
}
directory_iterator&
directory_iterator::operator++()
{
pimpl->next();
return *this;
}
const directory_entry& directory_iterator::operator*() const
{
return pimpl->get_reference();
}
const directory_entry* directory_iterator::operator->() const
{
return pimpl->get_pointer();
}
file_type
directory_iterator::type() const
{
return pimpl->type();
}
void
directory_iterator::swap(directory_iterator& d)
{
std::swap(pimpl, d.pimpl);
}
// FIXME: this isn't right
directory_iterator
directory_iterator::begin()
{
return directory_iterator(*this, 0);
/*
printf("directory_iterator::directory_iterator::begin - start\n");
size_t cur = pimpl->pos; // backup state
printf("directory_iterator::directory_iterator::begin - was at
[%zu][%s]\n", cur, this->pimpl->get_path().c_str()); pimpl->rewind();
directory_iterator *ret = new directory_iterator(*this); // copy ourself
pimpl->seek(cur); // restore state
printf("directory_iterator::directory_iterator::begin - end\n");
return *ret;
*/
}
directory_iterator
directory_iterator::end()
{
// return *(directory_iterator *)endPtr;
// printf("directory_iterator::directory_iterator::end - start\n");
size_t cur = pimpl->pos; // backup state
// printf("directory_iterator::directory_iterator::end - was at
// [%zu][%s]\n", cur, this->pimpl->get_path().c_str());
// spool to the end
size_t finalPos = pimpl->pos;
while(!pimpl->is_end())
{
if(pimpl->next())
{
finalPos = pimpl->pos;
}
}
// directory_iterator *ret = new directory_iterator(*this); // copy
// ourself printf("directory_iterator::directory_iterator::end - now at
// [%zu][%s]\n", pimpl->pos, this->pimpl->get_path().c_str());
pimpl->seek(cur); // restore state
return directory_iterator(*this, finalPos);
// printf("directory_iterator::directory_iterator::end - end\n");
// return *ret;
}
//
// recursive_directory_iterator
//
recursive_directory_iterator::recursive_directory_iterator()
{
}
recursive_directory_iterator::recursive_directory_iterator(const path& p)
{
descend(p);
}
recursive_directory_iterator::~recursive_directory_iterator()
{
while(!stack.empty())
{
ascend();
}
}
bool
recursive_directory_iterator::descend(const path& p)
{
directory_iterator it(p), end;
if(it != end)
{
directory_iterator* jt = new directory_iterator();
jt->swap(it);
stack.push(jt);
return true;
}
return false;
}
void
recursive_directory_iterator::ascend()
{
delete stack.top();
stack.pop();
}
const directory_entry& recursive_directory_iterator::operator*() const
{
return *(*stack.top());
}
const directory_entry* recursive_directory_iterator::operator->() const
{
return stack.top()->operator->();
}
recursive_directory_iterator&
recursive_directory_iterator::operator++()
{
if(stack.top()->type() == file_type::directory)
{
// go to directory's first child (if any)
if(descend((*stack.top())->path()))
{
return *this;
}
}
do
{
// move to sibling
stack.top()->operator++();
directory_iterator end;
if(*(stack.top()) != end)
{
return *this;
}
// move to parent
ascend();
} while(!stack.empty());
return *this;
}
bool
recursive_directory_iterator::operator==(
const recursive_directory_iterator& i) const
{
return stack.empty() && i.stack.empty();
}
bool
recursive_directory_iterator::operator!=(
const recursive_directory_iterator& i) const
{
return !(stack.empty() && i.stack.empty());
}
} // namespace filesystem
} // namespace cpp17

@ -1,151 +0,0 @@
/* Copyright (c) 2014, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_DIRITER_H
#define PBL_CPP_FS_DIRITER_H
#include <stack>
#include "direntry.h"
namespace cpp17
{
namespace filesystem
{
/** An iterator for traversing directory contents
*
* This class can be used for iterating over the contents of a directory. The
* parameterized constructor will make a "begin" iterator, and the default
* constructor will make an "end" iterator. One can dereference an iterator
* to get a directory_entry describing the file/subdirectory.
*
* @note The "." and ".." 'files' are ignored by this iterator, since they are
* not 'in' the directory.
*
* @note These objects are not copyable
*
* @note Only end iterators are ever considered equal. In particular, two
* directory_iterator-s constructed with the same argument may not point to the
* same file.
*/
class directory_iterator
{
public:
/** Construct an iterator for a directory
*
* After construction, the iterator will point to the first file in the
* directory.
*/
explicit directory_iterator(const path& path_);
/** Construct an end iterator
*/
directory_iterator();
/** Destructor
*/
~directory_iterator();
directory_iterator begin();
directory_iterator end();
/** Test if two iterators are equal
*
* Only two end iterators are equal
*/
bool operator==(const directory_iterator& i) const;
/** Test if two iterators are not equal
*
* Only two end iterators are equal
*/
bool operator!=(const directory_iterator& i) const;
/** Move to the next file/subdirectory
*/
directory_iterator& operator++();
/** Get information for the file system object
*
* @note Causes a stat. If all you need is the type of the file system object,
* use the cheaper type() member
*/
const directory_entry& operator*() const;
/** Get information for the file system object
*
* @note Causes a stat. If all you need is the type of the file system object,
* use the cheaper type() member
*/
const directory_entry* operator->() const;
file_type type() const;
void swap(directory_iterator&);
// non-copyable
// now it is
directory_iterator(const directory_iterator&);
directory_iterator& operator=(const directory_iterator&);
directory_iterator(const directory_iterator&, int pos);
//void *endPtr;
private:
class impl;
impl* pimpl;
};
class recursive_directory_iterator
{
public:
recursive_directory_iterator();
explicit recursive_directory_iterator(const path& p);
~recursive_directory_iterator();
recursive_directory_iterator& operator++();
const directory_entry& operator*() const;
const directory_entry* operator->() const;
bool operator==(const recursive_directory_iterator& i) const;
bool operator!=(const recursive_directory_iterator& i) const;
private:
// non-copyable
recursive_directory_iterator(const recursive_directory_iterator&);
recursive_directory_iterator& operator=(const recursive_directory_iterator&);
bool descend(const path& p);
void ascend();
std::stack< directory_iterator* > stack;
};
}
}
#endif // PBL_FS_DIRITER_H

@ -1,60 +0,0 @@
/* Copyright (c) 2018, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "equivalent.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
namespace cpp17
{
namespace filesystem
{
bool equivalent(
const path& p1,
const path& p2
)
{
struct stat s1;
if ( ::stat(p1.c_str(), &s1) == 0 )
{
struct stat s2;
if ( ::stat(p2.c_str(), &s2) == 0 )
{
return s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
}
}
return false;
}
}
}

@ -1,42 +0,0 @@
/* Copyright (c) 2018, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_EQUIVALENT_H
#define PBL_CPP_FS_EQUIVALENT_H
#include "path.h"
namespace cpp17
{
namespace filesystem
{
bool equivalent(const path&, const path&);
}
}
#endif // PBL_CPP_FS_EQUIVALENT_H

@ -1,303 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "filestatus.h"
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "path.h"
namespace
{
::cpp17::filesystem::file_status
from_mode_t(mode_t m)
{
::cpp17::filesystem::perms p =
static_cast< cpp17::filesystem::perms >(m & 0xFFF);
::cpp17::filesystem::file_type t = file_type::unknown;
if(S_ISREG(m))
{
t = file_type::regular;
}
else if(S_ISDIR(m))
{
t = file_type::directory;
}
else if(S_ISCHR(m))
{
t = file_type::character;
}
else if(S_ISBLK(m))
{
t = file_type::block;
}
else if(S_ISFIFO(m))
{
t = file_type::fifo;
}
#ifndef _WIN32 // these only work on cygnus or msys2!
else if(S_ISLNK(m))
{
t = file_type::symlink;
}
else if(S_ISSOCK(m))
{
t = file_type::socket;
}
#endif
return ::cpp17::filesystem::file_status(t, p);
}
} // namespace
namespace cpp17
{
namespace filesystem
{
file_status::file_status(const file_status& s) : t(s.t), p(s.p)
{
}
file_status::file_status(file_type t_, perms p_) : t(t_), p(p_)
{
}
file_status&
file_status::operator=(const file_status& s)
{
t = s.t;
p = s.p;
return *this;
}
file_type
file_status::type() const
{
return t;
}
void
file_status::type(file_type t_)
{
t = t_;
}
perms
file_status::permissions() const
{
return p;
}
void
file_status::permissions(perms p_)
{
p = p_;
}
std::ostream&
operator<<(std::ostream& os, const file_status& fs)
{
os << fs.type() << "; " << fs.permissions();
return os;
}
file_status
status(const path& path_)
{
if(!path_.empty())
{
struct stat st;
if(::stat(path_.c_str(), &st) == 0)
{
return from_mode_t(st.st_mode);
}
}
return file_status();
}
file_status
symlink_status(const path& path_)
{
if(!path_.empty())
{
struct stat st;
#ifndef _WIN32
if(::lstat(path_.c_str(), &st) == 0)
#else
if(::stat(path_.c_str(), &st) == 0)
#endif
{
return from_mode_t(st.st_mode);
}
}
return file_status();
}
bool
status_known(file_status s)
{
return s.type() != file_type::none;
}
bool
exists(file_status s)
{
return status_known(s) && s.type() != file_type::not_found;
}
bool
exists(const path& p, __attribute__((unused)) std::error_code& ec)
{
return exists(status(p));
}
bool
is_block_file(file_status s)
{
return s.type() == file_type::block;
}
bool
is_block_file(const path& p)
{
return is_block_file(status(p));
}
bool
is_character_file(file_status s)
{
return s.type() == file_type::character;
}
bool
is_character_file(const path& p)
{
return is_character_file(status(p));
}
bool
is_fifo(file_status s)
{
return s.type() == file_type::fifo;
}
bool
is_fifo(const path& p)
{
return is_fifo(status(p));
}
bool
is_other(file_status s)
{
return exists(s) && !is_regular_file(s) && !is_directory(s)
&& !is_symlink(s);
}
bool
is_other(const path& p)
{
return is_other(status(p));
}
bool
is_regular_file(file_status s)
{
return s.type() == file_type::regular;
}
bool
is_regular_file(const path& p)
{
return is_regular_file(status(p));
}
bool
is_socket(file_status s)
{
return s.type() == file_type::socket;
}
bool
is_socket(const path& p)
{
return is_socket(status(p));
}
bool
is_symlink(file_status s)
{
return s.type() == file_type::symlink;
}
bool
is_symlink(const path& p)
{
return is_symlink(status(p));
}
bool
is_directory(file_status s)
{
return s.type() == file_type::directory;
}
bool
is_directory(const path& p)
{
return is_directory(status(p));
}
std::size_t
file_size(const path& p)
{
if(!p.empty())
{
struct stat st;
if(::stat(p.c_str(), &st) == 0)
{
return st.st_size;
}
}
return std::size_t(-1);
}
} // namespace filesystem
} // namespace cpp17

@ -1,92 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_FILESTATUS_H
#define PBL_CPP_FS_FILESTATUS_H
#include <iosfwd>
#include <system_error>
#include "filetype.h"
#include "perms.h"
namespace cpp17
{
namespace filesystem
{
class path;
/** Information about a file's type and permissions
*
* Due to the nature of the file system, the information may not be exactly
* current.
*/
class file_status
{
public:
file_status(const file_status&);
explicit file_status(file_type = file_type::none, perms = perms::unknown);
file_status& operator=(const file_status&);
file_type type() const;
void type(file_type);
perms permissions() const;
void permissions(perms);
private:
file_type t;
perms p;
};
file_status status(const path&);
file_status symlink_status(const path&);
bool status_known(file_status);
bool exists(file_status);
bool exists(const path&, std::error_code&);
bool is_block_file(file_status);
bool is_block_file(const path&);
bool is_character_file(file_status);
bool is_character_file(const path&);
bool is_fifo(file_status);
bool is_fifo(const path&);
bool is_other(file_status);
bool is_other(const path&);
bool is_regular_file(file_status);
bool is_regular_file(const path&);
bool is_socket(file_status);
bool is_socket(const path&);
bool is_symlink(file_status);
bool is_symlink(const path&);
bool is_directory(file_status);
bool is_directory(const path&);
std::size_t file_size(const path&);
std::ostream& operator<<(std::ostream&, const file_status&);
}
}
#endif // PBL_CPP_FS_FILESTATUS_H

@ -1,59 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "filetype.h"
#include <iostream>
static const char* const friendly[] =
{
"Not found", "None", "Regular File", "Directory", "Symbolic Link",
"Block Device", "Character Device", "FIFO", "Socket"
};
namespace file_type
{
std::ostream& operator<<(
std::ostream& os,
file_type t
)
{
if ( -1 <= t && t < 8 )
{
os << friendly[t + 1];
}
else
{
os << "Unknown";
}
return os;
}
}

@ -1,54 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_FILETYPE_H
#define PBL_CPP_FS_FILETYPE_H
#include <iosfwd>
namespace file_type
{
enum file_type
{
not_found = -1, none = 0, regular, directory, symlink, block, character, fifo,
socket, unknown
};
std::ostream& operator<<(std::ostream&, file_type);
}
namespace cpp17
{
namespace filesystem
{
/** Types of file system objects
*/
typedef ::file_type::file_type file_type;
}
}
#endif // PBL_CPP_FS_FILETYPE_H

@ -1,698 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "path.h"
#include <algorithm>
namespace cpp17
{
namespace filesystem
{
path::path()
{
}
path::path(const string_type& s_) : s(s_)
{
}
path::path(const char* s_) : s(s_)
{
}
path::path(const path& p) : s(p.s)
{
}
path&
path::operator=(const path& p)
{
s = p.s;
return *this;
}
void
path::clear()
{
s.clear();
}
void
path::swap(path& p)
{
std::swap(p.s, s);
}
std::string
path::string() const
{
return s;
}
const char*
path::c_str() const
{
return s.c_str();
}
bool
path::empty() const
{
return s.empty();
}
path
path::extension() const
{
const std::size_t i = s.find_last_of(preferred_separator);
const std::size_t j = (i == std::string::npos ? 0 : i + 1);
if(j < s.length())
{
if(s.compare(j, std::string::npos, ".", 1) != 0
&& s.compare(j, std::string::npos, "..", 2) != 0)
{
const std::size_t k = s.find_last_of('.');
if(k != std::string::npos && j <= k)
{
return s.substr(k);
}
}
}
return path();
}
path
path::filename() const
{
const std::size_t i = s.find_last_of(preferred_separator);
if(i == std::string::npos)
{
return *this;
}
if(i + 1 < s.length())
{
return path(s.substr(i + 1));
}
else
{
return ".";
}
}
path
path::parent_path() const
{
const std::size_t i = s.find_last_of(preferred_separator);
if(i == std::string::npos)
{
return path();
}
return path(s.substr(0, i));
}
path&
path::remove_filename()
{
const std::size_t i = s.find_last_of(preferred_separator);
if(i != std::string::npos)
{
s.resize(i);
}
return *this;
}
path&
path::replace_filename(const path& p)
{
const std::size_t i = s.find_last_of(preferred_separator);
if(i != std::string::npos)
{
s.resize(i);
append(p);
}
else
{
assign(p);
}
return *this;
}
path::operator string_type() const
{
return s;
}
path&
path::append(const path& p)
{
bool sep = true;
if(!s.empty() && s[s.length() - 1] == preferred_separator)
{
sep = false;
}
else if(s.empty())
{
sep = false;
}
else if(p.empty() || p.s[0] == preferred_separator)
{
sep = false;
}
if(sep)
{
s += preferred_separator;
}
s.append(p.native());
return *this;
}
path&
path::operator/=(const path& p)
{
return append(p);
}
const std::string&
path::native() const
{
return s;
}
path
path::lexically_relative(const path& p) const
{
const_iterator first1 = begin(), last1 = end();
const_iterator first2 = p.begin(), last2 = p.end();
const_iterator it = first1;
const_iterator jt = first2;
while(it != last1 && jt != last2 && *it == *jt)
{
++it, ++jt;
}
if(it == first1 || jt == first2)
{
return path();
}
if(it == last1 && jt == last2)
{
return path(".");
}
path r;
for(; jt != last2; ++jt)
{
r /= "..";
}
for(; it != last1; ++it)
{
r /= *it;
}
return r;
}
bool
path::is_absolute() const
{
return !s.empty() && s[0] == preferred_separator;
}
path
path::lexically_normal() const
{
std::string t;
if(s.empty())
{
// error
return t;
}
const std::size_t n = s.length();
for(std::size_t i = 0; i < n;)
{
if(s[i] == '/')
{
// directory separator
t.push_back('/');
i = s.find_first_not_of('/', i);
}
else
{
// path component
const std::size_t j = std::min(s.find('/', i), n);
if(s.compare(i, j - i, ".", 1) == 0)
{
// handle dot
if(j < n)
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
else if(s.compare(i, j - i, "..", 2) == 0)
{
// handle dot-dot
const std::size_t l = t.length();
if(l == 0)
{
// no previous component (ex., "../src")
t.assign("..", 2);
i = j;
}
else
{
// remove previously copied component (unless root)
if(l >= 2)
{
const std::size_t k = t.find_last_of('/', l - 2);
if(k == std::string::npos)
{
t.clear();
}
else
{
t.resize(k + 1);
}
}
if(j < n)
{
i = s.find_first_not_of('/', j);
}
else
{
i = n;
}
}
}
else
{
// append path component
t.append(s, i, j - i);
i = j;
}
}
}
if(t.empty())
{
return ".";
}
// drop trailing slashes
const std::size_t i = t.find_last_not_of('/');
if(i != std::string::npos)
{
t.resize(i + 1);
}
return t;
}
int
path::compare(const path& p) const
{
const_iterator first1 = begin(), last1 = end();
const_iterator first2 = p.begin(), last2 = p.end();
while(first1 != last1 && first2 != last2)
{
if(first1->native() < first2->native())
{
return -1;
}
if(first2->native() < first1->native())
{
return 1;
}
++first1;
++first2;
}
if(first1 != last1)
{
return 1;
}
if(first2 != last2)
{
return -1;
}
return 0;
}
path::const_iterator
path::begin() const
{
begin_iterator_tag tag;
return const_iterator(this, tag);
}
path::const_iterator
path::end() const
{
end_iterator_tag tag;
return const_iterator(this, tag);
}
path::const_iterator::const_iterator()
: parent(0), first(std::string::npos), last(std::string::npos), value()
{
}
path::const_iterator::const_iterator(const path* parent_,
begin_iterator_tag)
: parent(parent_), first(0)
{
if(parent->s.empty())
{
first = std::string::npos;
last = std::string::npos;
}
else
{
const std::size_t k = parent->s.find_first_of(preferred_separator);
if(k == std::string::npos)
{
last = parent->s.length();
}
else if(k == 0)
{
last = 1;
}
else
{
last = k;
}
value = parent->s.substr(0, last);
}
}
path::const_iterator::const_iterator(const path* p, end_iterator_tag)
: parent(p), first(std::string::npos), last(std::string::npos), value()
{
}
path::const_iterator&
path::const_iterator::operator++()
{
if(parent)
{
if(last < parent->s.length())
{
// find next component
const std::size_t j =
parent->s.find_first_not_of(preferred_separator, last);
if(j == std::string::npos)
{
if(parent->s[first] == preferred_separator)
{
// path to root
first = std::string::npos;
last = std::string::npos;
value.clear();
}
else
{
// ends with directory
first = parent->s.length();
last = std::string::npos;
value = ".";
}
}
else
{
first = j;
// next path component
const std::size_t k =
parent->s.find_first_of(preferred_separator, j);
if(k == std::string::npos)
{
last = parent->s.length();
}
else
{
last = k;
}
value = parent->s.substr(first, last - first);
}
}
else
{
// go to end iterator
first = std::string::npos;
last = std::string::npos;
value.clear();
}
}
return *this;
}
path::const_iterator
path::const_iterator::operator++(int)
{
const_iterator t = *this;
operator++();
return t;
}
path::const_iterator&
path::const_iterator::operator--()
{
if(parent && first != 0)
{
if(first == std::string::npos)
{
// end iterator
if(!parent->s.empty())
{
const std::size_t j = parent->s.find_last_of(preferred_separator);
if(j == std::string::npos)
{
// single path component
first = 0;
last = parent->s.length();
value = parent->s;
}
else
{
if(j + 1 < parent->s.length())
{
// trailing filename
first = j + 1;
last = parent->s.length();
value = parent->s.substr(first, last - first);
}
else
{
// trailing directory, or root
const std::size_t k =
parent->s.find_last_not_of(preferred_separator, j);
if(k == std::string::npos)
{
first = 0;
last = 1;
value = parent->s.substr(first, last - first);
}
else
{
first = parent->s.length();
last = std::string::npos;
value = ".";
}
}
}
}
}
else
{
// on an actual path component, or the fake "."
const std::size_t j =
parent->s.find_last_not_of(preferred_separator, first - 1);
if(j == std::string::npos)
{
// beginning of absolute path
first = 0;
last = 1;
}
else
{
last = j + 1;
const std::size_t k =
parent->s.find_last_of(preferred_separator, j);
if(k == std::string::npos)
{
first = 0;
}
else
{
first = k + 1;
}
}
value = parent->s.substr(first, last - first);
}
}
return *this;
}
path::const_iterator
path::const_iterator::operator--(int)
{
const_iterator t = *this;
operator--();
return t;
}
bool
path::const_iterator::operator==(const const_iterator& o) const
{
return parent == o.parent && first == o.first;
}
bool
path::const_iterator::operator!=(const const_iterator& o) const
{
return parent != o.parent || first != o.first;
}
const path& path::const_iterator::operator*() const
{
return value;
}
const path* path::const_iterator::operator->() const
{
return &value;
}
path
operator/(const path& lhs, const path& rhs)
{
path res = lhs;
res.append(rhs);
return res;
}
std::ostream&
operator<<(std::ostream& os, const path& p)
{
return os << p.string();
}
bool
operator==(const path& l, const path& r)
{
return l.compare(r) == 0;
}
bool
operator!=(const path& l, const path& r)
{
return l.compare(r) != 0;
}
bool
operator<(const path& l, const path& r)
{
return l.compare(r) < 0;
}
bool
operator<=(const path& l, const path& r)
{
return l.compare(r) <= 0;
}
bool
operator>(const path& l, const path& r)
{
return l.compare(r) > 0;
}
bool
operator>=(const path& l, const path& r)
{
return l.compare(r) >= 0;
}
} // namespace filesystem
} // namespace cpp17

@ -1,192 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_PATH_H
#define PBL_CPP_FS_PATH_H
#include <string>
#include <iosfwd>
#include <iterator>
#include <iostream>
namespace cpp17
{
namespace filesystem
{
/** A file path
*
* A partial implementation of std::experimental::filesystem::path
* @todo Construct from the other basic_string types and pointer-to-char16_t, etc.
* @bug Throughout, preferred_separator is used incorrectly
*/
class path
{
public:
typedef char value_type;
typedef std::basic_string< value_type > string_type;
static const value_type preferred_separator = '/';
class const_iterator;
typedef const_iterator iterator;
/// An empty path
path();
/// Construct a path form the given string
path(const string_type&);
path(const char*);
template< typename Iterator >
path(Iterator first, Iterator last) : s(first, last)
{
}
/// Copy constructor
path(const path&);
/// Copy assignment
path& operator=(const path&);
template< typename Source >
path& operator=(const Source& source)
{
return assign(source);
}
template< typename Source >
path& assign(const Source& source)
{
s = string_type(source);
return *this;
}
template< typename Iterator >
path& assign(
Iterator first,
Iterator last
)
{
s = string_type(first, last);
return *this;
}
/// Clear the path
void clear();
/// Swap the two paths
void swap(path&);
std::string string() const;
const char* c_str() const;
path& operator/=(const path&);
path& append(const path&);
/// Is the path empty (i.e., "")
bool empty() const;
const std::string& native() const;
path extension() const;
path filename() const;
path parent_path() const;
path& remove_filename();
path& replace_filename(const path&);
operator string_type() const;
bool is_absolute() const;
path lexically_normal() const;
path lexically_relative(const path&) const;
int compare(const path&) const;
const_iterator begin() const;
const_iterator end() const;
private:
struct begin_iterator_tag {};
struct end_iterator_tag {};
std::string s;
};
class path::const_iterator
{
public:
typedef const path value_type;
typedef const path& reference;
typedef const path* pointer;
typedef std::ptrdiff_t difference_type;
const_iterator();
const_iterator(const path*, begin_iterator_tag);
const_iterator(const path*, end_iterator_tag);
const_iterator& operator++();
const_iterator operator++(int);
const_iterator& operator--();
const_iterator operator--(int);
bool operator==(const const_iterator&) const;
bool operator!=(const const_iterator&) const;
const path& operator*() const;
const path* operator->() const;
private:
const path* parent;
std::size_t first;
std::size_t last;
path value;
};
path operator/(const path& lhs, const path& rhs);
std::ostream& operator<<(std::ostream&, const path&);
bool operator==(const path&, const path&);
bool operator!=(const path&, const path&);
bool operator<(const path&, const path&);
bool operator<=(const path&, const path&);
bool operator>(const path&, const path&);
bool operator>=(const path&, const path&);
}
}
namespace std
{
template< >
struct iterator_traits< ::cpp17::filesystem::path::const_iterator >
{
typedef std::ptrdiff_t difference_type;
typedef const ::cpp17::filesystem::path value_type;
typedef const ::cpp17::filesystem::path* pointer;
typedef const ::cpp17::filesystem::path& reference;
typedef std::bidirectional_iterator_tag iterator_category;
};
}
#endif // PBL_FS_PATH_H

@ -1,48 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "perms.h"
#include <iostream>
#include <iomanip>
namespace perms
{
std::ostream& operator<<(
std::ostream& os,
perms p
)
{
std::ostream t( os.rdbuf() );
t << "mode: " << std::oct << static_cast< int >( p );
return os;
}
}

@ -1,101 +0,0 @@
/* Copyright (c) 2015, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_PERMS_H
#define PBL_CPP_FS_PERMS_H
#include <iosfwd>
namespace perms
{
/** File permissions
*
* See: std::experimental::filesystem::perms
*/
enum perms
{
none = 0,
owner_read = 0400, // S_IRUSR
owner_write = 0200, // S_IWUSR
owner_exec = 0100, // S_IXUSR
owner_all = 0700, // S_IRWXU
group_read = 040, // S_IRGRP
group_write = 020, // S_IWGRP
group_exec = 010, // S_IXGRP
group_all = 070, // S_IRWXG
others_read = 04, // S_IROTH
others_write = 02, // S_IWOTH
others_exec = 01, // S_IXOTH
others_all = 07, // S_IRWXO
all = 0777,
set_uid = 04000,
set_gid = 02000,
sticky_bit = 01000,
mask = 07777,
unknown = 0xffff,
add_perms = 0x10000,
remove_perms = 0x20000,
resolve_symlinks = 0x40000
};
inline perms operator|(
perms a,
perms b
)
{
return static_cast< perms >( static_cast< int >( a ) | static_cast< int >( b ) );
}
inline perms operator&(
perms a,
perms b
)
{
return static_cast< perms >( static_cast< int >( a ) & static_cast< int >( b ) );
}
inline perms operator^(
perms a,
perms b
)
{
return static_cast< perms >( static_cast< int >( a ) ^ static_cast< int >( b ) );
}
std::ostream& operator<<(std::ostream&, perms);
}
namespace cpp17
{
namespace filesystem
{
typedef ::perms::perms perms;
}
}
#endif // PBL_CPP_FS_PERMS_H

@ -1,62 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "remove.h"
#include <cstdio>
#include "diriter.h"
namespace cpp17
{
namespace filesystem
{
bool remove(const path& p)
{
return ::remove( p.c_str() ) == 0;
}
unsigned long remove_all(const path& p)
{
unsigned long total = 0;
for ( directory_iterator it(p), last; it != last; ++it )
{
total += remove_all( it->path() );
}
if ( remove(p) )
{
++total;
}
return total;
}
}
}

@ -1,43 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_REMOVE_H
#define PBL_CPP_FS_REMOVE_H
#include "path.h"
namespace cpp17
{
namespace filesystem
{
bool remove(const path&);
unsigned long remove_all(const path&);
}
}
#endif // PBL_CPP_FS_REMOVE_H

@ -1,51 +0,0 @@
/* Copyright (c) 2018, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "rename.h"
#include <cstdio>
#include "copyfile.h"
#include "remove.h"
namespace cpp17
{
namespace filesystem
{
/// @bug This is just a quick and dirty implementation
void rename(const path& from, const path& to)
{
if (std::rename(from.c_str(), to.c_str()) != 0)
{
if (copy_file(from, to))
cpp17::filesystem::remove(from);
}
}
}
}

@ -1,42 +0,0 @@
/* Copyright (c) 2018, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_RENAME_H
#define PBL_CPP_FS_RENAME_H
#include "path.h"
namespace cpp17
{
namespace filesystem
{
void rename(const path& from, const path& to);
}
}
#endif // PBL_CPP_FS_RENAME_H

@ -1,70 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tempdir.h"
#include <cstdlib>
namespace cpp17
{
namespace filesystem
{
/* TMPDIR is the POSIX variable for the temporary directory. Other variables
* are sometimes used, however, in non-conforming environments. Those are
* checked as fallback (following Boost's implementation)
*/
path temp_directory_path()
{
const char* p = std::getenv("TMPDIR");
if ( !p )
{
p = std::getenv("TMP");
if ( !p )
{
p = std::getenv("TEMP");
if ( !p )
{
p = std::getenv("TEMPDIR");
if ( !p )
{
p = "/tmp";
}
}
}
}
return path(p);
}
}
}

@ -1,42 +0,0 @@
/* Copyright (c) 2016, Pollard Banknote Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PBL_CPP_FS_TEMPDIR_H
#define PBL_CPP_FS_TEMPDIR_H
#include "path.h"
namespace cpp17
{
namespace filesystem
{
path temp_directory_path();
}
}
#endif // PBL_CPP_FS_TEMPDIR_H

@ -1,422 +0,0 @@
# This Makefile is intended to be included by another Makefile. It contains a
# number of common functions, variables, recipes. Ideally the calling Makefile
# will only need to define targets for that project.
#
# Features:
# - Shadow building
# - Auto dependency generation
# - debug target uses address sanitizer when available (GCC >= 4.8.0),
# and undefined behavior sanitizer (GCC >=4.9.0)
# - coloured error messages when available (GCC >=4.9.0)
# - pre-configured targets for cleaning .o files, insure leftovers
# - targets for callgrind, memcheck, insure, profiling and code coverage
#
# Organization
# - Supporting functions
# - Definitions of the variables used by this makefile (ex., CXX, WARNINGS)
# - Predefined configurations of variables (ex., DEBUG)
# - File type targets (ex., .o)
# - Named targets (ex., profile)
# - Inclusion of auto-dependencies
#
# TODO Profile guided optimization
# TODO Precompiled headers
# TODO Static analysis
# TODO Clang support
# TODO -fsanitize=integer for clang
# TODO -fsanitize=thread
# TODO ubsan prints messages to the stderr; does not terminate
# TODO dynamic/static libs
# TODO _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC
# TODO split up makefile into common functions, variables, configurations, recipes
# TODO -B option for TOOLCHAIN
# TODO CONFIG=RELEASE (strip, for example)
# TODO Different debug levels
# TODO CONFIG=HARDENED including some of the following options
# TODO -fstack-protector-strong?
# TODO -Wformat-security
# TODO -pie -fPIE
# TODO full relro -Wl,-z,relro,-z,now
# TODO -pipe
# TODO -flto
# Shadow building ==============================================================
# This gets the directory of the calling Makefile (and, presumably, where the
# source code resides
# Functions ====================================================================
gccversion = $(shell $(CXX) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
gcc48 = $(shell expr $(gccversion) \>= 40800)
gcc49 = $(shell expr $(gccversion) \>= 40900)
gcc51 = $(shell expr $(gccversion) \>= 50100)
# Convert a word to lowercase
lower = $(shell echo $(1) | tr '[:upper:]' '[:lower:]')
# Convert a word to uppercase
upper = $(shell echo $(1) | tr '[:lower:]' '[:upper:]')
# Variables ====================================================================
#
# The basic variables that this makefile uses
# Toolchain --------------------------------------------------------------------
# Which programs to use during compilation
# Path to a different toolchain (ex., ~/bin/gcc-4.9.0)
TOOLCHAIN =
ifndef TOOLCHAIN
# C++ compiler
CXX = g++
# Archive (.a) program
AR = ar
# Linker
LD = $(CXX)
PROFILER = gprof
else
# Use a particular set of tools
CXX = $(TOOLCHAIN)/bin/g++ -B$(TOOLCHAIN)/bin/
AR = $(TOOLCHAIN)/bin/ar
LD = $(CXX)
PROFILER = $(TOOLCHAIN)/bin/gprof
endif
# Misc
VALGRIND = valgrind
# Compiler flags ---------------------------------------------------------------
# Arguments to the toolchain programs
# Which version of C++ to compile for
STANDARD = -ansi -pedantic
# Optimization flags
OPTIMIZATION = -O2
# Architecture flags
TARGET_ARCH =
# Warnings
WARNINGS = -Wall -Wsign-compare -Wconversion -Wpointer-arith \
-Winit-self -Wcast-qual -Wredundant-decls -Wcast-align -Wwrite-strings \
-Wno-long-long -Woverloaded-virtual -Wformat -Wno-unknown-pragmas \
-Wnon-virtual-dtor -Wno-c++0x-compat
# -Wold-style-cast
ifeq "$(gcc51)" "1"
#WARNINGS += -Wsuggest-attribute=const -Wsuggest-attribute=pure
endif
# Level of debugging information to provide
DEBUGGING = -g
# Machine independent options
#-fno-nonansi-builtins
OPTIONS = -fuse-cxa-atexit -ffor-scope
ifeq "$(gcc49)" "1"
OPTIONS += -fdiagnostics-color
endif
# Flags to use when compiling C++ source into object files
CXXFLAGS = $(STANDARD) $(DEBUGGING) $(OPTIMIZATION) $(WARNINGS) $(OPTIONS) $(TARGET_ARCH)
# Directories to search for includes
INCLUDE =
# Any macros that can be defined on the command line
DEFINES = -D_FORTIFY_SOURCE=1
# Preprocessor flags
CPPFLAGS = $(INCLUDE) $(DEFINES)
# How to build an archive
ARFLAGS = crs
# Linker flags
LDFLAGS =
LDLIBS =
ifdef TOOLCHAIN
# Statically link the GCC and
LDFLAGS += -static-libgcc -static-libstdc++
# Dynamic linking
#LDFLAGS += -Wl,-rpath -Wl,$(TOOLCHAIN)/lib
#LDLIBS = -L$(TOOLCHAIN)/lib
endif
# Printing =====================================================================
# If this is not empty, print messages
VERBOSE =
# Predefined configurations ====================================================
# Combinations of the OPTIMIZATION, etc.
ifdef CONFIG
UCONFIG := $(call upper,$(CONFIG))
# Fast -------------------------------------------------------------------------
# A faster build, primarily for testing
ifeq "$(UCONFIG)" "FAST"
OPTIMIZATION = -O0
endif
# Tune -------------------------------------------------------------------------
# Heavily optimized for a fast application
ifeq "$(UCONFIG)" "TUNE"
ifeq "$(gcc48)" "1"
TARGET_ARCH = -march=native
endif
OPTIMIZATION = -O3 -mtune=native
endif
# Debug ------------------------------------------------------------------------
# Programmer is tracking a bug
ifeq "$(UCONFIG)" "DEBUG"
# Set additional warnings and flags
WARNINGS += -Wshadow -Wfloat-equal
ifeq "$(gcc51)" "1"
WARNINGS += -Wstrict-overflow=5
endif
DEBUGGING = -ggdb3 -fno-omit-frame-pointer -fno-default-inline -fno-inline -fno-merge-constants -ffloat-store
# -fno-elide-constructors
# Set the optimization level
ifeq "$(gcc48)" "1"
OPTIMIZATION = -Og
else
OPTIMIZATION = -O0
endif
# Turn on address sanitizer
ifeq "$(gcc48)" "1"
DEBUGGING += -fsanitize=address
LDFLAGS += -fsanitize=address -static-libasan
endif
# Turn on undefined behavior sanitizer and leak sanitizer
ifeq "$(gcc49)" "1"
DEBUGGING += -fsanitize=undefined -fsanitize=leak
LDFLAGS += -fsanitize=undefined -fsanitize=leak -static-libubsan -static-liblsan
endif
endif
# Profile ----------------------------------------------------------------------
# Programmer wants profile information
ifeq "$(UCONFIG)" "PROFILE"
OPTIMIZATION = -O2 -pg
LDFLAGS += -pg
endif
# Coverage ---------------------------------------------------------------------
# Programmer wants code coverage information
ifeq "$(UCONFIG)" "COVERAGE"
DEBUGGING += --coverage -fno-elide-constructors
LDFLAGS += --coverage
OPTIMIZATION = -O0
endif
# Insure -----------------------------------------------------------------------
# Programmer wants to run insure
ifeq "$(UCONFIG)" "INSURE"
CXX = insure
LDLIBS += -lstdc++
OPTIMIZATION = -O0
endif
endif
# Targets ======================================================================
.PHONY: no_default_goal depend clean_insure clean_objects clean_profile clean_depend distclean coverage profile memcheck callgrind cachegrind help help_common examples
no_default_goal:
$(error "The including Makefile hasn't specified a default goal. It should.")
# Dependency generation --------------------------------------------------------
DEPDIR := .deps
# Build object files with automatic dependency generation
# TODO maybe use LINK.cpp from 'make -p'
%.o: %.cpp
@mkdir -p $(@D)/$(DEPDIR)
ifeq ($(VERBOSE),)
@echo [CXX] $@
@$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).d -o $@ $<
else
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).d -o $@ $<
endif
%.a:
ifeq ($(VERBOSE),)
@echo [AR] $@
@$(AR) $(ARFLAGS) $@ $^ > /dev/null
else
$(AR) $(ARFLAGS) $@ $^ > /dev/null
endif
# A script for combining .a's. Dependency list for the mri should be
# subdirectories containing static libs. Name of the output library
# is inferred from the mri name (abc.mri produces libabc.a)
%.mri:
@echo 'CREATE $(patsubst %.mri,lib%.a,$@)' > $@
@for dir in $^; do echo ADDLIB $$dir >> $@; done
@echo 'SAVE' >> $@
# TODO dynamic libs
# %.so: CXXFLAGS += -fPIC
# %.so: LDFLAGS := -shared
# %.so:
# $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
# optionally add -Wl,-soname,$(SONAME)
# TODO java classes
# %.class: %.java
# $(JC) -cp . $<
# Code coverage ----------------------------------------------------------------
coverage:
ifdef COVERAGE_OUT
@TMPFILE=`mktemp`; lcov --capture --directory . --output-file $$TMPFILE; genhtml $$TMPFILE --output-directory $(COVERAGE_OUT); $(RM) $$TMPFILE
else
$(error You have not set COVERAGE_OUT)
endif
# Profiling --------------------------------------------------------------------
profile:
ifdef PROFILE_TARGET
$(PROFILE_TARGET) $(PROFILE_TARGET_ARGS)
ifdef PROFILE_OUT
@$(PROFILER) -c $(PROFILE_TARGET) > $(PROFILE_OUT)
else
$(error You have not specified PROFILE_OUT)
endif
else
$(error You have not specified PROFILE_TARGET)
endif
# Memcheck ---------------------------------------------------------------------
# User should set MEMCHECK_TARGET, MEMCHECK_TARGET_ARGS, and a recipe like:
# memcheck: $(MEMCHECK_TARGET)
memcheck:
$(VALGRIND) --tool=memcheck -v --read-var-info=yes --track-origins=yes --show-reachable=yes --leak-check=full --read-inline-info=yes --keep-stacktraces=alloc-and-free $(VALGRIND_TARGET) $(VALGRIND_TARGET_ARGS) 2> $(MEMCHECK_OUT)
# Callgrind --------------------------------------------------------------------
# User should set CALLGRIND_TARGET, CALLGRIND_TARGET_ARGS, and a recipe like:
# callgrind: $(CALLGRIND_TARGET)
callgrind:
$(VALGRIND) --tool=callgrind $(VALGRIND_TARGET) $(VALGRIND_TARGET_ARGS)
cachegrind:
$(VALGRIND) --tool=cachegrind --branch-sim=yes $(VALGRIND_TARGET) $(VALGRIND_TARGET_ARGS)
# Clean targets ----------------------------------------------------------------
# remove all .o files
clean_objects:
ifeq ($(VERBOSE),)
@find -name '*.o' -exec $(RM) '{}' \;
else
find -name '*.o' -exec $(RM) '{}' \;
endif
# remove all files left by insure
clean_insure:
ifeq ($(VERBOSE),)
@find -name '*.tcl' -exec $(RM) '{}' \;
@$(RM) tca.map tca.log
else
find -name '*.tcl' -exec $(RM) '{}' \;
$(RM) tca.map tca.log
endif
# remove all files left by gprof
clean_profile:
ifeq ($(VERBOSE),)
@$(RM) profile
@find \( -name '*.gcda' -o -name '*.gcno' \) -exec $(RM) '{}' \;
else
$(RM) profile
find \( -name '*.gcda' -o -name '*.gcno' \) -exec $(RM) '{}' \;
endif
clean_depend:
ifeq ($(VERBOSE),)
@find -depth -name $(DEPDIR) -type d -exec $(RM) -r '{}' \;
else
find -depth -name $(DEPDIR) -type d -exec $(RM) -r '{}' \;
endif
depend: clean clean_depend
distclean: depend
# Documentation ----------------------------------------------------------------
help_common:
@echo "==================================================================="
@echo "Here are some standard Makefile variables and their defaults:"
@echo " CXX ($(CXX))"
@echo " CPPFLAGS ($(CPPFLAGS))"
@echo " LDFLAGS ($(LDFLAGS))"
@echo " LDLIBS ($(LDLIBS))"
@echo " AR ($(AR))"
@echo " ARFLAGS ($(ARFLAGS))"
@echo
@echo "You can set the TOOLCHAIN variable to use a different compiler,"
@echo "linker, profiler. Ex., (~/bin/gcc-4.9.0)"
@echo
@echo "The CXXFLAGS variable is comprised of a number of other variables:"
@echo " STANDARD ($(STANDARD))"
@echo " DEBUGGING ($(DEBUGGING))"
@echo " OPTIMIZATION ($(OPTIMIZATION))"
@echo " WARNINGS ($(WARNINGS))"
@echo " TARGET_ARCH ($(TARGET_ARCH))"
@echo
@echo "For convenience, several preconfigured options are available by"
@echo "setting the CONFIG variale:"
@echo " DEBUG - Turns on debugging info; turns down optimization; enables"
@echo " address sanitizer, etc. if available"
@echo " PROFILE - Keeps optimization for release build; adds debugging"
@echo " and gprof flags"
@echo " COVERAGE - Don't inline functions"
@echo " INSURE - Build the target with the insure compiler"
@echo " TUNE - High optimization level; CPU-specific instructions"
@echo " FAST - A fast compilation with low optimization level"
@echo
@echo "==================================================================="
@echo "Here are some special targets and variables that affect them"
@echo
@echo " profile - First build a target with CONFIG=PROFILE and run it."
@echo " PROFILE_TARGET the name of the program to profile"
@echo " (default: $(PROFILE_TARGET))"
@echo " PROFILE_TARGET_ARGS arguments to the program to profile"
@echo " (default: $(PROFILE_TARGET_ARGS))"
@echo " PROFILE_OUT the file to place the profile data in"
@echo " (default: $(PROFILE_OUT))"
@echo " PROFILER Path to profiler"
@echo " (default: $(PROFILER))"
@echo " coverage - First build a target with CONFIG=COVERAGE and run it."
@echo " COVERAGE_OUT specifies where to put the resulting web pages"
@echo " (default: $(COVERAGE_OUT))"
@echo
@echo " memcheck - Run memcheck for VALGRIND_TARGET, testing memory access"
@echo " callgrind - Run callgrind for VALGRIND_TARGET, testing performance"
@echo " cachegrind - Run cachegrind for VALGRIND_TARGET, testing cache"
@echo " VALGRIND_TARGET The program to check"
@echo " (default: $(VALGRIND_TARGET))"
@echo " VALGRIND_TARGET_ARGS The arguments to VALGRIND_TARGET"
@echo " (default: $(VALGRIND_TARGET_ARGS))"
@echo " MEMCHECK_OUT Where to put the memcheck results"
@echo " (default: $(MEMCHECK_OUT))"
@echo "==================================================================="
help: help_common
# ==============================================================================
# Include dependencies which are stored as .d files in the $(DEPDIR) directories
# TODO prefer -wholename to -path, but old version of find doesn't have wholename
-include $(shell find -path '*/$(DEPDIR)/*.d')

@ -0,0 +1,85 @@
environment:
matrix:
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "Visual Studio 14 2015"
compiler: msvc
configuration: Release
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "Visual Studio 14 2015 Win64"
compiler: msvc
configuration: Release
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
generator: "Visual Studio 15 2017"
compiler: msvc
configuration: Release
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
generator: "Visual Studio 15 2017 Win64"
compiler: msvc
configuration: Release
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
generator: "Visual Studio 16 2019"
compiler: msvc19
configuration: Release
arch: Win32
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
generator: "Visual Studio 16 2019"
compiler: msvc19
configuration: Release
arch: x64
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "MinGW Makefiles"
compiler: mingw
TOOLCHAIN_PATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32\bin
CC: C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin/gcc.exe
CXX: C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin/g++.exe
configuration: Release
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "MinGW Makefiles"
compiler: mingw
TOOLCHAIN_PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin
CC: C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/gcc.exe
CXX: C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/g++.exe
configuration: Release
matrix:
fast_finish: false
init:
- cmd: cmake --version
- cmd: msbuild /version
install:
- cmd: reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
- cmd: ren "C:\Program Files\Git\usr\bin\sh.exe" _sh.exe
build_script:
- mkdir build
- cd build
- if [%compiler%]==[msvc] cmake -G"%generator%" ..
- if [%compiler%]==[msvc19] cmake -G"%generator%" -A "%arch%" ..
- if [%compiler%]==[mingw] set PATH=%TOOLCHAIN_PATH%;%PATH%
- if [%compiler%]==[mingw] cmake -G"%generator%" -DCMAKE_C_COMPILER=%CC% -DCMAKE_CXX_COMPILER=%CXX% -DCMAKE_SH=CMAKE_SH-NOTFOUND -DCMAKE_BUILD_TYPE=%configuration% ..
- cmake --build . --config %configuration%
test_script:
- cd %APPVEYOR_BUILD_FOLDER%\build
- set CTEST_OUTPUT_ON_FAILURE=1
- ctest -C %configuration%
- if exist "test\Release\std_filesystem_test.exe" test\Release\std_filesystem_test.exe & exit 0
- cd ..

@ -0,0 +1,25 @@
---
Language: Cpp
BasedOnStyle: Chromium
AccessModifierOffset: '-4'
IndentWidth: '4'
ColumnLimit: 256
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakConstructorInitializers: BeforeComma
ConstructorInitializerAllOnOneLineOrOnePerLine: false
IndentPPDirectives: None
...

@ -0,0 +1,17 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Detailed steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Additional context**
Add any other context about the problem here.

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

@ -0,0 +1,2 @@
/build*/
.vscode/

@ -0,0 +1,104 @@
language: cpp
dist: xenial # default distribution
os: linux # default os
sudo: false
matrix:
fast_finish: true
include:
- env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-5"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-6 && CXX=g++-6 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-6"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-7"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GENERATOR='Unix Makefiles' && CONFIG=Debug && GHC_COVERAGE=1"
addons: { apt: { packages: ["g++-7", "lcov"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-8"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-9 && CXX=g++-9 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-9"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-5.0"] } }
- env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-6.0"] } }
- env: MATRIX_EVAL="CC=clang-7 && CXX=clang++-7 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-7", "libc++-7-dev", "libc++abi-7-dev"], sources: ["llvm-toolchain-xenial-7"] } }
- env: MATRIX_EVAL="CC=clang-8 && CXX=clang++-8 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-8", "libc++-8-dev", "libc++abi-8-dev"], sources: ["llvm-toolchain-xenial-8"] } }
- env: MATRIX_EVAL="CC=clang-9 && CXX=clang++-9 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-9", "libc++-9-dev", "libc++abi-9-dev"], sources: [{sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main', key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'}] } }
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode9.2
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode10.1
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode11.2
install:
- eval "${MATRIX_EVAL}"
- |
if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
brew update
fi
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
gem install coveralls-lcov
fi
- $CC --version
- $CXX --version
- cmake --version
before_script:
- eval "${MATRIX_EVAL}"
- mkdir build
- cd build
- export VERBOSE=1
- |
if [ "${CONFIG}" = "Debug" ]; then
cmake -G"${GENERATOR}" -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} -DCMAKE_BUILD_TYPE=${CONFIG} -DGHC_COVERAGE=ON ..
else
cmake -G"${GENERATOR}" -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} -DCMAKE_BUILD_TYPE=${CONFIG} ..
fi
script:
- export VERBOSE=1
- cmake --build . --config ${CONFIG} --target filesystem_test
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
cmake --build . --config ${CONFIG} --target filesystem_test
test/filesystem_test
else
cmake --build . --config ${CONFIG}
ctest -C ${CONFIG} -E Windows
if [ -f "test/std_filesystem_test" ]; then
test/std_filesystem_test || true
fi
fi
after_success:
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
lcov --compat-libtool --directory . --capture --output-file coverage_output.info
lcov --remove coverage_output.info '/usr/*' '*/c++/*' '*.h' '*/catch.hpp' -o coverage.info
sed -i 's|SF:/.*/filesystem/|SF:../|g' coverage.info
coveralls-lcov coverage.info
fi

@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 3.7.2)
project(ghcfilesystem)
include(CMakeDependentOption)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_TESTING
"Enable tests" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_EXAMPLES
"Build examples" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
cmake_dependent_option(GHC_FILESYSTEM_WITH_INSTALL
"With install target" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
if(CMAKE_CXX_STANDARD LESS 11)
message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.")
endif()
add_library(ghc_filesystem INTERFACE)
target_include_directories(ghc_filesystem INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_options(ghc_filesystem INTERFACE "$<$<C_COMPILER_ID:MSVC>:/utf-8>")
target_compile_options(ghc_filesystem INTERFACE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
get_directory_property(hasParent PARENT_DIRECTORY)
if(NOT hasParent)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(GhcHelper)
if(GHC_FILESYSTEM_BUILD_TESTING)
enable_testing()
add_subdirectory(test)
endif()
if(GHC_FILESYSTEM_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
endif()
if(GHC_FILESYSTEM_WITH_INSTALL)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS ghc_filesystem EXPORT ghcFilesystemConfig)
install(EXPORT ghcFilesystemConfig NAMESPACE ghcFilesystem:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem)
endif()

@ -0,0 +1,27 @@
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,710 @@
![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue.svg)
[![Build Status](https://travis-ci.org/gulrak/filesystem.svg?branch=master)](https://travis-ci.org/gulrak/filesystem)
[![Build status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem)
[![Coverage Status](https://coveralls.io/repos/github/gulrak/filesystem/badge.svg?branch=master)](https://coveralls.io/github/gulrak/filesystem?branch=master)
[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.2.10)
# Filesystem
This is a header-only single-file std::filesystem compatible helper library,
based on the C++17 specs, but implemented for C++11, C++14 or C++17 (tightly following
the C++17 with very few documented exceptions). It is currently tested on
macOS 10.12/10.14, Windows 10, and Ubuntu 18.04 but should work on other versions too, as long as you have a
C++11 compatible compiler. It is of course in its own namespace `ghc::filesystem`
to not interfere with a regular `std::filesystem` should you use it in a mixed C++17
environment.
*It could still use some polishing, test coverage is above 90%, I didn't benchmark
much yet, but I'll try to optimize some parts and refactor others, so I'm striving
to improve it as long as it doesn't introduce additional C++17 compatibility
issues. Feedback is always welcome. Simply open an issue if you see something missing
or wrong or not behaving as expected and I'll comment.*
## Motivation
I'm often in need of filesystem functionality, mostly `fs::path`, but directory
access too, and when beginning to use C++11, I used that language update
to try to reduce my third-party dependencies. I could drop most of what
I used, but still missed some stuff that I started implementing for the
fun of it. Originally I based these helpers on my own coding- and naming
conventions. When C++17 was finalized, I wanted to use that interface,
but it took a while, to push myself to convert my classes.
The implementation is closely based on chapter 30.10 from the C++17 standard
and a draft close to that version is
[Working Draft N4687](https://github.com/cplusplus/draft/raw/master/papers/n4687.pdf).
It is from after the standardization of C++17 but it contains the latest filesystem
interface changes compared to the
[Working Draft N4659](https://github.com/cplusplus/draft/raw/master/papers/n4659.pdf).
I want to thank the people working on improving C++, I really liked how the language
evolved with C++11 and the following standards. Keep on the good work!
Oh, and if you ask yourself, what `ghc` is standing for, it is simply
`gulraks helper classes`, yeah, I know, not very imaginative, but I wanted a
short namespace and I use it in some of my private classes (so it has nothing
to do with Haskell).
## Platforms
`ghc::filesystem` is developed on macOS but tested on Windows and Linux.
It should work on any of these with a C++11-capable compiler. I currently
don't have a BSD derivate besides macOS, so the preprocessor checks will
cry out if you try to use it there, but if there is demand, I can try to
help. Also there are some checks to hopefully better work on Android, but
as I currently don't test with the Android NDK, I wouldn't call it a
supported platform yet. All in all, I don't see it replacing `std::filesystem`
where full C++17 is available, it doesn't try to be a "better"
`std::filesystem`, just a drop-in if you can't use it (with the exception
of the UTF-8 preference on Windows).
Unit tests are currently run with:
* macOS 10.12: Xcode 9.2 (clang-900.0.39.2), GCC 9.2, Clang 9.0, macOS 10.13: Xcode 10.1, macOS 10.14: Xcode 11.2
* Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64)
* Linux (Ubuntu): GCC (5.5, 6.5, 7.4, 8.3, 9.2), Clang (5.0, 6.0, 7.1, 8.0, 9.0)
## Tests
The header comes with a set of unit-tests and uses [CMake](https://cmake.org/)
as a build tool and [Catch2](https://github.com/catchorg/Catch2) as test framework.
All tests agains this implementation should succeed, depending on your environment
it might be that there are some warnings, e.g. if you have no rights to create
Symlinks on Windows or at least the test thinks so, but these are just informative.
To build the tests from inside the project directory under macOS or Linux just:
```cpp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
```
This generates `filesystem_test`, the binary that runs all tests.
If the default compiler is a GCC 8 or newer, or Clang 7 or newer, it
additionally tries to build a version of the test binary compiled against GCCs/Clangs
`std::filesystem` implementation, named `std_filesystem_test`
as an additional test of conformance. Ideally all tests should compile and
succeed with all filesystem implementations, but in reality, there are
some differences in behavior, sometimes due to room for interpretation in
in the standard, and there might be issues in these implementations too.
## Usage
### Downloads
The latest release version is [v1.2.10](https://github.com/gulrak/filesystem/tree/v1.2.10) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.2.10).
### Using it as Single-File-Header
As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header
or the `include/ghc` directory into your project folder oder point your include path to this place and
simply include the `filesystem.hpp` header (or `ghc/filesystem.hpp` if you use the subdirectory).
Everything is in the namespace `ghc::filesystem`, so one way to use it only as
a fallback could be:
```cpp
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
```
**Note that this code uses a two-stage preprocessor condition because Visual Studio 2015
doesn't like the `(<...>)` syntax, even if it could cut evaluation early before.**
**Note also, that on MSVC this detection only works starting from version 15.7 on and when setting
the `/Zc:__cplusplus` compile switch, as the compiler allways reports `199711L`
without that switch ([see](https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)).**
If you want to also use the `fstream` wrapper with `path` support as fallback,
you might use:
```cpp
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
```
Now you have e.g. `fs::ofstream out(somePath);` and it is either the wrapper or
the C++17 `std::ofstream`.
**Be aware, as a header-only library, it is not hiding the fact, that it
uses system includes, so they "pollute" your global namespace.**
:information_source: **Hint:** There is an additional header named `ghc/fs_std.hpp` that implements this
dynamic selection of a filesystem implementation, that you can include
instead of `ghc/filesystem.hpp` when you want std::filesystem where
available and ghc::filesystem where not. It also enables the `wchar_t`
support on `ghc::filesystem` on Windows, so the resulting implementation
in the `fs` namespace will be compatible.
### Using it as Forwarding-/Implementation-Header
Alternatively, starting from v1.1.0 `ghc::filesystem` can also be used by
including one of two additional wrapper headers. These allow to include
a forwarded version in most places (`ghc/fs_fwd.hpp`) while hiding the
implementation details in a single cpp that includes `ghc/fs_impl.hpp` to
implement the needed code. That way system includes are only visible from
inside the cpp, all other places are clean.
Be aware, that it is currently not supported to hide the implementation
into a Windows-DLL, as a DLL interface with C++ standard templates in interfaces
is a different beast. If someone is willing to give it a try, I might integrate
a PR but currently working on that myself is not a priority.
If you use the forwarding/implementation approach, you can still use the dynamic
switching like this:
```cpp
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/fs-fwd.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
```
and in the implementation hiding cpp, you might use (before any include that includes `ghc/fs_fwd.hpp`
to take precedence:
```cpp
#if !(defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>))
#include <ghc/fs_impl.hpp>
#endif
#endif
```
:information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and
`ghc/fs_std_impl.hpp` that use this technique, so you can simply include them
if you want to dynamically select the filesystem implementation. they also
enable the `wchar_t` support on `ghc::filesystem` on Windows, so the resulting
implementation in the `fs` namespace will be compatible.
### Git Submodule and CMake
Starting from v1.1.0, it is possible to add `ghc::filesystem`
as a git submodule, add the directory to your `CMakeLists.txt` with
`add_subdirectory()` and then simply use `target_link_libraries(your-target ghc_filesystem)`
to ensure correct include path that allow `#include <ghc/filesystem.hpp>`
to work.
The `CMakeLists.txt` offers a few options to customize its behaviour:
* `GHC_FILESYSTEM_BUILD_TESTING` - Compile tests, default is `OFF` when used as
a submodule, else `ON`.
* `GHC_FILESYSTEM_BUILD_EXAMPLES` - Compile the examples, default is `OFF` when used as
a submodule, else `ON`.
* `GHC_FILESYSTEM_WITH_INSTALL` - Add install target to build, default is `OFF` when used as
a submodule, else `ON`.
### Versioning
There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes
might make it needed to react on the version, but I don't plan to break anything.
It's the version as decimal number `(major * 10000 + minor * 100 + patch)`.
**Note:** Starting from v1.0.2 only even patch versions will be used for releases
and odd patch version will only be used for in between commits while working on
the next version.
## Documentation
There is almost no documentation in this release, as any `std::filesystem`
documentation would work, besides the few differences explained in the next
section. So you might head over to https://en.cppreference.com/w/cpp/filesystem
for a description of the components of this library.
The only additions to the standard are documented here:
### `ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`
These are simple wrappers around `std::ifstream`, `std::ofstream` and `std::fstream`.
They simply add an `open()` method and a constuctor with an `ghc::filesystem::path`
argument as the `fstream` variants in C++17 have them.
### `ghc::filesystem::u8arguments`
This is a helper class that currently checks for UTF-8 encoding on non-Windows platforms but on Windows it
fetches the command line arguments als Unicode strings from the OS with
```cpp
::CommandLineToArgvW(::GetCommandLineW(), &argc)
```
and then converts them to UTF-8, and replaces `argc` and `argv`. It is a guard-like
class that reverts its changes when going out of scope.
So basic usage is:
```cpp
namespace fs = ghc::filesystem;
int main(int argc, char* argv[])
{
fs::u8arguments u8guard(argc, argv);
if(!u8guard.valid()) {
std::cerr << "Bad encoding, needs UTF-8." << std::endl;
exit(EXIT_FAILURE);
}
// now use argc/argv as usual, they have utf-8 enconding on windows
// ...
return 0;
}
```
That way `argv` is UTF-8 encoded as long as the scope from `main` is valid.
**Note:** On macOS, while debugging under Xcode the code currently will return
`false` as Xcode starts the application with `US-ASCII` as encoding, no matter what
encoding is actually used and even setting `LC_ALL` in the product scheme doesn't
change anything. I still need to investigate this.
## Differences
As this implementation is based on existing code from my private helper
classes, it derived some constraints of it, leading to some differences
between this and the standard C++17 API.
### LWG Defects
This implementation has switchable behavior for the LWG defects
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
The currently selected behavior is following
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
where a regular file of the same name prohibits the creation of a directory and forces
the user of those functions to double-check via `fs::is_directory` if it really worked.
The more intuitive approach to directory creation of treating a file with that name as an
error is also advocated by the newer paper
[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revison
P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703)
and GCC by now switched to following its proposal
([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
### Not Implemented on C++ before C++17
```cpp
// methods in ghc::filesystem::path:
path& operator+=(basic_string_view<value_type> x);
int compare(basic_string_view<value_type> s) const;
```
These are not implemented under C++11 and C++14, as there is no
`std::basic_string_view` available and I did want to keep this
implementation self-contained and not write a full C++17-upgrade for
C++11/14. Starting with v1.1.0 these are supported when compiling
ghc::filesystem under C++17.
### Differences in API
```cpp
filesystem::path::string_type
filesystem::path::value_type
```
In Windows, an implementation should use `std::wstring` and `wchar_t` as types used
for the native representation, but as I'm a big fan of the
["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/), I decided
agains it for now. If you need to call some Windows API, use the W-variant
with the `path::wstring()` member
(e.g. `GetFileAttributesW(p.wstring().c_str())`). This gives you the
Unicode variant independant of the `UNICODE` macro and makes sharing code
between Windows, Linux and macOS easier.
Starting with v1.2.0 `ghc::filesystem` has the option to select the more
standard conforming APi with `wchar_t` and `std::wstring` on Windows by
defining `GHC_WIN_WSTRING_STRING_TYPE`. This define has no effect on other
platforms and will be set by the helping headers `ghc/fs_std.hpp` and
the pair `ghc/fs_std_fwd.hpp`/`ghc/fs_std_impl.hpp` to enhance compatibility.
```cpp
const path::string_type& path::native() const /*noexcept*/;
const path::value_type *path::c_str() const /*noexcept*/;
```
These two can not be `noexcept` with the current implementation. This due
to the fact, that internally path is working on the generic path version
only, and the getters need to do a conversion to native path format.
```cpp
const path::string_type& path::generic_string() const;
```
This returns a const reference, instead of a value, because it can. This
implementation uses the generic representation for internal workings, so
it's "free" to return that.
### Differences in Behavior
#### fs.path ([ref](https://en.cppreference.com/w/cpp/filesystem/path))
As the complete inner mechanics of this implementation `fs::path` are working
on the generic format, it is the internal representation. So creating any mixed
slash `fs::path` object under Windows (e.g. with `"C:\foo/bar"`) will lead to a
unified path with `"C:\foo\bar"` via `native()` and `"C:/foo/bar"` via
`generic_string()` API.
Additionally this implementation follows the standards suggestion to handle
posix paths of the form `"//host/path"` and USC path on windows also as having
a root-name (e.g. `"//host"`). The GCC implementation didn't choose to do that
while testing on Ubuntu 18.04 and macOS with GCC 8.1.0 or Clang 7.0.0. This difference
will show as warnings under std::filesystem. This leads to a change in the
algorithm described in the standard for `operator/=(path& p)` where any path
`p` with `p.is_absolute()` will degrade to an assignment, while this implementation
has the exception where `*this == *this.root_name()` and `p == preferred_seperator`
a normal append will be done, to allow:
```cpp
fs::path p1 = "//host/foo/bar/file.txt";
fs::path p2;
for (auto p : p1) p2 /= p;
ASSERT(p1 == p2);
```
For all non-host-leading paths the behaviour will match the one described by
the standard.
#### fs.op.copy ([ref](https://en.cppreference.com/w/cpp/filesystem/copy))
Then there is `fs::copy`. The tests in the suite fail partially with C++17 `std::filesystem`
on GCC/Clang. They complain about a copy call with `fs::copy_options::recursive` combined
with `fs::copy_options::create_symlinks` or `fs::copy_options::create_hard_links` if the
source is a directory. There is nothing in the standard that forbids this combination
and it is the only way to deep-copy a tree while only create links for the files.
There is [LWG #2682](https://wg21.cmeerw.net/lwg/issue2682) that supports this
interpretation, but the issue ignores the usefulness of the combination with recursive
and part of the justification for the proposed solution is "we did it so for almost two years".
But this makes `fs::copy` with `fs::copy_options::create_symlinks` or `fs::copy_options::create_hard_links`
just a more complicated syntax for the `fs::create_symlink` or `fs::create_hardlink` operation
and I don't want to believe, that this was the intention of the original writing.
As there is another issue related to copy, with a different take on the description.
**Note:** With v1.1.2 I decided to integrate a behavior switch for this and make the LWG #2682
the default.
## Open Issues
### General Known Issues
There are still some methods that break the `noexcept` clause, some
are related to LWG defects, some are due to my implementation. I
work on fixing the later ones, and might in cases where there is no
way of implementing the feature without risk of an exception, break
conformance and remove the `noexcept`.
### Windows
#### Symbolic Links on Windows
As symbolic links on Windows, while being supported more or less since
Windows Vista (with some strict security constraints) and fully since some earlier
build of Windows 10, when "Developer Mode" is activated, are at time of writing
(2018) rarely used, still they are supported with this implementation.
#### Permissions
The Windows ACL permission feature translates badly to the POSIX permission
bit mask used in the interface of C++17 filesystem. The permissions returned
in the `file_status` are therefore currently synthesized for the `user`-level
and copied to the `group`- and `other`-level. There is still some potential
for more interaction with the Windows permission system, but currently setting
or reading permissions with this implementation will most certainly not lead
to the expected behavior.
## Release Notes
### [v1.2.10](https://github.com/gulrak/filesystem/releases/tag/v1.2.10)
* The Visual Studio 2019 compiler, GCC 9.2 and Clang 9.0 where added to the
CI configuration.
* Bugfix for [#39](https://github.com/gulrak/filesystem/issues/39), `fs::rename`
on Windows didn't replace an axisting regular file as required by the standard,
but gave an error. New tests and a fix as provided in the issue was implemented.
* Bugfix for [#39](https://github.com/gulrak/filesystem/issues/39), for the
forwarding use via `fs_fwd.hpp` or `fs_std_fwd.hpp` der was a use of
`DWORD` in the forwarding part leading to an error if `Windows.h` was not
included before the header. The tests were changed to give an error in that
case too and the useage of `DWORD` was removed.
* Bugfix for [#38](https://github.com/gulrak/filesystem/issues/38), casting the
return value of `GetProcAddress` gave a warning with `-Wcast-function-type`
on MSYS2 and MinGW GCC 9 builds.
### [v1.2.8](https://github.com/gulrak/filesystem/releases/tag/v1.2.8)
* Pull request [#30](https://github.com/gulrak/filesystem/pull/30), the
`CMakeLists.txt` will automatically exclude building examples and tests when
used as submodule, the configuration options now use a prefixed name to
reduce risk of conflicts.
* Pull request [#24](https://github.com/gulrak/filesystem/pull/24), install
target now creates a `ghcFilesystemConfig.cmake` in
`${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem` for `find_package` that
exports a target as `ghcFilesystem::ghc_filesystem`.
* Pull request [#31](https://github.com/gulrak/filesystem/pull/31), fixes
`error: redundant redeclaration of 'constexpr' static data member` deprecation
warning in C++17 mode.
* Pull request [#32](https://github.com/gulrak/filesystem/pull/32), fixes
old-style-cast warnings.
* Pull request [#34](https://github.com/gulrak/filesystem/pull/34), fixes
[TOCTOU](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use) situation
on `fs::create_directories`, thanks for the PR!
* Feature [#35](https://github.com/gulrak/filesystem/issues/35), new CMake
option to add an install target `GHC_FILESYSTEM_WITH_INSTALL` that is
defaulted to OFF if `ghc::filesystem` is used via `add_subdirectory`.
* Bugfix for [#33](https://github.com/gulrak/filesystem/issues/33), fixes
an issue with `fs::path::lexically_normal()` that leaves a trailing separator
in case of a resulting path ending with `..` as last element.
* Bugfix for [#36](https://github.com/gulrak/filesystem/issues/36), warings
on Xcode 11.2 due to unhelpfull references in path element iteration.
### [v1.2.6](https://github.com/gulrak/filesystem/releases/tag/v1.2.6)
* Pull request [#23](https://github.com/gulrak/filesystem/pull/23), tests and
examples can now be disabled in CMake via seting `BUILD_TESTING` and
`BUILD_EXAMPLES` to `NO`, `OFF` or `FALSE`.
* Pull request [#25](https://github.com/gulrak/filesystem/pull/25),
missing specialization for construction from `std::string_view` when
available was added.
* Additional test case when `std::string_view` is available.
* Bugfix for [#27](https://github.com/gulrak/filesystem/issues/27), the
`fs::path::preferred_seperator` declaration was not compiling on pre
C++17 compilers and no test accessed it, to show the problem. Fixed
it to an construction C++11 compiler should accept and added a test that
is successful on all combinations tested.
* Bugfix for [#29](https://github.com/gulrak/filesystem/issues/29), stricter
warning settings where chosen and resulting warnings where fixed.
### [v1.2.4](https://github.com/gulrak/filesystem/releases/tag/v1.2.4)
* Enabled stronger warning switches and resulting fixed issues on GCC and MinGW
* Bugfix for #22, the `fs::copy_options` where not forwarded from `fs::copy` to
`fs::copy_file` in one of the cases.
### [v1.2.2](https://github.com/gulrak/filesystem/releases/tag/v1.2.2)
* Fix for ([#21](https://github.com/gulrak/filesystem/pull/21)), when compiling
on Alpine Linux with musl instead of glibc, the wrong `strerror_r` signature
was expected. The complex preprocessor define mix was dropped in favor of
the usual dispatch by overloading a unifying wrapper.
### [v1.2.0](https://github.com/gulrak/filesystem/releases/tag/v1.2.0)
* Added MinGW 32/64 and Visual Studio 2015 builds to the CI configuration.
* Fixed additional compilation issues on MinGW.
* Pull request ([#13](https://github.com/gulrak/filesystem/pull/13)), set
minimum required CMake version to 3.7.2 (as in Debian 8).
* Pull request ([#14](https://github.com/gulrak/filesystem/pull/14)), added
support for a make install target.
* Bugfix for ([#15](https://github.com/gulrak/filesystem/issues/15)), the
forward/impl way of using `ghc::filesystem` missed a `<vector>` include
in the windows case.
* Bugfix for ([#16](https://github.com/gulrak/filesystem/issues/16)),
VS2019 didn't like the old size dispatching in the utf8 decoder, so it
was changed to a sfinae based approach.
* New feature ([#17](https://github.com/gulrak/filesystem/issues/17)), optional
support for standard conforming `wchar_t/std::wstring` interface when
compiling on Windows with defined `GHC_WIN_WSTRING_STRING_TYPE`, this is
default when using the `ghc/fs_std*.hpp` header, to enhance compatibility.
* New feature ([#18](https://github.com/gulrak/filesystem/issues/18)), optional
filesystem exceptions/errors on unicode errors with defined
`GHC_RAISE_UNICODE_ERRORS` (instead of replacing invalid code points or
UTF-8 encoding errors with the replacement character `U+FFFD`).
* Pull request ([#20](https://github.com/gulrak/filesystem/pull/20)), fix for
file handle leak in `fs::copy_file`.
* Coverage now checked in CI (~95% line coverage).
### [v1.1.4](https://github.com/gulrak/filesystem/releases/tag/v1.1.4)
* Additional Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
error in old unified `readdir/readdir_r` code of `fs::directory_iterator`;
as `readdir_r` is now depricated, I decided to drop it and the resulting
code is much easier, shorter and due to more refactoring faster
* Fix for crashing unit tests against MSVC C++17 std::filesystem
* Travis-CI now additionally test with Xcode 10.2 on macOS
* Some minor refactorings
### [v1.1.2](https://github.com/gulrak/filesystem/releases/tag/v1.1.2)
* Bugfix for ([#11](https://github.com/gulrak/filesystem/issues/11)),
`fs::path::lexically_normal()` had some issues with `".."`-sequences.
* Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
`fs::recursive_directory_iterator` could run into endless loops,
the methods depth() and pop() had issues and the copy behaviour and
`input_iterator_tag` conformance was broken, added tests
* Restructured some CMake code into a macro to ease the support for
C++17 std::filesystem builds of tests and examples for interoperability
checks.
* Some fixes on Windows tests to ease interoperability test runs.
* Reduced noise on `fs::weakly_canonical()` tests against `std::fs`
* Added simple `du` example showing the `recursive_directory_iterator`
used to add the sizes of files in a directory tree.
* Added error checking in `fs::file_time_type` test helpers
* `fs::copy()` now conforms LWG #2682, disallowing the use of
`copy_option::create_symlinks' to be used on directories
### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0)
* Restructuring of the project directory. The header files are now using
`hpp` as extension to be marked as c++ and they where moved to
`include/ghc/` to be able to include by `<ghc/filesystem.hpp>` as the
former include name might have been to generic and conflict with other
files.
* Better CMake support: `ghc::filesystem` now can be used as a submodul
and added with `add_subdirectory` and will export itself as `ghc_filesystem`
target. To use it, only `target_link_libraries(your-target ghc_filesystem)`
is needed and the include directories will be set so `#include <ghc/filesystem.hpp>`
will be a valid directive.
Still you can simply only add the header file to you project and include it
from there.
* Enhancement ([#10](https://github.com/gulrak/filesystem/issues/10)),
support for separation of implementation and forwarded api: Two
additional simple includes are added, that can be used to forward
`ghc::filesystem` declarations (`fs_fwd.hpp`) and to wrap the
implementation into a single cpp (`fs_impl.hpp`)
* The `std::basic_string_view` variants of the `fs::path` api are
now supported when compiling with C++17.
* Added CI integration for Travis-CI and Appveyor.
* Fixed MinGW compilation issues.
* Added long filename support for Windows.
### [v1.0.10](https://github.com/gulrak/filesystem/releases/tag/v1.0.10)
* Bugfix for ([#9](https://github.com/gulrak/filesystem/issues/9)), added
missing return statement to `ghc::filesystem::path::generic_string()`
* Added checks to hopefully better compile against Android NDK. There where
no tests run yet, so feedback is needed to actually call this supported.
* `filesystem.h` was renamed `filesystem.hpp` to better reflect that it is
a c++ language header.
### [v1.0.8](https://github.com/gulrak/filesystem/releases/tag/v1.0.8)
* Bugfix for ([#6](https://github.com/gulrak/filesystem/issues/6)), where
`ghc::filesystem::remove()` and `ghc::filesystem::remove_all()` both are
now able to remove a single file and both will not raise an error if the
path doesn't exist.
* Merged pull request ([#7](https://github.com/gulrak/filesystem/pull/7)),
a typo leading to setting error code instead of comparing it in
`ghc::filesystem::remove()` under Windows.
* Bugfix for (([#8](https://github.com/gulrak/filesystem/issues/8)), the
Windows version of `ghc::filesystem::directory_iterator` now releases
resources when reaching `end()` like the POSIX one does.
### [v1.0.6](https://github.com/gulrak/filesystem/releases/tag/v1.0.6)
* Bugfix for ([#4](https://github.com/gulrak/filesystem/issues/4)), missing error_code
propagation in `ghc::filesystem::copy()` and `ghc::filesystem::remove_all` fixed.
* Bugfix for ([#5](https://github.com/gulrak/filesystem/issues/5)), added missing std
namespace in `ghc::filesystem::recursive_directory_iterator::difference_type`.
### [v1.0.4](https://github.com/gulrak/filesystem/releases/tag/v1.0.4)
* Bugfix for ([#3](https://github.com/gulrak/filesystem/issues/3)), fixed missing inlines
and added test to ensure including into multiple implementation files works as expected.
* Building tests with `-Wall -Wextra -Werror` and fixed resulting issues.
### [v1.0.2](https://github.com/gulrak/filesystem/releases/tag/v1.0.2)
* Updated catch2 to v2.4.0.
* Refactored `fs.op.permissions` test to work with all tested `std::filesystem`
implementations (gcc, clang, msvc++).
* Added helper class `ghc::filesystem::u8arguments` as `argv` converter, to
help follow the UTF-8 path on windows. Simply instantiate it with `argc` and
`argv` and it will fetch the Unicode version of the command line and convert
it to UTF-8. The destructor reverts the change.
* Added `examples` folder with hopefully some usefull example usage. Examples are
tested (and build) with `ghc::filesystem` and C++17 `std::filesystem` when
available.
* Starting with this version, only even patch level versions will be tagged and
odd patch levels mark in-between non-stable wip states.
* Tests can now also be run against MS version of std::filesystem for comparison.
* Added missing `fstream` include.
* Removed non-conforming C99 `timespec`/`timeval` usage.
* Fixed some integer type mismatches that could lead to warnings.
* Fixed `chrono` conversion issues in test and example on clang 7.0.0.
### [v1.0.1](https://github.com/gulrak/filesystem/releases/tag/v1.0.1)
* Bugfix: `ghc::filesystem::canonical` now sees empty path as non-existant and reports
an error. Due to this `ghc::filesystem::weakly_canonical` now returns relative
paths for non-existant argument paths. ([#1](https://github.com/gulrak/filesystem/issues/1))
* Bugfix: `ghc::filesystem::remove_all` now also counts directories removed ([#2](https://github.com/gulrak/filesystem/issues/2))
* Bugfix: `recursive_directory_iterator` tests didn't respect equality domain issues
and dereferencable constraints, leading to fails on `std::filesystem` tests.
* Bugfix: Some `noexcept` tagged methods and functions could indirectly throw exceptions
due to UFT-8 decoding issues.
* `std_filesystem_test` is now also generated if LLVM/clang 7.0.0 is found.
### [v1.0.0](https://github.com/gulrak/filesystem/releases/tag/v1.0.0)
This was the first public release version. It implements the full range of
C++17 std::filesystem, as far as possible without other C++17 dependencies.

@ -0,0 +1,38 @@
macro(AddExecutableWithStdFS targetName)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0))
if(APPLE)
include_directories(/usr/local/opt/llvm/include)
link_directories(/usr/local/opt/llvm/lib)
endif()
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
if(APPLE)
target_link_libraries(${targetName} -lc++fs)
else()
target_compile_options(${targetName} PRIVATE "-stdlib=libc++")
target_link_libraries(${targetName} -stdlib=libc++ -lc++fs)
endif()
target_link_libraries(${targetName} -lc++fs)
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0))
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
target_link_libraries(${targetName} -lstdc++fs)
endif()
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15))
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD_REQUIRED ON)
target_compile_options(${targetName} PRIVATE "/Zc:__cplusplus")
target_compile_definitions(${targetName} PRIVATE USE_STD_FS _CRT_SECURE_NO_WARNINGS)
endif()
endmacro()

@ -0,0 +1,5 @@
@PACKAGE_INIT@
set_and_check(ghcfilesystem_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
check_required_components(ghcfilesystem)

@ -0,0 +1,12 @@
add_executable(fs_dir dir.cpp)
target_link_libraries(fs_dir ghc_filesystem)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
AddExecutableWithStdFS(std_fs_dir dir.cpp)
add_executable(fs_du du.cpp)
target_link_libraries(fs_du ghc_filesystem)
AddExecutableWithStdFS(std_fs_du du.cpp)

@ -0,0 +1,60 @@
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
template <typename TP>
std::time_t to_time_t(TP tp)
{
// Based on trick from: Nico Josuttis, C++17 - The Complete Guide
std::chrono::system_clock::duration dt = std::chrono::duration_cast<std::chrono::system_clock::duration>(tp - TP::clock::now());
return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now() + dt);
}
static std::string perm_to_str(fs::perms prms)
{
std::string result;
result.reserve(9);
for (int i = 0; i < 9; ++i) {
result = ((static_cast<int>(prms) & (1 << i)) ? "xwrxwrxwr"[i] : '-') + result;
}
return result;
}
int main(int argc, char* argv[])
{
#ifdef GHC_FILESYSTEM_VERSION
fs::u8arguments u8guard(argc, argv);
if (!u8guard.valid()) {
std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl;
std::exit(EXIT_FAILURE);
}
#endif
if (argc > 2) {
std::cerr << "USAGE: dir <path>" << std::endl;
exit(1);
}
fs::path dir{"."};
if (argc == 2) {
dir = fs::u8path(argv[1]);
}
for (auto de : fs::directory_iterator(dir)) {
auto ft = to_time_t(de.last_write_time());
auto ftm = *std::localtime(&ft);
std::cout << (de.is_directory() ? "d" : "-") << perm_to_str(de.symlink_status().permissions()) << " " << std::setw(8) << (de.is_directory() ? "-" : std::to_string(de.file_size())) << " " << std::put_time(&ftm, "%Y-%m-%d %H:%M:%S") << " "
<< de.path().filename().string() << std::endl;
}
return 0;
}

@ -0,0 +1,61 @@
#include <iostream>
#include <iomanip>
#include <chrono>
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
int main(int argc, char* argv[])
{
#ifdef GHC_FILESYSTEM_VERSION
fs::u8arguments u8guard(argc, argv);
if(!u8guard.valid()) {
std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl;
std::exit(EXIT_FAILURE);
}
#endif
if(argc > 2) {
std::cerr << "USAGE: du <path>" << std::endl;
exit(1);
}
fs::path dir{"."};
if(argc == 2) {
dir = fs::u8path(argv[1]);
}
uint64_t totalSize = 0;
int totalDirs = 0;
int totalFiles = 0;
int maxDepth = 0;
try {
auto rdi = fs::recursive_directory_iterator(dir);
for(auto de : rdi) {
if(rdi.depth() > maxDepth) {
maxDepth = rdi.depth();
}
if(de.is_regular_file()) {
totalSize += de.file_size();
++totalFiles;
}
else if(de.is_directory()) {
++totalDirs;
}
}
}
catch(fs::filesystem_error fe) {
std::cerr << "Error: " << fe.what() << std::endl;
exit(1);
}
std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl;
return 0;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,46 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem.
// This file can be include at any place, where ghc::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace,
// as long as one cpp includes fs_impl.hpp to deliver the matching implementations.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
#endif // GHC_FILESYSTEM_FWD_H

@ -0,0 +1,43 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
// fs_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_fwd.hpp directly or via a different
// header to work.
//---------------------------------------------------------------------------------------
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>

@ -0,0 +1,64 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected
// or ghc::filesystem if not, and makes the resulting API available in the
// namespace fs.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_H

@ -0,0 +1,68 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem that uses std::filesystem if it detects it.
// This file can be include at any place, where fs::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace,
// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_FWD_H

@ -0,0 +1,51 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem that does nothing if std::filesystem is detected.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_std_fwd.hpp directly or via a different
// header to work.
//---------------------------------------------------------------------------------------
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#endif
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif

@ -0,0 +1,54 @@
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON)
include(ParseAndAddCatchTests)
if(GHC_COVERAGE)
message("Generating test runner for coverage run...")
set(CMAKE_EXE_LINKER_FLAGS "${CMCMAKE_EXE_LINKER_FLAGS} --coverage")
add_executable(filesystem_test filesystem_test.cpp catch.hpp)
if(MINGW)
target_compile_options(filesystem_test PUBLIC --coverage "-Wa,-mbig-obj")
else()
target_compile_options(filesystem_test PUBLIC --coverage)
endif()
target_link_libraries(filesystem_test PUBLIC ghc_filesystem --coverage)
else()
message("Generating test runner for normal test...")
add_executable(filesystem_test filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test ghc_filesystem)
target_compile_options(filesystem_test PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
ParseAndAddCatchTests(filesystem_test)
AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp)
if(WIN32)
add_executable(filesystem_test_wchar filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test_wchar ghc_filesystem)
target_compile_options(filesystem_test_wchar PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test_wchar PRIVATE _CRT_SECURE_NO_WARNINGS GHC_WIN_WSTRING_STRING_TYPE)
else()
target_compile_definitions(filesystem_test_wchar PRIVATE GHC_WIN_WSTRING_STRING_TYPE)
endif()
ParseAndAddCatchTests(filesystem_test_wchar)
endif()
endif()
add_executable(multifile_test multi1.cpp multi2.cpp catch.hpp)
target_link_libraries(multifile_test ghc_filesystem)
add_test(multifile_test multifile_test)
add_executable(fwd_impl_test fwd_test.cpp impl_test.cpp)
target_link_libraries(fwd_impl_test ghc_filesystem)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
add_test(fwd_impl_test fwd_impl_test)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,225 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_SCENARIO, #
# - CATCH_TEST_CASE_METHOD. #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# enable_testing() #
# #
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddCatchTests) #
# ParseAndAddCatchTests(${PROJECT_NAME}) #
# #
# The following variables affect the behavior of the script: #
# #
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
# -- enables debug messages #
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
# -- adds fixture class name to the test name #
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
# -- adds cmake target name to the test name #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
# a test should be run. For instance to use test MPI, one can write #
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
# just before calling this ParseAndAddCatchTests function #
# #
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
# command. For example, to include successful tests in the output, one can write #
# set(AdditionalCatchParameters --success) #
# #
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
# file in the target is set, and contains the list of the tests extracted from that target, or #
# from that file. This is useful, for example to add further labels or properties to the tests. #
# #
#==================================================================================================#
if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
endif()
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(ParseAndAddCatchTests_PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(ParseAndAddCatchTests_RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
return()
endif()
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
ParseAndAddCatchTests_RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
# Get string parts of test definition
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
# Strip wrapping quotation marks
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
# Validate that a test name and tags have been provided
list(LENGTH TestStrings TestStringsLength)
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
endif()
# Assign name and tags
list(GET TestStrings 0 Name)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
set(CTestName "${TestTarget}:${CTestName}")
endif()
# add target to labels to enable running all tests added from this target
set(Labels ${TestTarget})
if(TestStringsLength EQUAL 2)
list(GET TestStrings 1 Tags)
string(TOLOWER "${Tags}" Tags)
# remove target from labels if the test is hidden
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
list(REMOVE_ITEM Labels ${TestTarget})
endif()
string(REPLACE "]" ";" Tags "${Tags}")
string(REPLACE "[" "" Tags "${Tags}")
else()
# unset tags variable from previous loop
unset(Tags)
endif()
list(APPEND Labels ${Tags})
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
if(result)
set(HiddenTagFound ON)
break()
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Escape commas in the test spec
string(REPLACE "," "\\," Name ${Name})
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
else()
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
set_property(
TARGET ${TestTarget}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
set_property(
SOURCE ${SourceFile}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
endif()
endforeach()
endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
endforeach()
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,7 @@
// This test file is part of the fwd_test.cpp/impl_test.cpp pair
// and used to test the new optional two-part usage of ghc::filesystem
// where exactly one cpp includes fs_impl.hpp and all others use
// fs_fwd.hpp (to test this with maximum functionality, the unit tests
// are included here, signaling they should only include the fs_fwd.hpp)
#define GHC_FILESYSTEM_FWD_TEST
#include "filesystem_test.cpp"

@ -0,0 +1,9 @@
// This test file is part of the fwd_test.cpp/impl_test.cpp pair
// and used to test the new optional two-part usage of ghc::filesystem
// where exactly one cpp includes fs_impl.hpp and all others use
// fs_fwd.hpp (to test this with maximum functionality, the unit tests
// are included here, signaling they should only include the fs_fwd.hpp)
#define NOMINMAX
#include <ghc/fs_impl.hpp>
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

@ -0,0 +1,50 @@
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
// This test and the one in multi2.cpp doesn't actualy test relevant functionality,
// it is just used to check that it is possible to include filesystem.h in multiple
// source files.
TEST_CASE("Multifile-test 1", "[multi]")
{
CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
std::string str = "/usr/local/bin";
std::u16string u16str = u"/usr/local/bin";
std::u32string u32str = U"/usr/local/bin";
CHECK(str == fs::path(str.begin(), str.end()));
CHECK(str == fs::path(u16str.begin(), u16str.end()));
CHECK(str == fs::path(u32str.begin(), u32str.end()));
}

@ -0,0 +1,48 @@
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
#include "catch.hpp"
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
// This test and the one in multi1.cpp doesn't actualy test relevant functionality,
// it is just used to check that it is possible to include filesystem.h in multiple
// source files.
TEST_CASE("Multifile-test 2", "[multi]")
{
CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
std::string str = "/usr/local/bin";
std::u16string u16str = u"/usr/local/bin";
std::u32string u32str = U"/usr/local/bin";
CHECK(str == fs::path(str.begin(), str.end()));
CHECK(str == fs::path(u16str.begin(), u16str.end()));
CHECK(str == fs::path(u32str.begin(), u32str.end()));
}
Loading…
Cancel
Save