diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2015-04-30 20:11:52 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2015-04-30 20:11:52 +0100 |
commit | 0ca7ba9aa6a0b5b2c71184cd1853446cec9a0889 (patch) | |
tree | 898dad0f66d2410fa20e02cacb83b40aefe3d2ab /libstdc++-v3/src | |
parent | 59c1f3840203780d04974b37b617ac0d673e8c4a (diff) | |
download | gcc-0ca7ba9aa6a0b5b2c71184cd1853446cec9a0889.zip gcc-0ca7ba9aa6a0b5b2c71184cd1853446cec9a0889.tar.gz gcc-0ca7ba9aa6a0b5b2c71184cd1853446cec9a0889.tar.bz2 |
Implement N4100 File System TS
* acinclude.m4 (GLIBCXX_ENABLE_FILESYSTEM_TS): Define.
(GLIBCXX_CHECK_FILESYSTEM_DEPS): Define.
* config.h.in: Regenerate.
* configure: Regenerate.
* configure.ac: Enable filesystem TS and check its dependencies.
* include/Makefile.am: Add new headers.
* include/Makefile.in: Regenerate.
* include/bits/locale_conv.h (__do_str_code_cvt, __str_codecvt_in,
__str_codecvt_out): Move code conversion logic from wstring_convert
into new global functions.
(wstring_convert::to_bytes, wstring_convert::from_bytes): Use new
functions.
(wstring_convert::_M_conv): Remove.
* include/bits/quoted_string.h (_Quoted_string): Split out of iomanip.
* include/experimental/filesystem: New.
* include/experimental/fs_dir.h: New.
* include/experimental/fs_fwd.h: New.
* include/experimental/fs_ops.h: New.
* include/experimental/fs_path.h: New.
* include/std/iomanip (_Quoted_string): Move to bits/quoted_string.h.
* python/libstdcxx/v6/printers.py (StdExpPathPrinter): Add.
* src/Makefile.am (SUBDIRS): Add filesystem.
* src/Makefile.in: Regenerate.
* src/filesystem/Makefile.am: New.
* src/filesystem/Makefile.in: New.
* src/filesystem/dir.cc: New.
* src/filesystem/ops.cc: New.
* src/filesystem/path.cc: New.
* testsuite/experimental/filesystem/operations/absolute.cc: New.
* testsuite/experimental/filesystem/operations/copy.cc: New.
* testsuite/experimental/filesystem/operations/current_path.cc: New.
* testsuite/experimental/filesystem/path/append/path.cc: New.
* testsuite/experimental/filesystem/path/assign/assign.cc: New.
* testsuite/experimental/filesystem/path/assign/copy.cc: New.
* testsuite/experimental/filesystem/path/compare/compare.cc: New.
* testsuite/experimental/filesystem/path/compare/path.cc: New.
* testsuite/experimental/filesystem/path/compare/strings.cc: New.
* testsuite/experimental/filesystem/path/concat/path.cc: New.
* testsuite/experimental/filesystem/path/concat/strings.cc: New.
* testsuite/experimental/filesystem/path/construct/copy.cc: New.
* testsuite/experimental/filesystem/path/construct/default.cc: New.
* testsuite/experimental/filesystem/path/construct/locale.cc: New.
* testsuite/experimental/filesystem/path/construct/range.cc: New.
* testsuite/experimental/filesystem/path/decompose/extension.cc: New.
* testsuite/experimental/filesystem/path/decompose/filename.cc: New.
* testsuite/experimental/filesystem/path/decompose/parent_path.cc:
New.
* testsuite/experimental/filesystem/path/decompose/relative_path.cc:
New.
* testsuite/experimental/filesystem/path/decompose/root_directory.cc:
New.
* testsuite/experimental/filesystem/path/decompose/root_name.cc:
New.
* testsuite/experimental/filesystem/path/decompose/root_path.cc:
New.
* testsuite/experimental/filesystem/path/decompose/stem.cc: New.
* testsuite/experimental/filesystem/path/generic/generic_string.cc:
New.
* testsuite/experimental/filesystem/path/itr/traversal.cc: New.
* testsuite/experimental/filesystem/path/modifiers/clear.cc: New.
* testsuite/experimental/filesystem/path/modifiers/make_preferred.cc:
New.
* testsuite/experimental/filesystem/path/modifiers/remove_filename.cc:
New.
* testsuite/experimental/filesystem/path/modifiers/replace_extension.cc:
New.
* testsuite/experimental/filesystem/path/modifiers/replace_filename.cc:
New.
* testsuite/experimental/filesystem/path/modifiers/swap.cc: New.
* testsuite/experimental/filesystem/path/nonmember/hash_value.cc: New.
* testsuite/experimental/filesystem/path/query/empty.cc: New.
* testsuite/experimental/filesystem/path/query/has_extension.cc: New.
* testsuite/experimental/filesystem/path/query/has_filename.cc: New.
* testsuite/experimental/filesystem/path/query/has_parent_path.cc:
New.
* testsuite/experimental/filesystem/path/query/has_relative_path.cc:
New.
* testsuite/experimental/filesystem/path/query/has_root_directory.cc:
New.
* testsuite/experimental/filesystem/path/query/has_root_name.cc:
New.
* testsuite/experimental/filesystem/path/query/has_root_path.cc:
New.
* testsuite/experimental/filesystem/path/query/has_stem.cc: New.
* testsuite/experimental/filesystem/path/query/is_relative.cc: New.
* testsuite/util/testsuite_fs.h: New.
From-SVN: r222654
Diffstat (limited to 'libstdc++-v3/src')
-rw-r--r-- | libstdc++-v3/src/Makefile.am | 11 | ||||
-rw-r--r-- | libstdc++-v3/src/Makefile.in | 7 | ||||
-rw-r--r-- | libstdc++-v3/src/filesystem/Makefile.am | 100 | ||||
-rw-r--r-- | libstdc++-v3/src/filesystem/Makefile.in | 661 | ||||
-rw-r--r-- | libstdc++-v3/src/filesystem/dir.cc | 396 | ||||
-rw-r--r-- | libstdc++-v3/src/filesystem/ops.cc | 1169 | ||||
-rw-r--r-- | libstdc++-v3/src/filesystem/path.cc | 464 |
7 files changed, 2805 insertions, 3 deletions
diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am index debf967..a5f48b2 100644 --- a/libstdc++-v3/src/Makefile.am +++ b/libstdc++-v3/src/Makefile.am @@ -22,7 +22,13 @@ include $(top_srcdir)/fragment.am -SUBDIRS = c++98 c++11 +if ENABLE_FILESYSTEM_TS +filesystem_dir = filesystem +else +filesystem_dir = +endif + +SUBDIRS = c++98 c++11 $(filesystem_dir) # Cross compiler support. if VTV_CYGMIN @@ -52,6 +58,9 @@ endif vpath % $(top_srcdir)/src/c++98 vpath % $(top_srcdir)/src/c++11 +if ENABLE_FILESYSTEM_TS +vpath % $(top_srcdir)/src/filesystem +endif if GLIBCXX_LDBL_COMPAT ldbl_compat_sources = compatibility-ldbl.cc diff --git a/libstdc++-v3/src/Makefile.in b/libstdc++-v3/src/Makefile.in index dd9ecd1..433f9ea 100644 --- a/libstdc++-v3/src/Makefile.in +++ b/libstdc++-v3/src/Makefile.in @@ -123,7 +123,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) +DIST_SUBDIRS = c++98 c++11 filesystem ABI_TWEAKS_SRCDIR = @ABI_TWEAKS_SRCDIR@ ACLOCAL = @ACLOCAL@ ALLOCATOR_H = @ALLOCATOR_H@ @@ -346,7 +346,9 @@ WARN_CXXFLAGS = \ # -I/-D flags to pass when compiling. AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -SUBDIRS = c++98 c++11 +@ENABLE_FILESYSTEM_TS_FALSE@filesystem_dir = +@ENABLE_FILESYSTEM_TS_TRUE@filesystem_dir = filesystem +SUBDIRS = c++98 c++11 $(filesystem_dir) @VTV_CYGMIN_FALSE@toolexeclib_LTLIBRARIES = libstdc++.la # Cross compiler support. @@ -859,6 +861,7 @@ uninstall-am: uninstall-toolexeclibLTLIBRARIES vpath % $(top_srcdir)/src/c++98 vpath % $(top_srcdir)/src/c++11 +@ENABLE_FILESYSTEM_TS_TRUE@vpath % $(top_srcdir)/src/filesystem # Use special rules for compatibility-ldbl.cc compilation, as we need to # pass -mlong-double-64. diff --git a/libstdc++-v3/src/filesystem/Makefile.am b/libstdc++-v3/src/filesystem/Makefile.am new file mode 100644 index 0000000..c6e06c8 --- /dev/null +++ b/libstdc++-v3/src/filesystem/Makefile.am @@ -0,0 +1,100 @@ +## Makefile for the GNU C++ Filesystem library. +## +## Copyright (C) 2014 Free Software Foundation, Inc. +## +## Process this file with automake to produce Makefile.in. +## +## This file is part of GCC. +## +## GCC is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3, or (at your option) +## any later version. +## +## GCC is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GCC; see the file COPYING3. If not see +## <http://www.gnu.org/licenses/>. + +include $(top_srcdir)/fragment.am + +toolexeclib_LTLIBRARIES = libstdc++fs.la + +headers = + +sources = \ + dir.cc \ + ops.cc \ + path.cc + +# vpath % $(top_srcdir)/src/filesystem + +libstdc__fs_la_SOURCES = $(sources) + +# AM_CXXFLAGS needs to be in each subdirectory so that it can be +# modified in a per-library or per-sub-library way. Need to manually +# set this option because CONFIG_CXXFLAGS has to be after +# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden +# as the occasion call for it. +AM_CXXFLAGS = \ + $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \ + -std=gnu++14 \ + $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) + +AM_MAKEFLAGS = \ + "gxx_include_dir=$(gxx_include_dir)" + + +# Libtool notes + +# 1) In general, libtool expects an argument such as `--tag=CXX' when +# using the C++ compiler, because that will enable the settings +# detected when C++ support was being configured. However, when no +# such flag is given in the command line, libtool attempts to figure +# it out by matching the compiler name in each configuration section +# against a prefix of the command line. The problem is that, if the +# compiler name and its initial flags stored in the libtool +# configuration file don't match those in the command line, libtool +# can't decide which configuration to use, and it gives up. The +# correct solution is to add `--tag CXX' to LTCXXCOMPILE and maybe +# CXXLINK, just after $(LIBTOOL), so that libtool doesn't have to +# attempt to infer which configuration to use. +# +# The second tag argument, `--tag disable-shared` means that libtool +# only compiles each source once, for static objects. In actuality, +# glibcxx_lt_pic_flag and glibcxx_compiler_shared_flag are added to +# the libtool command that is used create the object, which is +# suitable for shared libraries. The `--tag disable-shared` must be +# placed after --tag CXX lest things CXX undo the affect of +# disable-shared. + +# 2) Need to explicitly set LTCXXCOMPILE so that EXTRA_CXX_FLAGS is +# last. (That way, things like -O2 passed down from the toplevel can +# be overridden by --enable-debug.) +LTCXXCOMPILE = \ + $(LIBTOOL) --tag CXX --tag disable-shared \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(TOPLEVEL_INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(EXTRA_CXX_FLAGS) + +LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) + +# 3) We'd have a problem when building the shared libstdc++ object if +# the rules automake generates would be used. We cannot allow g++ to +# be used since this would add -lstdc++ to the link line which of +# course is problematic at this point. So, we get the top-level +# directory to configure libstdc++-v3 to use gcc as the C++ +# compilation driver. +CXXLINK = \ + $(LIBTOOL) --tag CXX --tag disable-shared \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXX) \ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@ + +# By adding these files here, automake will remove them for 'make clean' +CLEANFILES = stamp-* + diff --git a/libstdc++-v3/src/filesystem/Makefile.in b/libstdc++-v3/src/filesystem/Makefile.in new file mode 100644 index 0000000..1ff2d72 --- /dev/null +++ b/libstdc++-v3/src/filesystem/Makefile.in @@ -0,0 +1,661 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +DIST_COMMON = $(top_srcdir)/fragment.am $(srcdir)/Makefile.in \ + $(srcdir)/Makefile.am +subdir = src/filesystem +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ + $(top_srcdir)/../config/enable.m4 \ + $(top_srcdir)/../config/futex.m4 \ + $(top_srcdir)/../config/iconv.m4 \ + $(top_srcdir)/../config/lead-dot.m4 \ + $(top_srcdir)/../config/lib-ld.m4 \ + $(top_srcdir)/../config/lib-link.m4 \ + $(top_srcdir)/../config/lib-prefix.m4 \ + $(top_srcdir)/../config/lthostflags.m4 \ + $(top_srcdir)/../config/multi.m4 \ + $(top_srcdir)/../config/no-executables.m4 \ + $(top_srcdir)/../config/override.m4 \ + $(top_srcdir)/../config/stdint.m4 \ + $(top_srcdir)/../config/unwind_ipinfo.m4 \ + $(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \ + $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \ + $(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/crossconfig.m4 \ + $(top_srcdir)/linkage.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/../config/gc++filt.m4 \ + $(top_srcdir)/../config/tls.m4 $(top_srcdir)/../config/gthr.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(toolexeclibdir)" +LTLIBRARIES = $(toolexeclib_LTLIBRARIES) +libstdc__fs_la_LIBADD = +am__objects_1 = dir.lo ops.lo path.lo +am_libstdc__fs_la_OBJECTS = $(am__objects_1) +libstdc__fs_la_OBJECTS = $(am_libstdc__fs_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = +am__depfiles_maybe = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +SOURCES = $(libstdc__fs_la_SOURCES) +ETAGS = etags +CTAGS = ctags +ABI_TWEAKS_SRCDIR = @ABI_TWEAKS_SRCDIR@ +ACLOCAL = @ACLOCAL@ +ALLOCATOR_H = @ALLOCATOR_H@ +ALLOCATOR_NAME = @ALLOCATOR_NAME@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +ATOMICITY_SRCDIR = @ATOMICITY_SRCDIR@ +ATOMIC_FLAGS = @ATOMIC_FLAGS@ +ATOMIC_WORD_SRCDIR = @ATOMIC_WORD_SRCDIR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASIC_FILE_CC = @BASIC_FILE_CC@ +BASIC_FILE_H = @BASIC_FILE_H@ +CC = @CC@ +CCODECVT_CC = @CCODECVT_CC@ +CCOLLATE_CC = @CCOLLATE_CC@ +CCTYPE_CC = @CCTYPE_CC@ +CFLAGS = @CFLAGS@ +CLOCALE_CC = @CLOCALE_CC@ +CLOCALE_H = @CLOCALE_H@ +CLOCALE_INTERNAL_H = @CLOCALE_INTERNAL_H@ +CMESSAGES_CC = @CMESSAGES_CC@ +CMESSAGES_H = @CMESSAGES_H@ +CMONEY_CC = @CMONEY_CC@ +CNUMERIC_CC = @CNUMERIC_CC@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPU_DEFINES_SRCDIR = @CPU_DEFINES_SRCDIR@ +CPU_OPT_BITS_RANDOM = @CPU_OPT_BITS_RANDOM@ +CPU_OPT_EXT_RANDOM = @CPU_OPT_EXT_RANDOM@ +CSTDIO_H = @CSTDIO_H@ +CTIME_CC = @CTIME_CC@ +CTIME_H = @CTIME_H@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXFILT = @CXXFILT@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +C_INCLUDE_DIR = @C_INCLUDE_DIR@ +DBLATEX = @DBLATEX@ +DEBUG_FLAGS = @DEBUG_FLAGS@ +DEFS = @DEFS@ +DOT = @DOT@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ERROR_CONSTANTS_SRCDIR = @ERROR_CONSTANTS_SRCDIR@ +EXEEXT = @EXEEXT@ +EXTRA_CXX_FLAGS = @EXTRA_CXX_FLAGS@ +FGREP = @FGREP@ +GLIBCXX_INCLUDES = @GLIBCXX_INCLUDES@ +GLIBCXX_LIBS = @GLIBCXX_LIBS@ +GREP = @GREP@ +HWCAP_FLAGS = @HWCAP_FLAGS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPTIMIZE_CXXFLAGS = @OPTIMIZE_CXXFLAGS@ +OPT_LDFLAGS = @OPT_LDFLAGS@ +OS_INC_SRCDIR = @OS_INC_SRCDIR@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ +RANLIB = @RANLIB@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYMVER_FILE = @SYMVER_FILE@ +TOPLEVEL_INCLUDES = @TOPLEVEL_INCLUDES@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VTV_CXXFLAGS = @VTV_CXXFLAGS@ +VTV_CXXLINKFLAGS = @VTV_CXXLINKFLAGS@ +VTV_PCH_CXXFLAGS = @VTV_PCH_CXXFLAGS@ +WARN_FLAGS = @WARN_FLAGS@ +WERROR = @WERROR@ +XMLLINT = @XMLLINT@ +XSLTPROC = @XSLTPROC@ +XSL_STYLE_DIR = @XSL_STYLE_DIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +baseline_dir = @baseline_dir@ +baseline_subdir_switch = @baseline_subdir_switch@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +check_msgfmt = @check_msgfmt@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_shared = @enable_shared@ +enable_static = @enable_static@ +exec_prefix = @exec_prefix@ +glibcxx_MOFILES = @glibcxx_MOFILES@ +glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@ +glibcxx_POFILES = @glibcxx_POFILES@ +glibcxx_builddir = @glibcxx_builddir@ +glibcxx_compiler_pic_flag = @glibcxx_compiler_pic_flag@ +glibcxx_compiler_shared_flag = @glibcxx_compiler_shared_flag@ +glibcxx_cxx98_abi = @glibcxx_cxx98_abi@ +glibcxx_localedir = @glibcxx_localedir@ +glibcxx_lt_pic_flag = @glibcxx_lt_pic_flag@ +glibcxx_prefixdir = @glibcxx_prefixdir@ +glibcxx_srcdir = @glibcxx_srcdir@ +glibcxx_toolexecdir = @glibcxx_toolexecdir@ +glibcxx_toolexeclibdir = @glibcxx_toolexeclibdir@ +gxx_include_dir = @gxx_include_dir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libtool_VERSION = @libtool_VERSION@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_host_flags = @lt_host_flags@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +multi_basedir = @multi_basedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +port_specific_symbol_files = @port_specific_symbol_files@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +python_mod_dir = @python_mod_dir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +thread_header = @thread_header@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +toplevel_builddir = @toplevel_builddir@ +toplevel_srcdir = @toplevel_srcdir@ + +# May be used by various substitution variables. +gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) +MAINT_CHARSET = latin1 +mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs +PWD_COMMAND = $${PWDCMD-pwd} +STAMP = echo timestamp > +toolexecdir = $(glibcxx_toolexecdir) +toolexeclibdir = $(glibcxx_toolexeclibdir) +@ENABLE_WERROR_FALSE@WERROR_FLAG = +@ENABLE_WERROR_TRUE@WERROR_FLAG = $(WERROR) +@ENABLE_EXTERN_TEMPLATE_FALSE@XTEMPLATE_FLAGS = +@ENABLE_EXTERN_TEMPLATE_TRUE@XTEMPLATE_FLAGS = -fno-implicit-templates + +# These bits are all figured out from configure. Look in acinclude.m4 +# or configure.ac to see how they are set. See GLIBCXX_EXPORT_FLAGS. +CONFIG_CXXFLAGS = \ + $(SECTION_FLAGS) $(HWCAP_FLAGS) -frandom-seed=$@ + +WARN_CXXFLAGS = \ + $(WARN_FLAGS) $(WERROR_FLAG) -fdiagnostics-show-location=once + + +# -I/-D flags to pass when compiling. +AM_CPPFLAGS = $(GLIBCXX_INCLUDES) +toolexeclib_LTLIBRARIES = libstdc++fs.la +headers = +sources = \ + dir.cc \ + ops.cc \ + path.cc + + +# vpath % $(top_srcdir)/src/filesystem +libstdc__fs_la_SOURCES = $(sources) + +# AM_CXXFLAGS needs to be in each subdirectory so that it can be +# modified in a per-library or per-sub-library way. Need to manually +# set this option because CONFIG_CXXFLAGS has to be after +# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden +# as the occasion call for it. +AM_CXXFLAGS = \ + $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \ + -std=gnu++14 \ + $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) + +AM_MAKEFLAGS = \ + "gxx_include_dir=$(gxx_include_dir)" + + +# Libtool notes + +# 1) In general, libtool expects an argument such as `--tag=CXX' when +# using the C++ compiler, because that will enable the settings +# detected when C++ support was being configured. However, when no +# such flag is given in the command line, libtool attempts to figure +# it out by matching the compiler name in each configuration section +# against a prefix of the command line. The problem is that, if the +# compiler name and its initial flags stored in the libtool +# configuration file don't match those in the command line, libtool +# can't decide which configuration to use, and it gives up. The +# correct solution is to add `--tag CXX' to LTCXXCOMPILE and maybe +# CXXLINK, just after $(LIBTOOL), so that libtool doesn't have to +# attempt to infer which configuration to use. +# +# The second tag argument, `--tag disable-shared` means that libtool +# only compiles each source once, for static objects. In actuality, +# glibcxx_lt_pic_flag and glibcxx_compiler_shared_flag are added to +# the libtool command that is used create the object, which is +# suitable for shared libraries. The `--tag disable-shared` must be +# placed after --tag CXX lest things CXX undo the affect of +# disable-shared. + +# 2) Need to explicitly set LTCXXCOMPILE so that EXTRA_CXX_FLAGS is +# last. (That way, things like -O2 passed down from the toplevel can +# be overridden by --enable-debug.) +LTCXXCOMPILE = \ + $(LIBTOOL) --tag CXX --tag disable-shared \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(TOPLEVEL_INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(EXTRA_CXX_FLAGS) + +LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) + +# 3) We'd have a problem when building the shared libstdc++ object if +# the rules automake generates would be used. We cannot allow g++ to +# be used since this would add -lstdc++ to the link line which of +# course is problematic at this point. So, we get the top-level +# directory to configure libstdc++-v3 to use gcc as the C++ +# compilation driver. +CXXLINK = \ + $(LIBTOOL) --tag CXX --tag disable-shared \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXX) \ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@ + + +# By adding these files here, automake will remove them for 'make clean' +CLEANFILES = stamp-* +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/fragment.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps src/filesystem/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps src/filesystem/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)" + @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \ + } + +uninstall-toolexeclibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \ + done + +clean-toolexeclibLTLIBRARIES: + -test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES) + @list='$(toolexeclib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstdc++fs.la: $(libstdc__fs_la_OBJECTS) $(libstdc__fs_la_DEPENDENCIES) + $(CXXLINK) -rpath $(toolexeclibdir) $(libstdc__fs_la_OBJECTS) $(libstdc__fs_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.cc.o: + $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: + $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: + $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(toolexeclibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-toolexeclibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-toolexeclibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-toolexeclibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-toolexeclibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip install-toolexeclibLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-toolexeclibLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc new file mode 100644 index 0000000..4ed869e --- /dev/null +++ b/libstdc++-v3/src/filesystem/dir.cc @@ -0,0 +1,396 @@ +// Class filesystem::directory_entry etc. -*- C++ -*- + +// Copyright (C) 2014-2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +#include <experimental/filesystem> +#include <utility> +#include <stack> +#include <tuple> +#include <string.h> +#include <errno.h> +#ifdef _GLIBCXX_HAVE_DIRENT_H +# ifdef _GLIBCXX_HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# include <dirent.h> +#else +// TODO: replace dummy definitions with suitable Win32 code +#ifndef EACCES +# define EACCES static_cast<int>(std::errc::permission_denied) +#endif +using DIR = void; +using P = std::experimental::filesystem::path; +static DIR* opendir(const P::value_type*) { return nullptr; } +static void closedir(DIR*) { } +struct dirent { const char* d_name; }; +static inline int readdir_r(DIR*, dirent*, dirent**) +{ return static_cast<int>(std::errc::not_supported); } +#endif + +namespace fs = std::experimental::filesystem; + +namespace +{ + struct ErrorCode + { + ErrorCode(std::error_code* p) : ec(p) { } + + ErrorCode(ErrorCode&& e) : ec(std::exchange(e.ec, nullptr)) { } + + ~ErrorCode() { if (ec) ec->clear(); } + + void assign(int err) + { + ec->assign(err, std::generic_category()); + ec = nullptr; + } + + explicit operator bool() { return ec != nullptr; } + + std::error_code* ec; + }; +} + +struct fs::_Dir +{ + _Dir() : dirp(nullptr) { } + + _Dir(DIR* dirp, const fs::path& path) : dirp(dirp), path(path) { } + + _Dir(_Dir&& d) + : dirp(std::exchange(d.dirp, nullptr)), path(std::move(d.path)), + entry(std::move(d.entry)), type(d.type) + { } + + _Dir& operator=(_Dir&&) = delete; + + ~_Dir() { if (dirp) ::closedir(dirp); } + + bool advance(ErrorCode); + + DIR* dirp; + fs::path path; + directory_entry entry; + file_type type = file_type::none; +}; + +namespace +{ + template<typename Bitmask> + bool is_set(Bitmask obj, Bitmask bits) + { + return (obj & bits) != Bitmask::none; + } + + fs::_Dir + opendir(const fs::path& p, fs::directory_options options, ErrorCode ec) + { + if (DIR* dirp = ::opendir(p.c_str())) + return {dirp, p}; + + const int err = errno; + if (err == EACCES + && is_set(options, fs::directory_options::skip_permission_denied)) + return {}; + + if (!ec) + _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error( + "directory iterator cannot open directory", p, + std::error_code(err, std::generic_category()))); + + ec.assign(err); + return {}; + } + + inline std::shared_ptr<fs::_Dir> + make_shared_dir(fs::_Dir&& dir) + { + if (dir.dirp) + return std::make_shared<fs::_Dir>(std::move(dir)); + return {}; + } + + inline fs::file_type + get_file_type(const dirent& d __attribute__((__unused__))) + { +#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE + switch (d.d_type) + { + case DT_BLK: + return fs::file_type::block; + case DT_CHR: + return fs::file_type::character; + case DT_DIR: + return fs::file_type::directory; + case DT_FIFO: + return fs::file_type::fifo; + case DT_LNK: + return fs::file_type::symlink; + case DT_REG: + return fs::file_type::regular; + case DT_SOCK: + return fs::file_type::socket; + case DT_UNKNOWN: + return fs::file_type::unknown; + default: + return fs::file_type::none; + } +#else + return fs::file_type::none; +#endif + } +} + +bool +fs::_Dir::advance(ErrorCode ec) +{ + ::dirent ent; + ::dirent* result; + if (int err = readdir_r(dirp, &ent, &result)) + { + if (!ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "directory iterator cannot advance", + std::error_code(err, std::generic_category()))); + ec.assign(err); + return true; + } + else if (result != nullptr) + { + // skip past dot and dot-dot + if (!strcmp(ent.d_name, ".") || !strcmp(ent.d_name, "..")) + return advance(std::move(ec)); + entry = fs::directory_entry{path / ent.d_name}; + type = get_file_type(ent); + return true; + } + else + { + // reached the end + entry = {}; + type = fs::file_type::none; + return false; + } +} + +fs::directory_iterator:: +directory_iterator(const path& p, directory_options options, error_code* ec) +: directory_iterator(make_shared_dir(opendir(p, options, ec)), ec) +{ } + +fs::directory_iterator:: +directory_iterator(std::shared_ptr<_Dir> dir, error_code* ec) +: _M_dir(std::move(dir)) +{ + if (_M_dir && !_M_dir->advance(ec)) + _M_dir.reset(); +} + +const fs::directory_entry& +fs::directory_iterator::operator*() const +{ + if (!_M_dir) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "non-dereferenceable directory iterator", + std::make_error_code(errc::invalid_argument))); + return _M_dir->entry; +} + +fs::directory_iterator& +fs::directory_iterator::operator++() +{ + if (!_M_dir) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "cannot advance non-dereferenceable directory iterator", + std::make_error_code(errc::invalid_argument))); + if (!_M_dir->advance(nullptr)) + _M_dir.reset(); + return *this; +} + +fs::directory_iterator& +fs::directory_iterator::increment(error_code& ec) noexcept +{ + if (!_M_dir) + { + ec = std::make_error_code(errc::invalid_argument); + return *this; + } + if (!_M_dir->advance(&ec)) + _M_dir.reset(); + return *this; +} + +using Dir_iter_pair = std::pair<fs::_Dir, fs::directory_iterator>; + +struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir> +{ + void clear() { c.clear(); } +}; + +fs::recursive_directory_iterator:: +recursive_directory_iterator(const path& p, directory_options options, + error_code* ec) +: _M_options(options), _M_pending(true) +{ + if (DIR* dirp = ::opendir(p.c_str())) + { + _M_dirs = std::make_shared<_Dir_stack>(); + _M_dirs->push(_Dir{ dirp, p }); + if (!_M_dirs->top().advance(ec)) + _M_dirs.reset(); + } + else + { + const int err = errno; + if (err == EACCES + && is_set(options, fs::directory_options::skip_permission_denied)) + return; + + if (!ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "recursive directory iterator cannot open directory", p, + std::error_code(err, std::generic_category()))); + + ec->assign(err, std::generic_category()); + } +} + +fs::recursive_directory_iterator::~recursive_directory_iterator() = default; + +int +fs::recursive_directory_iterator::depth() const +{ + return int(_M_dirs->size()) - 1; +} + +const fs::directory_entry& +fs::recursive_directory_iterator::operator*() const +{ + return _M_dirs->top().entry; +} + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator:: +operator=(const recursive_directory_iterator& other) noexcept = default; + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator:: +operator=(recursive_directory_iterator&& other) noexcept = default; + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator::operator++() +{ + error_code ec; + increment(ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "cannot increment recursive directory iterator", ec)); + return *this; +} + +namespace +{ + bool + recurse(const fs::_Dir& d, fs::directory_options options, std::error_code& ec) + { + bool follow_symlink + = is_set(options, fs::directory_options::follow_directory_symlink); +#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE + if (d.type == fs::file_type::directory) + return true; + if (d.type == fs::file_type::symlink && follow_symlink) + return d.entry.status().type() == fs::file_type::directory; + if (d.type != fs::file_type::none && d.type != fs::file_type::unknown) + return false; +#endif + const fs::path& path = d.entry.path(); + auto type = fs::symlink_status(path, ec).type(); + if (ec.value()) + return false; + if (type == fs::file_type::symlink) + { + if (!follow_symlink) + return false; + type = fs::status(path, ec).type(); + } + return type == fs::file_type::directory; + } +} + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator::increment(error_code& ec) noexcept +{ + if (!_M_dirs) + { + ec = std::make_error_code(errc::invalid_argument); + return *this; + } + + auto& top = _M_dirs->top(); + + if (std::exchange(_M_pending, true) && recurse(top, _M_options, ec)) + { + _Dir dir = opendir(top.entry.path(), _M_options, &ec); + if (ec.value()) + return *this; + if (dir.dirp) + { + _M_dirs->push(std::move(dir)); + if (!_M_dirs->top().advance(&ec)) // dir is empty + pop(); + return *this; + } + // else skip permission denied and continue in parent dir + } + + ec.clear(); + while (!_M_dirs->top().advance(&ec) && !ec.value()) + { + _M_dirs->pop(); + if (_M_dirs->empty()) + { + _M_dirs.reset(); + return *this; + } + } + return *this; +} + +void +fs::recursive_directory_iterator::pop() +{ + if (!_M_dirs) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "cannot pop non-dereferenceable recursive directory iterator", + std::make_error_code(errc::invalid_argument))); + + do { + _M_dirs->pop(); + if (_M_dirs->empty()) + { + _M_dirs.reset(); + return; + } + } while (!_M_dirs->top().advance(nullptr)); +} diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc new file mode 100644 index 0000000..091ca72 --- /dev/null +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -0,0 +1,1169 @@ +// Filesystem operations -*- C++ -*- + +// Copyright (C) 2014-2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +#include <experimental/filesystem> +#include <functional> +#include <stack> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#ifdef _GLIBCXX_HAVE_UNISTD_H +# include <unistd.h> +# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H) +# include <sys/types.h> +# include <sys/stat.h> +# endif +#endif +#ifdef _GLIBCXX_HAVE_FCNTL_H +# include <fcntl.h> +#endif +#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H +# include <sys/statvfs.h> +#endif +#ifdef _GLIBCXX_HAVE_GNU_SENDFILE +# include <sys/sendfile.h> +#else +# include <ext/stdio_filebuf.h> +# include <ostream> +#endif + +namespace fs = std::experimental::filesystem; + +fs::path +fs::absolute(const path& p, const path& base) +{ + const bool has_root_dir = p.has_root_directory(); + const bool has_root_name = p.has_root_name(); + path abs; + if (has_root_dir && has_root_name) + abs = p; + else + { + abs = base.is_absolute() ? base : absolute(base); + if (has_root_dir) + abs = abs.root_name() / p; + else if (has_root_name) + abs = p.root_name() / abs.root_directory() / abs.relative_path() + / p.relative_path(); + else + abs = abs / p; + } + return abs; +} + +namespace +{ + struct free_as_in_malloc + { + void operator()(void* p) const { ::free(p); } + }; + + using char_ptr = std::unique_ptr<char[], free_as_in_malloc>; +} + +fs::path +fs::canonical(const path& p, const path& base, error_code& ec) +{ + path can; +#ifdef _GLIBCXX_USE_REALPATH + if (char_ptr rp = char_ptr{::realpath(absolute(p, base).c_str(), nullptr)}) + { + can.assign(rp.get()); + ec.clear(); + } + else + ec.assign(errno, std::generic_category()); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif + return can; +} + +fs::path +fs::canonical(const path& p, error_code& ec) +{ + path cur = current_path(ec); + if (ec.value()) + return {}; + return canonical(p, cur, ec); +} + +fs::path +fs::canonical(const path& p, const path& base) +{ + error_code ec; + path can = canonical(p, base, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, ec)); + return can; +} + +void +fs::copy(const path& from, const path& to, copy_options options) +{ + error_code ec; + copy(from, to, options, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec)); +} + +namespace +{ + template<typename Bitmask> + bool is_set(Bitmask obj, Bitmask bits) + { + return (obj & bits) != Bitmask::none; + } +} + +#ifdef _GLIBCXX_HAVE_SYS_STAT_H +namespace +{ + fs::file_status + make_file_status(const struct ::stat& st) + { + using fs::file_status; + using fs::file_type; + using fs::perms; + file_type ft; + perms perm = static_cast<perms>(st.st_mode) & perms::mask; +#ifdef _GLIBCXX_HAVE_S_ISREG + if (S_ISREG(st.st_mode)) + ft = file_type::regular; + else if (S_ISDIR(st.st_mode)) + ft = file_type::directory; + else if (S_ISCHR(st.st_mode)) + ft = file_type::character; + else if (S_ISBLK(st.st_mode)) + ft = file_type::block; + else if (S_ISFIFO(st.st_mode)) + ft = file_type::fifo; + else if (S_ISLNK(st.st_mode)) + ft = file_type::symlink; + else if (S_ISSOCK(st.st_mode)) + ft = file_type::socket; + else +#endif + ft = file_type::unknown; + return file_status{ft, perm}; + } + + inline bool + is_not_found_errno(int err) + { + return err == ENOENT || err == ENOTDIR; + } + + inline fs::file_time_type + file_time(const struct ::stat& st) + { + using namespace std::chrono; + return fs::file_time_type{ +#ifdef _GLIBCXX_USE_ST_MTIM + seconds{st.st_mtim.tv_sec} + nanoseconds{st.st_mtim.tv_nsec} +#else + seconds{st.st_mtime} +#endif + }; + } + + bool + do_copy_file(const fs::path& from, const fs::path& to, + fs::copy_options option, + struct ::stat* from_st, struct ::stat* to_st, + std::error_code& ec) noexcept + { + struct ::stat st1, st2; + fs::file_status t, f; + + if (to_st == nullptr) + { + if (::stat(to.c_str(), &st1)) + { + int err = errno; + if (!is_not_found_errno(err)) + { + ec.assign(err, std::generic_category()); + return false; + } + } + else + to_st = &st1; + } + else if (to_st == from_st) + to_st = nullptr; + + if (to_st == nullptr) + t = fs::file_status{fs::file_type::not_found}; + else + t = make_file_status(*to_st); + + if (from_st == nullptr) + { + if (::stat(from.c_str(), &st2)) + { + ec.assign(errno, std::generic_category()); + return false; + } + else + from_st = &st2; + } + f = make_file_status(*from_st); + + if (exists(t)) + { + if (!is_other(t) && !is_other(f) + && to_st->st_dev == from_st->st_dev + && to_st->st_ino == from_st->st_ino) + { + ec = std::make_error_code(std::errc::file_exists); + return false; + } + + if (is_set(option, fs::copy_options::skip_existing)) + { + ec.clear(); + return false; + } + else if (is_set(option, fs::copy_options::update_existing)) + { + if (file_time(*from_st) <= file_time(*to_st)) + { + ec.clear(); + return false; + } + } + else if (!is_set(option, fs::copy_options::overwrite_existing)) + { + ec = std::make_error_code(std::errc::file_exists); + return false; + } + } + + struct CloseFD { + ~CloseFD() { if (fd != -1) ::close(fd); } + int fd; + }; + + CloseFD in = { ::open(from.c_str(), O_RDONLY) }; + if (in.fd == -1) + { + ec.assign(errno, std::generic_category()); + return false; + } + CloseFD out = { ::open(to.c_str(), O_WRONLY|O_CREAT) }; + if (out.fd == -1) + { + ec.assign(errno, std::generic_category()); + return false; + } + +#ifdef _GLIBCXX_HAVE_GNU_SENDFILE + auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size); + if (n != from_st->st_size) + { + ec.assign(errno, std::generic_category()); + return false; + } +#else + __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in); + __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out); + if (std::ostream(&sbout) << &sbin) + { + ec.clear(); + return true; + } + else + { + ec = std::make_error_code(std::errc::io_error); + return false; + } +#endif + +#ifdef _GLIBCXX_HAVE_FCHMOD + if (::fchmod(out.fd, from_st->st_mode)) +#else + if (::chmod(to.c_str(), from_st->st_mode)) +#endif + { + ec.assign(errno, std::generic_category()); + return false; + } + return true; + } +} +#endif + +void +fs::copy(const path& from, const path& to, copy_options options, + error_code& ec) noexcept +{ + bool skip_symlinks = is_set(options, copy_options::skip_symlinks); + bool create_symlinks = is_set(options, copy_options::create_symlinks); + bool use_lstat = create_symlinks || skip_symlinks; + + file_status f, t; + struct ::stat from_st, to_st; + if (use_lstat + ? ::lstat(from.c_str(), &from_st) + : ::stat(from.c_str(), &from_st)) + { + ec.assign(errno, std::generic_category()); + return; + } + if (use_lstat + ? ::lstat(to.c_str(), &to_st) + : ::stat(to.c_str(), &to_st)) + { + if (!is_not_found_errno(errno)) + { + ec.assign(errno, std::generic_category()); + return; + } + t = file_status{file_type::not_found}; + } + else + t = make_file_status(to_st); + f = make_file_status(from_st); + + if (exists(t) && !is_other(t) && !is_other(f) + && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino) + { + ec = std::make_error_code(std::errc::file_exists); + return; + } + if (is_other(f) || is_other(t)) + { + ec = std::make_error_code(std::errc::not_supported); + return; + } + if (is_directory(f) && is_regular_file(t)) + { + ec = std::make_error_code(std::errc::is_a_directory); + return; + } + + if (is_symlink(f)) + { + if (skip_symlinks) + ec.clear(); + else if (!exists(t) && is_set(options, copy_options::copy_symlinks)) + copy_symlink(from, to, ec); + else + // Not clear what should be done here. + // "Otherwise report an error as specified in Error reporting (7)." + ec = std::make_error_code(std::errc::invalid_argument); + } + else if (is_regular_file(f)) + { + if (is_set(options, copy_options::directories_only)) + ec.clear(); + else if (create_symlinks) + create_symlink(from, to, ec); + else if (is_set(options, copy_options::create_hard_links)) + create_hard_link(from, to, ec); + else if (is_directory(t)) + do_copy_file(from, to / from.filename(), options, &from_st, 0, ec); + else + { + auto ptr = exists(t) ? &to_st : &from_st; + do_copy_file(from, to, options, &from_st, ptr, ec); + } + } + else if (is_directory(f) && (is_set(options, copy_options::recursive) + || options == copy_options::none)) + { + if (!exists(t)) + if (!create_directory(to, from, ec)) + return; + // set an unused bit in options to disable further recursion + if (!is_set(options, copy_options::recursive)) + options |= static_cast<copy_options>(4096); + for (const directory_entry& x : directory_iterator(from)) + copy(x.path(), to/x.path().filename(), options, ec); + } + // "Otherwise no effects." (should ec.clear() be called?) +} + +bool +fs::copy_file(const path& from, const path& to, copy_options option) +{ + error_code ec; + bool result = copy_file(from, to, option, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to, + ec)); + return result; +} + +bool +fs::copy_file(const path& from, const path& to, copy_options option, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + return do_copy_file(from, to, option, nullptr, nullptr, ec); +#else + ec = std::make_error_code(std::errc::not_supported); + return false; +#endif +} + + +void +fs::copy_symlink(const path& existing_symlink, const path& new_symlink) +{ + error_code ec; + copy_symlink(existing_symlink, new_symlink, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink", + existing_symlink, new_symlink, ec)); +} + +void +fs::copy_symlink(const path& existing_symlink, const path& new_symlink, + error_code& ec) noexcept +{ + auto p = read_symlink(existing_symlink, ec); + if (ec.value()) + return; +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + if (is_directory(p)) + { + create_directory_symlink(p, new_symlink, ec); + return; + } +#endif + create_symlink(p, new_symlink, ec); +} + + +bool +fs::create_directories(const path& p) +{ + error_code ec; + bool result = create_directories(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p, + ec)); + return result; +} + +bool +fs::create_directories(const path& p, error_code& ec) noexcept +{ + std::stack<path> missing; + path pp = p; + ec.clear(); + while (!p.empty() && !exists(pp, ec) && !ec.value()) + { + missing.push(pp); + pp = pp.parent_path(); + } + while (!missing.empty() && !ec.value()) + { + create_directory(missing.top(), ec); + missing.pop(); + } + return missing.empty(); +} + +namespace +{ + bool + create_dir(const fs::path& p, fs::perms perm, std::error_code& ec) + { +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm); + if (::mkdir(p.c_str(), mode)) + { + ec.assign(errno, std::generic_category()); + return false; + } + else + { + ec.clear(); + return true; + } +#else + ec = std::make_error_code(std::errc::not_supported); + return false; +#endif + } +} // namespace + +bool +fs::create_directory(const path& p) +{ + error_code ec; + bool result = create_directory(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, + ec)); + return result; +} + +bool +fs::create_directory(const path& p, error_code& ec) noexcept +{ + return create_dir(p, perms::all, ec); +} + + +bool +fs::create_directory(const path& p, const path& attributes) +{ + error_code ec; + bool result = create_directory(p, attributes, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, + ec)); + return result; +} + +bool +fs::create_directory(const path& p, const path& attributes, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + struct ::stat st; + if (::stat(attributes.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return false; + } + return create_dir(p, static_cast<perms>(st.st_mode), ec); +#else + ec = std::make_error_code(std::errc::not_supported); + return false; +#endif +} + + +void +fs::create_directory_symlink(const path& to, const path& new_symlink) +{ + error_code ec; + create_directory_symlink(to, new_symlink, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink", + to, new_symlink, ec)); +} + +void +fs::create_directory_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + ec = std::make_error_code(std::errc::not_supported); +#else + create_symlink(to, new_symlink, ec); +#endif +} + + +void +fs::create_hard_link(const path& to, const path& new_hard_link) +{ + error_code ec; + create_hard_link(to, new_hard_link, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link", + to, new_hard_link, ec)); +} + +void +fs::create_hard_link(const path& to, const path& new_hard_link, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (::link(to.c_str(), new_hard_link.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + +void +fs::create_symlink(const path& to, const path& new_symlink) +{ + error_code ec; + create_symlink(to, new_symlink, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink", + to, new_symlink, ec)); +} + +void +fs::create_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (::symlink(to.c_str(), new_symlink.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + + +fs::path +fs::current_path() +{ + error_code ec; + path p = current_path(ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec)); + return p; +} + +fs::path +fs::current_path(error_code& ec) +{ + path p; +#ifdef _GLIBCXX_HAVE_UNISTD_H +#ifdef __GLIBC__ + if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)}) + { + p.assign(cwd.get()); + ec.clear(); + } + else + ec.assign(errno, std::generic_category()); +#else + long path_max = pathconf(".", _PC_PATH_MAX); + size_t size; + if (path_max == -1) + size = 1024; + else if (path_max > 10240) + size = 10240; + else + size = path_max; + for (char_ptr buf; p.empty(); size *= 2) + { + buf.reset((char*)malloc(size)); + if (buf) + { + if (getcwd(buf.get(), size)) + { + p.assign(buf.get()); + ec.clear(); + } + else if (errno != ERANGE) + { + ec.assign(errno, std::generic_category()); + return {}; + } + } + else + { + ec = std::make_error_code(std::errc::not_enough_memory); + return {}; + } + } +#endif // __GLIBC__ +#else // _GLIBCXX_HAVE_UNISTD_H + ec = std::make_error_code(std::errc::not_supported); +#endif + return p; +} + +void +fs::current_path(const path& p) +{ + error_code ec; + current_path(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec)); +} + +void +fs::current_path(const path& p, error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (int err = ::chdir(p.c_str())) + ec.assign(err, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + +bool +fs::equivalent(const path& p1, const path& p2) +{ + error_code ec; + auto result = equivalent(p1, p2, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence", + p1, p2, ec)); + return result; +} + +bool +fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + struct ::stat st1, st2; + if (::stat(p1.c_str(), &st1) == 0 && ::stat(p2.c_str(), &st2) == 0) + { + file_status s1 = make_file_status(st1); + file_status s2 = make_file_status(st2); + if (is_other(s1) && is_other(s2)) + { + ec = std::make_error_code(std::errc::not_supported); + return false; + } + ec.clear(); + return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; + } + else if (is_not_found_errno(errno)) + { + ec = std::make_error_code(std::errc::no_such_file_or_directory); + return false; + } + ec.assign(errno, std::generic_category()); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif + return false; +} + +std::uintmax_t +fs::file_size(const path& p) +{ + error_code ec; + auto sz = file_size(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec)); + return sz; +} + +namespace +{ + template<typename Accessor, typename T> + T + do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt) + { +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + struct ::stat st; + if (::stat(p.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return deflt; + } + ec.clear(); + return f(st); +#else + ec = std::make_error_code(std::errc::not_supported); + return deflt; +#endif + } +} + +std::uintmax_t +fs::file_size(const path& p, error_code& ec) noexcept +{ + return do_stat(p, ec, std::mem_fn(&stat::st_size), + static_cast<uintmax_t>(-1)); +} + +std::uintmax_t +fs::hard_link_count(const path& p) +{ + error_code ec; + auto count = hard_link_count(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec)); + return count; +} + +std::uintmax_t +fs::hard_link_count(const path& p, error_code& ec) noexcept +{ + return do_stat(p, ec, std::mem_fn(&stat::st_nlink), + static_cast<uintmax_t>(-1)); +} + +bool +fs::is_empty(const path& p) +{ + return fs::is_directory(status(p)) + ? fs::directory_iterator(p) == fs::directory_iterator() + : fs::file_size(p) == 0; +} + +bool +fs::is_empty(const path& p, error_code& ec) noexcept +{ + auto s = status(p, ec); + if (ec.value()) + return false; + return fs::is_directory(s) + ? fs::directory_iterator(p, ec) == fs::directory_iterator() + : fs::file_size(p, ec) == 0; +} + +fs::file_time_type +fs::last_write_time(const path& p) +{ + error_code ec; + auto t = last_write_time(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec)); + return t; +} + +fs::file_time_type +fs::last_write_time(const path& p, error_code& ec) noexcept +{ + return do_stat(p, ec, [](const auto& st) { return file_time(st); }, + file_time_type::min()); +} + +void +fs::last_write_time(const path& p, file_time_type new_time) +{ + error_code ec; + last_write_time(p, new_time, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec)); +} + +void +fs::last_write_time(const path& p __attribute__((__unused__)), + file_time_type new_time, error_code& ec) noexcept +{ + auto d = new_time.time_since_epoch(); + auto s = chrono::duration_cast<chrono::seconds>(d); + auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s); +#ifdef _GLIBCXX_USE_UTIMENSAT + struct ::timespec ts[2] = { + { 0, UTIME_OMIT }, + { static_cast<std::time_t>(s.count()), static_cast<long>(ns.count()) } + }; + if (utimensat(AT_FDCWD, p.c_str(), ts, 0)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + +void +fs::permissions(const path& p, perms prms) +{ + error_code ec; + permissions(p, prms, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec)); +} + +void fs::permissions(const path& p, perms prms, error_code& ec) noexcept +{ + if (int err = ::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0)) + ec.assign(err, std::generic_category()); + else + ec.clear(); +} + +fs::path +fs::read_symlink(const path& p) +{ + error_code ec; + path tgt = read_symlink(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec)); + return tgt; +} + +fs::path fs::read_symlink(const path& p, error_code& ec) +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + struct ::stat st; + if (::lstat(p.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return {}; + } + std::string buf(st.st_size, '\0'); + ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); + if (len == -1) + { + ec.assign(errno, std::generic_category()); + return {}; + } + return path{buf.data(), buf.data()+len}; +#else + ec = std::make_error_code(std::errc::not_supported); + return {}; +#endif +} + + +bool +fs::remove(const path& p) +{ + error_code ec; + bool result = fs::remove(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec)); + return result; +} + +bool +fs::remove(const path& p, error_code& ec) noexcept +{ + if (exists(symlink_status(p, ec))) + { + if (::remove(p.c_str()) == 0) + { + ec.clear(); + return true; + } + else + ec.assign(errno, std::generic_category()); + } + return false; +} + + +std::uintmax_t +fs::remove_all(const path& p) +{ + error_code ec; + bool result = remove_all(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec)); + return result; +} + +std::uintmax_t +fs::remove_all(const path& p, error_code& ec) noexcept +{ + auto fs = symlink_status(p, ec); + uintmax_t count = 0; + if (ec.value() == 0 && fs.type() == file_type::directory) + for (directory_iterator d(p, ec), end; ec.value() == 0 && d != end; ++d) + count += fs::remove(d->path(), ec); + if (ec.value()) + return -1; + return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear() +} + +void +fs::rename(const path& from, const path& to) +{ + error_code ec; + rename(from, to, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec)); +} + +void +fs::rename(const path& from, const path& to, error_code& ec) noexcept +{ + if (::rename(from.c_str(), to.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +} + +void +fs::resize_file(const path& p, uintmax_t size) +{ + error_code ec; + resize_file(p, size, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec)); +} + +void +fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max())) + ec.assign(EINVAL, std::generic_category()); + else if (::truncate(p.c_str(), size)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + + +fs::space_info +fs::space(const path& p) +{ + error_code ec; + space_info s = space(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec)); + return s; +} + +fs::space_info +fs::space(const path& p, error_code& ec) noexcept +{ + space_info info = { + static_cast<uintmax_t>(-1), + static_cast<uintmax_t>(-1), + static_cast<uintmax_t>(-1) + }; +#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H + struct ::statvfs f; + if (int err = ::statvfs(p.c_str(), &f)) + ec.assign(err, std::generic_category()); + else + { + info = space_info{ + f.f_blocks * f.f_frsize, + f.f_bfree * f.f_frsize, + f.f_bavail * f.f_frsize + }; + ec.clear(); + } +#endif + return info; +} + +#ifdef _GLIBCXX_HAVE_SYS_STAT_H +fs::file_status +fs::status(const fs::path& p, std::error_code& ec) noexcept +{ + file_status status; + struct ::stat st; + if (::stat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); + if (is_not_found_errno(err)) + status = file_status{file_type::not_found}; + } + else + { + status = make_file_status(st); + ec.clear(); + } + return status; +} + +fs::file_status +fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept +{ + file_status status; + struct ::stat st; + if (::lstat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); + if (is_not_found_errno(err)) + status = file_status{file_type::not_found}; + } + else + { + status = make_file_status(st); + ec.clear(); + } + return status; +} +#endif + +fs::file_status +fs::status(const fs::path& p) +{ + std::error_code ec; + auto s = status(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec)); + return s; +} + +fs::file_status +fs::symlink_status(const fs::path& p) +{ + std::error_code ec; + auto s = symlink_status(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", ec)); + return s; +} + +fs::path +fs::system_complete(const path& p) +{ + error_code ec; + path comp = system_complete(p, ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec)); + return comp; +} + +fs::path +fs::system_complete(const path& p, error_code& ec) +{ + path base = current_path(ec); +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + if (p.is_absolute() || !p.has_root_name() + || p.root_name() == base.root_name()) + return absolute(p, base); + // else TODO + ec = std::make_error_code(std::errc::not_supported); + return {}; +#else + if (ec.value()) + return {}; + return absolute(p, base); +#endif +} + +fs::path fs::temp_directory_path() +{ + error_code ec; + path tmp = temp_directory_path(ec); + if (ec.value()) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec)); + return tmp; +} + +fs::path fs::temp_directory_path(error_code& ec) +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + return {}; // TODO +#else + const char* tmpdir = ::getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + ec.clear(); + return tmpdir; +#endif +} + diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc new file mode 100644 index 0000000..db58f3b --- /dev/null +++ b/libstdc++-v3/src/filesystem/path.cc @@ -0,0 +1,464 @@ +// Class filesystem::path -*- C++ -*- + +// Copyright (C) 2014-2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +#include <experimental/filesystem> + +using std::experimental::filesystem::path; + +constexpr path::value_type path::preferred_separator; + +path& +path::remove_filename() +{ + if (_M_type == _Type::_Multi) + { + if (!_M_cmpts.empty()) + { + auto cmpt = --_M_cmpts.end(); + _M_pathname.erase(cmpt->_M_pos); + _M_cmpts.erase(cmpt); + _M_trim(); + } + } + else + clear(); + return *this; +} + +path& +path::replace_filename(const path& replacement) +{ + remove_filename(); + operator/=(replacement); + return *this; +} + +path& +path::replace_extension(const path& replacement) +{ + auto ext = _M_find_extension(); + if (ext.first && ext.second != string_type::npos) + { + if (ext.first == &_M_pathname) + _M_pathname.erase(ext.second); + else + { + const auto& back = _M_cmpts.back(); + if (ext.first != &back._M_pathname) + _GLIBCXX_THROW_OR_ABORT( + std::logic_error("path::replace_extension failed")); + _M_pathname.erase(back._M_pos + ext.second); + } + } + if (!replacement.empty() && replacement.native()[0] != '.') + _M_pathname += '.'; + _M_pathname += replacement.native(); + _M_split_cmpts(); + return *this; +} + +namespace +{ + template<typename Iter1, typename Iter2> + int do_compare(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) + { + int cmpt = 1; + while (begin1 != end1 && begin2 != end2) + { + if (begin1->native() < begin2->native()) + return -cmpt; + if (begin1->native() > begin2->native()) + return +cmpt; + ++begin1; + ++begin2; + ++cmpt; + } + if (begin1 == end1) + { + if (begin2 == end2) + return 0; + return -cmpt; + } + return +cmpt; + } +} + +int +path::compare(const path& p) const noexcept +{ + if (_M_type == _Type::_Multi && p._M_type == _Type::_Multi) + return do_compare(_M_cmpts.begin(), _M_cmpts.end(), + p._M_cmpts.begin(), p._M_cmpts.end()); + else if (_M_type == _Type::_Multi) + { + _Cmpt c[1] = { { p._M_pathname, p._M_type, 0 } }; + return do_compare(_M_cmpts.begin(), _M_cmpts.end(), c, c+1); + } + else if (p._M_type == _Type::_Multi) + { + _Cmpt c[1] = { { _M_pathname, _M_type, 0 } }; + return do_compare(c, c+1, p._M_cmpts.begin(), p._M_cmpts.end()); + } + else + return _M_pathname.compare(p._M_pathname); +} + +path +path::root_name() const +{ + path __ret; + if (_M_type == _Type::_Root_name) + __ret = *this; + else if (_M_cmpts.size() + && _M_cmpts.begin()->_M_type == _Type::_Root_name) + __ret = *_M_cmpts.begin(); + return __ret; +} + +path +path::root_directory() const +{ + path __ret; + if (_M_type == _Type::_Root_dir) + __ret = *this; + else if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + __ret = *__it; + } + return __ret; +} + + +path +path::root_path() const +{ + path __ret; + if (_M_type == _Type::_Root_name || _M_type == _Type::_Root_dir) + __ret = *this; + else if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + { + __ret = *__it++; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + { + __ret._M_pathname += preferred_separator; + __ret._M_split_cmpts(); + } + } + else if (__it->_M_type == _Type::_Root_dir) + __ret = *__it; + } + return __ret; +} + +path +path::relative_path() const +{ + path __ret; + if (_M_type == _Type::_Filename) + __ret = *this; + else if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + ++__it; + if (__it != _M_cmpts.end()) + __ret.assign(_M_pathname.substr(__it->_M_pos)); + } + return __ret; +} + +path +path::parent_path() const +{ + path __ret; + if (_M_cmpts.size() < 2) + return __ret; + for (auto __it = _M_cmpts.begin(), __end = --_M_cmpts.end(); + __it != __end; ++__it) + { + __ret /= *__it; + } + return __ret; +} + +bool +path::has_root_name() const +{ + if (_M_type == _Type::_Root_name) + return true; + if (!_M_cmpts.empty() && _M_cmpts.begin()->_M_type == _Type::_Root_name) + return true; + return false; +} + +bool +path::has_root_directory() const +{ + if (_M_type == _Type::_Root_dir) + return true; + if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + return true; + } + return false; +} + +bool +path::has_root_path() const +{ + if (_M_type == _Type::_Root_name || _M_type == _Type::_Root_dir) + return true; + if (!_M_cmpts.empty()) + { + auto __type = _M_cmpts.front()._M_type; + if (__type == _Type::_Root_name || __type == _Type::_Root_dir) + return true; + } + return false; +} + +bool +path::has_relative_path() const +{ + if (_M_type == _Type::_Filename) + return true; + if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + ++__it; + if (__it != _M_cmpts.end()) + return true; + } + return false; +} + + +bool +path::has_parent_path() const +{ + return _M_cmpts.size() > 1; +} + +bool +path::has_filename() const +{ + return !empty(); +} + +std::pair<const path::string_type*, std::size_t> +path::_M_find_extension() const +{ + const std::string* s = nullptr; + + if (_M_type != _Type::_Multi) + s = &_M_pathname; + else if (!_M_cmpts.empty()) + { + const auto& c = _M_cmpts.back(); + if (c._M_type == _Type::_Filename) + s = &c._M_pathname; + } + + if (s) + { + if (auto sz = s->size()) + { + if (sz <= 2 && (*s)[0] == '.') + { + if (sz == 1 || (*s)[1] == '.') // filename is "." or ".." + return { s, string_type::npos }; + else + return { s, 0 }; // filename is like ".?" + } + return { s, s->rfind('.') }; + } + } + return {}; +} + +void +path::_M_split_cmpts() +{ + _M_type = _Type::_Multi; + _M_cmpts.clear(); + + if (_M_pathname.empty()) + return; + + size_t pos = 0; + const size_t len = _M_pathname.size(); + + // look for root name or root directory + if (_S_is_dir_sep(_M_pathname[0])) + { + // look for root name, such as "//" or "//foo" + if (len > 1 && _M_pathname[1] == _M_pathname[0]) + { + if (len == 2) + { + // entire path is just "//" + _M_type = _Type::_Root_name; + return; + } + + if (!_S_is_dir_sep(_M_pathname[2])) + { + // got root name, find its end + pos = 3; + while (pos < len && !_S_is_dir_sep(_M_pathname[pos])) + ++pos; + _M_add_root_name(pos); + if (pos < len) // also got root directory + _M_add_root_dir(pos); + } + else + { + // got something like "///foo" which is just a root directory + // composed of multiple redundant directory separators + _M_add_root_dir(0); + } + } + else // got root directory + _M_add_root_dir(0); + ++pos; + } +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + else if (len > 1 && _M_pathname[1] == L':') + { + // got disk designator + _M_add_root_name(2); + if (len > 2 && _S_is_dir_sep(_M_pathname[2])) + _M_add_root_dir(2); + pos = 2; + } +#endif + + size_t back = pos; + while (pos < len) + { + if (_S_is_dir_sep(_M_pathname[pos])) + { + if (back != pos) + _M_add_filename(back, pos - back); + back = ++pos; + } + else + ++pos; + } + + if (back != pos) + _M_add_filename(back, pos - back); + else if (_S_is_dir_sep(_M_pathname.back())) + { + // [path.itr]/8 + // "Dot, if one or more trailing non-root slash characters are present." + if (_M_cmpts.back()._M_type == _Type::_Filename) + { + const auto& last = _M_cmpts.back(); + pos = last._M_pos + last._M_pathname.size(); + _M_cmpts.emplace_back(string_type(1, '.'), _Type::_Filename, pos); + } + } + + _M_trim(); +} + +void +path::_M_add_root_name(size_t n) +{ + _M_cmpts.emplace_back(_M_pathname.substr(0, n), _Type::_Root_name, 0); +} + +void +path::_M_add_root_dir(size_t pos) +{ + _M_cmpts.emplace_back(_M_pathname.substr(pos, 1), _Type::_Root_dir, pos); +} + +void +path::_M_add_filename(size_t pos, size_t n) +{ + _M_cmpts.emplace_back(_M_pathname.substr(pos, n), _Type::_Filename, pos); +} + +void +path::_M_trim() +{ + if (_M_cmpts.size() == 1) + { + _M_type = _M_cmpts.front()._M_type; + _M_cmpts.clear(); + } +} + +path::string_type +path::_S_convert_loc(const char* __first, const char* __last, + const std::locale& __loc) +{ + auto& __cvt = std::use_facet<codecvt<wchar_t, char, mbstate_t>>(__loc); + basic_string<wchar_t> __ws; + if (!__str_codecvt_in(__first, __last, __ws, __cvt)) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + return __ws; +#else + return _Cvt<wchar_t>::_S_convert(__ws.data(), __ws.data() + __ws.size()); +#endif +} + +std::size_t +std::experimental::filesystem::hash_value(const path& p) noexcept +{ + // [path.non-member] + // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)." + // Equality works as if by traversing the range [begin(), end()), meaning + // e.g. path("a//b") == path("a/b"), so we cannot simply hash _M_pathname + // but need to iterate over individual elements. Use the hash_combine from + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf + size_t seed = 0; + for (const auto& x : p) + { + seed ^= std::hash<path::string_type>()(x.native()) + 0x9e3779b9 + + (seed<<6) + (seed>>2); + } + return seed; +} |