aboutsummaryrefslogtreecommitdiff
path: root/dep
diff options
context:
space:
mode:
Diffstat (limited to 'dep')
-rw-r--r--dep/CMakeLists.txt31
-rw-r--r--dep/PackageList.txt18
-rw-r--r--dep/SFMT/CMakeLists.txt15
-rw-r--r--dep/boost/CMakeLists.txt70
-rw-r--r--dep/bzip2/CMakeLists.txt33
-rw-r--r--dep/cppformat/CMakeLists.txt48
-rw-r--r--dep/cppformat/README.rst29
-rw-r--r--dep/cppformat/cppformat/format.cc (renamed from dep/cppformat/format.cc)118
-rw-r--r--dep/cppformat/cppformat/format.h (renamed from dep/cppformat/format.h)531
-rw-r--r--dep/cppformat/cppformat/posix.cc (renamed from dep/cppformat/posix.cc)4
-rw-r--r--dep/cppformat/cppformat/posix.h (renamed from dep/cppformat/posix.h)63
-rw-r--r--dep/efsw/.hg_archival.txt5
-rw-r--r--dep/efsw/CMakeLists.txt85
-rw-r--r--dep/efsw/LICENSE22
-rw-r--r--dep/efsw/README.md138
-rw-r--r--dep/efsw/include/efsw/efsw.h151
-rw-r--r--dep/efsw/include/efsw/efsw.hpp197
-rw-r--r--dep/efsw/src/efsw/Debug.cpp85
-rw-r--r--dep/efsw/src/efsw/Debug.hpp50
-rw-r--r--dep/efsw/src/efsw/DirWatcherGeneric.cpp451
-rw-r--r--dep/efsw/src/efsw/DirWatcherGeneric.hpp55
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshot.cpp261
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshot.hpp46
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshotDiff.cpp29
-rw-r--r--dep/efsw/src/efsw/DirectorySnapshotDiff.hpp35
-rw-r--r--dep/efsw/src/efsw/FileInfo.cpp274
-rw-r--r--dep/efsw/src/efsw/FileInfo.hpp66
-rw-r--r--dep/efsw/src/efsw/FileSystem.cpp124
-rw-r--r--dep/efsw/src/efsw/FileSystem.hpp40
-rw-r--r--dep/efsw/src/efsw/FileWatcher.cpp145
-rw-r--r--dep/efsw/src/efsw/FileWatcherCWrapper.cpp132
-rw-r--r--dep/efsw/src/efsw/FileWatcherFSEvents.cpp278
-rw-r--r--dep/efsw/src/efsw/FileWatcherFSEvents.hpp107
-rw-r--r--dep/efsw/src/efsw/FileWatcherGeneric.cpp197
-rw-r--r--dep/efsw/src/efsw/FileWatcherGeneric.hpp59
-rw-r--r--dep/efsw/src/efsw/FileWatcherImpl.cpp29
-rw-r--r--dep/efsw/src/efsw/FileWatcherImpl.hpp54
-rw-r--r--dep/efsw/src/efsw/FileWatcherInotify.cpp531
-rw-r--r--dep/efsw/src/efsw/FileWatcherInotify.hpp73
-rw-r--r--dep/efsw/src/efsw/FileWatcherKqueue.cpp274
-rw-r--r--dep/efsw/src/efsw/FileWatcherKqueue.hpp78
-rw-r--r--dep/efsw/src/efsw/FileWatcherWin32.cpp291
-rw-r--r--dep/efsw/src/efsw/FileWatcherWin32.hpp69
-rw-r--r--dep/efsw/src/efsw/Log.cpp27
-rw-r--r--dep/efsw/src/efsw/Mutex.cpp26
-rw-r--r--dep/efsw/src/efsw/Mutex.hpp28
-rw-r--r--dep/efsw/src/efsw/String.cpp813
-rw-r--r--dep/efsw/src/efsw/String.hpp629
-rw-r--r--dep/efsw/src/efsw/System.cpp26
-rw-r--r--dep/efsw/src/efsw/System.hpp26
-rw-r--r--dep/efsw/src/efsw/Thread.cpp51
-rw-r--r--dep/efsw/src/efsw/Thread.hpp111
-rw-r--r--dep/efsw/src/efsw/Utf.hpp748
-rw-r--r--dep/efsw/src/efsw/Utf.inl671
-rw-r--r--dep/efsw/src/efsw/Watcher.cpp21
-rw-r--r--dep/efsw/src/efsw/Watcher.hpp30
-rw-r--r--dep/efsw/src/efsw/WatcherFSEvents.cpp264
-rw-r--r--dep/efsw/src/efsw/WatcherFSEvents.hpp70
-rw-r--r--dep/efsw/src/efsw/WatcherGeneric.cpp40
-rw-r--r--dep/efsw/src/efsw/WatcherGeneric.hpp30
-rw-r--r--dep/efsw/src/efsw/WatcherInotify.cpp35
-rw-r--r--dep/efsw/src/efsw/WatcherInotify.hpp25
-rw-r--r--dep/efsw/src/efsw/WatcherKqueue.cpp667
-rw-r--r--dep/efsw/src/efsw/WatcherKqueue.hpp94
-rw-r--r--dep/efsw/src/efsw/WatcherWin32.cpp150
-rw-r--r--dep/efsw/src/efsw/WatcherWin32.hpp77
-rw-r--r--dep/efsw/src/efsw/base.hpp110
-rw-r--r--dep/efsw/src/efsw/inotify-nosys.h159
-rw-r--r--dep/efsw/src/efsw/platform/platformimpl.hpp20
-rw-r--r--dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp144
-rw-r--r--dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp27
-rw-r--r--dep/efsw/src/efsw/platform/posix/MutexImpl.cpp32
-rw-r--r--dep/efsw/src/efsw/platform/posix/MutexImpl.hpp31
-rw-r--r--dep/efsw/src/efsw/platform/posix/SystemImpl.cpp180
-rw-r--r--dep/efsw/src/efsw/platform/posix/SystemImpl.hpp26
-rw-r--r--dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp68
-rw-r--r--dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp35
-rw-r--r--dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp89
-rw-r--r--dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp28
-rw-r--r--dep/efsw/src/efsw/platform/win/MutexImpl.cpp29
-rw-r--r--dep/efsw/src/efsw/platform/win/MutexImpl.hpp34
-rw-r--r--dep/efsw/src/efsw/platform/win/SystemImpl.cpp50
-rw-r--r--dep/efsw/src/efsw/platform/win/SystemImpl.hpp26
-rw-r--r--dep/efsw/src/efsw/platform/win/ThreadImpl.cpp56
-rw-r--r--dep/efsw/src/efsw/platform/win/ThreadImpl.hpp39
-rw-r--r--dep/efsw/src/efsw/sophist.h147
-rw-r--r--dep/efsw/src/test/efsw-test.cpp151
-rw-r--r--dep/g3dlite/CMakeLists.txt27
-rw-r--r--dep/gsoap/CMakeLists.txt25
-rw-r--r--dep/jemalloc/CMakeLists.txt123
-rw-r--r--dep/libmpq/CMakeLists.txt38
-rw-r--r--dep/mysql/CMakeLists.txt22
-rw-r--r--dep/openssl/CMakeLists.txt26
-rw-r--r--dep/process/CMakeLists.txt19
-rw-r--r--dep/readline/CMakeLists.txt38
-rw-r--r--dep/recastnavigation/Detour/CMakeLists.txt20
-rw-r--r--dep/recastnavigation/Recast/CMakeLists.txt21
-rw-r--r--dep/threads/CMakeLists.txt16
-rw-r--r--dep/utf8cpp/CMakeLists.txt15
-rw-r--r--dep/valgrind/CMakeLists.txt15
-rw-r--r--dep/zlib/CMakeLists.txt55
101 files changed, 11526 insertions, 465 deletions
diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt
index 7f4f1cd884c..48be56bc9ef 100644
--- a/dep/CMakeLists.txt
+++ b/dep/CMakeLists.txt
@@ -8,37 +8,38 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-if( MSVC )
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ string(REGEX REPLACE "/W[0-4] " "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ string(REGEX REPLACE "/W[0-4] " "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
add_definitions(/W0)
else()
add_definitions(-w)
endif()
-if(CMAKE_SYSTEM_NAME MATCHES "Linux")
- if(SERVERS AND NOT NOJEM)
- add_subdirectory(jemalloc)
- endif()
-endif()
-
-if(CMAKE_SYSTEM_NAME MATCHES "Windows")
- if(TOOLS)
- add_subdirectory(bzip2)
- endif()
- if(SERVERS OR TOOLS)
- add_subdirectory(zlib)
- endif()
-endif()
+add_subdirectory(threads)
if(SERVERS OR TOOLS)
+ add_subdirectory(boost)
+ add_subdirectory(process)
+ add_subdirectory(zlib)
add_subdirectory(g3dlite)
add_subdirectory(recastnavigation)
add_subdirectory(cppformat)
+ add_subdirectory(SFMT)
+ add_subdirectory(utf8cpp)
+ add_subdirectory(valgrind)
+ add_subdirectory(openssl)
+ add_subdirectory(jemalloc)
endif()
if(SERVERS)
+ add_subdirectory(mysql)
+ add_subdirectory(readline)
add_subdirectory(gsoap)
+ add_subdirectory(efsw)
endif()
if(TOOLS)
+ add_subdirectory(bzip2)
add_subdirectory(libmpq)
endif()
diff --git a/dep/PackageList.txt b/dep/PackageList.txt
index e84fef8d3b2..66421127162 100644
--- a/dep/PackageList.txt
+++ b/dep/PackageList.txt
@@ -1,6 +1,6 @@
TrinityCore uses (parts of or in whole) the following opensource software :
-Boost
+Boost (external)
http://www.boost.org
Version: 1.55
@@ -14,7 +14,11 @@ bzip2 (a freely available, patent free, high-quality data compressor)
cppformat (type safe format library)
https://github.com/cppformat/cppformat
- Version: 5c76d107cbaf5e851bd66b6c563e4fc7c90be7ad
+ Version: 5174b8ca281426af604b85fdf53be8a748b33f56
+
+efws (Entropia File System Watcher - crossplatform file system watcher)
+ https://bitbucket.org/SpartanJ/efsw
+ ff0b69daeca1edf7785a8a580518e462be5a6f3d
G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License)
http://g3d.sourceforge.net/
@@ -23,11 +27,19 @@ G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License)
jemalloc (a general-purpose scalable concurrent malloc-implementation)
http://www.canonware.com/jemalloc/
Version: 3.6.0
-
+
libMPQ (a library for reading MPQ files)
https://github.com/mbroemme/libmpq/
Version: d59b4cf1d107b5f6a0f67d6bc545c6c6ebef3d74
+libreadline (command line editing library)
+ https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
+ Version: external
+
+OpenSSL (general-purpose cryptography library)
+ https://www.openssl.org/
+ Version: external
+
SFMT (SIMD-oriented Fast Mersenne Twister)
Based on http://agner.org/random/
Version: 2010-Aug-03
diff --git a/dep/SFMT/CMakeLists.txt b/dep/SFMT/CMakeLists.txt
new file mode 100644
index 00000000000..5cf1b9bf972
--- /dev/null
+++ b/dep/SFMT/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+add_library(sfmt INTERFACE)
+
+target_include_directories(sfmt
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/dep/boost/CMakeLists.txt b/dep/boost/CMakeLists.txt
new file mode 100644
index 00000000000..6cda5fbec4e
--- /dev/null
+++ b/dep/boost/CMakeLists.txt
@@ -0,0 +1,70 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+if(WIN32)
+ set(BOOST_DEBUG ON)
+ if(DEFINED ENV{BOOST_ROOT})
+ set(BOOST_ROOT $ENV{BOOST_ROOT})
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0)
+ set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-12.0)
+ else()
+ set(BOOST_LIBRARYDIR ${BOOST_ROOT}/lib${PLATFORM}-msvc-14.0)
+ endif()
+ else()
+ message(FATAL_ERROR "No BOOST_ROOT environment variable could be found! Please make sure it is set and the points to your Boost installation.")
+ endif()
+
+ set(Boost_USE_STATIC_LIBS ON)
+ set(Boost_USE_MULTITHREADED ON)
+ set(Boost_USE_STATIC_RUNTIME OFF)
+endif()
+
+find_package(Boost 1.51 REQUIRED system filesystem thread program_options iostreams regex)
+
+# Find if Boost was compiled in C++03 mode because it requires -DBOOST_NO_CXX11_SCOPED_ENUMS
+
+include (CheckCXXSourceCompiles)
+
+set(CMAKE_REQUIRED_INCLUDES ${Boost_INCLUDE_DIR})
+set(CMAKE_REQUIRED_LIBRARIES ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_IOSTREAMS_LIBRARY})
+set(CMAKE_REQUIRED_FLAGS "-std=c++11")
+check_cxx_source_compiles("
+ #include <boost/filesystem/path.hpp>
+ #include <boost/filesystem/operations.hpp>
+ int main() { boost::filesystem::copy_file(boost::filesystem::path(), boost::filesystem::path()); }"
+boost_filesystem_copy_links_without_NO_SCOPED_ENUM)
+unset(CMAKE_REQUIRED_INCLUDES)
+unset(CMAKE_REQUIRED_LIBRARIES)
+unset(CMAKE_REQUIRED_FLAGS)
+
+add_library(boost INTERFACE)
+
+target_link_libraries(boost
+ INTERFACE
+ ${Boost_LIBRARIES})
+
+target_include_directories(boost
+ INTERFACE
+ ${Boost_INCLUDE_DIRS})
+
+if (boost_filesystem_copy_links_without_NO_SCOPED_ENUM)
+ target_compile_definitions(boost
+ INTERFACE
+ -DBOOST_DATE_TIME_NO_LIB
+ -DBOOST_REGEX_NO_LIB
+ -DBOOST_CHRONO_NO_LIB)
+else()
+ target_compile_definitions(boost
+ INTERFACE
+ -DBOOST_DATE_TIME_NO_LIB
+ -DBOOST_REGEX_NO_LIB
+ -DBOOST_CHRONO_NO_LIB
+ -DBOOST_NO_CXX11_SCOPED_ENUMS)
+endif()
diff --git a/dep/bzip2/CMakeLists.txt b/dep/bzip2/CMakeLists.txt
index d3aadbe002e..d5a7414f383 100644
--- a/dep/bzip2/CMakeLists.txt
+++ b/dep/bzip2/CMakeLists.txt
@@ -8,15 +8,30 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-file(GLOB sources *.c)
+if(UNIX)
+ # Look for an installed bzip2 on unix
+ find_package(BZip2 REQUIRED)
-set(bzip2_STAT_SRCS
- ${sources}
-)
+ add_library(bzip2 SHARED IMPORTED GLOBAL)
-include_directories(
- ${CMAKE_SOURCE_DIR}/dep/zlib
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
+ set_target_properties(bzip2
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${BZIP2_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${BZIP2_INCLUDE_DIRS}")
+else()
+ # Use the bundled source on windows
+ file(GLOB sources *.c)
+ add_library(bzip2 STATIC
+ ${sources})
-add_library(bzip2 STATIC ${bzip2_STAT_SRCS})
+ target_include_directories(bzip2
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+ set_target_properties(bzip2
+ PROPERTIES
+ FOLDER
+ "dep")
+endif()
diff --git a/dep/cppformat/CMakeLists.txt b/dep/cppformat/CMakeLists.txt
index 3be3e5f6dbb..1cbff49b871 100644
--- a/dep/cppformat/CMakeLists.txt
+++ b/dep/cppformat/CMakeLists.txt
@@ -1,31 +1,37 @@
-include(CheckCXXCompilerFlag)
-include(CheckSymbolExists)
-
-set(FMT_SOURCES format.cc format.h)
-
-# Use variadic templates
-add_definitions(-DFMT_VARIADIC_TEMPLATES=1)
-
-# Use deleted functions
-add_definitions(-DFMT_USE_DELETED_FUNCTIONS=1)
-
-# Use static assert
-add_definitions(-DFMT_USE_STATIC_ASSERT=1)
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+include(CheckSymbolExists)
if (WIN32)
check_symbol_exists(open io.h HAVE_OPEN)
else ()
check_symbol_exists(open fcntl.h HAVE_OPEN)
endif ()
+set(FMT_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.cc)
+
if (HAVE_OPEN)
- add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1)
- set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h)
-endif ()
+ set(FMT_SOURCES ${FMT_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.cc)
+endif()
-add_library(format STATIC ${FMT_SOURCES})
+add_library(cppformat STATIC ${FMT_SOURCES})
-if (CMAKE_COMPILER_IS_GNUCXX)
- set_target_properties(format PROPERTIES COMPILE_FLAGS
- "-Wall -Wextra -Wshadow -pedantic")
-endif ()
+target_include_directories(cppformat
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+set_target_properties(cppformat
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/cppformat/README.rst b/dep/cppformat/README.rst
index fb4399f0af4..e859f909466 100644
--- a/dep/cppformat/README.rst
+++ b/dep/cppformat/README.rst
@@ -28,9 +28,9 @@ Features
* Format API with `format string syntax
<http://cppformat.github.io/latest/syntax.html>`_
similar to the one used by `str.format
- <http://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
+ <https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python.
* Safe `printf implementation
- <http://cppformat.github.io/latest/reference.html#printf-formatting-functions>`_
+ <http://cppformat.github.io/latest/api.html#printf-formatting-functions>`_
including the POSIX extension for positional arguments.
* Support for user-defined types.
* High speed: performance of the format API is close to that of
@@ -103,10 +103,10 @@ An object of any user-defined type for which there is an overloaded
// s == "The date is 2012-12-9"
You can use the `FMT_VARIADIC
-<http://cppformat.github.io/latest/reference.html#utilities>`_
+<http://cppformat.github.io/latest/api.html#utilities>`_
macro to create your own functions similar to `format
-<http://cppformat.github.io/latest/reference.html#format>`_ and
-`print <http://cppformat.github.io/latest/reference.html#print>`_
+<http://cppformat.github.io/latest/api.html#format>`_ and
+`print <http://cppformat.github.io/latest/api.html#print>`_
which take arbitrary arguments:
.. code:: c++
@@ -132,13 +132,17 @@ Projects using this library
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
-* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_:
+* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
-* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine
+* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
+
+* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
+* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets
+
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
@@ -148,7 +152,7 @@ Projects using this library
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy
-* `Saddy <https://code.google.com/p/saddy/>`_:
+* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
Small crossplatform 2D graphic engine
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
@@ -188,7 +192,7 @@ doesn't support user-defined types. Printf also has safety issues although
they are mostly solved with `__attribute__ ((format (printf, ...))
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
There is a POSIX extension that adds positional arguments required for
-`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`_
+`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
to printf but it is not a part of C99 and may not be available on some
platforms.
@@ -376,18 +380,13 @@ C++ Format is distributed under the BSD `license
The `Format String Syntax
<http://cppformat.github.io/latest/syntax.html>`_
section in the documentation is based on the one from Python `string module
-documentation <http://docs.python.org/3/library/string.html#module-string>`_
+documentation <https://docs.python.org/3/library/string.html#module-string>`_
adapted for the current library. For this reason the documentation is
distributed under the Python Software Foundation license available in
`doc/python-license.txt
<https://raw.github.com/cppformat/cppformat/master/doc/python-license.txt>`_.
It only applies if you distribute the documentation of C++ Format.
-Links
------
-
-`API changes/compatibility report <http://upstream-tracker.org/versions/cppformat.html>`_
-
Acknowledgments
---------------
diff --git a/dep/cppformat/format.cc b/dep/cppformat/cppformat/format.cc
index 1970d53c500..daccd68f1da 100644
--- a/dep/cppformat/format.cc
+++ b/dep/cppformat/cppformat/format.cc
@@ -207,10 +207,15 @@ void format_error_code(fmt::Writer &out, int error_code,
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
- fmt::internal::IntTraits<int>::MainType ec_value = error_code;
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
- error_code_size += fmt::internal::count_digits(ec_value);
+ typedef fmt::internal::IntTraits<int>::MainType MainType;
+ MainType abs_value = static_cast<MainType>(error_code);
+ if (internal::is_negative(error_code)) {
+ abs_value = 0 - abs_value;
+ ++error_code_size;
+ }
+ error_code_size += fmt::internal::count_digits(abs_value);
if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
@@ -252,7 +257,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
template <typename T>
unsigned visit_any_int(T value) {
typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
- UnsignedType width = value;
+ UnsignedType width = static_cast<UnsignedType>(value);
if (fmt::internal::is_negative(value)) {
spec_.align_ = fmt::ALIGN_LEFT;
width = 0 - width;
@@ -278,8 +283,21 @@ class PrecisionHandler :
}
};
-// Converts an integer argument to an integral type T for printf.
+template <typename T, typename U>
+struct is_same {
+ enum { value = 0 };
+};
+
template <typename T>
+struct is_same<T, T> {
+ enum { value = 1 };
+};
+
+// An argument visitor that converts an integer argument to T for printf,
+// if T is an integral type. If T is void, the argument is converted to
+// corresponding signed or unsigned type depending on the type specifier:
+// 'd' and 'i' - signed, other - unsigned)
+template <typename T = void>
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
private:
fmt::internal::Arg &arg_;
@@ -300,21 +318,25 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
using fmt::internal::Arg;
- if (sizeof(T) <= sizeof(int)) {
+ typedef typename fmt::internal::Conditional<
+ is_same<T, void>::value, U, T>::type TargetType;
+ if (sizeof(TargetType) <= sizeof(int)) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_.type = Arg::INT;
- arg_.int_value = static_cast<int>(static_cast<T>(value));
+ arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
} else {
arg_.type = Arg::UINT;
- arg_.uint_value = static_cast<unsigned>(
- static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
+ typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
+ arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
}
} else {
if (is_signed) {
arg_.type = Arg::LONG_LONG;
- arg_.long_long_value =
- static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
+ // glibc's printf doesn't sign extend arguments of smaller types:
+ // std::printf("%lld", -42); // prints "4294967254"
+ // but we don't have to do the same because it's a UB.
+ arg_.long_long_value = static_cast<fmt::LongLong>(value);
} else {
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
@@ -340,6 +362,21 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
arg_.int_value = static_cast<char>(value);
}
};
+
+// Write the content of w to os.
+void write(std::ostream &os, fmt::Writer &w) {
+ const char *data = w.data();
+ typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
+ UnsignedStreamSize size = w.size();
+ UnsignedStreamSize max_size =
+ internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
+ do {
+ UnsignedStreamSize n = size <= max_size ? size : max_size;
+ os.write(data, static_cast<std::streamsize>(n));
+ data += n;
+ size -= n;
+ } while (size != 0);
+}
} // namespace
namespace internal {
@@ -551,27 +588,25 @@ FMT_FUNC void fmt::WindowsError::init(
FMT_FUNC void fmt::internal::format_windows_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT {
- class String {
- private:
- LPWSTR str_;
-
- public:
- String() : str_() {}
- ~String() { LocalFree(str_); }
- LPWSTR *ptr() { return &str_; }
- LPCWSTR c_str() const { return str_; }
- };
FMT_TRY {
- String system_message;
- if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
- error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
- UTF16ToUTF8 utf8_message;
- if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
- out << message << ": " << utf8_message;
- return;
+ MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
+ buffer.resize(INLINE_BUFFER_SIZE);
+ for (;;) {
+ wchar_t *system_message = &buffer[0];
+ int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ system_message, static_cast<uint32_t>(buffer.size()), 0);
+ if (result != 0) {
+ UTF16ToUTF8 utf8_message;
+ if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
+ out << message << ": " << utf8_message;
+ return;
+ }
+ break;
}
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ break; // Can't get error message, report error code instead.
+ buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
@@ -616,7 +651,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
- map_.insert(Pair(named_arg->name, *named_arg));
+ map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
@@ -628,7 +663,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
- map_.insert(Pair(named_arg->name, *named_arg));
+ map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
@@ -637,7 +672,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
- map_.insert(Pair(named_arg->name, *named_arg));
+ map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
@@ -659,6 +694,7 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
break;
case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
+ break;
default:
/*nothing*/;
}
@@ -763,7 +799,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
if (*s == '.') {
++s;
if ('0' <= *s && *s <= '9') {
- spec.precision_ = parse_nonnegative_int(s);
+ spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
} else if (*s == '*') {
++s;
spec.precision_ = PrecisionHandler().visit(get_arg(s));
@@ -772,7 +808,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
Arg arg = get_arg(s, arg_index);
if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
- spec.flags_ &= ~HASH_FLAG;
+ spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') {
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC;
@@ -809,7 +845,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
break;
default:
--s;
- ArgConverter<int>(arg, *s).visit(arg);
+ ArgConverter<void>(arg, *s).visit(arg);
}
// Parse type.
@@ -861,10 +897,11 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args);
}
-FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
+FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str,
+ ArgList args) {
MemoryWriter w;
w.write(format_str, args);
- os.write(w.data(), w.size());
+ write(os, w);
}
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
@@ -882,6 +919,13 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
}
+FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) {
+ MemoryWriter w;
+ printf(w, format, args);
+ write(os, w);
+ return static_cast<int>(w.size());
+}
+
#ifndef FMT_HEADER_ONLY
template struct fmt::internal::BasicData<void>;
diff --git a/dep/cppformat/format.h b/dep/cppformat/cppformat/format.h
index a98a166091b..08bb9b5d9e8 100644
--- a/dep/cppformat/format.h
+++ b/dep/cppformat/cppformat/format.h
@@ -28,14 +28,6 @@
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
-#if defined _MSC_VER && _MSC_VER <= 1500
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-typedef long long intmax_t;
-#else
-#include <stdint.h>
-#endif
-
#include <cassert>
#include <cmath>
#include <cstdio>
@@ -44,7 +36,8 @@ typedef long long intmax_t;
#include <memory>
#include <stdexcept>
#include <string>
-#include <map>
+#include <vector>
+#include <utility>
#ifndef FMT_USE_IOSTREAMS
# define FMT_USE_IOSTREAMS 1
@@ -64,40 +57,23 @@ typedef long long intmax_t;
# include <iterator>
#endif
-#ifdef _MSC_VER
-# include <intrin.h> // _BitScanReverse, _BitScanReverse64
-
-namespace fmt {
-namespace internal {
-# pragma intrinsic(_BitScanReverse)
-inline uint32_t clz(uint32_t x) {
- unsigned long r = 0;
- _BitScanReverse(&r, x);
- return 31 - r;
-}
-# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
-
-# ifdef _WIN64
-# pragma intrinsic(_BitScanReverse64)
-# endif
-
-inline uint32_t clzll(uint64_t x) {
- unsigned long r = 0;
-# ifdef _WIN64
- _BitScanReverse64(&r, x);
-# else
- // Scan the high 32 bits.
- if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
- return 63 - (r + 32);
+#if defined(_MSC_VER) && _MSC_VER <= 1500
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 intmax_t;
+#else
+#include <stdint.h>
+#endif
- // Scan the low 32 bits.
- _BitScanReverse(&r, static_cast<uint32_t>(x));
+#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
+# ifdef FMT_EXPORT
+# define FMT_API __declspec(dllexport)
+# elif defined(FMT_SHARED)
+# define FMT_API __declspec(dllimport)
# endif
- return 63 - r;
-}
-# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
-}
-}
+#endif
+#ifndef FMT_API
+# define FMT_API
#endif
#ifdef __GNUC__
@@ -174,21 +150,6 @@ inline uint32_t clzll(uint64_t x) {
# include <utility> // for std::move
#endif
-// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
-#ifndef FMT_USE_NOEXCEPT
-# define FMT_USE_NOEXCEPT 0
-#endif
-
-#ifndef FMT_NOEXCEPT
-# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
- (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
- _MSC_VER >= 1900
-# define FMT_NOEXCEPT noexcept
-# else
-# define FMT_NOEXCEPT throw()
-# endif
-#endif
-
// Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
@@ -208,6 +169,25 @@ inline uint32_t clzll(uint64_t x) {
# endif
#endif
+// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
+#ifndef FMT_USE_NOEXCEPT
+# define FMT_USE_NOEXCEPT 0
+#endif
+
+#ifndef FMT_NOEXCEPT
+# if FMT_EXCEPTIONS
+# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
+ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
+ _MSC_VER >= 1900
+# define FMT_NOEXCEPT noexcept
+# else
+# define FMT_NOEXCEPT throw()
+# endif
+# else
+# define FMT_NOEXCEPT
+# endif
+#endif
+
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#ifndef FMT_USE_DELETED_FUNCTIONS
@@ -241,6 +221,67 @@ inline uint32_t clzll(uint64_t x) {
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
+
+#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
+# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
+#endif
+
+#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
+# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
+#endif
+
+// Some compilers masquerade as both MSVC and GCC-likes or
+// otherwise support __builtin_clz and __builtin_clzll, so
+// only define FMT_BUILTIN_CLZ using the MSVC intrinsics
+// if the clz and clzll builtins are not available.
+#if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL)
+# include <intrin.h> // _BitScanReverse, _BitScanReverse64
+
+namespace fmt {
+namespace internal {
+# pragma intrinsic(_BitScanReverse)
+inline uint32_t clz(uint32_t x) {
+ unsigned long r = 0;
+ _BitScanReverse(&r, x);
+
+ assert(x != 0);
+ // Static analysis complains about using uninitialized data
+ // "r", but the only way that can happen is if "x" is 0,
+ // which the callers guarantee to not happen.
+# pragma warning(suppress: 6102)
+ return 31 - r;
+}
+# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
+
+# ifdef _WIN64
+# pragma intrinsic(_BitScanReverse64)
+# endif
+
+inline uint32_t clzll(uint64_t x) {
+ unsigned long r = 0;
+# ifdef _WIN64
+ _BitScanReverse64(&r, x);
+# else
+ // Scan the high 32 bits.
+ if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
+ return 63 - (r + 32);
+
+ // Scan the low 32 bits.
+ _BitScanReverse(&r, static_cast<uint32_t>(x));
+# endif
+
+ assert(x != 0);
+ // Static analysis complains about using uninitialized data
+ // "r", but the only way that can happen is if "x" is 0,
+ // which the callers guarantee to not happen.
+# pragma warning(suppress: 6102)
+ return 63 - r;
+}
+# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
+}
+}
+#endif
+
namespace fmt {
namespace internal {
struct DummyInt {
@@ -396,7 +437,7 @@ class BasicStringRef {
return std::basic_string<Char>(data_, size_);
}
- /** Returns the pointer to a C string. */
+ /** Returns a pointer to the string data. */
const Char *data() const { return data_; }
/** Returns the string size. */
@@ -492,6 +533,29 @@ class FormatError : public std::runtime_error {
};
namespace internal {
+
+// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
+template <typename T>
+struct MakeUnsigned { typedef T Type; };
+
+#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
+ template <> \
+ struct MakeUnsigned<T> { typedef U Type; }
+
+FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);
+FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);
+FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);
+FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);
+FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);
+FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);
+
+// Casts nonnegative integer to unsigned.
+template <typename Int>
+inline typename MakeUnsigned<Int>::Type to_unsigned(Int value) {
+ FMT_ASSERT(value >= 0, "negative value");
+ return static_cast<typename MakeUnsigned<Int>::Type>(value);
+}
+
// The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation.
enum { INLINE_BUFFER_SIZE = 500 };
@@ -581,8 +645,7 @@ class Buffer {
template <typename T>
template <typename U>
void Buffer<T>::append(const U *begin, const U *end) {
- assert(begin <= end);
- std::size_t new_size = size_ + (end - begin);
+ std::size_t new_size = size_ + internal::to_unsigned(end - begin);
if (new_size > capacity_)
grow(new_size);
std::uninitialized_copy(begin, end,
@@ -592,8 +655,8 @@ void Buffer<T>::append(const U *begin, const U *end) {
namespace internal {
-// A memory buffer for POD types with the first SIZE elements stored in
-// the object itself.
+// A memory buffer for trivially copyable/constructible types with the first SIZE
+// elements stored in the object itself.
template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
class MemoryBuffer : private Allocator, public Buffer<T> {
private:
@@ -676,7 +739,7 @@ class FixedBuffer : public fmt::Buffer<Char> {
FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {}
protected:
- void grow(std::size_t size);
+ FMT_API void grow(std::size_t size);
};
template <typename Char>
@@ -704,7 +767,7 @@ class CharTraits<char> : public BasicCharTraits<char> {
// Formats a floating-point number.
template <typename T>
- static int format_float(char *buffer, std::size_t size,
+ FMT_API static int format_float(char *buffer, std::size_t size,
const char *format, unsigned width, int precision, T value);
};
@@ -715,7 +778,7 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
static wchar_t convert(wchar_t value) { return value; }
template <typename T>
- static int format_float(wchar_t *buffer, std::size_t size,
+ FMT_API static int format_float(wchar_t *buffer, std::size_t size,
const wchar_t *format, unsigned width, int precision, T value);
};
@@ -754,27 +817,12 @@ struct IntTraits {
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
};
-// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
-template <typename T>
-struct MakeUnsigned { typedef T Type; };
-
-#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
- template <> \
- struct MakeUnsigned<T> { typedef U Type; }
-
-FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);
-FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);
-FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);
-FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);
-FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);
-FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);
-
-void report_unknown_type(char code, const char *type);
+FMT_API void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// configuration.
template <typename T = void>
-struct BasicData {
+struct FMT_API BasicData {
static const uint32_t POWERS_OF_10_32[];
static const uint64_t POWERS_OF_10_64[];
static const char DIGITS[];
@@ -782,22 +830,14 @@ struct BasicData {
typedef BasicData<> Data;
-#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
-# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
-#endif
-
-#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
-# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
-#endif
-
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
inline unsigned count_digits(uint64_t n) {
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
- unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
- return t - (n < Data::POWERS_OF_10_64[t]) + 1;
+ int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
+ return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1;
}
#else
// Fallback version of count_digits used when __builtin_clz is not available.
@@ -820,8 +860,8 @@ inline unsigned count_digits(uint64_t n) {
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline unsigned count_digits(uint32_t n) {
- uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
- return t - (n < Data::POWERS_OF_10_32[t]) + 1;
+ int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
+ return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1;
}
#endif
@@ -863,7 +903,7 @@ class UTF8ToUTF16 {
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;
public:
- explicit UTF8ToUTF16(StringRef s);
+ FMT_API explicit UTF8ToUTF16(StringRef s);
operator WStringRef() const { return WStringRef(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const wchar_t *c_str() const { return &buffer_[0]; }
@@ -878,7 +918,7 @@ class UTF16ToUTF8 {
public:
UTF16ToUTF8() {}
- explicit UTF16ToUTF8(WStringRef s);
+ FMT_API explicit UTF16ToUTF8(WStringRef s);
operator StringRef() const { return StringRef(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char *c_str() const { return &buffer_[0]; }
@@ -887,15 +927,15 @@ class UTF16ToUTF8 {
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
- int convert(WStringRef s);
+ FMT_API int convert(WStringRef s);
};
-void format_windows_error(fmt::Writer &out, int error_code,
- fmt::StringRef message) FMT_NOEXCEPT;
+FMT_API void format_windows_error(fmt::Writer &out, int error_code,
+ fmt::StringRef message) FMT_NOEXCEPT;
#endif
-void format_system_error(fmt::Writer &out, int error_code,
- fmt::StringRef message) FMT_NOEXCEPT;
+FMT_API void format_system_error(fmt::Writer &out, int error_code,
+ fmt::StringRef message) FMT_NOEXCEPT;
// A formatting argument value.
struct Value {
@@ -938,8 +978,8 @@ struct Value {
};
};
-// A formatting argument. It is a POD type to allow storage in
-// internal::MemoryBuffer.
+// A formatting argument. It is a trivially copyable/constructible type to
+// allow storage in internal::MemoryBuffer.
struct Arg : Value {
Type type;
};
@@ -976,6 +1016,7 @@ template <typename T>
T &get();
struct DummyStream : std::ostream {
+ DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
void operator<<(Null<>);
};
@@ -1199,17 +1240,27 @@ class MakeValue : public Arg {
static uint64_t type(const NamedArg<Char_> &) { return Arg::NAMED_ARG; }
};
+template <typename Formatter>
+class MakeArg : public Arg {
+public:
+ MakeArg() {
+ type = Arg::NONE;
+ }
+
+ template <typename T>
+ MakeArg(const T &value)
+ : Arg(MakeValue<Formatter>(value)) {
+ type = static_cast<Arg::Type>(MakeValue<Formatter>::type(value));
+ }
+};
+
template <typename Char>
struct NamedArg : Arg {
BasicStringRef<Char> name;
- typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
-
template <typename T>
NamedArg(BasicStringRef<Char> argname, const T &value)
- : Arg(MakeValue(value)), name(argname) {
- type = static_cast<Arg::Type>(MakeValue::type(value));
- }
+ : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {}
};
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
@@ -1631,17 +1682,22 @@ namespace internal {
template <typename Char>
class ArgMap {
private:
- typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType;
+ typedef std::vector<std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType;
typedef typename MapType::value_type Pair;
MapType map_;
public:
- void init(const ArgList &args);
+ FMT_API void init(const ArgList &args);
const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
- typename MapType::const_iterator it = map_.find(name);
- return it != map_.end() ? &it->second : 0;
+ // The list is unsorted, so just return the first matching name.
+ for (typename MapType::const_iterator it = map_.begin(), end = map_.end();
+ it != end; ++it) {
+ if (it->first == name)
+ return &it->second;
+ }
+ return 0;
}
};
@@ -1767,7 +1823,7 @@ class FormatterBase {
int next_arg_index_;
// Returns the argument with specified index.
- Arg do_get_arg(unsigned arg_index, const char *&error);
+ FMT_API Arg do_get_arg(unsigned arg_index, const char *&error);
protected:
const ArgList &args() const { return args_; }
@@ -1780,7 +1836,7 @@ class FormatterBase {
// Returns the next argument.
Arg next_arg(const char *&error) {
if (next_arg_index_ >= 0)
- return do_get_arg(next_arg_index_++, error);
+ return do_get_arg(internal::to_unsigned(next_arg_index_++), error);
error = "cannot switch from manual to automatic argument indexing";
return Arg();
}
@@ -1803,7 +1859,7 @@ class FormatterBase {
template <typename Char>
void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
if (start != end)
- w << BasicStringRef<Char>(start, end - start);
+ w << BasicStringRef<Char>(start, internal::to_unsigned(end - start));
}
};
@@ -1823,14 +1879,16 @@ class PrintfFormatter : private FormatterBase {
public:
explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {}
- void format(BasicWriter<Char> &writer, BasicCStringRef<Char> format_str);
+ FMT_API void format(BasicWriter<Char> &writer,
+ BasicCStringRef<Char> format_str);
};
} // namespace internal
-// A formatter.
+/** This template formats data and writes the output to a writer. */
template <typename CharType>
class BasicFormatter : private internal::FormatterBase {
public:
+ /** The character type for the output. */
typedef CharType Char;
private:
@@ -1852,13 +1910,23 @@ class BasicFormatter : private internal::FormatterBase {
internal::Arg parse_arg_name(const Char *&s);
public:
+ /**
+ \rst
+ Constructs a ``BasicFormatter`` object. References to the arguments and
+ the writer are stored in the formatter object so make sure they have
+ appropriate lifetimes.
+ \endrst
+ */
BasicFormatter(const ArgList &args, BasicWriter<Char> &w)
: internal::FormatterBase(args), writer_(w) {}
+ /** Returns a reference to the writer associated with this formatter. */
BasicWriter<Char> &writer() { return writer_; }
+ /** Formats stored arguments and writes the output to the writer. */
void format(BasicCStringRef<Char> format_str);
+ // Formats a single argument and advances format_str, a format string pointer.
const Char *format(const Char *&format_str, const internal::Arg &arg);
};
@@ -1889,16 +1957,29 @@ inline uint64_t make_type(const T &arg) {
return MakeValue< BasicFormatter<char> >::type(arg);
}
+template <unsigned N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)>
+struct ArgArray;
+
+template <unsigned N>
+struct ArgArray<N, true/*IsPacked*/> {
+ typedef Value Type[N > 0 ? N : 1];
+
+ template <typename Formatter, typename T>
+ static Value make(const T &value) {
+ Value result = MakeValue<Formatter>(value);
+ // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang:
+ // https://github.com/cppformat/cppformat/issues/276
+ (void)result.custom.format;
+ return result;
+ }
+};
+
template <unsigned N>
-struct ArgArray {
- // Computes the argument array size by adding 1 to N, which is the number of
- // arguments, if N is zero, because array of zero size is invalid, or if N
- // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
- // argument that marks the end of the list.
- enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) };
-
- typedef typename Conditional<
- (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE];
+struct ArgArray<N, false/*IsPacked*/> {
+ typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE
+
+ template <typename Formatter, typename T>
+ static Arg make(const T &value) { return MakeArg<Formatter>(value); }
};
#if FMT_USE_VARIADIC_TEMPLATES
@@ -1907,47 +1988,6 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) {
return make_type(first) | (make_type(tail...) << 4);
}
-inline void do_set_types(Arg *) {}
-
-template <typename T, typename... Args>
-inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
- args->type = static_cast<Arg::Type>(
- MakeValue< BasicFormatter<char> >::type(arg));
- do_set_types(args + 1, tail...);
-}
-
-template <typename... Args>
-inline void set_types(Arg *array, const Args & ... args) {
- if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS))
- do_set_types(array, args...);
- array[sizeof...(Args)].type = Arg::NONE;
-}
-
-template <typename... Args>
-inline void set_types(Value *, const Args & ...) {
- // Do nothing as types are passed separately from values.
-}
-
-template <typename Formatter, typename Value>
-inline void store_args(Value *) {}
-
-template <typename Formatter, typename Arg, typename T, typename... Args>
-inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
- // Assign only the Value subobject of Arg and don't overwrite type (if any)
- // that is assigned by set_types.
- Value &value = *args;
- value = MakeValue<Formatter>(arg);
- store_args<Formatter>(args + 1, tail...);
-}
-
-template <typename Formatter, typename... Args>
-ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
- const Args & ... args) {
- if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
- set_types(array, args...);
- store_args<Formatter>(array, args...);
- return ArgList(make_type(args...), array);
-}
#else
struct ArgType {
@@ -1985,7 +2025,7 @@ class FormatBuf : public std::basic_streambuf<Char> {
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
- size_t size = this->pptr() - start_;
+ size_t size = this->size();
buffer_.resize(size);
buffer_.reserve(size * 2);
@@ -1997,7 +2037,7 @@ class FormatBuf : public std::basic_streambuf<Char> {
}
size_t size() const {
- return this->pptr() - start_;
+ return to_unsigned(this->pptr() - start_);
}
};
} // namespace internal
@@ -2015,18 +2055,20 @@ class FormatBuf : public std::basic_streambuf<Char> {
# define FMT_VARIADIC_VOID(func, arg_type) \
template <typename... Args> \
void func(arg_type arg0, const Args & ... args) { \
- typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
- func(arg0, fmt::internal::make_arg_list< \
- fmt::BasicFormatter<Char> >(array, args...)); \
+ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
+ typename ArgArray::Type array{ \
+ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
+ func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \
}
// Defines a variadic constructor.
# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
template <typename... Args> \
ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
- typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
- func(arg0, arg1, fmt::internal::make_arg_list< \
- fmt::BasicFormatter<Char> >(array, args...)); \
+ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
+ typename ArgArray::Type array{ \
+ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
+ func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \
}
#else
@@ -2207,7 +2249,8 @@ class BasicWriter {
// Writes a decimal integer.
template <typename Int>
void write_decimal(Int value) {
- typename internal::IntTraits<Int>::MainType abs_value = value;
+ typedef typename internal::IntTraits<Int>::MainType MainType;
+ MainType abs_value = static_cast<MainType>(value);
if (internal::is_negative(value)) {
abs_value = 0 - abs_value;
*write_unsigned_decimal(abs_value, 1) = '-';
@@ -2474,9 +2517,9 @@ void BasicWriter<Char>::write_str(
return;
}
}
- std::size_t precision = spec.precision_;
+ std::size_t precision = static_cast<std::size_t>(spec.precision_);
if (spec.precision_ >= 0 && precision < str_size)
- str_size = spec.precision_;
+ str_size = precision;
write_str(str_value, str_size, spec);
}
@@ -2510,7 +2553,8 @@ typename BasicWriter<Char>::CharPtr
// is specified.
if (prefix_size > 0 && prefix[prefix_size - 1] == '0')
--prefix_size;
- unsigned number_size = prefix_size + spec.precision();
+ unsigned number_size =
+ prefix_size + internal::to_unsigned(spec.precision());
AlignSpec subspec(number_size, '0', ALIGN_NUMERIC);
if (number_size >= width)
return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);
@@ -2564,7 +2608,7 @@ template <typename T, typename Spec>
void BasicWriter<Char>::write_int(T value, Spec spec) {
unsigned prefix_size = 0;
typedef typename internal::IntTraits<T>::MainType UnsignedType;
- UnsignedType abs_value = value;
+ UnsignedType abs_value = static_cast<UnsignedType>(value);
char prefix[4] = "";
if (internal::is_negative(value)) {
prefix[0] = '-';
@@ -2643,8 +2687,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
template <typename Char>
template <typename T>
-void BasicWriter<Char>::write_double(
- T value, const FormatSpec &spec) {
+void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) {
// Check type.
char type = spec.type();
bool upper = false;
@@ -2744,6 +2787,8 @@ void BasicWriter<Char>::write_double(
// Format using snprintf.
Char fill = internal::CharTraits<Char>::cast(spec.fill());
+ unsigned n = 0;
+ Char *start = 0;
for (;;) {
std::size_t buffer_size = buffer_.capacity() - offset;
#ifdef _MSC_VER
@@ -2755,41 +2800,44 @@ void BasicWriter<Char>::write_double(
buffer_size = buffer_.capacity() - offset;
}
#endif
- Char *start = &buffer_[offset];
- int n = internal::CharTraits<Char>::format_float(
+ start = &buffer_[offset];
+ int result = internal::CharTraits<Char>::format_float(
start, buffer_size, format, width_for_sprintf, spec.precision(), value);
- if (n >= 0 && offset + n < buffer_.capacity()) {
- if (sign) {
- if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
- *start != ' ') {
- *(start - 1) = sign;
- sign = 0;
- } else {
- *(start - 1) = fill;
- }
- ++n;
- }
- if (spec.align() == ALIGN_CENTER &&
- spec.width() > static_cast<unsigned>(n)) {
- width = spec.width();
- CharPtr p = grow_buffer(width);
- std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char));
- fill_padding(p, spec.width(), n, fill);
- return;
- }
- if (spec.fill() != ' ' || sign) {
- while (*start == ' ')
- *start++ = fill;
- if (sign)
- *(start - 1) = sign;
- }
- grow_buffer(n);
- return;
+ if (result >= 0) {
+ n = internal::to_unsigned(result);
+ if (offset + n < buffer_.capacity())
+ break; // The buffer is large enough - continue with formatting.
+ buffer_.reserve(offset + n + 1);
+ } else {
+ // If result is negative we ask to increase the capacity by at least 1,
+ // but as std::vector, the buffer grows exponentially.
+ buffer_.reserve(buffer_.capacity() + 1);
}
- // If n is negative we ask to increase the capacity by at least 1,
- // but as std::vector, the buffer grows exponentially.
- buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
}
+ if (sign) {
+ if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
+ *start != ' ') {
+ *(start - 1) = sign;
+ sign = 0;
+ } else {
+ *(start - 1) = fill;
+ }
+ ++n;
+ }
+ if (spec.align() == ALIGN_CENTER && spec.width() > n) {
+ width = spec.width();
+ CharPtr p = grow_buffer(width);
+ std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char));
+ fill_padding(p, spec.width(), n, fill);
+ return;
+ }
+ if (spec.fill() != ' ' || sign) {
+ while (*start == ' ')
+ *start++ = fill;
+ if (sign)
+ *(start - 1) = sign;
+ }
+ grow_buffer(n);
}
/**
@@ -2920,22 +2968,21 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
output << value;
BasicStringRef<Char> str(&buffer[0], format_buf.size());
- typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
- internal::Arg arg = MakeValue(str);
- arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str));
- format_str = f.format(format_str, arg);
+ typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
+ format_str = f.format(format_str, MakeArg(str));
}
// Reports a system error without throwing an exception.
// Can be used to report errors from destructors.
-void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
+FMT_API void report_system_error(int error_code,
+ StringRef message) FMT_NOEXCEPT;
#if FMT_USE_WINDOWS_H
/** A Windows error. */
class WindowsError : public SystemError {
private:
- void init(int error_code, CStringRef format_str, ArgList args);
+ FMT_API void init(int error_code, CStringRef format_str, ArgList args);
public:
/**
@@ -2974,7 +3021,8 @@ class WindowsError : public SystemError {
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
-void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
+FMT_API void report_windows_error(int error_code,
+ StringRef message) FMT_NOEXCEPT;
#endif
@@ -2986,7 +3034,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
Example:
print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23);
*/
-void print_colored(Color c, CStringRef format, ArgList args);
+FMT_API void print_colored(Color c, CStringRef format, ArgList args);
/**
\rst
@@ -3018,7 +3066,7 @@ inline std::wstring format(WCStringRef format_str, ArgList args) {
print(stderr, "Don't {}!", "panic");
\endrst
*/
-void print(std::FILE *f, CStringRef format_str, ArgList args);
+FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args);
/**
\rst
@@ -3029,7 +3077,7 @@ void print(std::FILE *f, CStringRef format_str, ArgList args);
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
-void print(CStringRef format_str, ArgList args);
+FMT_API void print(CStringRef format_str, ArgList args);
template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
@@ -3066,7 +3114,7 @@ inline std::wstring sprintf(WCStringRef format, ArgList args) {
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
-int fprintf(std::FILE *f, CStringRef format, ArgList args);
+FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
/**
\rst
@@ -3132,10 +3180,10 @@ class FormatInt {
explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {}
explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {}
- /**
- Returns the number of characters written to the output buffer.
- */
- std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; }
+ /** Returns the number of characters written to the output buffer. */
+ std::size_t size() const {
+ return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1);
+ }
/**
Returns a pointer to the output buffer content. No terminating null
@@ -3165,7 +3213,8 @@ class FormatInt {
// write a terminating null character.
template <typename T>
inline void format_decimal(char *&buffer, T value) {
- typename internal::IntTraits<T>::MainType abs_value = value;
+ typedef typename internal::IntTraits<T>::MainType MainType;
+ MainType abs_value = static_cast<MainType>(value);
if (internal::is_negative(value)) {
*buffer++ = '-';
abs_value = 0 - abs_value;
@@ -3245,10 +3294,11 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
template <typename... Args> \
ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const Args & ... args) { \
- typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
+ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \
+ typename ArgArray::Type array{ \
+ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
- fmt::internal::make_arg_list< \
- fmt::BasicFormatter<Char> >(array, args...)); \
+ fmt::ArgList(fmt::internal::make_type(args...), array)); \
}
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
@@ -3361,8 +3411,20 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
print(cerr, "Don't {}!", "panic");
\endrst
*/
-void print(std::ostream &os, CStringRef format_str, ArgList args);
+FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
+
+/**
+ \rst
+ Prints formatted data to the stream *os*.
+
+ **Example**::
+
+ fprintf(cerr, "Don't %s!", "panic");
+ \endrst
+ */
+FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
+FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
#endif
namespace internal {
@@ -3374,7 +3436,7 @@ inline bool is_name_start(Char c) {
// Parses an unsigned integer advancing s to the end of the parsed input.
// This function assumes that the first character of s is a digit.
template <typename Char>
-int parse_nonnegative_int(const Char *&s) {
+unsigned parse_nonnegative_int(const Char *&s) {
assert('0' <= *s && *s <= '9');
unsigned value = 0;
do {
@@ -3453,7 +3515,6 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) {
return arg;
}
-// Should be after FormatSpec
template <typename Char>
const Char *BasicFormatter<Char>::format(
const Char *&format_str, const internal::Arg &arg) {
diff --git a/dep/cppformat/posix.cc b/dep/cppformat/cppformat/posix.cc
index 756281a0ebd..c6c2ae2c413 100644
--- a/dep/cppformat/posix.cc
+++ b/dep/cppformat/cppformat/posix.cc
@@ -173,7 +173,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) {
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot read from file");
- return result;
+ return internal::to_unsigned(result);
}
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
@@ -181,7 +181,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) {
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot write to file");
- return result;
+ return internal::to_unsigned(result);
}
fmt::File fmt::File::dup(int fd) {
diff --git a/dep/cppformat/posix.h b/dep/cppformat/cppformat/posix.h
index 88bcb4f557b..bfbd3851838 100644
--- a/dep/cppformat/posix.h
+++ b/dep/cppformat/cppformat/posix.h
@@ -34,11 +34,17 @@
#endif
#include <errno.h>
-#include <fcntl.h> // for O_RDONLY
+#include <fcntl.h> // for O_RDONLY
+#include <locale.h> // for locale_t
#include <stdio.h>
+#include <stdlib.h> // for strtod_l
#include <cstddef>
+#ifdef __APPLE__
+# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
+#endif
+
#include "format.h"
#ifndef FMT_POSIX
@@ -299,7 +305,8 @@ class File {
// Closes the file.
void close();
- // Returns the file size.
+ // Returns the file size. The size has signed type for consistency with
+ // stat::st_size.
LongLong size() const;
// Attempts to read count bytes from the file into the specified buffer.
@@ -331,6 +338,58 @@ class File {
// Returns the memory page size.
long getpagesize();
+
+#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER)
+# define FMT_LOCALE
+#endif
+
+#ifdef FMT_LOCALE
+// A "C" numeric locale.
+class Locale {
+ private:
+# ifdef _MSC_VER
+ typedef _locale_t locale_t;
+
+ enum { LC_NUMERIC_MASK = LC_NUMERIC };
+
+ static locale_t newlocale(int category_mask, const char *locale, locale_t) {
+ return _create_locale(category_mask, locale);
+ }
+
+ static void freelocale(locale_t locale) {
+ _free_locale(locale);
+ }
+
+ static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
+ return _strtod_l(nptr, endptr, locale);
+ }
+# endif
+
+ locale_t locale_;
+
+ FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
+
+ public:
+ typedef locale_t Type;
+
+ Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) {
+ if (!locale_)
+ throw fmt::SystemError(errno, "cannot create locale");
+ }
+ ~Locale() { freelocale(locale_); }
+
+ Type get() const { return locale_; }
+
+ // Converts string to floating-point number and advances str past the end
+ // of the parsed input.
+ double strtod(const char *&str) const {
+ char *end = 0;
+ double result = strtod_l(str, &end, locale_);
+ str = end;
+ return result;
+ }
+};
+#endif // FMT_LOCALE
} // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
diff --git a/dep/efsw/.hg_archival.txt b/dep/efsw/.hg_archival.txt
new file mode 100644
index 00000000000..19565afb668
--- /dev/null
+++ b/dep/efsw/.hg_archival.txt
@@ -0,0 +1,5 @@
+repo: 78c2ea8c48b213ee0078d6326a1dd719d0844764
+node: ff0b69daeca1edf7785a8a580518e462be5a6f3d
+branch: default
+latesttag: null
+latesttagdistance: 144
diff --git a/dep/efsw/CMakeLists.txt b/dep/efsw/CMakeLists.txt
new file mode 100644
index 00000000000..eecc5531944
--- /dev/null
+++ b/dep/efsw/CMakeLists.txt
@@ -0,0 +1,85 @@
+if (BUILD_SHARED_LIBS)
+ set(SRCS
+ src/efsw/DirectorySnapshot.cpp
+ src/efsw/DirectorySnapshotDiff.cpp
+ src/efsw/DirWatcherGeneric.cpp
+ src/efsw/FileInfo.cpp
+ src/efsw/FileSystem.cpp
+ src/efsw/FileWatcher.cpp
+ src/efsw/FileWatcherCWrapper.cpp
+ src/efsw/FileWatcherGeneric.cpp
+ src/efsw/FileWatcherImpl.cpp
+ src/efsw/Log.cpp
+ src/efsw/Mutex.cpp
+ src/efsw/String.cpp
+ src/efsw/System.cpp
+ src/efsw/Thread.cpp
+ src/efsw/Watcher.cpp
+ src/efsw/WatcherGeneric.cpp)
+
+ if(WIN32)
+ list(APPEND SRCS
+ src/efsw/platform/win/FileSystemImpl.cpp
+ src/efsw/platform/win/MutexImpl.cpp
+ src/efsw/platform/win/SystemImpl.cpp
+ src/efsw/platform/win/ThreadImpl.cpp)
+ else()
+ list(APPEND SRCS
+ src/efsw/platform/posix/FileSystemImpl.cpp
+ src/efsw/platform/posix/MutexImpl.cpp
+ src/efsw/platform/posix/SystemImpl.cpp
+ src/efsw/platform/posix/ThreadImpl.cpp)
+ endif()
+
+ if (WIN32)
+ list(APPEND SRCS
+ src/efsw/WatcherWin32.cpp
+ src/efsw/FileWatcherWin32.cpp)
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ list(APPEND SRCS
+ src/efsw/FileWatcherInotify.cpp
+ src/efsw/WatcherInotify.cpp)
+
+ if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h")
+ add_definitions(-DEFSW_INOTIFY_NOSYS)
+ endif()
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR APPLE)
+ list(APPEND SRCS
+ src/efsw/FileWatcherKqueue.cpp
+ src/efsw/WatcherKqueue.cpp)
+
+ if (APPLE)
+ list(APPEND SRCS
+ src/efsw/FileWatcherFSEvents.cpp
+ src/efsw/WatcherFSEvents.cpp)
+
+ exec_program(uname ARGS -v OUTPUT_VARIABLE OSX_VERSION)
+ string(REGEX MATCH "[0-9]+" OSX_VERSION ${OSX_VERSION})
+ if (NOT OSX_VERSION GREATER 9)
+ add_definitions(-DEFSW_FSEVENTS_NOT_SUPPORTED)
+ endif()
+
+ set(OPTIONAL_MAC_LINK_LIBRARIES "-framework CoreFoundation" "-framework CoreServices")
+ endif()
+ endif()
+
+ add_library(efsw STATIC ${SRCS})
+
+ target_include_directories(efsw
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src)
+
+ target_link_libraries(efsw
+ PUBLIC
+ threads
+ ${OPTIONAL_MAC_LINK_LIBRARIES})
+
+ set_target_properties(efsw
+ PROPERTIES
+ FOLDER
+ "dep")
+else()
+ add_library(efsw INTERFACE IMPORTED GLOBAL)
+endif()
diff --git a/dep/efsw/LICENSE b/dep/efsw/LICENSE
new file mode 100644
index 00000000000..ac8ac28988d
--- /dev/null
+++ b/dep/efsw/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Martín Lucas Golini
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
+http://code.google.com/p/simplefilewatcher/ also MIT licensed. \ No newline at end of file
diff --git a/dep/efsw/README.md b/dep/efsw/README.md
new file mode 100644
index 00000000000..fda0bb599aa
--- /dev/null
+++ b/dep/efsw/README.md
@@ -0,0 +1,138 @@
+Entropia File System Watcher
+============================
+**efsw** is a C++ cross-platform file system watcher and notifier.
+
+**efsw** monitors the file system asynchronously for changes to files and directories by watching a list of specified paths, and raises events when a directory or file change.
+
+**efsw** supports recursive directories watch, tracking the entire sub directory tree.
+
+**efsw** currently supports the following platforms:
+
+* Linux via [inotify](http://en.wikipedia.org/wiki/Inotify)
+
+* Windows via [I/O Completion Ports](http://en.wikipedia.org/wiki/IOCP)
+
+* Mac OS X via [FSEvents](http://en.wikipedia.org/wiki/FSEvents) or [kqueue](http://en.wikipedia.org/wiki/Kqueue)
+
+* FreeBSD/BSD via [kqueue](http://en.wikipedia.org/wiki/Kqueue)
+
+* OS-independent generic watcher
+(polling the disk for directory snapshots and comparing them periodically)
+
+If any of the backend fails to start by any reason, it will fallback to the OS-independent implementation.
+This should never happen, except for the Kqueue implementation, see `Platform limitations and clarifications`.
+
+**Code License**
+--------------
+[MIT License](http://www.opensource.org/licenses/mit-license.php)
+
+**Some example code:**
+--------------------
+
+ :::c++
+ // Inherits from the abstract listener class, and implements the the file action handler
+ class UpdateListener : public efsw::FileWatchListener
+ {
+ public:
+ UpdateListener() {}
+
+ void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" )
+ {
+ switch( action )
+ {
+ case efsw::Actions::Add:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added" << std::endl;
+ break;
+ case efsw::Actions::Delete:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete" << std::endl;
+ break;
+ case efsw::Actions::Modified:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified" << std::endl;
+ break;
+ case efsw::Actions::Moved:
+ std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from (" << oldFilename << ")" << std::endl;
+ break;
+ default:
+ std::cout << "Should never happen!" << std::endl;
+ }
+ }
+ };
+
+ // Create the file system watcher instance
+ // efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the generic file watcher instead of the platform specific backend
+ efsw::FileWatcher * fileWatcher = new efsw::FileWatcher();
+
+ // Create the instance of your efsw::FileWatcherListener implementation
+ UpdateListener * listener = new UpdateListener();
+
+ // Add a folder to watch, and get the efsw::WatchID
+ // It will watch the /tmp folder recursively ( the third parameter indicates that is recursive )
+ // Reporting the files and directories changes to the instance of the listener
+ efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true );
+
+ // Adds another directory to watch. This time as non-recursive.
+ efsw::WatchID watchID2 = fileWatcher->addWatch( "/usr", listener, false );
+
+ // Start watching asynchronously the directories
+ fileWatcher.watch();
+
+ // Remove the second watcher added
+ // You can also call removeWatch by passing the watch path ( it must end with an slash or backslash in windows, since that's how internally it's saved )
+ fileWatcher->removeWatch( watchID2 );
+
+**Dependencies**
+--------------
+None :)
+
+**Compiling**
+------------
+To generate project files you will need to [download and install](http://industriousone.com/premake/download) [Premake](http://industriousone.com/what-premake)
+
+Then you can generate the project for your platform just going to the project directory where the premake4.lua file is located and then execute:
+
+`premake4 gmake` to generate project Makefiles, then `cd make/*YOURPLATFORM*/`, and finally `make` or `make config=release` ( it will generate the static lib, the shared lib and the test application ).
+
+or
+
+`premake4 vs2010` to generate Visual Studio 2010 project.
+
+or
+
+`premake4 xcode4` to generate Xcode 4 project.
+
+There is also a cmake file that i don't oficially support but it works just fine, provided by [Mohammed Nafees](https://bitbucket.org/binaryking).
+
+**Platform limitations and clarifications**
+-------------------------------------------
+
+Directory paths are expected to be encoded as UTF-8 strings in all platforms.
+
+handleFileAction returns UTF-8 strings in all platforms.
+
+Windows and FSEvents Mac OS X implementation can't follow symlinks ( it will ignore followSymlinks() and allowOutOfScopeLinks() ).
+
+Kqueue implementation is limited by the maximun number of file descriptors allowed per process by the OS, in the case of reaching the file descriptors limit ( in BSD around 18000 and in OS X around 10240 ) it will fallback to the generic file watcher.
+
+OS X will only use Kqueue if OS X version is below to 10.5, and this implementation needs to be compiled separately from the OS X >= 10.5 implementation. Since there's no way to compile FSEvents backend in OS X below 10.5.
+
+FSEvents for OS X Lion and beyond in some cases will generate more actions that in reality ocurred, since fine-grained implementation of FSEvents doesn't give the order of the actions retrieved, in some cases i need to guess/aproximate the order of them.
+
+Generic watcher relies on the inode information to detect file and directories renames/move. Since Windows has no concept of inodes as Unix platforms do, there is no current reliable way of determining file/directory movement on Windows without help from the Windows API ( this is replaced with Add/Delete events ).
+
+Linux versions below 2.6.13 are not supported, since inotify wasn't implemented yet. I'm not interested in support older kernels, since i don't see the point. If someone needs this open an issue in the issue tracker and i may consider implenent a dnotify backend.
+
+OS-independent watcher, Kqueue and FSEvents for OS X below 10.5 keep cache of the directories structures, to be able to detect changes in the directories. This means that there's a memory overhead for this backends.
+
+**Useful information**
+--------------------
+The project also comes with a C API wrapper, contributed by [Sepul Sepehr Taghdisian](https://bitbucket.org/sepul).
+
+There's a string manipulation class not exposed in the efsw header ( efsw::String ) that can be used to make string encoding conversion.
+
+
+**Clarifications**
+----------------
+
+This software started as a fork of the [simplefilewatcher](http://code.google.com/p/simplefilewatcher/) by James Wynn (james[at]jameswynn.com), [MIT licensed](http://www.opensource.org/licenses/mit-license.html).
+
+The icon used for the project is part of the [Haiku®'s Icons](http://www.haiku-inc.org/haiku-icons.html), [MIT licensed](http://www.opensource.org/licenses/mit-license.html).
diff --git a/dep/efsw/include/efsw/efsw.h b/dep/efsw/include/efsw/efsw.h
new file mode 100644
index 00000000000..28e63e2139e
--- /dev/null
+++ b/dep/efsw/include/efsw/efsw.h
@@ -0,0 +1,151 @@
+/**
+ @author Sepul Sepehr Taghdisian
+
+ Copyright (c) 2013 Martin Lucas Golini
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
+ http://code.google.com/p/simplefilewatcher/ also MIT licensed.
+*/
+/** This is the C API wrapper of EFSW */
+#ifndef ESFW_H
+#define ESFW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_WIN32)
+ #ifdef EFSW_DYNAMIC
+ // Windows platforms
+ #ifdef EFSW_EXPORTS
+ // From DLL side, we must export
+ #define EFSW_API __declspec(dllexport)
+ #else
+ // From client application side, we must import
+ #define EFSW_API __declspec(dllimport)
+ #endif
+ #else
+ // No specific directive needed for static build
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+ #endif
+#else
+ #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
+ #define EFSW_API __attribute__ ((visibility("default")))
+ #endif
+
+ // Other platforms don't need to define anything
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+#endif
+
+/// Type for a watch id
+typedef long efsw_watchid;
+
+/// Type for watcher
+typedef void* efsw_watcher;
+
+enum efsw_action
+{
+ EFSW_ADD = 1, /// Sent when a file is created or renamed
+ EFSW_DELETE = 2, /// Sent when a file is deleted or renamed
+ EFSW_MODIFIED = 3, /// Sent when a file is modified
+ EFSW_MOVED = 4 /// Sent when a file is moved
+};
+
+enum efsw_error
+{
+ EFSW_NOTFOUND = -1,
+ EFSW_REPEATED = -2,
+ EFSW_OUTOFSCOPE = -3,
+ EFSW_NOTREADABLE = -4,
+ EFSW_REMOTE = -5,
+ EFSW_UNSPECIFIED = -6
+};
+
+/// Basic interface for listening for file events.
+typedef void (*efsw_pfn_fileaction_callback) (
+ efsw_watcher watcher,
+ efsw_watchid watchid,
+ const char* dir,
+ const char* filename,
+ enum efsw_action action,
+ const char* old_filename,
+ void* param
+);
+
+/**
+ * Creates a new file-watcher
+ * @param generic_mode Force the use of the Generic file watcher
+ */
+efsw_watcher EFSW_API efsw_create(int generic_mode);
+
+/// Release the file-watcher and unwatch any directories
+void EFSW_API efsw_release(efsw_watcher watcher);
+
+/// Retreive last error occured by file-watcher
+EFSW_API const char* efsw_getlasterror();
+
+/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
+/// For backwards compatibility.
+/// On error returns WatchID with Error type.
+efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory,
+ efsw_pfn_fileaction_callback callback_fn, int recursive, void* param);
+
+/// Remove a directory watch. This is a brute force search O(nlogn).
+void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory);
+
+/// Remove a directory watch. This is a map lookup O(logn).
+void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid);
+
+/// Starts watching ( in other thread )
+void EFSW_API efsw_watch(efsw_watcher watcher);
+
+/**
+ * Allow recursive watchers to follow symbolic links to other directories
+ * followSymlinks is disabled by default
+ */
+void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable);
+
+/** @return If can follow symbolic links to directorioes */
+int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher);
+
+/**
+ * When enable this it will allow symlinks to watch recursively out of the pointed directory.
+ * follorSymlinks must be enabled to this work.
+ * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed,
+ * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion.
+ * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ).
+ * Buy enabling out of scope links, it will allow this behavior.
+ * allowOutOfScopeLinks are disabled by default.
+ */
+void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow);
+
+/// @return Returns if out of scope links are allowed
+int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dep/efsw/include/efsw/efsw.hpp b/dep/efsw/include/efsw/efsw.hpp
new file mode 100644
index 00000000000..0693bb296f0
--- /dev/null
+++ b/dep/efsw/include/efsw/efsw.hpp
@@ -0,0 +1,197 @@
+/**
+ @author Martín Lucas Golini
+
+ Copyright (c) 2013 Martín Lucas Golini
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
+ http://code.google.com/p/simplefilewatcher/ also MIT licensed.
+*/
+
+#ifndef ESFW_HPP
+#define ESFW_HPP
+
+#include <string>
+#include <list>
+
+#if defined(_WIN32)
+ #ifdef EFSW_DYNAMIC
+ // Windows platforms
+ #ifdef EFSW_EXPORTS
+ // From DLL side, we must export
+ #define EFSW_API __declspec(dllexport)
+ #else
+ // From client application side, we must import
+ #define EFSW_API __declspec(dllimport)
+ #endif
+ #else
+ // No specific directive needed for static build
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+ #endif
+#else
+ #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
+ #define EFSW_API __attribute__ ((visibility("default")))
+ #endif
+
+ // Other platforms don't need to define anything
+ #ifndef EFSW_API
+ #define EFSW_API
+ #endif
+#endif
+
+namespace efsw {
+
+/// Type for a watch id
+typedef long WatchID;
+
+// forward declarations
+class FileWatcherImpl;
+class FileWatchListener;
+
+/// Actions to listen for. Rename will send two events, one for
+/// the deletion of the old file, and one for the creation of the
+/// new file.
+namespace Actions {
+ enum Action
+ {
+ /// Sent when a file is created or renamed
+ Add = 1,
+ /// Sent when a file is deleted or renamed
+ Delete = 2,
+ /// Sent when a file is modified
+ Modified = 3,
+ /// Sent when a file is moved
+ Moved = 4
+ };
+}
+typedef Actions::Action Action;
+
+/// Errors log namespace
+namespace Errors {
+
+enum Error
+{
+ FileNotFound = -1,
+ FileRepeated = -2,
+ FileOutOfScope = -3,
+ FileNotReadable = -4,
+ FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to watch this directory ). */
+ Unspecified = -6
+};
+
+class EFSW_API Log
+{
+ public:
+ /// @return The last error logged
+ static std::string getLastErrorLog();
+
+ /// Creates an error of the type specified
+ static Error createLastError( Error err, std::string log );
+};
+
+}
+typedef Errors::Error Error;
+
+/// Listens to files and directories and dispatches events
+/// to notify the listener of files and directories changes.
+/// @class FileWatcher
+class EFSW_API FileWatcher
+{
+ public:
+ /// Default constructor, will use the default platform file watcher
+ FileWatcher();
+
+ /// Constructor that lets you force the use of the Generic File Watcher
+ FileWatcher( bool useGenericFileWatcher );
+
+ virtual ~FileWatcher();
+
+ /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
+ /// For backwards compatibility.
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher);
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Starts watching ( in other thread )
+ void watch();
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+
+ /** Allow recursive watchers to follow symbolic links to other directories
+ * followSymlinks is disabled by default
+ */
+ void followSymlinks( bool follow );
+
+ /** @return If can follow symbolic links to directorioes */
+ const bool& followSymlinks() const;
+
+ /** When enable this it will allow symlinks to watch recursively out of the pointed directory.
+ * follorSymlinks must be enabled to this work.
+ * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed,
+ * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion.
+ * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ).
+ * Buy enabling out of scope links, it will allow this behavior.
+ * allowOutOfScopeLinks are disabled by default.
+ */
+ void allowOutOfScopeLinks( bool allow );
+
+ /// @return Returns if out of scope links are allowed
+ const bool& allowOutOfScopeLinks() const;
+ private:
+ /// The implementation
+ FileWatcherImpl * mImpl;
+ bool mFollowSymlinks;
+ bool mOutOfScopeLinks;
+};
+
+/// Basic interface for listening for file events.
+/// @class FileWatchListener
+class FileWatchListener
+{
+ public:
+ FileWatchListener() {}
+
+ virtual ~FileWatchListener() {}
+
+ /// Handles the action file action
+ /// @param watchid The watch id for the directory
+ /// @param dir The directory
+ /// @param filename The filename that was accessed (not full path)
+ /// @param action Action that was performed
+ /// @param oldFilename The name of the file or directory moved
+ virtual void handleFileAction(WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ) = 0;
+
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/Debug.cpp b/dep/efsw/src/efsw/Debug.cpp
new file mode 100644
index 00000000000..9c4ee02e5b6
--- /dev/null
+++ b/dep/efsw/src/efsw/Debug.cpp
@@ -0,0 +1,85 @@
+#include <efsw/Debug.hpp>
+#include <iostream>
+
+#ifdef EFSW_COMPILER_MSVC
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <crtdbg.h>
+#endif
+
+#include <cassert>
+#include <cstdio>
+#include <cstdarg>
+
+namespace efsw {
+
+#ifdef DEBUG
+
+void efREPORT_ASSERT( const char * File, int Line, const char * Exp )
+{
+ #ifdef EFSW_COMPILER_MSVC
+ _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp);
+
+ DebugBreak();
+ #else
+ std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl;
+
+ #if defined(EFSW_COMPILER_GCC) && defined(EFSW_32BIT) && !defined(EFSW_ARM)
+ asm("int3");
+ #else
+ assert( false );
+ #endif
+ #endif
+}
+
+void efPRINT( const char * format, ... )
+{
+ char buf[2048];
+ va_list args;
+
+ va_start( args, format );
+
+ #ifdef EFSW_COMPILER_MSVC
+ _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0]), format, args );
+ #else
+ vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args );
+ #endif
+
+ va_end( args );
+
+ #ifdef EFSW_COMPILER_MSVC
+ OutputDebugStringA( buf );
+ #else
+ std::cout << buf;
+ #endif
+}
+
+void efPRINTC( unsigned int cond, const char * format, ...)
+{
+ if ( 0 == cond )
+ return;
+
+ char buf[2048];
+ va_list args;
+
+ va_start( args, format );
+
+ #ifdef EFSW_COMPILER_MSVC
+ _vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args );
+ #else
+ vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args );
+ #endif
+
+ va_end( args );
+
+ #ifdef EFSW_COMPILER_MSVC
+ OutputDebugStringA( buf );
+ #else
+ std::cout << buf;
+ #endif
+}
+
+#endif
+
+}
+
diff --git a/dep/efsw/src/efsw/Debug.hpp b/dep/efsw/src/efsw/Debug.hpp
new file mode 100644
index 00000000000..75d6dce0466
--- /dev/null
+++ b/dep/efsw/src/efsw/Debug.hpp
@@ -0,0 +1,50 @@
+#ifndef EFSW_DEBUG_HPP
+#define EFSW_DEBUG_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+#ifdef DEBUG
+
+void efREPORT_ASSERT( const char * File, const int Line, const char * Exp );
+
+#define efASSERT( expr ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #expr ); }
+#define efASSERTM( expr, msg ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #msg ); }
+
+void efPRINT ( const char * format, ... );
+void efPRINTC ( unsigned int cond, const char * format, ... );
+
+#else
+
+#define efASSERT( expr )
+#define efASSERTM( expr, msg )
+
+#ifndef EFSW_COMPILER_MSVC
+ #define efPRINT( format, args... ) {}
+ #define efPRINTC( cond, format, args... ) {}
+#else
+ #define efPRINT
+ #define efPRINTC
+#endif
+
+#endif
+
+#ifdef EFSW_VERBOSE
+ #define efDEBUG efPRINT
+ #define efDEBUGC efPRINTC
+#else
+
+ #ifndef EFSW_COMPILER_MSVC
+ #define efDEBUG( format, args... ) {}
+ #define efDEBUGC( cond, format, args... ) {}
+ #else
+ #define efDEBUG
+ #define efDEBUGC
+ #endif
+
+#endif
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/DirWatcherGeneric.cpp b/dep/efsw/src/efsw/DirWatcherGeneric.cpp
new file mode 100644
index 00000000000..b80c14d24ce
--- /dev/null
+++ b/dep/efsw/src/efsw/DirWatcherGeneric.cpp
@@ -0,0 +1,451 @@
+#include <efsw/DirWatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/Debug.hpp>
+#include <efsw/String.hpp>
+
+namespace efsw {
+
+DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles ) :
+ Parent( parent ),
+ Watch( ws ),
+ Recursive( recursive ),
+ Deleted( false )
+{
+ resetDirectory( directory );
+
+ if ( !reportNewFiles )
+ {
+ DirSnap.scan();
+ }
+ else
+ {
+ DirectorySnapshotDiff Diff = DirSnap.scan();
+
+ if ( Diff.changed() )
+ {
+ FileInfoList::iterator it;
+
+ DiffIterator( FilesCreated )
+ {
+ handleAction( ( *it ).Filepath, Actions::Add );
+ }
+ }
+ }
+}
+
+DirWatcherGeneric::~DirWatcherGeneric()
+{
+ /// If the directory was deleted mark the files as deleted
+ if ( Deleted )
+ {
+ DirectorySnapshotDiff Diff = DirSnap.scan();
+
+ if ( !DirSnap.exists() )
+ {
+ FileInfoList::iterator it;
+
+ DiffIterator( FilesDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ }
+
+ DiffIterator( DirsDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ }
+ }
+ }
+
+ DirWatchMap::iterator it = Directories.begin();
+
+ for ( ; it != Directories.end(); it++ )
+ {
+ if ( Deleted )
+ {
+ /// If the directory was deleted, mark the flag for file deletion
+ it->second->Deleted = true;
+ }
+
+ efSAFE_DELETE( it->second );
+ }
+}
+
+void DirWatcherGeneric::resetDirectory( std::string directory )
+{
+ std::string dir( directory );
+
+ /// Is this a recursive watch?
+ if ( Watch->Directory != directory )
+ {
+ if ( !( directory.size() && ( directory.at(0) == FileSystem::getOSSlash() || directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) )
+ {
+ /// Get the real directory
+ if ( NULL != Parent )
+ {
+ FileSystem::dirAddSlashAtEnd(directory);
+
+ dir = Parent->DirSnap.DirectoryInfo.Filepath + directory;
+ }
+ else
+ {
+ efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." );
+ }
+ }
+ }
+
+ DirSnap.setDirectoryInfo( dir );
+}
+
+void DirWatcherGeneric::handleAction( const std::string &filename, unsigned long action, std::string oldFilename)
+{
+ Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, FileSystem::fileNameFromPath( filename ), (Action)action, oldFilename );
+}
+
+void DirWatcherGeneric::addChilds( bool reportNewFiles )
+{
+ if ( Recursive )
+ {
+ /// Create the subdirectories watchers
+ std::string dir;
+
+ for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ )
+ {
+ if ( it->second.isDirectory() && it->second.isReadable() && !FileSystem::isRemoteFS( it->second.Filepath ) )
+ {
+ /// Check if the directory is a symbolic link
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) );
+
+ dir = it->first;
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() )
+ {
+ continue;
+ }
+
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) )
+ {
+ continue;
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+ else
+ {
+ if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) )
+ {
+ continue;
+ }
+ }
+
+ if ( reportNewFiles )
+ {
+ handleAction( dir, Actions::Add );
+ }
+
+ Directories[dir] = new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles );
+
+ Directories[dir]->addChilds( reportNewFiles );
+ }
+ }
+ }
+}
+
+void DirWatcherGeneric::watch( bool reportOwnChange )
+{
+ DirectorySnapshotDiff Diff = DirSnap.scan();
+
+ if ( reportOwnChange && Diff.DirChanged && NULL != Parent )
+ {
+ Watch->Listener->handleFileAction( Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified );
+ }
+
+ if ( Diff.changed() )
+ {
+ FileInfoList::iterator it;
+ MovedList::iterator mit;
+
+ /// Files
+ DiffIterator( FilesCreated )
+ {
+ handleAction( (*it).Filepath, Actions::Add );
+ }
+
+ DiffIterator( FilesModified )
+ {
+ handleAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( FilesDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ }
+
+ DiffMovedIterator( FilesMoved )
+ {
+ handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
+ }
+
+ /// Directories
+ DiffIterator( DirsCreated )
+ {
+ createDirectory( (*it).Filepath );
+ }
+
+ DiffIterator( DirsModified )
+ {
+ handleAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( DirsDeleted )
+ {
+ handleAction( (*it).Filepath, Actions::Delete );
+ removeDirectory( (*it).Filepath );
+ }
+
+ DiffMovedIterator( DirsMoved )
+ {
+ handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
+ moveDirectory( (*mit).first, (*mit).second.Filepath );
+ }
+ }
+
+ /// Process the subdirectories looking for changes
+ for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); dit++ )
+ {
+ /// Just watch
+ dit->second->watch();
+ }
+}
+
+void DirWatcherGeneric::watchDir( std::string &dir )
+{
+ DirWatcherGeneric * watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() ?
+ findDirWatcher( dir ) :
+ findDirWatcherFast( dir );
+
+ if ( NULL != watcher )
+ {
+ watcher->watch( true );
+ }
+}
+
+DirWatcherGeneric * DirWatcherGeneric::findDirWatcherFast( std::string dir )
+{
+ // remove the common base ( dir should always start with the same base as the watcher )
+ efASSERT( !dir.empty() );
+ efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() );
+ efASSERT( DirSnap.DirectoryInfo.Filepath == dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) );
+
+ if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() )
+ {
+ dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 );
+ }
+
+ if ( dir.size() == 1 )
+ {
+ efASSERT( dir[0] == FileSystem::getOSSlash() );
+ return this;
+ }
+
+ size_t level = 0;
+ std::vector<std::string> dirv = String::split( dir, FileSystem::getOSSlash(), false );
+
+ DirWatcherGeneric * watcher = this;
+
+ while ( level < dirv.size() )
+ {
+ // search the dir level in the current watcher
+ DirWatchMap::iterator it = watcher->Directories.find( dirv[ level ] );
+
+ // found? continue with the next level
+ if ( it != watcher->Directories.end() )
+ {
+ watcher = it->second;
+
+ level++;
+ }
+ else
+ {
+ // couldn't found the folder level?
+ // directory not watched
+ return NULL;
+ }
+ }
+
+ return watcher;
+}
+
+DirWatcherGeneric * DirWatcherGeneric::findDirWatcher( std::string dir )
+{
+ if ( DirSnap.DirectoryInfo.Filepath == dir )
+ {
+ return this;
+ }
+ else
+ {
+ DirWatcherGeneric * watcher = NULL;
+
+ for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ )
+ {
+ watcher = it->second->findDirWatcher( dir );
+
+ if ( NULL != watcher )
+ {
+ return watcher;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+DirWatcherGeneric * DirWatcherGeneric::createDirectory( std::string newdir )
+{
+ FileSystem::dirRemoveSlashAtEnd( newdir );
+ newdir = FileSystem::fileNameFromPath( newdir );
+
+ DirWatcherGeneric * dw = NULL;
+
+ /// Check if the directory is a symbolic link
+ std::string dir( DirSnap.DirectoryInfo.Filepath + newdir );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) )
+ {
+ return NULL;
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+ bool skip = false;
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() )
+ {
+ skip = true;
+ }
+
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || !Watch->WatcherImpl->linkAllowed( curPath, link ) )
+ {
+ skip = true;
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+ else
+ {
+ if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) )
+ {
+ skip = true;
+ }
+ }
+
+ if ( !skip )
+ {
+ handleAction( newdir, Actions::Add );
+
+ /// Creates the new directory watcher of the subfolder and check for new files
+ dw = new DirWatcherGeneric( this, Watch, dir, Recursive );
+
+ dw->addChilds();
+
+ dw->watch();
+
+ /// Add it to the list of directories
+ Directories[ newdir ] = dw;
+ }
+
+ return dw;
+}
+
+void DirWatcherGeneric::removeDirectory( std::string dir )
+{
+ FileSystem::dirRemoveSlashAtEnd( dir );
+ dir = FileSystem::fileNameFromPath( dir );
+
+ DirWatcherGeneric * dw = NULL;
+ DirWatchMap::iterator dit;
+
+ /// Folder deleted
+
+ /// Search the folder, it should exists
+ dit = Directories.find( dir );
+
+ if ( dit != Directories.end() )
+ {
+ dw = dit->second;
+
+ /// Flag it as deleted so it fire the event for every file inside deleted
+ dw->Deleted = true;
+
+ /// Delete the DirWatcherGeneric
+ efSAFE_DELETE( dw );
+
+ /// Remove the directory from the map
+ Directories.erase( dit->first );
+ }
+}
+
+void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir )
+{
+ FileSystem::dirRemoveSlashAtEnd( oldDir );
+ oldDir = FileSystem::fileNameFromPath( oldDir );
+
+ FileSystem::dirRemoveSlashAtEnd( newDir );
+ newDir = FileSystem::fileNameFromPath( newDir );
+
+ DirWatcherGeneric * dw = NULL;
+ DirWatchMap::iterator dit;
+
+ /// Directory existed?
+ dit = Directories.find( oldDir );
+
+ if ( dit != Directories.end() )
+ {
+ dw = dit->second;
+
+ /// Remove the directory from the map
+ Directories.erase( dit->first );
+
+ Directories[ newDir ] = dw;
+
+ dw->resetDirectory( newDir );
+ }
+}
+
+bool DirWatcherGeneric::pathInWatches( std::string path )
+{
+ if ( DirSnap.DirectoryInfo.Filepath == path )
+ {
+ return true;
+ }
+
+ for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); it++ )
+ {
+ if ( it->second->pathInWatches( path ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/dep/efsw/src/efsw/DirWatcherGeneric.hpp b/dep/efsw/src/efsw/DirWatcherGeneric.hpp
new file mode 100644
index 00000000000..a7581904422
--- /dev/null
+++ b/dep/efsw/src/efsw/DirWatcherGeneric.hpp
@@ -0,0 +1,55 @@
+#ifndef EFSW_DIRWATCHERGENERIC_HPP
+#define EFSW_DIRWATCHERGENERIC_HPP
+
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileInfo.hpp>
+#include <efsw/DirectorySnapshot.hpp>
+#include <map>
+
+namespace efsw {
+
+class DirWatcherGeneric
+{
+ public:
+ typedef std::map<std::string, DirWatcherGeneric*> DirWatchMap;
+
+ DirWatcherGeneric * Parent;
+ WatcherGeneric * Watch;
+ DirectorySnapshot DirSnap;
+ DirWatchMap Directories;
+ bool Recursive;
+
+ DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles = false );
+
+ ~DirWatcherGeneric();
+
+ void watch( bool reportOwnChange = false );
+
+ void watchDir( std::string& dir );
+
+ static bool isDir( const std::string& directory );
+
+ bool pathInWatches( std::string path );
+
+ void addChilds( bool reportNewFiles = true );
+
+ DirWatcherGeneric * findDirWatcher( std::string dir );
+
+ DirWatcherGeneric * findDirWatcherFast( std::string dir );
+ protected:
+ bool Deleted;
+
+ DirWatcherGeneric * createDirectory( std::string newdir );
+
+ void removeDirectory( std::string dir );
+
+ void moveDirectory( std::string oldDir, std::string newDir );
+
+ void resetDirectory( std::string directory );
+
+ void handleAction( const std::string& filename, unsigned long action, std::string oldFilename = "");
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/DirectorySnapshot.cpp b/dep/efsw/src/efsw/DirectorySnapshot.cpp
new file mode 100644
index 00000000000..c0ef747548a
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshot.cpp
@@ -0,0 +1,261 @@
+#include <efsw/DirectorySnapshot.hpp>
+#include <efsw/FileSystem.hpp>
+
+namespace efsw {
+
+DirectorySnapshot::DirectorySnapshot()
+{
+}
+
+DirectorySnapshot::DirectorySnapshot( std::string directory )
+{
+ init( directory );
+}
+
+DirectorySnapshot::~DirectorySnapshot()
+{
+}
+
+void DirectorySnapshot::init( std::string directory )
+{
+ setDirectoryInfo( directory );
+ initFiles();
+}
+
+bool DirectorySnapshot::exists()
+{
+ return DirectoryInfo.exists();
+}
+
+void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff )
+{
+ FileInfo fi;
+
+ for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ )
+ {
+ fi = it->second;
+
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsDeleted.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesDeleted.push_back( fi );
+ }
+ }
+}
+
+void DirectorySnapshot::setDirectoryInfo( std::string directory )
+{
+ DirectoryInfo = FileInfo( directory );
+}
+
+void DirectorySnapshot::initFiles()
+{
+ Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
+
+ FileInfoMap::iterator it = Files.begin();
+ std::list<std::string> eraseFiles;
+
+ /// Remove all non regular files and non directories
+ for ( ; it != Files.end(); it++ )
+ {
+ if ( !it->second.isRegularFile() && !it->second.isDirectory() )
+ {
+ eraseFiles.push_back( it->first );
+ }
+ }
+
+ for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); eit++ )
+ {
+ Files.erase( *eit );
+ }
+}
+
+DirectorySnapshotDiff DirectorySnapshot::scan()
+{
+ DirectorySnapshotDiff Diff;
+
+ Diff.clear();
+
+ FileInfo curFI( DirectoryInfo.Filepath );
+
+ Diff.DirChanged = DirectoryInfo != curFI;
+
+ if ( Diff.DirChanged )
+ {
+ DirectoryInfo = curFI;
+ }
+
+ /// If the directory was erased, create the events for files and directories deletion
+ if ( !curFI.exists() )
+ {
+ deleteAll( Diff );
+
+ return Diff;
+ }
+
+ FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
+
+ if ( files.empty() && Files.empty() )
+ {
+ return Diff;
+ }
+
+ FileInfo fi;
+ FileInfoMap FilesCpy;
+ FileInfoMap::iterator it;
+ FileInfoMap::iterator fiIt;
+
+ if ( Diff.DirChanged )
+ {
+ FilesCpy = Files;
+ }
+
+ for ( it = files.begin(); it != files.end(); it++ )
+ {
+ fi = it->second;
+
+ /// File existed before?
+ fiIt = Files.find( it->first );
+
+ if ( fiIt != Files.end() )
+ {
+ /// Erase from the file list copy
+ FilesCpy.erase( it->first );
+
+ /// File changed?
+ if ( (*fiIt).second != fi )
+ {
+ /// Update the new file info
+ Files[ it->first ] = fi;
+
+ /// handle modified event
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsModified.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesModified.push_back( fi );
+ }
+ }
+ }
+ /// Only add regular files or directories
+ else if ( fi.isRegularFile() || fi.isDirectory() )
+ {
+ /// New file found
+ Files[ it->first ] = fi;
+
+ FileInfoMap::iterator fit;
+ std::string oldFile = "";
+
+ /// Check if the same inode already existed
+ if ( ( fit = nodeInFiles( fi ) ) != Files.end() )
+ {
+ oldFile = fit->first;
+
+ /// Avoid firing a Delete event
+ FilesCpy.erase( fit->first );
+
+ /// Delete the old file name
+ Files.erase( fit->first );
+
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) );
+ }
+ else
+ {
+ Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) );
+ }
+ }
+ else
+ {
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsCreated.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesCreated.push_back( fi );
+ }
+ }
+ }
+ }
+
+ if ( !Diff.DirChanged )
+ {
+ return Diff;
+ }
+
+ /// The files or directories that remains were deleted
+ for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ )
+ {
+ fi = it->second;
+
+ if ( fi.isDirectory() )
+ {
+ Diff.DirsDeleted.push_back( fi );
+ }
+ else
+ {
+ Diff.FilesDeleted.push_back( fi );
+ }
+
+ /// Remove the file or directory from the list of files
+ Files.erase( it->first );
+ }
+
+ return Diff;
+}
+
+FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi )
+{
+ FileInfoMap::iterator it;
+
+ if ( FileInfo::inodeSupported() )
+ {
+ for ( it = Files.begin(); it != Files.end(); it++ )
+ {
+ if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath )
+ {
+ return it;
+ }
+ }
+ }
+
+ return Files.end();
+}
+
+void DirectorySnapshot::addFile( std::string path )
+{
+ std::string name( FileSystem::fileNameFromPath( path ) );
+ Files[ name ] = FileInfo( path );
+}
+
+void DirectorySnapshot::removeFile( std::string path )
+{
+ std::string name( FileSystem::fileNameFromPath( path ) );
+
+ FileInfoMap::iterator it = Files.find( name );
+
+ if ( Files.end() != it )
+ {
+ Files.erase( it );
+ }
+}
+
+void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath )
+{
+ removeFile( oldPath );
+ addFile( newPath );
+}
+
+void DirectorySnapshot::updateFile(std::string path)
+{
+ addFile( path );
+}
+
+}
diff --git a/dep/efsw/src/efsw/DirectorySnapshot.hpp b/dep/efsw/src/efsw/DirectorySnapshot.hpp
new file mode 100644
index 00000000000..1ada66fe980
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshot.hpp
@@ -0,0 +1,46 @@
+#ifndef EFSW_DIRECTORYSNAPSHOT_HPP
+#define EFSW_DIRECTORYSNAPSHOT_HPP
+
+#include <efsw/DirectorySnapshotDiff.hpp>
+
+namespace efsw {
+
+class DirectorySnapshot
+{
+ public:
+ FileInfo DirectoryInfo;
+ FileInfoMap Files;
+
+ void setDirectoryInfo( std::string directory );
+
+ DirectorySnapshot();
+
+ DirectorySnapshot( std::string directory );
+
+ ~DirectorySnapshot();
+
+ void init( std::string directory );
+
+ bool exists();
+
+ DirectorySnapshotDiff scan();
+
+ FileInfoMap::iterator nodeInFiles( FileInfo& fi );
+
+ void addFile( std::string path );
+
+ void removeFile( std::string path );
+
+ void moveFile( std::string oldPath, std::string newPath );
+
+ void updateFile( std::string path );
+ protected:
+ void initFiles();
+
+ void deleteAll( DirectorySnapshotDiff &Diff );
+};
+
+}
+
+#endif
+
diff --git a/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp b/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp
new file mode 100644
index 00000000000..eabc6fdbda1
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshotDiff.cpp
@@ -0,0 +1,29 @@
+#include <efsw/DirectorySnapshotDiff.hpp>
+
+namespace efsw {
+
+void DirectorySnapshotDiff::clear()
+{
+ FilesCreated.clear();
+ FilesModified.clear();
+ FilesMoved.clear();
+ FilesDeleted.clear();
+ DirsCreated.clear();
+ DirsModified.clear();
+ DirsMoved.clear();
+ DirsDeleted.clear();
+}
+
+bool DirectorySnapshotDiff::changed()
+{
+ return !FilesCreated.empty() ||
+ !FilesModified.empty() ||
+ !FilesMoved.empty() ||
+ !FilesDeleted.empty() ||
+ !DirsCreated.empty() ||
+ !DirsModified.empty() ||
+ !DirsMoved.empty() ||
+ !DirsDeleted.empty();
+}
+
+}
diff --git a/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp b/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp
new file mode 100644
index 00000000000..042de9ce02c
--- /dev/null
+++ b/dep/efsw/src/efsw/DirectorySnapshotDiff.hpp
@@ -0,0 +1,35 @@
+#ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP
+#define EFSW_DIRECTORYSNAPSHOTDIFF_HPP
+
+#include <efsw/FileInfo.hpp>
+
+namespace efsw {
+
+class DirectorySnapshotDiff
+{
+ public:
+ FileInfoList FilesDeleted;
+ FileInfoList FilesCreated;
+ FileInfoList FilesModified;
+ MovedList FilesMoved;
+ FileInfoList DirsDeleted;
+ FileInfoList DirsCreated;
+ FileInfoList DirsModified;
+ MovedList DirsMoved;
+ bool DirChanged;
+
+ void clear();
+
+ bool changed();
+};
+
+#define DiffIterator( FileInfoListName ) it = Diff.FileInfoListName.begin(); \
+ for ( ; it != Diff.FileInfoListName.end(); it++ )
+
+#define DiffMovedIterator( MovedListName ) mit = Diff.MovedListName.begin(); \
+ for ( ; mit != Diff.MovedListName.end(); mit++ )
+
+}
+
+#endif
+
diff --git a/dep/efsw/src/efsw/FileInfo.cpp b/dep/efsw/src/efsw/FileInfo.cpp
new file mode 100644
index 00000000000..7003afc2a15
--- /dev/null
+++ b/dep/efsw/src/efsw/FileInfo.cpp
@@ -0,0 +1,274 @@
+#include <efsw/FileInfo.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/String.hpp>
+
+#ifndef _DARWIN_FEATURE_64_BIT_INODE
+#define _DARWIN_FEATURE_64_BIT_INODE
+#endif
+
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <stdlib.h>
+
+#ifdef EFSW_COMPILER_MSVC
+ #ifndef S_ISDIR
+ #define S_ISDIR(f) ((f)&_S_IFDIR)
+ #endif
+
+ #ifndef S_ISREG
+ #define S_ISREG(f) ((f)&_S_IFREG)
+ #endif
+
+ #ifndef S_ISRDBL
+ #define S_ISRDBL(f) ((f)&_S_IREAD)
+ #endif
+#else
+ #include <unistd.h>
+
+ #ifndef S_ISRDBL
+ #define S_ISRDBL(f) ((f)&S_IRUSR)
+ #endif
+#endif
+
+namespace efsw {
+
+bool FileInfo::exists( const std::string& filePath )
+{
+ FileInfo fi( filePath );
+ return fi.exists();
+}
+
+bool FileInfo::isLink( const std::string& filePath )
+{
+ FileInfo fi( filePath, true );
+ return fi.isLink();
+}
+
+bool FileInfo::inodeSupported()
+{
+ #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ return true;
+ #else
+ return false;
+ #endif
+}
+
+FileInfo::FileInfo() :
+ ModificationTime(0),
+ OwnerId(0),
+ GroupId(0),
+ Permissions(0),
+ Inode(0)
+{}
+
+FileInfo::FileInfo( const std::string& filepath ) :
+ Filepath( filepath ),
+ ModificationTime(0),
+ OwnerId(0),
+ GroupId(0),
+ Permissions(0),
+ Inode(0)
+{
+ getInfo();
+}
+
+FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) :
+ Filepath( filepath ),
+ ModificationTime(0),
+ OwnerId(0),
+ GroupId(0),
+ Permissions(0),
+ Inode(0)
+{
+ if ( linkInfo )
+ {
+ getRealInfo();
+ }
+ else
+ {
+ getInfo();
+ }
+}
+
+void FileInfo::getInfo()
+{
+ #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+ if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() )
+ {
+ Filepath += FileSystem::getOSSlash();
+ }
+ #endif
+
+ /// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a path slash
+ bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirRemoveSlashAtEnd( Filepath );
+ }
+
+ #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ struct stat st;
+ int res = stat( Filepath.c_str(), &st );
+ #else
+ struct _stat st;
+ int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
+ #endif
+
+ if ( 0 == res )
+ {
+ ModificationTime = st.st_mtime;
+ Size = st.st_size;
+ OwnerId = st.st_uid;
+ GroupId = st.st_gid;
+ Permissions = st.st_mode;
+ Inode = st.st_ino;
+ }
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirAddSlashAtEnd( Filepath );
+ }
+}
+
+void FileInfo::getRealInfo()
+{
+ bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirRemoveSlashAtEnd( Filepath );
+ }
+
+ #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ struct stat st;
+ int res = lstat( Filepath.c_str(), &st );
+ #else
+ struct _stat st;
+ int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
+ #endif
+
+ if ( 0 == res )
+ {
+ ModificationTime = st.st_mtime;
+ Size = st.st_size;
+ OwnerId = st.st_uid;
+ GroupId = st.st_gid;
+ Permissions = st.st_mode;
+ Inode = st.st_ino;
+ }
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirAddSlashAtEnd( Filepath );
+ }
+}
+
+bool FileInfo::operator==( const FileInfo& Other ) const
+{
+ return ( ModificationTime == Other.ModificationTime &&
+ Size == Other.Size &&
+ OwnerId == Other.OwnerId &&
+ GroupId == Other.GroupId &&
+ Permissions == Other.Permissions &&
+ Inode == Other.Inode
+ );
+}
+
+bool FileInfo::isDirectory()
+{
+ return 0 != S_ISDIR(Permissions);
+}
+
+bool FileInfo::isRegularFile()
+{
+ return 0 != S_ISREG(Permissions);
+}
+
+bool FileInfo::isReadable()
+{
+ return 0 != S_ISRDBL(Permissions);
+}
+
+bool FileInfo::isLink()
+{
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ return S_ISLNK(Permissions);
+#else
+ return false;
+#endif
+}
+
+std::string FileInfo::linksTo()
+{
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ if ( isLink() )
+ {
+ char * ch = realpath( Filepath.c_str(), NULL);
+
+ if ( NULL != ch )
+ {
+ std::string tstr( ch );
+
+ free( ch );
+
+ return tstr;
+ }
+ }
+#endif
+ return std::string("");
+}
+
+bool FileInfo::exists()
+{
+ bool slashAtEnd = FileSystem::slashAtEnd( Filepath );
+
+ if ( slashAtEnd )
+ {
+ FileSystem::dirRemoveSlashAtEnd(Filepath);
+ }
+
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ struct stat st;
+ int res = stat( Filepath.c_str(), &st );
+#else
+ struct _stat st;
+ int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st );
+#endif
+
+ if (slashAtEnd)
+ {
+ FileSystem::dirAddSlashAtEnd(Filepath);
+ }
+
+ return 0 == res;
+}
+
+FileInfo& FileInfo::operator=( const FileInfo& Other )
+{
+ this->Filepath = Other.Filepath;
+ this->Size = Other.Size;
+ this->ModificationTime = Other.ModificationTime;
+ this->GroupId = Other.GroupId;
+ this->OwnerId = Other.OwnerId;
+ this->Permissions = Other.Permissions;
+ this->Inode = Other.Inode;
+ return *this;
+}
+
+bool FileInfo::sameInode( const FileInfo& Other ) const
+{
+ return inodeSupported() && Inode == Other.Inode;
+}
+
+bool FileInfo::operator!=( const FileInfo& Other ) const
+{
+ return !(*this == Other);
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileInfo.hpp b/dep/efsw/src/efsw/FileInfo.hpp
new file mode 100644
index 00000000000..45cca6a7953
--- /dev/null
+++ b/dep/efsw/src/efsw/FileInfo.hpp
@@ -0,0 +1,66 @@
+#ifndef EFSW_FILEINFO_HPP
+#define EFSW_FILEINFO_HPP
+
+#include <efsw/base.hpp>
+#include <string>
+#include <map>
+#include <list>
+
+namespace efsw {
+
+class FileInfo
+{
+ public:
+ static bool exists( const std::string& filePath );
+
+ static bool isLink( const std::string& filePath );
+
+ static bool inodeSupported();
+
+ FileInfo();
+
+ FileInfo( const std::string& filepath );
+
+ FileInfo( const std::string& filepath, bool linkInfo );
+
+ bool operator==( const FileInfo& Other ) const;
+
+ bool operator!=( const FileInfo& Other ) const;
+
+ FileInfo& operator=( const FileInfo& Other );
+
+ bool isDirectory();
+
+ bool isRegularFile();
+
+ bool isReadable();
+
+ bool sameInode( const FileInfo& Other ) const;
+
+ bool isLink();
+
+ std::string linksTo();
+
+ bool exists();
+
+ void getInfo();
+
+ void getRealInfo();
+
+ std::string Filepath;
+ Uint64 ModificationTime;
+ Uint64 Size;
+ Uint32 OwnerId;
+ Uint32 GroupId;
+ Uint32 Permissions;
+ Uint64 Inode;
+};
+
+typedef std::map<std::string, FileInfo> FileInfoMap;
+typedef std::list<FileInfo> FileInfoList;
+typedef std::list< std::pair< std::string, FileInfo> > MovedList;
+
+}
+
+#endif
+
diff --git a/dep/efsw/src/efsw/FileSystem.cpp b/dep/efsw/src/efsw/FileSystem.cpp
new file mode 100644
index 00000000000..e3afa0b4046
--- /dev/null
+++ b/dep/efsw/src/efsw/FileSystem.cpp
@@ -0,0 +1,124 @@
+#include <efsw/FileSystem.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+#if EFSW_OS == EFSW_OS_MACOSX
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace efsw {
+
+bool FileSystem::isDirectory( const std::string& path )
+{
+ return Platform::FileSystem::isDirectory( path );
+}
+
+FileInfoMap FileSystem::filesInfoFromPath( std::string path ) {
+ dirAddSlashAtEnd( path );
+
+ return Platform::FileSystem::filesInfoFromPath( path );
+}
+
+char FileSystem::getOSSlash()
+{
+ return Platform::FileSystem::getOSSlash();
+}
+
+bool FileSystem::slashAtEnd( std::string &dir )
+{
+ return ( dir.size() && dir[ dir.size() - 1 ] == getOSSlash() );
+}
+
+void FileSystem::dirAddSlashAtEnd( std::string& dir )
+{
+ if ( dir.size() > 1 && dir[ dir.size() - 1 ] != getOSSlash() )
+ {
+ dir.push_back( getOSSlash() );
+ }
+}
+
+void FileSystem::dirRemoveSlashAtEnd( std::string& dir )
+{
+ if ( dir.size() > 1 && dir[ dir.size() - 1 ] == getOSSlash() )
+ {
+ dir.erase( dir.size() - 1 );
+ }
+}
+
+std::string FileSystem::fileNameFromPath( std::string filepath )
+{
+ dirRemoveSlashAtEnd( filepath );
+
+ size_t pos = filepath.find_last_of( getOSSlash() );
+
+ if ( pos != std::string::npos )
+ {
+ return filepath.substr( pos + 1 );
+ }
+
+ return filepath;
+}
+
+std::string FileSystem::pathRemoveFileName( std::string filepath )
+{
+ dirRemoveSlashAtEnd( filepath );
+
+ size_t pos = filepath.find_last_of( getOSSlash() );
+
+ if ( pos != std::string::npos )
+ {
+ return filepath.substr( 0, pos + 1 );
+ }
+
+ return filepath;
+}
+
+std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath )
+{
+ FileSystem::dirRemoveSlashAtEnd( dir );
+ FileInfo fi( dir, true );
+
+ /// Check with lstat and see if it's a link
+ if ( fi.isLink() )
+ {
+ /// get the real path of the link
+ std::string link( fi.linksTo() );
+
+ /// get the current path of the directory without the link dir path
+ curPath = FileSystem::pathRemoveFileName( dir );
+
+ /// ensure that ends with the os directory slash
+ FileSystem::dirAddSlashAtEnd( link );
+
+ return link;
+ }
+
+ /// if it's not a link return nothing
+ return "";
+}
+
+std::string FileSystem::precomposeFileName( const std::string& name )
+{
+#if EFSW_OS == EFSW_OS_MACOSX
+ CFStringRef cfStringRef = CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8);
+ CFMutableStringRef cfMutable = CFStringCreateMutableCopy(NULL, 0, cfStringRef);
+
+ CFStringNormalize(cfMutable,kCFStringNormalizationFormC);
+
+ char c_str[255 + 1];
+ CFStringGetCString(cfMutable, c_str, sizeof(c_str)-1, kCFStringEncodingUTF8);
+
+ CFRelease(cfStringRef);
+ CFRelease(cfMutable);
+
+ return std::string(c_str);
+#else
+ return name;
+#endif
+}
+
+bool FileSystem::isRemoteFS( const std::string& directory )
+{
+ return Platform::FileSystem::isRemoteFS( directory );
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileSystem.hpp b/dep/efsw/src/efsw/FileSystem.hpp
new file mode 100644
index 00000000000..4e2e1aeb7cd
--- /dev/null
+++ b/dep/efsw/src/efsw/FileSystem.hpp
@@ -0,0 +1,40 @@
+#ifndef EFSW_FILESYSTEM_HPP
+#define EFSW_FILESYSTEM_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/FileInfo.hpp>
+#include <map>
+
+namespace efsw {
+
+class FileSystem
+{
+ public:
+ static bool isDirectory( const std::string& path );
+
+ static FileInfoMap filesInfoFromPath( std::string path );
+
+ static char getOSSlash();
+
+ static bool slashAtEnd( std::string& dir );
+
+ static void dirAddSlashAtEnd( std::string& dir );
+
+ static void dirRemoveSlashAtEnd( std::string& dir );
+
+ static std::string fileNameFromPath( std::string filepath );
+
+ static std::string pathRemoveFileName( std::string filepath );
+
+ static void realPath( std::string curdir, std::string& path );
+
+ static std::string getLinkRealPath( std::string dir, std::string& curPath );
+
+ static std::string precomposeFileName(const std::string& name);
+
+ static bool isRemoteFS( const std::string& directory );
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcher.cpp b/dep/efsw/src/efsw/FileWatcher.cpp
new file mode 100644
index 00000000000..e33d5ec46fb
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcher.cpp
@@ -0,0 +1,145 @@
+#include <efsw/efsw.hpp>
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/FileWatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+# include <efsw/FileWatcherWin32.hpp>
+# define FILEWATCHER_IMPL FileWatcherWin32
+# define BACKEND_NAME "Win32"
+#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
+# include <efsw/FileWatcherInotify.hpp>
+# define FILEWATCHER_IMPL FileWatcherInotify
+# define BACKEND_NAME "Inotify"
+#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
+# include <efsw/FileWatcherKqueue.hpp>
+# define FILEWATCHER_IMPL FileWatcherKqueue
+# define BACKEND_NAME "Kqueue"
+#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+# include <efsw/FileWatcherFSEvents.hpp>
+# define FILEWATCHER_IMPL FileWatcherFSEvents
+# define BACKEND_NAME "FSEvents"
+#else
+# define FILEWATCHER_IMPL FileWatcherGeneric
+# define BACKEND_NAME "Generic"
+#endif
+
+#include <efsw/Debug.hpp>
+
+namespace efsw {
+
+FileWatcher::FileWatcher() :
+ mFollowSymlinks(false),
+ mOutOfScopeLinks(false)
+{
+ efDEBUG( "Using backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FILEWATCHER_IMPL( this );
+
+ if ( !mImpl->initOK() )
+ {
+ efSAFE_DELETE( mImpl );
+
+ efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FileWatcherGeneric( this );
+ }
+}
+
+FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
+ mFollowSymlinks(false),
+ mOutOfScopeLinks(false)
+{
+ if ( useGenericFileWatcher )
+ {
+ efDEBUG( "Using backend: Generic\n" );
+
+ mImpl = new FileWatcherGeneric( this );
+ }
+ else
+ {
+ efDEBUG( "Using backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FILEWATCHER_IMPL( this );
+
+ if ( !mImpl->initOK() )
+ {
+ efSAFE_DELETE( mImpl );
+
+ efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
+
+ mImpl = new FileWatcherGeneric( this );
+ }
+ }
+}
+
+FileWatcher::~FileWatcher()
+{
+ efSAFE_DELETE( mImpl );
+}
+
+WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher)
+{
+ if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) )
+ {
+ return mImpl->addWatch(directory, watcher, false);
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, directory );
+ }
+}
+
+WatchID FileWatcher::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) )
+ {
+ return mImpl->addWatch(directory, watcher, recursive);
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, directory );
+ }
+}
+
+void FileWatcher::removeWatch(const std::string& directory)
+{
+ mImpl->removeWatch(directory);
+}
+
+void FileWatcher::removeWatch(WatchID watchid)
+{
+ mImpl->removeWatch(watchid);
+}
+
+void FileWatcher::watch()
+{
+ mImpl->watch();
+}
+
+std::list<std::string> FileWatcher::directories()
+{
+ return mImpl->directories();
+}
+
+void FileWatcher::followSymlinks( bool follow )
+{
+ mFollowSymlinks = follow;
+}
+
+const bool& FileWatcher::followSymlinks() const
+{
+ return mFollowSymlinks;
+}
+
+void FileWatcher::allowOutOfScopeLinks( bool allow )
+{
+ mOutOfScopeLinks = allow;
+}
+
+const bool& FileWatcher::allowOutOfScopeLinks() const
+{
+ return mOutOfScopeLinks;
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileWatcherCWrapper.cpp b/dep/efsw/src/efsw/FileWatcherCWrapper.cpp
new file mode 100644
index 00000000000..2739e756bb2
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherCWrapper.cpp
@@ -0,0 +1,132 @@
+#include <efsw/efsw.h>
+#include <efsw/efsw.hpp>
+#include <vector>
+
+#define TOBOOL(i) ((i) == 0 ? false : true)
+
+/*************************************************************************************************/
+class Watcher_CAPI : public efsw::FileWatchListener
+{
+public:
+ efsw_watcher mWatcher;
+ efsw_pfn_fileaction_callback mFn;
+ void* mParam;
+public:
+ Watcher_CAPI(efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param)
+ {
+ mWatcher = watcher;
+ mFn = fn;
+ mParam = param;
+ }
+
+ void handleFileAction(efsw::WatchID watchid, const std::string& dir, const std::string& filename,
+ efsw::Action action, std::string oldFilename = "")
+ {
+ mFn(mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action,
+ oldFilename.c_str(), mParam );
+ }
+};
+
+/*************************************************************************************************
+ * globals
+ */
+static std::vector<Watcher_CAPI*> g_callbacks;
+
+Watcher_CAPI* find_callback(efsw_watcher watcher, efsw_pfn_fileaction_callback fn)
+{
+ for (std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); i++ )
+ {
+ Watcher_CAPI* callback = *i;
+
+ if (callback->mFn == fn && callback->mWatcher == watcher)
+ return *i;
+ }
+
+ return NULL;
+}
+
+Watcher_CAPI* remove_callback(efsw_watcher watcher)
+{
+ std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin();
+
+ while (i != g_callbacks.end()) {
+ Watcher_CAPI* callback = *i;
+
+ if (callback->mWatcher == watcher)
+ i = g_callbacks.erase(i);
+ else
+ i++;
+ }
+
+ return NULL;
+}
+
+
+/*************************************************************************************************/
+efsw_watcher efsw_create(int generic_mode)
+{
+ return (efsw_watcher)new efsw::FileWatcher(TOBOOL(generic_mode));
+}
+
+void efsw_release(efsw_watcher watcher)
+{
+ remove_callback(watcher);
+ delete (efsw::FileWatcher*)watcher;
+}
+
+const char* efsw_getlasterror()
+{
+ static std::string log_str;
+ log_str = efsw::Errors::Log::getLastErrorLog();
+ return log_str.c_str();
+}
+
+efsw_watchid efsw_addwatch(efsw_watcher watcher, const char* directory,
+ efsw_pfn_fileaction_callback callback_fn, int recursive, void * param)
+{
+ Watcher_CAPI* callback = find_callback(watcher, callback_fn);
+
+ if (callback == NULL) {
+ callback = new Watcher_CAPI(watcher, callback_fn, param);
+ g_callbacks.push_back(callback);
+ }
+
+ return ((efsw::FileWatcher*)watcher)->addWatch(std::string(directory), callback,
+ TOBOOL(recursive));
+}
+
+void efsw_removewatch(efsw_watcher watcher, const char* directory)
+{
+ ((efsw::FileWatcher*)watcher)->removeWatch(std::string(directory));
+}
+
+void efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid)
+{
+ ((efsw::FileWatcher*)watcher)->removeWatch(watchid);
+}
+
+void efsw_watch(efsw_watcher watcher)
+{
+ ((efsw::FileWatcher*)watcher)->watch();
+}
+
+void efsw_follow_symlinks(efsw_watcher watcher, int enable)
+{
+ ((efsw::FileWatcher*)watcher)->followSymlinks(TOBOOL(enable));
+}
+
+int efsw_follow_symlinks_isenabled(efsw_watcher watcher)
+{
+ return (int)((efsw::FileWatcher*)watcher)->followSymlinks();
+}
+
+void efsw_allow_outofscopelinks(efsw_watcher watcher, int allow)
+{
+ ((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks(TOBOOL(allow));
+}
+
+int efsw_outofscopelinks_isallowed(efsw_watcher watcher)
+{
+ return (int)((efsw::FileWatcher*)watcher)->allowOutOfScopeLinks();
+}
+
diff --git a/dep/efsw/src/efsw/FileWatcherFSEvents.cpp b/dep/efsw/src/efsw/FileWatcherFSEvents.cpp
new file mode 100644
index 00000000000..40156674132
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherFSEvents.cpp
@@ -0,0 +1,278 @@
+#include <efsw/FileWatcherFSEvents.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/Debug.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <sys/utsname.h>
+
+namespace efsw
+{
+
+int getOSXReleaseNumber()
+{
+ static int osxR = -1;
+
+ if ( -1 == osxR )
+ {
+ struct utsname os;
+
+ if ( -1 != uname( &os ) ) {
+ std::string release( os.release );
+
+ size_t pos = release.find_first_of( '.' );
+
+ if ( pos != std::string::npos )
+ {
+ release = release.substr( 0, pos );
+ }
+
+ int rel = 0;
+
+ if ( String::fromString<int>( rel, release ) )
+ {
+ osxR = rel;
+ }
+ }
+ }
+
+ return osxR;
+}
+
+bool FileWatcherFSEvents::isGranular()
+{
+ return getOSXReleaseNumber() >= 11;
+}
+
+void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef,
+ void *userData,
+ size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[] )
+{
+ WatcherFSEvents * watcher = static_cast<WatcherFSEvents*>( userData );
+
+ std::vector<FSEvent> events;
+ events.reserve( numEvents );
+
+ for ( size_t i = 0; i < numEvents; i++ )
+ {
+ events.push_back( FSEvent( std::string( ((char**)eventPaths)[i] ), (long)eventFlags[i], (Uint64)eventIds[i] ) );
+ }
+
+ watcher->handleActions( events );
+
+ watcher->process();
+
+ efDEBUG( "\n" );
+}
+
+FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mRunLoopRef( NULL ),
+ mLastWatchID(0),
+ mThread( NULL )
+{
+ mInitOK = true;
+
+ watch();
+}
+
+FileWatcherFSEvents::~FileWatcherFSEvents()
+{
+ WatchMap::iterator iter = mWatches.begin();
+
+ for( ; iter != mWatches.end(); ++iter )
+ {
+ WatcherFSEvents * watch = iter->second;
+
+ efSAFE_DELETE( watch );
+ }
+
+ mWatches.clear();
+
+ mInitOK = false;
+
+ if ( NULL != mRunLoopRef )
+ {
+ CFRunLoopStop( mRunLoopRef );
+ }
+
+ efSAFE_DELETE( mThread );
+}
+
+WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive )
+{
+ /// Wait to the RunLoopRef to be ready
+ while ( NULL == mRunLoopRef )
+ {
+ System::sleep( 1 );
+ }
+
+ std::string dir( directory );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+
+ /// Check if the directory is a symbolic link
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ mLastWatchID++;
+
+ WatcherFSEvents * pWatch = new WatcherFSEvents();
+ pWatch->Listener = watcher;
+ pWatch->ID = mLastWatchID;
+ pWatch->Directory = dir;
+ pWatch->Recursive = recursive;
+ pWatch->FWatcher = this;
+
+ pWatch->init();
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, pWatch));
+ mWatchesLock.unlock();
+
+ return pWatch->ID;
+}
+
+void FileWatcherFSEvents::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if( directory == iter->second->Directory )
+ {
+ removeWatch( iter->second->ID );
+ return;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherFSEvents::removeWatch(WatchID watchid)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.find( watchid );
+
+ if( iter == mWatches.end() )
+ return;
+
+ WatcherFSEvents * watch = iter->second;
+
+ mWatches.erase( iter );
+
+ efDEBUG( "Removed watch %s\n", watch->Directory.c_str() );
+
+ efSAFE_DELETE( watch );
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherFSEvents::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherFSEvents::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherFSEvents::run()
+{
+ mRunLoopRef = CFRunLoopGetCurrent();
+
+ while ( mInitOK )
+ {
+ if ( !mNeedInit.empty() )
+ {
+ for ( std::list<WatcherFSEvents*>::iterator it = mNeedInit.begin(); it != mNeedInit.end(); it++ )
+ {
+ (*it)->initAsync();
+ }
+
+ mNeedInit.clear();
+ }
+
+ CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut );
+ }
+}
+
+void FileWatcherFSEvents::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+ /// Not used
+}
+
+std::list<std::string> FileWatcherFSEvents::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ dirs.push_back( std::string( it->second->Directory ) );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherFSEvents::pathInWatches( const std::string& path )
+{
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherFSEvents.hpp b/dep/efsw/src/efsw/FileWatcherFSEvents.hpp
new file mode 100644
index 00000000000..6aafbc0b5ea
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherFSEvents.hpp
@@ -0,0 +1,107 @@
+#ifndef EFSW_FILEWATCHERFSEVENTS_HPP
+#define EFSW_FILEWATCHERFSEVENTS_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <efsw/WatcherFSEvents.hpp>
+#include <map>
+#include <list>
+#include <vector>
+
+namespace efsw
+{
+
+/* OSX < 10.7 has no file events */
+/* So i declare the events constants */
+enum FSEventEvents
+{
+ efswFSEventStreamCreateFlagFileEvents = 0x00000010,
+ efswFSEventStreamEventFlagItemCreated = 0x00000100,
+ efswFSEventStreamEventFlagItemRemoved = 0x00000200,
+ efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400,
+ efswFSEventStreamEventFlagItemRenamed = 0x00000800,
+ efswFSEventStreamEventFlagItemModified = 0x00001000,
+ efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000,
+ efswFSEventStreamEventFlagItemChangeOwner = 0x00004000,
+ efswFSEventStreamEventFlagItemXattrMod = 0x00008000,
+ efswFSEventStreamEventFlagItemIsFile = 0x00010000,
+ efswFSEventStreamEventFlagItemIsDir = 0x00020000,
+ efswFSEventStreamEventFlagItemIsSymlink = 0x00040000,
+ efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod |
+ efswFSEventStreamEventFlagItemModified |
+ efswFSEventStreamEventFlagItemInodeMetaMod |
+ efswFSEventStreamEventFlagItemChangeOwner |
+ efswFSEventStreamEventFlagItemXattrMod
+};
+
+/// Implementation for Win32 based on ReadDirectoryChangesW.
+/// @class FileWatcherFSEvents
+class FileWatcherFSEvents : public FileWatcherImpl
+{
+ friend class WatcherFSEvents;
+ public:
+ /// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 )
+ static bool isGranular();
+
+ /// type for a map from WatchID to WatcherWin32 pointer
+ typedef std::map<WatchID, WatcherFSEvents*> WatchMap;
+
+ FileWatcherFSEvents( FileWatcher * parent );
+
+ virtual ~FileWatcherFSEvents();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ static void FSEventCallback( ConstFSEventStreamRef streamRef,
+ void *userData,
+ size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]
+ );
+
+ CFRunLoopRef mRunLoopRef;
+
+ /// Vector of WatcherWin32 pointers
+ WatchMap mWatches;
+
+ /// The last watchid
+ WatchID mLastWatchID;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ bool pathInWatches( const std::string& path );
+
+ std::list<WatcherFSEvents*> mNeedInit;
+ private:
+ void run();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherGeneric.cpp b/dep/efsw/src/efsw/FileWatcherGeneric.cpp
new file mode 100644
index 00000000000..1534b6a9279
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherGeneric.cpp
@@ -0,0 +1,197 @@
+#include <efsw/FileWatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+
+namespace efsw
+{
+
+FileWatcherGeneric::FileWatcherGeneric( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mThread( NULL ),
+ mLastWatchID( 0 )
+{
+ mInitOK = true;
+ mIsGeneric = true;
+}
+
+FileWatcherGeneric::~FileWatcherGeneric()
+{
+ mInitOK = false;
+
+ mThread->wait();
+
+ efSAFE_DELETE( mThread );
+
+ /// Delete the watches
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ efSAFE_DELETE( (*it) );
+ }
+}
+
+WatchID FileWatcherGeneric::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+ else if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, dir );
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, dir );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ mLastWatchID++;
+
+ WatcherGeneric * pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive );
+
+ mWatchesLock.lock();
+ mWatches.push_back(pWatch);
+ mWatchesLock.unlock();
+
+ return pWatch->ID;
+}
+
+void FileWatcherGeneric::removeWatch( const std::string& directory )
+{
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Directory == directory )
+ {
+ WatcherGeneric * watch = (*it);
+
+ mWatchesLock.lock();
+
+ mWatches.erase( it );
+
+ efSAFE_DELETE( watch ) ;
+
+ mWatchesLock.unlock();
+
+ return;
+ }
+ }
+}
+
+void FileWatcherGeneric::removeWatch(WatchID watchid)
+{
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( (*it)->ID == watchid )
+ {
+ WatcherGeneric * watch = (*it);
+
+ mWatchesLock.lock();
+
+ mWatches.erase( it );
+
+ efSAFE_DELETE( watch ) ;
+
+ mWatchesLock.unlock();
+
+ return;
+ }
+ }
+}
+
+void FileWatcherGeneric::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherGeneric::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherGeneric::run()
+{
+ do
+ {
+ mWatchesLock.lock();
+
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ (*it)->watch();
+ }
+
+ mWatchesLock.unlock();
+
+ if ( mInitOK ) System::sleep( 1000 );
+ } while ( mInitOK );
+}
+
+void FileWatcherGeneric::handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+ /// Not used
+}
+
+std::list<std::string> FileWatcherGeneric::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ dirs.push_back( (*it)->Directory );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherGeneric::pathInWatches( const std::string& path )
+{
+ WatchList::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Directory == path || (*it)->pathInWatches( path ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileWatcherGeneric.hpp b/dep/efsw/src/efsw/FileWatcherGeneric.hpp
new file mode 100644
index 00000000000..fc9826580ab
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherGeneric.hpp
@@ -0,0 +1,59 @@
+#ifndef EFSW_FILEWATCHERGENERIC_HPP
+#define EFSW_FILEWATCHERGENERIC_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/DirWatcherGeneric.hpp>
+#include <list>
+
+namespace efsw
+{
+
+/// Implementation for Generic File Watcher.
+/// @class FileWatcherGeneric
+class FileWatcherGeneric : public FileWatcherImpl
+{
+ public:
+ typedef std::list<WatcherGeneric*> WatchList;
+
+ FileWatcherGeneric( FileWatcher * parent );
+
+ virtual ~FileWatcherGeneric();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ Thread * mThread;
+
+ /// The last watchid
+ WatchID mLastWatchID;
+
+ /// Map of WatchID to WatchStruct pointers
+ WatchList mWatches;
+
+ Mutex mWatchesLock;
+
+ bool pathInWatches( const std::string& path );
+ private:
+ void run();
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherImpl.cpp b/dep/efsw/src/efsw/FileWatcherImpl.cpp
new file mode 100644
index 00000000000..e6e0fc72a13
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherImpl.cpp
@@ -0,0 +1,29 @@
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/String.hpp>
+#include <efsw/System.hpp>
+
+namespace efsw {
+
+FileWatcherImpl::FileWatcherImpl( FileWatcher * parent ) :
+ mFileWatcher( parent ),
+ mInitOK( false ),
+ mIsGeneric( false )
+{
+ System::maxFD();
+}
+
+FileWatcherImpl::~FileWatcherImpl()
+{
+}
+
+bool FileWatcherImpl::initOK()
+{
+ return mInitOK;
+}
+
+bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link )
+{
+ return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || -1 != String::strStartsWith( curPath, link );
+}
+
+}
diff --git a/dep/efsw/src/efsw/FileWatcherImpl.hpp b/dep/efsw/src/efsw/FileWatcherImpl.hpp
new file mode 100644
index 00000000000..8f472bf56c5
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherImpl.hpp
@@ -0,0 +1,54 @@
+#ifndef EFSW_FILEWATCHERIMPL_HPP
+#define EFSW_FILEWATCHERIMPL_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/efsw.hpp>
+#include <efsw/Watcher.hpp>
+#include <efsw/Thread.hpp>
+#include <efsw/Mutex.hpp>
+
+namespace efsw {
+
+class FileWatcherImpl
+{
+ public:
+ FileWatcherImpl( FileWatcher * parent );
+
+ virtual ~FileWatcherImpl();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ virtual WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) = 0;
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ virtual void removeWatch(const std::string& directory) = 0;
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ virtual void removeWatch(WatchID watchid) = 0;
+
+ /// Updates the watcher. Must be called often.
+ virtual void watch() = 0;
+
+ /// Handles the action
+ virtual void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "") = 0;
+
+ /// @return Returns a list of the directories that are being watched
+ virtual std::list<std::string> directories() = 0;
+
+ /// @return true if the backend init successfully
+ virtual bool initOK();
+
+ /// @return If the link is allowed according to the current path and the state of out scope links
+ virtual bool linkAllowed( const std::string& curPath, const std::string& link );
+
+ /// Search if a directory already exists in the watches
+ virtual bool pathInWatches( const std::string& path ) = 0;
+
+ FileWatcher * mFileWatcher;
+ bool mInitOK;
+ bool mIsGeneric;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherInotify.cpp b/dep/efsw/src/efsw/FileWatcherInotify.cpp
new file mode 100644
index 00000000000..19c20761663
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherInotify.cpp
@@ -0,0 +1,531 @@
+#include <efsw/FileWatcherInotify.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef EFSW_INOTIFY_NOSYS
+#include <efsw/inotify-nosys.h>
+#else
+#include <sys/inotify.h>
+#endif
+
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/Debug.hpp>
+
+#define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)
+
+namespace efsw
+{
+
+FileWatcherInotify::FileWatcherInotify( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mFD(-1),
+ mThread(NULL)
+{
+ mFD = inotify_init();
+
+ if (mFD < 0)
+ {
+ efDEBUG( "Error: %s\n", strerror(errno) );
+ }
+ else
+ {
+ mInitOK = true;
+ }
+}
+
+FileWatcherInotify::~FileWatcherInotify()
+{
+ mInitOK = false;
+
+ efSAFE_DELETE( mThread );
+
+ WatchMap::iterator iter = mWatches.begin();
+ WatchMap::iterator end = mWatches.end();
+
+ for(; iter != end; ++iter)
+ {
+ efSAFE_DELETE( iter->second );
+ }
+
+ mWatches.clear();
+
+ if ( mFD != -1 )
+ {
+ close(mFD);
+ mFD = -1;
+ }
+}
+
+WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive )
+{
+ return addWatch( directory, watcher, recursive, NULL );
+}
+
+WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent )
+{
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+ else if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( NULL != parent && FileSystem::isRemoteFS( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, dir );
+ }
+
+ /// Check if the directory is a symbolic link
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( NULL != parent && !mFileWatcher->followSymlinks() )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+
+ /// If it's a symlink check if the realpath exists as a watcher, or
+ /// if the path is outside the current dir
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ int wd = inotify_add_watch (mFD, dir.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY);
+
+ if ( wd < 0 )
+ {
+ if( errno == ENOENT )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::Unspecified, std::string(strerror(errno)) );
+ }
+ }
+
+ efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd );
+
+ WatcherInotify * pWatch = new WatcherInotify();
+ pWatch->Listener = watcher;
+ pWatch->ID = wd;
+ pWatch->Directory = dir;
+ pWatch->Recursive = recursive;
+ pWatch->Parent = parent;
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(wd, pWatch));
+ mWatchesLock.unlock();
+
+ if ( NULL == pWatch->Parent )
+ {
+ mRealWatches[ pWatch->ID ] = pWatch;
+ }
+
+ if ( pWatch->Recursive )
+ {
+ std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory );
+ std::map<std::string, FileInfo>::iterator it = files.begin();
+
+ for ( ; it != files.end(); it++ )
+ {
+ FileInfo fi = it->second;
+
+ if ( fi.isDirectory() && fi.isReadable() )
+ {
+ addWatch( fi.Filepath, watcher, recursive, pWatch );
+ }
+ }
+ }
+
+ return wd;
+}
+
+void FileWatcherInotify::removeWatchLocked(WatchID watchid)
+{
+ WatchMap::iterator iter = mWatches.find( watchid );
+
+ WatcherInotify * watch = iter->second;
+
+ if ( watch->Recursive )
+ {
+ WatchMap::iterator it = mWatches.begin();
+ std::list<WatchID> eraseWatches;
+
+ for(; it != mWatches.end(); ++it)
+ {
+ if ( it->second != watch &&
+ it->second->inParentTree( watch )
+ )
+ {
+ eraseWatches.push_back( it->second->ID );
+ }
+ }
+
+ for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ )
+ {
+ removeWatch( *eit );
+ }
+ }
+
+ mWatches.erase( iter );
+
+ if ( NULL == watch->Parent )
+ {
+ WatchMap::iterator eraseit = mRealWatches.find( watch->ID );
+
+ if ( eraseit != mRealWatches.end() )
+ {
+ mRealWatches.erase( eraseit );
+ }
+ }
+
+ int err = inotify_rm_watch(mFD, watchid);
+
+ if ( err < 0 )
+ {
+ efDEBUG( "Error removing watch %d: %s\n", watchid, strerror(errno) );
+ }
+ else
+ {
+ efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid );
+ }
+
+ efSAFE_DELETE( watch );
+}
+
+void FileWatcherInotify::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if( directory == iter->second->Directory )
+ {
+ WatcherInotify * watch = iter->second;
+
+ if ( watch->Recursive )
+ {
+ WatchMap::iterator it = mWatches.begin();
+ std::list<WatchID> eraseWatches;
+
+ for(; it != mWatches.end(); ++it)
+ {
+ if ( it->second->inParentTree( watch ) )
+ {
+ eraseWatches.push_back( it->second->ID );
+ }
+ }
+
+ for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); eit++ )
+ {
+ removeWatchLocked( *eit );
+ }
+ }
+
+ mWatches.erase( iter );
+
+ if ( NULL == watch->Parent )
+ {
+ WatchMap::iterator eraseit = mRealWatches.find( watch->ID );
+
+ if ( eraseit != mRealWatches.end() )
+ {
+ mRealWatches.erase( eraseit );
+ }
+ }
+
+ int err = inotify_rm_watch(mFD, watch->ID);
+
+ if ( err < 0 )
+ {
+ efDEBUG( "Error removing watch %d: %s\n", watch->ID, strerror(errno) );
+ }
+ else
+ {
+ efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watch->ID );
+ }
+
+ efSAFE_DELETE( watch );
+
+ break;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherInotify::removeWatch( WatchID watchid )
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.find( watchid );
+
+ if( iter == mWatches.end() )
+ {
+ mWatchesLock.unlock();
+
+ return;
+ }
+
+ removeWatchLocked( watchid );
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherInotify::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherInotify::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherInotify::run()
+{
+ static char buff[BUFF_SIZE] = {0};
+ WatchMap::iterator wit;
+ std::list<WatcherInotify*> movedOutsideWatches;
+
+ do
+ {
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET (mFD, &rfds);
+ timeval timeout;
+ timeout.tv_sec=0;
+ timeout.tv_usec=100000;
+
+ if( select (FD_SETSIZE, &rfds, NULL, NULL, &timeout) > 0 )
+ {
+ ssize_t len, i = 0;
+
+ len = read (mFD, buff, BUFF_SIZE);
+
+ if (len != -1)
+ {
+ while (i < len)
+ {
+ struct inotify_event *pevent = (struct inotify_event *)&buff[i];
+
+ mWatchesLock.lock();
+
+ wit = mWatches.find( pevent->wd );
+
+ if ( wit != mWatches.end() )
+ {
+ handleAction(wit->second, pevent->name, pevent->mask);
+
+ /// Keep track of the IN_MOVED_FROM events to known if the IN_MOVED_TO event is also fired
+ if ( !wit->second->OldFileName.empty() )
+ {
+ movedOutsideWatches.push_back( wit->second );
+ }
+ }
+
+ mWatchesLock.unlock();
+
+ i += sizeof(struct inotify_event) + pevent->len;
+ }
+
+ if ( !movedOutsideWatches.empty() )
+ {
+ /// In case that the IN_MOVED_TO is never fired means that the file was moved to other folder
+ for ( std::list<WatcherInotify*>::iterator it = movedOutsideWatches.begin(); it != movedOutsideWatches.end(); it++ )
+ {
+ if ( !(*it)->OldFileName.empty() )
+ {
+ /// So we send a IN_DELETE event for files that where moved outside of our scope
+ handleAction( *it, (*it)->OldFileName, IN_DELETE );
+
+ /// Remove the OldFileName
+ (*it)->OldFileName = "";
+ }
+ }
+
+ movedOutsideWatches.clear();
+ }
+ }
+ }
+ } while( mInitOK );
+}
+
+void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath )
+{
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher
+ if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
+ {
+ bool found = false;
+
+ /// First check if exists
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == fpath )
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ addWatch( fpath, watch->Listener, watch->Recursive, static_cast<WatcherInotify*>( watch ) );
+ }
+ }
+}
+
+void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename )
+{
+ if ( !watch || !watch->Listener )
+ {
+ return;
+ }
+
+ std::string fpath( watch->Directory + filename );
+
+ if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified );
+ }
+ else if( IN_MOVED_TO & action )
+ {
+ /// If OldFileName doesn't exist means that the file has been moved from other folder, so we just send the Add event
+ if ( watch->OldFileName.empty() )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add );
+
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Modified );
+
+ checkForNewWatcher( watch, fpath );
+ }
+ else
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Moved, watch->OldFileName );
+ }
+
+ if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
+ {
+ /// Update the new directory path
+ std::string opath( watch->Directory + watch->OldFileName );
+ FileSystem::dirAddSlashAtEnd( opath );
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == opath && it->second->DirInfo.Inode == FileInfo( opath ).Inode )
+ {
+ it->second->Directory = fpath;
+ it->second->DirInfo = FileInfo( fpath );
+
+ break;
+ }
+ }
+ }
+
+ watch->OldFileName = "";
+ }
+ else if( IN_CREATE & action )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add );
+
+ checkForNewWatcher( watch, fpath );
+ }
+ else if ( IN_MOVED_FROM & action )
+ {
+ watch->OldFileName = filename;
+ }
+ else if( IN_DELETE & action )
+ {
+ watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete );
+
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ /// If the file erased is a directory and recursive is enabled, removes the directory erased
+ if ( watch->Recursive )
+ {
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == fpath )
+ {
+ removeWatch( it->second->ID );
+ break;
+ }
+ }
+ }
+ }
+}
+
+std::list<std::string> FileWatcherInotify::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ WatchMap::iterator it = mRealWatches.begin();
+
+ for ( ; it != mRealWatches.end(); it++ )
+ {
+ dirs.push_back( it->second->Directory );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherInotify::pathInWatches( const std::string& path )
+{
+ /// Search in the real watches, since it must allow adding a watch already watched as a subdir
+ WatchMap::iterator it = mRealWatches.begin();
+
+ for ( ; it != mRealWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherInotify.hpp b/dep/efsw/src/efsw/FileWatcherInotify.hpp
new file mode 100644
index 00000000000..43ee9ca6afc
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherInotify.hpp
@@ -0,0 +1,73 @@
+#ifndef EFSW_FILEWATCHERLINUX_HPP
+#define EFSW_FILEWATCHERLINUX_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
+
+#include <efsw/WatcherInotify.hpp>
+#include <map>
+
+namespace efsw
+{
+
+/// Implementation for Linux based on inotify.
+/// @class FileWatcherInotify
+class FileWatcherInotify : public FileWatcherImpl
+{
+ public:
+ /// type for a map from WatchID to WatchStruct pointer
+ typedef std::map<WatchID, WatcherInotify*> WatchMap;
+
+ FileWatcherInotify( FileWatcher * parent );
+
+ virtual ~FileWatcherInotify();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ /// Map of WatchID to WatchStruct pointers
+ WatchMap mWatches;
+
+ /// User added watches
+ WatchMap mRealWatches;
+
+ /// inotify file descriptor
+ int mFD;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent = NULL );
+
+ bool pathInWatches( const std::string& path );
+ private:
+ void run();
+
+ void removeWatchLocked(WatchID watchid);
+
+ void checkForNewWatcher( Watcher* watch, std::string fpath );
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherKqueue.cpp b/dep/efsw/src/efsw/FileWatcherKqueue.cpp
new file mode 100644
index 00000000000..600fd085b35
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherKqueue.cpp
@@ -0,0 +1,274 @@
+#include <efsw/FileWatcherKqueue.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/Debug.hpp>
+#include <efsw/WatcherGeneric.hpp>
+
+namespace efsw
+{
+
+FileWatcherKqueue::FileWatcherKqueue( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mLastWatchID(0),
+ mThread( NULL ),
+ mFileDescriptorCount( 1 ),
+ mAddingWatcher( false )
+{
+ mTimeOut.tv_sec = 0;
+ mTimeOut.tv_nsec = 0;
+ mInitOK = true;
+}
+
+FileWatcherKqueue::~FileWatcherKqueue()
+{
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ efSAFE_DELETE( iter->second );
+ }
+
+ mWatches.clear();
+
+ mInitOK = false;
+
+ mThread->wait();
+
+ efSAFE_DELETE( mThread );
+}
+
+WatchID FileWatcherKqueue::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ static bool s_ug = false;
+
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+ else if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ if ( pathInWatches( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( !linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ /// Check first if are enough file descriptors available to create another kqueue watcher, otherwise it creates a generic watcher
+ if ( availablesFD() )
+ {
+ mAddingWatcher = true;
+
+ WatcherKqueue * watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this );
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ mWatchesLock.unlock();
+
+ watch->addAll();
+
+ // if failed to open the directory... erase the watcher
+ if ( !watch->initOK() )
+ {
+ int le = watch->lastErrno();
+
+ mWatches.erase( watch->ID );
+
+ efSAFE_DELETE( watch );
+
+ mLastWatchID--;
+
+ // Probably the folder has too many files, create a generic watcher
+ if ( EACCES != le )
+ {
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ mWatchesLock.unlock();
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::Unspecified, link );
+ }
+ }
+
+ mAddingWatcher = false;
+ }
+ else
+ {
+ if ( !s_ug )
+ {
+ efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", mFileDescriptorCount );
+ s_ug = true;
+ }
+
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive );
+
+ mWatchesLock.lock();
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ mWatchesLock.unlock();
+ }
+
+ return mLastWatchID;
+}
+
+void FileWatcherKqueue::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if(directory == iter->second->Directory)
+ {
+ removeWatch(iter->first);
+ return;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherKqueue::removeWatch(WatchID watchid)
+{
+ mWatchesLock.lock();
+
+ WatchMap::iterator iter = mWatches.find(watchid);
+
+ if(iter == mWatches.end())
+ return;
+
+ Watcher* watch = iter->second;
+
+ mWatches.erase(iter);
+
+ efSAFE_DELETE( watch );
+
+ mWatchesLock.unlock();
+}
+
+bool FileWatcherKqueue::isAddingWatcher() const
+{
+ return mAddingWatcher;
+}
+
+void FileWatcherKqueue::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherKqueue::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherKqueue::run()
+{
+ do
+ {
+ mWatchesLock.lock();
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
+ {
+ it->second->watch();
+ }
+
+ mWatchesLock.unlock();
+
+ System::sleep( 500 );
+ } while( mInitOK );
+}
+
+void FileWatcherKqueue::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+}
+
+std::list<std::string> FileWatcherKqueue::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ WatchMap::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ dirs.push_back( it->second->Directory );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherKqueue::pathInWatches( const std::string& path )
+{
+ WatchMap::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void FileWatcherKqueue::addFD()
+{
+ mFileDescriptorCount++;
+}
+
+void FileWatcherKqueue::removeFD()
+{
+ mFileDescriptorCount--;
+}
+
+bool FileWatcherKqueue::availablesFD()
+{
+ return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherKqueue.hpp b/dep/efsw/src/efsw/FileWatcherKqueue.hpp
new file mode 100644
index 00000000000..0a2431e3777
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherKqueue.hpp
@@ -0,0 +1,78 @@
+#ifndef EFSW_FILEWATCHEROSX_HPP
+#define EFSW_FILEWATCHEROSX_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <efsw/WatcherKqueue.hpp>
+
+namespace efsw
+{
+
+/// Implementation for OSX based on kqueue.
+/// @class FileWatcherKqueue
+class FileWatcherKqueue : public FileWatcherImpl
+{
+ friend class WatcherKqueue;
+ public:
+ FileWatcherKqueue( FileWatcher * parent );
+
+ virtual ~FileWatcherKqueue();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ /// Map of WatchID to WatchStruct pointers
+ WatchMap mWatches;
+
+ /// time out data
+ struct timespec mTimeOut;
+
+ /// WatchID allocator
+ int mLastWatchID;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ std::list<WatchID> mRemoveList;
+
+ long mFileDescriptorCount;
+
+ bool mAddingWatcher;
+
+ bool isAddingWatcher() const;
+
+ bool pathInWatches( const std::string& path );
+
+ void addFD();
+
+ void removeFD();
+
+ bool availablesFD();
+ private:
+ void run();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherWin32.cpp b/dep/efsw/src/efsw/FileWatcherWin32.cpp
new file mode 100644
index 00000000000..fe78dd122cf
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherWin32.cpp
@@ -0,0 +1,291 @@
+#include <efsw/FileWatcherWin32.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/System.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw
+{
+
+FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) :
+ FileWatcherImpl( parent ),
+ mLastWatchID(0),
+ mThread( NULL )
+{
+ mInitOK = true;
+}
+
+FileWatcherWin32::~FileWatcherWin32()
+{
+ WatchVector::iterator iter = mWatches.begin();
+
+ mWatchesLock.lock();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ DestroyWatch((*iter));
+ }
+
+ mHandles.clear();
+ mWatches.clear();
+
+ mInitOK = false;
+
+ mWatchesLock.unlock();
+
+ efSAFE_DELETE( mThread );
+}
+
+WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
+{
+ std::string dir( directory );
+
+ FileInfo fi( dir );
+
+ if ( !fi.isDirectory() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( !fi.isReadable() )
+ {
+ return Errors::Log::createLastError( Errors::FileNotReadable, dir );
+ }
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ WatchID watchid = ++mLastWatchID;
+
+ mWatchesLock.lock();
+
+ WatcherStructWin32 * watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), recursive, FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_SIZE
+ );
+
+ if( NULL == watch )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+
+ if ( pathInWatches( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, dir );
+ }
+
+ // Add the handle to the handles vector
+ watch->Watch->ID = watchid;
+ watch->Watch->Watch = this;
+ watch->Watch->Listener = watcher;
+ watch->Watch->DirName = new char[dir.length()+1];
+ strcpy(watch->Watch->DirName, dir.c_str());
+
+ mHandles.push_back( watch->Watch->DirHandle );
+ mWatches.push_back( watch );
+ mWatchesLock.unlock();
+
+ return watchid;
+}
+
+void FileWatcherWin32::removeWatch(const std::string& directory)
+{
+ mWatchesLock.lock();
+
+ WatchVector::iterator iter = mWatches.begin();
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ if(directory == (*iter)->Watch->DirName)
+ {
+ removeWatch((*iter)->Watch->ID);
+ return;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherWin32::removeWatch(WatchID watchid)
+{
+ mWatchesLock.lock();
+
+ WatchVector::iterator iter = mWatches.begin();
+
+ WatcherStructWin32* watch = NULL;
+
+ for(; iter != mWatches.end(); ++iter)
+ {
+ // Find the watch ID
+ if ( (*iter)->Watch->ID == watchid )
+ {
+ watch = (*iter);
+
+ mWatches.erase( iter );
+
+ // Remove handle from the handle vector
+ HandleVector::iterator it = mHandles.begin();
+
+ for ( ; it != mHandles.end(); it++ )
+ {
+ if ( watch->Watch->DirHandle == (*it) )
+ {
+ mHandles.erase( it );
+ break;
+ }
+ }
+
+ DestroyWatch(watch);
+
+ break;
+ }
+ }
+
+ mWatchesLock.unlock();
+}
+
+void FileWatcherWin32::watch()
+{
+ if ( NULL == mThread )
+ {
+ mThread = new Thread( &FileWatcherWin32::run, this );
+ mThread->launch();
+ }
+}
+
+void FileWatcherWin32::run()
+{
+ if ( mHandles.empty() )
+ {
+ return;
+ }
+
+ do
+ {
+ if ( !mHandles.empty() )
+ {
+ mWatchesLock.lock();
+
+ for ( std::size_t i = 0; i < mWatches.size(); i++ )
+ {
+ WatcherStructWin32 * watch = mWatches[ i ];
+
+ // If the overlapped struct was cancelled ( because the creator thread doesn't exists anymore ),
+ // we recreate the overlapped in the current thread and refresh the watch
+ if ( /*STATUS_CANCELED*/0xC0000120 == watch->Overlapped.Internal )
+ {
+ watch->Overlapped = OVERLAPPED();
+ RefreshWatch(watch);
+ }
+
+ // First ensure that the handle is the same, this means that the watch was not removed.
+ if ( HasOverlappedIoCompleted( &watch->Overlapped ) && mHandles[ i ] == watch->Watch->DirHandle )
+ {
+ DWORD bytes;
+
+ if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) )
+ {
+ WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped );
+ }
+ }
+ }
+
+ mWatchesLock.unlock();
+
+ if ( mInitOK )
+ {
+ System::sleep( 10 );
+ }
+ }
+ else
+ {
+ // Wait for a new handle to be added
+ System::sleep( 10 );
+ }
+ } while ( mInitOK );
+}
+
+void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
+{
+ Action fwAction;
+
+ switch(action)
+ {
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ watch->OldFileName = filename;
+ return;
+ case FILE_ACTION_ADDED:
+ fwAction = Actions::Add;
+ break;
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ {
+ fwAction = Actions::Moved;
+
+ std::string fpath( watch->Directory + filename );
+
+ // Update the directory path
+ if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
+ {
+ // Update the new directory path
+ std::string opath( watch->Directory + watch->OldFileName );
+ FileSystem::dirAddSlashAtEnd( opath );
+ FileSystem::dirAddSlashAtEnd( fpath );
+
+ for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Watch->Directory == opath )
+ {
+ (*it)->Watch->Directory = fpath;
+
+ break;
+ }
+ }
+ }
+
+ watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName);
+ return;
+ }
+ case FILE_ACTION_REMOVED:
+ fwAction = Actions::Delete;
+ break;
+ case FILE_ACTION_MODIFIED:
+ fwAction = Actions::Modified;
+ break;
+ };
+
+ watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction);
+}
+
+std::list<std::string> FileWatcherWin32::directories()
+{
+ std::list<std::string> dirs;
+
+ mWatchesLock.lock();
+
+ for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ dirs.push_back( std::string( (*it)->Watch->DirName ) );
+ }
+
+ mWatchesLock.unlock();
+
+ return dirs;
+}
+
+bool FileWatcherWin32::pathInWatches( const std::string& path )
+{
+ for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ if ( (*it)->Watch->DirName == path )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/FileWatcherWin32.hpp b/dep/efsw/src/efsw/FileWatcherWin32.hpp
new file mode 100644
index 00000000000..505cd772b82
--- /dev/null
+++ b/dep/efsw/src/efsw/FileWatcherWin32.hpp
@@ -0,0 +1,69 @@
+#ifndef EFSW_FILEWATCHERWIN32_HPP
+#define EFSW_FILEWATCHERWIN32_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#include <efsw/WatcherWin32.hpp>
+#include <vector>
+#include <map>
+
+namespace efsw
+{
+
+/// Implementation for Win32 based on ReadDirectoryChangesW.
+/// @class FileWatcherWin32
+class FileWatcherWin32 : public FileWatcherImpl
+{
+ public:
+ /// type for a map from WatchID to WatcherWin32 pointer
+ typedef std::vector<WatcherStructWin32*> WatchVector;
+ typedef std::vector<HANDLE> HandleVector;
+
+ FileWatcherWin32( FileWatcher * parent );
+
+ virtual ~FileWatcherWin32();
+
+ /// Add a directory watch
+ /// On error returns WatchID with Error type.
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive);
+
+ /// Remove a directory watch. This is a brute force lazy search O(nlogn).
+ void removeWatch(const std::string& directory);
+
+ /// Remove a directory watch. This is a map lookup O(logn).
+ void removeWatch(WatchID watchid);
+
+ /// Updates the watcher. Must be called often.
+ void watch();
+
+ /// Handles the action
+ void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = "");
+
+ /// @return Returns a list of the directories that are being watched
+ std::list<std::string> directories();
+ protected:
+ /// Vector of WatcherWin32 pointers
+ WatchVector mWatches;
+
+ /// Keeps an updated handles vector
+ HandleVector mHandles;
+
+ /// The last watchid
+ WatchID mLastWatchID;
+
+ Thread * mThread;
+
+ Mutex mWatchesLock;
+
+ bool pathInWatches( const std::string& path );
+ private:
+ void run();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/Log.cpp b/dep/efsw/src/efsw/Log.cpp
new file mode 100644
index 00000000000..8e2860ac099
--- /dev/null
+++ b/dep/efsw/src/efsw/Log.cpp
@@ -0,0 +1,27 @@
+#include <efsw/efsw.hpp>
+
+namespace efsw { namespace Errors {
+
+static std::string LastError;
+
+std::string Log::getLastErrorLog()
+{
+ return LastError;
+}
+
+Error Log::createLastError( Error err, std::string log )
+{
+ switch ( err )
+ {
+ case FileNotFound: LastError = "File not found ( " + log + " )"; break;
+ case FileRepeated: LastError = "File reapeated in watches ( " + log + " )"; break;
+ case FileOutOfScope: LastError = "Symlink file out of scope ( " + log + " )"; break;
+ case FileRemote: LastError = "File is located in a remote file system, use a generic watcher. ( " + log + " )"; break;
+ case Unspecified:
+ default: LastError = log;
+ }
+
+ return err;
+}
+
+}}
diff --git a/dep/efsw/src/efsw/Mutex.cpp b/dep/efsw/src/efsw/Mutex.cpp
new file mode 100644
index 00000000000..b34ba066ee9
--- /dev/null
+++ b/dep/efsw/src/efsw/Mutex.cpp
@@ -0,0 +1,26 @@
+#include <efsw/Mutex.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+namespace efsw {
+
+Mutex::Mutex() :
+ mMutexImpl( new Platform::MutexImpl() )
+{
+}
+
+Mutex::~Mutex()
+{
+ efSAFE_DELETE( mMutexImpl );
+}
+
+void Mutex::lock()
+{
+ mMutexImpl->lock();
+}
+
+void Mutex::unlock()
+{
+ mMutexImpl->unlock();
+}
+
+}
diff --git a/dep/efsw/src/efsw/Mutex.hpp b/dep/efsw/src/efsw/Mutex.hpp
new file mode 100644
index 00000000000..e6e89def175
--- /dev/null
+++ b/dep/efsw/src/efsw/Mutex.hpp
@@ -0,0 +1,28 @@
+#ifndef EFSW_MUTEX_HPP
+#define EFSW_MUTEX_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+namespace Platform { class MutexImpl; }
+
+/** Simple mutex class */
+class Mutex {
+ public:
+ Mutex();
+
+ ~Mutex();
+
+ /** Lock the mutex */
+ void lock();
+
+ /** Unlock the mutex */
+ void unlock();
+ private:
+ Platform::MutexImpl * mMutexImpl;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/String.cpp b/dep/efsw/src/efsw/String.cpp
new file mode 100644
index 00000000000..f703d25cb35
--- /dev/null
+++ b/dep/efsw/src/efsw/String.cpp
@@ -0,0 +1,813 @@
+#include <iterator>
+#include <efsw/String.hpp>
+#include <efsw/Utf.hpp>
+
+namespace efsw {
+
+const std::size_t String::InvalidPos = StringType::npos;
+
+std::vector < std::string > String::split ( const std::string& str, const char& splitchar, const bool& pushEmptyString )
+{
+ std::vector < std::string > tmp;
+ std::string tmpstr;
+
+ for ( size_t i = 0; i < str.size(); i++ )
+ {
+ if ( str[i] == splitchar )
+ {
+ if ( pushEmptyString || tmpstr.size() )
+ {
+ tmp.push_back(tmpstr);
+ tmpstr = "";
+ }
+ }
+ else
+ {
+ tmpstr += str[i];
+ }
+ }
+
+ if ( tmpstr.size() )
+ {
+ tmp.push_back( tmpstr );
+ }
+
+ return tmp;
+}
+
+std::vector < String > String::split ( const String& str, const Uint32& splitchar, const bool& pushEmptyString )
+{
+ std::vector < String > tmp;
+ String tmpstr;
+
+ for ( size_t i = 0; i < str.size(); i++ )
+ {
+ if ( str[i] == splitchar )
+ {
+ if ( pushEmptyString || tmpstr.size() )
+ {
+ tmp.push_back(tmpstr);
+ tmpstr = "";
+ }
+ }
+ else
+ {
+ tmpstr += str[i];
+ }
+ }
+
+ if ( tmpstr.size() )
+ {
+ tmp.push_back( tmpstr );
+ }
+
+ return tmp;
+}
+
+int String::strStartsWith( const std::string& start, const std::string& str )
+{
+ int pos = -1;
+ size_t size = start.size();
+
+ if ( str.size() >= size )
+ {
+ for ( std::size_t i = 0; i < size; i++ )
+ {
+ if ( start[i] == str[i] )
+ {
+ pos = (int)i;
+ }
+ else
+ {
+ pos = -1;
+ break;
+ }
+ }
+ }
+
+ return pos;
+}
+
+int String::strStartsWith( const String& start, const String& str )
+{
+ int pos = -1;
+ size_t size = start.size();
+
+ if ( str.size() >= size )
+ {
+ for ( std::size_t i = 0; i < size; i++ )
+ {
+ if ( start[i] == str[i] )
+ {
+ pos = (int)i;
+ }
+ else
+ {
+ pos = -1;
+ break;
+ }
+ }
+ }
+
+ return pos;
+}
+
+String::String()
+{
+}
+
+String::String(char ansiChar, const std::locale& locale)
+{
+ mString += Utf32::DecodeAnsi(ansiChar, locale);
+}
+
+#ifndef EFSW_NO_WIDECHAR
+String::String(wchar_t wideChar)
+{
+ mString += Utf32::DecodeWide(wideChar);
+}
+#endif
+
+String::String(StringBaseType utf32Char)
+{
+ mString += utf32Char;
+}
+
+String::String( const char* uf8String ) {
+ if (uf8String)
+ {
+ std::size_t length = strlen(uf8String);
+
+ if (length > 0)
+ {
+ mString.reserve(length + 1);
+
+ Utf8::ToUtf32(uf8String, uf8String + length, std::back_inserter(mString));
+ }
+ }
+}
+
+String::String( const std::string& utf8String ) {
+ mString.reserve( utf8String.length() + 1 );
+
+ Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) );
+}
+
+String::String(const char* ansiString, const std::locale& locale)
+{
+ if (ansiString)
+ {
+ std::size_t length = strlen(ansiString);
+ if (length > 0)
+ {
+ mString.reserve(length + 1);
+ Utf32::FromAnsi(ansiString, ansiString + length, std::back_inserter(mString), locale);
+ }
+ }
+}
+
+String::String(const std::string& ansiString, const std::locale& locale)
+{
+ mString.reserve(ansiString.length() + 1);
+ Utf32::FromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(mString), locale);
+}
+
+#ifndef EFSW_NO_WIDECHAR
+String::String(const wchar_t* wideString)
+{
+ if (wideString)
+ {
+ std::size_t length = std::wcslen(wideString);
+ if (length > 0)
+ {
+ mString.reserve(length + 1);
+ Utf32::FromWide(wideString, wideString + length, std::back_inserter(mString));
+ }
+ }
+}
+
+String::String(const std::wstring& wideString)
+{
+ mString.reserve(wideString.length() + 1);
+ Utf32::FromWide(wideString.begin(), wideString.end(), std::back_inserter(mString));
+}
+#endif
+
+String::String(const StringBaseType* utf32String)
+{
+ if (utf32String)
+ mString = utf32String;
+}
+
+String::String(const StringType& utf32String) :
+mString(utf32String)
+{
+}
+
+String::String(const String& str) :
+mString(str.mString)
+{
+}
+
+String String::fromUtf8( const std::string& utf8String )
+{
+ String::StringType utf32;
+
+ utf32.reserve( utf8String.length() + 1 );
+
+ Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( utf32 ) );
+
+ return String( utf32 );
+}
+
+String::operator std::string() const
+{
+ return toAnsiString();
+}
+
+std::string String::toAnsiString(const std::locale& locale) const
+{
+ // Prepare the output string
+ std::string output;
+ output.reserve(mString.length() + 1);
+
+ // Convert
+ Utf32::ToAnsi(mString.begin(), mString.end(), std::back_inserter(output), 0, locale);
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+std::wstring String::toWideString() const
+{
+ // Prepare the output string
+ std::wstring output;
+ output.reserve(mString.length() + 1);
+
+ // Convert
+ Utf32::ToWide(mString.begin(), mString.end(), std::back_inserter(output), 0);
+
+ return output;
+}
+#endif
+
+std::string String::toUtf8() const {
+ // Prepare the output string
+ std::string output;
+ output.reserve(mString.length() + 1);
+
+ // Convert
+ Utf32::toUtf8(mString.begin(), mString.end(), std::back_inserter(output) );
+
+ return output;
+}
+
+String& String::operator =(const String& right)
+{
+ mString = right.mString;
+ return *this;
+}
+
+String& String::operator =( const StringBaseType& right )
+{
+ mString = right;
+ return *this;
+}
+
+String& String::operator +=(const String& right)
+{
+ mString += right.mString;
+ return *this;
+}
+
+String& String::operator +=( const StringBaseType& right )
+{
+ mString += right;
+ return *this;
+}
+
+
+String::StringBaseType String::operator [](std::size_t index) const
+{
+ return mString[index];
+}
+
+String::StringBaseType& String::operator [](std::size_t index)
+{
+ return mString[index];
+}
+
+String::StringBaseType String::at( std::size_t index ) const
+{
+ return mString.at( index );
+}
+
+void String::push_back( StringBaseType c )
+{
+ mString.push_back( c );
+}
+
+void String::swap ( String& str )
+{
+ mString.swap( str.mString );
+}
+
+void String::clear()
+{
+ mString.clear();
+}
+
+std::size_t String::size() const
+{
+ return mString.size();
+}
+
+std::size_t String::length() const
+{
+ return mString.length();
+}
+
+bool String::empty() const
+{
+ return mString.empty();
+}
+
+void String::erase(std::size_t position, std::size_t count)
+{
+ mString.erase(position, count);
+}
+
+String& String::insert(std::size_t position, const String& str)
+{
+ mString.insert(position, str.mString);
+ return *this;
+}
+
+String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n )
+{
+ mString.insert( pos1, str.mString, pos2, n );
+ return *this;
+}
+
+String& String::insert ( size_t pos1, const char* s, size_t n )
+{
+ String tmp( s );
+
+ mString.insert( pos1, tmp.data(), n );
+
+ return *this;
+}
+
+String& String::insert ( size_t pos1, size_t n, char c )
+{
+ mString.insert( pos1, n, c );
+ return *this;
+}
+
+String& String::insert ( size_t pos1, const char* s )
+{
+ String tmp( s );
+
+ mString.insert( pos1, tmp.data() );
+
+ return *this;
+}
+
+String::Iterator String::insert ( Iterator p, char c )
+{
+ return mString.insert( p, c );
+}
+
+void String::insert ( Iterator p, size_t n, char c )
+{
+ mString.insert( p, n, c );
+}
+
+const String::StringBaseType* String::c_str() const
+{
+ return mString.c_str();
+}
+
+const String::StringBaseType* String::data() const
+{
+ return mString.data();
+}
+
+String::Iterator String::begin()
+{
+ return mString.begin();
+}
+
+String::ConstIterator String::begin() const
+{
+ return mString.begin();
+}
+
+String::Iterator String::end()
+{
+ return mString.end();
+}
+
+String::ConstIterator String::end() const
+{
+ return mString.end();
+}
+
+String::ReverseIterator String::rbegin()
+{
+ return mString.rbegin();
+}
+
+String::ConstReverseIterator String::rbegin() const
+{
+ return mString.rbegin();
+}
+
+String::ReverseIterator String::rend()
+{
+ return mString.rend();
+}
+
+String::ConstReverseIterator String::rend() const
+{
+ return mString.rend();
+}
+
+void String::resize( std::size_t n, StringBaseType c )
+{
+ mString.resize( n, c );
+}
+
+void String::resize( std::size_t n )
+{
+ mString.resize( n );
+}
+
+std::size_t String::max_size() const
+{
+ return mString.max_size();
+}
+
+void String::reserve( size_t res_arg )
+{
+ mString.reserve( res_arg );
+}
+
+std::size_t String::capacity() const
+{
+ return mString.capacity();
+}
+
+String& String::assign ( const String& str )
+{
+ mString.assign( str.mString );
+ return *this;
+}
+
+String& String::assign ( const String& str, size_t pos, size_t n )
+{
+ mString.assign( str.mString, pos, n );
+ return *this;
+}
+
+String& String::assign ( const char* s, size_t n )
+{
+ String tmp( s );
+
+ mString.assign( tmp.mString );
+
+ return *this;
+}
+
+String& String::assign ( const char* s )
+{
+ String tmp( s );
+
+ mString.assign( tmp.mString );
+
+ return *this;
+}
+
+String& String::assign ( size_t n, char c )
+{
+ mString.assign( n, c );
+
+ return *this;
+}
+
+String& String::append ( const String& str )
+{
+ mString.append( str.mString );
+
+ return *this;
+}
+
+String& String::append ( const String& str, size_t pos, size_t n )
+{
+ mString.append( str.mString, pos, n );
+
+ return *this;
+}
+
+String& String::append ( const char* s, size_t n )
+{
+ String tmp( s );
+
+ mString.append( tmp.mString );
+
+ return *this;
+}
+
+String& String::append ( const char* s )
+{
+ String tmp( s );
+
+ mString.append( tmp.mString );
+
+ return *this;
+}
+
+String& String::append ( size_t n, char c )
+{
+ mString.append( n, c );
+
+ return *this;
+}
+
+String& String::append ( std::size_t n, StringBaseType c )
+{
+ mString.append( n, c );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const String& str )
+{
+ mString.replace( pos1, n1, str.mString );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, const String& str )
+{
+ mString.replace( i1, i2, str.mString );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 )
+{
+ mString.replace( pos1, n1, str.mString, pos2, n2 );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const char* s, size_t n2 )
+{
+ String tmp( s );
+
+ mString.replace( pos1, n1, tmp.data(), n2 );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, const char* s, size_t n2 )
+{
+ String tmp( s );
+
+ mString.replace( i1, i2, tmp.data(), n2 );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, const char* s )
+{
+ String tmp( s );
+
+ mString.replace( pos1, n1, tmp.mString );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, const char* s )
+{
+ String tmp( s );
+
+ mString.replace( i1, i2, tmp.mString );
+
+ return *this;
+}
+
+String& String::replace ( size_t pos1, size_t n1, size_t n2, char c )
+{
+ mString.replace( pos1, n1, n2, (StringBaseType)c );
+
+ return *this;
+}
+
+String& String::replace ( Iterator i1, Iterator i2, size_t n2, char c )
+{
+ mString.replace( i1, i2, n2, (StringBaseType)c );
+
+ return *this;
+}
+
+std::size_t String::find( const String& str, std::size_t start ) const
+{
+ return mString.find( str.mString, start );
+}
+
+std::size_t String::find ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find( String( s ), pos );
+}
+
+std::size_t String::find ( const char* s, std::size_t pos ) const
+{
+ return find( String( s ), pos );
+}
+
+size_t String::find ( char c, std::size_t pos ) const
+{
+ return mString.find( (StringBaseType)c, pos );
+}
+
+std::size_t String::rfind ( const String& str, std::size_t pos ) const
+{
+ return mString.rfind( str.mString, pos );
+}
+
+std::size_t String::rfind ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return rfind( String( s ), pos );
+}
+
+std::size_t String::rfind ( const char* s, std::size_t pos ) const
+{
+ return rfind( String( s ), pos );
+}
+
+std::size_t String::rfind ( char c, std::size_t pos ) const
+{
+ return mString.rfind( c, pos );
+}
+
+std::size_t String::copy ( StringBaseType* s, std::size_t n, std::size_t pos ) const
+{
+ return mString.copy( s, n, pos );
+}
+
+String String::substr ( std::size_t pos, std::size_t n ) const
+{
+ return String( mString.substr( pos, n ) );
+}
+
+int String::compare ( const String& str ) const
+{
+ return mString.compare( str.mString );
+}
+
+int String::compare ( const char* s ) const
+{
+ return compare( String( s ) );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const String& str ) const
+{
+ return mString.compare( pos1, n1, str.mString );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const char* s) const
+{
+ return compare( pos1, n1, String( s ) );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const
+{
+ return mString.compare( pos1, n1, str.mString, pos2, n2 );
+}
+
+int String::compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const
+{
+ return compare( pos1, n1, String( s ), 0, n2 );
+}
+
+std::size_t String::find_first_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_first_of( str.mString, pos );
+}
+
+std::size_t String::find_first_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_first_of( String( s ), pos );
+}
+
+std::size_t String::find_first_of ( const char* s, std::size_t pos ) const
+{
+ return find_first_of( String( s ), pos );
+}
+
+std::size_t String::find_first_of ( StringBaseType c, std::size_t pos ) const
+{
+ return mString.find_first_of( c, pos );
+}
+
+std::size_t String::find_last_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_last_of( str.mString, pos );
+}
+
+std::size_t String::find_last_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_last_of( String( s ), pos );
+}
+
+std::size_t String::find_last_of ( const char* s, std::size_t pos ) const
+{
+ return find_last_of( String( s ), pos );
+}
+
+std::size_t String::find_last_of ( StringBaseType c, std::size_t pos) const
+{
+ return mString.find_last_of( c, pos );
+}
+
+std::size_t String::find_first_not_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_first_not_of( str.mString, pos );
+}
+
+std::size_t String::find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_first_not_of( String( s ), pos );
+}
+
+std::size_t String::find_first_not_of ( const char* s, std::size_t pos ) const
+{
+ return find_first_not_of( String( s ), pos );
+}
+
+std::size_t String::find_first_not_of ( StringBaseType c, std::size_t pos ) const
+{
+ return mString.find_first_not_of( c, pos );
+}
+
+std::size_t String::find_last_not_of ( const String& str, std::size_t pos ) const
+{
+ return mString.find_last_not_of( str.mString, pos );
+}
+
+std::size_t String::find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const
+{
+ return find_last_not_of( String( s ), pos );
+}
+
+std::size_t String::find_last_not_of ( const char* s, std::size_t pos ) const
+{
+ return find_last_not_of( String( s ), pos );
+}
+
+std::size_t String::find_last_not_of ( StringBaseType c, std::size_t pos ) const
+{
+ return mString.find_last_not_of( c, pos );
+}
+
+bool operator ==(const String& left, const String& right)
+{
+ return left.mString == right.mString;
+}
+
+bool operator !=(const String& left, const String& right)
+{
+ return !(left == right);
+}
+
+bool operator <(const String& left, const String& right)
+{
+ return left.mString < right.mString;
+}
+
+bool operator >(const String& left, const String& right)
+{
+ return right < left;
+}
+
+bool operator <=(const String& left, const String& right)
+{
+ return !(right < left);
+}
+
+bool operator >=(const String& left, const String& right)
+{
+ return !(left < right);
+}
+
+String operator +(const String& left, const String& right)
+{
+ String string = left;
+ string += right;
+
+ return string;
+}
+
+}
diff --git a/dep/efsw/src/efsw/String.hpp b/dep/efsw/src/efsw/String.hpp
new file mode 100644
index 00000000000..ce7e3b75f89
--- /dev/null
+++ b/dep/efsw/src/efsw/String.hpp
@@ -0,0 +1,629 @@
+/** NOTE:
+* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php )
+* The class was modified to fit efsw own needs. This is not the original implementation from SFML2.
+* Functions and methods are the same that in std::string to facilitate portability.
+**/
+
+#ifndef EFSW_STRING_HPP
+#define EFSW_STRING_HPP
+
+#include <efsw/base.hpp>
+#include <locale>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+namespace efsw {
+
+/** @brief Utility string class that automatically handles conversions between types and encodings **/
+class String
+{
+ public :
+ typedef Uint32 StringBaseType;
+ typedef std::basic_string<StringBaseType> StringType;
+ typedef StringType::iterator Iterator; //! Iterator type
+ typedef StringType::const_iterator ConstIterator; //! Constant iterator type
+ typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type
+ typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type
+
+ static const std::size_t InvalidPos; ///< Represents an invalid position in the string
+
+ template <class T>
+ static std::string toStr(const T& i) {
+ std::ostringstream ss;
+ ss << i;
+ return ss.str();
+ }
+
+ /** Converts from a string to type */
+ template <class T>
+ static bool fromString(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) {
+ std::istringstream iss(s);
+ return !(iss >> f >> t).fail();
+ }
+
+ /** Converts from a String to type */
+ template <class T>
+ static bool fromString(T& t, const String& s, std::ios_base& (*f)(std::ios_base&) = std::dec ) {
+ std::istringstream iss( s.toUtf8() );
+ return !(iss >> f >> t).fail();
+ }
+
+ /** Split a string and hold it on a vector */
+ static std::vector < std::string > split( const std::string& str, const char& splitchar, const bool& pushEmptyString = false );
+
+ /** Split a string and hold it on a vector */
+ static std::vector < String > split( const String& str, const Uint32& splitchar, const bool& pushEmptyString = false );
+
+ /** Determine if a string starts with the string passed
+ ** @param start The substring expected to start
+ ** @param str The string to compare
+ ** @return -1 if the substring is no in str, otherwise the size of the substring
+ */
+ static int strStartsWith( const std::string& start, const std::string& str );
+
+ static int strStartsWith( const String& start, const String& str );
+
+ /** @brief Construct from an UTF-8 string to UTF-32 according
+ ** @param uf8String UTF-8 string to convert
+ **/
+ static String fromUtf8( const std::string& utf8String );
+
+ /** @brief Default constructor
+ ** This constructor creates an empty string.
+ **/
+ String();
+
+ /** @brief Construct from a single ANSI character and a locale
+ ** The source character is converted to UTF-32 according
+ ** to the given locale. If you want to use the current global
+ ** locale, rather use the other constructor.
+ ** @param ansiChar ANSI character to convert
+ ** @param locale Locale to use for conversion
+ **/
+ String( char ansiChar, const std::locale& locale = std::locale() );
+
+#ifndef EFSW_NO_WIDECHAR
+ /** @brief Construct from single wide character
+ ** @param wideChar Wide character to convert
+ **/
+ String( wchar_t wideChar );
+#endif
+
+ /** @brief Construct from single UTF-32 character
+ ** @param utf32Char UTF-32 character to convert
+ **/
+ String( StringBaseType utf32Char );
+
+ /** @brief Construct from an from a null-terminated C-style UTF-8 string to UTF-32
+ ** @param uf8String UTF-8 string to convert
+ **/
+ String( const char* uf8String );
+
+ /** @brief Construct from an UTF-8 string to UTF-32 according
+ ** @param uf8String UTF-8 string to convert
+ **/
+ String( const std::string& utf8String );
+
+ /** @brief Construct from a null-terminated C-style ANSI string and a locale
+ ** The source string is converted to UTF-32 according
+ ** to the given locale. If you want to use the current global
+ ** locale, rather use the other constructor.
+ ** @param ansiString ANSI string to convert
+ ** @param locale Locale to use for conversion
+ **/
+ String( const char* ansiString, const std::locale& locale );
+
+ /** @brief Construct from an ANSI string and a locale
+ ** The source string is converted to UTF-32 according
+ ** to the given locale. If you want to use the current global
+ ** locale, rather use the other constructor.
+ ** @param ansiString ANSI string to convert
+ ** @param locale Locale to use for conversion
+ **/
+ String( const std::string& ansiString, const std::locale& locale );
+
+#ifndef EFSW_NO_WIDECHAR
+ /** @brief Construct from null-terminated C-style wide string
+ ** @param wideString Wide string to convert
+ **/
+ String( const wchar_t* wideString );
+
+ /** @brief Construct from a wide string
+ ** @param wideString Wide string to convert
+ **/
+ String( const std::wstring& wideString );
+#endif
+
+ /** @brief Construct from a null-terminated C-style UTF-32 string
+ ** @param utf32String UTF-32 string to assign
+ **/
+ String( const StringBaseType* utf32String );
+
+ /** @brief Construct from an UTF-32 string
+ ** @param utf32String UTF-32 string to assign
+ **/
+ String( const StringType& utf32String );
+
+
+ /** @brief Copy constructor
+ ** @param str Instance to copy
+ **/
+ String( const String& str );
+
+ /** @brief Implicit cast operator to std::string (ANSI string)
+ ** The current global locale is used for conversion. If you
+ ** want to explicitely specify a locale, see toAnsiString.
+ ** Characters that do not fit in the target encoding are
+ ** discarded from the returned string.
+ ** This operator is defined for convenience, and is equivalent
+ ** to calling toAnsiString().
+ ** @return Converted ANSI string
+ ** @see toAnsiString, operator String
+ **/
+ operator std::string() const;
+
+ /** @brief Convert the unicode string to an ANSI string
+ ** The UTF-32 string is converted to an ANSI string in
+ ** the encoding defined by \a locale. If you want to use
+ ** the current global locale, see the other overload
+ ** of toAnsiString.
+ ** Characters that do not fit in the target encoding are
+ ** discarded from the returned string.
+ ** @param locale Locale to use for conversion
+ ** @return Converted ANSI string
+ ** @see toWideString, operator std::string
+ **/
+ std::string toAnsiString( const std::locale& locale = std::locale() ) const;
+
+#ifndef EFSW_NO_WIDECHAR
+ /** @brief Convert the unicode string to a wide string
+ ** Characters that do not fit in the target encoding are
+ ** discarded from the returned string.
+ ** @return Converted wide string
+ ** @see toAnsiString, operator String
+ **/
+ std::wstring toWideString() const;
+#endif
+
+ std::string toUtf8() const;
+
+ /** @brief Overload of assignment operator
+ ** @param right Instance to assign
+ ** @return Reference to self
+ **/
+ String& operator =(const String& right);
+
+ String& operator =( const StringBaseType& right );
+
+ /** @brief Overload of += operator to append an UTF-32 string
+ ** @param right String to append
+ ** @return Reference to self
+ **/
+ String& operator +=(const String& right);
+
+ String& operator +=( const StringBaseType& right );
+
+ /** @brief Overload of [] operator to access a character by its position
+ ** This function provides read-only access to characters.
+ ** Note: this function doesn't throw if \a index is out of range.
+ ** @param index Index of the character to get
+ ** @return Character at position \a index
+ **/
+ StringBaseType operator [](std::size_t index) const;
+
+ /** @brief Overload of [] operator to access a character by its position
+ ** This function provides read and write access to characters.
+ ** Note: this function doesn't throw if \a index is out of range.
+ ** @param index Index of the character to get
+ ** @return Reference to the character at position \a index
+ **/
+
+ StringBaseType& operator [](std::size_t index);
+
+ /** @brief Get character in string
+ ** Performs a range check, throwing an exception of type out_of_range in case that pos is not an actual position in the string.
+ ** @return The character at position pos in the string.
+ */
+ StringBaseType at( std::size_t index ) const;
+
+ /** @brief clear the string
+ ** This function removes all the characters from the string.
+ ** @see empty, erase
+ **/
+ void clear();
+
+ /** @brief Get the size of the string
+ ** @return Number of characters in the string
+ ** @see empty
+ **/
+ std::size_t size() const;
+
+ /** @see size() */
+ std::size_t length() const;
+
+ /** @brief Check whether the string is empty or not
+ ** @return True if the string is empty (i.e. contains no character)
+ ** @see clear, size
+ **/
+ bool empty() const;
+
+ /** @brief Erase one or more characters from the string
+ ** This function removes a sequence of \a count characters
+ ** starting from \a position.
+ ** @param position Position of the first character to erase
+ ** @param count Number of characters to erase
+ **/
+ void erase(std::size_t position, std::size_t count = 1);
+
+
+ /** @brief Insert one or more characters into the string
+ ** This function inserts the characters of \a str
+ ** into the string, starting from \a position.
+ ** @param position Position of insertion
+ ** @param str Characters to insert
+ **/
+ String& insert(std::size_t position, const String& str);
+
+ String& insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n );
+
+ String& insert ( std::size_t pos1, const char* s, std::size_t n );
+
+ String& insert ( std::size_t pos1, const char* s );
+
+ String& insert ( std::size_t pos1, size_t n, char c );
+
+ Iterator insert ( Iterator p, char c );
+
+ void insert ( Iterator p, std::size_t n, char c );
+
+ template<class InputIterator>
+ void insert ( Iterator p, InputIterator first, InputIterator last )
+ {
+ mString.insert( p, first, last );
+ }
+
+ /** @brief Find a sequence of one or more characters in the string
+ ** This function searches for the characters of \a str
+ ** into the string, starting from \a start.
+ ** @param str Characters to find
+ ** @param start Where to begin searching
+ ** @return Position of \a str in the string, or String::InvalidPos if not found
+ **/
+ std::size_t find( const String& str, std::size_t start = 0 ) const;
+
+ std::size_t find ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find ( const char* s, std::size_t pos = 0 ) const;
+
+ std::size_t find ( char c, std::size_t pos = 0 ) const;
+
+ /** @brief Get a pointer to the C-style array of characters
+ ** This functions provides a read-only access to a
+ ** null-terminated C-style representation of the string.
+ ** The returned pointer is temporary and is meant only for
+ ** immediate use, thus it is not recommended to store it.
+ ** @return Read-only pointer to the array of characters
+ **/
+ const StringBaseType* c_str() const;
+
+ /** @brief Get string data
+ ** Notice that no terminating null character is appended (see member c_str for such a functionality).
+ ** The returned array points to an internal location which should not be modified directly in the program.
+ ** Its contents are guaranteed to remain unchanged only until the next call to a non-constant member function of the string object.
+ ** @return Pointer to an internal array containing the same content as the string.
+ **/
+ const StringBaseType* data() const;
+
+ /** @brief Return an iterator to the beginning of the string
+ ** @return Read-write iterator to the beginning of the string characters
+ ** @see end
+ **/
+ Iterator begin();
+
+ /** @brief Return an iterator to the beginning of the string
+ ** @return Read-only iterator to the beginning of the string characters
+ ** @see end
+ **/
+ ConstIterator begin() const;
+
+ /** @brief Return an iterator to the beginning of the string
+ ** The end iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-write iterator to the end of the string characters
+ ** @see begin
+ **/
+ Iterator end();
+
+ /** @brief Return an iterator to the beginning of the string
+ ** The end iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-only iterator to the end of the string characters
+ ** @see begin
+ **/
+ ConstIterator end() const;
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** @return Read-write reverse iterator to the beginning of the string characters
+ ** @see end
+ **/
+ ReverseIterator rbegin();
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** @return Read-only reverse iterator to the beginning of the string characters
+ ** @see end
+ **/
+ ConstReverseIterator rbegin() const;
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** The end reverse iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-write reverse iterator to the end of the string characters
+ ** @see begin
+ **/
+ ReverseIterator rend();
+
+
+ /** @brief Return an reverse iterator to the beginning of the string
+ ** The end reverse iterator refers to 1 position past the last character;
+ ** thus it represents an invalid character and should never be
+ ** accessed.
+ ** @return Read-only reverse iterator to the end of the string characters
+ ** @see begin
+ **/
+ ConstReverseIterator rend() const;
+
+ /** @brief Resize String */
+ void resize ( std::size_t n, StringBaseType c );
+
+ /** @brief Resize String */
+ void resize ( std::size_t n );
+
+ /** @return Maximum size of string */
+ std::size_t max_size() const;
+
+ /** @brief Request a change in capacity */
+ void reserve ( size_t res_arg=0 );
+
+ /** @return Size of allocated storage */
+ std::size_t capacity() const;
+
+ /** @brief Append character to string */
+ void push_back( StringBaseType c );
+
+ /** @brief Swap contents with another string */
+ void swap ( String& str );
+
+ String& assign ( const String& str );
+
+ String& assign ( const String& str, std::size_t pos, std::size_t n );
+
+ String& assign ( const char* s, std::size_t n );
+
+ String& assign ( const char* s );
+
+ String& assign ( std::size_t n, char c );
+
+ template <class InputIterator>
+ String& assign ( InputIterator first, InputIterator last )
+ {
+ mString.assign( first, last );
+ return *this;
+ }
+
+ String& append ( const String& str );
+
+ String& append ( const String& str, std::size_t pos, std::size_t n );
+
+ String& append ( const char* s, std::size_t n );
+
+ String& append ( const char* s );
+
+ String& append ( std::size_t n, char c );
+
+ String& append ( std::size_t n, StringBaseType c );
+
+ template <class InputIterator>
+ String& append ( InputIterator first, InputIterator last )
+ {
+ mString.append( first, last );
+ return *this;
+ }
+
+ String& replace ( std::size_t pos1, std::size_t n1, const String& str );
+
+ String& replace ( Iterator i1, Iterator i2, const String& str );
+
+ String& replace ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 );
+
+ String& replace ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 );
+
+ String& replace ( Iterator i1, Iterator i2, const char* s, std::size_t n2 );
+
+ String& replace ( std::size_t pos1, std::size_t n1, const char* s );
+
+ String& replace ( Iterator i1, Iterator i2, const char* s );
+
+ String& replace ( std::size_t pos1, std::size_t n1, std::size_t n2, char c );
+
+ String& replace ( Iterator i1, Iterator i2, std::size_t n2, char c );
+
+ template<class InputIterator>
+ String& replace ( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 )
+ {
+ mString.replace( i1, i2, j1, j2 );
+ return *this;
+ }
+
+ std::size_t rfind ( const String& str, std::size_t pos = StringType::npos ) const;
+
+ std::size_t rfind ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t rfind ( const char* s, std::size_t pos = StringType::npos ) const;
+
+ std::size_t rfind ( char c, std::size_t pos = StringType::npos ) const;
+
+ String substr ( std::size_t pos = 0, std::size_t n = StringType::npos ) const;
+
+ std::size_t copy ( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const;
+
+ int compare ( const String& str ) const;
+
+ int compare ( const char* s ) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const String& str ) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const char* s) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, std::size_t n2 ) const;
+
+ int compare ( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2) const;
+
+ std::size_t find_first_of ( const String& str, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_first_of ( const char* s, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_of ( StringBaseType c, std::size_t pos = 0 ) const;
+
+ std::size_t find_last_of ( const String& str, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_last_of ( const char* s, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_of ( StringBaseType c, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_first_not_of ( const String& str, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_not_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_first_not_of ( const char* s, std::size_t pos = 0 ) const;
+
+ std::size_t find_first_not_of ( StringBaseType c, std::size_t pos = 0 ) const;
+
+ std::size_t find_last_not_of ( const String& str, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_not_of ( const char* s, std::size_t pos, std::size_t n ) const;
+
+ std::size_t find_last_not_of ( const char* s, std::size_t pos = StringType::npos ) const;
+
+ std::size_t find_last_not_of ( StringBaseType c, std::size_t pos = StringType::npos ) const;
+private :
+ friend bool operator ==(const String& left, const String& right);
+ friend bool operator <(const String& left, const String& right);
+
+ StringType mString; ///< Internal string of UTF-32 characters
+};
+
+/** @relates String
+** @brief Overload of == operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if both strings are equal
+**/
+ bool operator ==(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of != operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if both strings are different
+**/
+ bool operator !=(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of < operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically lesser than \a right
+**/
+ bool operator <(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of > operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically greater than \a right
+**/
+ bool operator >(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of <= operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically lesser or equal than \a right
+**/
+ bool operator <=(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of >= operator to compare two UTF-32 strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return True if \a left is alphabetically greater or equal than \a right
+**/
+ bool operator >=(const String& left, const String& right);
+
+/** @relates String
+** @brief Overload of binary + operator to concatenate two strings
+** @param left Left operand (a string)
+** @param right Right operand (a string)
+** @return Concatenated string
+**/
+ String operator +( const String& left, const String& right );
+
+}
+
+#endif
+
+/** @class efsw::String
+** @ingroup system
+** efsw::String is a utility string class defined mainly for
+** convenience. It is a Unicode string (implemented using
+** UTF-32), thus it can store any character in the world
+** (european, chinese, arabic, hebrew, etc.).
+** It automatically handles conversions from/to ANSI and
+** wide strings, so that you can work with standard string
+** classes and still be compatible with functions taking a
+** efsw::String.
+** @code
+** efsw::String s;
+** std::string s1 = s; // automatically converted to ANSI string
+** String s2 = s; // automatically converted to wide string
+** s = "hello"; // automatically converted from ANSI string
+** s = L"hello"; // automatically converted from wide string
+** s += 'a'; // automatically converted from ANSI string
+** s += L'a'; // automatically converted from wide string
+** @endcode
+** Conversions involving ANSI strings use the default user locale. However
+** it is possible to use a custom locale if necessary:
+** @code
+** std::locale locale;
+** efsw::String s;
+** ...
+** std::string s1 = s.toAnsiString(locale);
+** s = efsw::String("hello", locale);
+** @endcode
+**
+** efsw::String defines the most important functions of the
+** standard std::string class: removing, random access, iterating,
+** appending, comparing, etc. However it is a simple class
+** provided for convenience, and you may have to consider using
+** a more optimized class if your program requires complex string
+** handling. The automatic conversion functions will then take
+** care of converting your string to efsw::String whenever EE
+** requires it.
+**
+** Please note that EE also defines a low-level, generic
+** interface for Unicode handling, see the efsw::Utf classes.
+**
+** All credits to Laurent Gomila, i just modified and expanded a little bit the implementation.
+**/
diff --git a/dep/efsw/src/efsw/System.cpp b/dep/efsw/src/efsw/System.cpp
new file mode 100644
index 00000000000..f8767cbc58f
--- /dev/null
+++ b/dep/efsw/src/efsw/System.cpp
@@ -0,0 +1,26 @@
+#include <efsw/System.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+namespace efsw {
+
+void System::sleep( const unsigned long& ms )
+{
+ Platform::System::sleep( ms );
+}
+
+std::string System::getProcessPath()
+{
+ return Platform::System::getProcessPath();
+}
+
+void System::maxFD()
+{
+ Platform::System::maxFD();
+}
+
+Uint64 System::getMaxFD()
+{
+ return Platform::System::getMaxFD();
+}
+
+}
diff --git a/dep/efsw/src/efsw/System.hpp b/dep/efsw/src/efsw/System.hpp
new file mode 100644
index 00000000000..1d6f4a70f91
--- /dev/null
+++ b/dep/efsw/src/efsw/System.hpp
@@ -0,0 +1,26 @@
+#ifndef EFSW_SYSTEM_HPP
+#define EFSW_SYSTEM_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+class System
+{
+ public:
+ /// Sleep for x milliseconds
+ static void sleep( const unsigned long& ms );
+
+ /// @return The process binary path
+ static std::string getProcessPath();
+
+ /// Maximize the number of file descriptors allowed per process in the current OS
+ static void maxFD();
+
+ /// @return The number of supported file descriptors for the process
+ static Uint64 getMaxFD();
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/Thread.cpp b/dep/efsw/src/efsw/Thread.cpp
new file mode 100644
index 00000000000..fff41517dc1
--- /dev/null
+++ b/dep/efsw/src/efsw/Thread.cpp
@@ -0,0 +1,51 @@
+#include <efsw/Thread.hpp>
+#include <efsw/platform/platformimpl.hpp>
+
+namespace efsw {
+
+Thread::Thread() :
+ mThreadImpl(NULL),
+ mEntryPoint(NULL)
+{
+}
+
+Thread::~Thread()
+{
+ wait();
+
+ efSAFE_DELETE( mEntryPoint );
+}
+
+void Thread::launch()
+{
+ wait();
+
+ mThreadImpl = new Platform::ThreadImpl( this );
+}
+
+void Thread::wait()
+{
+ if ( mThreadImpl )
+ {
+ mThreadImpl->wait();
+
+ efSAFE_DELETE( mThreadImpl );
+ }
+}
+
+void Thread::terminate()
+{
+ if ( mThreadImpl )
+ {
+ mThreadImpl->terminate();
+
+ efSAFE_DELETE( mThreadImpl );
+ }
+}
+
+void Thread::run()
+{
+ mEntryPoint->run();
+}
+
+}
diff --git a/dep/efsw/src/efsw/Thread.hpp b/dep/efsw/src/efsw/Thread.hpp
new file mode 100644
index 00000000000..c7da9e8b33c
--- /dev/null
+++ b/dep/efsw/src/efsw/Thread.hpp
@@ -0,0 +1,111 @@
+#ifndef EFSW_THREAD_HPP
+#define EFSW_THREAD_HPP
+
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+namespace Platform { class ThreadImpl; }
+namespace Private { struct ThreadFunc; }
+
+/** @brief Thread manager class */
+class Thread {
+ public:
+ typedef void (*FuncType)(void*);
+
+ template <typename F>
+ Thread( F function );
+
+ template <typename F, typename A>
+ Thread( F function, A argument );
+
+ template <typename C>
+ Thread( void(C::*function)(), C* object );
+
+ virtual ~Thread();
+
+ /** Launch the thread */
+ virtual void launch();
+
+ /** Wait the thread until end */
+ void wait();
+
+ /** Terminate the thread */
+ void terminate();
+ protected:
+ Thread();
+ private:
+ friend class Platform::ThreadImpl;
+
+ /** The virtual function to run in the thread */
+ virtual void run();
+
+ Platform::ThreadImpl * mThreadImpl; ///< OS-specific implementation of the thread
+ Private::ThreadFunc * mEntryPoint; ///< Abstraction of the function to run
+};
+
+//! NOTE: Taken from SFML2 threads
+namespace Private {
+
+// Base class for abstract thread functions
+struct ThreadFunc
+{
+ virtual ~ThreadFunc() {}
+ virtual void run() = 0;
+};
+
+// Specialization using a functor (including free functions) with no argument
+template <typename T>
+struct ThreadFunctor : ThreadFunc
+{
+ ThreadFunctor(T functor) : m_functor(functor) {}
+ virtual void run() {m_functor();}
+ T m_functor;
+};
+
+// Specialization using a functor (including free functions) with one argument
+template <typename F, typename A>
+struct ThreadFunctorWithArg : ThreadFunc
+{
+ ThreadFunctorWithArg(F function, A arg) : m_function(function), m_arg(arg) {}
+ virtual void run() {m_function(m_arg);}
+ F m_function;
+ A m_arg;
+};
+
+// Specialization using a member function
+template <typename C>
+struct ThreadMemberFunc : ThreadFunc
+{
+ ThreadMemberFunc(void(C::*function)(), C* object) : m_function(function), m_object(object) {}
+ virtual void run() {(m_object->*m_function)();}
+ void(C::*m_function)();
+ C* m_object;
+};
+
+}
+
+template <typename F>
+Thread::Thread(F functor) :
+ mThreadImpl (NULL),
+ mEntryPoint( new Private::ThreadFunctor<F>(functor) )
+{
+}
+
+template <typename F, typename A>
+Thread::Thread(F function, A argument) :
+ mThreadImpl(NULL),
+ mEntryPoint( new Private::ThreadFunctorWithArg<F efCOMMA A>(function, argument) )
+{
+}
+
+template <typename C>
+Thread::Thread(void(C::*function)(), C* object) :
+ mThreadImpl(NULL),
+ mEntryPoint( new Private::ThreadMemberFunc<C>(function, object) )
+{
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/Utf.hpp b/dep/efsw/src/efsw/Utf.hpp
new file mode 100644
index 00000000000..925a7cc149b
--- /dev/null
+++ b/dep/efsw/src/efsw/Utf.hpp
@@ -0,0 +1,748 @@
+/** NOTE:
+* This code is based on the Utf implementation from SFML2. License zlib/png ( http://www.sfml-dev.org/license.php )
+* The class was modified to fit efsw own needs. This is not the original implementation from SFML2.
+* */
+
+#ifndef EFSW_UTF_HPP
+#define EFSW_UTF_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <locale>
+#include <string>
+#include <cstdlib>
+#include <efsw/base.hpp>
+
+namespace efsw {
+
+template <unsigned int N>
+class Utf;
+
+////////////////////////////////////////////////////////////
+/// \brief Specialization of the Utf template for UTF-8
+///
+////////////////////////////////////////////////////////////
+template <>
+class Utf<8> {
+public :
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single UTF-8 character
+ ///
+ /// Decoding a character means finding its unique 32-bits
+ /// code (called the codepoint) in the Unicode standard.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Codepoint of the decoded UTF-8 character
+ /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-8 character
+ ///
+ /// Encoding a character means converting a unique 32-bits
+ /// code (called the codepoint) in the target encoding, UTF-8.
+ ///
+ /// \param input Codepoint to encode as UTF-8
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out Encode(Uint32 input, Out output, Uint8 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Advance to the next UTF-8 character
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Next(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Count the number of characters of a UTF-8 sequence
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element, thus the
+ /// total size can be different from (begin - end).
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static std::size_t Count(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an ANSI characters range to UTF-8
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a wide characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromWide(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromLatin1(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-8 characters range to ANSI characters
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-8 characters range to wide characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0);
+#endif
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToLatin1(In begin, In end, Out output, char replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-8 characters range to UTF-8
+ ///
+ /// This functions does nothing more than a direct copy;
+ /// it is defined only to provide the same interface as other
+ /// specializations of the efsw::Utf<> template, and allow
+ /// generic code to be written on top of it.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out toUtf8(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-8 characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf16(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-8 characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf32(In begin, In end, Out output);
+};
+
+////////////////////////////////////////////////////////////
+/// \brief Specialization of the Utf template for UTF-16
+///
+////////////////////////////////////////////////////////////
+template <>
+class Utf<16>
+{
+public :
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single UTF-16 character
+ ///
+ /// Decoding a character means finding its unique 32-bits
+ /// code (called the codepoint) in the Unicode standard.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Codepoint of the decoded UTF-16 character
+ /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-16 character
+ ///
+ /// Encoding a character means converting a unique 32-bits
+ /// code (called the codepoint) in the target encoding, UTF-16.
+ ///
+ /// \param input Codepoint to encode as UTF-16
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out Encode(Uint32 input, Out output, Uint16 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Advance to the next UTF-16 character
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Next(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Count the number of characters of a UTF-16 sequence
+ ///
+ /// This function is necessary for multi-elements encodings, as
+ /// a single character may use more than 1 storage element, thus the
+ /// total size can be different from (begin - end).
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static std::size_t Count(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an ANSI characters range to UTF-16
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a wide characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromWide(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromLatin1(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to ANSI characters
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to wide characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0);
+#endif
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToLatin1(In begin, In end, Out output, char replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-16 characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out toUtf8(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-16 characters range to UTF-16
+ ///
+ /// This functions does nothing more than a direct copy;
+ /// it is defined only to provide the same interface as other
+ /// specializations of the efsw::Utf<> template, and allow
+ /// generic code to be written on top of it.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf16(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-16 characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf32(In begin, In end, Out output);
+};
+
+////////////////////////////////////////////////////////////
+/// \brief Specialization of the Utf template for UTF-32
+///
+////////////////////////////////////////////////////////////
+template <>
+class Utf<32>
+{
+public :
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single UTF-32 character
+ ///
+ /// Decoding a character means finding its unique 32-bits
+ /// code (called the codepoint) in the Unicode standard.
+ /// For UTF-32, the character value is the same as the codepoint.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Codepoint of the decoded UTF-32 character
+ /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-32 character
+ ///
+ /// Encoding a character means converting a unique 32-bits
+ /// code (called the codepoint) in the target encoding, UTF-32.
+ /// For UTF-32, the codepoint is the same as the character value.
+ ///
+ /// \param input Codepoint to encode as UTF-32
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out Encode(Uint32 input, Out output, Uint32 replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Advance to the next UTF-32 character
+ ///
+ /// This function is trivial for UTF-32, which can store
+ /// every character in a single storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static In Next(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Count the number of characters of a UTF-32 sequence
+ ///
+ /// This function is trivial for UTF-32, which can store
+ /// every character in a single storage element.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ ///
+ /// \return Iterator pointing to one past the last read element of the input sequence
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static std::size_t Count(In begin, In end);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an ANSI characters range to UTF-32
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a wide characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromWide(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out FromLatin1(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-32 characters range to ANSI characters
+ ///
+ /// The current global locale will be used by default, unless you
+ /// pass a custom one in the \a locale parameter.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-32 characters range to wide characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToWide(In begin, In end, Out output, wchar_t replacement = 0);
+#endif
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToLatin1(In begin, In end, Out output, char replacement = 0);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-32 characters range to UTF-8
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out toUtf8(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-32 characters range to UTF-16
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf16(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a UTF-32 characters range to UTF-32
+ ///
+ /// This functions does nothing more than a direct copy;
+ /// it is defined only to provide the same interface as other
+ /// specializations of the efsw::Utf<> template, and allow
+ /// generic code to be written on top of it.
+ ///
+ /// \param begin Iterator pointing to the beginning of the input sequence
+ /// \param end Iterator pointing to the end of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In, typename Out>
+ static Out ToUtf32(In begin, In end, Out output);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single ANSI character to UTF-32
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param input Input ANSI character
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Converted character
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static Uint32 DecodeAnsi(In input, const std::locale& locale = std::locale());
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Decode a single wide character to UTF-32
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param input Input wide character
+ ///
+ /// \return Converted character
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename In>
+ static Uint32 DecodeWide(In input);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-32 character to ANSI
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param codepoint Iterator pointing to the beginning of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to skip it)
+ /// \param locale Locale to use for conversion
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out EncodeAnsi(Uint32 codepoint, Out output, char replacement = 0, const std::locale& locale = std::locale());
+
+#ifndef EFSW_NO_WIDECHAR
+ ////////////////////////////////////////////////////////////
+ /// \brief Encode a single UTF-32 character to wide
+ ///
+ /// This function does not exist in other specializations
+ /// of efsw::Utf<>, it is defined for convenience (it is used by
+ /// several other conversion functions).
+ ///
+ /// \param codepoint Iterator pointing to the beginning of the input sequence
+ /// \param output Iterator pointing to the beginning of the output sequence
+ /// \param replacement Replacement if the input character is not convertible to wide (use 0 to skip it)
+ ///
+ /// \return Iterator to the end of the output sequence which has been written
+ ///
+ ////////////////////////////////////////////////////////////
+ template <typename Out>
+ static Out EncodeWide(Uint32 codepoint, Out output, wchar_t replacement = 0);
+#endif
+};
+
+#include "Utf.inl"
+
+// Make typedefs to get rid of the template syntax
+typedef Utf<8> Utf8;
+typedef Utf<16> Utf16;
+typedef Utf<32> Utf32;
+
+}
+#endif
+
+////////////////////////////////////////////////////////////
+/// \class efsw::Utf
+/// \ingroup system
+///
+/// Utility class providing generic functions for UTF conversions.
+///
+/// efsw::Utf is a low-level, generic interface for counting, iterating,
+/// encoding and decoding Unicode characters and strings. It is able
+/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings.
+///
+/// efsw::Utf<X> functions are all static, these classes are not meant to
+/// be instanciated. All the functions are template, so that you
+/// can use any character / string type for a given encoding.
+///
+/// It has 3 specializations:
+/// \li efsw::Utf<8> (typedef'd to efsw::Utf8)
+/// \li efsw::Utf<16> (typedef'd to efsw::Utf16)
+/// \li efsw::Utf<32> (typedef'd to efsw::Utf32)
+///
+////////////////////////////////////////////////////////////
diff --git a/dep/efsw/src/efsw/Utf.inl b/dep/efsw/src/efsw/Utf.inl
new file mode 100644
index 00000000000..db8fd5d61ee
--- /dev/null
+++ b/dep/efsw/src/efsw/Utf.inl
@@ -0,0 +1,671 @@
+// References :
+// http://www.unicode.org/
+// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
+// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h
+// http://people.w3.org/rishida/scripts/uniview/conversion
+////////////////////////////////////////////////////////////
+
+template <typename In>
+In Utf<8>::Decode(In begin, In end, Uint32& output, Uint32 replacement)
+{
+ // Some useful precomputed data
+ static const int trailing[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+ };
+ static const Uint32 offsets[6] =
+ {
+ 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080
+ };
+
+ // Decode the character
+ int trailingBytes = trailing[static_cast<Uint8>(*begin)];
+ if (begin + trailingBytes < end)
+ {
+ output = 0;
+ switch (trailingBytes)
+ {
+ case 5 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 4 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 3 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 2 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 1 : output += static_cast<Uint8>(*begin++); output <<= 6;
+ case 0 : output += static_cast<Uint8>(*begin++);
+ }
+ output -= offsets[trailingBytes];
+ }
+ else
+ {
+ // Incomplete character
+ begin = end;
+ output = replacement;
+ }
+
+ return begin;
+}
+
+template <typename Out>
+Out Utf<8>::Encode(Uint32 input, Out output, Uint8 replacement)
+{
+ // Some useful precomputed data
+ static const Uint8 firstBytes[7] =
+ {
+ 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
+ };
+
+ // Encode the character
+ if ((input > 0x0010FFFF) || ((input >= 0xD800) && (input <= 0xDBFF)))
+ {
+ // Invalid character
+ if (replacement)
+ *output++ = replacement;
+ }
+ else
+ {
+ // Valid character
+
+ // Get the number of bytes to write
+ int bytesToWrite = 1;
+ if (input < 0x80) bytesToWrite = 1;
+ else if (input < 0x800) bytesToWrite = 2;
+ else if (input < 0x10000) bytesToWrite = 3;
+ else if (input <= 0x0010FFFF) bytesToWrite = 4;
+
+ // Extract the bytes to write
+ Uint8 bytes[4];
+ switch (bytesToWrite)
+ {
+ case 4 : bytes[3] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 3 : bytes[2] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 2 : bytes[1] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
+ case 1 : bytes[0] = static_cast<Uint8> (input | firstBytes[bytesToWrite]);
+ }
+
+ // Add them to the output
+ const Uint8* currentByte = bytes;
+ switch (bytesToWrite)
+ {
+ case 4 : *output++ = *currentByte++;
+ case 3 : *output++ = *currentByte++;
+ case 2 : *output++ = *currentByte++;
+ case 1 : *output++ = *currentByte++;
+ }
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<8>::Next(In begin, In end)
+{
+ Uint32 codepoint;
+ return Decode(begin, end, codepoint);
+}
+
+template <typename In>
+std::size_t Utf<8>::Count(In begin, In end)
+{
+ std::size_t length = 0;
+ while (begin < end)
+ {
+ begin = Next(begin, end);
+ ++length;
+ }
+
+ return length;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::FromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeAnsi(*begin++, locale);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::FromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeWide(*begin++);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::FromLatin1(In begin, In end, Out output)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ output = Encode(*begin++, output);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeAnsi(codepoint, output, replacement, locale);
+ }
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename In, typename Out>
+Out Utf<8>::ToWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeWide(codepoint, output, replacement);
+ }
+
+ return output;
+}
+#endif
+
+template <typename In, typename Out>
+Out Utf<8>::ToLatin1(In begin, In end, Out output, char replacement)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ *output++ = codepoint < 256 ? static_cast<char>(codepoint) : replacement;
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::ToUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<16>::Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<8>::ToUtf32(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ *output++ = codepoint;
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<16>::Decode(In begin, In end, Uint32& output, Uint32 replacement)
+{
+ Uint16 first = *begin++;
+
+ // If it's a surrogate pair, first convert to a single UTF-32 character
+ if ((first >= 0xD800) && (first <= 0xDBFF))
+ {
+ if (begin < end)
+ {
+ Uint32 second = *begin++;
+ if ((second >= 0xDC00) && (second <= 0xDFFF))
+ {
+ // The second element is valid: convert the two elements to a UTF-32 character
+ output = static_cast<Uint32>(((first - 0xD800) << 10) + (second - 0xDC00) + 0x0010000);
+ }
+ else
+ {
+ // Invalid character
+ output = replacement;
+ }
+ }
+ else
+ {
+ // Invalid character
+ begin = end;
+ output = replacement;
+ }
+ }
+ else
+ {
+ // We can make a direct copy
+ output = first;
+ }
+
+ return begin;
+}
+
+template <typename Out>
+Out Utf<16>::Encode(Uint32 input, Out output, Uint16 replacement)
+{
+ if (input < 0xFFFF)
+ {
+ // The character can be copied directly, we just need to check if it's in the valid range
+ if ((input >= 0xD800) && (input <= 0xDFFF))
+ {
+ // Invalid character (this range is reserved)
+ if (replacement)
+ *output++ = replacement;
+ }
+ else
+ {
+ // Valid character directly convertible to a single UTF-16 character
+ *output++ = static_cast<Uint16>(input);
+ }
+ }
+ else if (input > 0x0010FFFF)
+ {
+ // Invalid character (greater than the maximum unicode value)
+ if (replacement)
+ *output++ = replacement;
+ }
+ else
+ {
+ // The input character will be converted to two UTF-16 elements
+ input -= 0x0010000;
+ *output++ = static_cast<Uint16>((input >> 10) + 0xD800);
+ *output++ = static_cast<Uint16>((input & 0x3FFUL) + 0xDC00);
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<16>::Next(In begin, In end)
+{
+ Uint32 codepoint;
+ return Decode(begin, end, codepoint);
+}
+
+template <typename In>
+std::size_t Utf<16>::Count(In begin, In end)
+{
+ std::size_t length = 0;
+ while (begin < end)
+ {
+ begin = Next(begin, end);
+ ++length;
+ }
+
+ return length;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::FromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeAnsi(*begin++, locale);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::FromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint = Utf<32>::DecodeWide(*begin++);
+ output = Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::FromLatin1(In begin, In end, Out output)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeAnsi(codepoint, output, replacement, locale);
+ }
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename In, typename Out>
+Out Utf<16>::ToWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<32>::EncodeWide(codepoint, output, replacement);
+ }
+
+ return output;
+}
+#endif
+
+template <typename In, typename Out>
+Out Utf<16>::ToLatin1(In begin, In end, Out output, char replacement)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ {
+ *output++ = *begin < 256 ? static_cast<char>(*begin) : replacement;
+ begin++;
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ output = Utf<8>::Encode(codepoint, output);
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::ToUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<16>::ToUtf32(In begin, In end, Out output)
+{
+ while (begin < end)
+ {
+ Uint32 codepoint;
+ begin = Decode(begin, end, codepoint);
+ *output++ = codepoint;
+ }
+
+ return output;
+}
+
+template <typename In>
+In Utf<32>::Decode(In begin, In end, Uint32& output, Uint32)
+{
+ output = *begin++;
+ return begin;
+}
+
+template <typename Out>
+Out Utf<32>::Encode(Uint32 input, Out output, Uint32 replacement)
+{
+ *output++ = input;
+ return output;
+}
+
+template <typename In>
+In Utf<32>::Next(In begin, In end)
+{
+ return ++begin;
+}
+
+template <typename In>
+std::size_t Utf<32>::Count(In begin, In end)
+{
+ return begin - end;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::FromAnsi(In begin, In end, Out output, const std::locale& locale)
+{
+ while (begin < end)
+ *output++ = DecodeAnsi(*begin++, locale);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::FromWide(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = DecodeWide(*begin++);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::FromLatin1(In begin, In end, Out output)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::ToAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
+{
+ while (begin < end)
+ output = EncodeAnsi(*begin++, output, replacement, locale);
+
+ return output;
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename In, typename Out>
+Out Utf<32>::ToWide(In begin, In end, Out output, wchar_t replacement)
+{
+ while (begin < end)
+ output = EncodeWide(*begin++, output, replacement);
+
+ return output;
+}
+#endif
+
+template <typename In, typename Out>
+Out Utf<32>::ToLatin1(In begin, In end, Out output, char replacement)
+{
+ // Latin-1 is directly compatible with Unicode encodings,
+ // and can thus be treated as (a sub-range of) UTF-32
+ while (begin < end)
+ {
+ *output++ = *begin < 256 ? static_cast<char>(*begin) : replacement;
+ begin++;
+ }
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::toUtf8(In begin, In end, Out output)
+{
+ while (begin < end)
+ output = Utf<8>::Encode(*begin++, output);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::ToUtf16(In begin, In end, Out output)
+{
+ while (begin < end)
+ output = Utf<16>::Encode(*begin++, output);
+
+ return output;
+}
+
+template <typename In, typename Out>
+Out Utf<32>::ToUtf32(In begin, In end, Out output)
+{
+ while (begin < end)
+ *output++ = *begin++;
+
+ return output;
+}
+
+template <typename In>
+Uint32 Utf<32>::DecodeAnsi(In input, const std::locale& locale)
+{
+ // On Windows, gcc's standard library (glibc++) has almost
+ // no support for Unicode stuff. As a consequence, in this
+ // context we can only use the default locale and ignore
+ // the one passed as parameter.
+
+ #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \
+ (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \
+ !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */
+
+ wchar_t character = 0;
+ mbtowc(&character, &input, 1);
+ return static_cast<Uint32>(character);
+
+ #else
+ // Get the facet of the locale which deals with character conversion
+ #ifndef EFSW_NO_WIDECHAR
+ const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
+ #else
+ const std::ctype<char>& facet = std::use_facet< std::ctype<char> >(locale);
+ #endif
+
+ // Use the facet to convert each character of the input string
+ return static_cast<Uint32>(facet.widen(input));
+
+ #endif
+}
+
+template <typename In>
+Uint32 Utf<32>::DecodeWide(In input)
+{
+ // The encoding of wide characters is not well defined and is left to the system;
+ // however we can safely assume that it is UCS-2 on Windows and
+ // UCS-4 on Unix systems.
+ // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4,
+ // and UCS-4 *is* UTF-32).
+
+ return input;
+}
+
+template <typename Out>
+Out Utf<32>::EncodeAnsi(Uint32 codepoint, Out output, char replacement, const std::locale& locale)
+{
+ // On Windows, gcc's standard library (glibc++) has almost
+ // no support for Unicode stuff. As a consequence, in this
+ // context we can only use the default locale and ignore
+ // the one passed as parameter.
+
+ #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \
+ (defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \
+ !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */
+
+ char character = 0;
+ if (wctomb(&character, static_cast<wchar_t>(codepoint)) >= 0)
+ *output++ = character;
+ else if (replacement)
+ *output++ = replacement;
+
+ return output;
+
+ #else
+ // Get the facet of the locale which deals with character conversion
+ #ifndef EFSW_NO_WIDECHAR
+ const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
+ #else
+ const std::ctype<char>& facet = std::use_facet< std::ctype<char> >(locale);
+ #endif
+
+ // Use the facet to convert each character of the input string
+ *output++ = facet.narrow(static_cast<wchar_t>(codepoint), replacement);
+
+ return output;
+
+ #endif
+}
+
+#ifndef EFSW_NO_WIDECHAR
+template <typename Out>
+Out Utf<32>::EncodeWide(Uint32 codepoint, Out output, wchar_t replacement)
+{
+ // The encoding of wide characters is not well defined and is left to the system;
+ // however we can safely assume that it is UCS-2 on Windows and
+ // UCS-4 on Unix systems.
+ // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4).
+ // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32).
+
+ switch (sizeof(wchar_t))
+ {
+ case 4:
+ {
+ *output++ = static_cast<wchar_t>(codepoint);
+ break;
+ }
+
+ default:
+ {
+ if ((codepoint <= 0xFFFF) && ((codepoint < 0xD800) || (codepoint > 0xDFFF)))
+ {
+ *output++ = static_cast<wchar_t>(codepoint);
+ }
+ else if (replacement)
+ {
+ *output++ = replacement;
+ }
+ break;
+ }
+ }
+
+ return output;
+}
+#endif
diff --git a/dep/efsw/src/efsw/Watcher.cpp b/dep/efsw/src/efsw/Watcher.cpp
new file mode 100644
index 00000000000..d81c84228ad
--- /dev/null
+++ b/dep/efsw/src/efsw/Watcher.cpp
@@ -0,0 +1,21 @@
+#include <efsw/Watcher.hpp>
+
+namespace efsw {
+
+Watcher::Watcher() :
+ ID(0),
+ Directory(""),
+ Listener(NULL),
+ Recursive(false)
+{
+}
+
+Watcher::Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ) :
+ ID( id ),
+ Directory( directory ),
+ Listener( listener ),
+ Recursive( recursive )
+{
+}
+
+}
diff --git a/dep/efsw/src/efsw/Watcher.hpp b/dep/efsw/src/efsw/Watcher.hpp
new file mode 100644
index 00000000000..5a35cb9a2ac
--- /dev/null
+++ b/dep/efsw/src/efsw/Watcher.hpp
@@ -0,0 +1,30 @@
+#ifndef EFSW_WATCHERIMPL_HPP
+#define EFSW_WATCHERIMPL_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/efsw.hpp>
+
+namespace efsw {
+
+/** @brief Base Watcher class */
+class Watcher
+{
+ public:
+ Watcher();
+
+ Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive );
+
+ virtual ~Watcher() {}
+
+ virtual void watch() {}
+
+ WatchID ID;
+ std::string Directory;
+ FileWatchListener * Listener;
+ bool Recursive;
+ std::string OldFileName;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherFSEvents.cpp b/dep/efsw/src/efsw/WatcherFSEvents.cpp
new file mode 100644
index 00000000000..3a9700c77ec
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherFSEvents.cpp
@@ -0,0 +1,264 @@
+#include <efsw/WatcherFSEvents.hpp>
+#include <efsw/FileWatcherFSEvents.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/Debug.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+namespace efsw {
+
+WatcherFSEvents::WatcherFSEvents() :
+ Watcher(),
+ FWatcher( NULL ),
+ FSStream( NULL ),
+ WatcherGen( NULL ),
+ initializedAsync( false )
+{
+}
+
+WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent ) :
+ Watcher( id, directory, listener, recursive ),
+ FWatcher( NULL ),
+ FSStream( NULL ),
+ WatcherGen( NULL ),
+ initializedAsync( false )
+{
+}
+
+WatcherFSEvents::~WatcherFSEvents()
+{
+ if ( initializedAsync )
+ {
+ FSEventStreamStop( FSStream );
+ FSEventStreamInvalidate( FSStream );
+ }
+
+ if ( NULL != FSStream )
+ {
+ FSEventStreamRelease( FSStream );
+ }
+
+ efSAFE_DELETE( WatcherGen );
+}
+
+void WatcherFSEvents::init()
+{
+ CFStringRef CFDirectory = CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 );
+ CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void **)&CFDirectory, 1, NULL );
+
+ Uint32 streamFlags = kFSEventStreamCreateFlagNone;
+
+ if ( FileWatcherFSEvents::isGranular() )
+ {
+ streamFlags = efswFSEventStreamCreateFlagFileEvents;
+ }
+ else
+ {
+ WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher, Recursive );
+ }
+
+ FSEventStreamContext ctx;
+ /* Initialize context */
+ ctx.version = 0;
+ ctx.info = this;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+
+ FSStream = FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags );
+
+ FWatcher->mNeedInit.push_back( this );
+
+ CFRelease( CFDirectoryArray );
+ CFRelease( CFDirectory );
+}
+
+void WatcherFSEvents::initAsync()
+{
+ FSEventStreamScheduleWithRunLoop( FSStream, FWatcher->mRunLoopRef, kCFRunLoopDefaultMode );
+ FSEventStreamStart( FSStream );
+ initializedAsync = true;
+}
+
+void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename )
+{
+ Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), FileSystem::precomposeFileName( filename ), action, oldFilename );
+}
+
+void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, std::string& filePath )
+{
+ if ( flags & efswFSEventStreamEventFlagItemCreated )
+ {
+ if ( FileInfo::exists( path ) )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Add );
+ }
+ }
+
+ if ( flags & efswFSEventsModified )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Modified );
+ }
+
+ if ( flags & efswFSEventStreamEventFlagItemRemoved )
+ {
+ // Since i don't know the order, at least i try to keep the data consistent with the real state
+ if ( !FileInfo::exists( path ) )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Delete );
+ }
+ }
+}
+
+void WatcherFSEvents::handleActions( std::vector<FSEvent>& events )
+{
+ size_t esize = events.size();
+
+ for ( size_t i = 0; i < esize; i++ )
+ {
+ FSEvent& event = events[i];
+
+ if ( event.Flags & ( kFSEventStreamEventFlagUserDropped |
+ kFSEventStreamEventFlagKernelDropped |
+ kFSEventStreamEventFlagEventIdsWrapped |
+ kFSEventStreamEventFlagHistoryDone |
+ kFSEventStreamEventFlagMount |
+ kFSEventStreamEventFlagUnmount |
+ kFSEventStreamEventFlagRootChanged ) )
+ {
+ continue;
+ }
+
+ if ( !Recursive )
+ {
+ /** In case that is not recursive the watcher, ignore the events from subfolders */
+ if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 )
+ {
+ continue;
+ }
+ }
+
+ if ( FileWatcherFSEvents::isGranular() )
+ {
+ std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) );
+ std::string filePath( FileSystem::fileNameFromPath( event.Path ) );
+
+ if ( event.Flags & ( efswFSEventStreamEventFlagItemCreated |
+ efswFSEventStreamEventFlagItemRemoved |
+ efswFSEventStreamEventFlagItemRenamed )
+ )
+ {
+ if ( dirPath != Directory )
+ {
+ DirsChanged.insert( dirPath );
+ }
+ }
+
+ // This is a mess. But it's FSEvents faults, because shrinks events from the same file in one single event ( so there's no order for them )
+ // For example a file could have been added modified and erased, but i can't know if first was erased and then added and modified, or added, then modified and then erased.
+ // I don't know what they were thinking by doing this...
+ efDEBUG( "Event in: %s - flags: %ld\n", path.c_str(), event.Flags );
+
+ if ( event.Flags & efswFSEventStreamEventFlagItemRenamed )
+ {
+ if ( ( i + 1 < esize ) &&
+ ( events[ i + 1 ].Flags & efswFSEventStreamEventFlagItemRenamed ) &&
+ ( events[ i + 1 ].Id == event.Id + 1 )
+ )
+ {
+ FSEvent& nEvent = events[ i + 1 ];
+ std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) );
+ std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) );
+
+ if ( event.Path != nEvent.Path )
+ {
+ if ( dirPath == newDir )
+ {
+ if ( !FileInfo::exists( event.Path ) )
+ {
+ sendFileAction( ID, dirPath, newFilepath, Actions::Moved, filePath );
+ }
+ else
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Moved, newFilepath );
+ }
+ }
+ else
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Delete );
+ sendFileAction( ID, newDir, newFilepath, Actions::Add );
+
+ if ( nEvent.Flags & efswFSEventsModified )
+ {
+ sendFileAction( ID, newDir, newFilepath, Actions::Modified );
+ }
+ }
+ }
+ else
+ {
+ handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath );
+ }
+
+ if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated |
+ efswFSEventStreamEventFlagItemRemoved |
+ efswFSEventStreamEventFlagItemRenamed )
+ )
+ {
+ if ( newDir != Directory )
+ {
+ DirsChanged.insert( newDir );
+ }
+ }
+
+ // Skip the renamed file
+ i++;
+ }
+ else if ( FileInfo::exists( event.Path ) )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Add );
+
+ if ( event.Flags & efswFSEventsModified )
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Modified );
+ }
+ }
+ else
+ {
+ sendFileAction( ID, dirPath, filePath, Actions::Delete );
+ }
+ }
+ else
+ {
+ handleAddModDel( event.Flags, event.Path, dirPath, filePath );
+ }
+ }
+ else
+ {
+ efDEBUG( "Directory: %s changed\n", event.Path.c_str() );
+ DirsChanged.insert( event.Path );
+ }
+ }
+}
+
+void WatcherFSEvents::process()
+{
+ std::set<std::string>::iterator it = DirsChanged.begin();
+
+ for ( ; it != DirsChanged.end(); it++ )
+ {
+ if ( !FileWatcherFSEvents::isGranular() )
+ {
+ WatcherGen->watchDir( (*it) );
+ }
+ else
+ {
+ sendFileAction( ID, FileSystem::pathRemoveFileName( (*it) ), FileSystem::fileNameFromPath( (*it) ), Actions::Modified );
+ }
+ }
+
+ DirsChanged.clear();
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherFSEvents.hpp b/dep/efsw/src/efsw/WatcherFSEvents.hpp
new file mode 100644
index 00000000000..d4fc5c9a8d3
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherFSEvents.hpp
@@ -0,0 +1,70 @@
+#ifndef EFSW_WATCHERINOTIFY_HPP
+#define EFSW_WATCHERINOTIFY_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileInfo.hpp>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <set>
+#include <vector>
+
+namespace efsw {
+
+class FileWatcherFSEvents;
+
+class FSEvent
+{
+ public:
+ FSEvent( std::string path, long flags, Uint64 id ) :
+ Path( path ),
+ Flags( flags ),
+ Id ( id )
+ {
+ }
+
+ std::string Path;
+ long Flags;
+ Uint64 Id;
+};
+
+class WatcherFSEvents : public Watcher
+{
+ public:
+ WatcherFSEvents();
+
+ WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent = NULL );
+
+ ~WatcherFSEvents();
+
+ void init();
+
+ void initAsync();
+
+ void handleActions( std::vector<FSEvent> & events );
+
+ void process();
+
+ FileWatcherFSEvents * FWatcher;
+
+ FSEventStreamRef FSStream;
+ protected:
+ void handleAddModDel( const Uint32 &flags, const std::string &path, std::string &dirPath, std::string &filePath );
+
+ WatcherGeneric * WatcherGen;
+
+ bool initializedAsync;
+
+ std::set<std::string> DirsChanged;
+
+ void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" );
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherGeneric.cpp b/dep/efsw/src/efsw/WatcherGeneric.cpp
new file mode 100644
index 00000000000..94170d3ce87
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherGeneric.cpp
@@ -0,0 +1,40 @@
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/DirWatcherGeneric.hpp>
+
+namespace efsw
+{
+
+WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ) :
+ Watcher( id, directory, fwl, recursive ),
+ WatcherImpl( fw ),
+ DirWatch( NULL )
+{
+ FileSystem::dirAddSlashAtEnd( Directory );
+
+ DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false );
+
+ DirWatch->addChilds( false );
+}
+
+WatcherGeneric::~WatcherGeneric()
+{
+ efSAFE_DELETE( DirWatch );
+}
+
+void WatcherGeneric::watch()
+{
+ DirWatch->watch();
+}
+
+void WatcherGeneric::watchDir( std::string dir )
+{
+ DirWatch->watchDir( dir );
+}
+
+bool WatcherGeneric::pathInWatches( std::string path )
+{
+ return DirWatch->pathInWatches( path );
+}
+
+}
diff --git a/dep/efsw/src/efsw/WatcherGeneric.hpp b/dep/efsw/src/efsw/WatcherGeneric.hpp
new file mode 100644
index 00000000000..8794e921b40
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherGeneric.hpp
@@ -0,0 +1,30 @@
+#ifndef EFSW_WATCHERGENERIC_HPP
+#define EFSW_WATCHERGENERIC_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+namespace efsw
+{
+
+class DirWatcherGeneric;
+
+class WatcherGeneric : public Watcher
+{
+ public:
+ FileWatcherImpl * WatcherImpl;
+ DirWatcherGeneric * DirWatch;
+
+ WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive );
+
+ ~WatcherGeneric();
+
+ void watch();
+
+ void watchDir( std::string dir );
+
+ bool pathInWatches( std::string path );
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherInotify.cpp b/dep/efsw/src/efsw/WatcherInotify.cpp
new file mode 100644
index 00000000000..741641bf43c
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherInotify.cpp
@@ -0,0 +1,35 @@
+#include <efsw/WatcherInotify.hpp>
+
+namespace efsw {
+
+WatcherInotify::WatcherInotify() :
+ Watcher(),
+ Parent( NULL )
+{
+}
+
+WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent ) :
+ Watcher( id, directory, listener, recursive ),
+ Parent( parent ),
+ DirInfo( directory )
+{
+}
+
+bool WatcherInotify::inParentTree( WatcherInotify * parent )
+{
+ WatcherInotify * tNext = Parent;
+
+ while ( NULL != tNext )
+ {
+ if ( tNext == parent )
+ {
+ return true;
+ }
+
+ tNext = tNext->Parent;
+ }
+
+ return false;
+}
+
+}
diff --git a/dep/efsw/src/efsw/WatcherInotify.hpp b/dep/efsw/src/efsw/WatcherInotify.hpp
new file mode 100644
index 00000000000..1caf399679b
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherInotify.hpp
@@ -0,0 +1,25 @@
+#ifndef EFSW_WATCHERINOTIFY_HPP
+#define EFSW_WATCHERINOTIFY_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/FileInfo.hpp>
+
+namespace efsw {
+
+class WatcherInotify : public Watcher
+{
+ public:
+ WatcherInotify();
+
+ WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent = NULL );
+
+ bool inParentTree( WatcherInotify * parent );
+
+ WatcherInotify * Parent;
+
+ FileInfo DirInfo;
+};
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherKqueue.cpp b/dep/efsw/src/efsw/WatcherKqueue.cpp
new file mode 100644
index 00000000000..8347fb53439
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherKqueue.cpp
@@ -0,0 +1,667 @@
+#include <efsw/WatcherKqueue.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <efsw/Debug.hpp>
+#include <efsw/String.hpp>
+#include <efsw/System.hpp>
+#include <efsw/FileSystem.hpp>
+#include <efsw/WatcherGeneric.hpp>
+#include <efsw/FileWatcherKqueue.hpp>
+
+#define KEVENT_RESERVE_VALUE (10)
+
+#ifndef O_EVTONLY
+#define O_EVTONLY (O_RDONLY | O_NONBLOCK)
+#endif
+
+namespace efsw {
+
+int comparator(const void* ke1, const void* ke2)
+{
+ const KEvent * kev1 = reinterpret_cast<const KEvent*>( ke1 );
+ const KEvent * kev2 = reinterpret_cast<const KEvent*>( ke2 );
+
+ if ( NULL != kev2->udata )
+ {
+ FileInfo * fi1 = reinterpret_cast<FileInfo*>( kev1->udata );
+ FileInfo * fi2 = reinterpret_cast<FileInfo*>( kev2->udata );
+
+ return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() );
+ }
+
+ return 1;
+}
+
+WatcherKqueue::WatcherKqueue(WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent ) :
+ Watcher( watchid, dirname, listener, recursive ),
+ mLastWatchID(0),
+ mChangeListCount( 0 ),
+ mKqueue( kqueue() ),
+ mWatcher( watcher ),
+ mParent( parent ),
+ mInitOK( true ),
+ mErrno(0)
+{
+ if ( -1 == mKqueue )
+ {
+ efDEBUG( "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", Directory.c_str(), mWatcher->mFileDescriptorCount );
+
+ mInitOK = false;
+ mErrno = errno;
+ }
+ else
+ {
+ mWatcher->addFD();
+ }
+}
+
+WatcherKqueue::~WatcherKqueue()
+{
+ // Remove the childs watchers ( sub-folders watches )
+ removeAll();
+
+ for ( size_t i = 0; i < mChangeListCount; i++ )
+ {
+ if ( NULL != mChangeList[i].udata )
+ {
+ FileInfo * fi = reinterpret_cast<FileInfo*>( mChangeList[i].udata );
+
+ efSAFE_DELETE( fi );
+ }
+ }
+
+ close( mKqueue );
+
+ mWatcher->removeFD();
+}
+
+void WatcherKqueue::addAll()
+{
+ if ( -1 == mKqueue )
+ {
+ return;
+ }
+
+ // scan directory and call addFile(name, false) on each file
+ FileSystem::dirAddSlashAtEnd( Directory );
+
+ efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str());
+
+ // add base dir
+ int fd = open( Directory.c_str(), O_EVTONLY );
+
+ if ( -1 == fd )
+ {
+ efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() );
+
+ if ( EACCES != errno )
+ {
+ mInitOK = false;
+ }
+
+ mErrno = errno;
+
+ return;
+ }
+
+ mDirSnap.setDirectoryInfo( Directory );
+ mDirSnap.scan();
+
+ mChangeList.resize( KEVENT_RESERVE_VALUE );
+
+ // Creates the kevent for the folder
+ EV_SET(
+ &mChangeList[0],
+ fd,
+ EVFILT_VNODE,
+ EV_ADD | EV_ENABLE | EV_ONESHOT,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
+ 0,
+ 0
+ );
+
+ mWatcher->addFD();
+
+ // Get the files and directories from the directory
+ FileInfoMap files = FileSystem::filesInfoFromPath( Directory );
+
+ for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ )
+ {
+ FileInfo& fi = it->second;
+
+ if ( fi.isRegularFile() )
+ {
+ // Add the regular files kevent
+ addFile( fi.Filepath , false );
+ }
+ else if ( Recursive && fi.isDirectory() && fi.isReadable() )
+ {
+ // Create another watcher for the subfolders ( if recursive )
+ WatchID id = addWatch( fi.Filepath, Listener, Recursive, this );
+
+ // If the watcher is not adding the watcher means that the directory was created
+ if ( id > 0 && !mWatcher->isAddingWatcher() )
+ {
+ handleFolderAction( fi.Filepath, Actions::Add );
+ }
+ }
+ }
+}
+
+void WatcherKqueue::removeAll()
+{
+ efDEBUG( "removeAll(): Removing all child watchers\n" );
+
+ std::list<WatchID> erase;
+
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
+ {
+ efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() );
+
+ erase.push_back( it->second->ID );
+ }
+
+ for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ )
+ {
+ removeWatch( *eit );
+ }
+}
+
+void WatcherKqueue::addFile(const std::string& name, bool emitEvents)
+{
+ efDEBUG( "addFile(): Added: %s\n", name.c_str() );
+
+ // Open the file to get the file descriptor
+ int fd = open( name.c_str(), O_EVTONLY );
+
+ if( fd == -1 )
+ {
+ efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", name.c_str(), mWatcher->mFileDescriptorCount );
+
+ Errors::Log::createLastError( Errors::FileNotReadable, name );
+
+ if ( EACCES != errno )
+ {
+ mInitOK = false;
+ }
+
+ mErrno = errno;
+
+ return;
+ }
+
+ mWatcher->addFD();
+
+ // increase the file kevent file count
+ mChangeListCount++;
+
+ if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() &&
+ mChangeListCount % KEVENT_RESERVE_VALUE == 0 )
+ {
+ size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE;
+ mChangeList.resize( reserve_size );
+ efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual size %ld.\n", Directory.c_str(), reserve_size, mChangeListCount );
+ }
+
+ // create entry
+ FileInfo * entry = new FileInfo( name );
+
+ // set the event data at the end of the list
+ EV_SET(
+ &mChangeList[mChangeListCount],
+ fd,
+ EVFILT_VNODE,
+ EV_ADD | EV_ENABLE | EV_ONESHOT,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
+ 0,
+ (void*)entry
+ );
+
+ // qsort sort the list by name
+ qsort(&mChangeList[1], mChangeListCount, sizeof(KEvent), comparator);
+
+ // handle action
+ if( emitEvents )
+ {
+ handleAction(name, Actions::Add);
+ }
+}
+
+void WatcherKqueue::removeFile( const std::string& name, bool emitEvents )
+{
+ efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() );
+
+ // bsearch
+ KEvent target;
+
+ // Create a temporary file info to search the kevent ( searching the directory )
+ FileInfo tempEntry( name );
+
+ target.udata = &tempEntry;
+
+ // Search the kevent
+ KEvent * ke = (KEvent*)bsearch(&target, &mChangeList[0], mChangeListCount + 1, sizeof(KEvent), comparator);
+
+ // Trying to remove a non-existing file?
+ if( !ke )
+ {
+ Errors::Log::createLastError( Errors::FileNotFound, name );
+ efDEBUG( "File not removed\n" );
+ return;
+ }
+
+ efDEBUG( "File removed\n" );
+
+ // handle action
+ if ( emitEvents )
+ {
+ handleAction( name, Actions::Delete );
+ }
+
+ // Delete the user data ( FileInfo ) from the kevent closed
+ FileInfo * del = reinterpret_cast<FileInfo*>( ke->udata );
+
+ efSAFE_DELETE( del );
+
+ // close the file descriptor from the kevent
+ close( ke->ident );
+
+ mWatcher->removeFD();
+
+ memset(ke, 0, sizeof(KEvent));
+
+ // move end to current
+ memcpy(ke, &mChangeList[mChangeListCount], sizeof(KEvent));
+ memset(&mChangeList[mChangeListCount], 0, sizeof(KEvent));
+ --mChangeListCount;
+}
+
+void WatcherKqueue::rescan()
+{
+ efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() );
+
+ DirectorySnapshotDiff Diff = mDirSnap.scan();
+
+ if ( Diff.DirChanged )
+ {
+ sendDirChanged();
+ }
+
+ if ( Diff.changed() )
+ {
+ FileInfoList::iterator it;
+ MovedList::iterator mit;
+
+ /// Files
+ DiffIterator( FilesCreated )
+ {
+ addFile( (*it).Filepath );
+ }
+
+ DiffIterator( FilesModified )
+ {
+ handleAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( FilesDeleted )
+ {
+ removeFile( (*it).Filepath );
+ }
+
+ DiffMovedIterator( FilesMoved )
+ {
+ handleAction( (*mit).second.Filepath, Actions::Moved, (*mit).first );
+ removeFile( Directory + (*mit).first, false );
+ addFile( (*mit).second.Filepath, false );
+ }
+
+ /// Directories
+ DiffIterator( DirsCreated )
+ {
+ handleFolderAction( (*it).Filepath, Actions::Add );
+ addWatch( (*it).Filepath, Listener, Recursive, this );
+ }
+
+ DiffIterator( DirsModified )
+ {
+ handleFolderAction( (*it).Filepath, Actions::Modified );
+ }
+
+ DiffIterator( DirsDeleted )
+ {
+ handleFolderAction( (*it).Filepath, Actions::Delete );
+
+ Watcher * watch = findWatcher( (*it).Filepath );
+
+ if ( NULL != watch )
+ {
+ removeWatch( watch->ID );
+
+ }
+ }
+
+ DiffMovedIterator( DirsMoved )
+ {
+ moveDirectory( Directory + (*mit).first, (*mit).second.Filepath );
+ }
+ }
+}
+
+WatchID WatcherKqueue::watchingDirectory( std::string dir )
+{
+ Watcher * watch = findWatcher( dir );
+
+ if ( NULL != watch )
+ {
+ return watch->ID;
+ }
+
+ return Errors::FileNotFound;
+}
+
+void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename )
+{
+ Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, FileSystem::fileNameFromPath( oldFilename ) );
+}
+
+void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action , const std::string &oldFilename )
+{
+ FileSystem::dirRemoveSlashAtEnd( filename );
+
+ handleAction( filename, action, oldFilename );
+}
+
+void WatcherKqueue::sendDirChanged()
+{
+ if ( NULL != mParent )
+ {
+ Listener->handleFileAction( mParent->ID, mParent->Directory, FileSystem::fileNameFromPath( Directory ), Actions::Modified );
+ }
+}
+
+void WatcherKqueue::watch()
+{
+ if ( -1 == mKqueue )
+ {
+ return;
+ }
+
+ int nev = 0;
+ KEvent event;
+
+ // First iterate the childs, to get the events from the deepest folder, to the watcher childs
+ for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it )
+ {
+ it->second->watch();
+ }
+
+ bool needScan = false;
+
+ // Then we get the the events of the current folder
+ while( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, &mWatcher->mTimeOut ) ) != 0 )
+ {
+ // An error ocurred?
+ if( nev == -1 )
+ {
+ efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() );
+ perror("kevent");
+ break;
+ }
+ else
+ {
+ FileInfo * entry = NULL;
+
+ // If udate == NULL means that it is the fisrt element of the change list, the folder.
+ // otherwise it is an event of some file inside the folder
+ if( ( entry = reinterpret_cast<FileInfo*> ( event.udata ) ) != NULL )
+ {
+ efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() );
+
+ // If the event flag is delete... the file was deleted
+ if ( event.fflags & NOTE_DELETE )
+ {
+ efDEBUG( "deleted\n" );
+
+ mDirSnap.removeFile( entry->Filepath );
+
+ removeFile( entry->Filepath );
+ }
+ else if ( event.fflags & NOTE_EXTEND ||
+ event.fflags & NOTE_WRITE ||
+ event.fflags & NOTE_ATTRIB
+ )
+ {
+ // The file was modified
+ efDEBUG( "modified\n" );
+
+ FileInfo fi( entry->Filepath );
+
+ if ( fi != *entry )
+ {
+ *entry = fi;
+
+ mDirSnap.updateFile( entry->Filepath );
+
+ handleAction( entry->Filepath, efsw::Actions::Modified );
+ }
+ }
+ else if ( event.fflags & NOTE_RENAME )
+ {
+ efDEBUG( "moved\n" );
+
+ needScan = true;
+ }
+ }
+ else
+ {
+ needScan = true;
+ }
+ }
+ }
+
+ if ( needScan )
+ {
+ rescan();
+ }
+}
+
+Watcher * WatcherKqueue::findWatcher( const std::string path )
+{
+ WatchMap::iterator it = mWatches.begin();
+
+ for ( ; it != mWatches.end(); it++ )
+ {
+ if ( it->second->Directory == path )
+ {
+ return it->second;
+ }
+ }
+
+ return NULL;
+}
+
+void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents )
+{
+ // Update the directory path if it's a watcher
+ std::string opath2( oldPath );
+ FileSystem::dirAddSlashAtEnd( opath2 );
+
+ Watcher * watch = findWatcher( opath2 );
+
+ if ( NULL != watch )
+ {
+ watch->Directory = opath2;
+ }
+
+ if ( emitEvents )
+ {
+ handleFolderAction( newPath, efsw::Actions::Moved, oldPath );
+ }
+}
+
+WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive , WatcherKqueue *parent)
+{
+ static long s_fc = 0;
+ static bool s_ug = false;
+
+ std::string dir( directory );
+
+ FileSystem::dirAddSlashAtEnd( dir );
+
+ // This should never happen here
+ if( !FileSystem::isDirectory( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileNotFound, dir );
+ }
+ else if ( pathInWatches( dir ) || pathInParent( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, directory );
+ }
+ else if ( NULL != parent && FileSystem::isRemoteFS( dir ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRemote, dir );
+ }
+
+ std::string curPath;
+ std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
+
+ if ( "" != link )
+ {
+ /// Avoid adding symlinks directories if it's now enabled
+ if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
+ }
+
+ if ( pathInWatches( link ) || pathInParent( link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileRepeated, link );
+ }
+ else if ( !mWatcher->linkAllowed( curPath, link ) )
+ {
+ return Errors::Log::createLastError( Errors::FileOutOfScope, link );
+ }
+ else
+ {
+ dir = link;
+ }
+ }
+
+ if ( mWatcher->availablesFD() )
+ {
+ WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent );
+
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+
+ watch->addAll();
+
+ s_fc++;
+
+ // if failed to open the directory... erase the watcher
+ if ( !watch->initOK() )
+ {
+ int le = watch->lastErrno();
+
+ mWatches.erase( watch->ID );
+
+ efSAFE_DELETE( watch );
+
+ mLastWatchID--;
+
+ // Probably the folder has too many files, create a generic watcher
+ if ( EACCES != le )
+ {
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
+
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ }
+ else
+ {
+ return Errors::Log::createLastError( Errors::Unspecified, link );
+ }
+ }
+ }
+ else
+ {
+ if ( !s_ug )
+ {
+ efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders added: %ld\n", mWatcher->mFileDescriptorCount, s_fc );
+ s_ug = true;
+ }
+
+ WatcherGeneric * watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive );
+
+ mWatches.insert(std::make_pair(mLastWatchID, watch));
+ }
+
+ return mLastWatchID;
+}
+
+bool WatcherKqueue::initOK()
+{
+ return mInitOK;
+}
+
+void WatcherKqueue::removeWatch( WatchID watchid )
+{
+ WatchMap::iterator iter = mWatches.find(watchid);
+
+ if(iter == mWatches.end())
+ return;
+
+ Watcher * watch = iter->second;
+
+ mWatches.erase(iter);
+
+ efSAFE_DELETE( watch );
+}
+
+bool WatcherKqueue::pathInWatches( const std::string& path )
+{
+ return NULL != findWatcher( path );
+}
+
+bool WatcherKqueue::pathInParent( const std::string &path )
+{
+ WatcherKqueue * pNext = mParent;
+
+ while ( NULL != pNext )
+ {
+ if ( pNext->pathInWatches( path ) )
+ {
+ return true;
+ }
+
+ pNext = pNext->mParent;
+ }
+
+ if ( mWatcher->pathInWatches( path ) )
+ {
+ return true;
+ }
+
+ if ( path == Directory )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+int WatcherKqueue::lastErrno()
+{
+ return mErrno;
+}
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherKqueue.hpp b/dep/efsw/src/efsw/WatcherKqueue.hpp
new file mode 100644
index 00000000000..4babbe73354
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherKqueue.hpp
@@ -0,0 +1,94 @@
+#ifndef EFSW_WATCHEROSX_HPP
+#define EFSW_WATCHEROSX_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
+
+#include <map>
+#include <vector>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <efsw/DirectorySnapshot.hpp>
+
+namespace efsw
+{
+
+class FileWatcherKqueue;
+class WatcherKqueue;
+
+typedef struct kevent KEvent;
+
+/// type for a map from WatchID to WatcherKqueue pointer
+typedef std::map<WatchID, Watcher*> WatchMap;
+
+class WatcherKqueue : public Watcher
+{
+ public:
+ WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent = NULL );
+
+ virtual ~WatcherKqueue();
+
+ void addFile( const std::string& name, bool emitEvents = true );
+
+ void removeFile( const std::string& name, bool emitEvents = true );
+
+ // called when the directory is actually changed
+ // means a file has been added or removed
+ // rescans the watched directory adding/removing files and sending notices
+ void rescan();
+
+ void handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename = "" );
+
+ void handleFolderAction( std::string filename, efsw::Action action, const std::string& oldFilename = "" );
+
+ void addAll();
+
+ void removeAll();
+
+ WatchID watchingDirectory( std::string dir );
+
+ void watch();
+
+ WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherKqueue * parent);
+
+ void removeWatch (WatchID watchid );
+
+ bool initOK();
+
+ int lastErrno();
+ protected:
+ WatchMap mWatches;
+ int mLastWatchID;
+
+ // index 0 is always the directory
+ std::vector<KEvent> mChangeList;
+ size_t mChangeListCount;
+ DirectorySnapshot mDirSnap;
+
+ /// The descriptor for the kqueue
+ int mKqueue;
+
+ FileWatcherKqueue * mWatcher;
+
+ WatcherKqueue * mParent;
+
+ bool mInitOK;
+ int mErrno;
+
+ bool pathInWatches( const std::string& path );
+
+ bool pathInParent( const std::string& path );
+
+ Watcher * findWatcher( const std::string path );
+
+ void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true );
+
+ void sendDirChanged();
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/WatcherWin32.cpp b/dep/efsw/src/efsw/WatcherWin32.cpp
new file mode 100644
index 00000000000..01d7b0fcd99
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherWin32.cpp
@@ -0,0 +1,150 @@
+#include <efsw/WatcherWin32.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw
+{
+
+/// Unpacks events and passes them to a user defined callback.
+void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
+{
+ char szFile[MAX_PATH];
+ PFILE_NOTIFY_INFORMATION pNotify;
+ WatcherStructWin32 * tWatch = (WatcherStructWin32*) lpOverlapped;
+ WatcherWin32 * pWatch = tWatch->Watch;
+ size_t offset = 0;
+
+ if (dwNumberOfBytesTransfered == 0)
+ {
+ RefreshWatch(tWatch); // If dwNumberOfBytesTransfered == 0, it means the buffer overflowed (too many changes between GetOverlappedResults calls). Those events are lost, but at least we can refresh so subsequent changes are seen again.
+ return;
+ }
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ do
+ {
+ bool skip = false;
+
+ pNotify = (PFILE_NOTIFY_INFORMATION) &pWatch->mBuffer[offset];
+ offset += pNotify->NextEntryOffset;
+
+ int count = WideCharToMultiByte(CP_UTF8, 0, pNotify->FileName,
+ pNotify->FileNameLength / sizeof(WCHAR),
+ szFile, MAX_PATH - 1, NULL, NULL);
+ szFile[count] = TEXT('\0');
+
+ std::string nfile( szFile );
+
+ if ( FILE_ACTION_MODIFIED == pNotify->Action )
+ {
+ FileInfo fifile( std::string( pWatch->DirName ) + nfile );
+
+ if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && pWatch->LastModifiedEvent.file.Size == fifile.Size && pWatch->LastModifiedEvent.fileName == nfile )
+ {
+ skip = true;
+ }
+
+ pWatch->LastModifiedEvent.fileName = nfile;
+ pWatch->LastModifiedEvent.file = fifile;
+ }
+
+ if ( !skip )
+ {
+ pWatch->Watch->handleAction(pWatch, nfile, pNotify->Action);
+ }
+ } while (pNotify->NextEntryOffset != 0);
+ }
+
+ if (!pWatch->StopNow)
+ {
+ RefreshWatch(tWatch);
+ }
+}
+
+/// Refreshes the directory monitoring.
+bool RefreshWatch(WatcherStructWin32* pWatch)
+{
+ return ReadDirectoryChangesW(
+ pWatch->Watch->DirHandle,
+ pWatch->Watch->mBuffer,
+ sizeof(pWatch->Watch->mBuffer),
+ pWatch->Watch->Recursive,
+ pWatch->Watch->NotifyFilter,
+ NULL,
+ &pWatch->Overlapped,
+ NULL
+ ) != 0;
+}
+
+/// Stops monitoring a directory.
+void DestroyWatch(WatcherStructWin32* pWatch)
+{
+ if (pWatch)
+ {
+ WatcherWin32 * tWatch = pWatch->Watch;
+
+ tWatch->StopNow = true;
+
+ CancelIo(tWatch->DirHandle);
+
+ RefreshWatch(pWatch);
+
+ if (!HasOverlappedIoCompleted(&pWatch->Overlapped))
+ {
+ SleepEx(5, TRUE);
+ }
+
+ CloseHandle(pWatch->Overlapped.hEvent);
+ CloseHandle(pWatch->Watch->DirHandle);
+ efSAFE_DELETE_ARRAY( pWatch->Watch->DirName );
+ efSAFE_DELETE( pWatch->Watch );
+ HeapFree(GetProcessHeap(), 0, pWatch);
+ }
+}
+
+/// Starts monitoring a directory.
+WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter)
+{
+ WatcherStructWin32 * tWatch;
+ size_t ptrsize = sizeof(*tWatch);
+ tWatch = static_cast<WatcherStructWin32*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize));
+
+ WatcherWin32 * pWatch = new WatcherWin32();
+ tWatch->Watch = pWatch;
+
+ pWatch->DirHandle = CreateFileW(
+ szDirectory,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+ NULL
+ );
+
+ if (pWatch->DirHandle != INVALID_HANDLE_VALUE)
+ {
+ tWatch->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ pWatch->NotifyFilter = NotifyFilter;
+ pWatch->Recursive = recursive;
+
+ if (RefreshWatch(tWatch))
+ {
+ return tWatch;
+ }
+ else
+ {
+ CloseHandle(tWatch->Overlapped.hEvent);
+ CloseHandle(pWatch->DirHandle);
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, tWatch);
+ return NULL;
+}
+
+}
+
+ #endif
diff --git a/dep/efsw/src/efsw/WatcherWin32.hpp b/dep/efsw/src/efsw/WatcherWin32.hpp
new file mode 100644
index 00000000000..3c6d988fbf4
--- /dev/null
+++ b/dep/efsw/src/efsw/WatcherWin32.hpp
@@ -0,0 +1,77 @@
+#ifndef EFSW_WATCHERWIN32_HPP
+#define EFSW_WATCHERWIN32_HPP
+
+#include <efsw/FileWatcherImpl.hpp>
+#include <efsw/FileInfo.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#include <windows.h>
+
+#ifdef EFSW_COMPILER_MSVC
+ #pragma comment(lib, "comctl32.lib")
+ #pragma comment(lib, "user32.lib")
+ #pragma comment(lib, "ole32.lib")
+
+ // disable secure warnings
+ #pragma warning (disable: 4996)
+#endif
+
+namespace efsw
+{
+
+class WatcherWin32;
+
+/// Internal watch data
+struct WatcherStructWin32
+{
+ OVERLAPPED Overlapped;
+ WatcherWin32 * Watch;
+};
+
+class cLastModifiedEvent
+{
+ public:
+ cLastModifiedEvent() {}
+ FileInfo file;
+ std::string fileName;
+};
+
+bool RefreshWatch(WatcherStructWin32* pWatch);
+
+void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped);
+
+void DestroyWatch(WatcherStructWin32* pWatch);
+
+WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter);
+
+class WatcherWin32 : public Watcher
+{
+ public:
+ WatcherWin32() :
+ Struct( NULL ),
+ DirHandle( NULL ),
+ lParam( 0 ),
+ NotifyFilter( 0 ),
+ StopNow( false ),
+ Watch( NULL ),
+ DirName( NULL )
+ {
+ }
+
+ WatcherStructWin32 * Struct;
+ HANDLE DirHandle;
+ BYTE mBuffer[63 * 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched is on the network! (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
+ LPARAM lParam;
+ DWORD NotifyFilter;
+ bool StopNow;
+ FileWatcherImpl* Watch;
+ char* DirName;
+ cLastModifiedEvent LastModifiedEvent;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/base.hpp b/dep/efsw/src/efsw/base.hpp
new file mode 100644
index 00000000000..26108c76985
--- /dev/null
+++ b/dep/efsw/src/efsw/base.hpp
@@ -0,0 +1,110 @@
+#ifndef EFSW_BASE
+#define EFSW_BASE
+
+#include <efsw/sophist.h>
+#include <efsw/efsw.hpp>
+
+namespace efsw {
+
+typedef SOPHIST_int8 Int8;
+typedef SOPHIST_uint8 Uint8;
+typedef SOPHIST_int16 Int16;
+typedef SOPHIST_uint16 Uint16;
+typedef SOPHIST_int32 Int32;
+typedef SOPHIST_uint32 Uint32;
+typedef SOPHIST_int64 Int64;
+typedef SOPHIST_uint64 Uint64;
+
+#define EFSW_OS_WIN 1
+#define EFSW_OS_LINUX 2
+#define EFSW_OS_MACOSX 3
+#define EFSW_OS_BSD 4
+#define EFSW_OS_SOLARIS 5
+#define EFSW_OS_HAIKU 6
+#define EFSW_OS_ANDROID 7
+#define EFSW_OS_IOS 8
+
+#define EFSW_PLATFORM_WIN32 1
+#define EFSW_PLATFORM_INOTIFY 2
+#define EFSW_PLATFORM_KQUEUE 3
+#define EFSW_PLATFORM_FSEVENTS 4
+#define EFSW_PLATFORM_GENERIC 5
+
+#if defined(_WIN32)
+ /// Any Windows platform
+ #define EFSW_OS EFSW_OS_WIN
+ #define EFSW_PLATFORM EFSW_PLATFORM_WIN32
+
+ #if ( defined( _MSCVER ) || defined( _MSC_VER ) )
+ #define EFSW_COMPILER_MSVC
+ #endif
+
+#elif defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ )
+ #define EFSW_OS EFSW_OS_BSD
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+
+#elif defined( __APPLE_CC__ ) || defined ( __APPLE__ )
+ #include <TargetConditionals.h>
+
+ #if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR )
+ #define EFSW_OS EFSW_OS_IOS
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+ #else
+ #define EFSW_OS EFSW_OS_MACOSX
+
+ #if defined(EFSW_FSEVENTS_NOT_SUPPORTED)
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+ #else
+ #define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS
+ #endif
+ #endif
+
+#elif defined(__linux__)
+ /// This includes Linux and Android
+ #ifndef EFSW_KQUEUE
+ #define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY
+ #else
+ /// This is for testing libkqueue, sadly it doesnt work
+ #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE
+ #endif
+
+ #if defined( __ANDROID__ ) || defined( ANDROID )
+ #define EFSW_OS EFSW_OS_ANDROID
+ #else
+ #define EFSW_OS EFSW_OS_LINUX
+ #endif
+
+#else
+ #if defined( __SVR4 )
+ #define EFSW_OS EFSW_OS_SOLARIS
+ #elif defined( __HAIKU__ ) || defined( __BEOS__ )
+ #define EFSW_OS EFSW_OS_HAIKU
+ #endif
+
+ /// Everything else
+ #define EFSW_PLATFORM EFSW_PLATFORM_GENERIC
+#endif
+
+#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
+ #define EFSW_PLATFORM_POSIX
+#endif
+
+#if 1 == SOPHIST_pointer64
+ #define EFSW_64BIT
+#else
+ #define EFSW_32BIT
+#endif
+
+#if defined(arm) || defined(__arm__)
+ #define EFSW_ARM
+#endif
+
+#define efCOMMA ,
+
+#define efSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define efSAFE_DELETE_ARRAY(p) { if(p) { delete [] (p); (p)=NULL; } }
+#define efARRAY_SIZE(__array) ( sizeof(__array) / sizeof(__array[0]) )
+
+}
+
+#endif
diff --git a/dep/efsw/src/efsw/inotify-nosys.h b/dep/efsw/src/efsw/inotify-nosys.h
new file mode 100644
index 00000000000..75df5d3ced3
--- /dev/null
+++ b/dep/efsw/src/efsw/inotify-nosys.h
@@ -0,0 +1,159 @@
+#ifndef _LINUX_INOTIFY_H
+#define _LINUX_INOTIFY_H
+
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/*
+ * struct inotify_event - structure read from the inotify device for each event
+ *
+ * When you are watching a directory, you will receive the filename for events
+ * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ */
+struct inotify_event {
+ int wd; /* watch descriptor */
+ uint32_t mask; /* watch mask */
+ uint32_t cookie; /* cookie to synchronize two events */
+ uint32_t len; /* length (including nulls) of name */
+ char name __flexarr; /* stub for possible name */
+};
+
+/* the following are legal, implemented events that user-space can watch for */
+#define IN_ACCESS 0x00000001 /* File was accessed */
+#define IN_MODIFY 0x00000002 /* File was modified */
+#define IN_ATTRIB 0x00000004 /* Metadata changed */
+#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
+#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
+#define IN_OPEN 0x00000020 /* File was opened */
+#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
+#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
+#define IN_CREATE 0x00000100 /* Subfile was created */
+#define IN_DELETE 0x00000200 /* Subfile was deleted */
+#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
+#define IN_MOVE_SELF 0x00000800 /* Self was moved */
+
+/* the following are legal events. they are sent as needed to any watch */
+#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
+#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
+#define IN_IGNORED 0x00008000 /* File was ignored */
+
+/* helper events */
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
+
+/* special flags */
+#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
+#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
+#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
+#define IN_ISDIR 0x40000000 /* event occurred against dir */
+#define IN_ONESHOT 0x80000000 /* only send event once */
+
+/*
+ * All of the events - we build the list by hand so that we can add flags in
+ * the future and not break backward compatibility. Apps will get only the
+ * events that they originally wanted. Be sure to add new events here!
+ */
+#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
+ IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
+ IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \
+ IN_MOVE_SELF)
+
+#if defined (__alpha__)
+# define __NR_inotify_init 444
+# define __NR_inotify_add_watch 445
+# define __NR_inotify_rm_watch 446
+
+#elif defined (__arm__)
+# define __NR_inotify_init (__NR_SYSCALL_BASE+316)
+# define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317)
+# define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318)
+
+#elif defined (__frv__)
+# define __NR_inotify_init 291
+# define __NR_inotify_add_watch 292
+# define __NR_inotify_rm_watch 293
+
+#elif defined(__i386__)
+# define __NR_inotify_init 291
+# define __NR_inotify_add_watch 292
+# define __NR_inotify_rm_watch 293
+
+#elif defined (__ia64__)
+# define __NR_inotify_init 1277
+# define __NR_inotify_add_watch 1278
+# define __NR_inotify_rm_watch 1279
+
+#elif defined (__mips__)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_inotify_init (__NR_Linux + 284)
+# define __NR_inotify_add_watch (__NR_Linux + 285)
+# define __NR_inotify_rm_watch (__NR_Linux + 286)
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_inotify_init (__NR_Linux + 243)
+# define __NR_inotify_add_watch (__NR_Linux + 243)
+# define __NR_inotify_rm_watch (__NR_Linux + 243)
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_inotify_init (__NR_Linux + 247)
+# define __NR_inotify_add_watch (__NR_Linux + 248)
+# define __NR_inotify_rm_watch (__NR_Linux + 249)
+# endif
+
+#elif defined(__parisc__)
+# define __NR_inotify_init (__NR_Linux + 269)
+# define __NR_inotify_add_watch (__NR_Linux + 270)
+# define __NR_inotify_rm_watch (__NR_Linux + 271)
+
+#elif defined(__powerpc__) || defined(__powerpc64__)
+# define __NR_inotify_init 275
+# define __NR_inotify_add_watch 276
+# define __NR_inotify_rm_watch 277
+
+#elif defined (__s390__)
+# define __NR_inotify_init 284
+# define __NR_inotify_add_watch 285
+# define __NR_inotify_rm_watch 286
+
+#elif defined (__sh__)
+# define __NR_inotify_init 290
+# define __NR_inotify_add_watch 291
+# define __NR_inotify_rm_watch 292
+
+#elif defined (__sh64__)
+# define __NR_inotify_init 318
+# define __NR_inotify_add_watch 319
+# define __NR_inotify_rm_watch 320
+
+#elif defined (__sparc__) || defined (__sparc64__)
+# define __NR_inotify_init 151
+# define __NR_inotify_add_watch 152
+# define __NR_inotify_rm_watch 156
+
+#elif defined(__x86_64__)
+# define __NR_inotify_init 253
+# define __NR_inotify_add_watch 254
+# define __NR_inotify_rm_watch 255
+
+#else
+# error "Unsupported architecture!"
+#endif
+
+static inline int inotify_init (void)
+{
+ return syscall (__NR_inotify_init);
+}
+
+static inline int inotify_add_watch (int fd, const char *name, uint32_t mask)
+{
+ return syscall (__NR_inotify_add_watch, fd, name, mask);
+}
+
+static inline int inotify_rm_watch (int fd, uint32_t wd)
+{
+ return syscall (__NR_inotify_rm_watch, fd, wd);
+}
+
+
+#endif /* _LINUX_INOTIFY_H */
diff --git a/dep/efsw/src/efsw/platform/platformimpl.hpp b/dep/efsw/src/efsw/platform/platformimpl.hpp
new file mode 100644
index 00000000000..86a74eee0c8
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/platformimpl.hpp
@@ -0,0 +1,20 @@
+#ifndef EFSW_PLATFORMIMPL_HPP
+#define EFSW_PLATFORMIMPL_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+ #include <efsw/platform/posix/ThreadImpl.hpp>
+ #include <efsw/platform/posix/MutexImpl.hpp>
+ #include <efsw/platform/posix/SystemImpl.hpp>
+ #include <efsw/platform/posix/FileSystemImpl.hpp>
+#elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+ #include <efsw/platform/win/ThreadImpl.hpp>
+ #include <efsw/platform/win/MutexImpl.hpp>
+ #include <efsw/platform/win/SystemImpl.hpp>
+ #include <efsw/platform/win/FileSystemImpl.hpp>
+#else
+ #error Thread, Mutex, and System not implemented for this platform.
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp
new file mode 100644
index 00000000000..e061b25d56b
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.cpp
@@ -0,0 +1,144 @@
+#include <efsw/platform/posix/FileSystemImpl.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <efsw/FileInfo.hpp>
+#include <efsw/FileSystem.hpp>
+#include <dirent.h>
+#include <cstring>
+
+#ifndef _DARWIN_FEATURE_64_BIT_INODE
+#define _DARWIN_FEATURE_64_BIT_INODE
+#endif
+
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#include <sys/stat.h>
+#include <cstdlib>
+
+#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID
+#include <sys/vfs.h>
+#elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+/** Remote file systems codes */
+#define S_MAGIC_AFS 0x5346414F
+#define S_MAGIC_AUFS 0x61756673
+#define S_MAGIC_CEPH 0x00C36400
+#define S_MAGIC_CIFS 0xFF534D42
+#define S_MAGIC_CODA 0x73757245
+#define S_MAGIC_FHGFS 0x19830326
+#define S_MAGIC_FUSEBLK 0x65735546
+#define S_MAGIC_FUSECTL 0x65735543
+#define S_MAGIC_GFS 0x01161970
+#define S_MAGIC_GPFS 0x47504653
+#define S_MAGIC_KAFS 0x6B414653
+#define S_MAGIC_LUSTRE 0x0BD00BD0
+#define S_MAGIC_NCP 0x564C
+#define S_MAGIC_NFS 0x6969
+#define S_MAGIC_NFSD 0x6E667364
+#define S_MAGIC_OCFS2 0x7461636F
+#define S_MAGIC_PANFS 0xAAD7AAEA
+#define S_MAGIC_PIPEFS 0x50495045
+#define S_MAGIC_SMB 0x517B
+#define S_MAGIC_SNFS 0xBEEFDEAD
+#define S_MAGIC_VMHGFS 0xBACBACBC
+#define S_MAGIC_VXFS 0xA501FCF5
+
+namespace efsw { namespace Platform {
+
+FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
+{
+ FileInfoMap files;
+
+ DIR *dp;
+ struct dirent *dirp;
+
+ if( ( dp = opendir( path.c_str() ) ) == NULL)
+ return files;
+
+ while ( ( dirp = readdir(dp) ) != NULL)
+ {
+ if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 )
+ {
+ std::string name( dirp->d_name );
+ std::string fpath( path + name );
+
+ files[ name ] = FileInfo( fpath );
+ }
+ }
+
+ closedir(dp);
+
+ return files;
+}
+
+char FileSystem::getOSSlash()
+{
+ return '/';
+}
+
+bool FileSystem::isDirectory( const std::string& path )
+{
+ struct stat st;
+ int res = stat( path.c_str(), &st );
+
+ if ( 0 == res )
+ {
+ return static_cast<bool>( S_ISDIR(st.st_mode) );
+ }
+
+ return false;
+}
+
+bool FileSystem::isRemoteFS( const std::string& directory )
+{
+#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS
+ struct statfs statfsbuf;
+
+ statfs( directory.c_str(), &statfsbuf );
+
+ switch ( statfsbuf.f_type | 0UL )
+ {
+ case S_MAGIC_AFS: /* 0x5346414F remote */
+ case S_MAGIC_AUFS: /* 0x61756673 remote */
+ case S_MAGIC_CEPH: /* 0x00C36400 remote */
+ case S_MAGIC_CIFS: /* 0xFF534D42 remote */
+ case S_MAGIC_CODA: /* 0x73757245 remote */
+ case S_MAGIC_FHGFS: /* 0x19830326 remote */
+ case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
+ case S_MAGIC_FUSECTL: /* 0x65735543 remote */
+ case S_MAGIC_GFS: /* 0x01161970 remote */
+ case S_MAGIC_GPFS: /* 0x47504653 remote */
+ case S_MAGIC_KAFS: /* 0x6B414653 remote */
+ case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
+ case S_MAGIC_NCP: /* 0x564C remote */
+ case S_MAGIC_NFS: /* 0x6969 remote */
+ case S_MAGIC_NFSD: /* 0x6E667364 remote */
+ case S_MAGIC_OCFS2: /* 0x7461636F remote */
+ case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
+ case S_MAGIC_PIPEFS: /* 0x50495045 remote */
+ case S_MAGIC_SMB: /* 0x517B remote */
+ case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
+ case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
+ case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+#endif
+
+ return false;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp
new file mode 100644
index 00000000000..865b3f8dfdf
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/FileSystemImpl.hpp
@@ -0,0 +1,27 @@
+#ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP
+#define EFSW_FILESYSTEMIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/FileInfo.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+namespace efsw { namespace Platform {
+
+class FileSystem
+{
+ public:
+ static FileInfoMap filesInfoFromPath( const std::string& path );
+
+ static char getOSSlash();
+
+ static bool isDirectory( const std::string& path );
+
+ static bool isRemoteFS( const std::string& directory );
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp b/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp
new file mode 100644
index 00000000000..6f2af5abc61
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/MutexImpl.cpp
@@ -0,0 +1,32 @@
+#include <efsw/platform/posix/MutexImpl.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+namespace efsw { namespace Platform {
+
+MutexImpl::MutexImpl()
+{
+ pthread_mutexattr_t attributes;
+ pthread_mutexattr_init(&attributes);
+ pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mMutex, &attributes);
+}
+
+MutexImpl::~MutexImpl()
+{
+ pthread_mutex_destroy(&mMutex);
+}
+
+void MutexImpl::lock()
+{
+ pthread_mutex_lock(&mMutex);
+}
+
+void MutexImpl::unlock()
+{
+ pthread_mutex_unlock(&mMutex);
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp b/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp
new file mode 100644
index 00000000000..d51eecb16aa
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/MutexImpl.hpp
@@ -0,0 +1,31 @@
+#ifndef EFSW_MUTEXIMPLPOSIX_HPP
+#define EFSW_MUTEXIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <pthread.h>
+
+namespace efsw { namespace Platform {
+
+class MutexImpl
+{
+ public:
+ MutexImpl();
+
+ ~MutexImpl();
+
+ void lock();
+
+ void unlock();
+ private:
+ pthread_mutex_t mMutex;
+};
+
+}}
+
+#endif
+
+#endif
+
diff --git a/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp b/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp
new file mode 100644
index 00000000000..22e37095afd
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/SystemImpl.cpp
@@ -0,0 +1,180 @@
+#include <efsw/platform/posix/SystemImpl.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <cstdio>
+#include <pthread.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <sys/resource.h>
+
+#include <efsw/FileSystem.hpp>
+#include <efsw/Debug.hpp>
+
+#if EFSW_OS == EFSW_OS_MACOSX
+ #include <CoreFoundation/CoreFoundation.h>
+#elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID
+ #include <libgen.h>
+ #include <unistd.h>
+#elif EFSW_OS == EFSW_OS_HAIKU
+ #include <kernel/OS.h>
+ #include <kernel/image.h>
+#elif EFSW_OS == EFSW_OS_SOLARIS
+ #include <stdlib.h>
+#elif EFSW_OS == EFSW_OS_BSD
+ #include <sys/sysctl.h>
+#endif
+
+namespace efsw { namespace Platform {
+
+void System::sleep( const unsigned long& ms )
+{
+ // usleep( static_cast<unsigned long>( ms * 1000 ) );
+
+ // usleep is not reliable enough (it might block the
+ // whole process instead of just the current thread)
+ // so we must use pthread_cond_timedwait instead
+
+ // this implementation is inspired from Qt
+ // and taken from SFML
+
+ unsigned long long usecs = ms * 1000;
+
+ // get the current time
+ timeval tv;
+ gettimeofday(&tv, NULL);
+
+ // construct the time limit (current time + time to wait)
+ timespec ti;
+ ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
+ ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
+ ti.tv_nsec %= 1000000000;
+
+ // create a mutex and thread condition
+ pthread_mutex_t mutex;
+ pthread_mutex_init(&mutex, 0);
+ pthread_cond_t condition;
+ pthread_cond_init(&condition, 0);
+
+ // wait...
+ pthread_mutex_lock(&mutex);
+ pthread_cond_timedwait(&condition, &mutex, &ti);
+ pthread_mutex_unlock(&mutex);
+
+ // destroy the mutex and condition
+ pthread_cond_destroy(&condition);
+}
+
+std::string System::getProcessPath()
+{
+#if EFSW_OS == EFSW_OS_MACOSX
+ char exe_file[FILENAME_MAX + 1];
+
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+
+ if (mainBundle)
+ {
+ CFURLRef mainURL = CFBundleCopyBundleURL(mainBundle);
+
+ if (mainURL)
+ {
+ int ok = CFURLGetFileSystemRepresentation ( mainURL, (Boolean) true, (UInt8*)exe_file, FILENAME_MAX );
+
+ if (ok)
+ {
+ return std::string(exe_file) + "/";
+ }
+ }
+ }
+
+ return "./";
+#elif EFSW_OS == EFSW_OS_LINUX
+ char exe_file[FILENAME_MAX + 1];
+
+ int size;
+
+ size = readlink("/proc/self/exe", exe_file, FILENAME_MAX);
+
+ if (size < 0)
+ {
+ return std::string( "./" );
+ }
+ else
+ {
+ exe_file[size] = '\0';
+ return std::string( dirname( exe_file ) ) + "/";
+ }
+
+#elif EFSW_OS == EFSW_OS_BSD
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ char buf[1024];
+ size_t cb = sizeof(buf);
+ sysctl(mib, 4, buf, &cb, NULL, 0);
+
+ return FileSystem::pathRemoveFileName( std::string( buf ) );
+
+#elif EFSW_OS == EFSW_OS_SOLARIS
+ return FileSystem::pathRemoveFileName( std::string( getexecname() ) );
+
+#elif EFSW_OS == EFSW_OS_HAIKU
+ image_info info;
+ int32 cookie = 0;
+
+ while ( B_OK == get_next_image_info( 0, &cookie, &info ) )
+ {
+ if ( info.type == B_APP_IMAGE )
+ break;
+ }
+
+ return FileSystem::pathRemoveFileName( std::string( info.name ) );
+
+#elif EFSW_OS == EFSW_OS_ANDROID
+ return "/sdcard/";
+
+#else
+ #warning getProcessPath() not implemented on this platform. ( will return "./" )
+ return "./";
+
+#endif
+}
+
+void System::maxFD()
+{
+ static bool maxed = false;
+
+ if ( !maxed )
+ {
+ struct rlimit limit;
+ getrlimit( RLIMIT_NOFILE, &limit );
+ limit.rlim_cur = limit.rlim_max;
+ setrlimit( RLIMIT_NOFILE, &limit );
+
+ getrlimit( RLIMIT_NOFILE, &limit );
+
+ efDEBUG( "File descriptor limit %ld\n", limit.rlim_cur );
+
+ maxed = true;
+ }
+}
+
+Uint64 System::getMaxFD()
+{
+ static rlim_t max_fd = 0;
+
+ if ( max_fd == 0 )
+ {
+ struct rlimit limit;
+ getrlimit( RLIMIT_NOFILE, &limit );
+ max_fd = limit.rlim_cur;
+ }
+
+ return max_fd;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp b/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp
new file mode 100644
index 00000000000..34734104467
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/SystemImpl.hpp
@@ -0,0 +1,26 @@
+#ifndef EFSW_SYSTEMIMPLPOSIX_HPP
+#define EFSW_SYSTEMIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+namespace efsw { namespace Platform {
+
+class System
+{
+ public:
+ static void sleep( const unsigned long& ms );
+
+ static std::string getProcessPath();
+
+ static void maxFD();
+
+ static Uint64 getMaxFD();
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp b/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp
new file mode 100644
index 00000000000..2d3671db9b8
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/ThreadImpl.cpp
@@ -0,0 +1,68 @@
+#include <efsw/platform/posix/ThreadImpl.hpp>
+#include <efsw/Thread.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <cassert>
+#include <iostream>
+#include <efsw/Debug.hpp>
+
+namespace efsw { namespace Platform {
+
+ThreadImpl::ThreadImpl( Thread * owner ) :
+ mIsActive(false)
+{
+ mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0;
+
+ if ( !mIsActive )
+ {
+ efDEBUG( "Failed to create thread\n" );
+ }
+}
+
+void ThreadImpl::wait()
+{
+ // Wait for the thread to finish, no timeout
+ if ( mIsActive )
+ {
+ assert( pthread_equal( pthread_self(), mThread ) == 0 );
+
+ pthread_join( mThread, NULL );
+
+ mIsActive = false; // Reset the thread state
+ }
+}
+
+void ThreadImpl::terminate()
+{
+ if ( mIsActive )
+ {
+ #if !defined( __ANDROID__ ) && !defined( ANDROID )
+ pthread_cancel( mThread );
+ #else
+ pthread_kill( mThread , SIGUSR1 );
+ #endif
+
+ mIsActive = false;
+ }
+}
+
+void * ThreadImpl::entryPoint( void * userData )
+{
+ // The Thread instance is stored in the user data
+ Thread * owner = static_cast<Thread*>( userData );
+
+ // Tell the thread to handle cancel requests immediatly
+ #ifdef PTHREAD_CANCEL_ASYNCHRONOUS
+ pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
+ #endif
+
+ // Forward to the owner
+ owner->run();
+
+ return NULL;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp b/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp
new file mode 100644
index 00000000000..be6dc1b3e58
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/posix/ThreadImpl.hpp
@@ -0,0 +1,35 @@
+#ifndef EFSW_THREADIMPLPOSIX_HPP
+#define EFSW_THREADIMPLPOSIX_HPP
+
+#include <efsw/base.hpp>
+
+#if defined( EFSW_PLATFORM_POSIX )
+
+#include <pthread.h>
+
+namespace efsw {
+
+class Thread;
+
+namespace Platform {
+
+class ThreadImpl
+{
+ public:
+ ThreadImpl( Thread * owner );
+
+ void wait();
+
+ void terminate();
+ protected:
+ static void * entryPoint( void* userData );
+
+ pthread_t mThread;
+ bool mIsActive;
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp b/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp
new file mode 100644
index 00000000000..376a474e662
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/FileSystemImpl.cpp
@@ -0,0 +1,89 @@
+#include <efsw/platform/win/FileSystemImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#ifndef EFSW_COMPILER_MSVC
+#include <dirent.h>
+#endif
+
+namespace efsw { namespace Platform {
+
+FileInfoMap FileSystem::filesInfoFromPath( const std::string& path )
+{
+ FileInfoMap files;
+
+ String tpath( path );
+
+ if ( tpath[ tpath.size() - 1 ] == '/' || tpath[ tpath.size() - 1 ] == '\\' )
+ {
+ tpath += "*";
+ }
+ else
+ {
+ tpath += "\\*";
+ }
+
+ WIN32_FIND_DATAW findFileData;
+ HANDLE hFind = FindFirstFileW( (LPCWSTR)tpath.toWideString().c_str(), &findFileData );
+
+ if( hFind != INVALID_HANDLE_VALUE )
+ {
+ std::string name( String( findFileData.cFileName ).toUtf8() );
+ std::string fpath( path + name );
+
+ if ( name != "." && name != ".." )
+ {
+ files[ name ] = FileInfo( fpath );
+ }
+
+ while( FindNextFileW( hFind, &findFileData ) )
+ {
+ name = String( findFileData.cFileName ).toUtf8();
+ fpath = path + name;
+
+ if ( name != "." && name != ".." )
+ {
+ files[ name ] = FileInfo( fpath );
+ }
+ }
+
+ FindClose( hFind );
+ }
+
+ return files;
+}
+
+char FileSystem::getOSSlash()
+{
+ return '\\';
+}
+
+bool FileSystem::isDirectory( const std::string& path )
+{
+ return 0 != ( GetFileAttributesW( String( path ).toWideString().c_str() ) & FILE_ATTRIBUTE_DIRECTORY );
+}
+
+bool FileSystem::isRemoteFS( const std::string& directory )
+{
+ if ((directory[0] == '\\' || directory[0] == '/') &&
+ (directory[1] == '\\' || directory[1] == '/'))
+ {
+ return true;
+ }
+
+ if ( directory.size() >= 3 )
+ {
+ return 4 == GetDriveTypeA( directory.substr( 0, 3 ).c_str() );
+ }
+
+ return false;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp b/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp
new file mode 100644
index 00000000000..597edc4a647
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/FileSystemImpl.hpp
@@ -0,0 +1,28 @@
+#ifndef EFSW_FILESYSTEMIMPLWIN_HPP
+#define EFSW_FILESYSTEMIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+#include <efsw/String.hpp>
+#include <efsw/FileInfo.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw { namespace Platform {
+
+class FileSystem
+{
+ public:
+ static FileInfoMap filesInfoFromPath( const std::string& path );
+
+ static char getOSSlash();
+
+ static bool isDirectory( const std::string& path );
+
+ static bool isRemoteFS( const std::string& directory );
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/MutexImpl.cpp b/dep/efsw/src/efsw/platform/win/MutexImpl.cpp
new file mode 100644
index 00000000000..0c8c36d8b39
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/MutexImpl.cpp
@@ -0,0 +1,29 @@
+#include <efsw/platform/win/MutexImpl.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw { namespace Platform {
+
+MutexImpl::MutexImpl()
+{
+ InitializeCriticalSection(&mMutex);
+}
+
+MutexImpl::~MutexImpl()
+{
+ DeleteCriticalSection(&mMutex);
+}
+
+void MutexImpl::lock()
+{
+ EnterCriticalSection(&mMutex);
+}
+
+void MutexImpl::unlock()
+{
+ LeaveCriticalSection(&mMutex);
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/MutexImpl.hpp b/dep/efsw/src/efsw/platform/win/MutexImpl.hpp
new file mode 100644
index 00000000000..da1e20c5fa9
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/MutexImpl.hpp
@@ -0,0 +1,34 @@
+#ifndef EFSW_MUTEXIMPLWIN_HPP
+#define EFSW_MUTEXIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+namespace efsw { namespace Platform {
+
+class MutexImpl
+{
+ public:
+ MutexImpl();
+
+ ~MutexImpl();
+
+ void lock();
+
+ void unlock();
+ private:
+ CRITICAL_SECTION mMutex;
+};
+
+}}
+
+#endif
+
+#endif
+
diff --git a/dep/efsw/src/efsw/platform/win/SystemImpl.cpp b/dep/efsw/src/efsw/platform/win/SystemImpl.cpp
new file mode 100644
index 00000000000..ddbe1e5c45c
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/SystemImpl.cpp
@@ -0,0 +1,50 @@
+#include <efsw/platform/win/SystemImpl.hpp>
+#include <efsw/String.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <cstdlib>
+
+namespace efsw { namespace Platform {
+
+void System::sleep( const unsigned long& ms )
+{
+ ::Sleep( ms );
+}
+
+std::string System::getProcessPath()
+{
+ // Get path to executable:
+ WCHAR szDrive[_MAX_DRIVE];
+ WCHAR szDir[_MAX_DIR];
+ WCHAR szFilename[_MAX_DIR];
+ WCHAR szExt[_MAX_DIR];
+ std::wstring dllName( _MAX_DIR, 0 );
+
+ GetModuleFileNameW(0, &dllName[0], _MAX_PATH);
+
+ #ifdef EFSW_COMPILER_MSVC
+ _wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR );
+ #else
+ _wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt);
+ #endif
+
+ return String( szDrive ).toUtf8() + String( szDir ).toUtf8();
+}
+
+void System::maxFD()
+{
+}
+
+Uint64 System::getMaxFD()
+{ // Number of ReadDirectory per thread
+ return 60;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/SystemImpl.hpp b/dep/efsw/src/efsw/platform/win/SystemImpl.hpp
new file mode 100644
index 00000000000..2f785e3565c
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/SystemImpl.hpp
@@ -0,0 +1,26 @@
+#ifndef EFSW_SYSTEMIMPLWIN_HPP
+#define EFSW_SYSTEMIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+namespace efsw { namespace Platform {
+
+class System
+{
+ public:
+ static void sleep( const unsigned long& ms );
+
+ static std::string getProcessPath();
+
+ static void maxFD();
+
+ static Uint64 getMaxFD();
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp b/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp
new file mode 100644
index 00000000000..2fa30f30060
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/ThreadImpl.cpp
@@ -0,0 +1,56 @@
+#include <efsw/platform/win/ThreadImpl.hpp>
+#include <efsw/Thread.hpp>
+#include <assert.h>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#include <efsw/Debug.hpp>
+
+namespace efsw { namespace Platform {
+
+ThreadImpl::ThreadImpl( Thread *owner )
+{
+ mThread = reinterpret_cast<HANDLE>( _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) );
+
+ if ( !mThread )
+ {
+ efDEBUG( "Failed to create thread\n" );
+ }
+}
+
+void ThreadImpl::wait()
+{
+ // Wait for the thread to finish, no timeout
+ if ( mThread )
+ {
+ assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself!
+
+ WaitForSingleObject( mThread, INFINITE );
+ }
+}
+
+void ThreadImpl::terminate()
+{
+ if ( mThread )
+ {
+ TerminateThread( mThread, 0 );
+ }
+}
+
+unsigned int __stdcall ThreadImpl::entryPoint( void * userData )
+{
+ // The Thread instance is stored in the user data
+ Thread * owner = static_cast<Thread*>( userData );
+
+ // Forward to the owner
+ owner->run();
+
+ // Optional, but it is cleaner
+ _endthreadex(0);
+
+ return 0;
+}
+
+}}
+
+#endif
diff --git a/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp b/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp
new file mode 100644
index 00000000000..506c659c675
--- /dev/null
+++ b/dep/efsw/src/efsw/platform/win/ThreadImpl.hpp
@@ -0,0 +1,39 @@
+#ifndef EFSW_THREADIMPLWIN_HPP
+#define EFSW_THREADIMPLWIN_HPP
+
+#include <efsw/base.hpp>
+
+#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <process.h>
+
+namespace efsw {
+
+class Thread;
+
+namespace Platform {
+
+class ThreadImpl
+{
+ public:
+ ThreadImpl( Thread * owner );
+
+ void wait();
+
+ void terminate();
+ protected:
+ static unsigned int __stdcall entryPoint(void* userData);
+
+ HANDLE mThread;
+ unsigned int mThreadId;
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/dep/efsw/src/efsw/sophist.h b/dep/efsw/src/efsw/sophist.h
new file mode 100644
index 00000000000..3a645040e2f
--- /dev/null
+++ b/dep/efsw/src/efsw/sophist.h
@@ -0,0 +1,147 @@
+/* sophist.h - 0.3 - public domain - Sean Barrett 2010
+** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net
+** Sophist provides portable types; you typedef/#define them to your own names
+**
+** defines:
+** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian
+** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined
+** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit
+**
+** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer
+** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16
+** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64
+** - SOPHIST_int64_constant(number) - macros for creating 64-bit
+** - SOPHIST_uint64_constant(number) integer constants
+** - SOPHIST_printf_format64 - string for printf format for int64
+*/
+
+#ifndef __INCLUDE_SOPHIST_H__
+#define __INCLUDE_SOPHIST_H__
+
+#define SOPHIST_compiletime_assert(name,val) \
+ typedef int SOPHIST__assert##name[(val) ? 1 : -1]
+
+/* define a couple synthetic rules to make code more readable */
+#if (defined(__sparc__) || defined(__sparc)) && \
+ (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__))
+ #define SOPHIST_sparc64
+#endif
+
+#if (defined(linux) || defined(__linux__)) && \
+ (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64))
+ #define SOPHIST_linux64
+#endif
+
+/* basic types */
+typedef signed char SOPHIST_int8;
+typedef unsigned char SOPHIST_uint8;
+
+typedef signed short SOPHIST_int16;
+typedef unsigned short SOPHIST_uint16;
+
+#ifdef __palmos__
+ typedef signed long SOPHIST_int32;
+ typedef unsigned long SOPHIST_uint32;
+#else
+ typedef signed int SOPHIST_int32;
+ typedef unsigned int SOPHIST_uint32;
+#endif
+
+#ifndef SOPHIST_NO_64
+ #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \
+ || (defined(__alpha) && defined(__DECC))
+
+ typedef signed __int64 SOPHIST_int64;
+ typedef unsigned __int64 SOPHIST_uint64;
+ #define SOPHIST_has_64 1
+ #define SOPHIST_int64_constant(x) (x##i64)
+ #define SOPHIST_uint64_constant(x) (x##ui64)
+ #define SOPHIST_printf_format64 "I64"
+
+ #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64)
+
+ typedef signed long SOPHIST_int64;
+ typedef unsigned long SOPHIST_uint64;
+
+ #define SOPHIST_has_64 1
+ #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x)
+ #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x)
+ #define SOPHIST_printf_format64 "l"
+
+ #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \
+ || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \
+ || defined(sgi) || defined (__sgi) || defined(__sgi__) \
+ || defined(_CRAYC)
+
+ typedef signed long long SOPHIST_int64;
+ typedef unsigned long long SOPHIST_uint64;
+
+ #define SOPHIST_has_64 1
+ #define SOPHIST_int64_constant(x) (x##LL)
+ #define SOPHIST_uint64_constant(x) (x##ULL)
+ #define SOPHIST_printf_format64 "ll"
+ #endif
+#endif
+
+#ifndef SOPHIST_has_64
+#define SOPHIST_has_64 0
+#endif
+
+SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1);
+SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2);
+SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4);
+SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4);
+
+#if SOPHIST_has_64
+ SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8);
+ SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8);
+#endif
+
+/* determine whether pointers are 64-bit */
+
+#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \
+ || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \
+ || defined(__64BIT__) \
+ || defined(__LP64) || defined(__LP64__) || defined(_LP64) \
+ || defined(_ADDR64) || defined(_CRAYC) \
+
+ #define SOPHIST_pointer64 1
+
+ SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8);
+
+ typedef SOPHIST_int64 SOPHIST_intptr;
+ typedef SOPHIST_uint64 SOPHIST_uintptr;
+#else
+
+ #define SOPHIST_pointer64 0
+
+ SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4);
+
+ /* do we care about pointers that are only 16-bit? */
+ typedef SOPHIST_int32 SOPHIST_intptr;
+ typedef SOPHIST_uint32 SOPHIST_uintptr;
+
+#endif
+
+SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *));
+
+/* enumerate known little endian cases; fallback to big-endian */
+
+#define SOPHIST_little_endian 1
+#define SOPHIST_big_endian 2
+
+#if defined(__386__) || defined(i386) || defined(__i386__) \
+ || defined(__X86) || defined(_M_IX86) \
+ || defined(_M_X64) || defined(__x86_64__) \
+ || defined(alpha) || defined(__alpha) || defined(__alpha__) \
+ || defined(_M_ALPHA) \
+ || defined(ARM) || defined(_ARM) || defined(__arm__) \
+ || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
+ || defined(_WIN32_WCE) || defined(__NT__) \
+ || defined(__MIPSEL__)
+ #define SOPHIST_endian SOPHIST_little_endian
+#else
+ #define SOPHIST_endian SOPHIST_big_endian
+#endif
+
+#endif /* __INCLUDE_SOPHIST_H__ */
diff --git a/dep/efsw/src/test/efsw-test.cpp b/dep/efsw/src/test/efsw-test.cpp
new file mode 100644
index 00000000000..a49e3414fcc
--- /dev/null
+++ b/dep/efsw/src/test/efsw-test.cpp
@@ -0,0 +1,151 @@
+#include <efsw/efsw.hpp>
+#include <efsw/System.hpp>
+#include <efsw/FileSystem.hpp>
+#include <signal.h>
+#include <iostream>
+
+bool STOP = false;
+
+void sigend(int signal)
+{
+ std::cout << std::endl << "Bye bye" << std::endl;
+ STOP = true;
+}
+
+/// Processes a file action
+class UpdateListener : public efsw::FileWatchListener
+{
+ public:
+ UpdateListener() {}
+
+ std::string getActionName( efsw::Action action )
+ {
+ switch ( action )
+ {
+ case efsw::Actions::Add: return "Add";
+ case efsw::Actions::Modified: return "Modified";
+ case efsw::Actions::Delete: return "Delete";
+ case efsw::Actions::Moved: return "Moved";
+ default: return "Bad Action";
+ }
+ }
+
+ void handleFileAction( efsw::WatchID watchid, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename = "" )
+ {
+ std::cout << "DIR (" << dir + ") FILE (" + ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + filename + ") has event " << getActionName( action ) << std::endl;
+ }
+};
+
+efsw::WatchID handleWatchID( efsw::WatchID watchid )
+{
+ switch ( watchid )
+ {
+ case efsw::Errors::FileNotFound:
+ case efsw::Errors::FileRepeated:
+ case efsw::Errors::FileOutOfScope:
+ case efsw::Errors::FileRemote:
+ case efsw::Errors::Unspecified:
+ {
+ std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
+ break;
+ }
+ default:
+ {
+ std::cout << "Added WatchID: " << watchid << std::endl;
+ }
+ }
+
+ return watchid;
+}
+
+int main(int argc, char **argv)
+{
+ signal( SIGABRT , sigend );
+ signal( SIGINT , sigend );
+ signal( SIGTERM , sigend );
+
+ std::cout << "Press ^C to exit demo" << std::endl;
+
+ bool commonTest = true;
+ bool useGeneric = false;
+ std::string path;
+
+ if ( argc >= 2 )
+ {
+ path = std::string( argv[1] );
+
+ if ( efsw::FileSystem::isDirectory( path ) )
+ {
+ commonTest = false;
+ }
+
+ if ( argc >= 3 )
+ {
+ if ( std::string( argv[2] ) == "true" )
+ {
+ useGeneric = true;
+ }
+ }
+ }
+
+ UpdateListener * ul = new UpdateListener();
+
+ /// create the file watcher object
+ efsw::FileWatcher fileWatcher( useGeneric );
+
+ fileWatcher.followSymlinks( false );
+ fileWatcher.allowOutOfScopeLinks( false );
+
+ if ( commonTest )
+ {
+ std::string CurPath( efsw::System::getProcessPath() );
+
+ std::cout << "CurPath: " << CurPath.c_str() << std::endl;
+
+ /// add a watch to the system
+ handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) );
+
+ /// starts watching
+ fileWatcher.watch();
+
+ /// adds another watch after started watching...
+ efsw::System::sleep( 100 );
+
+ efsw::WatchID watchID = handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) );
+
+ /// delete the watch
+ if ( watchID > 0 )
+ {
+ efsw::System::sleep( 1000 );
+ fileWatcher.removeWatch( watchID );
+ }
+ }
+ else
+ {
+ efsw::WatchID err;
+
+ if ( ( err = fileWatcher.addWatch( path, ul, true ) ) > 0 )
+ {
+ fileWatcher.watch();
+
+ std::cout << "Watching directory: " << path.c_str() << std::endl;
+
+ if ( useGeneric )
+ {
+ std::cout << "Using generic backend watcher" << std::endl;
+ }
+ }
+ else
+ {
+ std::cout << "Error trying to watch directory: " << path.c_str() << std::endl;
+ std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl;
+ }
+ }
+
+ while( !STOP )
+ {
+ efsw::System::sleep( 100 );
+ }
+
+ return 0;
+}
diff --git a/dep/g3dlite/CMakeLists.txt b/dep/g3dlite/CMakeLists.txt
index f1166c72e6d..4e579951d63 100644
--- a/dep/g3dlite/CMakeLists.txt
+++ b/dep/g3dlite/CMakeLists.txt
@@ -8,7 +8,6 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
set(g3dlib_STAT_SRCS
source/AABox.cpp
source/Any.cpp
@@ -55,20 +54,18 @@ set(g3dlib_STAT_SRCS
source/Vector4.cpp
)
-if(WIN32)
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_SOURCE_DIR}/dep/zlib
- )
-else()
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- )
-endif()
-
add_library(g3dlib STATIC ${g3dlib_STAT_SRCS})
+target_include_directories(g3dlib
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
target_link_libraries(g3dlib
- ${ZLIB_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT}
-)
+ PUBLIC
+ zlib
+ threads)
+
+set_target_properties(g3dlib
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/gsoap/CMakeLists.txt b/dep/gsoap/CMakeLists.txt
index b5fed7809af..bdcadf6e4dc 100644
--- a/dep/gsoap/CMakeLists.txt
+++ b/dep/gsoap/CMakeLists.txt
@@ -10,17 +10,22 @@
file(GLOB sources *.cpp *.h)
-set(gsoap_STAT_SRCS
- ${sources}
-)
+add_library(gsoap STATIC ${sources})
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
+set_target_properties(gsoap PROPERTIES LINKER_LANGUAGE CXX)
-# Little fix for MSVC / Windows platforms
-add_definitions(-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=0)
+target_include_directories(gsoap
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
-add_library(gsoap STATIC ${gsoap_STAT_SRCS})
+set_target_properties(gsoap
+ PROPERTIES
+ FOLDER
+ "dep")
-set_target_properties(gsoap PROPERTIES LINKER_LANGUAGE CXX)
+if (MSVC)
+ # Little fix for MSVC / Windows platforms
+ target_compile_definitions(gsoap
+ PRIVATE
+ -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=0)
+endif()
diff --git a/dep/jemalloc/CMakeLists.txt b/dep/jemalloc/CMakeLists.txt
index cf0ac435f0a..6774e5a75d2 100644
--- a/dep/jemalloc/CMakeLists.txt
+++ b/dep/jemalloc/CMakeLists.txt
@@ -8,54 +8,79 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# We need to generate the jemalloc_def.h header based on platform-specific settings
-if (PLATFORM EQUAL 32)
- set(JEM_SIZEDEF 2)
- set(JEM_TLSMODEL)
+if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT NOJEM)
+ # We need to generate the jemalloc_def.h header based on platform-specific settings
+ if (PLATFORM EQUAL 32)
+ set(JEM_SIZEDEF 2)
+ set(JEM_TLSMODEL)
+ else()
+ set(JEM_SIZEDEF 3)
+ set(JEM_TLSMODEL "__attribute__\(\(tls_model\(\"initial-exec\"\)\)\)")
+ endif()
+
+ # Create the header, so we can use it
+ configure_file(
+ "${CMAKE_SOURCE_DIR}/dep/jemalloc/jemalloc_defs.h.in.cmake"
+ "${BUILDDIR}/jemalloc_defs.h"
+ @ONLY
+ )
+
+ # Done, let's continue
+ set(jemalloc_STAT_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/arena.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/atomic.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/base.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/bitmap.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_dss.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_mmap.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ckh.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ctl.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/extent.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hash.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/huge.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/jemalloc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/mb.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/mutex.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/prof.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/quarantine.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rtree.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/stats.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/tcache.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/tsd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
+ )
+
+ add_library(jemalloc STATIC ${jemalloc_STAT_SRC})
+
+ target_include_directories(jemalloc
+ PRIVATE
+ ${BUILDDIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+ target_compile_definitions(jemalloc
+ PUBLIC
+ -DNO_BUFFERPOOL
+ PRIVATE
+ -D_GNU_SOURCE
+ -D_REENTRAN)
+
+ target_link_libraries(jemalloc
+ PUBLIC
+ threads
+ valgrind)
+
+ set_target_properties(jemalloc
+ PROPERTIES
+ FOLDER
+ "dep")
+
else()
- set(JEM_SIZEDEF 3)
- set(JEM_TLSMODEL "__attribute__\(\(tls_model\(\"initial-exec\"\)\)\)")
-endif()
+ # Provide a dummy target for jemalloc which is used when jemalloc
+ # is disabled or not supported.
+ add_library(jemalloc INTERFACE)
+ target_link_libraries(jemalloc
+ INTERFACE
+ valgrind)
-# Create the header, so we can use it
-configure_file(
- "${CMAKE_SOURCE_DIR}/dep/jemalloc/jemalloc_defs.h.in.cmake"
- "${BUILDDIR}/jemalloc_defs.h"
- @ONLY
-)
-
-# Done, let's continue
-set(jemalloc_STAT_SRC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/arena.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/atomic.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/base.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/bitmap.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_dss.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/chunk_mmap.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/ckh.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/ctl.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/extent.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/hash.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/huge.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/jemalloc.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/mb.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/mutex.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/prof.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/quarantine.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/rtree.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/stats.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/tcache.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/tsd.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/util.c
-)
-
-include_directories(
- ${BUILDDIR}/
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${VALGRIND_INCLUDE_DIR}
-)
-
-add_definitions(-D_GNU_SOURCE -D_REENTRANT)
-
-add_library(jemalloc STATIC ${jemalloc_STAT_SRC})
+endif()
diff --git a/dep/libmpq/CMakeLists.txt b/dep/libmpq/CMakeLists.txt
index 1213e6b11b7..e8b420fca53 100644
--- a/dep/libmpq/CMakeLists.txt
+++ b/dep/libmpq/CMakeLists.txt
@@ -8,27 +8,29 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-file(GLOB sources_mpq libmpq/*.c libmpq/*.h)
+file(GLOB sources libmpq/*.c libmpq/*.h)
-set(mpq_STAT_SRCS
- ${sources_mpq}
-)
+add_library(mpq STATIC ${sources})
-if( UNIX )
- include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_SOURCE_DIR}/dep/zlib
- ${CMAKE_SOURCE_DIR}/dep/bzip2
- )
-elseif( WIN32 )
- include_directories(
+set_target_properties(mpq PROPERTIES LINKER_LANGUAGE CXX)
+
+if(WIN32)
+ set(WIN_EXTRA_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/win)
+endif()
+
+target_include_directories(mpq
+ PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/win
+ ${WIN_EXTRA_INCLUDE}
${CMAKE_SOURCE_DIR}/dep/zlib
- ${CMAKE_SOURCE_DIR}/dep/bzip2
- )
-endif()
+ ${CMAKE_SOURCE_DIR}/dep/bzip2)
-add_library(mpq STATIC ${mpq_STAT_SRCS})
+target_link_libraries(mpq
+ PUBLIC
+ zlib
+ bzip2)
-set_target_properties(mpq PROPERTIES LINKER_LANGUAGE CXX)
+set_target_properties(mpq
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/mysql/CMakeLists.txt b/dep/mysql/CMakeLists.txt
new file mode 100644
index 00000000000..472535b0356
--- /dev/null
+++ b/dep/mysql/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+if (NOT MYSQL_FOUND)
+ message(FATAL_ERROR "MySQL wasn't found on your system but it's required to build the servers!")
+endif()
+
+add_library(mysql STATIC IMPORTED GLOBAL)
+
+set_target_properties(mysql
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${MYSQL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${MYSQL_INCLUDE_DIR}")
diff --git a/dep/openssl/CMakeLists.txt b/dep/openssl/CMakeLists.txt
new file mode 100644
index 00000000000..98561b2a0ed
--- /dev/null
+++ b/dep/openssl/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+
+# basic packagesearching and setup
+# (further support will be needed, this is a preliminary release!)
+set(OPENSSL_EXPECTED_VERSION 1.0.0)
+
+find_package(OpenSSL REQUIRED)
+
+add_library(openssl INTERFACE)
+
+target_link_libraries(openssl
+ INTERFACE
+ ${OPENSSL_LIBRARIES})
+
+target_include_directories(openssl
+ INTERFACE
+ ${OPENSSL_INCLUDE_DIR})
diff --git a/dep/process/CMakeLists.txt b/dep/process/CMakeLists.txt
new file mode 100644
index 00000000000..5a51917a00c
--- /dev/null
+++ b/dep/process/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+add_library(process INTERFACE)
+
+target_include_directories(process
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+target_link_libraries(process
+ INTERFACE
+ boost)
diff --git a/dep/readline/CMakeLists.txt b/dep/readline/CMakeLists.txt
new file mode 100644
index 00000000000..0e8679ba718
--- /dev/null
+++ b/dep/readline/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+if( UNIX )
+ # find Readline (terminal input library) includes and library
+ #
+ # READLINE_INCLUDE_DIR - where the directory containing the READLINE headers can be found
+ # READLINE_LIBRARY - full path to the READLINE library
+ find_path(READLINE_INCLUDE_DIR readline/readline.h)
+ find_library(READLINE_LIBRARY NAMES readline)
+
+ message(STATUS "Found Readline library: ${READLINE_LIBRARY}")
+ message(STATUS "Include dir is: ${READLINE_INCLUDE_DIR}")
+
+ if (NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARY)
+ message(FATAL_ERROR "** Readline library not found!\n** Your distro may provide a binary for Readline e.g. for ubuntu try apt-get install libreadline5-dev")
+ endif ()
+
+ add_library(readline SHARED IMPORTED GLOBAL)
+
+ set_target_properties(readline
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${READLINE_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${READLINE_INCLUDE_DIR}")
+
+else()
+ # Provide a dummy target
+ add_library(readline INTERFACE)
+endif()
diff --git a/dep/recastnavigation/Detour/CMakeLists.txt b/dep/recastnavigation/Detour/CMakeLists.txt
index b21e4ca6273..12be71d32b4 100644
--- a/dep/recastnavigation/Detour/CMakeLists.txt
+++ b/dep/recastnavigation/Detour/CMakeLists.txt
@@ -16,14 +16,18 @@ set(Detour_STAT_SRCS
Source/DetourNavMeshQuery.cpp
Source/DetourNode.cpp
)
-include_directories(Include)
-
-if(WIN32)
- include_directories(
- ${CMAKE_SOURCE_DIR}/dep/zlib
- )
-endif()
add_library(Detour STATIC ${Detour_STAT_SRCS})
-target_link_libraries(Detour ${ZLIB_LIBRARIES})
+target_include_directories(Detour
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/Include)
+
+target_link_libraries(Detour
+ PUBLIC
+ zlib)
+
+set_target_properties(Detour
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/recastnavigation/Recast/CMakeLists.txt b/dep/recastnavigation/Recast/CMakeLists.txt
index 738c010eb05..1eac4e75399 100644
--- a/dep/recastnavigation/Recast/CMakeLists.txt
+++ b/dep/recastnavigation/Recast/CMakeLists.txt
@@ -14,21 +14,24 @@ set(Recast_STAT_SRCS
Source/RecastArea.cpp
Source/RecastContour.cpp
Source/RecastFilter.cpp
- Source/RecastLayers.cpp
+ Source/RecastLayers.cpp
Source/RecastMesh.cpp
Source/RecastMeshDetail.cpp
Source/RecastRasterization.cpp
Source/RecastRegion.cpp
)
-include_directories(Include)
+add_library(Recast STATIC ${Recast_STAT_SRCS})
-if(WIN32)
- include_directories(
- ${CMAKE_SOURCE_DIR}/dep/zlib
- )
-endif()
+target_include_directories(Recast
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/Include)
-add_library(Recast STATIC ${Recast_STAT_SRCS})
+target_link_libraries(Recast
+ PUBLIC
+ zlib)
-target_link_libraries(Recast ${ZLIB_LIBRARIES}) \ No newline at end of file
+set_target_properties(Recast
+ PROPERTIES
+ FOLDER
+ "dep")
diff --git a/dep/threads/CMakeLists.txt b/dep/threads/CMakeLists.txt
new file mode 100644
index 00000000000..48e5eb00723
--- /dev/null
+++ b/dep/threads/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+find_package(Threads REQUIRED)
+
+add_library(threads INTERFACE)
+target_link_libraries(threads
+ INTERFACE
+ ${CMAKE_THREAD_LIBS_INIT})
diff --git a/dep/utf8cpp/CMakeLists.txt b/dep/utf8cpp/CMakeLists.txt
new file mode 100644
index 00000000000..edf8604d44c
--- /dev/null
+++ b/dep/utf8cpp/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+add_library(utf8cpp INTERFACE)
+
+target_include_directories(utf8cpp
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/dep/valgrind/CMakeLists.txt b/dep/valgrind/CMakeLists.txt
new file mode 100644
index 00000000000..d67cd33b426
--- /dev/null
+++ b/dep/valgrind/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author 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.
+
+add_library(valgrind INTERFACE)
+
+target_include_directories(valgrind
+ INTERFACE
+ "${VALGRIND_INCLUDE_DIR}")
diff --git a/dep/zlib/CMakeLists.txt b/dep/zlib/CMakeLists.txt
index 7feb134bcd5..b3e3d58fe55 100644
--- a/dep/zlib/CMakeLists.txt
+++ b/dep/zlib/CMakeLists.txt
@@ -8,22 +8,43 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-SET(zlib_STAT_SRCS
- adler32.c
- compress.c
- crc32.c
- deflate.c
- infback.c
- inffast.c
- inflate.c
- inftrees.c
- trees.c
- uncompr.c
- zutil.c
-)
+if(UNIX)
+ # Look for an installed zlib on unix
+ find_package(ZLIB REQUIRED)
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
-)
+ add_library(zlib SHARED IMPORTED GLOBAL)
-add_library(zlib STATIC ${zlib_STAT_SRCS})
+ set_target_properties(zlib
+ PROPERTIES
+ IMPORTED_LOCATION
+ "${ZLIB_LIBRARIES}"
+ INTERFACE_INCLUDE_DIRECTORIES
+ "${ZLIB_INCLUDE_DIRS}")
+else()
+ # Use the bundled source on windows
+ SET(zlib_STAT_SRCS
+ adler32.c
+ compress.c
+ crc32.c
+ deflate.c
+ infback.c
+ inffast.c
+ inflate.c
+ inftrees.c
+ trees.c
+ uncompr.c
+ zutil.c
+ )
+
+ add_library(zlib STATIC
+ ${zlib_STAT_SRCS})
+
+ target_include_directories(zlib
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR})
+
+ set_target_properties(zlib
+ PROPERTIES
+ FOLDER
+ "dep")
+endif()