diff options
Diffstat (limited to '')
79 files changed, 10083 insertions, 15 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 031af18..7532f81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -31,14 +31,116 @@ enable_language(CXX) | |||
| 31 | include_directories(src src/3rdParty ${LUA_INCLUDE_DIR}) | 31 | include_directories(src src/3rdParty ${LUA_INCLUDE_DIR}) |
| 32 | add_definitions(-std=c++17 -O3 -fPIC) | 32 | add_definitions(-std=c++17 -O3 -fPIC) |
| 33 | 33 | ||
| 34 | add_library(libyue MODULE src/yuescript/ast.cpp src/yuescript/parser.cpp src/yuescript/yue_parser.cpp src/yuescript/yue_compiler.cpp src/yuescript/yuescript.cpp) | 34 | add_library(libyue MODULE |
| 35 | src/yuescript/ast.cpp | ||
| 36 | src/yuescript/parser.cpp | ||
| 37 | src/yuescript/yue_parser.cpp | ||
| 38 | src/yuescript/yue_compiler.cpp | ||
| 39 | src/yuescript/yuescript.cpp | ||
| 40 | ) | ||
| 35 | set_target_properties(libyue PROPERTIES PREFIX "") | 41 | set_target_properties(libyue PROPERTIES PREFIX "") |
| 36 | set_target_properties(libyue PROPERTIES OUTPUT_NAME "yue") | 42 | set_target_properties(libyue PROPERTIES OUTPUT_NAME "yue") |
| 37 | target_link_libraries(libyue ${LUA_LIBRARIES}) | 43 | target_link_libraries(libyue ${LUA_LIBRARIES}) |
| 38 | 44 | ||
| 45 | add_executable(yue | ||
| 46 | src/yuescript/ast.cpp | ||
| 47 | src/yuescript/yue_compiler.cpp | ||
| 48 | src/yuescript/yue_parser.cpp | ||
| 49 | src/yuescript/yuescript.cpp | ||
| 50 | src/yuescript/parser.cpp | ||
| 51 | src/yue.cpp | ||
| 52 | ) | ||
| 53 | |||
| 54 | target_sources(yue PRIVATE | ||
| 55 | src/3rdParty/efsw/Debug.cpp | ||
| 56 | src/3rdParty/efsw/DirectorySnapshot.cpp | ||
| 57 | src/3rdParty/efsw/DirectorySnapshotDiff.cpp | ||
| 58 | src/3rdParty/efsw/DirWatcherGeneric.cpp | ||
| 59 | src/3rdParty/efsw/FileInfo.cpp | ||
| 60 | src/3rdParty/efsw/FileSystem.cpp | ||
| 61 | src/3rdParty/efsw/FileWatcher.cpp | ||
| 62 | src/3rdParty/efsw/FileWatcherCWrapper.cpp | ||
| 63 | src/3rdParty/efsw/FileWatcherGeneric.cpp | ||
| 64 | src/3rdParty/efsw/FileWatcherImpl.cpp | ||
| 65 | src/3rdParty/efsw/Log.cpp | ||
| 66 | src/3rdParty/efsw/Mutex.cpp | ||
| 67 | src/3rdParty/efsw/String.cpp | ||
| 68 | src/3rdParty/efsw/System.cpp | ||
| 69 | src/3rdParty/efsw/Thread.cpp | ||
| 70 | src/3rdParty/efsw/Watcher.cpp | ||
| 71 | src/3rdParty/efsw/WatcherGeneric.cpp | ||
| 72 | ) | ||
| 73 | |||
| 74 | if (WIN32) | ||
| 75 | target_sources(yue PRIVATE | ||
| 76 | src/3rdParty/efsw/platform/win/FileSystemImpl.cpp | ||
| 77 | src/3rdParty/efsw/platform/win/MutexImpl.cpp | ||
| 78 | src/3rdParty/efsw/platform/win/SystemImpl.cpp | ||
| 79 | src/3rdParty/efsw/platform/win/ThreadImpl.cpp | ||
| 80 | ) | ||
| 81 | else () | ||
| 82 | target_sources(yue PRIVATE | ||
| 83 | src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp | ||
| 84 | src/3rdParty/efsw/platform/posix/MutexImpl.cpp | ||
| 85 | src/3rdParty/efsw/platform/posix/SystemImpl.cpp | ||
| 86 | src/3rdParty/efsw/platform/posix/ThreadImpl.cpp | ||
| 87 | ) | ||
| 88 | endif() | ||
| 89 | |||
| 90 | if (APPLE) | ||
| 91 | target_sources(yue PRIVATE | ||
| 92 | src/3rdParty/efsw/FileWatcherFSEvents.cpp | ||
| 93 | src/3rdParty/efsw/FileWatcherKqueue.cpp | ||
| 94 | src/3rdParty/efsw/WatcherFSEvents.cpp | ||
| 95 | src/3rdParty/efsw/WatcherKqueue.cpp | ||
| 96 | ) | ||
| 97 | |||
| 98 | if (NOT CMAKE_SYSTEM_VERSION GREATER 9) | ||
| 99 | target_compile_definitions(yue PRIVATE EFSW_FSEVENTS_NOT_SUPPORTED) | ||
| 100 | endif() | ||
| 101 | elseif (WIN32) | ||
| 102 | target_sources(yue PRIVATE | ||
| 103 | src/3rdParty/efsw/FileWatcherWin32.cpp | ||
| 104 | src/3rdParty/efsw/WatcherWin32.cpp | ||
| 105 | ) | ||
| 106 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") | ||
| 107 | target_sources(yue PRIVATE | ||
| 108 | src/3rdParty/efsw/FileWatcherInotify.cpp | ||
| 109 | src/3rdParty/efsw/WatcherInotify.cpp | ||
| 110 | ) | ||
| 111 | |||
| 112 | if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h") | ||
| 113 | target_compile_definitions(yue PRIVATE EFSW_INOTIFY_NOSYS) | ||
| 114 | endif() | ||
| 115 | elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") | ||
| 116 | target_sources(yue PRIVATE | ||
| 117 | src/3rdParty/efsw/FileWatcherKqueue.cpp | ||
| 118 | src/3rdParty/efsw/WatcherKqueue.cpp | ||
| 119 | ) | ||
| 120 | endif() | ||
| 121 | |||
| 122 | if (MSVC) | ||
| 123 | target_compile_definitions(yue PRIVATE _SCL_SECURE_NO_WARNINGS) | ||
| 124 | else () | ||
| 125 | target_compile_options(yue PRIVATE -Wall -Wno-long-long -fPIC) | ||
| 126 | endif() | ||
| 127 | |||
| 128 | if (${CMAKE_BUILD_TYPE} MATCHES "Debug") | ||
| 129 | target_compile_definitions(yue PRIVATE DEBUG) | ||
| 130 | elseif (${CMAKE_BUILD_TYPE} MATCHES "Release") | ||
| 131 | target_compile_definitions(yue PRIVATE NDEBUG) | ||
| 132 | endif() | ||
| 133 | |||
| 39 | find_package(Threads REQUIRED) | 134 | find_package(Threads REQUIRED) |
| 40 | add_executable(yue src/yuescript/ast.cpp src/yuescript/yue_compiler.cpp src/yuescript/yue_parser.cpp src/yuescript/yuescript.cpp src/yuescript/parser.cpp src/yue.cpp) | 135 | if (APPLE) |
| 41 | target_link_libraries(yue ${LUA_LIBRARIES} Threads::Threads) | 136 | set(MAC_LIBS "-framework CoreFoundation" "-framework CoreServices") |
| 137 | target_link_libraries(yue PRIVATE ${LUA_LIBRARIES} ${MAC_LIBS} Threads::Threads) | ||
| 138 | elseif (NOT (${CMAKE_SYSTEM_NAME} MATCHES "Haiku") AND NOT WIN32) | ||
| 139 | target_link_libraries(yue PRIVATE ${LUA_LIBRARIES} Threads::Threads) | ||
| 140 | else () | ||
| 141 | target_link_libraries(yue PRIVATE ${LUA_LIBRARIES}) | ||
| 142 | endif() | ||
| 143 | |||
| 42 | IF(CMAKE_DL_LIBS) | 144 | IF(CMAKE_DL_LIBS) |
| 43 | target_link_libraries(yue ${CMAKE_DL_LIBS}) | 145 | target_link_libraries(yue ${CMAKE_DL_LIBS}) |
| 44 | ENDIF(CMAKE_DL_LIBS) | 146 | ENDIF(CMAKE_DL_LIBS) |
| @@ -59,6 +59,8 @@ endif | |||
| 59 | ifneq ($(UNAME_S),Darwin) | 59 | ifneq ($(UNAME_S),Darwin) |
| 60 | LINK_FLAGS += -lstdc++fs -Wl,-E | 60 | LINK_FLAGS += -lstdc++fs -Wl,-E |
| 61 | PLAT = linux | 61 | PLAT = linux |
| 62 | else | ||
| 63 | LINK_FLAGS += -framework CoreFoundation -framework CoreServices | ||
| 62 | endif | 64 | endif |
| 63 | 65 | ||
| 64 | # Function used to check variables. Use on the command line: | 66 | # Function used to check variables. Use on the command line: |
| @@ -123,6 +125,7 @@ ifeq ($(SOURCES),) | |||
| 123 | endif | 125 | endif |
| 124 | 126 | ||
| 125 | SOURCES := $(filter-out $(SRC_PATH)/yue_wasm.cpp, $(SOURCES)) | 127 | SOURCES := $(filter-out $(SRC_PATH)/yue_wasm.cpp, $(SOURCES)) |
| 128 | SOURCES := $(filter-out $(SRC_PATH)/3rdParty/%, $(SOURCES)) | ||
| 126 | 129 | ||
| 127 | ifeq ($(NO_LUA),true) | 130 | ifeq ($(NO_LUA),true) |
| 128 | SOURCES := $(filter-out $(SRC_PATH)/yuescript/yuescript.cpp, $(SOURCES)) | 131 | SOURCES := $(filter-out $(SRC_PATH)/yuescript/yuescript.cpp, $(SOURCES)) |
| @@ -134,6 +137,8 @@ OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o) | |||
| 134 | # Set the dependency files that will be used to add header dependencies | 137 | # Set the dependency files that will be used to add header dependencies |
| 135 | DEPS = $(OBJECTS:.o=.d) | 138 | DEPS = $(OBJECTS:.o=.d) |
| 136 | 139 | ||
| 140 | SOURCES += $(SRC_PATH)/3rdParty/efsw/Debug.cpp $(SRC_PATH)/3rdParty/efsw/DirectorySnapshot.cpp $(SRC_PATH)/3rdParty/efsw/DirectorySnapshotDiff.cpp $(SRC_PATH)/3rdParty/efsw/DirWatcherGeneric.cpp $(SRC_PATH)/3rdParty/efsw/FileInfo.cpp $(SRC_PATH)/3rdParty/efsw/FileSystem.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcher.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcherCWrapper.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcherGeneric.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcherImpl.cpp $(SRC_PATH)/3rdParty/efsw/Log.cpp $(SRC_PATH)/3rdParty/efsw/Mutex.cpp $(SRC_PATH)/3rdParty/efsw/String.cpp $(SRC_PATH)/3rdParty/efsw/System.cpp $(SRC_PATH)/3rdParty/efsw/Thread.cpp $(SRC_PATH)/3rdParty/efsw/Watcher.cpp $(SRC_PATH)/3rdParty/efsw/WatcherGeneric.cpp $(SRC_PATH)/3rdParty/efsw/platform/posix/FileSystemImpl.cpp $(SRC_PATH)/3rdParty/efsw/platform/posix/MutexImpl.cpp $(SRC_PATH)/3rdParty/efsw/platform/posix/SystemImpl.cpp $(SRC_PATH)/3rdParty/efsw/platform/posix/ThreadImpl.cpp | ||
| 141 | |||
| 137 | # Macros for timing compilation | 142 | # Macros for timing compilation |
| 138 | ifeq ($(UNAME_S),Darwin) | 143 | ifeq ($(UNAME_S),Darwin) |
| 139 | CUR_TIME = awk 'BEGIN{srand(); print srand()}' | 144 | CUR_TIME = awk 'BEGIN{srand(); print srand()}' |
| @@ -143,6 +148,7 @@ ifeq ($(UNAME_S),Darwin) | |||
| 143 | $(RM) $(TIME_FILE) ; \ | 148 | $(RM) $(TIME_FILE) ; \ |
| 144 | st=$$((`$(CUR_TIME)` - $$st)) ; \ | 149 | st=$$((`$(CUR_TIME)` - $$st)) ; \ |
| 145 | echo $$st | 150 | echo $$st |
| 151 | SOURCES += $(SRC_PATH)/3rdParty/efsw/FileWatcherFSEvents.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcherKqueue.cpp $(SRC_PATH)/3rdParty/efsw/WatcherFSEvents.cpp $(SRC_PATH)/3rdParty/efsw/WatcherKqueue.cpp | ||
| 146 | else | 152 | else |
| 147 | TIME_FILE = $(dir $@).$(notdir $@)_time | 153 | TIME_FILE = $(dir $@).$(notdir $@)_time |
| 148 | START_TIME = date '+%s' > $(TIME_FILE) | 154 | START_TIME = date '+%s' > $(TIME_FILE) |
| @@ -150,6 +156,7 @@ else | |||
| 150 | $(RM) $(TIME_FILE) ; \ | 156 | $(RM) $(TIME_FILE) ; \ |
| 151 | st=$$((`date '+%s'` - $$st - 86400)) ; \ | 157 | st=$$((`date '+%s'` - $$st - 86400)) ; \ |
| 152 | echo `date -u -d @$$st '+%H:%M:%S'` | 158 | echo `date -u -d @$$st '+%H:%M:%S'` |
| 159 | SOURCES += $(SRC_PATH)/3rdParty/efsw/FileWatcherFSEvents.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcherKqueue.cpp $(SRC_PATH)/3rdParty/efsw/WatcherFSEvents.cpp $(SRC_PATH)/3rdParty/efsw/WatcherKqueue.cpp $(SRC_PATH)/3rdParty/efsw/FileWatcherInotify.cpp $(SRC_PATH)/3rdParty/efsw/WatcherInotify.cpp | ||
| 153 | endif | 160 | endif |
| 154 | 161 | ||
| 155 | # Version macros | 162 | # Version macros |
diff --git a/src/3rdParty/efsw/Atomic.hpp b/src/3rdParty/efsw/Atomic.hpp new file mode 100755 index 0000000..4008dfc --- /dev/null +++ b/src/3rdParty/efsw/Atomic.hpp | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #ifndef EFSW_ATOMIC_BOOL_HPP | ||
| 2 | #define EFSW_ATOMIC_BOOL_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #ifdef EFSW_USE_CXX11 | ||
| 7 | #include <atomic> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | namespace efsw { | ||
| 11 | |||
| 12 | template <typename T> class Atomic { | ||
| 13 | public: | ||
| 14 | explicit Atomic( T set = false ) : set_( set ) {} | ||
| 15 | |||
| 16 | Atomic& operator=( T set ) { | ||
| 17 | #ifdef EFSW_USE_CXX11 | ||
| 18 | set_.store( set, std::memory_order_release ); | ||
| 19 | #else | ||
| 20 | set_ = set; | ||
| 21 | #endif | ||
| 22 | return *this; | ||
| 23 | } | ||
| 24 | |||
| 25 | explicit operator T() const { | ||
| 26 | #ifdef EFSW_USE_CXX11 | ||
| 27 | return set_.load( std::memory_order_acquire ); | ||
| 28 | #else | ||
| 29 | return set_; | ||
| 30 | #endif | ||
| 31 | } | ||
| 32 | |||
| 33 | T load() const { | ||
| 34 | #ifdef EFSW_USE_CXX11 | ||
| 35 | return set_.load( std::memory_order_acquire ); | ||
| 36 | #else | ||
| 37 | return set_; | ||
| 38 | #endif | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | #ifdef EFSW_USE_CXX11 | ||
| 43 | std::atomic<T> set_; | ||
| 44 | #else | ||
| 45 | volatile T set_; | ||
| 46 | #endif | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace efsw | ||
| 50 | |||
| 51 | #endif | ||
diff --git a/src/3rdParty/efsw/Debug.cpp b/src/3rdParty/efsw/Debug.cpp new file mode 100755 index 0000000..18cfd31 --- /dev/null +++ b/src/3rdParty/efsw/Debug.cpp | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | #include <efsw/Debug.hpp> | ||
| 2 | #include <iostream> | ||
| 3 | |||
| 4 | #ifdef EFSW_COMPILER_MSVC | ||
| 5 | #define WIN32_LEAN_AND_MEAN | ||
| 6 | #include <crtdbg.h> | ||
| 7 | #include <windows.h> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #include <cassert> | ||
| 11 | #include <cstdarg> | ||
| 12 | #include <cstdio> | ||
| 13 | |||
| 14 | namespace efsw { | ||
| 15 | |||
| 16 | #ifdef DEBUG | ||
| 17 | |||
| 18 | void efREPORT_ASSERT( const char* File, int Line, const char* Exp ) { | ||
| 19 | #ifdef EFSW_COMPILER_MSVC | ||
| 20 | _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp ); | ||
| 21 | |||
| 22 | DebugBreak(); | ||
| 23 | #else | ||
| 24 | std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl; | ||
| 25 | |||
| 26 | #if defined( EFSW_COMPILER_GCC ) && defined( EFSW_32BIT ) && !defined( EFSW_ARM ) | ||
| 27 | asm( "int3" ); | ||
| 28 | #else | ||
| 29 | assert( false ); | ||
| 30 | #endif | ||
| 31 | #endif | ||
| 32 | } | ||
| 33 | |||
| 34 | void efPRINT( const char* format, ... ) { | ||
| 35 | char buf[2048]; | ||
| 36 | va_list args; | ||
| 37 | |||
| 38 | va_start( args, format ); | ||
| 39 | |||
| 40 | #ifdef EFSW_COMPILER_MSVC | ||
| 41 | _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0] ), format, args ); | ||
| 42 | #else | ||
| 43 | vsnprintf( buf, sizeof( buf ) / sizeof( buf[0] ), format, args ); | ||
| 44 | #endif | ||
| 45 | |||
| 46 | va_end( args ); | ||
| 47 | |||
| 48 | #ifdef EFSW_COMPILER_MSVC | ||
| 49 | OutputDebugStringA( buf ); | ||
| 50 | #else | ||
| 51 | std::cout << buf; | ||
| 52 | #endif | ||
| 53 | } | ||
| 54 | |||
| 55 | void efPRINTC( unsigned int cond, const char* format, ... ) { | ||
| 56 | if ( 0 == cond ) | ||
| 57 | return; | ||
| 58 | |||
| 59 | char buf[2048]; | ||
| 60 | va_list args; | ||
| 61 | |||
| 62 | va_start( args, format ); | ||
| 63 | |||
| 64 | #ifdef EFSW_COMPILER_MSVC | ||
| 65 | _vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args ); | ||
| 66 | #else | ||
| 67 | vsnprintf( buf, sizeof( buf ) / sizeof( buf[0] ), format, args ); | ||
| 68 | #endif | ||
| 69 | |||
| 70 | va_end( args ); | ||
| 71 | |||
| 72 | #ifdef EFSW_COMPILER_MSVC | ||
| 73 | OutputDebugStringA( buf ); | ||
| 74 | #else | ||
| 75 | std::cout << buf; | ||
| 76 | #endif | ||
| 77 | } | ||
| 78 | |||
| 79 | #endif | ||
| 80 | |||
| 81 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/Debug.hpp b/src/3rdParty/efsw/Debug.hpp new file mode 100755 index 0000000..78d3557 --- /dev/null +++ b/src/3rdParty/efsw/Debug.hpp | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #ifndef EFSW_DEBUG_HPP | ||
| 2 | #define EFSW_DEBUG_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | #ifdef DEBUG | ||
| 9 | |||
| 10 | void efREPORT_ASSERT( const char* File, const int Line, const char* Exp ); | ||
| 11 | |||
| 12 | #define efASSERT( expr ) \ | ||
| 13 | if ( !( expr ) ) { \ | ||
| 14 | efREPORT_ASSERT( __FILE__, __LINE__, #expr ); \ | ||
| 15 | } | ||
| 16 | #define efASSERTM( expr, msg ) \ | ||
| 17 | if ( !( expr ) ) { \ | ||
| 18 | efREPORT_ASSERT( __FILE__, __LINE__, #msg ); \ | ||
| 19 | } | ||
| 20 | |||
| 21 | void efPRINT( const char* format, ... ); | ||
| 22 | void efPRINTC( unsigned int cond, const char* format, ... ); | ||
| 23 | |||
| 24 | #else | ||
| 25 | |||
| 26 | #define efASSERT( expr ) | ||
| 27 | #define efASSERTM( expr, msg ) | ||
| 28 | |||
| 29 | #ifndef EFSW_COMPILER_MSVC | ||
| 30 | #define efPRINT( format, args... ) \ | ||
| 31 | {} | ||
| 32 | #define efPRINTC( cond, format, args... ) \ | ||
| 33 | {} | ||
| 34 | #else | ||
| 35 | #define efPRINT | ||
| 36 | #define efPRINTC | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #endif | ||
| 40 | |||
| 41 | #ifdef EFSW_VERBOSE | ||
| 42 | #define efDEBUG efPRINT | ||
| 43 | #define efDEBUGC efPRINTC | ||
| 44 | #else | ||
| 45 | |||
| 46 | #ifndef EFSW_COMPILER_MSVC | ||
| 47 | #define efDEBUG( format, args... ) \ | ||
| 48 | {} | ||
| 49 | #define efDEBUGC( cond, format, args... ) \ | ||
| 50 | {} | ||
| 51 | #else | ||
| 52 | #define efDEBUG | ||
| 53 | #define efDEBUGC | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #endif | ||
| 57 | |||
| 58 | } // namespace efsw | ||
| 59 | |||
| 60 | #endif | ||
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.cpp b/src/3rdParty/efsw/DirWatcherGeneric.cpp new file mode 100755 index 0000000..8b6bc8a --- /dev/null +++ b/src/3rdParty/efsw/DirWatcherGeneric.cpp | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | #include <efsw/Debug.hpp> | ||
| 2 | #include <efsw/DirWatcherGeneric.hpp> | ||
| 3 | #include <efsw/FileSystem.hpp> | ||
| 4 | #include <efsw/String.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws, | ||
| 9 | const std::string& directory, bool recursive, | ||
| 10 | bool reportNewFiles ) : | ||
| 11 | Parent( parent ), Watch( ws ), Recursive( recursive ), Deleted( false ) { | ||
| 12 | resetDirectory( directory ); | ||
| 13 | |||
| 14 | if ( !reportNewFiles ) { | ||
| 15 | DirSnap.scan(); | ||
| 16 | } else { | ||
| 17 | DirectorySnapshotDiff Diff = DirSnap.scan(); | ||
| 18 | |||
| 19 | if ( Diff.changed() ) { | ||
| 20 | FileInfoList::iterator it; | ||
| 21 | |||
| 22 | DiffIterator( FilesCreated ) { | ||
| 23 | handleAction( ( *it ).Filepath, Actions::Add ); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | DirWatcherGeneric::~DirWatcherGeneric() { | ||
| 30 | /// If the directory was deleted mark the files as deleted | ||
| 31 | if ( Deleted ) { | ||
| 32 | DirectorySnapshotDiff Diff = DirSnap.scan(); | ||
| 33 | |||
| 34 | if ( !DirSnap.exists() ) { | ||
| 35 | FileInfoList::iterator it; | ||
| 36 | |||
| 37 | DiffIterator( FilesDeleted ) { | ||
| 38 | handleAction( ( *it ).Filepath, Actions::Delete ); | ||
| 39 | } | ||
| 40 | |||
| 41 | DiffIterator( DirsDeleted ) { | ||
| 42 | handleAction( ( *it ).Filepath, Actions::Delete ); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | DirWatchMap::iterator it = Directories.begin(); | ||
| 48 | |||
| 49 | for ( ; it != Directories.end(); ++it ) { | ||
| 50 | if ( Deleted ) { | ||
| 51 | /// If the directory was deleted, mark the flag for file deletion | ||
| 52 | it->second->Deleted = true; | ||
| 53 | } | ||
| 54 | |||
| 55 | efSAFE_DELETE( it->second ); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | void DirWatcherGeneric::resetDirectory( std::string directory ) { | ||
| 60 | std::string dir( directory ); | ||
| 61 | |||
| 62 | /// Is this a recursive watch? | ||
| 63 | if ( Watch->Directory != directory ) { | ||
| 64 | if ( !( directory.size() && | ||
| 65 | ( directory.at( 0 ) == FileSystem::getOSSlash() || | ||
| 66 | directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) ) { | ||
| 67 | /// Get the real directory | ||
| 68 | if ( NULL != Parent ) { | ||
| 69 | std::string parentPath( Parent->DirSnap.DirectoryInfo.Filepath ); | ||
| 70 | FileSystem::dirAddSlashAtEnd( parentPath ); | ||
| 71 | FileSystem::dirAddSlashAtEnd( directory ); | ||
| 72 | |||
| 73 | dir = parentPath + directory; | ||
| 74 | } else { | ||
| 75 | efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." ); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | DirSnap.setDirectoryInfo( dir ); | ||
| 81 | } | ||
| 82 | |||
| 83 | void DirWatcherGeneric::handleAction( const std::string& filename, unsigned long action, | ||
| 84 | std::string oldFilename ) { | ||
| 85 | Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, | ||
| 86 | FileSystem::fileNameFromPath( filename ), (Action)action, | ||
| 87 | oldFilename ); | ||
| 88 | } | ||
| 89 | |||
| 90 | void DirWatcherGeneric::addChilds( bool reportNewFiles ) { | ||
| 91 | if ( Recursive ) { | ||
| 92 | /// Create the subdirectories watchers | ||
| 93 | std::string dir; | ||
| 94 | |||
| 95 | for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ ) { | ||
| 96 | if ( it->second.isDirectory() && it->second.isReadable() && | ||
| 97 | !FileSystem::isRemoteFS( it->second.Filepath ) ) { | ||
| 98 | /// Check if the directory is a symbolic link | ||
| 99 | std::string curPath; | ||
| 100 | std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) ); | ||
| 101 | |||
| 102 | dir = it->first; | ||
| 103 | |||
| 104 | if ( "" != link ) { | ||
| 105 | /// Avoid adding symlinks directories if it's now enabled | ||
| 106 | if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) { | ||
| 107 | continue; | ||
| 108 | } | ||
| 109 | |||
| 110 | /// If it's a symlink check if the realpath exists as a watcher, or | ||
| 111 | /// if the path is outside the current dir | ||
| 112 | if ( Watch->WatcherImpl->pathInWatches( link ) || | ||
| 113 | Watch->pathInWatches( link ) || | ||
| 114 | !Watch->WatcherImpl->linkAllowed( curPath, link ) ) { | ||
| 115 | continue; | ||
| 116 | } else { | ||
| 117 | dir = link; | ||
| 118 | } | ||
| 119 | } else { | ||
| 120 | if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) { | ||
| 121 | continue; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | if ( reportNewFiles ) { | ||
| 126 | handleAction( dir, Actions::Add ); | ||
| 127 | } | ||
| 128 | |||
| 129 | Directories[dir] = | ||
| 130 | new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles ); | ||
| 131 | |||
| 132 | Directories[dir]->addChilds( reportNewFiles ); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | void DirWatcherGeneric::watch( bool reportOwnChange ) { | ||
| 139 | DirectorySnapshotDiff Diff = DirSnap.scan(); | ||
| 140 | |||
| 141 | if ( reportOwnChange && Diff.DirChanged && NULL != Parent ) { | ||
| 142 | Watch->Listener->handleFileAction( | ||
| 143 | Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), | ||
| 144 | FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified ); | ||
| 145 | } | ||
| 146 | |||
| 147 | if ( Diff.changed() ) { | ||
| 148 | FileInfoList::iterator it; | ||
| 149 | MovedList::iterator mit; | ||
| 150 | |||
| 151 | /// Files | ||
| 152 | DiffIterator( FilesCreated ) { | ||
| 153 | handleAction( ( *it ).Filepath, Actions::Add ); | ||
| 154 | } | ||
| 155 | |||
| 156 | DiffIterator( FilesModified ) { | ||
| 157 | handleAction( ( *it ).Filepath, Actions::Modified ); | ||
| 158 | } | ||
| 159 | |||
| 160 | DiffIterator( FilesDeleted ) { | ||
| 161 | handleAction( ( *it ).Filepath, Actions::Delete ); | ||
| 162 | } | ||
| 163 | |||
| 164 | DiffMovedIterator( FilesMoved ) { | ||
| 165 | handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first ); | ||
| 166 | } | ||
| 167 | |||
| 168 | /// Directories | ||
| 169 | DiffIterator( DirsCreated ) { | ||
| 170 | createDirectory( ( *it ).Filepath ); | ||
| 171 | } | ||
| 172 | |||
| 173 | DiffIterator( DirsModified ) { | ||
| 174 | handleAction( ( *it ).Filepath, Actions::Modified ); | ||
| 175 | } | ||
| 176 | |||
| 177 | DiffIterator( DirsDeleted ) { | ||
| 178 | handleAction( ( *it ).Filepath, Actions::Delete ); | ||
| 179 | removeDirectory( ( *it ).Filepath ); | ||
| 180 | } | ||
| 181 | |||
| 182 | DiffMovedIterator( DirsMoved ) { | ||
| 183 | handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first ); | ||
| 184 | moveDirectory( ( *mit ).first, ( *mit ).second.Filepath ); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | /// Process the subdirectories looking for changes | ||
| 189 | for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); ++dit ) { | ||
| 190 | /// Just watch | ||
| 191 | dit->second->watch(); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | void DirWatcherGeneric::watchDir( std::string& dir ) { | ||
| 196 | DirWatcherGeneric* watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() | ||
| 197 | ? findDirWatcher( dir ) | ||
| 198 | : findDirWatcherFast( dir ); | ||
| 199 | |||
| 200 | if ( NULL != watcher ) { | ||
| 201 | watcher->watch( true ); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | DirWatcherGeneric* DirWatcherGeneric::findDirWatcherFast( std::string dir ) { | ||
| 206 | // remove the common base ( dir should always start with the same base as the watcher ) | ||
| 207 | efASSERT( !dir.empty() ); | ||
| 208 | efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ); | ||
| 209 | efASSERT( DirSnap.DirectoryInfo.Filepath == | ||
| 210 | dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) ); | ||
| 211 | |||
| 212 | if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ) { | ||
| 213 | dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 ); | ||
| 214 | } | ||
| 215 | |||
| 216 | if ( dir.size() == 1 ) { | ||
| 217 | efASSERT( dir[0] == FileSystem::getOSSlash() ); | ||
| 218 | return this; | ||
| 219 | } | ||
| 220 | |||
| 221 | size_t level = 0; | ||
| 222 | std::vector<std::string> dirv = String::split( dir, FileSystem::getOSSlash(), false ); | ||
| 223 | |||
| 224 | DirWatcherGeneric* watcher = this; | ||
| 225 | |||
| 226 | while ( level < dirv.size() ) { | ||
| 227 | // search the dir level in the current watcher | ||
| 228 | DirWatchMap::iterator it = watcher->Directories.find( dirv[level] ); | ||
| 229 | |||
| 230 | // found? continue with the next level | ||
| 231 | if ( it != watcher->Directories.end() ) { | ||
| 232 | watcher = it->second; | ||
| 233 | |||
| 234 | level++; | ||
| 235 | } else { | ||
| 236 | // couldn't found the folder level? | ||
| 237 | // directory not watched | ||
| 238 | return NULL; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | return watcher; | ||
| 243 | } | ||
| 244 | |||
| 245 | DirWatcherGeneric* DirWatcherGeneric::findDirWatcher( std::string dir ) { | ||
| 246 | if ( DirSnap.DirectoryInfo.Filepath == dir ) { | ||
| 247 | return this; | ||
| 248 | } else { | ||
| 249 | DirWatcherGeneric* watcher = NULL; | ||
| 250 | |||
| 251 | for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) { | ||
| 252 | watcher = it->second->findDirWatcher( dir ); | ||
| 253 | |||
| 254 | if ( NULL != watcher ) { | ||
| 255 | return watcher; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | return NULL; | ||
| 261 | } | ||
| 262 | |||
| 263 | DirWatcherGeneric* DirWatcherGeneric::createDirectory( std::string newdir ) { | ||
| 264 | FileSystem::dirRemoveSlashAtEnd( newdir ); | ||
| 265 | newdir = FileSystem::fileNameFromPath( newdir ); | ||
| 266 | |||
| 267 | DirWatcherGeneric* dw = NULL; | ||
| 268 | |||
| 269 | /// Check if the directory is a symbolic link | ||
| 270 | std::string parentPath( DirSnap.DirectoryInfo.Filepath ); | ||
| 271 | FileSystem::dirAddSlashAtEnd( parentPath ); | ||
| 272 | std::string dir( parentPath + newdir ); | ||
| 273 | |||
| 274 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 275 | |||
| 276 | FileInfo fi( dir ); | ||
| 277 | |||
| 278 | if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) ) { | ||
| 279 | return NULL; | ||
| 280 | } | ||
| 281 | |||
| 282 | std::string curPath; | ||
| 283 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 284 | bool skip = false; | ||
| 285 | |||
| 286 | if ( "" != link ) { | ||
| 287 | /// Avoid adding symlinks directories if it's now enabled | ||
| 288 | if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) { | ||
| 289 | skip = true; | ||
| 290 | } | ||
| 291 | |||
| 292 | /// If it's a symlink check if the realpath exists as a watcher, or | ||
| 293 | /// if the path is outside the current dir | ||
| 294 | if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || | ||
| 295 | !Watch->WatcherImpl->linkAllowed( curPath, link ) ) { | ||
| 296 | skip = true; | ||
| 297 | } else { | ||
| 298 | dir = link; | ||
| 299 | } | ||
| 300 | } else { | ||
| 301 | if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) { | ||
| 302 | skip = true; | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | if ( !skip ) { | ||
| 307 | handleAction( newdir, Actions::Add ); | ||
| 308 | |||
| 309 | /// Creates the new directory watcher of the subfolder and check for new files | ||
| 310 | dw = new DirWatcherGeneric( this, Watch, dir, Recursive ); | ||
| 311 | |||
| 312 | dw->addChilds(); | ||
| 313 | |||
| 314 | dw->watch(); | ||
| 315 | |||
| 316 | /// Add it to the list of directories | ||
| 317 | Directories[newdir] = dw; | ||
| 318 | } | ||
| 319 | |||
| 320 | return dw; | ||
| 321 | } | ||
| 322 | |||
| 323 | void DirWatcherGeneric::removeDirectory( std::string dir ) { | ||
| 324 | FileSystem::dirRemoveSlashAtEnd( dir ); | ||
| 325 | dir = FileSystem::fileNameFromPath( dir ); | ||
| 326 | |||
| 327 | DirWatcherGeneric* dw = NULL; | ||
| 328 | DirWatchMap::iterator dit; | ||
| 329 | |||
| 330 | /// Folder deleted | ||
| 331 | |||
| 332 | /// Search the folder, it should exists | ||
| 333 | dit = Directories.find( dir ); | ||
| 334 | |||
| 335 | if ( dit != Directories.end() ) { | ||
| 336 | dw = dit->second; | ||
| 337 | |||
| 338 | /// Flag it as deleted so it fire the event for every file inside deleted | ||
| 339 | dw->Deleted = true; | ||
| 340 | |||
| 341 | /// Delete the DirWatcherGeneric | ||
| 342 | efSAFE_DELETE( dw ); | ||
| 343 | |||
| 344 | /// Remove the directory from the map | ||
| 345 | Directories.erase( dit->first ); | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir ) { | ||
| 350 | FileSystem::dirRemoveSlashAtEnd( oldDir ); | ||
| 351 | oldDir = FileSystem::fileNameFromPath( oldDir ); | ||
| 352 | |||
| 353 | FileSystem::dirRemoveSlashAtEnd( newDir ); | ||
| 354 | newDir = FileSystem::fileNameFromPath( newDir ); | ||
| 355 | |||
| 356 | DirWatcherGeneric* dw = NULL; | ||
| 357 | DirWatchMap::iterator dit; | ||
| 358 | |||
| 359 | /// Directory existed? | ||
| 360 | dit = Directories.find( oldDir ); | ||
| 361 | |||
| 362 | if ( dit != Directories.end() ) { | ||
| 363 | dw = dit->second; | ||
| 364 | |||
| 365 | /// Remove the directory from the map | ||
| 366 | Directories.erase( dit->first ); | ||
| 367 | |||
| 368 | Directories[newDir] = dw; | ||
| 369 | |||
| 370 | dw->resetDirectory( newDir ); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | bool DirWatcherGeneric::pathInWatches( std::string path ) { | ||
| 375 | if ( DirSnap.DirectoryInfo.Filepath == path ) { | ||
| 376 | return true; | ||
| 377 | } | ||
| 378 | |||
| 379 | for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) { | ||
| 380 | if ( it->second->pathInWatches( path ) ) { | ||
| 381 | return true; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | return false; | ||
| 386 | } | ||
| 387 | |||
| 388 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.hpp b/src/3rdParty/efsw/DirWatcherGeneric.hpp new file mode 100755 index 0000000..ca52de7 --- /dev/null +++ b/src/3rdParty/efsw/DirWatcherGeneric.hpp | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #ifndef EFSW_DIRWATCHERGENERIC_HPP | ||
| 2 | #define EFSW_DIRWATCHERGENERIC_HPP | ||
| 3 | |||
| 4 | #include <efsw/DirectorySnapshot.hpp> | ||
| 5 | #include <efsw/FileInfo.hpp> | ||
| 6 | #include <efsw/WatcherGeneric.hpp> | ||
| 7 | #include <map> | ||
| 8 | |||
| 9 | namespace efsw { | ||
| 10 | |||
| 11 | class DirWatcherGeneric { | ||
| 12 | public: | ||
| 13 | typedef std::map<std::string, DirWatcherGeneric*> DirWatchMap; | ||
| 14 | |||
| 15 | DirWatcherGeneric* Parent; | ||
| 16 | WatcherGeneric* Watch; | ||
| 17 | DirectorySnapshot DirSnap; | ||
| 18 | DirWatchMap Directories; | ||
| 19 | bool Recursive; | ||
| 20 | |||
| 21 | DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws, const std::string& directory, | ||
| 22 | bool recursive, bool reportNewFiles = false ); | ||
| 23 | |||
| 24 | ~DirWatcherGeneric(); | ||
| 25 | |||
| 26 | void watch( bool reportOwnChange = false ); | ||
| 27 | |||
| 28 | void watchDir( std::string& dir ); | ||
| 29 | |||
| 30 | static bool isDir( const std::string& directory ); | ||
| 31 | |||
| 32 | bool pathInWatches( std::string path ); | ||
| 33 | |||
| 34 | void addChilds( bool reportNewFiles = true ); | ||
| 35 | |||
| 36 | DirWatcherGeneric* findDirWatcher( std::string dir ); | ||
| 37 | |||
| 38 | DirWatcherGeneric* findDirWatcherFast( std::string dir ); | ||
| 39 | |||
| 40 | protected: | ||
| 41 | bool Deleted; | ||
| 42 | |||
| 43 | DirWatcherGeneric* createDirectory( std::string newdir ); | ||
| 44 | |||
| 45 | void removeDirectory( std::string dir ); | ||
| 46 | |||
| 47 | void moveDirectory( std::string oldDir, std::string newDir ); | ||
| 48 | |||
| 49 | void resetDirectory( std::string directory ); | ||
| 50 | |||
| 51 | void handleAction( const std::string& filename, unsigned long action, | ||
| 52 | std::string oldFilename = "" ); | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace efsw | ||
| 56 | |||
| 57 | #endif | ||
diff --git a/src/3rdParty/efsw/DirectorySnapshot.cpp b/src/3rdParty/efsw/DirectorySnapshot.cpp new file mode 100755 index 0000000..6049e4a --- /dev/null +++ b/src/3rdParty/efsw/DirectorySnapshot.cpp | |||
| @@ -0,0 +1,212 @@ | |||
| 1 | #include <efsw/DirectorySnapshot.hpp> | ||
| 2 | #include <efsw/FileSystem.hpp> | ||
| 3 | |||
| 4 | namespace efsw { | ||
| 5 | |||
| 6 | DirectorySnapshot::DirectorySnapshot() {} | ||
| 7 | |||
| 8 | DirectorySnapshot::DirectorySnapshot( std::string directory ) { | ||
| 9 | init( directory ); | ||
| 10 | } | ||
| 11 | |||
| 12 | DirectorySnapshot::~DirectorySnapshot() {} | ||
| 13 | |||
| 14 | void DirectorySnapshot::init( std::string directory ) { | ||
| 15 | setDirectoryInfo( directory ); | ||
| 16 | initFiles(); | ||
| 17 | } | ||
| 18 | |||
| 19 | bool DirectorySnapshot::exists() { | ||
| 20 | return DirectoryInfo.exists(); | ||
| 21 | } | ||
| 22 | |||
| 23 | void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff ) { | ||
| 24 | FileInfo fi; | ||
| 25 | |||
| 26 | for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ ) { | ||
| 27 | fi = it->second; | ||
| 28 | |||
| 29 | if ( fi.isDirectory() ) { | ||
| 30 | Diff.DirsDeleted.push_back( fi ); | ||
| 31 | } else { | ||
| 32 | Diff.FilesDeleted.push_back( fi ); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | Files.clear(); | ||
| 37 | } | ||
| 38 | |||
| 39 | void DirectorySnapshot::setDirectoryInfo( std::string directory ) { | ||
| 40 | DirectoryInfo = FileInfo( directory ); | ||
| 41 | } | ||
| 42 | |||
| 43 | void DirectorySnapshot::initFiles() { | ||
| 44 | Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); | ||
| 45 | |||
| 46 | FileInfoMap::iterator it = Files.begin(); | ||
| 47 | std::list<std::string> eraseFiles; | ||
| 48 | |||
| 49 | /// Remove all non regular files and non directories | ||
| 50 | for ( ; it != Files.end(); it++ ) { | ||
| 51 | if ( !it->second.isRegularFile() && !it->second.isDirectory() ) { | ||
| 52 | eraseFiles.push_back( it->first ); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); | ||
| 57 | eit++ ) { | ||
| 58 | Files.erase( *eit ); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | DirectorySnapshotDiff DirectorySnapshot::scan() { | ||
| 63 | DirectorySnapshotDiff Diff; | ||
| 64 | |||
| 65 | Diff.clear(); | ||
| 66 | |||
| 67 | FileInfo curFI( DirectoryInfo.Filepath ); | ||
| 68 | |||
| 69 | Diff.DirChanged = DirectoryInfo != curFI; | ||
| 70 | |||
| 71 | if ( Diff.DirChanged ) { | ||
| 72 | DirectoryInfo = curFI; | ||
| 73 | } | ||
| 74 | |||
| 75 | /// If the directory was erased, create the events for files and directories deletion | ||
| 76 | if ( !curFI.exists() ) { | ||
| 77 | deleteAll( Diff ); | ||
| 78 | |||
| 79 | return Diff; | ||
| 80 | } | ||
| 81 | |||
| 82 | FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); | ||
| 83 | |||
| 84 | if ( files.empty() && Files.empty() ) { | ||
| 85 | return Diff; | ||
| 86 | } | ||
| 87 | |||
| 88 | FileInfo fi; | ||
| 89 | FileInfoMap FilesCpy; | ||
| 90 | FileInfoMap::iterator it; | ||
| 91 | FileInfoMap::iterator fiIt; | ||
| 92 | |||
| 93 | if ( Diff.DirChanged ) { | ||
| 94 | FilesCpy = Files; | ||
| 95 | } | ||
| 96 | |||
| 97 | for ( it = files.begin(); it != files.end(); it++ ) { | ||
| 98 | fi = it->second; | ||
| 99 | |||
| 100 | /// File existed before? | ||
| 101 | fiIt = Files.find( it->first ); | ||
| 102 | |||
| 103 | if ( fiIt != Files.end() ) { | ||
| 104 | /// Erase from the file list copy | ||
| 105 | FilesCpy.erase( it->first ); | ||
| 106 | |||
| 107 | /// File changed? | ||
| 108 | if ( ( *fiIt ).second != fi ) { | ||
| 109 | /// Update the new file info | ||
| 110 | Files[it->first] = fi; | ||
| 111 | |||
| 112 | /// handle modified event | ||
| 113 | if ( fi.isDirectory() ) { | ||
| 114 | Diff.DirsModified.push_back( fi ); | ||
| 115 | } else { | ||
| 116 | Diff.FilesModified.push_back( fi ); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | /// Only add regular files or directories | ||
| 121 | else if ( fi.isRegularFile() || fi.isDirectory() ) { | ||
| 122 | /// New file found | ||
| 123 | Files[it->first] = fi; | ||
| 124 | |||
| 125 | FileInfoMap::iterator fit; | ||
| 126 | std::string oldFile = ""; | ||
| 127 | |||
| 128 | /// Check if the same inode already existed | ||
| 129 | if ( ( fit = nodeInFiles( fi ) ) != Files.end() ) { | ||
| 130 | oldFile = fit->first; | ||
| 131 | |||
| 132 | /// Avoid firing a Delete event | ||
| 133 | FilesCpy.erase( fit->first ); | ||
| 134 | |||
| 135 | /// Delete the old file name | ||
| 136 | Files.erase( fit->first ); | ||
| 137 | |||
| 138 | if ( fi.isDirectory() ) { | ||
| 139 | Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) ); | ||
| 140 | } else { | ||
| 141 | Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) ); | ||
| 142 | } | ||
| 143 | } else { | ||
| 144 | if ( fi.isDirectory() ) { | ||
| 145 | Diff.DirsCreated.push_back( fi ); | ||
| 146 | } else { | ||
| 147 | Diff.FilesCreated.push_back( fi ); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | if ( !Diff.DirChanged ) { | ||
| 154 | return Diff; | ||
| 155 | } | ||
| 156 | |||
| 157 | /// The files or directories that remains were deleted | ||
| 158 | for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ ) { | ||
| 159 | fi = it->second; | ||
| 160 | |||
| 161 | if ( fi.isDirectory() ) { | ||
| 162 | Diff.DirsDeleted.push_back( fi ); | ||
| 163 | } else { | ||
| 164 | Diff.FilesDeleted.push_back( fi ); | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Remove the file or directory from the list of files | ||
| 168 | Files.erase( it->first ); | ||
| 169 | } | ||
| 170 | |||
| 171 | return Diff; | ||
| 172 | } | ||
| 173 | |||
| 174 | FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi ) { | ||
| 175 | FileInfoMap::iterator it; | ||
| 176 | |||
| 177 | if ( FileInfo::inodeSupported() ) { | ||
| 178 | for ( it = Files.begin(); it != Files.end(); it++ ) { | ||
| 179 | if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath ) { | ||
| 180 | return it; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | return Files.end(); | ||
| 186 | } | ||
| 187 | |||
| 188 | void DirectorySnapshot::addFile( std::string path ) { | ||
| 189 | std::string name( FileSystem::fileNameFromPath( path ) ); | ||
| 190 | Files[name] = FileInfo( path ); | ||
| 191 | } | ||
| 192 | |||
| 193 | void DirectorySnapshot::removeFile( std::string path ) { | ||
| 194 | std::string name( FileSystem::fileNameFromPath( path ) ); | ||
| 195 | |||
| 196 | FileInfoMap::iterator it = Files.find( name ); | ||
| 197 | |||
| 198 | if ( Files.end() != it ) { | ||
| 199 | Files.erase( it ); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath ) { | ||
| 204 | removeFile( oldPath ); | ||
| 205 | addFile( newPath ); | ||
| 206 | } | ||
| 207 | |||
| 208 | void DirectorySnapshot::updateFile( std::string path ) { | ||
| 209 | addFile( path ); | ||
| 210 | } | ||
| 211 | |||
| 212 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/DirectorySnapshot.hpp b/src/3rdParty/efsw/DirectorySnapshot.hpp new file mode 100755 index 0000000..0e60542 --- /dev/null +++ b/src/3rdParty/efsw/DirectorySnapshot.hpp | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | #ifndef EFSW_DIRECTORYSNAPSHOT_HPP | ||
| 2 | #define EFSW_DIRECTORYSNAPSHOT_HPP | ||
| 3 | |||
| 4 | #include <efsw/DirectorySnapshotDiff.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | class DirectorySnapshot { | ||
| 9 | public: | ||
| 10 | FileInfo DirectoryInfo; | ||
| 11 | FileInfoMap Files; | ||
| 12 | |||
| 13 | void setDirectoryInfo( std::string directory ); | ||
| 14 | |||
| 15 | DirectorySnapshot(); | ||
| 16 | |||
| 17 | DirectorySnapshot( std::string directory ); | ||
| 18 | |||
| 19 | ~DirectorySnapshot(); | ||
| 20 | |||
| 21 | void init( std::string directory ); | ||
| 22 | |||
| 23 | bool exists(); | ||
| 24 | |||
| 25 | DirectorySnapshotDiff scan(); | ||
| 26 | |||
| 27 | FileInfoMap::iterator nodeInFiles( FileInfo& fi ); | ||
| 28 | |||
| 29 | void addFile( std::string path ); | ||
| 30 | |||
| 31 | void removeFile( std::string path ); | ||
| 32 | |||
| 33 | void moveFile( std::string oldPath, std::string newPath ); | ||
| 34 | |||
| 35 | void updateFile( std::string path ); | ||
| 36 | |||
| 37 | protected: | ||
| 38 | void initFiles(); | ||
| 39 | |||
| 40 | void deleteAll( DirectorySnapshotDiff& Diff ); | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace efsw | ||
| 44 | |||
| 45 | #endif | ||
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp new file mode 100755 index 0000000..37ee507 --- /dev/null +++ b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #include <efsw/DirectorySnapshotDiff.hpp> | ||
| 2 | |||
| 3 | namespace efsw { | ||
| 4 | |||
| 5 | void DirectorySnapshotDiff::clear() { | ||
| 6 | FilesCreated.clear(); | ||
| 7 | FilesModified.clear(); | ||
| 8 | FilesMoved.clear(); | ||
| 9 | FilesDeleted.clear(); | ||
| 10 | DirsCreated.clear(); | ||
| 11 | DirsModified.clear(); | ||
| 12 | DirsMoved.clear(); | ||
| 13 | DirsDeleted.clear(); | ||
| 14 | } | ||
| 15 | |||
| 16 | bool DirectorySnapshotDiff::changed() { | ||
| 17 | return !FilesCreated.empty() || !FilesModified.empty() || !FilesMoved.empty() || | ||
| 18 | !FilesDeleted.empty() || !DirsCreated.empty() || !DirsModified.empty() || | ||
| 19 | !DirsMoved.empty() || !DirsDeleted.empty(); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp new file mode 100755 index 0000000..26a29ec --- /dev/null +++ b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP | ||
| 2 | #define EFSW_DIRECTORYSNAPSHOTDIFF_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileInfo.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | class DirectorySnapshotDiff { | ||
| 9 | public: | ||
| 10 | FileInfoList FilesDeleted; | ||
| 11 | FileInfoList FilesCreated; | ||
| 12 | FileInfoList FilesModified; | ||
| 13 | MovedList FilesMoved; | ||
| 14 | FileInfoList DirsDeleted; | ||
| 15 | FileInfoList DirsCreated; | ||
| 16 | FileInfoList DirsModified; | ||
| 17 | MovedList DirsMoved; | ||
| 18 | bool DirChanged; | ||
| 19 | |||
| 20 | void clear(); | ||
| 21 | |||
| 22 | bool changed(); | ||
| 23 | }; | ||
| 24 | |||
| 25 | #define DiffIterator( FileInfoListName ) \ | ||
| 26 | it = Diff.FileInfoListName.begin(); \ | ||
| 27 | for ( ; it != Diff.FileInfoListName.end(); it++ ) | ||
| 28 | |||
| 29 | #define DiffMovedIterator( MovedListName ) \ | ||
| 30 | mit = Diff.MovedListName.begin(); \ | ||
| 31 | for ( ; mit != Diff.MovedListName.end(); mit++ ) | ||
| 32 | |||
| 33 | } // namespace efsw | ||
| 34 | |||
| 35 | #endif | ||
diff --git a/src/3rdParty/efsw/FileInfo.cpp b/src/3rdParty/efsw/FileInfo.cpp new file mode 100755 index 0000000..707f617 --- /dev/null +++ b/src/3rdParty/efsw/FileInfo.cpp | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | #include <efsw/FileInfo.hpp> | ||
| 2 | #include <efsw/FileSystem.hpp> | ||
| 3 | #include <efsw/String.hpp> | ||
| 4 | |||
| 5 | #ifndef _DARWIN_FEATURE_64_BIT_INODE | ||
| 6 | #define _DARWIN_FEATURE_64_BIT_INODE | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #ifndef _FILE_OFFSET_BITS | ||
| 10 | #define _FILE_OFFSET_BITS 64 | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #include <sys/stat.h> | ||
| 14 | |||
| 15 | #include <limits.h> | ||
| 16 | #include <stdlib.h> | ||
| 17 | |||
| 18 | #ifdef EFSW_COMPILER_MSVC | ||
| 19 | #ifndef S_ISDIR | ||
| 20 | #define S_ISDIR( f ) ( (f)&_S_IFDIR ) | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #ifndef S_ISREG | ||
| 24 | #define S_ISREG( f ) ( (f)&_S_IFREG ) | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #ifndef S_ISRDBL | ||
| 28 | #define S_ISRDBL( f ) ( (f)&_S_IREAD ) | ||
| 29 | #endif | ||
| 30 | #else | ||
| 31 | #include <unistd.h> | ||
| 32 | |||
| 33 | #ifndef S_ISRDBL | ||
| 34 | #define S_ISRDBL( f ) ( (f)&S_IRUSR ) | ||
| 35 | #endif | ||
| 36 | #endif | ||
| 37 | |||
| 38 | namespace efsw { | ||
| 39 | |||
| 40 | bool FileInfo::exists( const std::string& filePath ) { | ||
| 41 | FileInfo fi( filePath ); | ||
| 42 | return fi.exists(); | ||
| 43 | } | ||
| 44 | |||
| 45 | bool FileInfo::isLink( const std::string& filePath ) { | ||
| 46 | FileInfo fi( filePath, true ); | ||
| 47 | return fi.isLink(); | ||
| 48 | } | ||
| 49 | |||
| 50 | bool FileInfo::inodeSupported() { | ||
| 51 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 52 | return true; | ||
| 53 | #else | ||
| 54 | return false; | ||
| 55 | #endif | ||
| 56 | } | ||
| 57 | |||
| 58 | FileInfo::FileInfo() : | ||
| 59 | ModificationTime( 0 ), OwnerId( 0 ), GroupId( 0 ), Permissions( 0 ), Inode( 0 ) {} | ||
| 60 | |||
| 61 | FileInfo::FileInfo( const std::string& filepath ) : | ||
| 62 | Filepath( filepath ), | ||
| 63 | ModificationTime( 0 ), | ||
| 64 | OwnerId( 0 ), | ||
| 65 | GroupId( 0 ), | ||
| 66 | Permissions( 0 ), | ||
| 67 | Inode( 0 ) { | ||
| 68 | getInfo(); | ||
| 69 | } | ||
| 70 | |||
| 71 | FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) : | ||
| 72 | Filepath( filepath ), | ||
| 73 | ModificationTime( 0 ), | ||
| 74 | OwnerId( 0 ), | ||
| 75 | GroupId( 0 ), | ||
| 76 | Permissions( 0 ), | ||
| 77 | Inode( 0 ) { | ||
| 78 | if ( linkInfo ) { | ||
| 79 | getRealInfo(); | ||
| 80 | } else { | ||
| 81 | getInfo(); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | void FileInfo::getInfo() { | ||
| 86 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 87 | if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() ) { | ||
| 88 | Filepath += FileSystem::getOSSlash(); | ||
| 89 | } | ||
| 90 | #endif | ||
| 91 | |||
| 92 | /// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a | ||
| 93 | /// path slash | ||
| 94 | bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); | ||
| 95 | |||
| 96 | if ( slashAtEnd ) { | ||
| 97 | FileSystem::dirRemoveSlashAtEnd( Filepath ); | ||
| 98 | } | ||
| 99 | |||
| 100 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 101 | struct stat st; | ||
| 102 | int res = stat( Filepath.c_str(), &st ); | ||
| 103 | #else | ||
| 104 | struct _stat st; | ||
| 105 | int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); | ||
| 106 | #endif | ||
| 107 | |||
| 108 | if ( 0 == res ) { | ||
| 109 | ModificationTime = st.st_mtime; | ||
| 110 | Size = st.st_size; | ||
| 111 | OwnerId = st.st_uid; | ||
| 112 | GroupId = st.st_gid; | ||
| 113 | Permissions = st.st_mode; | ||
| 114 | Inode = st.st_ino; | ||
| 115 | } | ||
| 116 | |||
| 117 | if ( slashAtEnd ) { | ||
| 118 | FileSystem::dirAddSlashAtEnd( Filepath ); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | void FileInfo::getRealInfo() { | ||
| 123 | bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); | ||
| 124 | |||
| 125 | if ( slashAtEnd ) { | ||
| 126 | FileSystem::dirRemoveSlashAtEnd( Filepath ); | ||
| 127 | } | ||
| 128 | |||
| 129 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 130 | struct stat st; | ||
| 131 | int res = lstat( Filepath.c_str(), &st ); | ||
| 132 | #else | ||
| 133 | struct _stat st; | ||
| 134 | int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); | ||
| 135 | #endif | ||
| 136 | |||
| 137 | if ( 0 == res ) { | ||
| 138 | ModificationTime = st.st_mtime; | ||
| 139 | Size = st.st_size; | ||
| 140 | OwnerId = st.st_uid; | ||
| 141 | GroupId = st.st_gid; | ||
| 142 | Permissions = st.st_mode; | ||
| 143 | Inode = st.st_ino; | ||
| 144 | } | ||
| 145 | |||
| 146 | if ( slashAtEnd ) { | ||
| 147 | FileSystem::dirAddSlashAtEnd( Filepath ); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | bool FileInfo::operator==( const FileInfo& Other ) const { | ||
| 152 | return ( ModificationTime == Other.ModificationTime && Size == Other.Size && | ||
| 153 | OwnerId == Other.OwnerId && GroupId == Other.GroupId && | ||
| 154 | Permissions == Other.Permissions && Inode == Other.Inode ); | ||
| 155 | } | ||
| 156 | |||
| 157 | bool FileInfo::isDirectory() const { | ||
| 158 | return 0 != S_ISDIR( Permissions ); | ||
| 159 | } | ||
| 160 | |||
| 161 | bool FileInfo::isRegularFile() const { | ||
| 162 | return 0 != S_ISREG( Permissions ); | ||
| 163 | } | ||
| 164 | |||
| 165 | bool FileInfo::isReadable() const { | ||
| 166 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 167 | static bool isRoot = getuid() == 0; | ||
| 168 | return isRoot || 0 != S_ISRDBL( Permissions ); | ||
| 169 | #else | ||
| 170 | return 0 != S_ISRDBL( Permissions ); | ||
| 171 | #endif | ||
| 172 | } | ||
| 173 | |||
| 174 | bool FileInfo::isLink() const { | ||
| 175 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 176 | return S_ISLNK( Permissions ); | ||
| 177 | #else | ||
| 178 | return false; | ||
| 179 | #endif | ||
| 180 | } | ||
| 181 | |||
| 182 | std::string FileInfo::linksTo() { | ||
| 183 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 184 | if ( isLink() ) { | ||
| 185 | char* ch = realpath( Filepath.c_str(), NULL ); | ||
| 186 | |||
| 187 | if ( NULL != ch ) { | ||
| 188 | std::string tstr( ch ); | ||
| 189 | |||
| 190 | free( ch ); | ||
| 191 | |||
| 192 | return tstr; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | #endif | ||
| 196 | return std::string( "" ); | ||
| 197 | } | ||
| 198 | |||
| 199 | bool FileInfo::exists() { | ||
| 200 | bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); | ||
| 201 | |||
| 202 | if ( slashAtEnd ) { | ||
| 203 | FileSystem::dirRemoveSlashAtEnd( Filepath ); | ||
| 204 | } | ||
| 205 | |||
| 206 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 207 | struct stat st; | ||
| 208 | int res = stat( Filepath.c_str(), &st ); | ||
| 209 | #else | ||
| 210 | struct _stat st; | ||
| 211 | int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); | ||
| 212 | #endif | ||
| 213 | |||
| 214 | if ( slashAtEnd ) { | ||
| 215 | FileSystem::dirAddSlashAtEnd( Filepath ); | ||
| 216 | } | ||
| 217 | |||
| 218 | return 0 == res; | ||
| 219 | } | ||
| 220 | |||
| 221 | FileInfo& FileInfo::operator=( const FileInfo& Other ) { | ||
| 222 | this->Filepath = Other.Filepath; | ||
| 223 | this->Size = Other.Size; | ||
| 224 | this->ModificationTime = Other.ModificationTime; | ||
| 225 | this->GroupId = Other.GroupId; | ||
| 226 | this->OwnerId = Other.OwnerId; | ||
| 227 | this->Permissions = Other.Permissions; | ||
| 228 | this->Inode = Other.Inode; | ||
| 229 | return *this; | ||
| 230 | } | ||
| 231 | |||
| 232 | bool FileInfo::sameInode( const FileInfo& Other ) const { | ||
| 233 | return inodeSupported() && Inode == Other.Inode; | ||
| 234 | } | ||
| 235 | |||
| 236 | bool FileInfo::operator!=( const FileInfo& Other ) const { | ||
| 237 | return !( *this == Other ); | ||
| 238 | } | ||
| 239 | |||
| 240 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileInfo.hpp b/src/3rdParty/efsw/FileInfo.hpp new file mode 100755 index 0000000..a8dd3d3 --- /dev/null +++ b/src/3rdParty/efsw/FileInfo.hpp | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | #ifndef EFSW_FILEINFO_HPP | ||
| 2 | #define EFSW_FILEINFO_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | #include <list> | ||
| 6 | #include <map> | ||
| 7 | #include <string> | ||
| 8 | |||
| 9 | namespace efsw { | ||
| 10 | |||
| 11 | class FileInfo { | ||
| 12 | public: | ||
| 13 | static bool exists( const std::string& filePath ); | ||
| 14 | |||
| 15 | static bool isLink( const std::string& filePath ); | ||
| 16 | |||
| 17 | static bool inodeSupported(); | ||
| 18 | |||
| 19 | FileInfo(); | ||
| 20 | |||
| 21 | FileInfo( const std::string& filepath ); | ||
| 22 | |||
| 23 | FileInfo( const std::string& filepath, bool linkInfo ); | ||
| 24 | |||
| 25 | bool operator==( const FileInfo& Other ) const; | ||
| 26 | |||
| 27 | bool operator!=( const FileInfo& Other ) const; | ||
| 28 | |||
| 29 | FileInfo& operator=( const FileInfo& Other ); | ||
| 30 | |||
| 31 | bool isDirectory() const; | ||
| 32 | |||
| 33 | bool isRegularFile() const; | ||
| 34 | |||
| 35 | bool isReadable() const; | ||
| 36 | |||
| 37 | bool sameInode( const FileInfo& Other ) const; | ||
| 38 | |||
| 39 | bool isLink() const; | ||
| 40 | |||
| 41 | std::string linksTo(); | ||
| 42 | |||
| 43 | bool exists(); | ||
| 44 | |||
| 45 | void getInfo(); | ||
| 46 | |||
| 47 | void getRealInfo(); | ||
| 48 | |||
| 49 | std::string Filepath; | ||
| 50 | Uint64 ModificationTime; | ||
| 51 | Uint64 Size; | ||
| 52 | Uint32 OwnerId; | ||
| 53 | Uint32 GroupId; | ||
| 54 | Uint32 Permissions; | ||
| 55 | Uint64 Inode; | ||
| 56 | }; | ||
| 57 | |||
| 58 | typedef std::map<std::string, FileInfo> FileInfoMap; | ||
| 59 | typedef std::list<FileInfo> FileInfoList; | ||
| 60 | typedef std::list<std::pair<std::string, FileInfo>> MovedList; | ||
| 61 | |||
| 62 | } // namespace efsw | ||
| 63 | |||
| 64 | #endif | ||
diff --git a/src/3rdParty/efsw/FileSystem.cpp b/src/3rdParty/efsw/FileSystem.cpp new file mode 100755 index 0000000..867f120 --- /dev/null +++ b/src/3rdParty/efsw/FileSystem.cpp | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | #include <efsw/FileSystem.hpp> | ||
| 2 | #include <efsw/platform/platformimpl.hpp> | ||
| 3 | |||
| 4 | #if EFSW_OS == EFSW_OS_MACOSX | ||
| 5 | #include <CoreFoundation/CoreFoundation.h> | ||
| 6 | #endif | ||
| 7 | |||
| 8 | namespace efsw { | ||
| 9 | |||
| 10 | bool FileSystem::isDirectory( const std::string& path ) { | ||
| 11 | return Platform::FileSystem::isDirectory( path ); | ||
| 12 | } | ||
| 13 | |||
| 14 | FileInfoMap FileSystem::filesInfoFromPath( std::string path ) { | ||
| 15 | dirAddSlashAtEnd( path ); | ||
| 16 | |||
| 17 | return Platform::FileSystem::filesInfoFromPath( path ); | ||
| 18 | } | ||
| 19 | |||
| 20 | char FileSystem::getOSSlash() { | ||
| 21 | return Platform::FileSystem::getOSSlash(); | ||
| 22 | } | ||
| 23 | |||
| 24 | bool FileSystem::slashAtEnd( std::string& dir ) { | ||
| 25 | return ( dir.size() && dir[dir.size() - 1] == getOSSlash() ); | ||
| 26 | } | ||
| 27 | |||
| 28 | void FileSystem::dirAddSlashAtEnd( std::string& dir ) { | ||
| 29 | if ( dir.size() > 1 && dir[dir.size() - 1] != getOSSlash() ) { | ||
| 30 | dir.push_back( getOSSlash() ); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { | ||
| 35 | if ( dir.size() > 1 && dir[dir.size() - 1] == getOSSlash() ) { | ||
| 36 | dir.erase( dir.size() - 1 ); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | std::string FileSystem::fileNameFromPath( std::string filepath ) { | ||
| 41 | dirRemoveSlashAtEnd( filepath ); | ||
| 42 | |||
| 43 | size_t pos = filepath.find_last_of( getOSSlash() ); | ||
| 44 | |||
| 45 | if ( pos != std::string::npos ) { | ||
| 46 | return filepath.substr( pos + 1 ); | ||
| 47 | } | ||
| 48 | |||
| 49 | return filepath; | ||
| 50 | } | ||
| 51 | |||
| 52 | std::string FileSystem::pathRemoveFileName( std::string filepath ) { | ||
| 53 | dirRemoveSlashAtEnd( filepath ); | ||
| 54 | |||
| 55 | size_t pos = filepath.find_last_of( getOSSlash() ); | ||
| 56 | |||
| 57 | if ( pos != std::string::npos ) { | ||
| 58 | return filepath.substr( 0, pos + 1 ); | ||
| 59 | } | ||
| 60 | |||
| 61 | return filepath; | ||
| 62 | } | ||
| 63 | |||
| 64 | std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath ) { | ||
| 65 | FileSystem::dirRemoveSlashAtEnd( dir ); | ||
| 66 | FileInfo fi( dir, true ); | ||
| 67 | |||
| 68 | /// Check with lstat and see if it's a link | ||
| 69 | if ( fi.isLink() ) { | ||
| 70 | /// get the real path of the link | ||
| 71 | std::string link( fi.linksTo() ); | ||
| 72 | |||
| 73 | /// get the current path of the directory without the link dir path | ||
| 74 | curPath = FileSystem::pathRemoveFileName( dir ); | ||
| 75 | |||
| 76 | /// ensure that ends with the os directory slash | ||
| 77 | FileSystem::dirAddSlashAtEnd( link ); | ||
| 78 | |||
| 79 | return link; | ||
| 80 | } | ||
| 81 | |||
| 82 | /// if it's not a link return nothing | ||
| 83 | return ""; | ||
| 84 | } | ||
| 85 | |||
| 86 | std::string FileSystem::precomposeFileName( const std::string& name ) { | ||
| 87 | #if EFSW_OS == EFSW_OS_MACOSX | ||
| 88 | CFStringRef cfStringRef = | ||
| 89 | CFStringCreateWithCString( kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8 ); | ||
| 90 | CFMutableStringRef cfMutable = CFStringCreateMutableCopy( NULL, 0, cfStringRef ); | ||
| 91 | |||
| 92 | CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); | ||
| 93 | |||
| 94 | char c_str[255 + 1]; | ||
| 95 | CFStringGetCString( cfMutable, c_str, sizeof( c_str ) - 1, kCFStringEncodingUTF8 ); | ||
| 96 | |||
| 97 | CFRelease( cfStringRef ); | ||
| 98 | CFRelease( cfMutable ); | ||
| 99 | |||
| 100 | return std::string( c_str ); | ||
| 101 | #else | ||
| 102 | return name; | ||
| 103 | #endif | ||
| 104 | } | ||
| 105 | |||
| 106 | bool FileSystem::isRemoteFS( const std::string& directory ) { | ||
| 107 | return Platform::FileSystem::isRemoteFS( directory ); | ||
| 108 | } | ||
| 109 | |||
| 110 | bool FileSystem::changeWorkingDirectory( const std::string& directory ) { | ||
| 111 | return Platform::FileSystem::changeWorkingDirectory( directory ); | ||
| 112 | } | ||
| 113 | |||
| 114 | std::string FileSystem::getCurrentWorkingDirectory() { | ||
| 115 | return Platform::FileSystem::getCurrentWorkingDirectory(); | ||
| 116 | } | ||
| 117 | |||
| 118 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileSystem.hpp b/src/3rdParty/efsw/FileSystem.hpp new file mode 100755 index 0000000..6c24386 --- /dev/null +++ b/src/3rdParty/efsw/FileSystem.hpp | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef EFSW_FILESYSTEM_HPP | ||
| 2 | #define EFSW_FILESYSTEM_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileInfo.hpp> | ||
| 5 | #include <efsw/base.hpp> | ||
| 6 | #include <map> | ||
| 7 | |||
| 8 | namespace efsw { | ||
| 9 | |||
| 10 | class FileSystem { | ||
| 11 | public: | ||
| 12 | static bool isDirectory( const std::string& path ); | ||
| 13 | |||
| 14 | static FileInfoMap filesInfoFromPath( std::string path ); | ||
| 15 | |||
| 16 | static char getOSSlash(); | ||
| 17 | |||
| 18 | static bool slashAtEnd( std::string& dir ); | ||
| 19 | |||
| 20 | static void dirAddSlashAtEnd( std::string& dir ); | ||
| 21 | |||
| 22 | static void dirRemoveSlashAtEnd( std::string& dir ); | ||
| 23 | |||
| 24 | static std::string fileNameFromPath( std::string filepath ); | ||
| 25 | |||
| 26 | static std::string pathRemoveFileName( std::string filepath ); | ||
| 27 | |||
| 28 | static std::string getLinkRealPath( std::string dir, std::string& curPath ); | ||
| 29 | |||
| 30 | static std::string precomposeFileName( const std::string& name ); | ||
| 31 | |||
| 32 | static bool isRemoteFS( const std::string& directory ); | ||
| 33 | |||
| 34 | static bool changeWorkingDirectory( const std::string& path ); | ||
| 35 | |||
| 36 | static std::string getCurrentWorkingDirectory(); | ||
| 37 | }; | ||
| 38 | |||
| 39 | } // namespace efsw | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcher.cpp b/src/3rdParty/efsw/FileWatcher.cpp new file mode 100755 index 0000000..696a46f --- /dev/null +++ b/src/3rdParty/efsw/FileWatcher.cpp | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | #include <efsw/FileSystem.hpp> | ||
| 2 | #include <efsw/FileWatcherGeneric.hpp> | ||
| 3 | #include <efsw/FileWatcherImpl.hpp> | ||
| 4 | #include <efsw/efsw.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 7 | #include <efsw/FileWatcherWin32.hpp> | ||
| 8 | #define FILEWATCHER_IMPL FileWatcherWin32 | ||
| 9 | #define BACKEND_NAME "Win32" | ||
| 10 | #elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | ||
| 11 | #include <efsw/FileWatcherInotify.hpp> | ||
| 12 | #define FILEWATCHER_IMPL FileWatcherInotify | ||
| 13 | #define BACKEND_NAME "Inotify" | ||
| 14 | #elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE | ||
| 15 | #include <efsw/FileWatcherKqueue.hpp> | ||
| 16 | #define FILEWATCHER_IMPL FileWatcherKqueue | ||
| 17 | #define BACKEND_NAME "Kqueue" | ||
| 18 | #elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 19 | #include <efsw/FileWatcherFSEvents.hpp> | ||
| 20 | #define FILEWATCHER_IMPL FileWatcherFSEvents | ||
| 21 | #define BACKEND_NAME "FSEvents" | ||
| 22 | #else | ||
| 23 | #define FILEWATCHER_IMPL FileWatcherGeneric | ||
| 24 | #define BACKEND_NAME "Generic" | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #include <efsw/Debug.hpp> | ||
| 28 | |||
| 29 | namespace efsw { | ||
| 30 | |||
| 31 | FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { | ||
| 32 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); | ||
| 33 | |||
| 34 | mImpl = new FILEWATCHER_IMPL( this ); | ||
| 35 | |||
| 36 | if ( !mImpl->initOK() ) { | ||
| 37 | efSAFE_DELETE( mImpl ); | ||
| 38 | |||
| 39 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); | ||
| 40 | |||
| 41 | mImpl = new FileWatcherGeneric( this ); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | FileWatcher::FileWatcher( bool useGenericFileWatcher ) : | ||
| 46 | mFollowSymlinks( false ), mOutOfScopeLinks( false ) { | ||
| 47 | if ( useGenericFileWatcher ) { | ||
| 48 | efDEBUG( "Using backend: Generic\n" ); | ||
| 49 | |||
| 50 | mImpl = new FileWatcherGeneric( this ); | ||
| 51 | } else { | ||
| 52 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); | ||
| 53 | |||
| 54 | mImpl = new FILEWATCHER_IMPL( this ); | ||
| 55 | |||
| 56 | if ( !mImpl->initOK() ) { | ||
| 57 | efSAFE_DELETE( mImpl ); | ||
| 58 | |||
| 59 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); | ||
| 60 | |||
| 61 | mImpl = new FileWatcherGeneric( this ); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | FileWatcher::~FileWatcher() { | ||
| 67 | efSAFE_DELETE( mImpl ); | ||
| 68 | } | ||
| 69 | |||
| 70 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { | ||
| 71 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { | ||
| 72 | return mImpl->addWatch( directory, watcher, false ); | ||
| 73 | } else { | ||
| 74 | return Errors::Log::createLastError( Errors::FileRemote, directory ); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 79 | bool recursive ) { | ||
| 80 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { | ||
| 81 | return mImpl->addWatch( directory, watcher, recursive ); | ||
| 82 | } else { | ||
| 83 | return Errors::Log::createLastError( Errors::FileRemote, directory ); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void FileWatcher::removeWatch( const std::string& directory ) { | ||
| 88 | mImpl->removeWatch( directory ); | ||
| 89 | } | ||
| 90 | |||
| 91 | void FileWatcher::removeWatch( WatchID watchid ) { | ||
| 92 | mImpl->removeWatch( watchid ); | ||
| 93 | } | ||
| 94 | |||
| 95 | void FileWatcher::watch() { | ||
| 96 | mImpl->watch(); | ||
| 97 | } | ||
| 98 | |||
| 99 | std::list<std::string> FileWatcher::directories() { | ||
| 100 | return mImpl->directories(); | ||
| 101 | } | ||
| 102 | |||
| 103 | void FileWatcher::followSymlinks( bool follow ) { | ||
| 104 | mFollowSymlinks = follow; | ||
| 105 | } | ||
| 106 | |||
| 107 | const bool& FileWatcher::followSymlinks() const { | ||
| 108 | return mFollowSymlinks; | ||
| 109 | } | ||
| 110 | |||
| 111 | void FileWatcher::allowOutOfScopeLinks( bool allow ) { | ||
| 112 | mOutOfScopeLinks = allow; | ||
| 113 | } | ||
| 114 | |||
| 115 | const bool& FileWatcher::allowOutOfScopeLinks() const { | ||
| 116 | return mOutOfScopeLinks; | ||
| 117 | } | ||
| 118 | |||
| 119 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherCWrapper.cpp b/src/3rdParty/efsw/FileWatcherCWrapper.cpp new file mode 100755 index 0000000..5c49a66 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherCWrapper.cpp | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | #include <efsw/efsw.h> | ||
| 2 | #include <efsw/efsw.hpp> | ||
| 3 | #include <vector> | ||
| 4 | |||
| 5 | #define TOBOOL( i ) ( ( i ) == 0 ? false : true ) | ||
| 6 | |||
| 7 | /*************************************************************************************************/ | ||
| 8 | class Watcher_CAPI : public efsw::FileWatchListener { | ||
| 9 | public: | ||
| 10 | efsw_watcher mWatcher; | ||
| 11 | efsw_pfn_fileaction_callback mFn; | ||
| 12 | void* mParam; | ||
| 13 | |||
| 14 | public: | ||
| 15 | Watcher_CAPI( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) : | ||
| 16 | mWatcher( watcher ), mFn( fn ), mParam( param ) {} | ||
| 17 | |||
| 18 | void handleFileAction( efsw::WatchID watchid, const std::string& dir, | ||
| 19 | const std::string& filename, efsw::Action action, | ||
| 20 | std::string oldFilename = "" ) { | ||
| 21 | mFn( mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action, | ||
| 22 | oldFilename.c_str(), mParam ); | ||
| 23 | } | ||
| 24 | }; | ||
| 25 | |||
| 26 | /************************************************************************************************* | ||
| 27 | * globals | ||
| 28 | */ | ||
| 29 | static std::vector<Watcher_CAPI*> g_callbacks; | ||
| 30 | |||
| 31 | Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) { | ||
| 32 | for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); | ||
| 33 | ++i ) { | ||
| 34 | Watcher_CAPI* callback = *i; | ||
| 35 | |||
| 36 | if ( callback->mFn == fn && callback->mWatcher == watcher ) | ||
| 37 | return *i; | ||
| 38 | } | ||
| 39 | |||
| 40 | return NULL; | ||
| 41 | } | ||
| 42 | |||
| 43 | Watcher_CAPI* remove_callback( efsw_watcher watcher ) { | ||
| 44 | std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); | ||
| 45 | |||
| 46 | while ( i != g_callbacks.end() ) { | ||
| 47 | Watcher_CAPI* callback = *i; | ||
| 48 | |||
| 49 | if ( callback->mWatcher == watcher ) | ||
| 50 | i = g_callbacks.erase( i ); | ||
| 51 | else | ||
| 52 | ++i; | ||
| 53 | } | ||
| 54 | |||
| 55 | return NULL; | ||
| 56 | } | ||
| 57 | |||
| 58 | /*************************************************************************************************/ | ||
| 59 | efsw_watcher efsw_create( int generic_mode ) { | ||
| 60 | return ( efsw_watcher ) new efsw::FileWatcher( TOBOOL( generic_mode ) ); | ||
| 61 | } | ||
| 62 | |||
| 63 | void efsw_release( efsw_watcher watcher ) { | ||
| 64 | remove_callback( watcher ); | ||
| 65 | delete (efsw::FileWatcher*)watcher; | ||
| 66 | } | ||
| 67 | |||
| 68 | const char* efsw_getlasterror() { | ||
| 69 | static std::string log_str; | ||
| 70 | log_str = efsw::Errors::Log::getLastErrorLog(); | ||
| 71 | return log_str.c_str(); | ||
| 72 | } | ||
| 73 | |||
| 74 | efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, | ||
| 75 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { | ||
| 76 | Watcher_CAPI* callback = find_callback( watcher, callback_fn ); | ||
| 77 | |||
| 78 | if ( callback == NULL ) { | ||
| 79 | callback = new Watcher_CAPI( watcher, callback_fn, param ); | ||
| 80 | g_callbacks.push_back( callback ); | ||
| 81 | } | ||
| 82 | |||
| 83 | return ( (efsw::FileWatcher*)watcher ) | ||
| 84 | ->addWatch( std::string( directory ), callback, TOBOOL( recursive ) ); | ||
| 85 | } | ||
| 86 | |||
| 87 | void efsw_removewatch( efsw_watcher watcher, const char* directory ) { | ||
| 88 | ( (efsw::FileWatcher*)watcher )->removeWatch( std::string( directory ) ); | ||
| 89 | } | ||
| 90 | |||
| 91 | void efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid ) { | ||
| 92 | ( (efsw::FileWatcher*)watcher )->removeWatch( watchid ); | ||
| 93 | } | ||
| 94 | |||
| 95 | void efsw_watch( efsw_watcher watcher ) { | ||
| 96 | ( (efsw::FileWatcher*)watcher )->watch(); | ||
| 97 | } | ||
| 98 | |||
| 99 | void efsw_follow_symlinks( efsw_watcher watcher, int enable ) { | ||
| 100 | ( (efsw::FileWatcher*)watcher )->followSymlinks( TOBOOL( enable ) ); | ||
| 101 | } | ||
| 102 | |||
| 103 | int efsw_follow_symlinks_isenabled( efsw_watcher watcher ) { | ||
| 104 | return (int)( (efsw::FileWatcher*)watcher )->followSymlinks(); | ||
| 105 | } | ||
| 106 | |||
| 107 | void efsw_allow_outofscopelinks( efsw_watcher watcher, int allow ) { | ||
| 108 | ( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks( TOBOOL( allow ) ); | ||
| 109 | } | ||
| 110 | |||
| 111 | int efsw_outofscopelinks_isallowed( efsw_watcher watcher ) { | ||
| 112 | return (int)( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks(); | ||
| 113 | } | ||
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.cpp b/src/3rdParty/efsw/FileWatcherFSEvents.cpp new file mode 100755 index 0000000..970810d --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherFSEvents.cpp | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | #include <efsw/Debug.hpp> | ||
| 2 | #include <efsw/FileSystem.hpp> | ||
| 3 | #include <efsw/FileWatcherFSEvents.hpp> | ||
| 4 | #include <efsw/Lock.hpp> | ||
| 5 | #include <efsw/String.hpp> | ||
| 6 | #include <efsw/System.hpp> | ||
| 7 | |||
| 8 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 9 | |||
| 10 | #include <sys/utsname.h> | ||
| 11 | |||
| 12 | namespace efsw { | ||
| 13 | |||
| 14 | int getOSXReleaseNumber() { | ||
| 15 | static int osxR = -1; | ||
| 16 | |||
| 17 | if ( -1 == osxR ) { | ||
| 18 | struct utsname os; | ||
| 19 | |||
| 20 | if ( -1 != uname( &os ) ) { | ||
| 21 | std::string release( os.release ); | ||
| 22 | |||
| 23 | size_t pos = release.find_first_of( '.' ); | ||
| 24 | |||
| 25 | if ( pos != std::string::npos ) { | ||
| 26 | release = release.substr( 0, pos ); | ||
| 27 | } | ||
| 28 | |||
| 29 | int rel = 0; | ||
| 30 | |||
| 31 | if ( String::fromString<int>( rel, release ) ) { | ||
| 32 | osxR = rel; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | return osxR; | ||
| 38 | } | ||
| 39 | |||
| 40 | bool FileWatcherFSEvents::isGranular() { | ||
| 41 | return getOSXReleaseNumber() >= 11; | ||
| 42 | } | ||
| 43 | |||
| 44 | void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, | ||
| 45 | size_t numEvents, void* eventPaths, | ||
| 46 | const FSEventStreamEventFlags eventFlags[], | ||
| 47 | const FSEventStreamEventId eventIds[] ) { | ||
| 48 | WatcherFSEvents* watcher = static_cast<WatcherFSEvents*>( userData ); | ||
| 49 | |||
| 50 | std::vector<FSEvent> events; | ||
| 51 | events.reserve( numEvents ); | ||
| 52 | |||
| 53 | for ( size_t i = 0; i < numEvents; i++ ) { | ||
| 54 | events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i], | ||
| 55 | (Uint64)eventIds[i] ) ); | ||
| 56 | } | ||
| 57 | |||
| 58 | watcher->handleActions( events ); | ||
| 59 | |||
| 60 | watcher->process(); | ||
| 61 | |||
| 62 | efDEBUG( "\n" ); | ||
| 63 | } | ||
| 64 | |||
| 65 | FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : | ||
| 66 | FileWatcherImpl( parent ), mRunLoopRef( NULL ), mLastWatchID( 0 ), mThread( NULL ) { | ||
| 67 | mInitOK = true; | ||
| 68 | |||
| 69 | watch(); | ||
| 70 | } | ||
| 71 | |||
| 72 | FileWatcherFSEvents::~FileWatcherFSEvents() { | ||
| 73 | mInitOK = false; | ||
| 74 | |||
| 75 | if ( mRunLoopRef.load() ) | ||
| 76 | CFRunLoopStop( mRunLoopRef.load() ); | ||
| 77 | |||
| 78 | efSAFE_DELETE( mThread ); | ||
| 79 | |||
| 80 | WatchMap::iterator iter = mWatches.begin(); | ||
| 81 | |||
| 82 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 83 | WatcherFSEvents* watch = iter->second; | ||
| 84 | |||
| 85 | efSAFE_DELETE( watch ); | ||
| 86 | } | ||
| 87 | |||
| 88 | mWatches.clear(); | ||
| 89 | } | ||
| 90 | |||
| 91 | WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 92 | bool recursive ) { | ||
| 93 | /// Wait to the RunLoopRef to be ready | ||
| 94 | while ( NULL == mRunLoopRef.load() ) { | ||
| 95 | System::sleep( 1 ); | ||
| 96 | } | ||
| 97 | |||
| 98 | std::string dir( directory ); | ||
| 99 | |||
| 100 | FileInfo fi( dir ); | ||
| 101 | |||
| 102 | if ( !fi.isDirectory() ) { | ||
| 103 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 104 | } else if ( !fi.isReadable() ) { | ||
| 105 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
| 106 | } | ||
| 107 | |||
| 108 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 109 | |||
| 110 | if ( pathInWatches( dir ) ) { | ||
| 111 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Check if the directory is a symbolic link | ||
| 115 | std::string curPath; | ||
| 116 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 117 | |||
| 118 | if ( "" != link ) { | ||
| 119 | /// If it's a symlink check if the realpath exists as a watcher, or | ||
| 120 | /// if the path is outside the current dir | ||
| 121 | if ( pathInWatches( link ) ) { | ||
| 122 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 123 | } else if ( !linkAllowed( curPath, link ) ) { | ||
| 124 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 125 | } else { | ||
| 126 | dir = link; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | mLastWatchID++; | ||
| 131 | |||
| 132 | WatcherFSEvents* pWatch = new WatcherFSEvents(); | ||
| 133 | pWatch->Listener = watcher; | ||
| 134 | pWatch->ID = mLastWatchID; | ||
| 135 | pWatch->Directory = dir; | ||
| 136 | pWatch->Recursive = recursive; | ||
| 137 | pWatch->FWatcher = this; | ||
| 138 | |||
| 139 | pWatch->init(); | ||
| 140 | |||
| 141 | Lock lock( mWatchesLock ); | ||
| 142 | mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); | ||
| 143 | |||
| 144 | return pWatch->ID; | ||
| 145 | } | ||
| 146 | |||
| 147 | void FileWatcherFSEvents::removeWatch( const std::string& directory ) { | ||
| 148 | Lock lock( mWatchesLock ); | ||
| 149 | |||
| 150 | WatchMap::iterator iter = mWatches.begin(); | ||
| 151 | |||
| 152 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 153 | if ( directory == iter->second->Directory ) { | ||
| 154 | removeWatch( iter->second->ID ); | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | void FileWatcherFSEvents::removeWatch( WatchID watchid ) { | ||
| 161 | Lock lock( mWatchesLock ); | ||
| 162 | |||
| 163 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 164 | |||
| 165 | if ( iter == mWatches.end() ) | ||
| 166 | return; | ||
| 167 | |||
| 168 | WatcherFSEvents* watch = iter->second; | ||
| 169 | |||
| 170 | mWatches.erase( iter ); | ||
| 171 | |||
| 172 | efDEBUG( "Removed watch %s\n", watch->Directory.c_str() ); | ||
| 173 | |||
| 174 | efSAFE_DELETE( watch ); | ||
| 175 | } | ||
| 176 | |||
| 177 | void FileWatcherFSEvents::watch() { | ||
| 178 | if ( NULL == mThread ) { | ||
| 179 | mThread = new Thread( &FileWatcherFSEvents::run, this ); | ||
| 180 | mThread->launch(); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | void FileWatcherFSEvents::run() { | ||
| 185 | mRunLoopRef = CFRunLoopGetCurrent(); | ||
| 186 | |||
| 187 | while ( mInitOK ) { | ||
| 188 | mNeedInitMutex.lock(); | ||
| 189 | |||
| 190 | if ( !mNeedInit.empty() ) { | ||
| 191 | for ( std::vector<WatcherFSEvents*>::iterator it = mNeedInit.begin(); | ||
| 192 | it != mNeedInit.end(); ++it ) { | ||
| 193 | ( *it )->initAsync(); | ||
| 194 | } | ||
| 195 | |||
| 196 | mNeedInit.clear(); | ||
| 197 | } | ||
| 198 | |||
| 199 | mNeedInitMutex.unlock(); | ||
| 200 | |||
| 201 | if ( mWatches.empty() ) { | ||
| 202 | System::sleep( 100 ); | ||
| 203 | } else { | ||
| 204 | CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut ); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | mRunLoopRef = NULL; | ||
| 209 | } | ||
| 210 | |||
| 211 | void FileWatcherFSEvents::handleAction( Watcher* watch, const std::string& filename, | ||
| 212 | unsigned long action, std::string oldFilename ) { | ||
| 213 | /// Not used | ||
| 214 | } | ||
| 215 | |||
| 216 | std::list<std::string> FileWatcherFSEvents::directories() { | ||
| 217 | std::list<std::string> dirs; | ||
| 218 | |||
| 219 | Lock lock( mWatchesLock ); | ||
| 220 | |||
| 221 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 222 | dirs.push_back( std::string( it->second->Directory ) ); | ||
| 223 | } | ||
| 224 | |||
| 225 | return dirs; | ||
| 226 | } | ||
| 227 | |||
| 228 | bool FileWatcherFSEvents::pathInWatches( const std::string& path ) { | ||
| 229 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 230 | if ( it->second->Directory == path ) { | ||
| 231 | return true; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | return false; | ||
| 236 | } | ||
| 237 | |||
| 238 | } // namespace efsw | ||
| 239 | |||
| 240 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.hpp b/src/3rdParty/efsw/FileWatcherFSEvents.hpp new file mode 100755 index 0000000..5279847 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherFSEvents.hpp | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | #ifndef EFSW_FILEWATCHERFSEVENTS_HPP | ||
| 2 | #define EFSW_FILEWATCHERFSEVENTS_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileWatcherImpl.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 7 | |||
| 8 | #include <CoreFoundation/CoreFoundation.h> | ||
| 9 | #include <CoreServices/CoreServices.h> | ||
| 10 | #include <efsw/WatcherFSEvents.hpp> | ||
| 11 | #include <list> | ||
| 12 | #include <map> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | namespace efsw { | ||
| 16 | |||
| 17 | /* OSX < 10.7 has no file events */ | ||
| 18 | /* So i declare the events constants */ | ||
| 19 | enum FSEventEvents { | ||
| 20 | efswFSEventStreamCreateFlagFileEvents = 0x00000010, | ||
| 21 | efswFSEventStreamEventFlagItemCreated = 0x00000100, | ||
| 22 | efswFSEventStreamEventFlagItemRemoved = 0x00000200, | ||
| 23 | efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, | ||
| 24 | efswFSEventStreamEventFlagItemRenamed = 0x00000800, | ||
| 25 | efswFSEventStreamEventFlagItemModified = 0x00001000, | ||
| 26 | efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, | ||
| 27 | efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, | ||
| 28 | efswFSEventStreamEventFlagItemXattrMod = 0x00008000, | ||
| 29 | efswFSEventStreamEventFlagItemIsFile = 0x00010000, | ||
| 30 | efswFSEventStreamEventFlagItemIsDir = 0x00020000, | ||
| 31 | efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, | ||
| 32 | efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | | ||
| 33 | efswFSEventStreamEventFlagItemModified | | ||
| 34 | efswFSEventStreamEventFlagItemInodeMetaMod | ||
| 35 | }; | ||
| 36 | |||
| 37 | /// Implementation for Win32 based on ReadDirectoryChangesW. | ||
| 38 | /// @class FileWatcherFSEvents | ||
| 39 | class FileWatcherFSEvents : public FileWatcherImpl { | ||
| 40 | friend class WatcherFSEvents; | ||
| 41 | |||
| 42 | public: | ||
| 43 | /// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 ) | ||
| 44 | static bool isGranular(); | ||
| 45 | |||
| 46 | /// type for a map from WatchID to WatcherWin32 pointer | ||
| 47 | typedef std::map<WatchID, WatcherFSEvents*> WatchMap; | ||
| 48 | |||
| 49 | FileWatcherFSEvents( FileWatcher* parent ); | ||
| 50 | |||
| 51 | virtual ~FileWatcherFSEvents(); | ||
| 52 | |||
| 53 | /// Add a directory watch | ||
| 54 | /// On error returns WatchID with Error type. | ||
| 55 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | ||
| 56 | |||
| 57 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | ||
| 58 | void removeWatch( const std::string& directory ); | ||
| 59 | |||
| 60 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 61 | void removeWatch( WatchID watchid ); | ||
| 62 | |||
| 63 | /// Updates the watcher. Must be called often. | ||
| 64 | void watch(); | ||
| 65 | |||
| 66 | /// Handles the action | ||
| 67 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | ||
| 68 | std::string oldFilename = "" ); | ||
| 69 | |||
| 70 | /// @return Returns a list of the directories that are being watched | ||
| 71 | std::list<std::string> directories(); | ||
| 72 | |||
| 73 | protected: | ||
| 74 | static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, | ||
| 75 | void* eventPaths, const FSEventStreamEventFlags eventFlags[], | ||
| 76 | const FSEventStreamEventId eventIds[] ); | ||
| 77 | |||
| 78 | Atomic<CFRunLoopRef> mRunLoopRef; | ||
| 79 | |||
| 80 | /// Vector of WatcherWin32 pointers | ||
| 81 | WatchMap mWatches; | ||
| 82 | |||
| 83 | /// The last watchid | ||
| 84 | WatchID mLastWatchID; | ||
| 85 | |||
| 86 | Thread* mThread; | ||
| 87 | |||
| 88 | Mutex mWatchesLock; | ||
| 89 | |||
| 90 | bool pathInWatches( const std::string& path ); | ||
| 91 | |||
| 92 | std::vector<WatcherFSEvents*> mNeedInit; | ||
| 93 | Mutex mNeedInitMutex; | ||
| 94 | |||
| 95 | private: | ||
| 96 | void run(); | ||
| 97 | }; | ||
| 98 | |||
| 99 | } // namespace efsw | ||
| 100 | |||
| 101 | #endif | ||
| 102 | |||
| 103 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp new file mode 100755 index 0000000..074cff1 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp | |||
| @@ -0,0 +1,156 @@ | |||
| 1 | #include <efsw/FileSystem.hpp> | ||
| 2 | #include <efsw/FileWatcherGeneric.hpp> | ||
| 3 | #include <efsw/Lock.hpp> | ||
| 4 | #include <efsw/System.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | FileWatcherGeneric::FileWatcherGeneric( FileWatcher* parent ) : | ||
| 9 | FileWatcherImpl( parent ), mThread( NULL ), mLastWatchID( 0 ) { | ||
| 10 | mInitOK = true; | ||
| 11 | mIsGeneric = true; | ||
| 12 | } | ||
| 13 | |||
| 14 | FileWatcherGeneric::~FileWatcherGeneric() { | ||
| 15 | mInitOK = false; | ||
| 16 | |||
| 17 | efSAFE_DELETE( mThread ); | ||
| 18 | |||
| 19 | /// Delete the watches | ||
| 20 | WatchList::iterator it = mWatches.begin(); | ||
| 21 | |||
| 22 | for ( ; it != mWatches.end(); ++it ) { | ||
| 23 | efSAFE_DELETE( ( *it ) ); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 28 | bool recursive ) { | ||
| 29 | std::string dir( directory ); | ||
| 30 | |||
| 31 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 32 | |||
| 33 | FileInfo fi( dir ); | ||
| 34 | |||
| 35 | if ( !fi.isDirectory() ) { | ||
| 36 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 37 | } else if ( !fi.isReadable() ) { | ||
| 38 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
| 39 | } else if ( pathInWatches( dir ) ) { | ||
| 40 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); | ||
| 41 | } | ||
| 42 | |||
| 43 | std::string curPath; | ||
| 44 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 45 | |||
| 46 | if ( "" != link ) { | ||
| 47 | if ( pathInWatches( link ) ) { | ||
| 48 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); | ||
| 49 | } else if ( !linkAllowed( curPath, link ) ) { | ||
| 50 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 51 | } else { | ||
| 52 | dir = link; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | mLastWatchID++; | ||
| 57 | |||
| 58 | WatcherGeneric* pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive ); | ||
| 59 | |||
| 60 | Lock lock( mWatchesLock ); | ||
| 61 | mWatches.push_back( pWatch ); | ||
| 62 | |||
| 63 | return pWatch->ID; | ||
| 64 | } | ||
| 65 | |||
| 66 | void FileWatcherGeneric::removeWatch( const std::string& directory ) { | ||
| 67 | WatchList::iterator it = mWatches.begin(); | ||
| 68 | |||
| 69 | for ( ; it != mWatches.end(); ++it ) { | ||
| 70 | if ( ( *it )->Directory == directory ) { | ||
| 71 | WatcherGeneric* watch = ( *it ); | ||
| 72 | |||
| 73 | Lock lock( mWatchesLock ); | ||
| 74 | |||
| 75 | mWatches.erase( it ); | ||
| 76 | |||
| 77 | efSAFE_DELETE( watch ); | ||
| 78 | |||
| 79 | return; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | void FileWatcherGeneric::removeWatch( WatchID watchid ) { | ||
| 85 | WatchList::iterator it = mWatches.begin(); | ||
| 86 | |||
| 87 | for ( ; it != mWatches.end(); ++it ) { | ||
| 88 | if ( ( *it )->ID == watchid ) { | ||
| 89 | WatcherGeneric* watch = ( *it ); | ||
| 90 | |||
| 91 | Lock lock( mWatchesLock ); | ||
| 92 | |||
| 93 | mWatches.erase( it ); | ||
| 94 | |||
| 95 | efSAFE_DELETE( watch ); | ||
| 96 | |||
| 97 | return; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | void FileWatcherGeneric::watch() { | ||
| 103 | if ( NULL == mThread ) { | ||
| 104 | mThread = new Thread( &FileWatcherGeneric::run, this ); | ||
| 105 | mThread->launch(); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | void FileWatcherGeneric::run() { | ||
| 110 | do { | ||
| 111 | { | ||
| 112 | Lock lock( mWatchesLock ); | ||
| 113 | |||
| 114 | WatchList::iterator it = mWatches.begin(); | ||
| 115 | |||
| 116 | for ( ; it != mWatches.end(); ++it ) { | ||
| 117 | ( *it )->watch(); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | if ( mInitOK ) | ||
| 122 | System::sleep( 1000 ); | ||
| 123 | } while ( mInitOK ); | ||
| 124 | } | ||
| 125 | |||
| 126 | void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned long, std::string ) { | ||
| 127 | /// Not used | ||
| 128 | } | ||
| 129 | |||
| 130 | std::list<std::string> FileWatcherGeneric::directories() { | ||
| 131 | std::list<std::string> dirs; | ||
| 132 | |||
| 133 | Lock lock( mWatchesLock ); | ||
| 134 | |||
| 135 | WatchList::iterator it = mWatches.begin(); | ||
| 136 | |||
| 137 | for ( ; it != mWatches.end(); ++it ) { | ||
| 138 | dirs.push_back( ( *it )->Directory ); | ||
| 139 | } | ||
| 140 | |||
| 141 | return dirs; | ||
| 142 | } | ||
| 143 | |||
| 144 | bool FileWatcherGeneric::pathInWatches( const std::string& path ) { | ||
| 145 | WatchList::iterator it = mWatches.begin(); | ||
| 146 | |||
| 147 | for ( ; it != mWatches.end(); ++it ) { | ||
| 148 | if ( ( *it )->Directory == path || ( *it )->pathInWatches( path ) ) { | ||
| 149 | return true; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | return false; | ||
| 154 | } | ||
| 155 | |||
| 156 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.hpp b/src/3rdParty/efsw/FileWatcherGeneric.hpp new file mode 100755 index 0000000..4cb0b67 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherGeneric.hpp | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #ifndef EFSW_FILEWATCHERGENERIC_HPP | ||
| 2 | #define EFSW_FILEWATCHERGENERIC_HPP | ||
| 3 | |||
| 4 | #include <efsw/DirWatcherGeneric.hpp> | ||
| 5 | #include <efsw/FileWatcherImpl.hpp> | ||
| 6 | #include <efsw/WatcherGeneric.hpp> | ||
| 7 | #include <list> | ||
| 8 | |||
| 9 | namespace efsw { | ||
| 10 | |||
| 11 | /// Implementation for Generic File Watcher. | ||
| 12 | /// @class FileWatcherGeneric | ||
| 13 | class FileWatcherGeneric : public FileWatcherImpl { | ||
| 14 | public: | ||
| 15 | typedef std::list<WatcherGeneric*> WatchList; | ||
| 16 | |||
| 17 | FileWatcherGeneric( FileWatcher* parent ); | ||
| 18 | |||
| 19 | virtual ~FileWatcherGeneric(); | ||
| 20 | |||
| 21 | /// Add a directory watch | ||
| 22 | /// On error returns WatchID with Error type. | ||
| 23 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | ||
| 24 | |||
| 25 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | ||
| 26 | void removeWatch( const std::string& directory ); | ||
| 27 | |||
| 28 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 29 | void removeWatch( WatchID watchid ); | ||
| 30 | |||
| 31 | /// Updates the watcher. Must be called often. | ||
| 32 | void watch(); | ||
| 33 | |||
| 34 | /// Handles the action | ||
| 35 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | ||
| 36 | std::string oldFilename = "" ); | ||
| 37 | |||
| 38 | /// @return Returns a list of the directories that are being watched | ||
| 39 | std::list<std::string> directories(); | ||
| 40 | |||
| 41 | protected: | ||
| 42 | Thread* mThread; | ||
| 43 | |||
| 44 | /// The last watchid | ||
| 45 | WatchID mLastWatchID; | ||
| 46 | |||
| 47 | /// Map of WatchID to WatchStruct pointers | ||
| 48 | WatchList mWatches; | ||
| 49 | |||
| 50 | Mutex mWatchesLock; | ||
| 51 | |||
| 52 | bool pathInWatches( const std::string& path ); | ||
| 53 | |||
| 54 | private: | ||
| 55 | void run(); | ||
| 56 | }; | ||
| 57 | |||
| 58 | } // namespace efsw | ||
| 59 | |||
| 60 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherImpl.cpp b/src/3rdParty/efsw/FileWatcherImpl.cpp new file mode 100755 index 0000000..f6b86a5 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherImpl.cpp | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #include <efsw/FileWatcherImpl.hpp> | ||
| 2 | #include <efsw/String.hpp> | ||
| 3 | #include <efsw/System.hpp> | ||
| 4 | |||
| 5 | namespace efsw { | ||
| 6 | |||
| 7 | FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : | ||
| 8 | mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { | ||
| 9 | System::maxFD(); | ||
| 10 | } | ||
| 11 | |||
| 12 | FileWatcherImpl::~FileWatcherImpl() {} | ||
| 13 | |||
| 14 | bool FileWatcherImpl::initOK() { | ||
| 15 | return static_cast<bool>( mInitOK ); | ||
| 16 | } | ||
| 17 | |||
| 18 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { | ||
| 19 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || | ||
| 20 | -1 != String::strStartsWith( curPath, link ); | ||
| 21 | } | ||
| 22 | |||
| 23 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherImpl.hpp b/src/3rdParty/efsw/FileWatcherImpl.hpp new file mode 100755 index 0000000..ea1beb8 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherImpl.hpp | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #ifndef EFSW_FILEWATCHERIMPL_HPP | ||
| 2 | #define EFSW_FILEWATCHERIMPL_HPP | ||
| 3 | |||
| 4 | #include <efsw/Atomic.hpp> | ||
| 5 | #include <efsw/Mutex.hpp> | ||
| 6 | #include <efsw/Thread.hpp> | ||
| 7 | #include <efsw/Watcher.hpp> | ||
| 8 | #include <efsw/base.hpp> | ||
| 9 | #include <efsw/efsw.hpp> | ||
| 10 | |||
| 11 | namespace efsw { | ||
| 12 | |||
| 13 | class FileWatcherImpl { | ||
| 14 | public: | ||
| 15 | FileWatcherImpl( FileWatcher* parent ); | ||
| 16 | |||
| 17 | virtual ~FileWatcherImpl(); | ||
| 18 | |||
| 19 | /// Add a directory watch | ||
| 20 | /// On error returns WatchID with Error type. | ||
| 21 | virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 22 | bool recursive ) = 0; | ||
| 23 | |||
| 24 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | ||
| 25 | virtual void removeWatch( const std::string& directory ) = 0; | ||
| 26 | |||
| 27 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 28 | virtual void removeWatch( WatchID watchid ) = 0; | ||
| 29 | |||
| 30 | /// Updates the watcher. Must be called often. | ||
| 31 | virtual void watch() = 0; | ||
| 32 | |||
| 33 | /// Handles the action | ||
| 34 | virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | ||
| 35 | std::string oldFilename = "" ) = 0; | ||
| 36 | |||
| 37 | /// @return Returns a list of the directories that are being watched | ||
| 38 | virtual std::list<std::string> directories() = 0; | ||
| 39 | |||
| 40 | /// @return true if the backend init successfully | ||
| 41 | virtual bool initOK(); | ||
| 42 | |||
| 43 | /// @return If the link is allowed according to the current path and the state of out scope | ||
| 44 | /// links | ||
| 45 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); | ||
| 46 | |||
| 47 | /// Search if a directory already exists in the watches | ||
| 48 | virtual bool pathInWatches( const std::string& path ) = 0; | ||
| 49 | |||
| 50 | FileWatcher* mFileWatcher; | ||
| 51 | Atomic<bool> mInitOK; | ||
| 52 | bool mIsGeneric; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace efsw | ||
| 56 | |||
| 57 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherInotify.cpp b/src/3rdParty/efsw/FileWatcherInotify.cpp new file mode 100755 index 0000000..e0da76b --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherInotify.cpp | |||
| @@ -0,0 +1,599 @@ | |||
| 1 | #include <efsw/FileWatcherInotify.hpp> | ||
| 2 | |||
| 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | ||
| 4 | |||
| 5 | #include <errno.h> | ||
| 6 | #include <fcntl.h> | ||
| 7 | #include <stdio.h> | ||
| 8 | #include <string.h> | ||
| 9 | #include <sys/stat.h> | ||
| 10 | #include <unistd.h> | ||
| 11 | |||
| 12 | #ifdef EFSW_INOTIFY_NOSYS | ||
| 13 | #include <efsw/inotify-nosys.h> | ||
| 14 | #else | ||
| 15 | #include <sys/inotify.h> | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #include <efsw/Debug.hpp> | ||
| 19 | #include <efsw/FileSystem.hpp> | ||
| 20 | #include <efsw/Lock.hpp> | ||
| 21 | #include <efsw/String.hpp> | ||
| 22 | #include <efsw/System.hpp> | ||
| 23 | |||
| 24 | #define BUFF_SIZE ( ( sizeof( struct inotify_event ) + FILENAME_MAX ) * 1024 ) | ||
| 25 | |||
| 26 | namespace efsw { | ||
| 27 | |||
| 28 | FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : | ||
| 29 | FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ) { | ||
| 30 | mFD = inotify_init(); | ||
| 31 | |||
| 32 | if ( mFD < 0 ) { | ||
| 33 | efDEBUG( "Error: %s\n", strerror( errno ) ); | ||
| 34 | } else { | ||
| 35 | mInitOK = true; | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | FileWatcherInotify::~FileWatcherInotify() { | ||
| 40 | mInitOK = false; | ||
| 41 | |||
| 42 | Lock initLock( mInitLock ); | ||
| 43 | |||
| 44 | efSAFE_DELETE( mThread ); | ||
| 45 | |||
| 46 | Lock l( mWatchesLock ); | ||
| 47 | Lock l2( mRealWatchesLock ); | ||
| 48 | WatchMap::iterator iter = mWatches.begin(); | ||
| 49 | WatchMap::iterator end = mWatches.end(); | ||
| 50 | |||
| 51 | for ( ; iter != end; ++iter ) { | ||
| 52 | efSAFE_DELETE( iter->second ); | ||
| 53 | } | ||
| 54 | |||
| 55 | mWatches.clear(); | ||
| 56 | |||
| 57 | if ( mFD != -1 ) { | ||
| 58 | close( mFD ); | ||
| 59 | mFD = -1; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 64 | bool recursive ) { | ||
| 65 | if ( !mInitOK ) | ||
| 66 | return Errors::Log::createLastError( Errors::Unspecified, directory ); | ||
| 67 | Lock initLock( mInitLock ); | ||
| 68 | return addWatch( directory, watcher, recursive, NULL ); | ||
| 69 | } | ||
| 70 | |||
| 71 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 72 | bool recursive, WatcherInotify* parent ) { | ||
| 73 | std::string dir( directory ); | ||
| 74 | |||
| 75 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 76 | |||
| 77 | FileInfo fi( dir ); | ||
| 78 | |||
| 79 | if ( !fi.isDirectory() ) { | ||
| 80 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 81 | } else if ( !fi.isReadable() ) { | ||
| 82 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
| 83 | } else if ( pathInWatches( dir ) ) { | ||
| 84 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 85 | } else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) { | ||
| 86 | return Errors::Log::createLastError( Errors::FileRemote, dir ); | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Check if the directory is a symbolic link | ||
| 90 | std::string curPath; | ||
| 91 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 92 | |||
| 93 | if ( "" != link ) { | ||
| 94 | /// Avoid adding symlinks directories if it's now enabled | ||
| 95 | if ( NULL != parent && !mFileWatcher->followSymlinks() ) { | ||
| 96 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 97 | } | ||
| 98 | |||
| 99 | /// If it's a symlink check if the realpath exists as a watcher, or | ||
| 100 | /// if the path is outside the current dir | ||
| 101 | if ( pathInWatches( link ) ) { | ||
| 102 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 103 | } else if ( !linkAllowed( curPath, link ) ) { | ||
| 104 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 105 | } else { | ||
| 106 | dir = link; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | int wd = inotify_add_watch( mFD, dir.c_str(), | ||
| 111 | IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | | ||
| 112 | IN_DELETE | IN_MODIFY ); | ||
| 113 | |||
| 114 | if ( wd < 0 ) { | ||
| 115 | if ( errno == ENOENT ) { | ||
| 116 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 117 | } else { | ||
| 118 | return Errors::Log::createLastError( Errors::Unspecified, | ||
| 119 | std::string( strerror( errno ) ) ); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd ); | ||
| 124 | |||
| 125 | WatcherInotify* pWatch = new WatcherInotify(); | ||
| 126 | pWatch->Listener = watcher; | ||
| 127 | pWatch->ID = parent ? parent->ID : wd; | ||
| 128 | pWatch->InotifyID = wd; | ||
| 129 | pWatch->Directory = dir; | ||
| 130 | pWatch->Recursive = recursive; | ||
| 131 | pWatch->Parent = parent; | ||
| 132 | |||
| 133 | { | ||
| 134 | Lock lock( mWatchesLock ); | ||
| 135 | mWatches.insert( std::make_pair( wd, pWatch ) ); | ||
| 136 | } | ||
| 137 | |||
| 138 | if ( NULL == pWatch->Parent ) { | ||
| 139 | Lock l( mRealWatchesLock ); | ||
| 140 | mRealWatches[pWatch->InotifyID] = pWatch; | ||
| 141 | } | ||
| 142 | |||
| 143 | if ( pWatch->Recursive ) { | ||
| 144 | std::map<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory ); | ||
| 145 | std::map<std::string, FileInfo>::iterator it = files.begin(); | ||
| 146 | |||
| 147 | for ( ; it != files.end(); ++it ) { | ||
| 148 | if ( !mInitOK ) | ||
| 149 | break; | ||
| 150 | |||
| 151 | const FileInfo& cfi = it->second; | ||
| 152 | |||
| 153 | if ( cfi.isDirectory() && cfi.isReadable() ) { | ||
| 154 | addWatch( cfi.Filepath, watcher, recursive, pWatch ); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | return wd; | ||
| 160 | } | ||
| 161 | |||
| 162 | void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { | ||
| 163 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 164 | |||
| 165 | WatcherInotify* watch = iter->second; | ||
| 166 | |||
| 167 | for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm = | ||
| 168 | mMovedOutsideWatches.begin(); | ||
| 169 | mMovedOutsideWatches.end() != itm; ++itm ) { | ||
| 170 | if ( itm->first == watch ) { | ||
| 171 | mMovedOutsideWatches.erase( itm ); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | if ( watch->Recursive ) { | ||
| 177 | WatchMap::iterator it = mWatches.begin(); | ||
| 178 | std::list<WatchID> eraseWatches; | ||
| 179 | |||
| 180 | for ( ; it != mWatches.end(); ++it ) { | ||
| 181 | if ( it->second != watch && it->second->inParentTree( watch ) ) { | ||
| 182 | eraseWatches.push_back( it->second->InotifyID ); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); | ||
| 187 | ++eit ) { | ||
| 188 | removeWatch( *eit ); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | mWatches.erase( iter ); | ||
| 193 | |||
| 194 | if ( NULL == watch->Parent ) { | ||
| 195 | WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); | ||
| 196 | |||
| 197 | if ( eraseit != mRealWatches.end() ) { | ||
| 198 | mRealWatches.erase( eraseit ); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | int err = inotify_rm_watch( mFD, watchid ); | ||
| 203 | |||
| 204 | if ( err < 0 ) { | ||
| 205 | efDEBUG( "Error removing watch %d: %s\n", watchid, strerror( errno ) ); | ||
| 206 | } else { | ||
| 207 | efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid ); | ||
| 208 | } | ||
| 209 | |||
| 210 | efSAFE_DELETE( watch ); | ||
| 211 | } | ||
| 212 | |||
| 213 | void FileWatcherInotify::removeWatch( const std::string& directory ) { | ||
| 214 | if ( !mInitOK ) | ||
| 215 | return; | ||
| 216 | Lock initLock( mInitLock ); | ||
| 217 | Lock lock( mWatchesLock ); | ||
| 218 | Lock l( mRealWatchesLock ); | ||
| 219 | |||
| 220 | WatchMap::iterator iter = mWatches.begin(); | ||
| 221 | |||
| 222 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 223 | if ( directory == iter->second->Directory ) { | ||
| 224 | WatcherInotify* watch = iter->second; | ||
| 225 | |||
| 226 | if ( watch->Recursive ) { | ||
| 227 | WatchMap::iterator it = mWatches.begin(); | ||
| 228 | std::list<WatchID> eraseWatches; | ||
| 229 | |||
| 230 | for ( ; it != mWatches.end(); ++it ) { | ||
| 231 | if ( it->second->inParentTree( watch ) ) { | ||
| 232 | eraseWatches.push_back( it->second->InotifyID ); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); | ||
| 237 | eit != eraseWatches.end(); ++eit ) { | ||
| 238 | removeWatchLocked( *eit ); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | mWatches.erase( iter ); | ||
| 243 | |||
| 244 | if ( NULL == watch->Parent ) { | ||
| 245 | WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); | ||
| 246 | |||
| 247 | if ( eraseit != mRealWatches.end() ) { | ||
| 248 | mRealWatches.erase( eraseit ); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | int err = inotify_rm_watch( mFD, watch->InotifyID ); | ||
| 253 | |||
| 254 | if ( err < 0 ) { | ||
| 255 | efDEBUG( "Error removing watch %d: %s\n", watch->InotifyID, strerror( errno ) ); | ||
| 256 | } else { | ||
| 257 | efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), | ||
| 258 | watch->InotifyID ); | ||
| 259 | } | ||
| 260 | |||
| 261 | efSAFE_DELETE( watch ); | ||
| 262 | |||
| 263 | break; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | void FileWatcherInotify::removeWatch( WatchID watchid ) { | ||
| 269 | if ( !mInitOK ) | ||
| 270 | return; | ||
| 271 | Lock initLock( mInitLock ); | ||
| 272 | Lock lock( mWatchesLock ); | ||
| 273 | |||
| 274 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 275 | |||
| 276 | if ( iter == mWatches.end() ) { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | removeWatchLocked( watchid ); | ||
| 281 | } | ||
| 282 | |||
| 283 | void FileWatcherInotify::watch() { | ||
| 284 | if ( NULL == mThread ) { | ||
| 285 | mThread = new Thread( &FileWatcherInotify::run, this ); | ||
| 286 | mThread->launch(); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) { | ||
| 291 | FileSystem::dirRemoveSlashAtEnd( dir ); | ||
| 292 | std::string watcherPath = FileSystem::pathRemoveFileName( dir ); | ||
| 293 | FileSystem::dirAddSlashAtEnd( watcherPath ); | ||
| 294 | Lock lock( mWatchesLock ); | ||
| 295 | |||
| 296 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 297 | Watcher* watcher = it->second; | ||
| 298 | |||
| 299 | if ( watcher->Directory == watcherPath ) { | ||
| 300 | return watcher; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | return NULL; | ||
| 305 | } | ||
| 306 | |||
| 307 | void FileWatcherInotify::run() { | ||
| 308 | char* buff = new char[BUFF_SIZE]; | ||
| 309 | memset( buff, 0, BUFF_SIZE ); | ||
| 310 | WatchMap::iterator wit; | ||
| 311 | |||
| 312 | WatcherInotify* currentMoveFrom = NULL; | ||
| 313 | u_int32_t currentMoveCookie = -1; | ||
| 314 | bool lastWasMovedFrom = false; | ||
| 315 | std::string prevOldFileName; | ||
| 316 | |||
| 317 | do { | ||
| 318 | fd_set rfds; | ||
| 319 | FD_ZERO( &rfds ); | ||
| 320 | FD_SET( mFD, &rfds ); | ||
| 321 | timeval timeout; | ||
| 322 | timeout.tv_sec = 0; | ||
| 323 | timeout.tv_usec = 100000; | ||
| 324 | |||
| 325 | if ( select( FD_SETSIZE, &rfds, NULL, NULL, &timeout ) > 0 ) { | ||
| 326 | ssize_t len; | ||
| 327 | |||
| 328 | len = read( mFD, buff, BUFF_SIZE ); | ||
| 329 | |||
| 330 | if ( len != -1 ) { | ||
| 331 | ssize_t i = 0; | ||
| 332 | |||
| 333 | while ( i < len ) { | ||
| 334 | struct inotify_event* pevent = (struct inotify_event*)&buff[i]; | ||
| 335 | |||
| 336 | { | ||
| 337 | { | ||
| 338 | Lock lock( mWatchesLock ); | ||
| 339 | |||
| 340 | wit = mWatches.find( pevent->wd ); | ||
| 341 | } | ||
| 342 | |||
| 343 | if ( wit != mWatches.end() ) { | ||
| 344 | handleAction( wit->second, (char*)pevent->name, pevent->mask ); | ||
| 345 | |||
| 346 | if ( ( pevent->mask & IN_MOVED_TO ) && wit->second == currentMoveFrom && | ||
| 347 | pevent->cookie == currentMoveCookie ) { | ||
| 348 | /// make pair success | ||
| 349 | currentMoveFrom = NULL; | ||
| 350 | currentMoveCookie = -1; | ||
| 351 | } else if ( pevent->mask & IN_MOVED_FROM ) { | ||
| 352 | // Previous event was moved from and current event is moved from | ||
| 353 | // Treat it as a DELETE or moved ouside watches | ||
| 354 | if ( lastWasMovedFrom && currentMoveFrom ) { | ||
| 355 | mMovedOutsideWatches.push_back( | ||
| 356 | std::make_pair( currentMoveFrom, prevOldFileName ) ); | ||
| 357 | } | ||
| 358 | |||
| 359 | currentMoveFrom = wit->second; | ||
| 360 | currentMoveCookie = pevent->cookie; | ||
| 361 | } else { | ||
| 362 | /// Keep track of the IN_MOVED_FROM events to know | ||
| 363 | /// if the IN_MOVED_TO event is also fired | ||
| 364 | if ( currentMoveFrom ) { | ||
| 365 | mMovedOutsideWatches.push_back( | ||
| 366 | std::make_pair( currentMoveFrom, prevOldFileName ) ); | ||
| 367 | } | ||
| 368 | |||
| 369 | currentMoveFrom = NULL; | ||
| 370 | currentMoveCookie = -1; | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | lastWasMovedFrom = ( pevent->mask & IN_MOVED_FROM ) != 0; | ||
| 375 | if ( pevent->mask & IN_MOVED_FROM ) | ||
| 376 | prevOldFileName = std::string( (char*)pevent->name ); | ||
| 377 | } | ||
| 378 | |||
| 379 | i += sizeof( struct inotify_event ) + pevent->len; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } else { | ||
| 383 | // Here means no event received | ||
| 384 | // If last event is IN_MOVED_FROM, we assume no IN_MOVED_TO | ||
| 385 | if ( currentMoveFrom ) { | ||
| 386 | mMovedOutsideWatches.push_back( | ||
| 387 | std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) ); | ||
| 388 | } | ||
| 389 | |||
| 390 | currentMoveFrom = NULL; | ||
| 391 | currentMoveCookie = -1; | ||
| 392 | } | ||
| 393 | |||
| 394 | if ( !mMovedOutsideWatches.empty() ) { | ||
| 395 | // We need to make a copy since the element mMovedOutsideWatches could be modified | ||
| 396 | // during the iteration. | ||
| 397 | std::vector<std::pair<WatcherInotify*, std::string>> movedOutsideWatches( | ||
| 398 | mMovedOutsideWatches ); | ||
| 399 | |||
| 400 | /// In case that the IN_MOVED_TO is never fired means that the file was moved to other | ||
| 401 | /// folder | ||
| 402 | for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator it = | ||
| 403 | movedOutsideWatches.begin(); | ||
| 404 | it != movedOutsideWatches.end(); ++it ) { | ||
| 405 | |||
| 406 | // Skip if the watch has already being removed | ||
| 407 | if ( mMovedOutsideWatches.size() != movedOutsideWatches.size() ) { | ||
| 408 | bool found = false; | ||
| 409 | for ( std::vector<std::pair<WatcherInotify*, std::string>>::iterator itm = | ||
| 410 | mMovedOutsideWatches.begin(); | ||
| 411 | mMovedOutsideWatches.end() != itm; ++itm ) { | ||
| 412 | if ( itm->first == it->first ) { | ||
| 413 | found = true; | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | if ( !found ) | ||
| 418 | continue; | ||
| 419 | } | ||
| 420 | |||
| 421 | Watcher* watch = ( *it ).first; | ||
| 422 | const std::string& oldFileName = ( *it ).second; | ||
| 423 | |||
| 424 | /// Check if the file move was a folder already being watched | ||
| 425 | std::list<Watcher*> eraseWatches; | ||
| 426 | |||
| 427 | { | ||
| 428 | Lock lock( mWatchesLock ); | ||
| 429 | |||
| 430 | for ( ; wit != mWatches.end(); ++wit ) { | ||
| 431 | Watcher* oldWatch = wit->second; | ||
| 432 | |||
| 433 | if ( oldWatch != watch && | ||
| 434 | -1 != String::strStartsWith( watch->Directory + oldFileName + "/", | ||
| 435 | oldWatch->Directory ) ) { | ||
| 436 | eraseWatches.push_back( oldWatch ); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | /// Remove invalid watches | ||
| 442 | eraseWatches.sort(); | ||
| 443 | |||
| 444 | if ( eraseWatches.empty() ) { | ||
| 445 | handleAction( watch, oldFileName, IN_DELETE ); | ||
| 446 | } else { | ||
| 447 | for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); | ||
| 448 | eit != eraseWatches.rend(); ++eit ) { | ||
| 449 | Watcher* rmWatch = *eit; | ||
| 450 | |||
| 451 | /// Create Delete event for removed watches that have been moved too | ||
| 452 | if ( Watcher* cntWatch = watcherContainsDirectory( rmWatch->Directory ) ) { | ||
| 453 | handleAction( cntWatch, | ||
| 454 | FileSystem::fileNameFromPath( rmWatch->Directory ), | ||
| 455 | IN_DELETE ); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | mMovedOutsideWatches.clear(); | ||
| 462 | } | ||
| 463 | } while ( mInitOK ); | ||
| 464 | |||
| 465 | delete[] buff; | ||
| 466 | } | ||
| 467 | |||
| 468 | void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) { | ||
| 469 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 470 | |||
| 471 | /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher | ||
| 472 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | ||
| 473 | bool found = false; | ||
| 474 | |||
| 475 | { | ||
| 476 | Lock lock( mWatchesLock ); | ||
| 477 | |||
| 478 | /// First check if exists | ||
| 479 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 480 | if ( it->second->Directory == fpath ) { | ||
| 481 | found = true; | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | if ( !found ) { | ||
| 488 | addWatch( fpath, watch->Listener, watch->Recursive, | ||
| 489 | static_cast<WatcherInotify*>( watch ) ); | ||
| 490 | } | ||
| 491 | } | ||
| 492 | } | ||
| 493 | |||
| 494 | void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, | ||
| 495 | unsigned long action, std::string ) { | ||
| 496 | if ( !watch || !watch->Listener || !mInitOK ) { | ||
| 497 | return; | ||
| 498 | } | ||
| 499 | |||
| 500 | Lock initLock( mInitLock ); | ||
| 501 | |||
| 502 | std::string fpath( watch->Directory + filename ); | ||
| 503 | |||
| 504 | if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) { | ||
| 505 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 506 | Actions::Modified ); | ||
| 507 | } else if ( IN_MOVED_TO & action ) { | ||
| 508 | /// If OldFileName doesn't exist means that the file has been moved from other folder, so we | ||
| 509 | /// just send the Add event | ||
| 510 | if ( watch->OldFileName.empty() ) { | ||
| 511 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 512 | Actions::Add ); | ||
| 513 | |||
| 514 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 515 | Actions::Modified ); | ||
| 516 | |||
| 517 | checkForNewWatcher( watch, fpath ); | ||
| 518 | } else { | ||
| 519 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, | ||
| 520 | Actions::Moved, watch->OldFileName ); | ||
| 521 | } | ||
| 522 | |||
| 523 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | ||
| 524 | /// Update the new directory path | ||
| 525 | std::string opath( watch->Directory + watch->OldFileName ); | ||
| 526 | FileSystem::dirAddSlashAtEnd( opath ); | ||
| 527 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 528 | |||
| 529 | Lock lock( mWatchesLock ); | ||
| 530 | |||
| 531 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 532 | if ( it->second->Directory == opath ) { | ||
| 533 | it->second->Directory = fpath; | ||
| 534 | it->second->DirInfo = FileInfo( fpath ); | ||
| 535 | } else if ( -1 != String::strStartsWith( opath, it->second->Directory ) ) { | ||
| 536 | it->second->Directory = fpath + it->second->Directory.substr( opath.size() ); | ||
| 537 | it->second->DirInfo.Filepath = it->second->Directory; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | watch->OldFileName = ""; | ||
| 543 | } else if ( IN_CREATE & action ) { | ||
| 544 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); | ||
| 545 | |||
| 546 | checkForNewWatcher( watch, fpath ); | ||
| 547 | } else if ( IN_MOVED_FROM & action ) { | ||
| 548 | watch->OldFileName = filename; | ||
| 549 | } else if ( IN_DELETE & action ) { | ||
| 550 | watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete ); | ||
| 551 | |||
| 552 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 553 | |||
| 554 | /// If the file erased is a directory and recursive is enabled, removes the directory erased | ||
| 555 | if ( watch->Recursive ) { | ||
| 556 | Lock l( mWatchesLock ); | ||
| 557 | |||
| 558 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 559 | if ( it->second->Directory == fpath ) { | ||
| 560 | removeWatchLocked( it->second->InotifyID ); | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | } | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | std::list<std::string> FileWatcherInotify::directories() { | ||
| 569 | std::list<std::string> dirs; | ||
| 570 | |||
| 571 | Lock l( mRealWatchesLock ); | ||
| 572 | |||
| 573 | WatchMap::iterator it = mRealWatches.begin(); | ||
| 574 | |||
| 575 | for ( ; it != mRealWatches.end(); ++it ) { | ||
| 576 | dirs.push_back( it->second->Directory ); | ||
| 577 | } | ||
| 578 | |||
| 579 | return dirs; | ||
| 580 | } | ||
| 581 | |||
| 582 | bool FileWatcherInotify::pathInWatches( const std::string& path ) { | ||
| 583 | Lock l( mRealWatchesLock ); | ||
| 584 | |||
| 585 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir | ||
| 586 | WatchMap::iterator it = mRealWatches.begin(); | ||
| 587 | |||
| 588 | for ( ; it != mRealWatches.end(); ++it ) { | ||
| 589 | if ( it->second->Directory == path ) { | ||
| 590 | return true; | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 594 | return false; | ||
| 595 | } | ||
| 596 | |||
| 597 | } // namespace efsw | ||
| 598 | |||
| 599 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherInotify.hpp b/src/3rdParty/efsw/FileWatcherInotify.hpp new file mode 100755 index 0000000..dc922ac --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherInotify.hpp | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | #ifndef EFSW_FILEWATCHERLINUX_HPP | ||
| 2 | #define EFSW_FILEWATCHERLINUX_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileWatcherImpl.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | ||
| 7 | |||
| 8 | #include <efsw/WatcherInotify.hpp> | ||
| 9 | #include <map> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | namespace efsw { | ||
| 13 | |||
| 14 | /// Implementation for Linux based on inotify. | ||
| 15 | /// @class FileWatcherInotify | ||
| 16 | class FileWatcherInotify : public FileWatcherImpl { | ||
| 17 | public: | ||
| 18 | /// type for a map from WatchID to WatchStruct pointer | ||
| 19 | typedef std::map<WatchID, WatcherInotify*> WatchMap; | ||
| 20 | |||
| 21 | FileWatcherInotify( FileWatcher* parent ); | ||
| 22 | |||
| 23 | virtual ~FileWatcherInotify(); | ||
| 24 | |||
| 25 | /// Add a directory watch | ||
| 26 | /// On error returns WatchID with Error type. | ||
| 27 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | ||
| 28 | |||
| 29 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | ||
| 30 | void removeWatch( const std::string& directory ); | ||
| 31 | |||
| 32 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 33 | void removeWatch( WatchID watchid ); | ||
| 34 | |||
| 35 | /// Updates the watcher. Must be called often. | ||
| 36 | void watch(); | ||
| 37 | |||
| 38 | /// Handles the action | ||
| 39 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | ||
| 40 | std::string oldFilename = "" ); | ||
| 41 | |||
| 42 | /// @return Returns a list of the directories that are being watched | ||
| 43 | std::list<std::string> directories(); | ||
| 44 | |||
| 45 | protected: | ||
| 46 | /// Map of WatchID to WatchStruct pointers | ||
| 47 | WatchMap mWatches; | ||
| 48 | |||
| 49 | /// User added watches | ||
| 50 | WatchMap mRealWatches; | ||
| 51 | |||
| 52 | /// inotify file descriptor | ||
| 53 | int mFD; | ||
| 54 | |||
| 55 | Thread* mThread; | ||
| 56 | |||
| 57 | Mutex mWatchesLock; | ||
| 58 | Mutex mRealWatchesLock; | ||
| 59 | Mutex mInitLock; | ||
| 60 | std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches; | ||
| 61 | |||
| 62 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, | ||
| 63 | WatcherInotify* parent = NULL ); | ||
| 64 | |||
| 65 | bool pathInWatches( const std::string& path ); | ||
| 66 | |||
| 67 | private: | ||
| 68 | void run(); | ||
| 69 | |||
| 70 | void removeWatchLocked( WatchID watchid ); | ||
| 71 | |||
| 72 | void checkForNewWatcher( Watcher* watch, std::string fpath ); | ||
| 73 | |||
| 74 | Watcher* watcherContainsDirectory( std::string dir ); | ||
| 75 | }; | ||
| 76 | |||
| 77 | } // namespace efsw | ||
| 78 | |||
| 79 | #endif | ||
| 80 | |||
| 81 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.cpp b/src/3rdParty/efsw/FileWatcherKqueue.cpp new file mode 100755 index 0000000..9c86755 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherKqueue.cpp | |||
| @@ -0,0 +1,227 @@ | |||
| 1 | #include <efsw/FileWatcherKqueue.hpp> | ||
| 2 | |||
| 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 4 | |||
| 5 | #include <dirent.h> | ||
| 6 | #include <efsw/Debug.hpp> | ||
| 7 | #include <efsw/FileSystem.hpp> | ||
| 8 | #include <efsw/Lock.hpp> | ||
| 9 | #include <efsw/System.hpp> | ||
| 10 | #include <efsw/WatcherGeneric.hpp> | ||
| 11 | #include <errno.h> | ||
| 12 | #include <fcntl.h> | ||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <string.h> | ||
| 16 | #include <sys/stat.h> | ||
| 17 | #include <sys/time.h> | ||
| 18 | #include <unistd.h> | ||
| 19 | |||
| 20 | namespace efsw { | ||
| 21 | |||
| 22 | FileWatcherKqueue::FileWatcherKqueue( FileWatcher* parent ) : | ||
| 23 | FileWatcherImpl( parent ), | ||
| 24 | mLastWatchID( 0 ), | ||
| 25 | mThread( NULL ), | ||
| 26 | mFileDescriptorCount( 1 ), | ||
| 27 | mAddingWatcher( false ) { | ||
| 28 | mTimeOut.tv_sec = 0; | ||
| 29 | mTimeOut.tv_nsec = 0; | ||
| 30 | mInitOK = true; | ||
| 31 | } | ||
| 32 | |||
| 33 | FileWatcherKqueue::~FileWatcherKqueue() { | ||
| 34 | WatchMap::iterator iter = mWatches.begin(); | ||
| 35 | |||
| 36 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 37 | efSAFE_DELETE( iter->second ); | ||
| 38 | } | ||
| 39 | |||
| 40 | mWatches.clear(); | ||
| 41 | |||
| 42 | mInitOK = false; | ||
| 43 | |||
| 44 | efSAFE_DELETE( mThread ); | ||
| 45 | } | ||
| 46 | |||
| 47 | WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 48 | bool recursive ) { | ||
| 49 | static bool s_ug = false; | ||
| 50 | |||
| 51 | std::string dir( directory ); | ||
| 52 | |||
| 53 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 54 | |||
| 55 | FileInfo fi( dir ); | ||
| 56 | |||
| 57 | if ( !fi.isDirectory() ) { | ||
| 58 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 59 | } else if ( !fi.isReadable() ) { | ||
| 60 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
| 61 | } else if ( pathInWatches( dir ) ) { | ||
| 62 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 63 | } | ||
| 64 | |||
| 65 | std::string curPath; | ||
| 66 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 67 | |||
| 68 | if ( "" != link ) { | ||
| 69 | if ( pathInWatches( link ) ) { | ||
| 70 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 71 | } else if ( !linkAllowed( curPath, link ) ) { | ||
| 72 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 73 | } else { | ||
| 74 | dir = link; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Check first if are enough file descriptors available to create another kqueue watcher, | ||
| 79 | /// otherwise it creates a generic watcher | ||
| 80 | if ( availablesFD() ) { | ||
| 81 | mAddingWatcher = true; | ||
| 82 | |||
| 83 | WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this ); | ||
| 84 | |||
| 85 | { | ||
| 86 | Lock lock( mWatchesLock ); | ||
| 87 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
| 88 | } | ||
| 89 | |||
| 90 | watch->addAll(); | ||
| 91 | |||
| 92 | // if failed to open the directory... erase the watcher | ||
| 93 | if ( !watch->initOK() ) { | ||
| 94 | int le = watch->lastErrno(); | ||
| 95 | |||
| 96 | mWatches.erase( watch->ID ); | ||
| 97 | |||
| 98 | efSAFE_DELETE( watch ); | ||
| 99 | |||
| 100 | mLastWatchID--; | ||
| 101 | |||
| 102 | // Probably the folder has too many files, create a generic watcher | ||
| 103 | if ( EACCES != le ) { | ||
| 104 | WatcherGeneric* genericWatch = | ||
| 105 | new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); | ||
| 106 | |||
| 107 | Lock lock( mWatchesLock ); | ||
| 108 | mWatches.insert( std::make_pair( mLastWatchID, genericWatch ) ); | ||
| 109 | } else { | ||
| 110 | return Errors::Log::createLastError( Errors::Unspecified, link ); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | mAddingWatcher = false; | ||
| 115 | } else { | ||
| 116 | if ( !s_ug ) { | ||
| 117 | efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", | ||
| 118 | mFileDescriptorCount ); | ||
| 119 | s_ug = true; | ||
| 120 | } | ||
| 121 | |||
| 122 | WatcherGeneric* watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); | ||
| 123 | |||
| 124 | Lock lock( mWatchesLock ); | ||
| 125 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
| 126 | } | ||
| 127 | |||
| 128 | return mLastWatchID; | ||
| 129 | } | ||
| 130 | |||
| 131 | void FileWatcherKqueue::removeWatch( const std::string& directory ) { | ||
| 132 | Lock lock( mWatchesLock ); | ||
| 133 | |||
| 134 | WatchMap::iterator iter = mWatches.begin(); | ||
| 135 | |||
| 136 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 137 | if ( directory == iter->second->Directory ) { | ||
| 138 | removeWatch( iter->first ); | ||
| 139 | return; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | void FileWatcherKqueue::removeWatch( WatchID watchid ) { | ||
| 145 | Lock lock( mWatchesLock ); | ||
| 146 | |||
| 147 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 148 | |||
| 149 | if ( iter == mWatches.end() ) | ||
| 150 | return; | ||
| 151 | |||
| 152 | Watcher* watch = iter->second; | ||
| 153 | |||
| 154 | mWatches.erase( iter ); | ||
| 155 | |||
| 156 | efSAFE_DELETE( watch ); | ||
| 157 | } | ||
| 158 | |||
| 159 | bool FileWatcherKqueue::isAddingWatcher() const { | ||
| 160 | return mAddingWatcher; | ||
| 161 | } | ||
| 162 | |||
| 163 | void FileWatcherKqueue::watch() { | ||
| 164 | if ( NULL == mThread ) { | ||
| 165 | mThread = new Thread( &FileWatcherKqueue::run, this ); | ||
| 166 | mThread->launch(); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | void FileWatcherKqueue::run() { | ||
| 171 | do { | ||
| 172 | { | ||
| 173 | Lock lock( mWatchesLock ); | ||
| 174 | |||
| 175 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 176 | it->second->watch(); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | System::sleep( 500 ); | ||
| 181 | } while ( mInitOK ); | ||
| 182 | } | ||
| 183 | |||
| 184 | void FileWatcherKqueue::handleAction( Watcher* watch, const std::string& filename, | ||
| 185 | unsigned long action, std::string oldFilename ) {} | ||
| 186 | |||
| 187 | std::list<std::string> FileWatcherKqueue::directories() { | ||
| 188 | std::list<std::string> dirs; | ||
| 189 | |||
| 190 | Lock lock( mWatchesLock ); | ||
| 191 | |||
| 192 | WatchMap::iterator it = mWatches.begin(); | ||
| 193 | |||
| 194 | for ( ; it != mWatches.end(); ++it ) { | ||
| 195 | dirs.push_back( it->second->Directory ); | ||
| 196 | } | ||
| 197 | |||
| 198 | return dirs; | ||
| 199 | } | ||
| 200 | |||
| 201 | bool FileWatcherKqueue::pathInWatches( const std::string& path ) { | ||
| 202 | WatchMap::iterator it = mWatches.begin(); | ||
| 203 | |||
| 204 | for ( ; it != mWatches.end(); ++it ) { | ||
| 205 | if ( it->second->Directory == path ) { | ||
| 206 | return true; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | return false; | ||
| 211 | } | ||
| 212 | |||
| 213 | void FileWatcherKqueue::addFD() { | ||
| 214 | mFileDescriptorCount++; | ||
| 215 | } | ||
| 216 | |||
| 217 | void FileWatcherKqueue::removeFD() { | ||
| 218 | mFileDescriptorCount--; | ||
| 219 | } | ||
| 220 | |||
| 221 | bool FileWatcherKqueue::availablesFD() { | ||
| 222 | return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500; | ||
| 223 | } | ||
| 224 | |||
| 225 | } // namespace efsw | ||
| 226 | |||
| 227 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.hpp b/src/3rdParty/efsw/FileWatcherKqueue.hpp new file mode 100755 index 0000000..1bf3755 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherKqueue.hpp | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | #ifndef EFSW_FILEWATCHEROSX_HPP | ||
| 2 | #define EFSW_FILEWATCHEROSX_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileWatcherImpl.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 7 | |||
| 8 | #include <efsw/WatcherKqueue.hpp> | ||
| 9 | |||
| 10 | namespace efsw { | ||
| 11 | |||
| 12 | /// Implementation for OSX based on kqueue. | ||
| 13 | /// @class FileWatcherKqueue | ||
| 14 | class FileWatcherKqueue : public FileWatcherImpl { | ||
| 15 | friend class WatcherKqueue; | ||
| 16 | |||
| 17 | public: | ||
| 18 | FileWatcherKqueue( FileWatcher* parent ); | ||
| 19 | |||
| 20 | virtual ~FileWatcherKqueue(); | ||
| 21 | |||
| 22 | /// Add a directory watch | ||
| 23 | /// On error returns WatchID with Error type. | ||
| 24 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | ||
| 25 | |||
| 26 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | ||
| 27 | void removeWatch( const std::string& directory ); | ||
| 28 | |||
| 29 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 30 | void removeWatch( WatchID watchid ); | ||
| 31 | |||
| 32 | /// Updates the watcher. Must be called often. | ||
| 33 | void watch(); | ||
| 34 | |||
| 35 | /// Handles the action | ||
| 36 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | ||
| 37 | std::string oldFilename = "" ); | ||
| 38 | |||
| 39 | /// @return Returns a list of the directories that are being watched | ||
| 40 | std::list<std::string> directories(); | ||
| 41 | |||
| 42 | protected: | ||
| 43 | /// Map of WatchID to WatchStruct pointers | ||
| 44 | WatchMap mWatches; | ||
| 45 | |||
| 46 | /// time out data | ||
| 47 | struct timespec mTimeOut; | ||
| 48 | |||
| 49 | /// WatchID allocator | ||
| 50 | int mLastWatchID; | ||
| 51 | |||
| 52 | Thread* mThread; | ||
| 53 | |||
| 54 | Mutex mWatchesLock; | ||
| 55 | |||
| 56 | std::list<WatchID> mRemoveList; | ||
| 57 | |||
| 58 | long mFileDescriptorCount; | ||
| 59 | |||
| 60 | bool mAddingWatcher; | ||
| 61 | |||
| 62 | bool isAddingWatcher() const; | ||
| 63 | |||
| 64 | bool pathInWatches( const std::string& path ); | ||
| 65 | |||
| 66 | void addFD(); | ||
| 67 | |||
| 68 | void removeFD(); | ||
| 69 | |||
| 70 | bool availablesFD(); | ||
| 71 | |||
| 72 | private: | ||
| 73 | void run(); | ||
| 74 | }; | ||
| 75 | |||
| 76 | } // namespace efsw | ||
| 77 | |||
| 78 | #endif | ||
| 79 | |||
| 80 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherWin32.cpp b/src/3rdParty/efsw/FileWatcherWin32.cpp new file mode 100755 index 0000000..963dc98 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherWin32.cpp | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | #include <efsw/FileSystem.hpp> | ||
| 2 | #include <efsw/FileWatcherWin32.hpp> | ||
| 3 | #include <efsw/Lock.hpp> | ||
| 4 | #include <efsw/String.hpp> | ||
| 5 | #include <efsw/System.hpp> | ||
| 6 | |||
| 7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 8 | |||
| 9 | namespace efsw { | ||
| 10 | |||
| 11 | FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : | ||
| 12 | FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { | ||
| 13 | mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); | ||
| 14 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) | ||
| 15 | mInitOK = true; | ||
| 16 | } | ||
| 17 | |||
| 18 | FileWatcherWin32::~FileWatcherWin32() { | ||
| 19 | mInitOK = false; | ||
| 20 | |||
| 21 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { | ||
| 22 | PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); | ||
| 23 | } | ||
| 24 | |||
| 25 | efSAFE_DELETE( mThread ); | ||
| 26 | |||
| 27 | removeAllWatches(); | ||
| 28 | |||
| 29 | CloseHandle( mIOCP ); | ||
| 30 | } | ||
| 31 | |||
| 32 | WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 33 | bool recursive ) { | ||
| 34 | std::string dir( directory ); | ||
| 35 | |||
| 36 | FileInfo fi( dir ); | ||
| 37 | |||
| 38 | if ( !fi.isDirectory() ) { | ||
| 39 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 40 | } else if ( !fi.isReadable() ) { | ||
| 41 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
| 42 | } | ||
| 43 | |||
| 44 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 45 | |||
| 46 | Lock lock( mWatchesLock ); | ||
| 47 | |||
| 48 | if ( pathInWatches( dir ) ) { | ||
| 49 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); | ||
| 50 | } | ||
| 51 | |||
| 52 | WatchID watchid = ++mLastWatchID; | ||
| 53 | |||
| 54 | WatcherStructWin32* watch = CreateWatch( | ||
| 55 | String::fromUtf8( dir ).toWideString().c_str(), recursive, | ||
| 56 | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME | | ||
| 57 | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE, | ||
| 58 | mIOCP ); | ||
| 59 | |||
| 60 | if ( NULL == watch ) { | ||
| 61 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 62 | } | ||
| 63 | |||
| 64 | // Add the handle to the handles vector | ||
| 65 | watch->Watch->ID = watchid; | ||
| 66 | watch->Watch->Watch = this; | ||
| 67 | watch->Watch->Listener = watcher; | ||
| 68 | watch->Watch->DirName = new char[dir.length() + 1]; | ||
| 69 | strcpy( watch->Watch->DirName, dir.c_str() ); | ||
| 70 | |||
| 71 | mWatches.insert( watch ); | ||
| 72 | |||
| 73 | return watchid; | ||
| 74 | } | ||
| 75 | |||
| 76 | void FileWatcherWin32::removeWatch( const std::string& directory ) { | ||
| 77 | Lock lock( mWatchesLock ); | ||
| 78 | |||
| 79 | Watches::iterator iter = mWatches.begin(); | ||
| 80 | |||
| 81 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 82 | if ( directory == ( *iter )->Watch->DirName ) { | ||
| 83 | removeWatch( *iter ); | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | void FileWatcherWin32::removeWatch( WatchID watchid ) { | ||
| 90 | Lock lock( mWatchesLock ); | ||
| 91 | |||
| 92 | Watches::iterator iter = mWatches.begin(); | ||
| 93 | |||
| 94 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 95 | // Find the watch ID | ||
| 96 | if ( ( *iter )->Watch->ID == watchid ) { | ||
| 97 | removeWatch( *iter ); | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { | ||
| 104 | Lock lock( mWatchesLock ); | ||
| 105 | |||
| 106 | DestroyWatch( watch ); | ||
| 107 | mWatches.erase( watch ); | ||
| 108 | } | ||
| 109 | |||
| 110 | void FileWatcherWin32::watch() { | ||
| 111 | if ( NULL == mThread ) { | ||
| 112 | mThread = new Thread( &FileWatcherWin32::run, this ); | ||
| 113 | mThread->launch(); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | void FileWatcherWin32::removeAllWatches() { | ||
| 118 | Lock lock( mWatchesLock ); | ||
| 119 | |||
| 120 | Watches::iterator iter = mWatches.begin(); | ||
| 121 | |||
| 122 | for ( ; iter != mWatches.end(); ++iter ) { | ||
| 123 | DestroyWatch( ( *iter ) ); | ||
| 124 | } | ||
| 125 | |||
| 126 | mWatches.clear(); | ||
| 127 | } | ||
| 128 | |||
| 129 | void FileWatcherWin32::run() { | ||
| 130 | do { | ||
| 131 | if ( mInitOK && !mWatches.empty() ) { | ||
| 132 | DWORD numOfBytes = 0; | ||
| 133 | OVERLAPPED* ov = NULL; | ||
| 134 | ULONG_PTR compKey = 0; | ||
| 135 | BOOL res = FALSE; | ||
| 136 | |||
| 137 | while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, | ||
| 138 | INFINITE ) ) != FALSE ) { | ||
| 139 | if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { | ||
| 140 | break; | ||
| 141 | } else { | ||
| 142 | Lock lock( mWatchesLock ); | ||
| 143 | WatchCallback( numOfBytes, ov ); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } else { | ||
| 147 | System::sleep( 10 ); | ||
| 148 | } | ||
| 149 | } while ( mInitOK ); | ||
| 150 | |||
| 151 | removeAllWatches(); | ||
| 152 | } | ||
| 153 | |||
| 154 | void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, | ||
| 155 | unsigned long action, std::string /*oldFilename*/ ) { | ||
| 156 | Action fwAction; | ||
| 157 | |||
| 158 | switch ( action ) { | ||
| 159 | case FILE_ACTION_RENAMED_OLD_NAME: | ||
| 160 | watch->OldFileName = filename; | ||
| 161 | return; | ||
| 162 | case FILE_ACTION_ADDED: | ||
| 163 | fwAction = Actions::Add; | ||
| 164 | break; | ||
| 165 | case FILE_ACTION_RENAMED_NEW_NAME: { | ||
| 166 | fwAction = Actions::Moved; | ||
| 167 | |||
| 168 | std::string fpath( watch->Directory + filename ); | ||
| 169 | |||
| 170 | // Update the directory path | ||
| 171 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | ||
| 172 | // Update the new directory path | ||
| 173 | std::string opath( watch->Directory + watch->OldFileName ); | ||
| 174 | FileSystem::dirAddSlashAtEnd( opath ); | ||
| 175 | FileSystem::dirAddSlashAtEnd( fpath ); | ||
| 176 | |||
| 177 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 178 | if ( ( *it )->Watch->Directory == opath ) { | ||
| 179 | ( *it )->Watch->Directory = fpath; | ||
| 180 | |||
| 181 | break; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); | ||
| 187 | std::string realFilename = filename; | ||
| 188 | std::size_t sepPos = filename.find_last_of( "/\\" ); | ||
| 189 | std::string oldFolderPath = | ||
| 190 | static_cast<WatcherWin32*>( watch )->DirName + | ||
| 191 | watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); | ||
| 192 | |||
| 193 | if ( sepPos != std::string::npos ) { | ||
| 194 | folderPath += filename.substr( 0, sepPos ); | ||
| 195 | realFilename = filename.substr( sepPos + 1 ); | ||
| 196 | } | ||
| 197 | |||
| 198 | if ( folderPath == oldFolderPath ) { | ||
| 199 | watch->Listener->handleFileAction( | ||
| 200 | watch->ID, folderPath, realFilename, fwAction, | ||
| 201 | FileSystem::fileNameFromPath( watch->OldFileName ) ); | ||
| 202 | } else { | ||
| 203 | watch->Listener->handleFileAction( watch->ID, | ||
| 204 | static_cast<WatcherWin32*>( watch )->DirName, | ||
| 205 | filename, fwAction, watch->OldFileName ); | ||
| 206 | } | ||
| 207 | return; | ||
| 208 | } | ||
| 209 | case FILE_ACTION_REMOVED: | ||
| 210 | fwAction = Actions::Delete; | ||
| 211 | break; | ||
| 212 | case FILE_ACTION_MODIFIED: | ||
| 213 | fwAction = Actions::Modified; | ||
| 214 | break; | ||
| 215 | default: | ||
| 216 | return; | ||
| 217 | }; | ||
| 218 | |||
| 219 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); | ||
| 220 | std::string realFilename = filename; | ||
| 221 | std::size_t sepPos = filename.find_last_of( "/\\" ); | ||
| 222 | |||
| 223 | if ( sepPos != std::string::npos ) { | ||
| 224 | folderPath += filename.substr( 0, sepPos ); | ||
| 225 | realFilename = filename.substr( sepPos + 1 ); | ||
| 226 | } | ||
| 227 | |||
| 228 | watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); | ||
| 229 | } | ||
| 230 | |||
| 231 | std::list<std::string> FileWatcherWin32::directories() { | ||
| 232 | std::list<std::string> dirs; | ||
| 233 | |||
| 234 | Lock lock( mWatchesLock ); | ||
| 235 | |||
| 236 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 237 | dirs.push_back( std::string( ( *it )->Watch->DirName ) ); | ||
| 238 | } | ||
| 239 | |||
| 240 | return dirs; | ||
| 241 | } | ||
| 242 | |||
| 243 | bool FileWatcherWin32::pathInWatches( const std::string& path ) { | ||
| 244 | Lock lock( mWatchesLock ); | ||
| 245 | |||
| 246 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 247 | if ( ( *it )->Watch->DirName == path ) { | ||
| 248 | return true; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | return false; | ||
| 253 | } | ||
| 254 | |||
| 255 | } // namespace efsw | ||
| 256 | |||
| 257 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherWin32.hpp b/src/3rdParty/efsw/FileWatcherWin32.hpp new file mode 100755 index 0000000..94439cf --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherWin32.hpp | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | #ifndef EFSW_FILEWATCHERWIN32_HPP | ||
| 2 | #define EFSW_FILEWATCHERWIN32_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 7 | |||
| 8 | #include <efsw/WatcherWin32.hpp> | ||
| 9 | #include <map> | ||
| 10 | #include <set> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | namespace efsw { | ||
| 14 | |||
| 15 | /// Implementation for Win32 based on ReadDirectoryChangesW. | ||
| 16 | /// @class FileWatcherWin32 | ||
| 17 | class FileWatcherWin32 : public FileWatcherImpl { | ||
| 18 | public: | ||
| 19 | /// type for a map from WatchID to WatcherWin32 pointer | ||
| 20 | typedef std::set<WatcherStructWin32*> Watches; | ||
| 21 | |||
| 22 | FileWatcherWin32( FileWatcher* parent ); | ||
| 23 | |||
| 24 | virtual ~FileWatcherWin32(); | ||
| 25 | |||
| 26 | /// Add a directory watch | ||
| 27 | /// On error returns WatchID with Error type. | ||
| 28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | ||
| 29 | |||
| 30 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | ||
| 31 | void removeWatch( const std::string& directory ); | ||
| 32 | |||
| 33 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 34 | void removeWatch( WatchID watchid ); | ||
| 35 | |||
| 36 | /// Updates the watcher. Must be called often. | ||
| 37 | void watch(); | ||
| 38 | |||
| 39 | /// Handles the action | ||
| 40 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | ||
| 41 | std::string oldFilename = "" ); | ||
| 42 | |||
| 43 | /// @return Returns a list of the directories that are being watched | ||
| 44 | std::list<std::string> directories(); | ||
| 45 | |||
| 46 | protected: | ||
| 47 | HANDLE mIOCP; | ||
| 48 | Watches mWatches; | ||
| 49 | |||
| 50 | /// The last watchid | ||
| 51 | WatchID mLastWatchID; | ||
| 52 | Thread* mThread; | ||
| 53 | Mutex mWatchesLock; | ||
| 54 | |||
| 55 | bool pathInWatches( const std::string& path ); | ||
| 56 | |||
| 57 | /// Remove all directory watches. | ||
| 58 | void removeAllWatches(); | ||
| 59 | |||
| 60 | void removeWatch( WatcherStructWin32* watch ); | ||
| 61 | |||
| 62 | private: | ||
| 63 | void run(); | ||
| 64 | }; | ||
| 65 | |||
| 66 | } // namespace efsw | ||
| 67 | |||
| 68 | #endif | ||
| 69 | |||
| 70 | #endif | ||
diff --git a/src/3rdParty/efsw/LICENSE b/src/3rdParty/efsw/LICENSE new file mode 100755 index 0000000..37f354a --- /dev/null +++ b/src/3rdParty/efsw/LICENSE | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | Copyright (c) 2020 MartÃn Lucas Golini | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 4 | of this software and associated documentation files (the "Software"), to deal | ||
| 5 | in the Software without restriction, including without limitation the rights | ||
| 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 7 | copies of the Software, and to permit persons to whom the Software is | ||
| 8 | furnished to do so, subject to the following conditions: | ||
| 9 | |||
| 10 | The above copyright notice and this permission notice shall be included in | ||
| 11 | all copies or substantial portions of the Software. | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 19 | THE SOFTWARE. | ||
| 20 | |||
| 21 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) | ||
| 22 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. | ||
diff --git a/src/3rdParty/efsw/Lock.hpp b/src/3rdParty/efsw/Lock.hpp new file mode 100755 index 0000000..e8c522a --- /dev/null +++ b/src/3rdParty/efsw/Lock.hpp | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #ifndef EFSW_LOCK_HPP | ||
| 2 | #define EFSW_LOCK_HPP | ||
| 3 | |||
| 4 | #include <efsw/Mutex.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | /** Simple mutex class */ | ||
| 9 | class Lock { | ||
| 10 | public: | ||
| 11 | explicit Lock( Mutex& mutex ) : mMutex( mutex ) { mMutex.lock(); } | ||
| 12 | |||
| 13 | ~Lock() { mMutex.unlock(); } | ||
| 14 | |||
| 15 | private: | ||
| 16 | Mutex& mMutex; | ||
| 17 | }; | ||
| 18 | |||
| 19 | } // namespace efsw | ||
| 20 | |||
| 21 | #endif | ||
diff --git a/src/3rdParty/efsw/Log.cpp b/src/3rdParty/efsw/Log.cpp new file mode 100755 index 0000000..ddf7a62 --- /dev/null +++ b/src/3rdParty/efsw/Log.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #include <efsw/efsw.hpp> | ||
| 2 | |||
| 3 | namespace efsw { namespace Errors { | ||
| 4 | |||
| 5 | static std::string LastError; | ||
| 6 | |||
| 7 | std::string Log::getLastErrorLog() { | ||
| 8 | return LastError; | ||
| 9 | } | ||
| 10 | |||
| 11 | Error Log::createLastError( Error err, std::string log ) { | ||
| 12 | switch ( err ) { | ||
| 13 | case FileNotFound: | ||
| 14 | LastError = "File not found ( " + log + " )"; | ||
| 15 | break; | ||
| 16 | case FileRepeated: | ||
| 17 | LastError = "File reapeated in watches ( " + log + " )"; | ||
| 18 | break; | ||
| 19 | case FileOutOfScope: | ||
| 20 | LastError = "Symlink file out of scope ( " + log + " )"; | ||
| 21 | break; | ||
| 22 | case FileRemote: | ||
| 23 | LastError = | ||
| 24 | "File is located in a remote file system, use a generic watcher. ( " + log + " )"; | ||
| 25 | break; | ||
| 26 | case Unspecified: | ||
| 27 | default: | ||
| 28 | LastError = log; | ||
| 29 | } | ||
| 30 | |||
| 31 | return err; | ||
| 32 | } | ||
| 33 | |||
| 34 | }} // namespace efsw::Errors | ||
diff --git a/src/3rdParty/efsw/Mutex.cpp b/src/3rdParty/efsw/Mutex.cpp new file mode 100755 index 0000000..c961db1 --- /dev/null +++ b/src/3rdParty/efsw/Mutex.cpp | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #include <efsw/Mutex.hpp> | ||
| 2 | #include <efsw/platform/platformimpl.hpp> | ||
| 3 | |||
| 4 | namespace efsw { | ||
| 5 | |||
| 6 | Mutex::Mutex() : mMutexImpl( new Platform::MutexImpl() ) {} | ||
| 7 | |||
| 8 | Mutex::~Mutex() { | ||
| 9 | efSAFE_DELETE( mMutexImpl ); | ||
| 10 | } | ||
| 11 | |||
| 12 | void Mutex::lock() { | ||
| 13 | mMutexImpl->lock(); | ||
| 14 | } | ||
| 15 | |||
| 16 | void Mutex::unlock() { | ||
| 17 | mMutexImpl->unlock(); | ||
| 18 | } | ||
| 19 | |||
| 20 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/Mutex.hpp b/src/3rdParty/efsw/Mutex.hpp new file mode 100755 index 0000000..d98ad17 --- /dev/null +++ b/src/3rdParty/efsw/Mutex.hpp | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #ifndef EFSW_MUTEX_HPP | ||
| 2 | #define EFSW_MUTEX_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | namespace Platform { | ||
| 9 | class MutexImpl; | ||
| 10 | } | ||
| 11 | |||
| 12 | /** Simple mutex class */ | ||
| 13 | class Mutex { | ||
| 14 | public: | ||
| 15 | Mutex(); | ||
| 16 | |||
| 17 | ~Mutex(); | ||
| 18 | |||
| 19 | /** Lock the mutex */ | ||
| 20 | void lock(); | ||
| 21 | |||
| 22 | /** Unlock the mutex */ | ||
| 23 | void unlock(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | Platform::MutexImpl* mMutexImpl; | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace efsw | ||
| 30 | |||
| 31 | #endif | ||
diff --git a/src/3rdParty/efsw/String.cpp b/src/3rdParty/efsw/String.cpp new file mode 100755 index 0000000..8c9a3cc --- /dev/null +++ b/src/3rdParty/efsw/String.cpp | |||
| @@ -0,0 +1,669 @@ | |||
| 1 | #include <efsw/String.hpp> | ||
| 2 | #include <efsw/Utf.hpp> | ||
| 3 | #include <iterator> | ||
| 4 | |||
| 5 | namespace efsw { | ||
| 6 | |||
| 7 | const std::size_t String::InvalidPos = StringType::npos; | ||
| 8 | |||
| 9 | std::vector<std::string> String::split( const std::string& str, const char& splitchar, | ||
| 10 | const bool& pushEmptyString ) { | ||
| 11 | std::vector<std::string> tmp; | ||
| 12 | std::string tmpstr; | ||
| 13 | |||
| 14 | for ( size_t i = 0; i < str.size(); i++ ) { | ||
| 15 | if ( str[i] == splitchar ) { | ||
| 16 | if ( pushEmptyString || tmpstr.size() ) { | ||
| 17 | tmp.push_back( tmpstr ); | ||
| 18 | tmpstr = ""; | ||
| 19 | } | ||
| 20 | } else { | ||
| 21 | tmpstr += str[i]; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | if ( tmpstr.size() ) { | ||
| 26 | tmp.push_back( tmpstr ); | ||
| 27 | } | ||
| 28 | |||
| 29 | return tmp; | ||
| 30 | } | ||
| 31 | |||
| 32 | std::vector<String> String::split( const String& str, const Uint32& splitchar, | ||
| 33 | const bool& pushEmptyString ) { | ||
| 34 | std::vector<String> tmp; | ||
| 35 | String tmpstr; | ||
| 36 | |||
| 37 | for ( size_t i = 0; i < str.size(); i++ ) { | ||
| 38 | if ( str[i] == splitchar ) { | ||
| 39 | if ( pushEmptyString || tmpstr.size() ) { | ||
| 40 | tmp.push_back( tmpstr ); | ||
| 41 | tmpstr = ""; | ||
| 42 | } | ||
| 43 | } else { | ||
| 44 | tmpstr += str[i]; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | if ( tmpstr.size() ) { | ||
| 49 | tmp.push_back( tmpstr ); | ||
| 50 | } | ||
| 51 | |||
| 52 | return tmp; | ||
| 53 | } | ||
| 54 | |||
| 55 | int String::strStartsWith( const std::string& start, const std::string& str ) { | ||
| 56 | int pos = -1; | ||
| 57 | size_t size = start.size(); | ||
| 58 | |||
| 59 | if ( str.size() >= size ) { | ||
| 60 | for ( std::size_t i = 0; i < size; i++ ) { | ||
| 61 | if ( start[i] == str[i] ) { | ||
| 62 | pos = (int)i; | ||
| 63 | } else { | ||
| 64 | pos = -1; | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | return pos; | ||
| 71 | } | ||
| 72 | |||
| 73 | int String::strStartsWith( const String& start, const String& str ) { | ||
| 74 | int pos = -1; | ||
| 75 | size_t size = start.size(); | ||
| 76 | |||
| 77 | if ( str.size() >= size ) { | ||
| 78 | for ( std::size_t i = 0; i < size; i++ ) { | ||
| 79 | if ( start[i] == str[i] ) { | ||
| 80 | pos = (int)i; | ||
| 81 | } else { | ||
| 82 | pos = -1; | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | return pos; | ||
| 89 | } | ||
| 90 | |||
| 91 | String::String() {} | ||
| 92 | |||
| 93 | String::String( char ansiChar, const std::locale& locale ) { | ||
| 94 | mString += Utf32::DecodeAnsi( ansiChar, locale ); | ||
| 95 | } | ||
| 96 | |||
| 97 | #ifndef EFSW_NO_WIDECHAR | ||
| 98 | String::String( wchar_t wideChar ) { | ||
| 99 | mString += Utf32::DecodeWide( wideChar ); | ||
| 100 | } | ||
| 101 | #endif | ||
| 102 | |||
| 103 | String::String( StringBaseType utf32Char ) { | ||
| 104 | mString += utf32Char; | ||
| 105 | } | ||
| 106 | |||
| 107 | String::String( const char* uf8String ) { | ||
| 108 | if ( uf8String ) { | ||
| 109 | std::size_t length = strlen( uf8String ); | ||
| 110 | |||
| 111 | if ( length > 0 ) { | ||
| 112 | mString.reserve( length + 1 ); | ||
| 113 | |||
| 114 | Utf8::ToUtf32( uf8String, uf8String + length, std::back_inserter( mString ) ); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | String::String( const std::string& utf8String ) { | ||
| 120 | mString.reserve( utf8String.length() + 1 ); | ||
| 121 | |||
| 122 | Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) ); | ||
| 123 | } | ||
| 124 | |||
| 125 | String::String( const char* ansiString, const std::locale& locale ) { | ||
| 126 | if ( ansiString ) { | ||
| 127 | std::size_t length = strlen( ansiString ); | ||
| 128 | if ( length > 0 ) { | ||
| 129 | mString.reserve( length + 1 ); | ||
| 130 | Utf32::FromAnsi( ansiString, ansiString + length, std::back_inserter( mString ), | ||
| 131 | locale ); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | String::String( const std::string& ansiString, const std::locale& locale ) { | ||
| 137 | mString.reserve( ansiString.length() + 1 ); | ||
| 138 | Utf32::FromAnsi( ansiString.begin(), ansiString.end(), std::back_inserter( mString ), locale ); | ||
| 139 | } | ||
| 140 | |||
| 141 | #ifndef EFSW_NO_WIDECHAR | ||
| 142 | String::String( const wchar_t* wideString ) { | ||
| 143 | if ( wideString ) { | ||
| 144 | std::size_t length = std::wcslen( wideString ); | ||
| 145 | if ( length > 0 ) { | ||
| 146 | mString.reserve( length + 1 ); | ||
| 147 | Utf32::FromWide( wideString, wideString + length, std::back_inserter( mString ) ); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | String::String( const std::wstring& wideString ) { | ||
| 153 | mString.reserve( wideString.length() + 1 ); | ||
| 154 | Utf32::FromWide( wideString.begin(), wideString.end(), std::back_inserter( mString ) ); | ||
| 155 | } | ||
| 156 | #endif | ||
| 157 | |||
| 158 | String::String( const StringBaseType* utf32String ) { | ||
| 159 | if ( utf32String ) | ||
| 160 | mString = utf32String; | ||
| 161 | } | ||
| 162 | |||
| 163 | String::String( const StringType& utf32String ) : mString( utf32String ) {} | ||
| 164 | |||
| 165 | String::String( const String& str ) : mString( str.mString ) {} | ||
| 166 | |||
| 167 | String String::fromUtf8( const std::string& utf8String ) { | ||
| 168 | String::StringType utf32; | ||
| 169 | |||
| 170 | utf32.reserve( utf8String.length() + 1 ); | ||
| 171 | |||
| 172 | Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( utf32 ) ); | ||
| 173 | |||
| 174 | return String( utf32 ); | ||
| 175 | } | ||
| 176 | |||
| 177 | String::operator std::string() const { | ||
| 178 | return toAnsiString(); | ||
| 179 | } | ||
| 180 | |||
| 181 | std::string String::toAnsiString( const std::locale& locale ) const { | ||
| 182 | // Prepare the output string | ||
| 183 | std::string output; | ||
| 184 | output.reserve( mString.length() + 1 ); | ||
| 185 | |||
| 186 | // Convert | ||
| 187 | Utf32::ToAnsi( mString.begin(), mString.end(), std::back_inserter( output ), 0, locale ); | ||
| 188 | |||
| 189 | return output; | ||
| 190 | } | ||
| 191 | |||
| 192 | #ifndef EFSW_NO_WIDECHAR | ||
| 193 | std::wstring String::toWideString() const { | ||
| 194 | // Prepare the output string | ||
| 195 | std::wstring output; | ||
| 196 | output.reserve( mString.length() + 1 ); | ||
| 197 | |||
| 198 | // Convert | ||
| 199 | Utf32::ToWide( mString.begin(), mString.end(), std::back_inserter( output ), 0 ); | ||
| 200 | |||
| 201 | return output; | ||
| 202 | } | ||
| 203 | #endif | ||
| 204 | |||
| 205 | std::string String::toUtf8() const { | ||
| 206 | // Prepare the output string | ||
| 207 | std::string output; | ||
| 208 | output.reserve( mString.length() + 1 ); | ||
| 209 | |||
| 210 | // Convert | ||
| 211 | Utf32::toUtf8( mString.begin(), mString.end(), std::back_inserter( output ) ); | ||
| 212 | |||
| 213 | return output; | ||
| 214 | } | ||
| 215 | |||
| 216 | String& String::operator=( const String& right ) { | ||
| 217 | mString = right.mString; | ||
| 218 | return *this; | ||
| 219 | } | ||
| 220 | |||
| 221 | String& String::operator=( const StringBaseType& right ) { | ||
| 222 | mString = right; | ||
| 223 | return *this; | ||
| 224 | } | ||
| 225 | |||
| 226 | String& String::operator+=( const String& right ) { | ||
| 227 | mString += right.mString; | ||
| 228 | return *this; | ||
| 229 | } | ||
| 230 | |||
| 231 | String& String::operator+=( const StringBaseType& right ) { | ||
| 232 | mString += right; | ||
| 233 | return *this; | ||
| 234 | } | ||
| 235 | |||
| 236 | String::StringBaseType String::operator[]( std::size_t index ) const { | ||
| 237 | return mString[index]; | ||
| 238 | } | ||
| 239 | |||
| 240 | String::StringBaseType& String::operator[]( std::size_t index ) { | ||
| 241 | return mString[index]; | ||
| 242 | } | ||
| 243 | |||
| 244 | String::StringBaseType String::at( std::size_t index ) const { | ||
| 245 | return mString.at( index ); | ||
| 246 | } | ||
| 247 | |||
| 248 | void String::push_back( StringBaseType c ) { | ||
| 249 | mString.push_back( c ); | ||
| 250 | } | ||
| 251 | |||
| 252 | void String::swap( String& str ) { | ||
| 253 | mString.swap( str.mString ); | ||
| 254 | } | ||
| 255 | |||
| 256 | void String::clear() { | ||
| 257 | mString.clear(); | ||
| 258 | } | ||
| 259 | |||
| 260 | std::size_t String::size() const { | ||
| 261 | return mString.size(); | ||
| 262 | } | ||
| 263 | |||
| 264 | std::size_t String::length() const { | ||
| 265 | return mString.length(); | ||
| 266 | } | ||
| 267 | |||
| 268 | bool String::empty() const { | ||
| 269 | return mString.empty(); | ||
| 270 | } | ||
| 271 | |||
| 272 | void String::erase( std::size_t position, std::size_t count ) { | ||
| 273 | mString.erase( position, count ); | ||
| 274 | } | ||
| 275 | |||
| 276 | String& String::insert( std::size_t position, const String& str ) { | ||
| 277 | mString.insert( position, str.mString ); | ||
| 278 | return *this; | ||
| 279 | } | ||
| 280 | |||
| 281 | String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ) { | ||
| 282 | mString.insert( pos1, str.mString, pos2, n ); | ||
| 283 | return *this; | ||
| 284 | } | ||
| 285 | |||
| 286 | String& String::insert( size_t pos1, const char* s, size_t n ) { | ||
| 287 | String tmp( s ); | ||
| 288 | |||
| 289 | mString.insert( pos1, tmp.data(), n ); | ||
| 290 | |||
| 291 | return *this; | ||
| 292 | } | ||
| 293 | |||
| 294 | String& String::insert( size_t pos1, size_t n, char c ) { | ||
| 295 | mString.insert( pos1, n, c ); | ||
| 296 | return *this; | ||
| 297 | } | ||
| 298 | |||
| 299 | String& String::insert( size_t pos1, const char* s ) { | ||
| 300 | String tmp( s ); | ||
| 301 | |||
| 302 | mString.insert( pos1, tmp.data() ); | ||
| 303 | |||
| 304 | return *this; | ||
| 305 | } | ||
| 306 | |||
| 307 | String::Iterator String::insert( Iterator p, char c ) { | ||
| 308 | return mString.insert( p, c ); | ||
| 309 | } | ||
| 310 | |||
| 311 | void String::insert( Iterator p, size_t n, char c ) { | ||
| 312 | mString.insert( p, n, c ); | ||
| 313 | } | ||
| 314 | |||
| 315 | const String::StringBaseType* String::c_str() const { | ||
| 316 | return mString.c_str(); | ||
| 317 | } | ||
| 318 | |||
| 319 | const String::StringBaseType* String::data() const { | ||
| 320 | return mString.data(); | ||
| 321 | } | ||
| 322 | |||
| 323 | String::Iterator String::begin() { | ||
| 324 | return mString.begin(); | ||
| 325 | } | ||
| 326 | |||
| 327 | String::ConstIterator String::begin() const { | ||
| 328 | return mString.begin(); | ||
| 329 | } | ||
| 330 | |||
| 331 | String::Iterator String::end() { | ||
| 332 | return mString.end(); | ||
| 333 | } | ||
| 334 | |||
| 335 | String::ConstIterator String::end() const { | ||
| 336 | return mString.end(); | ||
| 337 | } | ||
| 338 | |||
| 339 | String::ReverseIterator String::rbegin() { | ||
| 340 | return mString.rbegin(); | ||
| 341 | } | ||
| 342 | |||
| 343 | String::ConstReverseIterator String::rbegin() const { | ||
| 344 | return mString.rbegin(); | ||
| 345 | } | ||
| 346 | |||
| 347 | String::ReverseIterator String::rend() { | ||
| 348 | return mString.rend(); | ||
| 349 | } | ||
| 350 | |||
| 351 | String::ConstReverseIterator String::rend() const { | ||
| 352 | return mString.rend(); | ||
| 353 | } | ||
| 354 | |||
| 355 | void String::resize( std::size_t n, StringBaseType c ) { | ||
| 356 | mString.resize( n, c ); | ||
| 357 | } | ||
| 358 | |||
| 359 | void String::resize( std::size_t n ) { | ||
| 360 | mString.resize( n ); | ||
| 361 | } | ||
| 362 | |||
| 363 | std::size_t String::max_size() const { | ||
| 364 | return mString.max_size(); | ||
| 365 | } | ||
| 366 | |||
| 367 | void String::reserve( size_t res_arg ) { | ||
| 368 | mString.reserve( res_arg ); | ||
| 369 | } | ||
| 370 | |||
| 371 | std::size_t String::capacity() const { | ||
| 372 | return mString.capacity(); | ||
| 373 | } | ||
| 374 | |||
| 375 | String& String::assign( const String& str ) { | ||
| 376 | mString.assign( str.mString ); | ||
| 377 | return *this; | ||
| 378 | } | ||
| 379 | |||
| 380 | String& String::assign( const String& str, size_t pos, size_t n ) { | ||
| 381 | mString.assign( str.mString, pos, n ); | ||
| 382 | return *this; | ||
| 383 | } | ||
| 384 | |||
| 385 | String& String::assign( const char* s, size_t n ) { | ||
| 386 | String tmp( s ); | ||
| 387 | |||
| 388 | mString.assign( tmp.mString ); | ||
| 389 | |||
| 390 | return *this; | ||
| 391 | } | ||
| 392 | |||
| 393 | String& String::assign( const char* s ) { | ||
| 394 | String tmp( s ); | ||
| 395 | |||
| 396 | mString.assign( tmp.mString ); | ||
| 397 | |||
| 398 | return *this; | ||
| 399 | } | ||
| 400 | |||
| 401 | String& String::assign( size_t n, char c ) { | ||
| 402 | mString.assign( n, c ); | ||
| 403 | |||
| 404 | return *this; | ||
| 405 | } | ||
| 406 | |||
| 407 | String& String::append( const String& str ) { | ||
| 408 | mString.append( str.mString ); | ||
| 409 | |||
| 410 | return *this; | ||
| 411 | } | ||
| 412 | |||
| 413 | String& String::append( const String& str, size_t pos, size_t n ) { | ||
| 414 | mString.append( str.mString, pos, n ); | ||
| 415 | |||
| 416 | return *this; | ||
| 417 | } | ||
| 418 | |||
| 419 | String& String::append( const char* s, size_t n ) { | ||
| 420 | String tmp( s ); | ||
| 421 | |||
| 422 | mString.append( tmp.mString ); | ||
| 423 | |||
| 424 | return *this; | ||
| 425 | } | ||
| 426 | |||
| 427 | String& String::append( const char* s ) { | ||
| 428 | String tmp( s ); | ||
| 429 | |||
| 430 | mString.append( tmp.mString ); | ||
| 431 | |||
| 432 | return *this; | ||
| 433 | } | ||
| 434 | |||
| 435 | String& String::append( size_t n, char c ) { | ||
| 436 | mString.append( n, c ); | ||
| 437 | |||
| 438 | return *this; | ||
| 439 | } | ||
| 440 | |||
| 441 | String& String::append( std::size_t n, StringBaseType c ) { | ||
| 442 | mString.append( n, c ); | ||
| 443 | |||
| 444 | return *this; | ||
| 445 | } | ||
| 446 | |||
| 447 | String& String::replace( size_t pos1, size_t n1, const String& str ) { | ||
| 448 | mString.replace( pos1, n1, str.mString ); | ||
| 449 | |||
| 450 | return *this; | ||
| 451 | } | ||
| 452 | |||
| 453 | String& String::replace( Iterator i1, Iterator i2, const String& str ) { | ||
| 454 | mString.replace( i1, i2, str.mString ); | ||
| 455 | |||
| 456 | return *this; | ||
| 457 | } | ||
| 458 | |||
| 459 | String& String::replace( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 ) { | ||
| 460 | mString.replace( pos1, n1, str.mString, pos2, n2 ); | ||
| 461 | |||
| 462 | return *this; | ||
| 463 | } | ||
| 464 | |||
| 465 | String& String::replace( size_t pos1, size_t n1, const char* s, size_t n2 ) { | ||
| 466 | String tmp( s ); | ||
| 467 | |||
| 468 | mString.replace( pos1, n1, tmp.data(), n2 ); | ||
| 469 | |||
| 470 | return *this; | ||
| 471 | } | ||
| 472 | |||
| 473 | String& String::replace( Iterator i1, Iterator i2, const char* s, size_t n2 ) { | ||
| 474 | String tmp( s ); | ||
| 475 | |||
| 476 | mString.replace( i1, i2, tmp.data(), n2 ); | ||
| 477 | |||
| 478 | return *this; | ||
| 479 | } | ||
| 480 | |||
| 481 | String& String::replace( size_t pos1, size_t n1, const char* s ) { | ||
| 482 | String tmp( s ); | ||
| 483 | |||
| 484 | mString.replace( pos1, n1, tmp.mString ); | ||
| 485 | |||
| 486 | return *this; | ||
| 487 | } | ||
| 488 | |||
| 489 | String& String::replace( Iterator i1, Iterator i2, const char* s ) { | ||
| 490 | String tmp( s ); | ||
| 491 | |||
| 492 | mString.replace( i1, i2, tmp.mString ); | ||
| 493 | |||
| 494 | return *this; | ||
| 495 | } | ||
| 496 | |||
| 497 | String& String::replace( size_t pos1, size_t n1, size_t n2, char c ) { | ||
| 498 | mString.replace( pos1, n1, n2, (StringBaseType)c ); | ||
| 499 | |||
| 500 | return *this; | ||
| 501 | } | ||
| 502 | |||
| 503 | String& String::replace( Iterator i1, Iterator i2, size_t n2, char c ) { | ||
| 504 | mString.replace( i1, i2, n2, (StringBaseType)c ); | ||
| 505 | |||
| 506 | return *this; | ||
| 507 | } | ||
| 508 | |||
| 509 | std::size_t String::find( const String& str, std::size_t start ) const { | ||
| 510 | return mString.find( str.mString, start ); | ||
| 511 | } | ||
| 512 | |||
| 513 | std::size_t String::find( const char* s, std::size_t pos, std::size_t n ) const { | ||
| 514 | return find( String( s ), pos ); | ||
| 515 | } | ||
| 516 | |||
| 517 | std::size_t String::find( const char* s, std::size_t pos ) const { | ||
| 518 | return find( String( s ), pos ); | ||
| 519 | } | ||
| 520 | |||
| 521 | size_t String::find( char c, std::size_t pos ) const { | ||
| 522 | return mString.find( (StringBaseType)c, pos ); | ||
| 523 | } | ||
| 524 | |||
| 525 | std::size_t String::rfind( const String& str, std::size_t pos ) const { | ||
| 526 | return mString.rfind( str.mString, pos ); | ||
| 527 | } | ||
| 528 | |||
| 529 | std::size_t String::rfind( const char* s, std::size_t pos, std::size_t n ) const { | ||
| 530 | return rfind( String( s ), pos ); | ||
| 531 | } | ||
| 532 | |||
| 533 | std::size_t String::rfind( const char* s, std::size_t pos ) const { | ||
| 534 | return rfind( String( s ), pos ); | ||
| 535 | } | ||
| 536 | |||
| 537 | std::size_t String::rfind( char c, std::size_t pos ) const { | ||
| 538 | return mString.rfind( c, pos ); | ||
| 539 | } | ||
| 540 | |||
| 541 | std::size_t String::copy( StringBaseType* s, std::size_t n, std::size_t pos ) const { | ||
| 542 | return mString.copy( s, n, pos ); | ||
| 543 | } | ||
| 544 | |||
| 545 | String String::substr( std::size_t pos, std::size_t n ) const { | ||
| 546 | return String( mString.substr( pos, n ) ); | ||
| 547 | } | ||
| 548 | |||
| 549 | int String::compare( const String& str ) const { | ||
| 550 | return mString.compare( str.mString ); | ||
| 551 | } | ||
| 552 | |||
| 553 | int String::compare( const char* s ) const { | ||
| 554 | return compare( String( s ) ); | ||
| 555 | } | ||
| 556 | |||
| 557 | int String::compare( std::size_t pos1, std::size_t n1, const String& str ) const { | ||
| 558 | return mString.compare( pos1, n1, str.mString ); | ||
| 559 | } | ||
| 560 | |||
| 561 | int String::compare( std::size_t pos1, std::size_t n1, const char* s ) const { | ||
| 562 | return compare( pos1, n1, String( s ) ); | ||
| 563 | } | ||
| 564 | |||
| 565 | int String::compare( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, | ||
| 566 | std::size_t n2 ) const { | ||
| 567 | return mString.compare( pos1, n1, str.mString, pos2, n2 ); | ||
| 568 | } | ||
| 569 | |||
| 570 | int String::compare( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ) const { | ||
| 571 | return compare( pos1, n1, String( s ), 0, n2 ); | ||
| 572 | } | ||
| 573 | |||
| 574 | std::size_t String::find_first_of( const String& str, std::size_t pos ) const { | ||
| 575 | return mString.find_first_of( str.mString, pos ); | ||
| 576 | } | ||
| 577 | |||
| 578 | std::size_t String::find_first_of( const char* s, std::size_t pos, std::size_t n ) const { | ||
| 579 | return find_first_of( String( s ), pos ); | ||
| 580 | } | ||
| 581 | |||
| 582 | std::size_t String::find_first_of( const char* s, std::size_t pos ) const { | ||
| 583 | return find_first_of( String( s ), pos ); | ||
| 584 | } | ||
| 585 | |||
| 586 | std::size_t String::find_first_of( StringBaseType c, std::size_t pos ) const { | ||
| 587 | return mString.find_first_of( c, pos ); | ||
| 588 | } | ||
| 589 | |||
| 590 | std::size_t String::find_last_of( const String& str, std::size_t pos ) const { | ||
| 591 | return mString.find_last_of( str.mString, pos ); | ||
| 592 | } | ||
| 593 | |||
| 594 | std::size_t String::find_last_of( const char* s, std::size_t pos, std::size_t n ) const { | ||
| 595 | return find_last_of( String( s ), pos ); | ||
| 596 | } | ||
| 597 | |||
| 598 | std::size_t String::find_last_of( const char* s, std::size_t pos ) const { | ||
| 599 | return find_last_of( String( s ), pos ); | ||
| 600 | } | ||
| 601 | |||
| 602 | std::size_t String::find_last_of( StringBaseType c, std::size_t pos ) const { | ||
| 603 | return mString.find_last_of( c, pos ); | ||
| 604 | } | ||
| 605 | |||
| 606 | std::size_t String::find_first_not_of( const String& str, std::size_t pos ) const { | ||
| 607 | return mString.find_first_not_of( str.mString, pos ); | ||
| 608 | } | ||
| 609 | |||
| 610 | std::size_t String::find_first_not_of( const char* s, std::size_t pos, std::size_t n ) const { | ||
| 611 | return find_first_not_of( String( s ), pos ); | ||
| 612 | } | ||
| 613 | |||
| 614 | std::size_t String::find_first_not_of( const char* s, std::size_t pos ) const { | ||
| 615 | return find_first_not_of( String( s ), pos ); | ||
| 616 | } | ||
| 617 | |||
| 618 | std::size_t String::find_first_not_of( StringBaseType c, std::size_t pos ) const { | ||
| 619 | return mString.find_first_not_of( c, pos ); | ||
| 620 | } | ||
| 621 | |||
| 622 | std::size_t String::find_last_not_of( const String& str, std::size_t pos ) const { | ||
| 623 | return mString.find_last_not_of( str.mString, pos ); | ||
| 624 | } | ||
| 625 | |||
| 626 | std::size_t String::find_last_not_of( const char* s, std::size_t pos, std::size_t n ) const { | ||
| 627 | return find_last_not_of( String( s ), pos ); | ||
| 628 | } | ||
| 629 | |||
| 630 | std::size_t String::find_last_not_of( const char* s, std::size_t pos ) const { | ||
| 631 | return find_last_not_of( String( s ), pos ); | ||
| 632 | } | ||
| 633 | |||
| 634 | std::size_t String::find_last_not_of( StringBaseType c, std::size_t pos ) const { | ||
| 635 | return mString.find_last_not_of( c, pos ); | ||
| 636 | } | ||
| 637 | |||
| 638 | bool operator==( const String& left, const String& right ) { | ||
| 639 | return left.mString == right.mString; | ||
| 640 | } | ||
| 641 | |||
| 642 | bool operator!=( const String& left, const String& right ) { | ||
| 643 | return !( left == right ); | ||
| 644 | } | ||
| 645 | |||
| 646 | bool operator<( const String& left, const String& right ) { | ||
| 647 | return left.mString < right.mString; | ||
| 648 | } | ||
| 649 | |||
| 650 | bool operator>( const String& left, const String& right ) { | ||
| 651 | return right < left; | ||
| 652 | } | ||
| 653 | |||
| 654 | bool operator<=( const String& left, const String& right ) { | ||
| 655 | return !( right < left ); | ||
| 656 | } | ||
| 657 | |||
| 658 | bool operator>=( const String& left, const String& right ) { | ||
| 659 | return !( left < right ); | ||
| 660 | } | ||
| 661 | |||
| 662 | String operator+( const String& left, const String& right ) { | ||
| 663 | String string = left; | ||
| 664 | string += right; | ||
| 665 | |||
| 666 | return string; | ||
| 667 | } | ||
| 668 | |||
| 669 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/String.hpp b/src/3rdParty/efsw/String.hpp new file mode 100755 index 0000000..65bce33 --- /dev/null +++ b/src/3rdParty/efsw/String.hpp | |||
| @@ -0,0 +1,631 @@ | |||
| 1 | /** NOTE: | ||
| 2 | * This code is based on the Utf implementation from SFML2. License zlib/png ( | ||
| 3 | *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not | ||
| 4 | *the original implementation from SFML2. Functions and methods are the same that in std::string to | ||
| 5 | *facilitate portability. | ||
| 6 | **/ | ||
| 7 | |||
| 8 | #ifndef EFSW_STRING_HPP | ||
| 9 | #define EFSW_STRING_HPP | ||
| 10 | |||
| 11 | #include <cstdlib> | ||
| 12 | #include <cstring> | ||
| 13 | #include <efsw/base.hpp> | ||
| 14 | #include <fstream> | ||
| 15 | #include <iostream> | ||
| 16 | #include <locale> | ||
| 17 | #include <sstream> | ||
| 18 | #include <string> | ||
| 19 | #include <vector> | ||
| 20 | |||
| 21 | namespace efsw { | ||
| 22 | |||
| 23 | /** @brief Utility string class that automatically handles conversions between types and encodings | ||
| 24 | * **/ | ||
| 25 | class String { | ||
| 26 | public: | ||
| 27 | typedef Uint32 StringBaseType; | ||
| 28 | typedef std::basic_string<StringBaseType> StringType; | ||
| 29 | typedef StringType::iterator Iterator; //! Iterator type | ||
| 30 | typedef StringType::const_iterator ConstIterator; //! Constant iterator type | ||
| 31 | typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type | ||
| 32 | typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type | ||
| 33 | |||
| 34 | static const std::size_t InvalidPos; ///< Represents an invalid position in the string | ||
| 35 | |||
| 36 | template <class T> static std::string toStr( const T& i ) { | ||
| 37 | std::ostringstream ss; | ||
| 38 | ss << i; | ||
| 39 | return ss.str(); | ||
| 40 | } | ||
| 41 | |||
| 42 | /** Converts from a string to type */ | ||
| 43 | template <class T> | ||
| 44 | static bool fromString( T& t, const std::string& s, | ||
| 45 | std::ios_base& ( *f )( std::ios_base& ) = std::dec ) { | ||
| 46 | std::istringstream iss( s ); | ||
| 47 | return !( iss >> f >> t ).fail(); | ||
| 48 | } | ||
| 49 | |||
| 50 | /** Converts from a String to type */ | ||
| 51 | template <class T> | ||
| 52 | static bool fromString( T& t, const String& s, | ||
| 53 | std::ios_base& ( *f )( std::ios_base& ) = std::dec ) { | ||
| 54 | std::istringstream iss( s.toUtf8() ); | ||
| 55 | return !( iss >> f >> t ).fail(); | ||
| 56 | } | ||
| 57 | |||
| 58 | /** Split a string and hold it on a vector */ | ||
| 59 | static std::vector<std::string> split( const std::string& str, const char& splitchar, | ||
| 60 | const bool& pushEmptyString = false ); | ||
| 61 | |||
| 62 | /** Split a string and hold it on a vector */ | ||
| 63 | static std::vector<String> split( const String& str, const Uint32& splitchar, | ||
| 64 | const bool& pushEmptyString = false ); | ||
| 65 | |||
| 66 | /** Determine if a string starts with the string passed | ||
| 67 | ** @param start The substring expected to start | ||
| 68 | ** @param str The string to compare | ||
| 69 | ** @return -1 if the substring is no in str, otherwise the size of the substring | ||
| 70 | */ | ||
| 71 | static int strStartsWith( const std::string& start, const std::string& str ); | ||
| 72 | |||
| 73 | static int strStartsWith( const String& start, const String& str ); | ||
| 74 | |||
| 75 | /** @brief Construct from an UTF-8 string to UTF-32 according | ||
| 76 | ** @param uf8String UTF-8 string to convert | ||
| 77 | **/ | ||
| 78 | static String fromUtf8( const std::string& utf8String ); | ||
| 79 | |||
| 80 | /** @brief Default constructor | ||
| 81 | ** This constructor creates an empty string. | ||
| 82 | **/ | ||
| 83 | String(); | ||
| 84 | |||
| 85 | /** @brief Construct from a single ANSI character and a locale | ||
| 86 | ** The source character is converted to UTF-32 according | ||
| 87 | ** to the given locale. If you want to use the current global | ||
| 88 | ** locale, rather use the other constructor. | ||
| 89 | ** @param ansiChar ANSI character to convert | ||
| 90 | ** @param locale Locale to use for conversion | ||
| 91 | **/ | ||
| 92 | String( char ansiChar, const std::locale& locale = std::locale() ); | ||
| 93 | |||
| 94 | #ifndef EFSW_NO_WIDECHAR | ||
| 95 | /** @brief Construct from single wide character | ||
| 96 | ** @param wideChar Wide character to convert | ||
| 97 | **/ | ||
| 98 | String( wchar_t wideChar ); | ||
| 99 | #endif | ||
| 100 | |||
| 101 | /** @brief Construct from single UTF-32 character | ||
| 102 | ** @param utf32Char UTF-32 character to convert | ||
| 103 | **/ | ||
| 104 | String( StringBaseType utf32Char ); | ||
| 105 | |||
| 106 | /** @brief Construct from an from a null-terminated C-style UTF-8 string to UTF-32 | ||
| 107 | ** @param uf8String UTF-8 string to convert | ||
| 108 | **/ | ||
| 109 | String( const char* uf8String ); | ||
| 110 | |||
| 111 | /** @brief Construct from an UTF-8 string to UTF-32 according | ||
| 112 | ** @param uf8String UTF-8 string to convert | ||
| 113 | **/ | ||
| 114 | String( const std::string& utf8String ); | ||
| 115 | |||
| 116 | /** @brief Construct from a null-terminated C-style ANSI string and a locale | ||
| 117 | ** The source string is converted to UTF-32 according | ||
| 118 | ** to the given locale. If you want to use the current global | ||
| 119 | ** locale, rather use the other constructor. | ||
| 120 | ** @param ansiString ANSI string to convert | ||
| 121 | ** @param locale Locale to use for conversion | ||
| 122 | **/ | ||
| 123 | String( const char* ansiString, const std::locale& locale ); | ||
| 124 | |||
| 125 | /** @brief Construct from an ANSI string and a locale | ||
| 126 | ** The source string is converted to UTF-32 according | ||
| 127 | ** to the given locale. If you want to use the current global | ||
| 128 | ** locale, rather use the other constructor. | ||
| 129 | ** @param ansiString ANSI string to convert | ||
| 130 | ** @param locale Locale to use for conversion | ||
| 131 | **/ | ||
| 132 | String( const std::string& ansiString, const std::locale& locale ); | ||
| 133 | |||
| 134 | #ifndef EFSW_NO_WIDECHAR | ||
| 135 | /** @brief Construct from null-terminated C-style wide string | ||
| 136 | ** @param wideString Wide string to convert | ||
| 137 | **/ | ||
| 138 | String( const wchar_t* wideString ); | ||
| 139 | |||
| 140 | /** @brief Construct from a wide string | ||
| 141 | ** @param wideString Wide string to convert | ||
| 142 | **/ | ||
| 143 | String( const std::wstring& wideString ); | ||
| 144 | #endif | ||
| 145 | |||
| 146 | /** @brief Construct from a null-terminated C-style UTF-32 string | ||
| 147 | ** @param utf32String UTF-32 string to assign | ||
| 148 | **/ | ||
| 149 | String( const StringBaseType* utf32String ); | ||
| 150 | |||
| 151 | /** @brief Construct from an UTF-32 string | ||
| 152 | ** @param utf32String UTF-32 string to assign | ||
| 153 | **/ | ||
| 154 | String( const StringType& utf32String ); | ||
| 155 | |||
| 156 | /** @brief Copy constructor | ||
| 157 | ** @param str Instance to copy | ||
| 158 | **/ | ||
| 159 | String( const String& str ); | ||
| 160 | |||
| 161 | /** @brief Implicit cast operator to std::string (ANSI string) | ||
| 162 | ** The current global locale is used for conversion. If you | ||
| 163 | ** want to explicitely specify a locale, see toAnsiString. | ||
| 164 | ** Characters that do not fit in the target encoding are | ||
| 165 | ** discarded from the returned string. | ||
| 166 | ** This operator is defined for convenience, and is equivalent | ||
| 167 | ** to calling toAnsiString(). | ||
| 168 | ** @return Converted ANSI string | ||
| 169 | ** @see toAnsiString, operator String | ||
| 170 | **/ | ||
| 171 | operator std::string() const; | ||
| 172 | |||
| 173 | /** @brief Convert the unicode string to an ANSI string | ||
| 174 | ** The UTF-32 string is converted to an ANSI string in | ||
| 175 | ** the encoding defined by \a locale. If you want to use | ||
| 176 | ** the current global locale, see the other overload | ||
| 177 | ** of toAnsiString. | ||
| 178 | ** Characters that do not fit in the target encoding are | ||
| 179 | ** discarded from the returned string. | ||
| 180 | ** @param locale Locale to use for conversion | ||
| 181 | ** @return Converted ANSI string | ||
| 182 | ** @see toWideString, operator std::string | ||
| 183 | **/ | ||
| 184 | std::string toAnsiString( const std::locale& locale = std::locale() ) const; | ||
| 185 | |||
| 186 | #ifndef EFSW_NO_WIDECHAR | ||
| 187 | /** @brief Convert the unicode string to a wide string | ||
| 188 | ** Characters that do not fit in the target encoding are | ||
| 189 | ** discarded from the returned string. | ||
| 190 | ** @return Converted wide string | ||
| 191 | ** @see toAnsiString, operator String | ||
| 192 | **/ | ||
| 193 | std::wstring toWideString() const; | ||
| 194 | #endif | ||
| 195 | |||
| 196 | std::string toUtf8() const; | ||
| 197 | |||
| 198 | /** @brief Overload of assignment operator | ||
| 199 | ** @param right Instance to assign | ||
| 200 | ** @return Reference to self | ||
| 201 | **/ | ||
| 202 | String& operator=( const String& right ); | ||
| 203 | |||
| 204 | String& operator=( const StringBaseType& right ); | ||
| 205 | |||
| 206 | /** @brief Overload of += operator to append an UTF-32 string | ||
| 207 | ** @param right String to append | ||
| 208 | ** @return Reference to self | ||
| 209 | **/ | ||
| 210 | String& operator+=( const String& right ); | ||
| 211 | |||
| 212 | String& operator+=( const StringBaseType& right ); | ||
| 213 | |||
| 214 | /** @brief Overload of [] operator to access a character by its position | ||
| 215 | ** This function provides read-only access to characters. | ||
| 216 | ** Note: this function doesn't throw if \a index is out of range. | ||
| 217 | ** @param index Index of the character to get | ||
| 218 | ** @return Character at position \a index | ||
| 219 | **/ | ||
| 220 | StringBaseType operator[]( std::size_t index ) const; | ||
| 221 | |||
| 222 | /** @brief Overload of [] operator to access a character by its position | ||
| 223 | ** This function provides read and write access to characters. | ||
| 224 | ** Note: this function doesn't throw if \a index is out of range. | ||
| 225 | ** @param index Index of the character to get | ||
| 226 | ** @return Reference to the character at position \a index | ||
| 227 | **/ | ||
| 228 | |||
| 229 | StringBaseType& operator[]( std::size_t index ); | ||
| 230 | |||
| 231 | /** @brief Get character in string | ||
| 232 | ** Performs a range check, throwing an exception of type out_of_range in case that pos is not an | ||
| 233 | *actual position in the string. | ||
| 234 | ** @return The character at position pos in the string. | ||
| 235 | */ | ||
| 236 | StringBaseType at( std::size_t index ) const; | ||
| 237 | |||
| 238 | /** @brief clear the string | ||
| 239 | ** This function removes all the characters from the string. | ||
| 240 | ** @see empty, erase | ||
| 241 | **/ | ||
| 242 | void clear(); | ||
| 243 | |||
| 244 | /** @brief Get the size of the string | ||
| 245 | ** @return Number of characters in the string | ||
| 246 | ** @see empty | ||
| 247 | **/ | ||
| 248 | std::size_t size() const; | ||
| 249 | |||
| 250 | /** @see size() */ | ||
| 251 | std::size_t length() const; | ||
| 252 | |||
| 253 | /** @brief Check whether the string is empty or not | ||
| 254 | ** @return True if the string is empty (i.e. contains no character) | ||
| 255 | ** @see clear, size | ||
| 256 | **/ | ||
| 257 | bool empty() const; | ||
| 258 | |||
| 259 | /** @brief Erase one or more characters from the string | ||
| 260 | ** This function removes a sequence of \a count characters | ||
| 261 | ** starting from \a position. | ||
| 262 | ** @param position Position of the first character to erase | ||
| 263 | ** @param count Number of characters to erase | ||
| 264 | **/ | ||
| 265 | void erase( std::size_t position, std::size_t count = 1 ); | ||
| 266 | |||
| 267 | /** @brief Insert one or more characters into the string | ||
| 268 | ** This function inserts the characters of \a str | ||
| 269 | ** into the string, starting from \a position. | ||
| 270 | ** @param position Position of insertion | ||
| 271 | ** @param str Characters to insert | ||
| 272 | **/ | ||
| 273 | String& insert( std::size_t position, const String& str ); | ||
| 274 | |||
| 275 | String& insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ); | ||
| 276 | |||
| 277 | String& insert( std::size_t pos1, const char* s, std::size_t n ); | ||
| 278 | |||
| 279 | String& insert( std::size_t pos1, const char* s ); | ||
| 280 | |||
| 281 | String& insert( std::size_t pos1, size_t n, char c ); | ||
| 282 | |||
| 283 | Iterator insert( Iterator p, char c ); | ||
| 284 | |||
| 285 | void insert( Iterator p, std::size_t n, char c ); | ||
| 286 | |||
| 287 | template <class InputIterator> | ||
| 288 | void insert( Iterator p, InputIterator first, InputIterator last ) { | ||
| 289 | mString.insert( p, first, last ); | ||
| 290 | } | ||
| 291 | |||
| 292 | /** @brief Find a sequence of one or more characters in the string | ||
| 293 | ** This function searches for the characters of \a str | ||
| 294 | ** into the string, starting from \a start. | ||
| 295 | ** @param str Characters to find | ||
| 296 | ** @param start Where to begin searching | ||
| 297 | ** @return Position of \a str in the string, or String::InvalidPos if not found | ||
| 298 | **/ | ||
| 299 | std::size_t find( const String& str, std::size_t start = 0 ) const; | ||
| 300 | |||
| 301 | std::size_t find( const char* s, std::size_t pos, std::size_t n ) const; | ||
| 302 | |||
| 303 | std::size_t find( const char* s, std::size_t pos = 0 ) const; | ||
| 304 | |||
| 305 | std::size_t find( char c, std::size_t pos = 0 ) const; | ||
| 306 | |||
| 307 | /** @brief Get a pointer to the C-style array of characters | ||
| 308 | ** This functions provides a read-only access to a | ||
| 309 | ** null-terminated C-style representation of the string. | ||
| 310 | ** The returned pointer is temporary and is meant only for | ||
| 311 | ** immediate use, thus it is not recommended to store it. | ||
| 312 | ** @return Read-only pointer to the array of characters | ||
| 313 | **/ | ||
| 314 | const StringBaseType* c_str() const; | ||
| 315 | |||
| 316 | /** @brief Get string data | ||
| 317 | ** Notice that no terminating null character is appended (see member c_str for such a | ||
| 318 | *functionality). | ||
| 319 | ** The returned array points to an internal location which should not be modified directly in | ||
| 320 | *the program. | ||
| 321 | ** Its contents are guaranteed to remain unchanged only until the next call to a non-constant | ||
| 322 | *member function of the string object. | ||
| 323 | ** @return Pointer to an internal array containing the same content as the string. | ||
| 324 | **/ | ||
| 325 | const StringBaseType* data() const; | ||
| 326 | |||
| 327 | /** @brief Return an iterator to the beginning of the string | ||
| 328 | ** @return Read-write iterator to the beginning of the string characters | ||
| 329 | ** @see end | ||
| 330 | **/ | ||
| 331 | Iterator begin(); | ||
| 332 | |||
| 333 | /** @brief Return an iterator to the beginning of the string | ||
| 334 | ** @return Read-only iterator to the beginning of the string characters | ||
| 335 | ** @see end | ||
| 336 | **/ | ||
| 337 | ConstIterator begin() const; | ||
| 338 | |||
| 339 | /** @brief Return an iterator to the beginning of the string | ||
| 340 | ** The end iterator refers to 1 position past the last character; | ||
| 341 | ** thus it represents an invalid character and should never be | ||
| 342 | ** accessed. | ||
| 343 | ** @return Read-write iterator to the end of the string characters | ||
| 344 | ** @see begin | ||
| 345 | **/ | ||
| 346 | Iterator end(); | ||
| 347 | |||
| 348 | /** @brief Return an iterator to the beginning of the string | ||
| 349 | ** The end iterator refers to 1 position past the last character; | ||
| 350 | ** thus it represents an invalid character and should never be | ||
| 351 | ** accessed. | ||
| 352 | ** @return Read-only iterator to the end of the string characters | ||
| 353 | ** @see begin | ||
| 354 | **/ | ||
| 355 | ConstIterator end() const; | ||
| 356 | |||
| 357 | /** @brief Return an reverse iterator to the beginning of the string | ||
| 358 | ** @return Read-write reverse iterator to the beginning of the string characters | ||
| 359 | ** @see end | ||
| 360 | **/ | ||
| 361 | ReverseIterator rbegin(); | ||
| 362 | |||
| 363 | /** @brief Return an reverse iterator to the beginning of the string | ||
| 364 | ** @return Read-only reverse iterator to the beginning of the string characters | ||
| 365 | ** @see end | ||
| 366 | **/ | ||
| 367 | ConstReverseIterator rbegin() const; | ||
| 368 | |||
| 369 | /** @brief Return an reverse iterator to the beginning of the string | ||
| 370 | ** The end reverse iterator refers to 1 position past the last character; | ||
| 371 | ** thus it represents an invalid character and should never be | ||
| 372 | ** accessed. | ||
| 373 | ** @return Read-write reverse iterator to the end of the string characters | ||
| 374 | ** @see begin | ||
| 375 | **/ | ||
| 376 | ReverseIterator rend(); | ||
| 377 | |||
| 378 | /** @brief Return an reverse iterator to the beginning of the string | ||
| 379 | ** The end reverse iterator refers to 1 position past the last character; | ||
| 380 | ** thus it represents an invalid character and should never be | ||
| 381 | ** accessed. | ||
| 382 | ** @return Read-only reverse iterator to the end of the string characters | ||
| 383 | ** @see begin | ||
| 384 | **/ | ||
| 385 | ConstReverseIterator rend() const; | ||
| 386 | |||
| 387 | /** @brief Resize String */ | ||
| 388 | void resize( std::size_t n, StringBaseType c ); | ||
| 389 | |||
| 390 | /** @brief Resize String */ | ||
| 391 | void resize( std::size_t n ); | ||
| 392 | |||
| 393 | /** @return Maximum size of string */ | ||
| 394 | std::size_t max_size() const; | ||
| 395 | |||
| 396 | /** @brief Request a change in capacity */ | ||
| 397 | void reserve( size_t res_arg = 0 ); | ||
| 398 | |||
| 399 | /** @return Size of allocated storage */ | ||
| 400 | std::size_t capacity() const; | ||
| 401 | |||
| 402 | /** @brief Append character to string */ | ||
| 403 | void push_back( StringBaseType c ); | ||
| 404 | |||
| 405 | /** @brief Swap contents with another string */ | ||
| 406 | void swap( String& str ); | ||
| 407 | |||
| 408 | String& assign( const String& str ); | ||
| 409 | |||
| 410 | String& assign( const String& str, std::size_t pos, std::size_t n ); | ||
| 411 | |||
| 412 | String& assign( const char* s, std::size_t n ); | ||
| 413 | |||
| 414 | String& assign( const char* s ); | ||
| 415 | |||
| 416 | String& assign( std::size_t n, char c ); | ||
| 417 | |||
| 418 | template <class InputIterator> String& assign( InputIterator first, InputIterator last ) { | ||
| 419 | mString.assign( first, last ); | ||
| 420 | return *this; | ||
| 421 | } | ||
| 422 | |||
| 423 | String& append( const String& str ); | ||
| 424 | |||
| 425 | String& append( const String& str, std::size_t pos, std::size_t n ); | ||
| 426 | |||
| 427 | String& append( const char* s, std::size_t n ); | ||
| 428 | |||
| 429 | String& append( const char* s ); | ||
| 430 | |||
| 431 | String& append( std::size_t n, char c ); | ||
| 432 | |||
| 433 | String& append( std::size_t n, StringBaseType c ); | ||
| 434 | |||
| 435 | template <class InputIterator> String& append( InputIterator first, InputIterator last ) { | ||
| 436 | mString.append( first, last ); | ||
| 437 | return *this; | ||
| 438 | } | ||
| 439 | |||
| 440 | String& replace( std::size_t pos1, std::size_t n1, const String& str ); | ||
| 441 | |||
| 442 | String& replace( Iterator i1, Iterator i2, const String& str ); | ||
| 443 | |||
| 444 | String& replace( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, | ||
| 445 | std::size_t n2 ); | ||
| 446 | |||
| 447 | String& replace( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ); | ||
| 448 | |||
| 449 | String& replace( Iterator i1, Iterator i2, const char* s, std::size_t n2 ); | ||
| 450 | |||
| 451 | String& replace( std::size_t pos1, std::size_t n1, const char* s ); | ||
| 452 | |||
| 453 | String& replace( Iterator i1, Iterator i2, const char* s ); | ||
| 454 | |||
| 455 | String& replace( std::size_t pos1, std::size_t n1, std::size_t n2, char c ); | ||
| 456 | |||
| 457 | String& replace( Iterator i1, Iterator i2, std::size_t n2, char c ); | ||
| 458 | |||
| 459 | template <class InputIterator> | ||
| 460 | String& replace( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 ) { | ||
| 461 | mString.replace( i1, i2, j1, j2 ); | ||
| 462 | return *this; | ||
| 463 | } | ||
| 464 | |||
| 465 | std::size_t rfind( const String& str, std::size_t pos = StringType::npos ) const; | ||
| 466 | |||
| 467 | std::size_t rfind( const char* s, std::size_t pos, std::size_t n ) const; | ||
| 468 | |||
| 469 | std::size_t rfind( const char* s, std::size_t pos = StringType::npos ) const; | ||
| 470 | |||
| 471 | std::size_t rfind( char c, std::size_t pos = StringType::npos ) const; | ||
| 472 | |||
| 473 | String substr( std::size_t pos = 0, std::size_t n = StringType::npos ) const; | ||
| 474 | |||
| 475 | std::size_t copy( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const; | ||
| 476 | |||
| 477 | int compare( const String& str ) const; | ||
| 478 | |||
| 479 | int compare( const char* s ) const; | ||
| 480 | |||
| 481 | int compare( std::size_t pos1, std::size_t n1, const String& str ) const; | ||
| 482 | |||
| 483 | int compare( std::size_t pos1, std::size_t n1, const char* s ) const; | ||
| 484 | |||
| 485 | int compare( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, | ||
| 486 | std::size_t n2 ) const; | ||
| 487 | |||
| 488 | int compare( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ) const; | ||
| 489 | |||
| 490 | std::size_t find_first_of( const String& str, std::size_t pos = 0 ) const; | ||
| 491 | |||
| 492 | std::size_t find_first_of( const char* s, std::size_t pos, std::size_t n ) const; | ||
| 493 | |||
| 494 | std::size_t find_first_of( const char* s, std::size_t pos = 0 ) const; | ||
| 495 | |||
| 496 | std::size_t find_first_of( StringBaseType c, std::size_t pos = 0 ) const; | ||
| 497 | |||
| 498 | std::size_t find_last_of( const String& str, std::size_t pos = StringType::npos ) const; | ||
| 499 | |||
| 500 | std::size_t find_last_of( const char* s, std::size_t pos, std::size_t n ) const; | ||
| 501 | |||
| 502 | std::size_t find_last_of( const char* s, std::size_t pos = StringType::npos ) const; | ||
| 503 | |||
| 504 | std::size_t find_last_of( StringBaseType c, std::size_t pos = StringType::npos ) const; | ||
| 505 | |||
| 506 | std::size_t find_first_not_of( const String& str, std::size_t pos = 0 ) const; | ||
| 507 | |||
| 508 | std::size_t find_first_not_of( const char* s, std::size_t pos, std::size_t n ) const; | ||
| 509 | |||
| 510 | std::size_t find_first_not_of( const char* s, std::size_t pos = 0 ) const; | ||
| 511 | |||
| 512 | std::size_t find_first_not_of( StringBaseType c, std::size_t pos = 0 ) const; | ||
| 513 | |||
| 514 | std::size_t find_last_not_of( const String& str, std::size_t pos = StringType::npos ) const; | ||
| 515 | |||
| 516 | std::size_t find_last_not_of( const char* s, std::size_t pos, std::size_t n ) const; | ||
| 517 | |||
| 518 | std::size_t find_last_not_of( const char* s, std::size_t pos = StringType::npos ) const; | ||
| 519 | |||
| 520 | std::size_t find_last_not_of( StringBaseType c, std::size_t pos = StringType::npos ) const; | ||
| 521 | |||
| 522 | private: | ||
| 523 | friend bool operator==( const String& left, const String& right ); | ||
| 524 | friend bool operator<( const String& left, const String& right ); | ||
| 525 | |||
| 526 | StringType mString; ///< Internal string of UTF-32 characters | ||
| 527 | }; | ||
| 528 | |||
| 529 | /** @relates String | ||
| 530 | ** @brief Overload of == operator to compare two UTF-32 strings | ||
| 531 | ** @param left Left operand (a string) | ||
| 532 | ** @param right Right operand (a string) | ||
| 533 | ** @return True if both strings are equal | ||
| 534 | **/ | ||
| 535 | bool operator==( const String& left, const String& right ); | ||
| 536 | |||
| 537 | /** @relates String | ||
| 538 | ** @brief Overload of != operator to compare two UTF-32 strings | ||
| 539 | ** @param left Left operand (a string) | ||
| 540 | ** @param right Right operand (a string) | ||
| 541 | ** @return True if both strings are different | ||
| 542 | **/ | ||
| 543 | bool operator!=( const String& left, const String& right ); | ||
| 544 | |||
| 545 | /** @relates String | ||
| 546 | ** @brief Overload of < operator to compare two UTF-32 strings | ||
| 547 | ** @param left Left operand (a string) | ||
| 548 | ** @param right Right operand (a string) | ||
| 549 | ** @return True if \a left is alphabetically lesser than \a right | ||
| 550 | **/ | ||
| 551 | bool operator<( const String& left, const String& right ); | ||
| 552 | |||
| 553 | /** @relates String | ||
| 554 | ** @brief Overload of > operator to compare two UTF-32 strings | ||
| 555 | ** @param left Left operand (a string) | ||
| 556 | ** @param right Right operand (a string) | ||
| 557 | ** @return True if \a left is alphabetically greater than \a right | ||
| 558 | **/ | ||
| 559 | bool operator>( const String& left, const String& right ); | ||
| 560 | |||
| 561 | /** @relates String | ||
| 562 | ** @brief Overload of <= operator to compare two UTF-32 strings | ||
| 563 | ** @param left Left operand (a string) | ||
| 564 | ** @param right Right operand (a string) | ||
| 565 | ** @return True if \a left is alphabetically lesser or equal than \a right | ||
| 566 | **/ | ||
| 567 | bool operator<=( const String& left, const String& right ); | ||
| 568 | |||
| 569 | /** @relates String | ||
| 570 | ** @brief Overload of >= operator to compare two UTF-32 strings | ||
| 571 | ** @param left Left operand (a string) | ||
| 572 | ** @param right Right operand (a string) | ||
| 573 | ** @return True if \a left is alphabetically greater or equal than \a right | ||
| 574 | **/ | ||
| 575 | bool operator>=( const String& left, const String& right ); | ||
| 576 | |||
| 577 | /** @relates String | ||
| 578 | ** @brief Overload of binary + operator to concatenate two strings | ||
| 579 | ** @param left Left operand (a string) | ||
| 580 | ** @param right Right operand (a string) | ||
| 581 | ** @return Concatenated string | ||
| 582 | **/ | ||
| 583 | String operator+( const String& left, const String& right ); | ||
| 584 | |||
| 585 | } // namespace efsw | ||
| 586 | |||
| 587 | #endif | ||
| 588 | |||
| 589 | /** @class efsw::String | ||
| 590 | ** @ingroup system | ||
| 591 | ** efsw::String is a utility string class defined mainly for | ||
| 592 | ** convenience. It is a Unicode string (implemented using | ||
| 593 | ** UTF-32), thus it can store any character in the world | ||
| 594 | ** (european, chinese, arabic, hebrew, etc.). | ||
| 595 | ** It automatically handles conversions from/to ANSI and | ||
| 596 | ** wide strings, so that you can work with standard string | ||
| 597 | ** classes and still be compatible with functions taking a | ||
| 598 | ** efsw::String. | ||
| 599 | ** @code | ||
| 600 | ** efsw::String s; | ||
| 601 | ** std::string s1 = s; // automatically converted to ANSI string | ||
| 602 | ** String s2 = s; // automatically converted to wide string | ||
| 603 | ** s = "hello"; // automatically converted from ANSI string | ||
| 604 | ** s = L"hello"; // automatically converted from wide string | ||
| 605 | ** s += 'a'; // automatically converted from ANSI string | ||
| 606 | ** s += L'a'; // automatically converted from wide string | ||
| 607 | ** @endcode | ||
| 608 | ** Conversions involving ANSI strings use the default user locale. However | ||
| 609 | ** it is possible to use a custom locale if necessary: | ||
| 610 | ** @code | ||
| 611 | ** std::locale locale; | ||
| 612 | ** efsw::String s; | ||
| 613 | ** ... | ||
| 614 | ** std::string s1 = s.toAnsiString(locale); | ||
| 615 | ** s = efsw::String("hello", locale); | ||
| 616 | ** @endcode | ||
| 617 | ** | ||
| 618 | ** efsw::String defines the most important functions of the | ||
| 619 | ** standard std::string class: removing, random access, iterating, | ||
| 620 | ** appending, comparing, etc. However it is a simple class | ||
| 621 | ** provided for convenience, and you may have to consider using | ||
| 622 | ** a more optimized class if your program requires complex string | ||
| 623 | ** handling. The automatic conversion functions will then take | ||
| 624 | ** care of converting your string to efsw::String whenever EE | ||
| 625 | ** requires it. | ||
| 626 | ** | ||
| 627 | ** Please note that EE also defines a low-level, generic | ||
| 628 | ** interface for Unicode handling, see the efsw::Utf classes. | ||
| 629 | ** | ||
| 630 | ** All credits to Laurent Gomila, i just modified and expanded a little bit the implementation. | ||
| 631 | **/ | ||
diff --git a/src/3rdParty/efsw/System.cpp b/src/3rdParty/efsw/System.cpp new file mode 100755 index 0000000..ba68bf4 --- /dev/null +++ b/src/3rdParty/efsw/System.cpp | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #include <efsw/System.hpp> | ||
| 2 | #include <efsw/platform/platformimpl.hpp> | ||
| 3 | |||
| 4 | namespace efsw { | ||
| 5 | |||
| 6 | void System::sleep( const unsigned long& ms ) { | ||
| 7 | Platform::System::sleep( ms ); | ||
| 8 | } | ||
| 9 | |||
| 10 | std::string System::getProcessPath() { | ||
| 11 | return Platform::System::getProcessPath(); | ||
| 12 | } | ||
| 13 | |||
| 14 | void System::maxFD() { | ||
| 15 | Platform::System::maxFD(); | ||
| 16 | } | ||
| 17 | |||
| 18 | Uint64 System::getMaxFD() { | ||
| 19 | return Platform::System::getMaxFD(); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/System.hpp b/src/3rdParty/efsw/System.hpp new file mode 100755 index 0000000..498e121 --- /dev/null +++ b/src/3rdParty/efsw/System.hpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #ifndef EFSW_SYSTEM_HPP | ||
| 2 | #define EFSW_SYSTEM_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | class System { | ||
| 9 | public: | ||
| 10 | /// Sleep for x milliseconds | ||
| 11 | static void sleep( const unsigned long& ms ); | ||
| 12 | |||
| 13 | /// @return The process binary path | ||
| 14 | static std::string getProcessPath(); | ||
| 15 | |||
| 16 | /// Maximize the number of file descriptors allowed per process in the current OS | ||
| 17 | static void maxFD(); | ||
| 18 | |||
| 19 | /// @return The number of supported file descriptors for the process | ||
| 20 | static Uint64 getMaxFD(); | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace efsw | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/src/3rdParty/efsw/Thread.cpp b/src/3rdParty/efsw/Thread.cpp new file mode 100755 index 0000000..e3f0fa0 --- /dev/null +++ b/src/3rdParty/efsw/Thread.cpp | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #include <efsw/Thread.hpp> | ||
| 2 | #include <efsw/platform/platformimpl.hpp> | ||
| 3 | |||
| 4 | namespace efsw { | ||
| 5 | |||
| 6 | Thread::Thread() : mThreadImpl( NULL ), mEntryPoint( NULL ) {} | ||
| 7 | |||
| 8 | Thread::~Thread() { | ||
| 9 | wait(); | ||
| 10 | |||
| 11 | efSAFE_DELETE( mEntryPoint ); | ||
| 12 | } | ||
| 13 | |||
| 14 | void Thread::launch() { | ||
| 15 | wait(); | ||
| 16 | |||
| 17 | mThreadImpl = new Platform::ThreadImpl( this ); | ||
| 18 | } | ||
| 19 | |||
| 20 | void Thread::wait() { | ||
| 21 | if ( mThreadImpl ) { | ||
| 22 | mThreadImpl->wait(); | ||
| 23 | |||
| 24 | efSAFE_DELETE( mThreadImpl ); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | void Thread::terminate() { | ||
| 29 | if ( mThreadImpl ) { | ||
| 30 | mThreadImpl->terminate(); | ||
| 31 | |||
| 32 | efSAFE_DELETE( mThreadImpl ); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | void Thread::run() { | ||
| 37 | mEntryPoint->run(); | ||
| 38 | } | ||
| 39 | |||
| 40 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/Thread.hpp b/src/3rdParty/efsw/Thread.hpp new file mode 100755 index 0000000..b60373c --- /dev/null +++ b/src/3rdParty/efsw/Thread.hpp | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | #ifndef EFSW_THREAD_HPP | ||
| 2 | #define EFSW_THREAD_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | namespace Platform { | ||
| 9 | class ThreadImpl; | ||
| 10 | } | ||
| 11 | namespace Private { | ||
| 12 | struct ThreadFunc; | ||
| 13 | } | ||
| 14 | |||
| 15 | /** @brief Thread manager class */ | ||
| 16 | class Thread { | ||
| 17 | public: | ||
| 18 | typedef void ( *FuncType )( void* ); | ||
| 19 | |||
| 20 | template <typename F> Thread( F function ); | ||
| 21 | |||
| 22 | template <typename F, typename A> Thread( F function, A argument ); | ||
| 23 | |||
| 24 | template <typename C> Thread( void ( C::*function )(), C* object ); | ||
| 25 | |||
| 26 | virtual ~Thread(); | ||
| 27 | |||
| 28 | /** Launch the thread */ | ||
| 29 | virtual void launch(); | ||
| 30 | |||
| 31 | /** Wait the thread until end */ | ||
| 32 | void wait(); | ||
| 33 | |||
| 34 | /** Terminate the thread */ | ||
| 35 | void terminate(); | ||
| 36 | |||
| 37 | protected: | ||
| 38 | Thread(); | ||
| 39 | |||
| 40 | private: | ||
| 41 | friend class Platform::ThreadImpl; | ||
| 42 | |||
| 43 | /** The virtual function to run in the thread */ | ||
| 44 | virtual void run(); | ||
| 45 | |||
| 46 | Platform::ThreadImpl* mThreadImpl; ///< OS-specific implementation of the thread | ||
| 47 | Private::ThreadFunc* mEntryPoint; ///< Abstraction of the function to run | ||
| 48 | }; | ||
| 49 | |||
| 50 | //! NOTE: Taken from SFML2 threads | ||
| 51 | namespace Private { | ||
| 52 | |||
| 53 | // Base class for abstract thread functions | ||
| 54 | struct ThreadFunc { | ||
| 55 | virtual ~ThreadFunc() {} | ||
| 56 | virtual void run() = 0; | ||
| 57 | }; | ||
| 58 | |||
| 59 | // Specialization using a functor (including free functions) with no argument | ||
| 60 | template <typename T> struct ThreadFunctor : ThreadFunc { | ||
| 61 | ThreadFunctor( T functor ) : m_functor( functor ) {} | ||
| 62 | virtual void run() { m_functor(); } | ||
| 63 | T m_functor; | ||
| 64 | }; | ||
| 65 | |||
| 66 | // Specialization using a functor (including free functions) with one argument | ||
| 67 | template <typename F, typename A> struct ThreadFunctorWithArg : ThreadFunc { | ||
| 68 | ThreadFunctorWithArg( F function, A arg ) : m_function( function ), m_arg( arg ) {} | ||
| 69 | virtual void run() { m_function( m_arg ); } | ||
| 70 | F m_function; | ||
| 71 | A m_arg; | ||
| 72 | }; | ||
| 73 | |||
| 74 | // Specialization using a member function | ||
| 75 | template <typename C> struct ThreadMemberFunc : ThreadFunc { | ||
| 76 | ThreadMemberFunc( void ( C::*function )(), C* object ) : | ||
| 77 | m_function( function ), m_object( object ) {} | ||
| 78 | virtual void run() { ( m_object->*m_function )(); } | ||
| 79 | void ( C::*m_function )(); | ||
| 80 | C* m_object; | ||
| 81 | }; | ||
| 82 | |||
| 83 | } // namespace Private | ||
| 84 | |||
| 85 | template <typename F> | ||
| 86 | Thread::Thread( F functor ) : | ||
| 87 | mThreadImpl( NULL ), mEntryPoint( new Private::ThreadFunctor<F>( functor ) ) {} | ||
| 88 | |||
| 89 | template <typename F, typename A> | ||
| 90 | Thread::Thread( F function, A argument ) : | ||
| 91 | mThreadImpl( NULL ), | ||
| 92 | mEntryPoint( new Private::ThreadFunctorWithArg<F efCOMMA A>( function, argument ) ) {} | ||
| 93 | |||
| 94 | template <typename C> | ||
| 95 | Thread::Thread( void ( C::*function )(), C* object ) : | ||
| 96 | mThreadImpl( NULL ), mEntryPoint( new Private::ThreadMemberFunc<C>( function, object ) ) {} | ||
| 97 | |||
| 98 | } // namespace efsw | ||
| 99 | |||
| 100 | #endif | ||
diff --git a/src/3rdParty/efsw/Utf.hpp b/src/3rdParty/efsw/Utf.hpp new file mode 100755 index 0000000..6e9ea71 --- /dev/null +++ b/src/3rdParty/efsw/Utf.hpp | |||
| @@ -0,0 +1,721 @@ | |||
| 1 | /** NOTE: | ||
| 2 | * This code is based on the Utf implementation from SFML2. License zlib/png ( | ||
| 3 | *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not | ||
| 4 | *the original implementation from SFML2. | ||
| 5 | * */ | ||
| 6 | |||
| 7 | #ifndef EFSW_UTF_HPP | ||
| 8 | #define EFSW_UTF_HPP | ||
| 9 | |||
| 10 | //////////////////////////////////////////////////////////// | ||
| 11 | // Headers | ||
| 12 | //////////////////////////////////////////////////////////// | ||
| 13 | #include <cstdlib> | ||
| 14 | #include <efsw/base.hpp> | ||
| 15 | #include <locale> | ||
| 16 | #include <string> | ||
| 17 | |||
| 18 | namespace efsw { | ||
| 19 | |||
| 20 | template <unsigned int N> class Utf; | ||
| 21 | |||
| 22 | //////////////////////////////////////////////////////////// | ||
| 23 | /// \brief Specialization of the Utf template for UTF-8 | ||
| 24 | /// | ||
| 25 | //////////////////////////////////////////////////////////// | ||
| 26 | template <> class Utf<8> { | ||
| 27 | public: | ||
| 28 | //////////////////////////////////////////////////////////// | ||
| 29 | /// \brief Decode a single UTF-8 character | ||
| 30 | /// | ||
| 31 | /// Decoding a character means finding its unique 32-bits | ||
| 32 | /// code (called the codepoint) in the Unicode standard. | ||
| 33 | /// | ||
| 34 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 35 | /// \param end Iterator pointing to the end of the input sequence | ||
| 36 | /// \param output Codepoint of the decoded UTF-8 character | ||
| 37 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | ||
| 38 | /// | ||
| 39 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 40 | /// | ||
| 41 | //////////////////////////////////////////////////////////// | ||
| 42 | template <typename In> | ||
| 43 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | ||
| 44 | |||
| 45 | //////////////////////////////////////////////////////////// | ||
| 46 | /// \brief Encode a single UTF-8 character | ||
| 47 | /// | ||
| 48 | /// Encoding a character means converting a unique 32-bits | ||
| 49 | /// code (called the codepoint) in the target encoding, UTF-8. | ||
| 50 | /// | ||
| 51 | /// \param input Codepoint to encode as UTF-8 | ||
| 52 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 53 | /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) | ||
| 54 | /// | ||
| 55 | /// \return Iterator to the end of the output sequence which has been written | ||
| 56 | /// | ||
| 57 | //////////////////////////////////////////////////////////// | ||
| 58 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); | ||
| 59 | |||
| 60 | //////////////////////////////////////////////////////////// | ||
| 61 | /// \brief Advance to the next UTF-8 character | ||
| 62 | /// | ||
| 63 | /// This function is necessary for multi-elements encodings, as | ||
| 64 | /// a single character may use more than 1 storage element. | ||
| 65 | /// | ||
| 66 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 67 | /// \param end Iterator pointing to the end of the input sequence | ||
| 68 | /// | ||
| 69 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 70 | /// | ||
| 71 | //////////////////////////////////////////////////////////// | ||
| 72 | template <typename In> static In Next( In begin, In end ); | ||
| 73 | |||
| 74 | //////////////////////////////////////////////////////////// | ||
| 75 | /// \brief Count the number of characters of a UTF-8 sequence | ||
| 76 | /// | ||
| 77 | /// This function is necessary for multi-elements encodings, as | ||
| 78 | /// a single character may use more than 1 storage element, thus the | ||
| 79 | /// total size can be different from (begin - end). | ||
| 80 | /// | ||
| 81 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 82 | /// \param end Iterator pointing to the end of the input sequence | ||
| 83 | /// | ||
| 84 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 85 | /// | ||
| 86 | //////////////////////////////////////////////////////////// | ||
| 87 | template <typename In> static std::size_t Count( In begin, In end ); | ||
| 88 | |||
| 89 | //////////////////////////////////////////////////////////// | ||
| 90 | /// \brief Convert an ANSI characters range to UTF-8 | ||
| 91 | /// | ||
| 92 | /// The current global locale will be used by default, unless you | ||
| 93 | /// pass a custom one in the \a locale parameter. | ||
| 94 | /// | ||
| 95 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 96 | /// \param end Iterator pointing to the end of the input sequence | ||
| 97 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 98 | /// \param locale Locale to use for conversion | ||
| 99 | /// | ||
| 100 | /// \return Iterator to the end of the output sequence which has been written | ||
| 101 | /// | ||
| 102 | //////////////////////////////////////////////////////////// | ||
| 103 | template <typename In, typename Out> | ||
| 104 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | ||
| 105 | |||
| 106 | //////////////////////////////////////////////////////////// | ||
| 107 | /// \brief Convert a wide characters range to UTF-8 | ||
| 108 | /// | ||
| 109 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 110 | /// \param end Iterator pointing to the end of the input sequence | ||
| 111 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 112 | /// | ||
| 113 | /// \return Iterator to the end of the output sequence which has been written | ||
| 114 | /// | ||
| 115 | //////////////////////////////////////////////////////////// | ||
| 116 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | ||
| 117 | |||
| 118 | //////////////////////////////////////////////////////////// | ||
| 119 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 | ||
| 120 | /// | ||
| 121 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 122 | /// \param end Iterator pointing to the end of the input sequence | ||
| 123 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 124 | /// \param locale Locale to use for conversion | ||
| 125 | /// | ||
| 126 | /// \return Iterator to the end of the output sequence which has been written | ||
| 127 | /// | ||
| 128 | //////////////////////////////////////////////////////////// | ||
| 129 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | ||
| 130 | |||
| 131 | //////////////////////////////////////////////////////////// | ||
| 132 | /// \brief Convert an UTF-8 characters range to ANSI characters | ||
| 133 | /// | ||
| 134 | /// The current global locale will be used by default, unless you | ||
| 135 | /// pass a custom one in the \a locale parameter. | ||
| 136 | /// | ||
| 137 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 138 | /// \param end Iterator pointing to the end of the input sequence | ||
| 139 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 140 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | ||
| 141 | /// \param locale Locale to use for conversion | ||
| 142 | /// | ||
| 143 | /// \return Iterator to the end of the output sequence which has been written | ||
| 144 | /// | ||
| 145 | //////////////////////////////////////////////////////////// | ||
| 146 | template <typename In, typename Out> | ||
| 147 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | ||
| 148 | const std::locale& locale = std::locale() ); | ||
| 149 | |||
| 150 | #ifndef EFSW_NO_WIDECHAR | ||
| 151 | //////////////////////////////////////////////////////////// | ||
| 152 | /// \brief Convert an UTF-8 characters range to wide characters | ||
| 153 | /// | ||
| 154 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 155 | /// \param end Iterator pointing to the end of the input sequence | ||
| 156 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 157 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | ||
| 158 | /// | ||
| 159 | /// \return Iterator to the end of the output sequence which has been written | ||
| 160 | /// | ||
| 161 | //////////////////////////////////////////////////////////// | ||
| 162 | template <typename In, typename Out> | ||
| 163 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | ||
| 164 | #endif | ||
| 165 | |||
| 166 | //////////////////////////////////////////////////////////// | ||
| 167 | /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters | ||
| 168 | /// | ||
| 169 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 170 | /// \param end Iterator pointing to the end of the input sequence | ||
| 171 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 172 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | ||
| 173 | /// | ||
| 174 | /// \return Iterator to the end of the output sequence which has been written | ||
| 175 | /// | ||
| 176 | //////////////////////////////////////////////////////////// | ||
| 177 | template <typename In, typename Out> | ||
| 178 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | ||
| 179 | |||
| 180 | //////////////////////////////////////////////////////////// | ||
| 181 | /// \brief Convert a UTF-8 characters range to UTF-8 | ||
| 182 | /// | ||
| 183 | /// This functions does nothing more than a direct copy; | ||
| 184 | /// it is defined only to provide the same interface as other | ||
| 185 | /// specializations of the efsw::Utf<> template, and allow | ||
| 186 | /// generic code to be written on top of it. | ||
| 187 | /// | ||
| 188 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 189 | /// \param end Iterator pointing to the end of the input sequence | ||
| 190 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 191 | /// | ||
| 192 | /// \return Iterator to the end of the output sequence which has been written | ||
| 193 | /// | ||
| 194 | //////////////////////////////////////////////////////////// | ||
| 195 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | ||
| 196 | |||
| 197 | //////////////////////////////////////////////////////////// | ||
| 198 | /// \brief Convert a UTF-8 characters range to UTF-16 | ||
| 199 | /// | ||
| 200 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 201 | /// \param end Iterator pointing to the end of the input sequence | ||
| 202 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 203 | /// | ||
| 204 | /// \return Iterator to the end of the output sequence which has been written | ||
| 205 | /// | ||
| 206 | //////////////////////////////////////////////////////////// | ||
| 207 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | ||
| 208 | |||
| 209 | //////////////////////////////////////////////////////////// | ||
| 210 | /// \brief Convert a UTF-8 characters range to UTF-32 | ||
| 211 | /// | ||
| 212 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 213 | /// \param end Iterator pointing to the end of the input sequence | ||
| 214 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 215 | /// | ||
| 216 | /// \return Iterator to the end of the output sequence which has been written | ||
| 217 | /// | ||
| 218 | //////////////////////////////////////////////////////////// | ||
| 219 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | ||
| 220 | }; | ||
| 221 | |||
| 222 | //////////////////////////////////////////////////////////// | ||
| 223 | /// \brief Specialization of the Utf template for UTF-16 | ||
| 224 | /// | ||
| 225 | //////////////////////////////////////////////////////////// | ||
| 226 | template <> class Utf<16> { | ||
| 227 | public: | ||
| 228 | //////////////////////////////////////////////////////////// | ||
| 229 | /// \brief Decode a single UTF-16 character | ||
| 230 | /// | ||
| 231 | /// Decoding a character means finding its unique 32-bits | ||
| 232 | /// code (called the codepoint) in the Unicode standard. | ||
| 233 | /// | ||
| 234 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 235 | /// \param end Iterator pointing to the end of the input sequence | ||
| 236 | /// \param output Codepoint of the decoded UTF-16 character | ||
| 237 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | ||
| 238 | /// | ||
| 239 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 240 | /// | ||
| 241 | //////////////////////////////////////////////////////////// | ||
| 242 | template <typename In> | ||
| 243 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | ||
| 244 | |||
| 245 | //////////////////////////////////////////////////////////// | ||
| 246 | /// \brief Encode a single UTF-16 character | ||
| 247 | /// | ||
| 248 | /// Encoding a character means converting a unique 32-bits | ||
| 249 | /// code (called the codepoint) in the target encoding, UTF-16. | ||
| 250 | /// | ||
| 251 | /// \param input Codepoint to encode as UTF-16 | ||
| 252 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 253 | /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) | ||
| 254 | /// | ||
| 255 | /// \return Iterator to the end of the output sequence which has been written | ||
| 256 | /// | ||
| 257 | //////////////////////////////////////////////////////////// | ||
| 258 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); | ||
| 259 | |||
| 260 | //////////////////////////////////////////////////////////// | ||
| 261 | /// \brief Advance to the next UTF-16 character | ||
| 262 | /// | ||
| 263 | /// This function is necessary for multi-elements encodings, as | ||
| 264 | /// a single character may use more than 1 storage element. | ||
| 265 | /// | ||
| 266 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 267 | /// \param end Iterator pointing to the end of the input sequence | ||
| 268 | /// | ||
| 269 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 270 | /// | ||
| 271 | //////////////////////////////////////////////////////////// | ||
| 272 | template <typename In> static In Next( In begin, In end ); | ||
| 273 | |||
| 274 | //////////////////////////////////////////////////////////// | ||
| 275 | /// \brief Count the number of characters of a UTF-16 sequence | ||
| 276 | /// | ||
| 277 | /// This function is necessary for multi-elements encodings, as | ||
| 278 | /// a single character may use more than 1 storage element, thus the | ||
| 279 | /// total size can be different from (begin - end). | ||
| 280 | /// | ||
| 281 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 282 | /// \param end Iterator pointing to the end of the input sequence | ||
| 283 | /// | ||
| 284 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 285 | /// | ||
| 286 | //////////////////////////////////////////////////////////// | ||
| 287 | template <typename In> static std::size_t Count( In begin, In end ); | ||
| 288 | |||
| 289 | //////////////////////////////////////////////////////////// | ||
| 290 | /// \brief Convert an ANSI characters range to UTF-16 | ||
| 291 | /// | ||
| 292 | /// The current global locale will be used by default, unless you | ||
| 293 | /// pass a custom one in the \a locale parameter. | ||
| 294 | /// | ||
| 295 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 296 | /// \param end Iterator pointing to the end of the input sequence | ||
| 297 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 298 | /// \param locale Locale to use for conversion | ||
| 299 | /// | ||
| 300 | /// \return Iterator to the end of the output sequence which has been written | ||
| 301 | /// | ||
| 302 | //////////////////////////////////////////////////////////// | ||
| 303 | template <typename In, typename Out> | ||
| 304 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | ||
| 305 | |||
| 306 | //////////////////////////////////////////////////////////// | ||
| 307 | /// \brief Convert a wide characters range to UTF-16 | ||
| 308 | /// | ||
| 309 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 310 | /// \param end Iterator pointing to the end of the input sequence | ||
| 311 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 312 | /// | ||
| 313 | /// \return Iterator to the end of the output sequence which has been written | ||
| 314 | /// | ||
| 315 | //////////////////////////////////////////////////////////// | ||
| 316 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | ||
| 317 | |||
| 318 | //////////////////////////////////////////////////////////// | ||
| 319 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 | ||
| 320 | /// | ||
| 321 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 322 | /// \param end Iterator pointing to the end of the input sequence | ||
| 323 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 324 | /// \param locale Locale to use for conversion | ||
| 325 | /// | ||
| 326 | /// \return Iterator to the end of the output sequence which has been written | ||
| 327 | /// | ||
| 328 | //////////////////////////////////////////////////////////// | ||
| 329 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | ||
| 330 | |||
| 331 | //////////////////////////////////////////////////////////// | ||
| 332 | /// \brief Convert an UTF-16 characters range to ANSI characters | ||
| 333 | /// | ||
| 334 | /// The current global locale will be used by default, unless you | ||
| 335 | /// pass a custom one in the \a locale parameter. | ||
| 336 | /// | ||
| 337 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 338 | /// \param end Iterator pointing to the end of the input sequence | ||
| 339 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 340 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | ||
| 341 | /// \param locale Locale to use for conversion | ||
| 342 | /// | ||
| 343 | /// \return Iterator to the end of the output sequence which has been written | ||
| 344 | /// | ||
| 345 | //////////////////////////////////////////////////////////// | ||
| 346 | template <typename In, typename Out> | ||
| 347 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | ||
| 348 | const std::locale& locale = std::locale() ); | ||
| 349 | |||
| 350 | #ifndef EFSW_NO_WIDECHAR | ||
| 351 | //////////////////////////////////////////////////////////// | ||
| 352 | /// \brief Convert an UTF-16 characters range to wide characters | ||
| 353 | /// | ||
| 354 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 355 | /// \param end Iterator pointing to the end of the input sequence | ||
| 356 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 357 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | ||
| 358 | /// | ||
| 359 | /// \return Iterator to the end of the output sequence which has been written | ||
| 360 | /// | ||
| 361 | //////////////////////////////////////////////////////////// | ||
| 362 | template <typename In, typename Out> | ||
| 363 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | ||
| 364 | #endif | ||
| 365 | |||
| 366 | //////////////////////////////////////////////////////////// | ||
| 367 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters | ||
| 368 | /// | ||
| 369 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 370 | /// \param end Iterator pointing to the end of the input sequence | ||
| 371 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 372 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | ||
| 373 | /// | ||
| 374 | /// \return Iterator to the end of the output sequence which has been written | ||
| 375 | /// | ||
| 376 | //////////////////////////////////////////////////////////// | ||
| 377 | template <typename In, typename Out> | ||
| 378 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | ||
| 379 | |||
| 380 | //////////////////////////////////////////////////////////// | ||
| 381 | /// \brief Convert a UTF-16 characters range to UTF-8 | ||
| 382 | /// | ||
| 383 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 384 | /// \param end Iterator pointing to the end of the input sequence | ||
| 385 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 386 | /// | ||
| 387 | /// \return Iterator to the end of the output sequence which has been written | ||
| 388 | /// | ||
| 389 | //////////////////////////////////////////////////////////// | ||
| 390 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | ||
| 391 | |||
| 392 | //////////////////////////////////////////////////////////// | ||
| 393 | /// \brief Convert a UTF-16 characters range to UTF-16 | ||
| 394 | /// | ||
| 395 | /// This functions does nothing more than a direct copy; | ||
| 396 | /// it is defined only to provide the same interface as other | ||
| 397 | /// specializations of the efsw::Utf<> template, and allow | ||
| 398 | /// generic code to be written on top of it. | ||
| 399 | /// | ||
| 400 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 401 | /// \param end Iterator pointing to the end of the input sequence | ||
| 402 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 403 | /// | ||
| 404 | /// \return Iterator to the end of the output sequence which has been written | ||
| 405 | /// | ||
| 406 | //////////////////////////////////////////////////////////// | ||
| 407 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | ||
| 408 | |||
| 409 | //////////////////////////////////////////////////////////// | ||
| 410 | /// \brief Convert a UTF-16 characters range to UTF-32 | ||
| 411 | /// | ||
| 412 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 413 | /// \param end Iterator pointing to the end of the input sequence | ||
| 414 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 415 | /// | ||
| 416 | /// \return Iterator to the end of the output sequence which has been written | ||
| 417 | /// | ||
| 418 | //////////////////////////////////////////////////////////// | ||
| 419 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | ||
| 420 | }; | ||
| 421 | |||
| 422 | //////////////////////////////////////////////////////////// | ||
| 423 | /// \brief Specialization of the Utf template for UTF-32 | ||
| 424 | /// | ||
| 425 | //////////////////////////////////////////////////////////// | ||
| 426 | template <> class Utf<32> { | ||
| 427 | public: | ||
| 428 | //////////////////////////////////////////////////////////// | ||
| 429 | /// \brief Decode a single UTF-32 character | ||
| 430 | /// | ||
| 431 | /// Decoding a character means finding its unique 32-bits | ||
| 432 | /// code (called the codepoint) in the Unicode standard. | ||
| 433 | /// For UTF-32, the character value is the same as the codepoint. | ||
| 434 | /// | ||
| 435 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 436 | /// \param end Iterator pointing to the end of the input sequence | ||
| 437 | /// \param output Codepoint of the decoded UTF-32 character | ||
| 438 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | ||
| 439 | /// | ||
| 440 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 441 | /// | ||
| 442 | //////////////////////////////////////////////////////////// | ||
| 443 | template <typename In> | ||
| 444 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | ||
| 445 | |||
| 446 | //////////////////////////////////////////////////////////// | ||
| 447 | /// \brief Encode a single UTF-32 character | ||
| 448 | /// | ||
| 449 | /// Encoding a character means converting a unique 32-bits | ||
| 450 | /// code (called the codepoint) in the target encoding, UTF-32. | ||
| 451 | /// For UTF-32, the codepoint is the same as the character value. | ||
| 452 | /// | ||
| 453 | /// \param input Codepoint to encode as UTF-32 | ||
| 454 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 455 | /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) | ||
| 456 | /// | ||
| 457 | /// \return Iterator to the end of the output sequence which has been written | ||
| 458 | /// | ||
| 459 | //////////////////////////////////////////////////////////// | ||
| 460 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); | ||
| 461 | |||
| 462 | //////////////////////////////////////////////////////////// | ||
| 463 | /// \brief Advance to the next UTF-32 character | ||
| 464 | /// | ||
| 465 | /// This function is trivial for UTF-32, which can store | ||
| 466 | /// every character in a single storage element. | ||
| 467 | /// | ||
| 468 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 469 | /// \param end Iterator pointing to the end of the input sequence | ||
| 470 | /// | ||
| 471 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 472 | /// | ||
| 473 | //////////////////////////////////////////////////////////// | ||
| 474 | template <typename In> static In Next( In begin, In end ); | ||
| 475 | |||
| 476 | //////////////////////////////////////////////////////////// | ||
| 477 | /// \brief Count the number of characters of a UTF-32 sequence | ||
| 478 | /// | ||
| 479 | /// This function is trivial for UTF-32, which can store | ||
| 480 | /// every character in a single storage element. | ||
| 481 | /// | ||
| 482 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 483 | /// \param end Iterator pointing to the end of the input sequence | ||
| 484 | /// | ||
| 485 | /// \return Iterator pointing to one past the last read element of the input sequence | ||
| 486 | /// | ||
| 487 | //////////////////////////////////////////////////////////// | ||
| 488 | template <typename In> static std::size_t Count( In begin, In end ); | ||
| 489 | |||
| 490 | //////////////////////////////////////////////////////////// | ||
| 491 | /// \brief Convert an ANSI characters range to UTF-32 | ||
| 492 | /// | ||
| 493 | /// The current global locale will be used by default, unless you | ||
| 494 | /// pass a custom one in the \a locale parameter. | ||
| 495 | /// | ||
| 496 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 497 | /// \param end Iterator pointing to the end of the input sequence | ||
| 498 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 499 | /// \param locale Locale to use for conversion | ||
| 500 | /// | ||
| 501 | /// \return Iterator to the end of the output sequence which has been written | ||
| 502 | /// | ||
| 503 | //////////////////////////////////////////////////////////// | ||
| 504 | template <typename In, typename Out> | ||
| 505 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | ||
| 506 | |||
| 507 | //////////////////////////////////////////////////////////// | ||
| 508 | /// \brief Convert a wide characters range to UTF-32 | ||
| 509 | /// | ||
| 510 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 511 | /// \param end Iterator pointing to the end of the input sequence | ||
| 512 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 513 | /// | ||
| 514 | /// \return Iterator to the end of the output sequence which has been written | ||
| 515 | /// | ||
| 516 | //////////////////////////////////////////////////////////// | ||
| 517 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | ||
| 518 | |||
| 519 | //////////////////////////////////////////////////////////// | ||
| 520 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 | ||
| 521 | /// | ||
| 522 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 523 | /// \param end Iterator pointing to the end of the input sequence | ||
| 524 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 525 | /// \param locale Locale to use for conversion | ||
| 526 | /// | ||
| 527 | /// \return Iterator to the end of the output sequence which has been written | ||
| 528 | /// | ||
| 529 | //////////////////////////////////////////////////////////// | ||
| 530 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | ||
| 531 | |||
| 532 | //////////////////////////////////////////////////////////// | ||
| 533 | /// \brief Convert an UTF-32 characters range to ANSI characters | ||
| 534 | /// | ||
| 535 | /// The current global locale will be used by default, unless you | ||
| 536 | /// pass a custom one in the \a locale parameter. | ||
| 537 | /// | ||
| 538 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 539 | /// \param end Iterator pointing to the end of the input sequence | ||
| 540 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 541 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | ||
| 542 | /// \param locale Locale to use for conversion | ||
| 543 | /// | ||
| 544 | /// \return Iterator to the end of the output sequence which has been written | ||
| 545 | /// | ||
| 546 | //////////////////////////////////////////////////////////// | ||
| 547 | template <typename In, typename Out> | ||
| 548 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | ||
| 549 | const std::locale& locale = std::locale() ); | ||
| 550 | |||
| 551 | #ifndef EFSW_NO_WIDECHAR | ||
| 552 | //////////////////////////////////////////////////////////// | ||
| 553 | /// \brief Convert an UTF-32 characters range to wide characters | ||
| 554 | /// | ||
| 555 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 556 | /// \param end Iterator pointing to the end of the input sequence | ||
| 557 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 558 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | ||
| 559 | /// | ||
| 560 | /// \return Iterator to the end of the output sequence which has been written | ||
| 561 | /// | ||
| 562 | //////////////////////////////////////////////////////////// | ||
| 563 | template <typename In, typename Out> | ||
| 564 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | ||
| 565 | #endif | ||
| 566 | |||
| 567 | //////////////////////////////////////////////////////////// | ||
| 568 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters | ||
| 569 | /// | ||
| 570 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 571 | /// \param end Iterator pointing to the end of the input sequence | ||
| 572 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 573 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | ||
| 574 | /// | ||
| 575 | /// \return Iterator to the end of the output sequence which has been written | ||
| 576 | /// | ||
| 577 | //////////////////////////////////////////////////////////// | ||
| 578 | template <typename In, typename Out> | ||
| 579 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | ||
| 580 | |||
| 581 | //////////////////////////////////////////////////////////// | ||
| 582 | /// \brief Convert a UTF-32 characters range to UTF-8 | ||
| 583 | /// | ||
| 584 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 585 | /// \param end Iterator pointing to the end of the input sequence | ||
| 586 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 587 | /// | ||
| 588 | /// \return Iterator to the end of the output sequence which has been written | ||
| 589 | /// | ||
| 590 | //////////////////////////////////////////////////////////// | ||
| 591 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | ||
| 592 | |||
| 593 | //////////////////////////////////////////////////////////// | ||
| 594 | /// \brief Convert a UTF-32 characters range to UTF-16 | ||
| 595 | /// | ||
| 596 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 597 | /// \param end Iterator pointing to the end of the input sequence | ||
| 598 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 599 | /// | ||
| 600 | /// \return Iterator to the end of the output sequence which has been written | ||
| 601 | /// | ||
| 602 | //////////////////////////////////////////////////////////// | ||
| 603 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | ||
| 604 | |||
| 605 | //////////////////////////////////////////////////////////// | ||
| 606 | /// \brief Convert a UTF-32 characters range to UTF-32 | ||
| 607 | /// | ||
| 608 | /// This functions does nothing more than a direct copy; | ||
| 609 | /// it is defined only to provide the same interface as other | ||
| 610 | /// specializations of the efsw::Utf<> template, and allow | ||
| 611 | /// generic code to be written on top of it. | ||
| 612 | /// | ||
| 613 | /// \param begin Iterator pointing to the beginning of the input sequence | ||
| 614 | /// \param end Iterator pointing to the end of the input sequence | ||
| 615 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 616 | /// | ||
| 617 | /// \return Iterator to the end of the output sequence which has been written | ||
| 618 | /// | ||
| 619 | //////////////////////////////////////////////////////////// | ||
| 620 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | ||
| 621 | |||
| 622 | //////////////////////////////////////////////////////////// | ||
| 623 | /// \brief Decode a single ANSI character to UTF-32 | ||
| 624 | /// | ||
| 625 | /// This function does not exist in other specializations | ||
| 626 | /// of efsw::Utf<>, it is defined for convenience (it is used by | ||
| 627 | /// several other conversion functions). | ||
| 628 | /// | ||
| 629 | /// \param input Input ANSI character | ||
| 630 | /// \param locale Locale to use for conversion | ||
| 631 | /// | ||
| 632 | /// \return Converted character | ||
| 633 | /// | ||
| 634 | //////////////////////////////////////////////////////////// | ||
| 635 | template <typename In> | ||
| 636 | static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); | ||
| 637 | |||
| 638 | //////////////////////////////////////////////////////////// | ||
| 639 | /// \brief Decode a single wide character to UTF-32 | ||
| 640 | /// | ||
| 641 | /// This function does not exist in other specializations | ||
| 642 | /// of efsw::Utf<>, it is defined for convenience (it is used by | ||
| 643 | /// several other conversion functions). | ||
| 644 | /// | ||
| 645 | /// \param input Input wide character | ||
| 646 | /// | ||
| 647 | /// \return Converted character | ||
| 648 | /// | ||
| 649 | //////////////////////////////////////////////////////////// | ||
| 650 | template <typename In> static Uint32 DecodeWide( In input ); | ||
| 651 | |||
| 652 | //////////////////////////////////////////////////////////// | ||
| 653 | /// \brief Encode a single UTF-32 character to ANSI | ||
| 654 | /// | ||
| 655 | /// This function does not exist in other specializations | ||
| 656 | /// of efsw::Utf<>, it is defined for convenience (it is used by | ||
| 657 | /// several other conversion functions). | ||
| 658 | /// | ||
| 659 | /// \param codepoint Iterator pointing to the beginning of the input sequence | ||
| 660 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 661 | /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to | ||
| 662 | /// skip it) \param locale Locale to use for conversion | ||
| 663 | /// | ||
| 664 | /// \return Iterator to the end of the output sequence which has been written | ||
| 665 | /// | ||
| 666 | //////////////////////////////////////////////////////////// | ||
| 667 | template <typename Out> | ||
| 668 | static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, | ||
| 669 | const std::locale& locale = std::locale() ); | ||
| 670 | |||
| 671 | #ifndef EFSW_NO_WIDECHAR | ||
| 672 | //////////////////////////////////////////////////////////// | ||
| 673 | /// \brief Encode a single UTF-32 character to wide | ||
| 674 | /// | ||
| 675 | /// This function does not exist in other specializations | ||
| 676 | /// of efsw::Utf<>, it is defined for convenience (it is used by | ||
| 677 | /// several other conversion functions). | ||
| 678 | /// | ||
| 679 | /// \param codepoint Iterator pointing to the beginning of the input sequence | ||
| 680 | /// \param output Iterator pointing to the beginning of the output sequence | ||
| 681 | /// \param replacement Replacement if the input character is not convertible to wide (use 0 to | ||
| 682 | /// skip it) | ||
| 683 | /// | ||
| 684 | /// \return Iterator to the end of the output sequence which has been written | ||
| 685 | /// | ||
| 686 | //////////////////////////////////////////////////////////// | ||
| 687 | template <typename Out> | ||
| 688 | static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); | ||
| 689 | #endif | ||
| 690 | }; | ||
| 691 | |||
| 692 | #include "Utf.inl" | ||
| 693 | |||
| 694 | // Make typedefs to get rid of the template syntax | ||
| 695 | typedef Utf<8> Utf8; | ||
| 696 | typedef Utf<16> Utf16; | ||
| 697 | typedef Utf<32> Utf32; | ||
| 698 | |||
| 699 | } // namespace efsw | ||
| 700 | #endif | ||
| 701 | |||
| 702 | //////////////////////////////////////////////////////////// | ||
| 703 | /// \class efsw::Utf | ||
| 704 | /// \ingroup system | ||
| 705 | /// | ||
| 706 | /// Utility class providing generic functions for UTF conversions. | ||
| 707 | /// | ||
| 708 | /// efsw::Utf is a low-level, generic interface for counting, iterating, | ||
| 709 | /// encoding and decoding Unicode characters and strings. It is able | ||
| 710 | /// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. | ||
| 711 | /// | ||
| 712 | /// efsw::Utf<X> functions are all static, these classes are not meant to | ||
| 713 | /// be instanciated. All the functions are template, so that you | ||
| 714 | /// can use any character / string type for a given encoding. | ||
| 715 | /// | ||
| 716 | /// It has 3 specializations: | ||
| 717 | /// \li efsw::Utf<8> (typedef'd to efsw::Utf8) | ||
| 718 | /// \li efsw::Utf<16> (typedef'd to efsw::Utf16) | ||
| 719 | /// \li efsw::Utf<32> (typedef'd to efsw::Utf32) | ||
| 720 | /// | ||
| 721 | //////////////////////////////////////////////////////////// | ||
diff --git a/src/3rdParty/efsw/Utf.inl b/src/3rdParty/efsw/Utf.inl new file mode 100755 index 0000000..7e3e9d6 --- /dev/null +++ b/src/3rdParty/efsw/Utf.inl | |||
| @@ -0,0 +1,576 @@ | |||
| 1 | // References : | ||
| 2 | // http://www.unicode.org/ | ||
| 3 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c | ||
| 4 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h | ||
| 5 | // http://people.w3.org/rishida/scripts/uniview/conversion | ||
| 6 | //////////////////////////////////////////////////////////// | ||
| 7 | |||
| 8 | template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { | ||
| 9 | // Some useful precomputed data | ||
| 10 | static const int trailing[256] = { | ||
| 11 | 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, | ||
| 12 | 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, | ||
| 13 | 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, | ||
| 14 | 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, | ||
| 15 | 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, | ||
| 16 | 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, | ||
| 17 | 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, | ||
| 18 | 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, | ||
| 19 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; | ||
| 20 | static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, | ||
| 21 | 0x03C82080, 0xFA082080, 0x82082080 }; | ||
| 22 | |||
| 23 | // Decode the character | ||
| 24 | int trailingBytes = trailing[static_cast<Uint8>( *begin )]; | ||
| 25 | if ( begin + trailingBytes < end ) { | ||
| 26 | output = 0; | ||
| 27 | switch ( trailingBytes ) { | ||
| 28 | case 5: | ||
| 29 | output += static_cast<Uint8>( *begin++ ); | ||
| 30 | output <<= 6; | ||
| 31 | case 4: | ||
| 32 | output += static_cast<Uint8>( *begin++ ); | ||
| 33 | output <<= 6; | ||
| 34 | case 3: | ||
| 35 | output += static_cast<Uint8>( *begin++ ); | ||
| 36 | output <<= 6; | ||
| 37 | case 2: | ||
| 38 | output += static_cast<Uint8>( *begin++ ); | ||
| 39 | output <<= 6; | ||
| 40 | case 1: | ||
| 41 | output += static_cast<Uint8>( *begin++ ); | ||
| 42 | output <<= 6; | ||
| 43 | case 0: | ||
| 44 | output += static_cast<Uint8>( *begin++ ); | ||
| 45 | } | ||
| 46 | output -= offsets[trailingBytes]; | ||
| 47 | } else { | ||
| 48 | // Incomplete character | ||
| 49 | begin = end; | ||
| 50 | output = replacement; | ||
| 51 | } | ||
| 52 | |||
| 53 | return begin; | ||
| 54 | } | ||
| 55 | |||
| 56 | template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { | ||
| 57 | // Some useful precomputed data | ||
| 58 | static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | ||
| 59 | |||
| 60 | // Encode the character | ||
| 61 | if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { | ||
| 62 | // Invalid character | ||
| 63 | if ( replacement ) | ||
| 64 | *output++ = replacement; | ||
| 65 | } else { | ||
| 66 | // Valid character | ||
| 67 | |||
| 68 | // Get the number of bytes to write | ||
| 69 | int bytesToWrite = 1; | ||
| 70 | if ( input < 0x80 ) | ||
| 71 | bytesToWrite = 1; | ||
| 72 | else if ( input < 0x800 ) | ||
| 73 | bytesToWrite = 2; | ||
| 74 | else if ( input < 0x10000 ) | ||
| 75 | bytesToWrite = 3; | ||
| 76 | else if ( input <= 0x0010FFFF ) | ||
| 77 | bytesToWrite = 4; | ||
| 78 | |||
| 79 | // Extract the bytes to write | ||
| 80 | Uint8 bytes[4]; | ||
| 81 | switch ( bytesToWrite ) { | ||
| 82 | case 4: | ||
| 83 | bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | ||
| 84 | input >>= 6; | ||
| 85 | case 3: | ||
| 86 | bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | ||
| 87 | input >>= 6; | ||
| 88 | case 2: | ||
| 89 | bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | ||
| 90 | input >>= 6; | ||
| 91 | case 1: | ||
| 92 | bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] ); | ||
| 93 | } | ||
| 94 | |||
| 95 | // Add them to the output | ||
| 96 | const Uint8* currentByte = bytes; | ||
| 97 | switch ( bytesToWrite ) { | ||
| 98 | case 4: | ||
| 99 | *output++ = *currentByte++; | ||
| 100 | case 3: | ||
| 101 | *output++ = *currentByte++; | ||
| 102 | case 2: | ||
| 103 | *output++ = *currentByte++; | ||
| 104 | case 1: | ||
| 105 | *output++ = *currentByte++; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | return output; | ||
| 110 | } | ||
| 111 | |||
| 112 | template <typename In> In Utf<8>::Next( In begin, In end ) { | ||
| 113 | Uint32 codepoint; | ||
| 114 | return Decode( begin, end, codepoint ); | ||
| 115 | } | ||
| 116 | |||
| 117 | template <typename In> std::size_t Utf<8>::Count( In begin, In end ) { | ||
| 118 | std::size_t length = 0; | ||
| 119 | while ( begin < end ) { | ||
| 120 | begin = Next( begin, end ); | ||
| 121 | ++length; | ||
| 122 | } | ||
| 123 | |||
| 124 | return length; | ||
| 125 | } | ||
| 126 | |||
| 127 | template <typename In, typename Out> | ||
| 128 | Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | ||
| 129 | while ( begin < end ) { | ||
| 130 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); | ||
| 131 | output = Encode( codepoint, output ); | ||
| 132 | } | ||
| 133 | |||
| 134 | return output; | ||
| 135 | } | ||
| 136 | |||
| 137 | template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) { | ||
| 138 | while ( begin < end ) { | ||
| 139 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); | ||
| 140 | output = Encode( codepoint, output ); | ||
| 141 | } | ||
| 142 | |||
| 143 | return output; | ||
| 144 | } | ||
| 145 | |||
| 146 | template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) { | ||
| 147 | // Latin-1 is directly compatible with Unicode encodings, | ||
| 148 | // and can thus be treated as (a sub-range of) UTF-32 | ||
| 149 | while ( begin < end ) | ||
| 150 | output = Encode( *begin++, output ); | ||
| 151 | |||
| 152 | return output; | ||
| 153 | } | ||
| 154 | |||
| 155 | template <typename In, typename Out> | ||
| 156 | Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | ||
| 157 | while ( begin < end ) { | ||
| 158 | Uint32 codepoint; | ||
| 159 | begin = Decode( begin, end, codepoint ); | ||
| 160 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); | ||
| 161 | } | ||
| 162 | |||
| 163 | return output; | ||
| 164 | } | ||
| 165 | |||
| 166 | #ifndef EFSW_NO_WIDECHAR | ||
| 167 | template <typename In, typename Out> | ||
| 168 | Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | ||
| 169 | while ( begin < end ) { | ||
| 170 | Uint32 codepoint; | ||
| 171 | begin = Decode( begin, end, codepoint ); | ||
| 172 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); | ||
| 173 | } | ||
| 174 | |||
| 175 | return output; | ||
| 176 | } | ||
| 177 | #endif | ||
| 178 | |||
| 179 | template <typename In, typename Out> | ||
| 180 | Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { | ||
| 181 | // Latin-1 is directly compatible with Unicode encodings, | ||
| 182 | // and can thus be treated as (a sub-range of) UTF-32 | ||
| 183 | while ( begin < end ) { | ||
| 184 | Uint32 codepoint; | ||
| 185 | begin = Decode( begin, end, codepoint ); | ||
| 186 | *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement; | ||
| 187 | } | ||
| 188 | |||
| 189 | return output; | ||
| 190 | } | ||
| 191 | |||
| 192 | template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) { | ||
| 193 | while ( begin < end ) | ||
| 194 | *output++ = *begin++; | ||
| 195 | |||
| 196 | return output; | ||
| 197 | } | ||
| 198 | |||
| 199 | template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) { | ||
| 200 | while ( begin < end ) { | ||
| 201 | Uint32 codepoint; | ||
| 202 | begin = Decode( begin, end, codepoint ); | ||
| 203 | output = Utf<16>::Encode( codepoint, output ); | ||
| 204 | } | ||
| 205 | |||
| 206 | return output; | ||
| 207 | } | ||
| 208 | |||
| 209 | template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) { | ||
| 210 | while ( begin < end ) { | ||
| 211 | Uint32 codepoint; | ||
| 212 | begin = Decode( begin, end, codepoint ); | ||
| 213 | *output++ = codepoint; | ||
| 214 | } | ||
| 215 | |||
| 216 | return output; | ||
| 217 | } | ||
| 218 | |||
| 219 | template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { | ||
| 220 | Uint16 first = *begin++; | ||
| 221 | |||
| 222 | // If it's a surrogate pair, first convert to a single UTF-32 character | ||
| 223 | if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { | ||
| 224 | if ( begin < end ) { | ||
| 225 | Uint32 second = *begin++; | ||
| 226 | if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { | ||
| 227 | // The second element is valid: convert the two elements to a UTF-32 character | ||
| 228 | output = static_cast<Uint32>( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + | ||
| 229 | 0x0010000 ); | ||
| 230 | } else { | ||
| 231 | // Invalid character | ||
| 232 | output = replacement; | ||
| 233 | } | ||
| 234 | } else { | ||
| 235 | // Invalid character | ||
| 236 | begin = end; | ||
| 237 | output = replacement; | ||
| 238 | } | ||
| 239 | } else { | ||
| 240 | // We can make a direct copy | ||
| 241 | output = first; | ||
| 242 | } | ||
| 243 | |||
| 244 | return begin; | ||
| 245 | } | ||
| 246 | |||
| 247 | template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { | ||
| 248 | if ( input < 0xFFFF ) { | ||
| 249 | // The character can be copied directly, we just need to check if it's in the valid range | ||
| 250 | if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { | ||
| 251 | // Invalid character (this range is reserved) | ||
| 252 | if ( replacement ) | ||
| 253 | *output++ = replacement; | ||
| 254 | } else { | ||
| 255 | // Valid character directly convertible to a single UTF-16 character | ||
| 256 | *output++ = static_cast<Uint16>( input ); | ||
| 257 | } | ||
| 258 | } else if ( input > 0x0010FFFF ) { | ||
| 259 | // Invalid character (greater than the maximum unicode value) | ||
| 260 | if ( replacement ) | ||
| 261 | *output++ = replacement; | ||
| 262 | } else { | ||
| 263 | // The input character will be converted to two UTF-16 elements | ||
| 264 | input -= 0x0010000; | ||
| 265 | *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 ); | ||
| 266 | *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 ); | ||
| 267 | } | ||
| 268 | |||
| 269 | return output; | ||
| 270 | } | ||
| 271 | |||
| 272 | template <typename In> In Utf<16>::Next( In begin, In end ) { | ||
| 273 | Uint32 codepoint; | ||
| 274 | return Decode( begin, end, codepoint ); | ||
| 275 | } | ||
| 276 | |||
| 277 | template <typename In> std::size_t Utf<16>::Count( In begin, In end ) { | ||
| 278 | std::size_t length = 0; | ||
| 279 | while ( begin < end ) { | ||
| 280 | begin = Next( begin, end ); | ||
| 281 | ++length; | ||
| 282 | } | ||
| 283 | |||
| 284 | return length; | ||
| 285 | } | ||
| 286 | |||
| 287 | template <typename In, typename Out> | ||
| 288 | Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | ||
| 289 | while ( begin < end ) { | ||
| 290 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); | ||
| 291 | output = Encode( codepoint, output ); | ||
| 292 | } | ||
| 293 | |||
| 294 | return output; | ||
| 295 | } | ||
| 296 | |||
| 297 | template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) { | ||
| 298 | while ( begin < end ) { | ||
| 299 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); | ||
| 300 | output = Encode( codepoint, output ); | ||
| 301 | } | ||
| 302 | |||
| 303 | return output; | ||
| 304 | } | ||
| 305 | |||
| 306 | template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) { | ||
| 307 | // Latin-1 is directly compatible with Unicode encodings, | ||
| 308 | // and can thus be treated as (a sub-range of) UTF-32 | ||
| 309 | while ( begin < end ) | ||
| 310 | *output++ = *begin++; | ||
| 311 | |||
| 312 | return output; | ||
| 313 | } | ||
| 314 | |||
| 315 | template <typename In, typename Out> | ||
| 316 | Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | ||
| 317 | while ( begin < end ) { | ||
| 318 | Uint32 codepoint; | ||
| 319 | begin = Decode( begin, end, codepoint ); | ||
| 320 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); | ||
| 321 | } | ||
| 322 | |||
| 323 | return output; | ||
| 324 | } | ||
| 325 | |||
| 326 | #ifndef EFSW_NO_WIDECHAR | ||
| 327 | template <typename In, typename Out> | ||
| 328 | Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | ||
| 329 | while ( begin < end ) { | ||
| 330 | Uint32 codepoint; | ||
| 331 | begin = Decode( begin, end, codepoint ); | ||
| 332 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); | ||
| 333 | } | ||
| 334 | |||
| 335 | return output; | ||
| 336 | } | ||
| 337 | #endif | ||
| 338 | |||
| 339 | template <typename In, typename Out> | ||
| 340 | Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { | ||
| 341 | // Latin-1 is directly compatible with Unicode encodings, | ||
| 342 | // and can thus be treated as (a sub-range of) UTF-32 | ||
| 343 | while ( begin < end ) { | ||
| 344 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; | ||
| 345 | begin++; | ||
| 346 | } | ||
| 347 | |||
| 348 | return output; | ||
| 349 | } | ||
| 350 | |||
| 351 | template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) { | ||
| 352 | while ( begin < end ) { | ||
| 353 | Uint32 codepoint; | ||
| 354 | begin = Decode( begin, end, codepoint ); | ||
| 355 | output = Utf<8>::Encode( codepoint, output ); | ||
| 356 | } | ||
| 357 | |||
| 358 | return output; | ||
| 359 | } | ||
| 360 | |||
| 361 | template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) { | ||
| 362 | while ( begin < end ) | ||
| 363 | *output++ = *begin++; | ||
| 364 | |||
| 365 | return output; | ||
| 366 | } | ||
| 367 | |||
| 368 | template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) { | ||
| 369 | while ( begin < end ) { | ||
| 370 | Uint32 codepoint; | ||
| 371 | begin = Decode( begin, end, codepoint ); | ||
| 372 | *output++ = codepoint; | ||
| 373 | } | ||
| 374 | |||
| 375 | return output; | ||
| 376 | } | ||
| 377 | |||
| 378 | template <typename In> In Utf<32>::Decode( In begin, In end, Uint32& output, Uint32 ) { | ||
| 379 | output = *begin++; | ||
| 380 | return begin; | ||
| 381 | } | ||
| 382 | |||
| 383 | template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 replacement ) { | ||
| 384 | *output++ = input; | ||
| 385 | return output; | ||
| 386 | } | ||
| 387 | |||
| 388 | template <typename In> In Utf<32>::Next( In begin, In end ) { | ||
| 389 | return ++begin; | ||
| 390 | } | ||
| 391 | |||
| 392 | template <typename In> std::size_t Utf<32>::Count( In begin, In end ) { | ||
| 393 | return begin - end; | ||
| 394 | } | ||
| 395 | |||
| 396 | template <typename In, typename Out> | ||
| 397 | Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | ||
| 398 | while ( begin < end ) | ||
| 399 | *output++ = DecodeAnsi( *begin++, locale ); | ||
| 400 | |||
| 401 | return output; | ||
| 402 | } | ||
| 403 | |||
| 404 | template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) { | ||
| 405 | while ( begin < end ) | ||
| 406 | *output++ = DecodeWide( *begin++ ); | ||
| 407 | |||
| 408 | return output; | ||
| 409 | } | ||
| 410 | |||
| 411 | template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) { | ||
| 412 | // Latin-1 is directly compatible with Unicode encodings, | ||
| 413 | // and can thus be treated as (a sub-range of) UTF-32 | ||
| 414 | while ( begin < end ) | ||
| 415 | *output++ = *begin++; | ||
| 416 | |||
| 417 | return output; | ||
| 418 | } | ||
| 419 | |||
| 420 | template <typename In, typename Out> | ||
| 421 | Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | ||
| 422 | while ( begin < end ) | ||
| 423 | output = EncodeAnsi( *begin++, output, replacement, locale ); | ||
| 424 | |||
| 425 | return output; | ||
| 426 | } | ||
| 427 | |||
| 428 | #ifndef EFSW_NO_WIDECHAR | ||
| 429 | template <typename In, typename Out> | ||
| 430 | Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | ||
| 431 | while ( begin < end ) | ||
| 432 | output = EncodeWide( *begin++, output, replacement ); | ||
| 433 | |||
| 434 | return output; | ||
| 435 | } | ||
| 436 | #endif | ||
| 437 | |||
| 438 | template <typename In, typename Out> | ||
| 439 | Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { | ||
| 440 | // Latin-1 is directly compatible with Unicode encodings, | ||
| 441 | // and can thus be treated as (a sub-range of) UTF-32 | ||
| 442 | while ( begin < end ) { | ||
| 443 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; | ||
| 444 | begin++; | ||
| 445 | } | ||
| 446 | |||
| 447 | return output; | ||
| 448 | } | ||
| 449 | |||
| 450 | template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) { | ||
| 451 | while ( begin < end ) | ||
| 452 | output = Utf<8>::Encode( *begin++, output ); | ||
| 453 | |||
| 454 | return output; | ||
| 455 | } | ||
| 456 | |||
| 457 | template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) { | ||
| 458 | while ( begin < end ) | ||
| 459 | output = Utf<16>::Encode( *begin++, output ); | ||
| 460 | |||
| 461 | return output; | ||
| 462 | } | ||
| 463 | |||
| 464 | template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) { | ||
| 465 | while ( begin < end ) | ||
| 466 | *output++ = *begin++; | ||
| 467 | |||
| 468 | return output; | ||
| 469 | } | ||
| 470 | |||
| 471 | template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { | ||
| 472 | // On Windows, gcc's standard library (glibc++) has almost | ||
| 473 | // no support for Unicode stuff. As a consequence, in this | ||
| 474 | // context we can only use the default locale and ignore | ||
| 475 | // the one passed as parameter. | ||
| 476 | |||
| 477 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ | ||
| 478 | ( defined( __GLIBCPP__ ) || \ | ||
| 479 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ | ||
| 480 | !( defined( __SGI_STL_PORT ) || \ | ||
| 481 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ | ||
| 482 | |||
| 483 | wchar_t character = 0; | ||
| 484 | mbtowc( &character, &input, 1 ); | ||
| 485 | return static_cast<Uint32>( character ); | ||
| 486 | |||
| 487 | #else | ||
| 488 | // Get the facet of the locale which deals with character conversion | ||
| 489 | #ifndef EFSW_NO_WIDECHAR | ||
| 490 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); | ||
| 491 | #else | ||
| 492 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); | ||
| 493 | #endif | ||
| 494 | |||
| 495 | // Use the facet to convert each character of the input string | ||
| 496 | return static_cast<Uint32>( facet.widen( input ) ); | ||
| 497 | |||
| 498 | #endif | ||
| 499 | } | ||
| 500 | |||
| 501 | template <typename In> Uint32 Utf<32>::DecodeWide( In input ) { | ||
| 502 | // The encoding of wide characters is not well defined and is left to the system; | ||
| 503 | // however we can safely assume that it is UCS-2 on Windows and | ||
| 504 | // UCS-4 on Unix systems. | ||
| 505 | // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, | ||
| 506 | // and UCS-4 *is* UTF-32). | ||
| 507 | |||
| 508 | return input; | ||
| 509 | } | ||
| 510 | |||
| 511 | template <typename Out> | ||
| 512 | Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, | ||
| 513 | const std::locale& locale ) { | ||
| 514 | // On Windows, gcc's standard library (glibc++) has almost | ||
| 515 | // no support for Unicode stuff. As a consequence, in this | ||
| 516 | // context we can only use the default locale and ignore | ||
| 517 | // the one passed as parameter. | ||
| 518 | |||
| 519 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ | ||
| 520 | ( defined( __GLIBCPP__ ) || \ | ||
| 521 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ | ||
| 522 | !( defined( __SGI_STL_PORT ) || \ | ||
| 523 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ | ||
| 524 | |||
| 525 | char character = 0; | ||
| 526 | if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 ) | ||
| 527 | *output++ = character; | ||
| 528 | else if ( replacement ) | ||
| 529 | *output++ = replacement; | ||
| 530 | |||
| 531 | return output; | ||
| 532 | |||
| 533 | #else | ||
| 534 | // Get the facet of the locale which deals with character conversion | ||
| 535 | #ifndef EFSW_NO_WIDECHAR | ||
| 536 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); | ||
| 537 | #else | ||
| 538 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); | ||
| 539 | #endif | ||
| 540 | |||
| 541 | // Use the facet to convert each character of the input string | ||
| 542 | *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement ); | ||
| 543 | |||
| 544 | return output; | ||
| 545 | |||
| 546 | #endif | ||
| 547 | } | ||
| 548 | |||
| 549 | #ifndef EFSW_NO_WIDECHAR | ||
| 550 | template <typename Out> | ||
| 551 | Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { | ||
| 552 | // The encoding of wide characters is not well defined and is left to the system; | ||
| 553 | // however we can safely assume that it is UCS-2 on Windows and | ||
| 554 | // UCS-4 on Unix systems. | ||
| 555 | // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). | ||
| 556 | // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). | ||
| 557 | |||
| 558 | switch ( sizeof( wchar_t ) ) { | ||
| 559 | case 4: { | ||
| 560 | *output++ = static_cast<wchar_t>( codepoint ); | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | |||
| 564 | default: { | ||
| 565 | if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { | ||
| 566 | *output++ = static_cast<wchar_t>( codepoint ); | ||
| 567 | } else if ( replacement ) { | ||
| 568 | *output++ = replacement; | ||
| 569 | } | ||
| 570 | break; | ||
| 571 | } | ||
| 572 | } | ||
| 573 | |||
| 574 | return output; | ||
| 575 | } | ||
| 576 | #endif | ||
diff --git a/src/3rdParty/efsw/Watcher.cpp b/src/3rdParty/efsw/Watcher.cpp new file mode 100755 index 0000000..913ae3c --- /dev/null +++ b/src/3rdParty/efsw/Watcher.cpp | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #include <efsw/Watcher.hpp> | ||
| 2 | |||
| 3 | namespace efsw { | ||
| 4 | |||
| 5 | Watcher::Watcher() : ID( 0 ), Directory( "" ), Listener( NULL ), Recursive( false ) {} | ||
| 6 | |||
| 7 | Watcher::Watcher( WatchID id, std::string directory, FileWatchListener* listener, bool recursive ) : | ||
| 8 | ID( id ), Directory( directory ), Listener( listener ), Recursive( recursive ) {} | ||
| 9 | |||
| 10 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/Watcher.hpp b/src/3rdParty/efsw/Watcher.hpp new file mode 100755 index 0000000..84f0980 --- /dev/null +++ b/src/3rdParty/efsw/Watcher.hpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #ifndef EFSW_WATCHERIMPL_HPP | ||
| 2 | #define EFSW_WATCHERIMPL_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | #include <efsw/efsw.hpp> | ||
| 6 | |||
| 7 | namespace efsw { | ||
| 8 | |||
| 9 | /** @brief Base Watcher class */ | ||
| 10 | class Watcher { | ||
| 11 | public: | ||
| 12 | Watcher(); | ||
| 13 | |||
| 14 | Watcher( WatchID id, std::string directory, FileWatchListener* listener, bool recursive ); | ||
| 15 | |||
| 16 | virtual ~Watcher() {} | ||
| 17 | |||
| 18 | virtual void watch() {} | ||
| 19 | |||
| 20 | WatchID ID; | ||
| 21 | std::string Directory; | ||
| 22 | FileWatchListener* Listener; | ||
| 23 | bool Recursive; | ||
| 24 | std::string OldFileName; | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace efsw | ||
| 28 | |||
| 29 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherFSEvents.cpp b/src/3rdParty/efsw/WatcherFSEvents.cpp new file mode 100755 index 0000000..6ccf527 --- /dev/null +++ b/src/3rdParty/efsw/WatcherFSEvents.cpp | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | #include <efsw/Debug.hpp> | ||
| 2 | #include <efsw/FileSystem.hpp> | ||
| 3 | #include <efsw/FileWatcherFSEvents.hpp> | ||
| 4 | #include <efsw/WatcherFSEvents.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 7 | |||
| 8 | namespace efsw { | ||
| 9 | |||
| 10 | WatcherFSEvents::WatcherFSEvents() : | ||
| 11 | Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ), initializedAsync( false ) {} | ||
| 12 | |||
| 13 | WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, | ||
| 14 | bool recursive, WatcherFSEvents* parent ) : | ||
| 15 | Watcher( id, directory, listener, recursive ), | ||
| 16 | FWatcher( NULL ), | ||
| 17 | FSStream( NULL ), | ||
| 18 | WatcherGen( NULL ), | ||
| 19 | initializedAsync( false ) {} | ||
| 20 | |||
| 21 | WatcherFSEvents::~WatcherFSEvents() { | ||
| 22 | if ( NULL != FSStream ) { | ||
| 23 | if ( initializedAsync ) { | ||
| 24 | FSEventStreamStop( FSStream ); | ||
| 25 | } | ||
| 26 | |||
| 27 | FSEventStreamInvalidate( FSStream ); | ||
| 28 | FSEventStreamRelease( FSStream ); | ||
| 29 | } | ||
| 30 | |||
| 31 | efSAFE_DELETE( WatcherGen ); | ||
| 32 | } | ||
| 33 | |||
| 34 | void WatcherFSEvents::init() { | ||
| 35 | CFStringRef CFDirectory = | ||
| 36 | CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 ); | ||
| 37 | CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void**)&CFDirectory, 1, NULL ); | ||
| 38 | |||
| 39 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; | ||
| 40 | |||
| 41 | if ( FileWatcherFSEvents::isGranular() ) { | ||
| 42 | streamFlags = efswFSEventStreamCreateFlagFileEvents; | ||
| 43 | } else { | ||
| 44 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); | ||
| 45 | } | ||
| 46 | |||
| 47 | FSEventStreamContext ctx; | ||
| 48 | /* Initialize context */ | ||
| 49 | ctx.version = 0; | ||
| 50 | ctx.info = this; | ||
| 51 | ctx.retain = NULL; | ||
| 52 | ctx.release = NULL; | ||
| 53 | ctx.copyDescription = NULL; | ||
| 54 | |||
| 55 | FSStream = | ||
| 56 | FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, | ||
| 57 | CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); | ||
| 58 | FWatcher.load()->mNeedInitMutex.lock(); | ||
| 59 | FWatcher.load()->mNeedInit.push_back( this ); | ||
| 60 | FWatcher.load()->mNeedInitMutex.unlock(); | ||
| 61 | |||
| 62 | CFRelease( CFDirectoryArray ); | ||
| 63 | CFRelease( CFDirectory ); | ||
| 64 | } | ||
| 65 | |||
| 66 | void WatcherFSEvents::initAsync() { | ||
| 67 | FSEventStreamScheduleWithRunLoop( FSStream, FWatcher.load()->mRunLoopRef.load(), | ||
| 68 | kCFRunLoopDefaultMode ); | ||
| 69 | FSEventStreamStart( FSStream ); | ||
| 70 | initializedAsync = true; | ||
| 71 | } | ||
| 72 | |||
| 73 | void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, | ||
| 74 | const std::string& filename, Action action, | ||
| 75 | std::string oldFilename ) { | ||
| 76 | Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), | ||
| 77 | FileSystem::precomposeFileName( filename ), action, oldFilename ); | ||
| 78 | } | ||
| 79 | |||
| 80 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, | ||
| 81 | std::string& dirPath, std::string& filePath ) { | ||
| 82 | if ( flags & efswFSEventStreamEventFlagItemCreated ) { | ||
| 83 | if ( FileInfo::exists( path ) ) { | ||
| 84 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | if ( flags & efswFSEventsModified ) { | ||
| 89 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | ||
| 90 | } | ||
| 91 | |||
| 92 | if ( flags & efswFSEventStreamEventFlagItemRemoved ) { | ||
| 93 | // Since i don't know the order, at least i try to keep the data consistent with the real | ||
| 94 | // state | ||
| 95 | if ( !FileInfo::exists( path ) ) { | ||
| 96 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | ||
| 102 | size_t esize = events.size(); | ||
| 103 | |||
| 104 | for ( size_t i = 0; i < esize; i++ ) { | ||
| 105 | FSEvent& event = events[i]; | ||
| 106 | |||
| 107 | if ( event.Flags & | ||
| 108 | ( kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped | | ||
| 109 | kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone | | ||
| 110 | kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount | | ||
| 111 | kFSEventStreamEventFlagRootChanged ) ) { | ||
| 112 | continue; | ||
| 113 | } | ||
| 114 | |||
| 115 | if ( !Recursive ) { | ||
| 116 | /** In case that is not recursive the watcher, ignore the events from subfolders */ | ||
| 117 | if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 ) { | ||
| 118 | continue; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | if ( FileWatcherFSEvents::isGranular() ) { | ||
| 123 | std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) ); | ||
| 124 | std::string filePath( FileSystem::fileNameFromPath( event.Path ) ); | ||
| 125 | |||
| 126 | if ( event.Flags & | ||
| 127 | ( efswFSEventStreamEventFlagItemCreated | efswFSEventStreamEventFlagItemRemoved | | ||
| 128 | efswFSEventStreamEventFlagItemRenamed ) ) { | ||
| 129 | if ( dirPath != Directory ) { | ||
| 130 | DirsChanged.insert( dirPath ); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | // This is a mess. But it's FSEvents faults, because shrinks events from the same file | ||
| 135 | // in one single event ( so there's no order for them ) For example a file could have | ||
| 136 | // been added modified and erased, but i can't know if first was erased and then added | ||
| 137 | // and modified, or added, then modified and then erased. I don't know what they were | ||
| 138 | // thinking by doing this... | ||
| 139 | efDEBUG( "Event in: %s - flags: %ld\n", event.Path.c_str(), event.Flags ); | ||
| 140 | |||
| 141 | if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { | ||
| 142 | if ( ( i + 1 < esize ) && | ||
| 143 | ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && | ||
| 144 | ( events[i + 1].Id == event.Id + 1 ) ) { | ||
| 145 | FSEvent& nEvent = events[i + 1]; | ||
| 146 | std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); | ||
| 147 | std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); | ||
| 148 | |||
| 149 | if ( event.Path != nEvent.Path ) { | ||
| 150 | if ( dirPath == newDir ) { | ||
| 151 | if ( !FileInfo::exists( event.Path ) ) { | ||
| 152 | sendFileAction( ID, dirPath, newFilepath, Actions::Moved, | ||
| 153 | filePath ); | ||
| 154 | } else { | ||
| 155 | sendFileAction( ID, dirPath, filePath, Actions::Moved, | ||
| 156 | newFilepath ); | ||
| 157 | } | ||
| 158 | } else { | ||
| 159 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | ||
| 160 | sendFileAction( ID, newDir, newFilepath, Actions::Add ); | ||
| 161 | |||
| 162 | if ( nEvent.Flags & efswFSEventsModified ) { | ||
| 163 | sendFileAction( ID, newDir, newFilepath, Actions::Modified ); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } else { | ||
| 167 | handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); | ||
| 168 | } | ||
| 169 | |||
| 170 | if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | | ||
| 171 | efswFSEventStreamEventFlagItemRemoved | | ||
| 172 | efswFSEventStreamEventFlagItemRenamed ) ) { | ||
| 173 | if ( newDir != Directory ) { | ||
| 174 | DirsChanged.insert( newDir ); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | // Skip the renamed file | ||
| 179 | i++; | ||
| 180 | } else if ( FileInfo::exists( event.Path ) ) { | ||
| 181 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | ||
| 182 | |||
| 183 | if ( event.Flags & efswFSEventsModified ) { | ||
| 184 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | ||
| 185 | } | ||
| 186 | } else { | ||
| 187 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | ||
| 188 | } | ||
| 189 | } else { | ||
| 190 | handleAddModDel( event.Flags, event.Path, dirPath, filePath ); | ||
| 191 | } | ||
| 192 | } else { | ||
| 193 | efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); | ||
| 194 | DirsChanged.insert( event.Path ); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | void WatcherFSEvents::process() { | ||
| 200 | std::set<std::string>::iterator it = DirsChanged.begin(); | ||
| 201 | |||
| 202 | for ( ; it != DirsChanged.end(); it++ ) { | ||
| 203 | if ( !FileWatcherFSEvents::isGranular() ) { | ||
| 204 | WatcherGen->watchDir( ( *it ) ); | ||
| 205 | } else { | ||
| 206 | sendFileAction( ID, FileSystem::pathRemoveFileName( ( *it ) ), | ||
| 207 | FileSystem::fileNameFromPath( ( *it ) ), Actions::Modified ); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | DirsChanged.clear(); | ||
| 212 | } | ||
| 213 | |||
| 214 | } // namespace efsw | ||
| 215 | |||
| 216 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherFSEvents.hpp b/src/3rdParty/efsw/WatcherFSEvents.hpp new file mode 100755 index 0000000..4dbb231 --- /dev/null +++ b/src/3rdParty/efsw/WatcherFSEvents.hpp | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | #ifndef EFSW_WATCHERINOTIFY_HPP | ||
| 2 | #define EFSW_WATCHERINOTIFY_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileWatcherImpl.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 7 | |||
| 8 | #include <CoreFoundation/CoreFoundation.h> | ||
| 9 | #include <CoreServices/CoreServices.h> | ||
| 10 | #include <efsw/FileInfo.hpp> | ||
| 11 | #include <efsw/WatcherGeneric.hpp> | ||
| 12 | #include <set> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | namespace efsw { | ||
| 16 | |||
| 17 | class FileWatcherFSEvents; | ||
| 18 | |||
| 19 | class FSEvent { | ||
| 20 | public: | ||
| 21 | FSEvent( std::string path, long flags, Uint64 id ) : Path( path ), Flags( flags ), Id( id ) {} | ||
| 22 | |||
| 23 | std::string Path; | ||
| 24 | long Flags; | ||
| 25 | Uint64 Id; | ||
| 26 | }; | ||
| 27 | |||
| 28 | class WatcherFSEvents : public Watcher { | ||
| 29 | public: | ||
| 30 | WatcherFSEvents(); | ||
| 31 | |||
| 32 | WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, | ||
| 33 | WatcherFSEvents* parent = NULL ); | ||
| 34 | |||
| 35 | ~WatcherFSEvents(); | ||
| 36 | |||
| 37 | void init(); | ||
| 38 | |||
| 39 | void initAsync(); | ||
| 40 | |||
| 41 | void handleActions( std::vector<FSEvent>& events ); | ||
| 42 | |||
| 43 | void process(); | ||
| 44 | |||
| 45 | Atomic<FileWatcherFSEvents*> FWatcher; | ||
| 46 | FSEventStreamRef FSStream; | ||
| 47 | |||
| 48 | protected: | ||
| 49 | void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, | ||
| 50 | std::string& filePath ); | ||
| 51 | |||
| 52 | WatcherGeneric* WatcherGen; | ||
| 53 | |||
| 54 | Atomic<bool> initializedAsync; | ||
| 55 | |||
| 56 | std::set<std::string> DirsChanged; | ||
| 57 | |||
| 58 | void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, | ||
| 59 | Action action, std::string oldFilename = "" ); | ||
| 60 | }; | ||
| 61 | |||
| 62 | } // namespace efsw | ||
| 63 | |||
| 64 | #endif | ||
| 65 | |||
| 66 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherGeneric.cpp b/src/3rdParty/efsw/WatcherGeneric.cpp new file mode 100755 index 0000000..a6bb106 --- /dev/null +++ b/src/3rdParty/efsw/WatcherGeneric.cpp | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #include <efsw/DirWatcherGeneric.hpp> | ||
| 2 | #include <efsw/FileSystem.hpp> | ||
| 3 | #include <efsw/WatcherGeneric.hpp> | ||
| 4 | |||
| 5 | namespace efsw { | ||
| 6 | |||
| 7 | WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener* fwl, | ||
| 8 | FileWatcherImpl* fw, bool recursive ) : | ||
| 9 | Watcher( id, directory, fwl, recursive ), WatcherImpl( fw ), DirWatch( NULL ) { | ||
| 10 | FileSystem::dirAddSlashAtEnd( Directory ); | ||
| 11 | |||
| 12 | DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false ); | ||
| 13 | |||
| 14 | DirWatch->addChilds( false ); | ||
| 15 | } | ||
| 16 | |||
| 17 | WatcherGeneric::~WatcherGeneric() { | ||
| 18 | efSAFE_DELETE( DirWatch ); | ||
| 19 | } | ||
| 20 | |||
| 21 | void WatcherGeneric::watch() { | ||
| 22 | DirWatch->watch(); | ||
| 23 | } | ||
| 24 | |||
| 25 | void WatcherGeneric::watchDir( std::string dir ) { | ||
| 26 | DirWatch->watchDir( dir ); | ||
| 27 | } | ||
| 28 | |||
| 29 | bool WatcherGeneric::pathInWatches( std::string path ) { | ||
| 30 | return DirWatch->pathInWatches( path ); | ||
| 31 | } | ||
| 32 | |||
| 33 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/WatcherGeneric.hpp b/src/3rdParty/efsw/WatcherGeneric.hpp new file mode 100755 index 0000000..9cf8365 --- /dev/null +++ b/src/3rdParty/efsw/WatcherGeneric.hpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #ifndef EFSW_WATCHERGENERIC_HPP | ||
| 2 | #define EFSW_WATCHERGENERIC_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileWatcherImpl.hpp> | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | class DirWatcherGeneric; | ||
| 9 | |||
| 10 | class WatcherGeneric : public Watcher { | ||
| 11 | public: | ||
| 12 | FileWatcherImpl* WatcherImpl; | ||
| 13 | DirWatcherGeneric* DirWatch; | ||
| 14 | |||
| 15 | WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener* fwl, | ||
| 16 | FileWatcherImpl* fw, bool recursive ); | ||
| 17 | |||
| 18 | ~WatcherGeneric(); | ||
| 19 | |||
| 20 | void watch(); | ||
| 21 | |||
| 22 | void watchDir( std::string dir ); | ||
| 23 | |||
| 24 | bool pathInWatches( std::string path ); | ||
| 25 | }; | ||
| 26 | |||
| 27 | } // namespace efsw | ||
| 28 | |||
| 29 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherInotify.cpp b/src/3rdParty/efsw/WatcherInotify.cpp new file mode 100755 index 0000000..7259bb1 --- /dev/null +++ b/src/3rdParty/efsw/WatcherInotify.cpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #include <efsw/WatcherInotify.hpp> | ||
| 2 | |||
| 3 | namespace efsw { | ||
| 4 | |||
| 5 | WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} | ||
| 6 | |||
| 7 | WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, | ||
| 8 | bool recursive, WatcherInotify* parent ) : | ||
| 9 | Watcher( id, directory, listener, recursive ), Parent( parent ), DirInfo( directory ) {} | ||
| 10 | |||
| 11 | bool WatcherInotify::inParentTree( WatcherInotify* parent ) { | ||
| 12 | WatcherInotify* tNext = Parent; | ||
| 13 | |||
| 14 | while ( NULL != tNext ) { | ||
| 15 | if ( tNext == parent ) { | ||
| 16 | return true; | ||
| 17 | } | ||
| 18 | |||
| 19 | tNext = tNext->Parent; | ||
| 20 | } | ||
| 21 | |||
| 22 | return false; | ||
| 23 | } | ||
| 24 | |||
| 25 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/WatcherInotify.hpp b/src/3rdParty/efsw/WatcherInotify.hpp new file mode 100755 index 0000000..bf2ff5e --- /dev/null +++ b/src/3rdParty/efsw/WatcherInotify.hpp | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #ifndef EFSW_WATCHERINOTIFY_HPP | ||
| 2 | #define EFSW_WATCHERINOTIFY_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileInfo.hpp> | ||
| 5 | #include <efsw/FileWatcherImpl.hpp> | ||
| 6 | |||
| 7 | namespace efsw { | ||
| 8 | |||
| 9 | class WatcherInotify : public Watcher { | ||
| 10 | public: | ||
| 11 | WatcherInotify(); | ||
| 12 | |||
| 13 | WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, | ||
| 14 | WatcherInotify* parent = NULL ); | ||
| 15 | |||
| 16 | bool inParentTree( WatcherInotify* parent ); | ||
| 17 | |||
| 18 | WatcherInotify* Parent; | ||
| 19 | WatchID InotifyID; | ||
| 20 | |||
| 21 | FileInfo DirInfo; | ||
| 22 | }; | ||
| 23 | |||
| 24 | } // namespace efsw | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherKqueue.cpp b/src/3rdParty/efsw/WatcherKqueue.cpp new file mode 100755 index 0000000..441948a --- /dev/null +++ b/src/3rdParty/efsw/WatcherKqueue.cpp | |||
| @@ -0,0 +1,569 @@ | |||
| 1 | #include <efsw/WatcherKqueue.hpp> | ||
| 2 | |||
| 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 4 | |||
| 5 | #include <cstdio> | ||
| 6 | #include <cstdlib> | ||
| 7 | #include <cstring> | ||
| 8 | #include <dirent.h> | ||
| 9 | #include <efsw/Debug.hpp> | ||
| 10 | #include <efsw/FileSystem.hpp> | ||
| 11 | #include <efsw/FileWatcherKqueue.hpp> | ||
| 12 | #include <efsw/String.hpp> | ||
| 13 | #include <efsw/System.hpp> | ||
| 14 | #include <efsw/WatcherGeneric.hpp> | ||
| 15 | #include <errno.h> | ||
| 16 | #include <fcntl.h> | ||
| 17 | #include <sys/stat.h> | ||
| 18 | #include <unistd.h> | ||
| 19 | |||
| 20 | #define KEVENT_RESERVE_VALUE ( 10 ) | ||
| 21 | |||
| 22 | #ifndef O_EVTONLY | ||
| 23 | #define O_EVTONLY ( O_RDONLY | O_NONBLOCK ) | ||
| 24 | #endif | ||
| 25 | |||
| 26 | namespace efsw { | ||
| 27 | |||
| 28 | int comparator( const void* ke1, const void* ke2 ) { | ||
| 29 | const KEvent* kev1 = reinterpret_cast<const KEvent*>( ke1 ); | ||
| 30 | const KEvent* kev2 = reinterpret_cast<const KEvent*>( ke2 ); | ||
| 31 | |||
| 32 | if ( NULL != kev2->udata ) { | ||
| 33 | FileInfo* fi1 = reinterpret_cast<FileInfo*>( kev1->udata ); | ||
| 34 | FileInfo* fi2 = reinterpret_cast<FileInfo*>( kev2->udata ); | ||
| 35 | |||
| 36 | return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() ); | ||
| 37 | } | ||
| 38 | |||
| 39 | return 1; | ||
| 40 | } | ||
| 41 | |||
| 42 | WatcherKqueue::WatcherKqueue( WatchID watchid, const std::string& dirname, | ||
| 43 | FileWatchListener* listener, bool recursive, | ||
| 44 | FileWatcherKqueue* watcher, WatcherKqueue* parent ) : | ||
| 45 | Watcher( watchid, dirname, listener, recursive ), | ||
| 46 | mLastWatchID( 0 ), | ||
| 47 | mChangeListCount( 0 ), | ||
| 48 | mKqueue( kqueue() ), | ||
| 49 | mWatcher( watcher ), | ||
| 50 | mParent( parent ), | ||
| 51 | mInitOK( true ), | ||
| 52 | mErrno( 0 ) { | ||
| 53 | if ( -1 == mKqueue ) { | ||
| 54 | efDEBUG( | ||
| 55 | "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", | ||
| 56 | Directory.c_str(), mWatcher->mFileDescriptorCount ); | ||
| 57 | |||
| 58 | mInitOK = false; | ||
| 59 | mErrno = errno; | ||
| 60 | } else { | ||
| 61 | mWatcher->addFD(); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | WatcherKqueue::~WatcherKqueue() { | ||
| 66 | // Remove the childs watchers ( sub-folders watches ) | ||
| 67 | removeAll(); | ||
| 68 | |||
| 69 | for ( size_t i = 0; i < mChangeListCount; i++ ) { | ||
| 70 | if ( NULL != mChangeList[i].udata ) { | ||
| 71 | FileInfo* fi = reinterpret_cast<FileInfo*>( mChangeList[i].udata ); | ||
| 72 | |||
| 73 | efSAFE_DELETE( fi ); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | close( mKqueue ); | ||
| 78 | |||
| 79 | mWatcher->removeFD(); | ||
| 80 | } | ||
| 81 | |||
| 82 | void WatcherKqueue::addAll() { | ||
| 83 | if ( -1 == mKqueue ) { | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | // scan directory and call addFile(name, false) on each file | ||
| 88 | FileSystem::dirAddSlashAtEnd( Directory ); | ||
| 89 | |||
| 90 | efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str() ); | ||
| 91 | |||
| 92 | // add base dir | ||
| 93 | int fd = open( Directory.c_str(), O_EVTONLY ); | ||
| 94 | |||
| 95 | if ( -1 == fd ) { | ||
| 96 | efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() ); | ||
| 97 | |||
| 98 | if ( EACCES != errno ) { | ||
| 99 | mInitOK = false; | ||
| 100 | } | ||
| 101 | |||
| 102 | mErrno = errno; | ||
| 103 | |||
| 104 | return; | ||
| 105 | } | ||
| 106 | |||
| 107 | mDirSnap.setDirectoryInfo( Directory ); | ||
| 108 | mDirSnap.scan(); | ||
| 109 | |||
| 110 | mChangeList.resize( KEVENT_RESERVE_VALUE ); | ||
| 111 | |||
| 112 | // Creates the kevent for the folder | ||
| 113 | EV_SET( &mChangeList[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, | ||
| 114 | NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 0, 0 ); | ||
| 115 | |||
| 116 | mWatcher->addFD(); | ||
| 117 | |||
| 118 | // Get the files and directories from the directory | ||
| 119 | FileInfoMap files = FileSystem::filesInfoFromPath( Directory ); | ||
| 120 | |||
| 121 | for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ ) { | ||
| 122 | FileInfo& fi = it->second; | ||
| 123 | |||
| 124 | if ( fi.isRegularFile() ) { | ||
| 125 | // Add the regular files kevent | ||
| 126 | addFile( fi.Filepath, false ); | ||
| 127 | } else if ( Recursive && fi.isDirectory() && fi.isReadable() ) { | ||
| 128 | // Create another watcher for the subfolders ( if recursive ) | ||
| 129 | WatchID id = addWatch( fi.Filepath, Listener, Recursive, this ); | ||
| 130 | |||
| 131 | // If the watcher is not adding the watcher means that the directory was created | ||
| 132 | if ( id > 0 && !mWatcher->isAddingWatcher() ) { | ||
| 133 | handleFolderAction( fi.Filepath, Actions::Add ); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | void WatcherKqueue::removeAll() { | ||
| 140 | efDEBUG( "removeAll(): Removing all child watchers\n" ); | ||
| 141 | |||
| 142 | std::list<WatchID> erase; | ||
| 143 | |||
| 144 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { | ||
| 145 | efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); | ||
| 146 | |||
| 147 | erase.push_back( it->second->ID ); | ||
| 148 | } | ||
| 149 | |||
| 150 | for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { | ||
| 151 | removeWatch( *eit ); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | void WatcherKqueue::addFile( const std::string& name, bool emitEvents ) { | ||
| 156 | efDEBUG( "addFile(): Added: %s\n", name.c_str() ); | ||
| 157 | |||
| 158 | // Open the file to get the file descriptor | ||
| 159 | int fd = open( name.c_str(), O_EVTONLY ); | ||
| 160 | |||
| 161 | if ( fd == -1 ) { | ||
| 162 | efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", | ||
| 163 | name.c_str(), mWatcher->mFileDescriptorCount ); | ||
| 164 | |||
| 165 | Errors::Log::createLastError( Errors::FileNotReadable, name ); | ||
| 166 | |||
| 167 | if ( EACCES != errno ) { | ||
| 168 | mInitOK = false; | ||
| 169 | } | ||
| 170 | |||
| 171 | mErrno = errno; | ||
| 172 | |||
| 173 | return; | ||
| 174 | } | ||
| 175 | |||
| 176 | mWatcher->addFD(); | ||
| 177 | |||
| 178 | // increase the file kevent file count | ||
| 179 | mChangeListCount++; | ||
| 180 | |||
| 181 | if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() && | ||
| 182 | mChangeListCount % KEVENT_RESERVE_VALUE == 0 ) { | ||
| 183 | size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE; | ||
| 184 | mChangeList.resize( reserve_size ); | ||
| 185 | efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual " | ||
| 186 | "size %ld.\n", | ||
| 187 | Directory.c_str(), reserve_size, mChangeListCount ); | ||
| 188 | } | ||
| 189 | |||
| 190 | // create entry | ||
| 191 | FileInfo* entry = new FileInfo( name ); | ||
| 192 | |||
| 193 | // set the event data at the end of the list | ||
| 194 | EV_SET( &mChangeList[mChangeListCount], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, | ||
| 195 | NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 0, (void*)entry ); | ||
| 196 | |||
| 197 | // qsort sort the list by name | ||
| 198 | qsort( &mChangeList[1], mChangeListCount, sizeof( KEvent ), comparator ); | ||
| 199 | |||
| 200 | // handle action | ||
| 201 | if ( emitEvents ) { | ||
| 202 | handleAction( name, Actions::Add ); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | void WatcherKqueue::removeFile( const std::string& name, bool emitEvents ) { | ||
| 207 | efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() ); | ||
| 208 | |||
| 209 | // bsearch | ||
| 210 | KEvent target; | ||
| 211 | |||
| 212 | // Create a temporary file info to search the kevent ( searching the directory ) | ||
| 213 | FileInfo tempEntry( name ); | ||
| 214 | |||
| 215 | target.udata = &tempEntry; | ||
| 216 | |||
| 217 | // Search the kevent | ||
| 218 | KEvent* ke = (KEvent*)bsearch( &target, &mChangeList[0], mChangeListCount + 1, sizeof( KEvent ), | ||
| 219 | comparator ); | ||
| 220 | |||
| 221 | // Trying to remove a non-existing file? | ||
| 222 | if ( !ke ) { | ||
| 223 | Errors::Log::createLastError( Errors::FileNotFound, name ); | ||
| 224 | efDEBUG( "File not removed\n" ); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | efDEBUG( "File removed\n" ); | ||
| 229 | |||
| 230 | // handle action | ||
| 231 | if ( emitEvents ) { | ||
| 232 | handleAction( name, Actions::Delete ); | ||
| 233 | } | ||
| 234 | |||
| 235 | // Delete the user data ( FileInfo ) from the kevent closed | ||
| 236 | FileInfo* del = reinterpret_cast<FileInfo*>( ke->udata ); | ||
| 237 | |||
| 238 | efSAFE_DELETE( del ); | ||
| 239 | |||
| 240 | // close the file descriptor from the kevent | ||
| 241 | close( ke->ident ); | ||
| 242 | |||
| 243 | mWatcher->removeFD(); | ||
| 244 | |||
| 245 | memset( ke, 0, sizeof( KEvent ) ); | ||
| 246 | |||
| 247 | // move end to current | ||
| 248 | memcpy( ke, &mChangeList[mChangeListCount], sizeof( KEvent ) ); | ||
| 249 | memset( &mChangeList[mChangeListCount], 0, sizeof( KEvent ) ); | ||
| 250 | --mChangeListCount; | ||
| 251 | } | ||
| 252 | |||
| 253 | void WatcherKqueue::rescan() { | ||
| 254 | efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() ); | ||
| 255 | |||
| 256 | DirectorySnapshotDiff Diff = mDirSnap.scan(); | ||
| 257 | |||
| 258 | if ( Diff.DirChanged ) { | ||
| 259 | sendDirChanged(); | ||
| 260 | } | ||
| 261 | |||
| 262 | if ( Diff.changed() ) { | ||
| 263 | FileInfoList::iterator it; | ||
| 264 | MovedList::iterator mit; | ||
| 265 | |||
| 266 | /// Files | ||
| 267 | DiffIterator( FilesCreated ) { | ||
| 268 | addFile( ( *it ).Filepath ); | ||
| 269 | } | ||
| 270 | |||
| 271 | DiffIterator( FilesModified ) { | ||
| 272 | handleAction( ( *it ).Filepath, Actions::Modified ); | ||
| 273 | } | ||
| 274 | |||
| 275 | DiffIterator( FilesDeleted ) { | ||
| 276 | removeFile( ( *it ).Filepath ); | ||
| 277 | } | ||
| 278 | |||
| 279 | DiffMovedIterator( FilesMoved ) { | ||
| 280 | handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first ); | ||
| 281 | removeFile( Directory + ( *mit ).first, false ); | ||
| 282 | addFile( ( *mit ).second.Filepath, false ); | ||
| 283 | } | ||
| 284 | |||
| 285 | /// Directories | ||
| 286 | DiffIterator( DirsCreated ) { | ||
| 287 | handleFolderAction( ( *it ).Filepath, Actions::Add ); | ||
| 288 | addWatch( ( *it ).Filepath, Listener, Recursive, this ); | ||
| 289 | } | ||
| 290 | |||
| 291 | DiffIterator( DirsModified ) { | ||
| 292 | handleFolderAction( ( *it ).Filepath, Actions::Modified ); | ||
| 293 | } | ||
| 294 | |||
| 295 | DiffIterator( DirsDeleted ) { | ||
| 296 | handleFolderAction( ( *it ).Filepath, Actions::Delete ); | ||
| 297 | |||
| 298 | Watcher* watch = findWatcher( ( *it ).Filepath ); | ||
| 299 | |||
| 300 | if ( NULL != watch ) { | ||
| 301 | removeWatch( watch->ID ); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | DiffMovedIterator( DirsMoved ) { | ||
| 306 | moveDirectory( Directory + ( *mit ).first, ( *mit ).second.Filepath ); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | WatchID WatcherKqueue::watchingDirectory( std::string dir ) { | ||
| 312 | Watcher* watch = findWatcher( dir ); | ||
| 313 | |||
| 314 | if ( NULL != watch ) { | ||
| 315 | return watch->ID; | ||
| 316 | } | ||
| 317 | |||
| 318 | return Errors::FileNotFound; | ||
| 319 | } | ||
| 320 | |||
| 321 | void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, | ||
| 322 | const std::string& oldFilename ) { | ||
| 323 | Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, | ||
| 324 | FileSystem::fileNameFromPath( oldFilename ) ); | ||
| 325 | } | ||
| 326 | |||
| 327 | void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action, | ||
| 328 | const std::string& oldFilename ) { | ||
| 329 | FileSystem::dirRemoveSlashAtEnd( filename ); | ||
| 330 | |||
| 331 | handleAction( filename, action, oldFilename ); | ||
| 332 | } | ||
| 333 | |||
| 334 | void WatcherKqueue::sendDirChanged() { | ||
| 335 | if ( NULL != mParent ) { | ||
| 336 | Listener->handleFileAction( mParent->ID, mParent->Directory, | ||
| 337 | FileSystem::fileNameFromPath( Directory ), Actions::Modified ); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | void WatcherKqueue::watch() { | ||
| 342 | if ( -1 == mKqueue ) { | ||
| 343 | return; | ||
| 344 | } | ||
| 345 | |||
| 346 | int nev = 0; | ||
| 347 | KEvent event; | ||
| 348 | |||
| 349 | // First iterate the childs, to get the events from the deepest folder, to the watcher childs | ||
| 350 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
| 351 | it->second->watch(); | ||
| 352 | } | ||
| 353 | |||
| 354 | bool needScan = false; | ||
| 355 | |||
| 356 | // Then we get the the events of the current folder | ||
| 357 | while ( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, | ||
| 358 | &mWatcher->mTimeOut ) ) != 0 ) { | ||
| 359 | // An error ocurred? | ||
| 360 | if ( nev == -1 ) { | ||
| 361 | efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() ); | ||
| 362 | perror( "kevent" ); | ||
| 363 | break; | ||
| 364 | } else { | ||
| 365 | FileInfo* entry = NULL; | ||
| 366 | |||
| 367 | // If udate == NULL means that it is the fisrt element of the change list, the folder. | ||
| 368 | // otherwise it is an event of some file inside the folder | ||
| 369 | if ( ( entry = reinterpret_cast<FileInfo*>( event.udata ) ) != NULL ) { | ||
| 370 | efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() ); | ||
| 371 | |||
| 372 | // If the event flag is delete... the file was deleted | ||
| 373 | if ( event.fflags & NOTE_DELETE ) { | ||
| 374 | efDEBUG( "deleted\n" ); | ||
| 375 | |||
| 376 | mDirSnap.removeFile( entry->Filepath ); | ||
| 377 | |||
| 378 | removeFile( entry->Filepath ); | ||
| 379 | } else if ( event.fflags & NOTE_EXTEND || event.fflags & NOTE_WRITE || | ||
| 380 | event.fflags & NOTE_ATTRIB ) { | ||
| 381 | // The file was modified | ||
| 382 | efDEBUG( "modified\n" ); | ||
| 383 | |||
| 384 | FileInfo fi( entry->Filepath ); | ||
| 385 | |||
| 386 | if ( fi != *entry ) { | ||
| 387 | *entry = fi; | ||
| 388 | |||
| 389 | mDirSnap.updateFile( entry->Filepath ); | ||
| 390 | |||
| 391 | handleAction( entry->Filepath, efsw::Actions::Modified ); | ||
| 392 | } | ||
| 393 | } else if ( event.fflags & NOTE_RENAME ) { | ||
| 394 | efDEBUG( "moved\n" ); | ||
| 395 | |||
| 396 | needScan = true; | ||
| 397 | } | ||
| 398 | } else { | ||
| 399 | needScan = true; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | if ( needScan ) { | ||
| 405 | rescan(); | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | Watcher* WatcherKqueue::findWatcher( const std::string path ) { | ||
| 410 | WatchMap::iterator it = mWatches.begin(); | ||
| 411 | |||
| 412 | for ( ; it != mWatches.end(); it++ ) { | ||
| 413 | if ( it->second->Directory == path ) { | ||
| 414 | return it->second; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | return NULL; | ||
| 419 | } | ||
| 420 | |||
| 421 | void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents ) { | ||
| 422 | // Update the directory path if it's a watcher | ||
| 423 | std::string opath2( oldPath ); | ||
| 424 | FileSystem::dirAddSlashAtEnd( opath2 ); | ||
| 425 | |||
| 426 | Watcher* watch = findWatcher( opath2 ); | ||
| 427 | |||
| 428 | if ( NULL != watch ) { | ||
| 429 | watch->Directory = opath2; | ||
| 430 | } | ||
| 431 | |||
| 432 | if ( emitEvents ) { | ||
| 433 | handleFolderAction( newPath, efsw::Actions::Moved, oldPath ); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
| 438 | bool recursive, WatcherKqueue* parent ) { | ||
| 439 | static long s_fc = 0; | ||
| 440 | static bool s_ug = false; | ||
| 441 | |||
| 442 | std::string dir( directory ); | ||
| 443 | |||
| 444 | FileSystem::dirAddSlashAtEnd( dir ); | ||
| 445 | |||
| 446 | // This should never happen here | ||
| 447 | if ( !FileSystem::isDirectory( dir ) ) { | ||
| 448 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
| 449 | } else if ( pathInWatches( dir ) || pathInParent( dir ) ) { | ||
| 450 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
| 451 | } else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) { | ||
| 452 | return Errors::Log::createLastError( Errors::FileRemote, dir ); | ||
| 453 | } | ||
| 454 | |||
| 455 | std::string curPath; | ||
| 456 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
| 457 | |||
| 458 | if ( "" != link ) { | ||
| 459 | /// Avoid adding symlinks directories if it's now enabled | ||
| 460 | if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() ) { | ||
| 461 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
| 462 | } | ||
| 463 | |||
| 464 | if ( pathInWatches( link ) || pathInParent( link ) ) { | ||
| 465 | return Errors::Log::createLastError( Errors::FileRepeated, link ); | ||
| 466 | } else if ( !mWatcher->linkAllowed( curPath, link ) ) { | ||
| 467 | return Errors::Log::createLastError( Errors::FileOutOfScope, link ); | ||
| 468 | } else { | ||
| 469 | dir = link; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | if ( mWatcher->availablesFD() ) { | ||
| 474 | WatcherKqueue* watch = | ||
| 475 | new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent ); | ||
| 476 | |||
| 477 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
| 478 | |||
| 479 | watch->addAll(); | ||
| 480 | |||
| 481 | s_fc++; | ||
| 482 | |||
| 483 | // if failed to open the directory... erase the watcher | ||
| 484 | if ( !watch->initOK() ) { | ||
| 485 | int le = watch->lastErrno(); | ||
| 486 | |||
| 487 | mWatches.erase( watch->ID ); | ||
| 488 | |||
| 489 | efSAFE_DELETE( watch ); | ||
| 490 | |||
| 491 | mLastWatchID--; | ||
| 492 | |||
| 493 | // Probably the folder has too many files, create a generic watcher | ||
| 494 | if ( EACCES != le ) { | ||
| 495 | WatcherGeneric* watch = | ||
| 496 | new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); | ||
| 497 | |||
| 498 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
| 499 | } else { | ||
| 500 | return Errors::Log::createLastError( Errors::Unspecified, link ); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | } else { | ||
| 504 | if ( !s_ug ) { | ||
| 505 | efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders " | ||
| 506 | "added: %ld\n", | ||
| 507 | mWatcher->mFileDescriptorCount, s_fc ); | ||
| 508 | s_ug = true; | ||
| 509 | } | ||
| 510 | |||
| 511 | WatcherGeneric* watch = | ||
| 512 | new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); | ||
| 513 | |||
| 514 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
| 515 | } | ||
| 516 | |||
| 517 | return mLastWatchID; | ||
| 518 | } | ||
| 519 | |||
| 520 | bool WatcherKqueue::initOK() { | ||
| 521 | return mInitOK; | ||
| 522 | } | ||
| 523 | |||
| 524 | void WatcherKqueue::removeWatch( WatchID watchid ) { | ||
| 525 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
| 526 | |||
| 527 | if ( iter == mWatches.end() ) | ||
| 528 | return; | ||
| 529 | |||
| 530 | Watcher* watch = iter->second; | ||
| 531 | |||
| 532 | mWatches.erase( iter ); | ||
| 533 | |||
| 534 | efSAFE_DELETE( watch ); | ||
| 535 | } | ||
| 536 | |||
| 537 | bool WatcherKqueue::pathInWatches( const std::string& path ) { | ||
| 538 | return NULL != findWatcher( path ); | ||
| 539 | } | ||
| 540 | |||
| 541 | bool WatcherKqueue::pathInParent( const std::string& path ) { | ||
| 542 | WatcherKqueue* pNext = mParent; | ||
| 543 | |||
| 544 | while ( NULL != pNext ) { | ||
| 545 | if ( pNext->pathInWatches( path ) ) { | ||
| 546 | return true; | ||
| 547 | } | ||
| 548 | |||
| 549 | pNext = pNext->mParent; | ||
| 550 | } | ||
| 551 | |||
| 552 | if ( mWatcher->pathInWatches( path ) ) { | ||
| 553 | return true; | ||
| 554 | } | ||
| 555 | |||
| 556 | if ( path == Directory ) { | ||
| 557 | return true; | ||
| 558 | } | ||
| 559 | |||
| 560 | return false; | ||
| 561 | } | ||
| 562 | |||
| 563 | int WatcherKqueue::lastErrno() { | ||
| 564 | return mErrno; | ||
| 565 | } | ||
| 566 | |||
| 567 | } // namespace efsw | ||
| 568 | |||
| 569 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherKqueue.hpp b/src/3rdParty/efsw/WatcherKqueue.hpp new file mode 100755 index 0000000..87d898c --- /dev/null +++ b/src/3rdParty/efsw/WatcherKqueue.hpp | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #ifndef EFSW_WATCHEROSX_HPP | ||
| 2 | #define EFSW_WATCHEROSX_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileWatcherImpl.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
| 7 | |||
| 8 | #include <efsw/DirectorySnapshot.hpp> | ||
| 9 | #include <map> | ||
| 10 | #include <sys/event.h> | ||
| 11 | #include <sys/types.h> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | namespace efsw { | ||
| 15 | |||
| 16 | class FileWatcherKqueue; | ||
| 17 | class WatcherKqueue; | ||
| 18 | |||
| 19 | typedef struct kevent KEvent; | ||
| 20 | |||
| 21 | /// type for a map from WatchID to WatcherKqueue pointer | ||
| 22 | typedef std::map<WatchID, Watcher*> WatchMap; | ||
| 23 | |||
| 24 | class WatcherKqueue : public Watcher { | ||
| 25 | public: | ||
| 26 | WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, | ||
| 27 | bool recursive, FileWatcherKqueue* watcher, WatcherKqueue* parent = NULL ); | ||
| 28 | |||
| 29 | virtual ~WatcherKqueue(); | ||
| 30 | |||
| 31 | void addFile( const std::string& name, bool emitEvents = true ); | ||
| 32 | |||
| 33 | void removeFile( const std::string& name, bool emitEvents = true ); | ||
| 34 | |||
| 35 | // called when the directory is actually changed | ||
| 36 | // means a file has been added or removed | ||
| 37 | // rescans the watched directory adding/removing files and sending notices | ||
| 38 | void rescan(); | ||
| 39 | |||
| 40 | void handleAction( const std::string& filename, efsw::Action action, | ||
| 41 | const std::string& oldFilename = "" ); | ||
| 42 | |||
| 43 | void handleFolderAction( std::string filename, efsw::Action action, | ||
| 44 | const std::string& oldFilename = "" ); | ||
| 45 | |||
| 46 | void addAll(); | ||
| 47 | |||
| 48 | void removeAll(); | ||
| 49 | |||
| 50 | WatchID watchingDirectory( std::string dir ); | ||
| 51 | |||
| 52 | void watch(); | ||
| 53 | |||
| 54 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, | ||
| 55 | WatcherKqueue* parent ); | ||
| 56 | |||
| 57 | void removeWatch( WatchID watchid ); | ||
| 58 | |||
| 59 | bool initOK(); | ||
| 60 | |||
| 61 | int lastErrno(); | ||
| 62 | |||
| 63 | protected: | ||
| 64 | WatchMap mWatches; | ||
| 65 | int mLastWatchID; | ||
| 66 | |||
| 67 | // index 0 is always the directory | ||
| 68 | std::vector<KEvent> mChangeList; | ||
| 69 | size_t mChangeListCount; | ||
| 70 | DirectorySnapshot mDirSnap; | ||
| 71 | |||
| 72 | /// The descriptor for the kqueue | ||
| 73 | int mKqueue; | ||
| 74 | |||
| 75 | FileWatcherKqueue* mWatcher; | ||
| 76 | |||
| 77 | WatcherKqueue* mParent; | ||
| 78 | |||
| 79 | bool mInitOK; | ||
| 80 | int mErrno; | ||
| 81 | |||
| 82 | bool pathInWatches( const std::string& path ); | ||
| 83 | |||
| 84 | bool pathInParent( const std::string& path ); | ||
| 85 | |||
| 86 | Watcher* findWatcher( const std::string path ); | ||
| 87 | |||
| 88 | void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true ); | ||
| 89 | |||
| 90 | void sendDirChanged(); | ||
| 91 | }; | ||
| 92 | |||
| 93 | } // namespace efsw | ||
| 94 | |||
| 95 | #endif | ||
| 96 | |||
| 97 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherWin32.cpp b/src/3rdParty/efsw/WatcherWin32.cpp new file mode 100755 index 0000000..3e8bcc7 --- /dev/null +++ b/src/3rdParty/efsw/WatcherWin32.cpp | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | #include <efsw/String.hpp> | ||
| 2 | #include <efsw/WatcherWin32.hpp> | ||
| 3 | |||
| 4 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 5 | |||
| 6 | namespace efsw { | ||
| 7 | |||
| 8 | /// Unpacks events and passes them to a user defined callback. | ||
| 9 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { | ||
| 10 | if ( dwNumberOfBytesTransfered == 0 || NULL == lpOverlapped ) { | ||
| 11 | return; | ||
| 12 | } | ||
| 13 | |||
| 14 | char szFile[MAX_PATH]; | ||
| 15 | PFILE_NOTIFY_INFORMATION pNotify; | ||
| 16 | WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; | ||
| 17 | WatcherWin32* pWatch = tWatch->Watch; | ||
| 18 | size_t offset = 0; | ||
| 19 | |||
| 20 | do { | ||
| 21 | bool skip = false; | ||
| 22 | |||
| 23 | pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; | ||
| 24 | offset += pNotify->NextEntryOffset; | ||
| 25 | |||
| 26 | int count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
| 27 | pNotify->FileNameLength / sizeof( WCHAR ), szFile, | ||
| 28 | MAX_PATH - 1, NULL, NULL ); | ||
| 29 | szFile[count] = TEXT( '\0' ); | ||
| 30 | |||
| 31 | std::string nfile( szFile ); | ||
| 32 | |||
| 33 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { | ||
| 34 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); | ||
| 35 | |||
| 36 | if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && | ||
| 37 | pWatch->LastModifiedEvent.file.Size == fifile.Size && | ||
| 38 | pWatch->LastModifiedEvent.fileName == nfile ) { | ||
| 39 | skip = true; | ||
| 40 | } | ||
| 41 | |||
| 42 | pWatch->LastModifiedEvent.fileName = nfile; | ||
| 43 | pWatch->LastModifiedEvent.file = fifile; | ||
| 44 | } | ||
| 45 | |||
| 46 | if ( !skip ) { | ||
| 47 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); | ||
| 48 | } | ||
| 49 | } while ( pNotify->NextEntryOffset != 0 ); | ||
| 50 | |||
| 51 | if ( !pWatch->StopNow ) { | ||
| 52 | RefreshWatch( tWatch ); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /// Refreshes the directory monitoring. | ||
| 57 | bool RefreshWatch( WatcherStructWin32* pWatch ) { | ||
| 58 | return ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer, | ||
| 59 | sizeof( pWatch->Watch->Buffer ), pWatch->Watch->Recursive, | ||
| 60 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | ||
| 61 | NULL ) != 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | /// Stops monitoring a directory. | ||
| 65 | void DestroyWatch( WatcherStructWin32* pWatch ) { | ||
| 66 | if ( pWatch ) { | ||
| 67 | WatcherWin32* tWatch = pWatch->Watch; | ||
| 68 | tWatch->StopNow = true; | ||
| 69 | CancelIoEx( pWatch->Watch->DirHandle, &pWatch->Overlapped ); | ||
| 70 | CloseHandle( pWatch->Watch->DirHandle ); | ||
| 71 | efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); | ||
| 72 | efSAFE_DELETE( pWatch->Watch ); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Starts monitoring a directory. | ||
| 77 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | ||
| 78 | HANDLE iocp ) { | ||
| 79 | WatcherStructWin32* tWatch; | ||
| 80 | size_t ptrsize = sizeof( *tWatch ); | ||
| 81 | tWatch = static_cast<WatcherStructWin32*>( | ||
| 82 | HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize ) ); | ||
| 83 | |||
| 84 | WatcherWin32* pWatch = new WatcherWin32(); | ||
| 85 | tWatch->Watch = pWatch; | ||
| 86 | |||
| 87 | pWatch->DirHandle = CreateFileW( | ||
| 88 | szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, | ||
| 89 | OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL ); | ||
| 90 | |||
| 91 | if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && | ||
| 92 | CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { | ||
| 93 | pWatch->NotifyFilter = NotifyFilter; | ||
| 94 | pWatch->Recursive = recursive; | ||
| 95 | |||
| 96 | if ( RefreshWatch( tWatch ) ) { | ||
| 97 | return tWatch; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | CloseHandle( pWatch->DirHandle ); | ||
| 102 | efSAFE_DELETE( pWatch->Watch ); | ||
| 103 | HeapFree( GetProcessHeap(), 0, tWatch ); | ||
| 104 | return NULL; | ||
| 105 | } | ||
| 106 | |||
| 107 | } // namespace efsw | ||
| 108 | |||
| 109 | #endif | ||
diff --git a/src/3rdParty/efsw/WatcherWin32.hpp b/src/3rdParty/efsw/WatcherWin32.hpp new file mode 100755 index 0000000..71e13be --- /dev/null +++ b/src/3rdParty/efsw/WatcherWin32.hpp | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #ifndef EFSW_WATCHERWIN32_HPP | ||
| 2 | #define EFSW_WATCHERWIN32_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileInfo.hpp> | ||
| 5 | #include <efsw/FileWatcherImpl.hpp> | ||
| 6 | |||
| 7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 8 | |||
| 9 | #include <windows.h> | ||
| 10 | |||
| 11 | #ifdef EFSW_COMPILER_MSVC | ||
| 12 | #pragma comment( lib, "comctl32.lib" ) | ||
| 13 | #pragma comment( lib, "user32.lib" ) | ||
| 14 | #pragma comment( lib, "ole32.lib" ) | ||
| 15 | |||
| 16 | // disable secure warnings | ||
| 17 | #pragma warning( disable : 4996 ) | ||
| 18 | #endif | ||
| 19 | |||
| 20 | namespace efsw { | ||
| 21 | |||
| 22 | class WatcherWin32; | ||
| 23 | |||
| 24 | /// Internal watch data | ||
| 25 | struct WatcherStructWin32 { | ||
| 26 | OVERLAPPED Overlapped; | ||
| 27 | WatcherWin32* Watch; | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct sLastModifiedEvent { | ||
| 31 | FileInfo file; | ||
| 32 | std::string fileName; | ||
| 33 | }; | ||
| 34 | |||
| 35 | bool RefreshWatch( WatcherStructWin32* pWatch ); | ||
| 36 | |||
| 37 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); | ||
| 38 | |||
| 39 | void DestroyWatch( WatcherStructWin32* pWatch ); | ||
| 40 | |||
| 41 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | ||
| 42 | HANDLE iocp ); | ||
| 43 | |||
| 44 | class WatcherWin32 : public Watcher { | ||
| 45 | public: | ||
| 46 | WatcherWin32() : | ||
| 47 | Struct( NULL ), | ||
| 48 | DirHandle( NULL ), | ||
| 49 | lParam( 0 ), | ||
| 50 | NotifyFilter( 0 ), | ||
| 51 | StopNow( false ), | ||
| 52 | Watch( NULL ), | ||
| 53 | DirName( NULL ) {} | ||
| 54 | |||
| 55 | WatcherStructWin32* Struct; | ||
| 56 | HANDLE DirHandle; | ||
| 57 | BYTE Buffer | ||
| 58 | [63 * | ||
| 59 | 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched | ||
| 60 | // is on the network! (see | ||
| 61 | // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) | ||
| 62 | LPARAM lParam; | ||
| 63 | DWORD NotifyFilter; | ||
| 64 | bool StopNow; | ||
| 65 | FileWatcherImpl* Watch; | ||
| 66 | char* DirName; | ||
| 67 | sLastModifiedEvent LastModifiedEvent; | ||
| 68 | }; | ||
| 69 | |||
| 70 | } // namespace efsw | ||
| 71 | |||
| 72 | #endif | ||
| 73 | |||
| 74 | #endif | ||
diff --git a/src/3rdParty/efsw/base.hpp b/src/3rdParty/efsw/base.hpp new file mode 100755 index 0000000..43abc4f --- /dev/null +++ b/src/3rdParty/efsw/base.hpp | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | #ifndef EFSW_BASE | ||
| 2 | #define EFSW_BASE | ||
| 3 | |||
| 4 | #include <efsw/efsw.hpp> | ||
| 5 | #include <efsw/sophist.h> | ||
| 6 | |||
| 7 | namespace efsw { | ||
| 8 | |||
| 9 | typedef SOPHIST_int8 Int8; | ||
| 10 | typedef SOPHIST_uint8 Uint8; | ||
| 11 | typedef SOPHIST_int16 Int16; | ||
| 12 | typedef SOPHIST_uint16 Uint16; | ||
| 13 | typedef SOPHIST_int32 Int32; | ||
| 14 | typedef SOPHIST_uint32 Uint32; | ||
| 15 | typedef SOPHIST_int64 Int64; | ||
| 16 | typedef SOPHIST_uint64 Uint64; | ||
| 17 | |||
| 18 | #define EFSW_OS_WIN 1 | ||
| 19 | #define EFSW_OS_LINUX 2 | ||
| 20 | #define EFSW_OS_MACOSX 3 | ||
| 21 | #define EFSW_OS_BSD 4 | ||
| 22 | #define EFSW_OS_SOLARIS 5 | ||
| 23 | #define EFSW_OS_HAIKU 6 | ||
| 24 | #define EFSW_OS_ANDROID 7 | ||
| 25 | #define EFSW_OS_IOS 8 | ||
| 26 | |||
| 27 | #define EFSW_PLATFORM_WIN32 1 | ||
| 28 | #define EFSW_PLATFORM_INOTIFY 2 | ||
| 29 | #define EFSW_PLATFORM_KQUEUE 3 | ||
| 30 | #define EFSW_PLATFORM_FSEVENTS 4 | ||
| 31 | #define EFSW_PLATFORM_GENERIC 5 | ||
| 32 | |||
| 33 | #if defined( _WIN32 ) | ||
| 34 | /// Any Windows platform | ||
| 35 | #define EFSW_OS EFSW_OS_WIN | ||
| 36 | #define EFSW_PLATFORM EFSW_PLATFORM_WIN32 | ||
| 37 | |||
| 38 | #if ( defined( _MSCVER ) || defined( _MSC_VER ) ) | ||
| 39 | #define EFSW_COMPILER_MSVC | ||
| 40 | #endif | ||
| 41 | |||
| 42 | /// Force windows target version above or equal to Windows Server 2008 or Windows Vista | ||
| 43 | #if _WIN32_WINNT < 0x600 | ||
| 44 | #undef _WIN32_WINNT | ||
| 45 | #define _WIN32_WINNT 0x600 | ||
| 46 | #endif | ||
| 47 | #elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) || \ | ||
| 48 | defined( __DragonFly__ ) | ||
| 49 | #define EFSW_OS EFSW_OS_BSD | ||
| 50 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE | ||
| 51 | |||
| 52 | #elif defined( __APPLE_CC__ ) || defined( __APPLE__ ) | ||
| 53 | #include <TargetConditionals.h> | ||
| 54 | |||
| 55 | #if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || \ | ||
| 56 | ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR ) | ||
| 57 | #define EFSW_OS EFSW_OS_IOS | ||
| 58 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE | ||
| 59 | #else | ||
| 60 | #define EFSW_OS EFSW_OS_MACOSX | ||
| 61 | |||
| 62 | #if defined( EFSW_FSEVENTS_NOT_SUPPORTED ) | ||
| 63 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE | ||
| 64 | #else | ||
| 65 | #define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS | ||
| 66 | #endif | ||
| 67 | #endif | ||
| 68 | |||
| 69 | #elif defined( __linux__ ) | ||
| 70 | /// This includes Linux and Android | ||
| 71 | #ifndef EFSW_KQUEUE | ||
| 72 | #define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY | ||
| 73 | #else | ||
| 74 | /// This is for testing libkqueue, sadly it doesnt work | ||
| 75 | #define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE | ||
| 76 | #endif | ||
| 77 | |||
| 78 | #if defined( __ANDROID__ ) || defined( ANDROID ) | ||
| 79 | #define EFSW_OS EFSW_OS_ANDROID | ||
| 80 | #else | ||
| 81 | #define EFSW_OS EFSW_OS_LINUX | ||
| 82 | #endif | ||
| 83 | |||
| 84 | #else | ||
| 85 | #if defined( __SVR4 ) | ||
| 86 | #define EFSW_OS EFSW_OS_SOLARIS | ||
| 87 | #elif defined( __HAIKU__ ) || defined( __BEOS__ ) | ||
| 88 | #define EFSW_OS EFSW_OS_HAIKU | ||
| 89 | #endif | ||
| 90 | |||
| 91 | /// Everything else | ||
| 92 | #define EFSW_PLATFORM EFSW_PLATFORM_GENERIC | ||
| 93 | #endif | ||
| 94 | |||
| 95 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
| 96 | #define EFSW_PLATFORM_POSIX | ||
| 97 | #endif | ||
| 98 | |||
| 99 | #if 1 == SOPHIST_pointer64 | ||
| 100 | #define EFSW_64BIT | ||
| 101 | #else | ||
| 102 | #define EFSW_32BIT | ||
| 103 | #endif | ||
| 104 | |||
| 105 | #if defined( arm ) || defined( __arm__ ) | ||
| 106 | #define EFSW_ARM | ||
| 107 | #endif | ||
| 108 | |||
| 109 | #define efCOMMA , | ||
| 110 | |||
| 111 | #define efSAFE_DELETE( p ) \ | ||
| 112 | { \ | ||
| 113 | if ( p ) { \ | ||
| 114 | delete ( p ); \ | ||
| 115 | ( p ) = NULL; \ | ||
| 116 | } \ | ||
| 117 | } | ||
| 118 | #define efSAFE_DELETE_ARRAY( p ) \ | ||
| 119 | { \ | ||
| 120 | if ( p ) { \ | ||
| 121 | delete[] ( p ); \ | ||
| 122 | ( p ) = NULL; \ | ||
| 123 | } \ | ||
| 124 | } | ||
| 125 | #define efARRAY_SIZE( __array ) ( sizeof( __array ) / sizeof( __array[0] ) ) | ||
| 126 | |||
| 127 | } // namespace efsw | ||
| 128 | |||
| 129 | #endif | ||
diff --git a/src/3rdParty/efsw/efsw.h b/src/3rdParty/efsw/efsw.h new file mode 100755 index 0000000..28e63e2 --- /dev/null +++ b/src/3rdParty/efsw/efsw.h | |||
| @@ -0,0 +1,151 @@ | |||
| 1 | /** | ||
| 2 | @author Sepul Sepehr Taghdisian | ||
| 3 | |||
| 4 | Copyright (c) 2013 Martin Lucas Golini | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in | ||
| 14 | all copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | THE SOFTWARE. | ||
| 23 | |||
| 24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) | ||
| 25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. | ||
| 26 | */ | ||
| 27 | /** This is the C API wrapper of EFSW */ | ||
| 28 | #ifndef ESFW_H | ||
| 29 | #define ESFW_H | ||
| 30 | |||
| 31 | #ifdef __cplusplus | ||
| 32 | extern "C" { | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #if defined(_WIN32) | ||
| 36 | #ifdef EFSW_DYNAMIC | ||
| 37 | // Windows platforms | ||
| 38 | #ifdef EFSW_EXPORTS | ||
| 39 | // From DLL side, we must export | ||
| 40 | #define EFSW_API __declspec(dllexport) | ||
| 41 | #else | ||
| 42 | // From client application side, we must import | ||
| 43 | #define EFSW_API __declspec(dllimport) | ||
| 44 | #endif | ||
| 45 | #else | ||
| 46 | // No specific directive needed for static build | ||
| 47 | #ifndef EFSW_API | ||
| 48 | #define EFSW_API | ||
| 49 | #endif | ||
| 50 | #endif | ||
| 51 | #else | ||
| 52 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | ||
| 53 | #define EFSW_API __attribute__ ((visibility("default"))) | ||
| 54 | #endif | ||
| 55 | |||
| 56 | // Other platforms don't need to define anything | ||
| 57 | #ifndef EFSW_API | ||
| 58 | #define EFSW_API | ||
| 59 | #endif | ||
| 60 | #endif | ||
| 61 | |||
| 62 | /// Type for a watch id | ||
| 63 | typedef long efsw_watchid; | ||
| 64 | |||
| 65 | /// Type for watcher | ||
| 66 | typedef void* efsw_watcher; | ||
| 67 | |||
| 68 | enum efsw_action | ||
| 69 | { | ||
| 70 | EFSW_ADD = 1, /// Sent when a file is created or renamed | ||
| 71 | EFSW_DELETE = 2, /// Sent when a file is deleted or renamed | ||
| 72 | EFSW_MODIFIED = 3, /// Sent when a file is modified | ||
| 73 | EFSW_MOVED = 4 /// Sent when a file is moved | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum efsw_error | ||
| 77 | { | ||
| 78 | EFSW_NOTFOUND = -1, | ||
| 79 | EFSW_REPEATED = -2, | ||
| 80 | EFSW_OUTOFSCOPE = -3, | ||
| 81 | EFSW_NOTREADABLE = -4, | ||
| 82 | EFSW_REMOTE = -5, | ||
| 83 | EFSW_UNSPECIFIED = -6 | ||
| 84 | }; | ||
| 85 | |||
| 86 | /// Basic interface for listening for file events. | ||
| 87 | typedef void (*efsw_pfn_fileaction_callback) ( | ||
| 88 | efsw_watcher watcher, | ||
| 89 | efsw_watchid watchid, | ||
| 90 | const char* dir, | ||
| 91 | const char* filename, | ||
| 92 | enum efsw_action action, | ||
| 93 | const char* old_filename, | ||
| 94 | void* param | ||
| 95 | ); | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Creates a new file-watcher | ||
| 99 | * @param generic_mode Force the use of the Generic file watcher | ||
| 100 | */ | ||
| 101 | efsw_watcher EFSW_API efsw_create(int generic_mode); | ||
| 102 | |||
| 103 | /// Release the file-watcher and unwatch any directories | ||
| 104 | void EFSW_API efsw_release(efsw_watcher watcher); | ||
| 105 | |||
| 106 | /// Retreive last error occured by file-watcher | ||
| 107 | EFSW_API const char* efsw_getlasterror(); | ||
| 108 | |||
| 109 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | ||
| 110 | /// For backwards compatibility. | ||
| 111 | /// On error returns WatchID with Error type. | ||
| 112 | efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory, | ||
| 113 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param); | ||
| 114 | |||
| 115 | /// Remove a directory watch. This is a brute force search O(nlogn). | ||
| 116 | void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory); | ||
| 117 | |||
| 118 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 119 | void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid); | ||
| 120 | |||
| 121 | /// Starts watching ( in other thread ) | ||
| 122 | void EFSW_API efsw_watch(efsw_watcher watcher); | ||
| 123 | |||
| 124 | /** | ||
| 125 | * Allow recursive watchers to follow symbolic links to other directories | ||
| 126 | * followSymlinks is disabled by default | ||
| 127 | */ | ||
| 128 | void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable); | ||
| 129 | |||
| 130 | /** @return If can follow symbolic links to directorioes */ | ||
| 131 | int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher); | ||
| 132 | |||
| 133 | /** | ||
| 134 | * When enable this it will allow symlinks to watch recursively out of the pointed directory. | ||
| 135 | * follorSymlinks must be enabled to this work. | ||
| 136 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, | ||
| 137 | * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. | ||
| 138 | * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). | ||
| 139 | * Buy enabling out of scope links, it will allow this behavior. | ||
| 140 | * allowOutOfScopeLinks are disabled by default. | ||
| 141 | */ | ||
| 142 | void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow); | ||
| 143 | |||
| 144 | /// @return Returns if out of scope links are allowed | ||
| 145 | int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher); | ||
| 146 | |||
| 147 | #ifdef __cplusplus | ||
| 148 | } | ||
| 149 | #endif | ||
| 150 | |||
| 151 | #endif | ||
diff --git a/src/3rdParty/efsw/efsw.hpp b/src/3rdParty/efsw/efsw.hpp new file mode 100755 index 0000000..12af116 --- /dev/null +++ b/src/3rdParty/efsw/efsw.hpp | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | /** | ||
| 2 | @author MartÃn Lucas Golini | ||
| 3 | |||
| 4 | Copyright (c) 2013 MartÃn Lucas Golini | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in | ||
| 14 | all copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | THE SOFTWARE. | ||
| 23 | |||
| 24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) | ||
| 25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #ifndef ESFW_HPP | ||
| 29 | #define ESFW_HPP | ||
| 30 | |||
| 31 | #include <list> | ||
| 32 | #include <string> | ||
| 33 | |||
| 34 | #if defined( _WIN32 ) | ||
| 35 | #ifdef EFSW_DYNAMIC | ||
| 36 | // Windows platforms | ||
| 37 | #ifdef EFSW_EXPORTS | ||
| 38 | // From DLL side, we must export | ||
| 39 | #define EFSW_API __declspec( dllexport ) | ||
| 40 | #else | ||
| 41 | // From client application side, we must import | ||
| 42 | #define EFSW_API __declspec( dllimport ) | ||
| 43 | #endif | ||
| 44 | #else | ||
| 45 | // No specific directive needed for static build | ||
| 46 | #ifndef EFSW_API | ||
| 47 | #define EFSW_API | ||
| 48 | #endif | ||
| 49 | #endif | ||
| 50 | #else | ||
| 51 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | ||
| 52 | #ifndef EFSW_API | ||
| 53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) | ||
| 54 | #endif | ||
| 55 | #endif | ||
| 56 | |||
| 57 | // Other platforms don't need to define anything | ||
| 58 | #ifndef EFSW_API | ||
| 59 | #define EFSW_API | ||
| 60 | #endif | ||
| 61 | #endif | ||
| 62 | |||
| 63 | namespace efsw { | ||
| 64 | |||
| 65 | /// Type for a watch id | ||
| 66 | typedef long WatchID; | ||
| 67 | |||
| 68 | // forward declarations | ||
| 69 | class FileWatcherImpl; | ||
| 70 | class FileWatchListener; | ||
| 71 | |||
| 72 | /// Actions to listen for. Rename will send two events, one for | ||
| 73 | /// the deletion of the old file, and one for the creation of the | ||
| 74 | /// new file. | ||
| 75 | namespace Actions { | ||
| 76 | enum Action { | ||
| 77 | /// Sent when a file is created or renamed | ||
| 78 | Add = 1, | ||
| 79 | /// Sent when a file is deleted or renamed | ||
| 80 | Delete = 2, | ||
| 81 | /// Sent when a file is modified | ||
| 82 | Modified = 3, | ||
| 83 | /// Sent when a file is moved | ||
| 84 | Moved = 4 | ||
| 85 | }; | ||
| 86 | } | ||
| 87 | typedef Actions::Action Action; | ||
| 88 | |||
| 89 | /// Errors log namespace | ||
| 90 | namespace Errors { | ||
| 91 | |||
| 92 | enum Error { | ||
| 93 | FileNotFound = -1, | ||
| 94 | FileRepeated = -2, | ||
| 95 | FileOutOfScope = -3, | ||
| 96 | FileNotReadable = -4, | ||
| 97 | FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to | ||
| 98 | watch this directory ). */ | ||
| 99 | Unspecified = -6 | ||
| 100 | }; | ||
| 101 | |||
| 102 | class EFSW_API Log { | ||
| 103 | public: | ||
| 104 | /// @return The last error logged | ||
| 105 | static std::string getLastErrorLog(); | ||
| 106 | |||
| 107 | /// Creates an error of the type specified | ||
| 108 | static Error createLastError( Error err, std::string log ); | ||
| 109 | }; | ||
| 110 | |||
| 111 | } // namespace Errors | ||
| 112 | typedef Errors::Error Error; | ||
| 113 | |||
| 114 | /// Listens to files and directories and dispatches events | ||
| 115 | /// to notify the listener of files and directories changes. | ||
| 116 | /// @class FileWatcher | ||
| 117 | class EFSW_API FileWatcher { | ||
| 118 | public: | ||
| 119 | /// Default constructor, will use the default platform file watcher | ||
| 120 | FileWatcher(); | ||
| 121 | |||
| 122 | /// Constructor that lets you force the use of the Generic File Watcher | ||
| 123 | explicit FileWatcher( bool useGenericFileWatcher ); | ||
| 124 | |||
| 125 | virtual ~FileWatcher(); | ||
| 126 | |||
| 127 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | ||
| 128 | /// For backwards compatibility. | ||
| 129 | /// On error returns WatchID with Error type. | ||
| 130 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); | ||
| 131 | |||
| 132 | /// Add a directory watch | ||
| 133 | /// On error returns WatchID with Error type. | ||
| 134 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | ||
| 135 | |||
| 136 | /// Remove a directory watch. This is a brute force search O(nlogn). | ||
| 137 | void removeWatch( const std::string& directory ); | ||
| 138 | |||
| 139 | /// Remove a directory watch. This is a map lookup O(logn). | ||
| 140 | void removeWatch( WatchID watchid ); | ||
| 141 | |||
| 142 | /// Starts watching ( in other thread ) | ||
| 143 | void watch(); | ||
| 144 | |||
| 145 | /// @return Returns a list of the directories that are being watched | ||
| 146 | std::list<std::string> directories(); | ||
| 147 | |||
| 148 | /** Allow recursive watchers to follow symbolic links to other directories | ||
| 149 | * followSymlinks is disabled by default | ||
| 150 | */ | ||
| 151 | void followSymlinks( bool follow ); | ||
| 152 | |||
| 153 | /** @return If can follow symbolic links to directorioes */ | ||
| 154 | const bool& followSymlinks() const; | ||
| 155 | |||
| 156 | /** When enable this it will allow symlinks to watch recursively out of the pointed directory. | ||
| 157 | * follorSymlinks must be enabled to this work. | ||
| 158 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is | ||
| 159 | * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid | ||
| 160 | * great levels of recursion. Enabling this could lead in infinite recursion, and crash the | ||
| 161 | * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow | ||
| 162 | * this behavior. allowOutOfScopeLinks are disabled by default. | ||
| 163 | */ | ||
| 164 | void allowOutOfScopeLinks( bool allow ); | ||
| 165 | |||
| 166 | /// @return Returns if out of scope links are allowed | ||
| 167 | const bool& allowOutOfScopeLinks() const; | ||
| 168 | |||
| 169 | private: | ||
| 170 | /// The implementation | ||
| 171 | FileWatcherImpl* mImpl; | ||
| 172 | bool mFollowSymlinks; | ||
| 173 | bool mOutOfScopeLinks; | ||
| 174 | }; | ||
| 175 | |||
| 176 | /// Basic interface for listening for file events. | ||
| 177 | /// @class FileWatchListener | ||
| 178 | class FileWatchListener { | ||
| 179 | public: | ||
| 180 | virtual ~FileWatchListener() {} | ||
| 181 | |||
| 182 | /// Handles the action file action | ||
| 183 | /// @param watchid The watch id for the directory | ||
| 184 | /// @param dir The directory | ||
| 185 | /// @param filename The filename that was accessed (not full path) | ||
| 186 | /// @param action Action that was performed | ||
| 187 | /// @param oldFilename The name of the file or directory moved | ||
| 188 | virtual void handleFileAction( WatchID watchid, const std::string& dir, | ||
| 189 | const std::string& filename, Action action, | ||
| 190 | std::string oldFilename = "" ) = 0; | ||
| 191 | }; | ||
| 192 | |||
| 193 | } // namespace efsw | ||
| 194 | |||
| 195 | #endif | ||
diff --git a/src/3rdParty/efsw/inotify-nosys.h b/src/3rdParty/efsw/inotify-nosys.h new file mode 100755 index 0000000..be1e627 --- /dev/null +++ b/src/3rdParty/efsw/inotify-nosys.h | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | #ifndef _LINUX_INOTIFY_H | ||
| 2 | #define _LINUX_INOTIFY_H | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <sys/syscall.h> | ||
| 6 | #include <unistd.h> | ||
| 7 | |||
| 8 | /* | ||
| 9 | * struct inotify_event - structure read from the inotify device for each event | ||
| 10 | * | ||
| 11 | * When you are watching a directory, you will receive the filename for events | ||
| 12 | * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd. | ||
| 13 | */ | ||
| 14 | struct inotify_event { | ||
| 15 | int wd; /* watch descriptor */ | ||
| 16 | uint32_t mask; /* watch mask */ | ||
| 17 | uint32_t cookie; /* cookie to synchronize two events */ | ||
| 18 | uint32_t len; /* length (including nulls) of name */ | ||
| 19 | char name __flexarr; /* stub for possible name */ | ||
| 20 | }; | ||
| 21 | |||
| 22 | /* the following are legal, implemented events that user-space can watch for */ | ||
| 23 | #define IN_ACCESS 0x00000001 /* File was accessed */ | ||
| 24 | #define IN_MODIFY 0x00000002 /* File was modified */ | ||
| 25 | #define IN_ATTRIB 0x00000004 /* Metadata changed */ | ||
| 26 | #define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ | ||
| 27 | #define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ | ||
| 28 | #define IN_OPEN 0x00000020 /* File was opened */ | ||
| 29 | #define IN_MOVED_FROM 0x00000040 /* File was moved from X */ | ||
| 30 | #define IN_MOVED_TO 0x00000080 /* File was moved to Y */ | ||
| 31 | #define IN_CREATE 0x00000100 /* Subfile was created */ | ||
| 32 | #define IN_DELETE 0x00000200 /* Subfile was deleted */ | ||
| 33 | #define IN_DELETE_SELF 0x00000400 /* Self was deleted */ | ||
| 34 | #define IN_MOVE_SELF 0x00000800 /* Self was moved */ | ||
| 35 | |||
| 36 | /* the following are legal events. they are sent as needed to any watch */ | ||
| 37 | #define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */ | ||
| 38 | #define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ | ||
| 39 | #define IN_IGNORED 0x00008000 /* File was ignored */ | ||
| 40 | |||
| 41 | /* helper events */ | ||
| 42 | #define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */ | ||
| 43 | #define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */ | ||
| 44 | |||
| 45 | /* special flags */ | ||
| 46 | #define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */ | ||
| 47 | #define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */ | ||
| 48 | #define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */ | ||
| 49 | #define IN_ISDIR 0x40000000 /* event occurred against dir */ | ||
| 50 | #define IN_ONESHOT 0x80000000 /* only send event once */ | ||
| 51 | |||
| 52 | /* | ||
| 53 | * All of the events - we build the list by hand so that we can add flags in | ||
| 54 | * the future and not break backward compatibility. Apps will get only the | ||
| 55 | * events that they originally wanted. Be sure to add new events here! | ||
| 56 | */ | ||
| 57 | #define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \ | ||
| 58 | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \ | ||
| 59 | IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \ | ||
| 60 | IN_MOVE_SELF) | ||
| 61 | |||
| 62 | #if defined (__alpha__) | ||
| 63 | # define __NR_inotify_init 444 | ||
| 64 | # define __NR_inotify_add_watch 445 | ||
| 65 | # define __NR_inotify_rm_watch 446 | ||
| 66 | |||
| 67 | #elif defined (__arm__) | ||
| 68 | # define __NR_inotify_init (__NR_SYSCALL_BASE+316) | ||
| 69 | # define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317) | ||
| 70 | # define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318) | ||
| 71 | |||
| 72 | #elif defined (__aarch64__) | ||
| 73 | # define __NR_inotify_init 1043 | ||
| 74 | # define __NR_inotify_add_watch 27 | ||
| 75 | # define __NR_inotify_rm_watch 28 | ||
| 76 | |||
| 77 | #elif defined (__frv__) | ||
| 78 | # define __NR_inotify_init 291 | ||
| 79 | # define __NR_inotify_add_watch 292 | ||
| 80 | # define __NR_inotify_rm_watch 293 | ||
| 81 | |||
| 82 | #elif defined(__i386__) | ||
| 83 | # define __NR_inotify_init 291 | ||
| 84 | # define __NR_inotify_add_watch 292 | ||
| 85 | # define __NR_inotify_rm_watch 293 | ||
| 86 | |||
| 87 | #elif defined (__ia64__) | ||
| 88 | # define __NR_inotify_init 1277 | ||
| 89 | # define __NR_inotify_add_watch 1278 | ||
| 90 | # define __NR_inotify_rm_watch 1279 | ||
| 91 | |||
| 92 | #elif defined (__mips__) | ||
| 93 | # if _MIPS_SIM == _MIPS_SIM_ABI32 | ||
| 94 | # define __NR_inotify_init (__NR_Linux + 284) | ||
| 95 | # define __NR_inotify_add_watch (__NR_Linux + 285) | ||
| 96 | # define __NR_inotify_rm_watch (__NR_Linux + 286) | ||
| 97 | # endif | ||
| 98 | # if _MIPS_SIM == _MIPS_SIM_ABI64 | ||
| 99 | # define __NR_inotify_init (__NR_Linux + 243) | ||
| 100 | # define __NR_inotify_add_watch (__NR_Linux + 243) | ||
| 101 | # define __NR_inotify_rm_watch (__NR_Linux + 243) | ||
| 102 | # endif | ||
| 103 | # if _MIPS_SIM == _MIPS_SIM_NABI32 | ||
| 104 | # define __NR_inotify_init (__NR_Linux + 247) | ||
| 105 | # define __NR_inotify_add_watch (__NR_Linux + 248) | ||
| 106 | # define __NR_inotify_rm_watch (__NR_Linux + 249) | ||
| 107 | # endif | ||
| 108 | |||
| 109 | #elif defined(__parisc__) | ||
| 110 | # define __NR_inotify_init (__NR_Linux + 269) | ||
| 111 | # define __NR_inotify_add_watch (__NR_Linux + 270) | ||
| 112 | # define __NR_inotify_rm_watch (__NR_Linux + 271) | ||
| 113 | |||
| 114 | #elif defined(__powerpc__) || defined(__powerpc64__) | ||
| 115 | # define __NR_inotify_init 275 | ||
| 116 | # define __NR_inotify_add_watch 276 | ||
| 117 | # define __NR_inotify_rm_watch 277 | ||
| 118 | |||
| 119 | #elif defined (__s390__) | ||
| 120 | # define __NR_inotify_init 284 | ||
| 121 | # define __NR_inotify_add_watch 285 | ||
| 122 | # define __NR_inotify_rm_watch 286 | ||
| 123 | |||
| 124 | #elif defined (__sh__) | ||
| 125 | # define __NR_inotify_init 290 | ||
| 126 | # define __NR_inotify_add_watch 291 | ||
| 127 | # define __NR_inotify_rm_watch 292 | ||
| 128 | |||
| 129 | #elif defined (__sh64__) | ||
| 130 | # define __NR_inotify_init 318 | ||
| 131 | # define __NR_inotify_add_watch 319 | ||
| 132 | # define __NR_inotify_rm_watch 320 | ||
| 133 | |||
| 134 | #elif defined (__sparc__) || defined (__sparc64__) | ||
| 135 | # define __NR_inotify_init 151 | ||
| 136 | # define __NR_inotify_add_watch 152 | ||
| 137 | # define __NR_inotify_rm_watch 156 | ||
| 138 | |||
| 139 | #elif defined(__x86_64__) | ||
| 140 | # define __NR_inotify_init 253 | ||
| 141 | # define __NR_inotify_add_watch 254 | ||
| 142 | # define __NR_inotify_rm_watch 255 | ||
| 143 | |||
| 144 | #else | ||
| 145 | # error "Unsupported architecture!" | ||
| 146 | #endif | ||
| 147 | |||
| 148 | static inline int inotify_init (void) | ||
| 149 | { | ||
| 150 | return syscall (__NR_inotify_init); | ||
| 151 | } | ||
| 152 | |||
| 153 | static inline int inotify_add_watch (int fd, const char *name, uint32_t mask) | ||
| 154 | { | ||
| 155 | return syscall (__NR_inotify_add_watch, fd, name, mask); | ||
| 156 | } | ||
| 157 | |||
| 158 | static inline int inotify_rm_watch (int fd, uint32_t wd) | ||
| 159 | { | ||
| 160 | return syscall (__NR_inotify_rm_watch, fd, wd); | ||
| 161 | } | ||
| 162 | |||
| 163 | |||
| 164 | #endif /* _LINUX_INOTIFY_H */ | ||
diff --git a/src/3rdParty/efsw/platform/platformimpl.hpp b/src/3rdParty/efsw/platform/platformimpl.hpp new file mode 100755 index 0000000..5442580 --- /dev/null +++ b/src/3rdParty/efsw/platform/platformimpl.hpp | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef EFSW_PLATFORMIMPL_HPP | ||
| 2 | #define EFSW_PLATFORMIMPL_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 7 | #include <efsw/platform/posix/ThreadImpl.hpp> | ||
| 8 | #include <efsw/platform/posix/MutexImpl.hpp> | ||
| 9 | #include <efsw/platform/posix/SystemImpl.hpp> | ||
| 10 | #include <efsw/platform/posix/FileSystemImpl.hpp> | ||
| 11 | #elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 12 | #include <efsw/platform/win/ThreadImpl.hpp> | ||
| 13 | #include <efsw/platform/win/MutexImpl.hpp> | ||
| 14 | #include <efsw/platform/win/SystemImpl.hpp> | ||
| 15 | #include <efsw/platform/win/FileSystemImpl.hpp> | ||
| 16 | #else | ||
| 17 | #error Thread, Mutex, and System not implemented for this platform. | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp new file mode 100755 index 0000000..92eeb47 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | #include <efsw/platform/posix/FileSystemImpl.hpp> | ||
| 2 | |||
| 3 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <dirent.h> | ||
| 7 | #include <efsw/FileInfo.hpp> | ||
| 8 | #include <efsw/FileSystem.hpp> | ||
| 9 | #include <unistd.h> | ||
| 10 | |||
| 11 | #ifndef _DARWIN_FEATURE_64_BIT_INODE | ||
| 12 | #define _DARWIN_FEATURE_64_BIT_INODE | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #ifndef _FILE_OFFSET_BITS | ||
| 16 | #define _FILE_OFFSET_BITS 64 | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include <climits> | ||
| 20 | #include <cstdlib> | ||
| 21 | #include <sys/stat.h> | ||
| 22 | |||
| 23 | #if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID | ||
| 24 | #include <sys/vfs.h> | ||
| 25 | #elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS | ||
| 26 | #include <sys/mount.h> | ||
| 27 | #include <sys/param.h> | ||
| 28 | #endif | ||
| 29 | |||
| 30 | /** Remote file systems codes */ | ||
| 31 | #define S_MAGIC_AFS 0x5346414F | ||
| 32 | #define S_MAGIC_AUFS 0x61756673 | ||
| 33 | #define S_MAGIC_CEPH 0x00C36400 | ||
| 34 | #define S_MAGIC_CIFS 0xFF534D42 | ||
| 35 | #define S_MAGIC_CODA 0x73757245 | ||
| 36 | #define S_MAGIC_FHGFS 0x19830326 | ||
| 37 | #define S_MAGIC_FUSEBLK 0x65735546 | ||
| 38 | #define S_MAGIC_FUSECTL 0x65735543 | ||
| 39 | #define S_MAGIC_GFS 0x01161970 | ||
| 40 | #define S_MAGIC_GPFS 0x47504653 | ||
| 41 | #define S_MAGIC_KAFS 0x6B414653 | ||
| 42 | #define S_MAGIC_LUSTRE 0x0BD00BD0 | ||
| 43 | #define S_MAGIC_NCP 0x564C | ||
| 44 | #define S_MAGIC_NFS 0x6969 | ||
| 45 | #define S_MAGIC_NFSD 0x6E667364 | ||
| 46 | #define S_MAGIC_OCFS2 0x7461636F | ||
| 47 | #define S_MAGIC_PANFS 0xAAD7AAEA | ||
| 48 | #define S_MAGIC_PIPEFS 0x50495045 | ||
| 49 | #define S_MAGIC_SMB 0x517B | ||
| 50 | #define S_MAGIC_SNFS 0xBEEFDEAD | ||
| 51 | #define S_MAGIC_VMHGFS 0xBACBACBC | ||
| 52 | #define S_MAGIC_VXFS 0xA501FCF5 | ||
| 53 | |||
| 54 | #if EFSW_OS == EFSW_OS_LINUX | ||
| 55 | #include <cstdio> | ||
| 56 | #include <mntent.h> | ||
| 57 | #endif | ||
| 58 | |||
| 59 | namespace efsw { namespace Platform { | ||
| 60 | |||
| 61 | #if EFSW_OS == EFSW_OS_LINUX | ||
| 62 | |||
| 63 | std::string findMountPoint( std::string file ) { | ||
| 64 | std::string cwd = FileSystem::getCurrentWorkingDirectory(); | ||
| 65 | struct stat last_stat; | ||
| 66 | struct stat file_stat; | ||
| 67 | |||
| 68 | stat( file.c_str(), &file_stat ); | ||
| 69 | |||
| 70 | std::string mp; | ||
| 71 | |||
| 72 | if ( efsw::FileSystem::isDirectory( file ) ) { | ||
| 73 | last_stat = file_stat; | ||
| 74 | |||
| 75 | if ( !FileSystem::changeWorkingDirectory( file ) ) | ||
| 76 | return ""; | ||
| 77 | } else { | ||
| 78 | std::string dir = efsw::FileSystem::pathRemoveFileName( file ); | ||
| 79 | |||
| 80 | if ( !FileSystem::changeWorkingDirectory( dir ) ) | ||
| 81 | return ""; | ||
| 82 | |||
| 83 | if ( stat( ".", &last_stat ) < 0 ) | ||
| 84 | return ""; | ||
| 85 | } | ||
| 86 | |||
| 87 | while ( true ) { | ||
| 88 | struct stat st; | ||
| 89 | |||
| 90 | if ( stat( "..", &st ) < 0 ) | ||
| 91 | goto done; | ||
| 92 | |||
| 93 | if ( st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino ) | ||
| 94 | break; | ||
| 95 | |||
| 96 | if ( !FileSystem::changeWorkingDirectory( ".." ) ) { | ||
| 97 | goto done; | ||
| 98 | } | ||
| 99 | |||
| 100 | last_stat = st; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* Finally reached a mount point, see what it's called. */ | ||
| 104 | mp = FileSystem::getCurrentWorkingDirectory(); | ||
| 105 | |||
| 106 | done: | ||
| 107 | FileSystem::changeWorkingDirectory( cwd ); | ||
| 108 | |||
| 109 | return mp; | ||
| 110 | } | ||
| 111 | |||
| 112 | std::string findDevicePath( const std::string& directory ) { | ||
| 113 | struct mntent* ent; | ||
| 114 | FILE* aFile; | ||
| 115 | |||
| 116 | aFile = setmntent( "/proc/mounts", "r" ); | ||
| 117 | |||
| 118 | if ( aFile == NULL ) | ||
| 119 | return ""; | ||
| 120 | |||
| 121 | while ( NULL != ( ent = getmntent( aFile ) ) ) { | ||
| 122 | std::string dirName( ent->mnt_dir ); | ||
| 123 | |||
| 124 | if ( dirName == directory ) { | ||
| 125 | std::string fsName( ent->mnt_fsname ); | ||
| 126 | |||
| 127 | endmntent( aFile ); | ||
| 128 | |||
| 129 | return fsName; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | endmntent( aFile ); | ||
| 134 | |||
| 135 | return ""; | ||
| 136 | } | ||
| 137 | |||
| 138 | bool isLocalFUSEDirectory( std::string directory ) { | ||
| 139 | efsw::FileSystem::dirRemoveSlashAtEnd( directory ); | ||
| 140 | |||
| 141 | directory = findMountPoint( directory ); | ||
| 142 | |||
| 143 | if ( !directory.empty() ) { | ||
| 144 | std::string devicePath = findDevicePath( directory ); | ||
| 145 | |||
| 146 | return !devicePath.empty(); | ||
| 147 | } | ||
| 148 | |||
| 149 | return false; | ||
| 150 | } | ||
| 151 | |||
| 152 | #endif | ||
| 153 | |||
| 154 | bool FileSystem::changeWorkingDirectory( const std::string& path ) { | ||
| 155 | return -1 != chdir( path.c_str() ); | ||
| 156 | } | ||
| 157 | |||
| 158 | std::string FileSystem::getCurrentWorkingDirectory() { | ||
| 159 | char dir[PATH_MAX + 1]; | ||
| 160 | char* result = getcwd( dir, PATH_MAX + 1 ); | ||
| 161 | return result != NULL ? std::string( result ) : std::string(); | ||
| 162 | } | ||
| 163 | |||
| 164 | FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) { | ||
| 165 | FileInfoMap files; | ||
| 166 | |||
| 167 | DIR* dp; | ||
| 168 | struct dirent* dirp; | ||
| 169 | |||
| 170 | if ( ( dp = opendir( path.c_str() ) ) == NULL ) | ||
| 171 | return files; | ||
| 172 | |||
| 173 | while ( ( dirp = readdir( dp ) ) != NULL ) { | ||
| 174 | if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) { | ||
| 175 | std::string name( dirp->d_name ); | ||
| 176 | std::string fpath( path + name ); | ||
| 177 | |||
| 178 | files[name] = FileInfo( fpath ); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | closedir( dp ); | ||
| 183 | |||
| 184 | return files; | ||
| 185 | } | ||
| 186 | |||
| 187 | char FileSystem::getOSSlash() { | ||
| 188 | return '/'; | ||
| 189 | } | ||
| 190 | |||
| 191 | bool FileSystem::isDirectory( const std::string& path ) { | ||
| 192 | struct stat st; | ||
| 193 | int res = stat( path.c_str(), &st ); | ||
| 194 | |||
| 195 | if ( 0 == res ) { | ||
| 196 | return static_cast<bool>( S_ISDIR( st.st_mode ) ); | ||
| 197 | } | ||
| 198 | |||
| 199 | return false; | ||
| 200 | } | ||
| 201 | |||
| 202 | bool FileSystem::isRemoteFS( const std::string& directory ) { | ||
| 203 | #if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || \ | ||
| 204 | EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS | ||
| 205 | struct statfs statfsbuf; | ||
| 206 | |||
| 207 | statfs( directory.c_str(), &statfsbuf ); | ||
| 208 | |||
| 209 | switch ( statfsbuf.f_type | 0UL ) { | ||
| 210 | case S_MAGIC_FUSEBLK: /* 0x65735546 remote */ | ||
| 211 | { | ||
| 212 | #if EFSW_OS == EFSW_OS_LINUX | ||
| 213 | return !isLocalFUSEDirectory( directory ); | ||
| 214 | #endif | ||
| 215 | } | ||
| 216 | case S_MAGIC_AFS: /* 0x5346414F remote */ | ||
| 217 | case S_MAGIC_AUFS: /* 0x61756673 remote */ | ||
| 218 | case S_MAGIC_CEPH: /* 0x00C36400 remote */ | ||
| 219 | case S_MAGIC_CIFS: /* 0xFF534D42 remote */ | ||
| 220 | case S_MAGIC_CODA: /* 0x73757245 remote */ | ||
| 221 | case S_MAGIC_FHGFS: /* 0x19830326 remote */ | ||
| 222 | case S_MAGIC_FUSECTL: /* 0x65735543 remote */ | ||
| 223 | case S_MAGIC_GFS: /* 0x01161970 remote */ | ||
| 224 | case S_MAGIC_GPFS: /* 0x47504653 remote */ | ||
| 225 | case S_MAGIC_KAFS: /* 0x6B414653 remote */ | ||
| 226 | case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */ | ||
| 227 | case S_MAGIC_NCP: /* 0x564C remote */ | ||
| 228 | case S_MAGIC_NFS: /* 0x6969 remote */ | ||
| 229 | case S_MAGIC_NFSD: /* 0x6E667364 remote */ | ||
| 230 | case S_MAGIC_OCFS2: /* 0x7461636F remote */ | ||
| 231 | case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */ | ||
| 232 | case S_MAGIC_PIPEFS: /* 0x50495045 remote */ | ||
| 233 | case S_MAGIC_SMB: /* 0x517B remote */ | ||
| 234 | case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */ | ||
| 235 | case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */ | ||
| 236 | case S_MAGIC_VXFS: /* 0xA501FCF5 remote */ | ||
| 237 | { | ||
| 238 | return true; | ||
| 239 | } | ||
| 240 | default: { | ||
| 241 | return false; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | #endif | ||
| 245 | |||
| 246 | return false; | ||
| 247 | } | ||
| 248 | |||
| 249 | }} // namespace efsw::Platform | ||
| 250 | |||
| 251 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp new file mode 100755 index 0000000..0bfba76 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP | ||
| 2 | #define EFSW_FILESYSTEMIMPLPOSIX_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileInfo.hpp> | ||
| 5 | #include <efsw/base.hpp> | ||
| 6 | |||
| 7 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 8 | |||
| 9 | namespace efsw { namespace Platform { | ||
| 10 | |||
| 11 | class FileSystem { | ||
| 12 | public: | ||
| 13 | static FileInfoMap filesInfoFromPath( const std::string& path ); | ||
| 14 | |||
| 15 | static char getOSSlash(); | ||
| 16 | |||
| 17 | static bool isDirectory( const std::string& path ); | ||
| 18 | |||
| 19 | static bool isRemoteFS( const std::string& directory ); | ||
| 20 | |||
| 21 | static bool changeWorkingDirectory( const std::string& path ); | ||
| 22 | |||
| 23 | static std::string getCurrentWorkingDirectory(); | ||
| 24 | }; | ||
| 25 | |||
| 26 | }} // namespace efsw::Platform | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp new file mode 100755 index 0000000..2233798 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #include <efsw/platform/posix/MutexImpl.hpp> | ||
| 2 | |||
| 3 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 4 | |||
| 5 | namespace efsw { namespace Platform { | ||
| 6 | |||
| 7 | MutexImpl::MutexImpl() { | ||
| 8 | pthread_mutexattr_t attributes; | ||
| 9 | pthread_mutexattr_init( &attributes ); | ||
| 10 | pthread_mutexattr_settype( &attributes, PTHREAD_MUTEX_RECURSIVE ); | ||
| 11 | pthread_mutex_init( &mMutex, &attributes ); | ||
| 12 | } | ||
| 13 | |||
| 14 | MutexImpl::~MutexImpl() { | ||
| 15 | pthread_mutex_destroy( &mMutex ); | ||
| 16 | } | ||
| 17 | |||
| 18 | void MutexImpl::lock() { | ||
| 19 | pthread_mutex_lock( &mMutex ); | ||
| 20 | } | ||
| 21 | |||
| 22 | void MutexImpl::unlock() { | ||
| 23 | pthread_mutex_unlock( &mMutex ); | ||
| 24 | } | ||
| 25 | |||
| 26 | }} // namespace efsw::Platform | ||
| 27 | |||
| 28 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp new file mode 100755 index 0000000..a33d827 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #ifndef EFSW_MUTEXIMPLPOSIX_HPP | ||
| 2 | #define EFSW_MUTEXIMPLPOSIX_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 7 | |||
| 8 | #include <pthread.h> | ||
| 9 | |||
| 10 | namespace efsw { namespace Platform { | ||
| 11 | |||
| 12 | class MutexImpl { | ||
| 13 | public: | ||
| 14 | MutexImpl(); | ||
| 15 | |||
| 16 | ~MutexImpl(); | ||
| 17 | |||
| 18 | void lock(); | ||
| 19 | |||
| 20 | void unlock(); | ||
| 21 | |||
| 22 | private: | ||
| 23 | pthread_mutex_t mMutex; | ||
| 24 | }; | ||
| 25 | |||
| 26 | }} // namespace efsw::Platform | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp new file mode 100755 index 0000000..37d4120 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | #include <efsw/platform/posix/SystemImpl.hpp> | ||
| 2 | |||
| 3 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 4 | |||
| 5 | #include <cstdio> | ||
| 6 | #include <limits.h> | ||
| 7 | #include <pthread.h> | ||
| 8 | #include <sys/resource.h> | ||
| 9 | #include <sys/time.h> | ||
| 10 | |||
| 11 | #include <efsw/Debug.hpp> | ||
| 12 | #include <efsw/FileSystem.hpp> | ||
| 13 | |||
| 14 | #if EFSW_OS == EFSW_OS_MACOSX | ||
| 15 | #include <CoreFoundation/CoreFoundation.h> | ||
| 16 | #elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID | ||
| 17 | #include <libgen.h> | ||
| 18 | #include <unistd.h> | ||
| 19 | #elif EFSW_OS == EFSW_OS_HAIKU | ||
| 20 | #include <kernel/OS.h> | ||
| 21 | #include <kernel/image.h> | ||
| 22 | #elif EFSW_OS == EFSW_OS_SOLARIS | ||
| 23 | #include <stdlib.h> | ||
| 24 | #elif EFSW_OS == EFSW_OS_BSD | ||
| 25 | #include <sys/sysctl.h> | ||
| 26 | #endif | ||
| 27 | |||
| 28 | namespace efsw { namespace Platform { | ||
| 29 | |||
| 30 | void System::sleep( const unsigned long& ms ) { | ||
| 31 | // usleep( static_cast<unsigned long>( ms * 1000 ) ); | ||
| 32 | |||
| 33 | // usleep is not reliable enough (it might block the | ||
| 34 | // whole process instead of just the current thread) | ||
| 35 | // so we must use pthread_cond_timedwait instead | ||
| 36 | |||
| 37 | // this implementation is inspired from Qt | ||
| 38 | // and taken from SFML | ||
| 39 | |||
| 40 | unsigned long long usecs = ms * 1000; | ||
| 41 | |||
| 42 | // get the current time | ||
| 43 | timeval tv; | ||
| 44 | gettimeofday( &tv, NULL ); | ||
| 45 | |||
| 46 | // construct the time limit (current time + time to wait) | ||
| 47 | timespec ti; | ||
| 48 | ti.tv_nsec = ( tv.tv_usec + ( usecs % 1000000 ) ) * 1000; | ||
| 49 | ti.tv_sec = tv.tv_sec + ( usecs / 1000000 ) + ( ti.tv_nsec / 1000000000 ); | ||
| 50 | ti.tv_nsec %= 1000000000; | ||
| 51 | |||
| 52 | // create a mutex and thread condition | ||
| 53 | pthread_mutex_t mutex; | ||
| 54 | pthread_mutex_init( &mutex, 0 ); | ||
| 55 | pthread_cond_t condition; | ||
| 56 | pthread_cond_init( &condition, 0 ); | ||
| 57 | |||
| 58 | // wait... | ||
| 59 | pthread_mutex_lock( &mutex ); | ||
| 60 | pthread_cond_timedwait( &condition, &mutex, &ti ); | ||
| 61 | pthread_mutex_unlock( &mutex ); | ||
| 62 | |||
| 63 | // destroy the mutex and condition | ||
| 64 | pthread_cond_destroy( &condition ); | ||
| 65 | } | ||
| 66 | |||
| 67 | std::string System::getProcessPath() { | ||
| 68 | #if EFSW_OS == EFSW_OS_MACOSX | ||
| 69 | char exe_file[FILENAME_MAX + 1]; | ||
| 70 | |||
| 71 | CFBundleRef mainBundle = CFBundleGetMainBundle(); | ||
| 72 | |||
| 73 | if ( mainBundle ) { | ||
| 74 | CFURLRef mainURL = CFBundleCopyBundleURL( mainBundle ); | ||
| 75 | |||
| 76 | if ( mainURL ) { | ||
| 77 | int ok = CFURLGetFileSystemRepresentation( mainURL, ( Boolean ) true, (UInt8*)exe_file, | ||
| 78 | FILENAME_MAX ); | ||
| 79 | |||
| 80 | if ( ok ) { | ||
| 81 | return std::string( exe_file ) + "/"; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | return "./"; | ||
| 87 | #elif EFSW_OS == EFSW_OS_LINUX | ||
| 88 | char exe_file[FILENAME_MAX + 1]; | ||
| 89 | |||
| 90 | int size; | ||
| 91 | |||
| 92 | size = readlink( "/proc/self/exe", exe_file, FILENAME_MAX ); | ||
| 93 | |||
| 94 | if ( size < 0 ) { | ||
| 95 | return std::string( "./" ); | ||
| 96 | } else { | ||
| 97 | exe_file[size] = '\0'; | ||
| 98 | return std::string( dirname( exe_file ) ) + "/"; | ||
| 99 | } | ||
| 100 | |||
| 101 | #elif EFSW_OS == EFSW_OS_BSD | ||
| 102 | int mib[4]; | ||
| 103 | mib[0] = CTL_KERN; | ||
| 104 | mib[1] = KERN_PROC; | ||
| 105 | mib[2] = KERN_PROC_PATHNAME; | ||
| 106 | mib[3] = -1; | ||
| 107 | char buf[1024]; | ||
| 108 | size_t cb = sizeof( buf ); | ||
| 109 | sysctl( mib, 4, buf, &cb, NULL, 0 ); | ||
| 110 | |||
| 111 | return FileSystem::pathRemoveFileName( std::string( buf ) ); | ||
| 112 | |||
| 113 | #elif EFSW_OS == EFSW_OS_SOLARIS | ||
| 114 | return FileSystem::pathRemoveFileName( std::string( getexecname() ) ); | ||
| 115 | |||
| 116 | #elif EFSW_OS == EFSW_OS_HAIKU | ||
| 117 | image_info info; | ||
| 118 | int32 cookie = 0; | ||
| 119 | |||
| 120 | while ( B_OK == get_next_image_info( 0, &cookie, &info ) ) { | ||
| 121 | if ( info.type == B_APP_IMAGE ) | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | |||
| 125 | return FileSystem::pathRemoveFileName( std::string( info.name ) ); | ||
| 126 | |||
| 127 | #elif EFSW_OS == EFSW_OS_ANDROID | ||
| 128 | return "/sdcard/"; | ||
| 129 | |||
| 130 | #else | ||
| 131 | #warning getProcessPath() not implemented on this platform. ( will return "./" ) | ||
| 132 | return "./"; | ||
| 133 | |||
| 134 | #endif | ||
| 135 | } | ||
| 136 | |||
| 137 | void System::maxFD() { | ||
| 138 | static bool maxed = false; | ||
| 139 | |||
| 140 | if ( !maxed ) { | ||
| 141 | struct rlimit limit; | ||
| 142 | getrlimit( RLIMIT_NOFILE, &limit ); | ||
| 143 | limit.rlim_cur = limit.rlim_max; | ||
| 144 | setrlimit( RLIMIT_NOFILE, &limit ); | ||
| 145 | |||
| 146 | getrlimit( RLIMIT_NOFILE, &limit ); | ||
| 147 | |||
| 148 | efDEBUG( "File descriptor limit %ld\n", limit.rlim_cur ); | ||
| 149 | |||
| 150 | maxed = true; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | Uint64 System::getMaxFD() { | ||
| 155 | static rlim_t max_fd = 0; | ||
| 156 | |||
| 157 | if ( max_fd == 0 ) { | ||
| 158 | struct rlimit limit; | ||
| 159 | getrlimit( RLIMIT_NOFILE, &limit ); | ||
| 160 | max_fd = limit.rlim_cur; | ||
| 161 | } | ||
| 162 | |||
| 163 | return max_fd; | ||
| 164 | } | ||
| 165 | |||
| 166 | }} // namespace efsw::Platform | ||
| 167 | |||
| 168 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp new file mode 100755 index 0000000..9322b06 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #ifndef EFSW_SYSTEMIMPLPOSIX_HPP | ||
| 2 | #define EFSW_SYSTEMIMPLPOSIX_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 7 | |||
| 8 | namespace efsw { namespace Platform { | ||
| 9 | |||
| 10 | class System { | ||
| 11 | public: | ||
| 12 | static void sleep( const unsigned long& ms ); | ||
| 13 | |||
| 14 | static std::string getProcessPath(); | ||
| 15 | |||
| 16 | static void maxFD(); | ||
| 17 | |||
| 18 | static Uint64 getMaxFD(); | ||
| 19 | }; | ||
| 20 | |||
| 21 | }} // namespace efsw::Platform | ||
| 22 | |||
| 23 | #endif | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp new file mode 100755 index 0000000..e0ae84f --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include <efsw/Thread.hpp> | ||
| 2 | #include <efsw/platform/posix/ThreadImpl.hpp> | ||
| 3 | |||
| 4 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 5 | |||
| 6 | #include <cassert> | ||
| 7 | #include <efsw/Debug.hpp> | ||
| 8 | #include <iostream> | ||
| 9 | |||
| 10 | namespace efsw { namespace Platform { | ||
| 11 | |||
| 12 | ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) { | ||
| 13 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; | ||
| 14 | |||
| 15 | if ( !mIsActive ) { | ||
| 16 | efDEBUG( "Failed to create thread\n" ); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | void ThreadImpl::wait() { | ||
| 21 | // Wait for the thread to finish, no timeout | ||
| 22 | if ( mIsActive ) { | ||
| 23 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); | ||
| 24 | |||
| 25 | pthread_join( mThread, NULL ); | ||
| 26 | |||
| 27 | mIsActive = false; // Reset the thread state | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | void ThreadImpl::terminate() { | ||
| 32 | if ( mIsActive ) { | ||
| 33 | #if !defined( __ANDROID__ ) && !defined( ANDROID ) | ||
| 34 | pthread_cancel( mThread ); | ||
| 35 | #else | ||
| 36 | pthread_kill( mThread, SIGUSR1 ); | ||
| 37 | #endif | ||
| 38 | |||
| 39 | mIsActive = false; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | void* ThreadImpl::entryPoint( void* userData ) { | ||
| 44 | // The Thread instance is stored in the user data | ||
| 45 | Thread* owner = static_cast<Thread*>( userData ); | ||
| 46 | |||
| 47 | // Tell the thread to handle cancel requests immediatly | ||
| 48 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS | ||
| 49 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); | ||
| 50 | #endif | ||
| 51 | |||
| 52 | // Forward to the owner | ||
| 53 | owner->run(); | ||
| 54 | |||
| 55 | return NULL; | ||
| 56 | } | ||
| 57 | |||
| 58 | }} // namespace efsw::Platform | ||
| 59 | |||
| 60 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp new file mode 100755 index 0000000..ffc6da0 --- /dev/null +++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #ifndef EFSW_THREADIMPLPOSIX_HPP | ||
| 2 | #define EFSW_THREADIMPLPOSIX_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if defined( EFSW_PLATFORM_POSIX ) | ||
| 7 | |||
| 8 | #include <pthread.h> | ||
| 9 | |||
| 10 | namespace efsw { | ||
| 11 | |||
| 12 | class Thread; | ||
| 13 | |||
| 14 | namespace Platform { | ||
| 15 | |||
| 16 | class ThreadImpl { | ||
| 17 | public: | ||
| 18 | ThreadImpl( Thread* owner ); | ||
| 19 | |||
| 20 | void wait(); | ||
| 21 | |||
| 22 | void terminate(); | ||
| 23 | |||
| 24 | protected: | ||
| 25 | static void* entryPoint( void* userData ); | ||
| 26 | |||
| 27 | pthread_t mThread; | ||
| 28 | bool mIsActive; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Platform | ||
| 32 | } // namespace efsw | ||
| 33 | |||
| 34 | #endif | ||
| 35 | |||
| 36 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp new file mode 100755 index 0000000..2b87513 --- /dev/null +++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | #include <efsw/platform/win/FileSystemImpl.hpp> | ||
| 2 | |||
| 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 4 | |||
| 5 | #include <climits> | ||
| 6 | #ifndef WIN32_LEAN_AND_MEAN | ||
| 7 | #define WIN32_LEAN_AND_MEAN | ||
| 8 | #endif | ||
| 9 | #include <windows.h> | ||
| 10 | |||
| 11 | #ifndef EFSW_COMPILER_MSVC | ||
| 12 | #include <dirent.h> | ||
| 13 | #else | ||
| 14 | #include <direct.h> | ||
| 15 | #endif | ||
| 16 | |||
| 17 | namespace efsw { namespace Platform { | ||
| 18 | |||
| 19 | bool FileSystem::changeWorkingDirectory( const std::string& path ) { | ||
| 20 | int res; | ||
| 21 | #ifdef EFSW_COMPILER_MSVC | ||
| 22 | #ifdef UNICODE | ||
| 23 | res = _wchdir( String::fromUtf8( path.c_str() ).toWideString().c_str() ); | ||
| 24 | #else | ||
| 25 | res = _chdir( String::fromUtf8( path.c_str() ).toAnsiString().c_str() ); | ||
| 26 | #endif | ||
| 27 | #else | ||
| 28 | res = chdir( path.c_str() ); | ||
| 29 | #endif | ||
| 30 | return -1 != res; | ||
| 31 | } | ||
| 32 | |||
| 33 | std::string FileSystem::getCurrentWorkingDirectory() { | ||
| 34 | #ifdef EFSW_COMPILER_MSVC | ||
| 35 | #if defined( UNICODE ) && !defined( EFSW_NO_WIDECHAR ) | ||
| 36 | wchar_t dir[_MAX_PATH]; | ||
| 37 | return ( 0 != GetCurrentDirectoryW( _MAX_PATH, dir ) ) ? String( dir ).toUtf8() : std::string(); | ||
| 38 | #else | ||
| 39 | char dir[_MAX_PATH]; | ||
| 40 | return ( 0 != GetCurrentDirectory( _MAX_PATH, dir ) ) ? String( dir, std::locale() ).toUtf8() | ||
| 41 | : std::string(); | ||
| 42 | #endif | ||
| 43 | #else | ||
| 44 | char dir[PATH_MAX + 1]; | ||
| 45 | getcwd( dir, PATH_MAX + 1 ); | ||
| 46 | return std::string( dir ); | ||
| 47 | #endif | ||
| 48 | } | ||
| 49 | |||
| 50 | FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) { | ||
| 51 | FileInfoMap files; | ||
| 52 | |||
| 53 | String tpath( path ); | ||
| 54 | |||
| 55 | if ( tpath[tpath.size() - 1] == '/' || tpath[tpath.size() - 1] == '\\' ) { | ||
| 56 | tpath += "*"; | ||
| 57 | } else { | ||
| 58 | tpath += "\\*"; | ||
| 59 | } | ||
| 60 | |||
| 61 | WIN32_FIND_DATAW findFileData; | ||
| 62 | HANDLE hFind = FindFirstFileW( (LPCWSTR)tpath.toWideString().c_str(), &findFileData ); | ||
| 63 | |||
| 64 | if ( hFind != INVALID_HANDLE_VALUE ) { | ||
| 65 | std::string name( String( findFileData.cFileName ).toUtf8() ); | ||
| 66 | std::string fpath( path + name ); | ||
| 67 | |||
| 68 | if ( name != "." && name != ".." ) { | ||
| 69 | files[name] = FileInfo( fpath ); | ||
| 70 | } | ||
| 71 | |||
| 72 | while ( FindNextFileW( hFind, &findFileData ) ) { | ||
| 73 | name = String( findFileData.cFileName ).toUtf8(); | ||
| 74 | fpath = path + name; | ||
| 75 | |||
| 76 | if ( name != "." && name != ".." ) { | ||
| 77 | files[name] = FileInfo( fpath ); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | FindClose( hFind ); | ||
| 82 | } | ||
| 83 | |||
| 84 | return files; | ||
| 85 | } | ||
| 86 | |||
| 87 | char FileSystem::getOSSlash() { | ||
| 88 | return '\\'; | ||
| 89 | } | ||
| 90 | |||
| 91 | bool FileSystem::isDirectory( const std::string& path ) { | ||
| 92 | DWORD attrs = GetFileAttributesW( String( path ).toWideString().c_str() ); | ||
| 93 | return attrs != INVALID_FILE_ATTRIBUTES && ( attrs & FILE_ATTRIBUTE_DIRECTORY ) != 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | bool FileSystem::isRemoteFS( const std::string& directory ) { | ||
| 97 | if ( ( directory[0] == '\\' || directory[0] == '/' ) && | ||
| 98 | ( directory[1] == '\\' || directory[1] == '/' ) ) { | ||
| 99 | return true; | ||
| 100 | } | ||
| 101 | |||
| 102 | if ( directory.size() >= 3 ) { | ||
| 103 | return 4 == GetDriveTypeA( directory.substr( 0, 3 ).c_str() ); | ||
| 104 | } | ||
| 105 | |||
| 106 | return false; | ||
| 107 | } | ||
| 108 | |||
| 109 | }} // namespace efsw::Platform | ||
| 110 | |||
| 111 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp new file mode 100755 index 0000000..e952efc --- /dev/null +++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #ifndef EFSW_FILESYSTEMIMPLWIN_HPP | ||
| 2 | #define EFSW_FILESYSTEMIMPLWIN_HPP | ||
| 3 | |||
| 4 | #include <efsw/FileInfo.hpp> | ||
| 5 | #include <efsw/String.hpp> | ||
| 6 | #include <efsw/base.hpp> | ||
| 7 | |||
| 8 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 9 | |||
| 10 | namespace efsw { namespace Platform { | ||
| 11 | |||
| 12 | class FileSystem { | ||
| 13 | public: | ||
| 14 | static FileInfoMap filesInfoFromPath( const std::string& path ); | ||
| 15 | |||
| 16 | static char getOSSlash(); | ||
| 17 | |||
| 18 | static bool isDirectory( const std::string& path ); | ||
| 19 | |||
| 20 | static bool isRemoteFS( const std::string& directory ); | ||
| 21 | |||
| 22 | static bool changeWorkingDirectory( const std::string& path ); | ||
| 23 | |||
| 24 | static std::string getCurrentWorkingDirectory(); | ||
| 25 | }; | ||
| 26 | |||
| 27 | }} // namespace efsw::Platform | ||
| 28 | |||
| 29 | #endif | ||
| 30 | |||
| 31 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.cpp b/src/3rdParty/efsw/platform/win/MutexImpl.cpp new file mode 100755 index 0000000..62b7f83 --- /dev/null +++ b/src/3rdParty/efsw/platform/win/MutexImpl.cpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #include <efsw/platform/win/MutexImpl.hpp> | ||
| 2 | |||
| 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 4 | |||
| 5 | namespace efsw { namespace Platform { | ||
| 6 | |||
| 7 | MutexImpl::MutexImpl() { | ||
| 8 | InitializeCriticalSection( &mMutex ); | ||
| 9 | } | ||
| 10 | |||
| 11 | MutexImpl::~MutexImpl() { | ||
| 12 | DeleteCriticalSection( &mMutex ); | ||
| 13 | } | ||
| 14 | |||
| 15 | void MutexImpl::lock() { | ||
| 16 | EnterCriticalSection( &mMutex ); | ||
| 17 | } | ||
| 18 | |||
| 19 | void MutexImpl::unlock() { | ||
| 20 | LeaveCriticalSection( &mMutex ); | ||
| 21 | } | ||
| 22 | |||
| 23 | }} // namespace efsw::Platform | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.hpp b/src/3rdParty/efsw/platform/win/MutexImpl.hpp new file mode 100755 index 0000000..7b06492 --- /dev/null +++ b/src/3rdParty/efsw/platform/win/MutexImpl.hpp | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #ifndef EFSW_MUTEXIMPLWIN_HPP | ||
| 2 | #define EFSW_MUTEXIMPLWIN_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 7 | |||
| 8 | #ifndef WIN32_LEAN_AND_MEAN | ||
| 9 | #define WIN32_LEAN_AND_MEAN | ||
| 10 | #endif | ||
| 11 | #include <windows.h> | ||
| 12 | |||
| 13 | namespace efsw { namespace Platform { | ||
| 14 | |||
| 15 | class MutexImpl { | ||
| 16 | public: | ||
| 17 | MutexImpl(); | ||
| 18 | |||
| 19 | ~MutexImpl(); | ||
| 20 | |||
| 21 | void lock(); | ||
| 22 | |||
| 23 | void unlock(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | CRITICAL_SECTION mMutex; | ||
| 27 | }; | ||
| 28 | |||
| 29 | }} // namespace efsw::Platform | ||
| 30 | |||
| 31 | #endif | ||
| 32 | |||
| 33 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.cpp b/src/3rdParty/efsw/platform/win/SystemImpl.cpp new file mode 100755 index 0000000..d1f2b21 --- /dev/null +++ b/src/3rdParty/efsw/platform/win/SystemImpl.cpp | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #include <efsw/String.hpp> | ||
| 2 | #include <efsw/platform/win/SystemImpl.hpp> | ||
| 3 | |||
| 4 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 5 | |||
| 6 | #ifndef WIN32_LEAN_AND_MEAN | ||
| 7 | #define WIN32_LEAN_AND_MEAN | ||
| 8 | #endif | ||
| 9 | #include <cstdlib> | ||
| 10 | #include <windows.h> | ||
| 11 | |||
| 12 | namespace efsw { namespace Platform { | ||
| 13 | |||
| 14 | void System::sleep( const unsigned long& ms ) { | ||
| 15 | ::Sleep( ms ); | ||
| 16 | } | ||
| 17 | |||
| 18 | std::string System::getProcessPath() { | ||
| 19 | // Get path to executable: | ||
| 20 | WCHAR szDrive[_MAX_DRIVE]; | ||
| 21 | WCHAR szDir[_MAX_DIR]; | ||
| 22 | WCHAR szFilename[_MAX_DIR]; | ||
| 23 | WCHAR szExt[_MAX_DIR]; | ||
| 24 | std::wstring dllName( _MAX_DIR, 0 ); | ||
| 25 | |||
| 26 | GetModuleFileNameW( 0, &dllName[0], _MAX_PATH ); | ||
| 27 | |||
| 28 | #ifdef EFSW_COMPILER_MSVC | ||
| 29 | _wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, | ||
| 30 | szExt, _MAX_DIR ); | ||
| 31 | #else | ||
| 32 | _wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt ); | ||
| 33 | #endif | ||
| 34 | |||
| 35 | return String( szDrive ).toUtf8() + String( szDir ).toUtf8(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void System::maxFD() {} | ||
| 39 | |||
| 40 | Uint64 System::getMaxFD() { // Number of ReadDirectory per thread | ||
| 41 | return 60; | ||
| 42 | } | ||
| 43 | |||
| 44 | }} // namespace efsw::Platform | ||
| 45 | |||
| 46 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.hpp b/src/3rdParty/efsw/platform/win/SystemImpl.hpp new file mode 100755 index 0000000..99b4867 --- /dev/null +++ b/src/3rdParty/efsw/platform/win/SystemImpl.hpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #ifndef EFSW_SYSTEMIMPLWIN_HPP | ||
| 2 | #define EFSW_SYSTEMIMPLWIN_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 7 | |||
| 8 | namespace efsw { namespace Platform { | ||
| 9 | |||
| 10 | class System { | ||
| 11 | public: | ||
| 12 | static void sleep( const unsigned long& ms ); | ||
| 13 | |||
| 14 | static std::string getProcessPath(); | ||
| 15 | |||
| 16 | static void maxFD(); | ||
| 17 | |||
| 18 | static Uint64 getMaxFD(); | ||
| 19 | }; | ||
| 20 | |||
| 21 | }} // namespace efsw::Platform | ||
| 22 | |||
| 23 | #endif | ||
| 24 | |||
| 25 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp new file mode 100755 index 0000000..d0fde8b --- /dev/null +++ b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | #include <assert.h> | ||
| 2 | #include <efsw/Thread.hpp> | ||
| 3 | #include <efsw/platform/win/ThreadImpl.hpp> | ||
| 4 | |||
| 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 6 | |||
| 7 | #include <efsw/Debug.hpp> | ||
| 8 | |||
| 9 | namespace efsw { namespace Platform { | ||
| 10 | |||
| 11 | ThreadImpl::ThreadImpl( Thread* owner ) { | ||
| 12 | mThread = reinterpret_cast<HANDLE>( | ||
| 13 | _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); | ||
| 14 | |||
| 15 | if ( !mThread ) { | ||
| 16 | efDEBUG( "Failed to create thread\n" ); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | ThreadImpl::~ThreadImpl() { | ||
| 21 | if ( mThread ) { | ||
| 22 | CloseHandle( mThread ); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | void ThreadImpl::wait() { | ||
| 27 | // Wait for the thread to finish, no timeout | ||
| 28 | if ( mThread ) { | ||
| 29 | assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself! | ||
| 30 | |||
| 31 | WaitForSingleObject( mThread, INFINITE ); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | void ThreadImpl::terminate() { | ||
| 36 | if ( mThread ) { | ||
| 37 | TerminateThread( mThread, 0 ); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | unsigned int __stdcall ThreadImpl::entryPoint( void* userData ) { | ||
| 42 | // The Thread instance is stored in the user data | ||
| 43 | Thread* owner = static_cast<Thread*>( userData ); | ||
| 44 | |||
| 45 | // Forward to the owner | ||
| 46 | owner->run(); | ||
| 47 | |||
| 48 | // Optional, but it is cleaner | ||
| 49 | _endthreadex( 0 ); | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | }} // namespace efsw::Platform | ||
| 55 | |||
| 56 | #endif | ||
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp new file mode 100755 index 0000000..1afb593 --- /dev/null +++ b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | #ifndef EFSW_THREADIMPLWIN_HPP | ||
| 2 | #define EFSW_THREADIMPLWIN_HPP | ||
| 3 | |||
| 4 | #include <efsw/base.hpp> | ||
| 5 | |||
| 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | ||
| 7 | |||
| 8 | #ifndef WIN32_LEAN_AND_MEAN | ||
| 9 | #define WIN32_LEAN_AND_MEAN | ||
| 10 | #endif | ||
| 11 | #include <process.h> | ||
| 12 | #include <windows.h> | ||
| 13 | |||
| 14 | namespace efsw { | ||
| 15 | |||
| 16 | class Thread; | ||
| 17 | |||
| 18 | namespace Platform { | ||
| 19 | |||
| 20 | class ThreadImpl { | ||
| 21 | public: | ||
| 22 | ThreadImpl( Thread* owner ); | ||
| 23 | |||
| 24 | ~ThreadImpl(); | ||
| 25 | |||
| 26 | void wait(); | ||
| 27 | |||
| 28 | void terminate(); | ||
| 29 | |||
| 30 | protected: | ||
| 31 | static unsigned int __stdcall entryPoint( void* userData ); | ||
| 32 | |||
| 33 | HANDLE mThread; | ||
| 34 | unsigned int mThreadId; | ||
| 35 | }; | ||
| 36 | |||
| 37 | } // namespace Platform | ||
| 38 | } // namespace efsw | ||
| 39 | |||
| 40 | #endif | ||
| 41 | |||
| 42 | #endif | ||
diff --git a/src/3rdParty/efsw/sophist.h b/src/3rdParty/efsw/sophist.h new file mode 100755 index 0000000..3a64504 --- /dev/null +++ b/src/3rdParty/efsw/sophist.h | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | /* sophist.h - 0.3 - public domain - Sean Barrett 2010 | ||
| 2 | ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net | ||
| 3 | ** Sophist provides portable types; you typedef/#define them to your own names | ||
| 4 | ** | ||
| 5 | ** defines: | ||
| 6 | ** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian | ||
| 7 | ** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined | ||
| 8 | ** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit | ||
| 9 | ** | ||
| 10 | ** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer | ||
| 11 | ** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 | ||
| 12 | ** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 | ||
| 13 | ** - SOPHIST_int64_constant(number) - macros for creating 64-bit | ||
| 14 | ** - SOPHIST_uint64_constant(number) integer constants | ||
| 15 | ** - SOPHIST_printf_format64 - string for printf format for int64 | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __INCLUDE_SOPHIST_H__ | ||
| 19 | #define __INCLUDE_SOPHIST_H__ | ||
| 20 | |||
| 21 | #define SOPHIST_compiletime_assert(name,val) \ | ||
| 22 | typedef int SOPHIST__assert##name[(val) ? 1 : -1] | ||
| 23 | |||
| 24 | /* define a couple synthetic rules to make code more readable */ | ||
| 25 | #if (defined(__sparc__) || defined(__sparc)) && \ | ||
| 26 | (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) | ||
| 27 | #define SOPHIST_sparc64 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #if (defined(linux) || defined(__linux__)) && \ | ||
| 31 | (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) | ||
| 32 | #define SOPHIST_linux64 | ||
| 33 | #endif | ||
| 34 | |||
| 35 | /* basic types */ | ||
| 36 | typedef signed char SOPHIST_int8; | ||
| 37 | typedef unsigned char SOPHIST_uint8; | ||
| 38 | |||
| 39 | typedef signed short SOPHIST_int16; | ||
| 40 | typedef unsigned short SOPHIST_uint16; | ||
| 41 | |||
| 42 | #ifdef __palmos__ | ||
| 43 | typedef signed long SOPHIST_int32; | ||
| 44 | typedef unsigned long SOPHIST_uint32; | ||
| 45 | #else | ||
| 46 | typedef signed int SOPHIST_int32; | ||
| 47 | typedef unsigned int SOPHIST_uint32; | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #ifndef SOPHIST_NO_64 | ||
| 51 | #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ | ||
| 52 | || (defined(__alpha) && defined(__DECC)) | ||
| 53 | |||
| 54 | typedef signed __int64 SOPHIST_int64; | ||
| 55 | typedef unsigned __int64 SOPHIST_uint64; | ||
| 56 | #define SOPHIST_has_64 1 | ||
| 57 | #define SOPHIST_int64_constant(x) (x##i64) | ||
| 58 | #define SOPHIST_uint64_constant(x) (x##ui64) | ||
| 59 | #define SOPHIST_printf_format64 "I64" | ||
| 60 | |||
| 61 | #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) | ||
| 62 | |||
| 63 | typedef signed long SOPHIST_int64; | ||
| 64 | typedef unsigned long SOPHIST_uint64; | ||
| 65 | |||
| 66 | #define SOPHIST_has_64 1 | ||
| 67 | #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) | ||
| 68 | #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) | ||
| 69 | #define SOPHIST_printf_format64 "l" | ||
| 70 | |||
| 71 | #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ | ||
| 72 | || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ | ||
| 73 | || defined(sgi) || defined (__sgi) || defined(__sgi__) \ | ||
| 74 | || defined(_CRAYC) | ||
| 75 | |||
| 76 | typedef signed long long SOPHIST_int64; | ||
| 77 | typedef unsigned long long SOPHIST_uint64; | ||
| 78 | |||
| 79 | #define SOPHIST_has_64 1 | ||
| 80 | #define SOPHIST_int64_constant(x) (x##LL) | ||
| 81 | #define SOPHIST_uint64_constant(x) (x##ULL) | ||
| 82 | #define SOPHIST_printf_format64 "ll" | ||
| 83 | #endif | ||
| 84 | #endif | ||
| 85 | |||
| 86 | #ifndef SOPHIST_has_64 | ||
| 87 | #define SOPHIST_has_64 0 | ||
| 88 | #endif | ||
| 89 | |||
| 90 | SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); | ||
| 91 | SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); | ||
| 92 | SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); | ||
| 93 | SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); | ||
| 94 | |||
| 95 | #if SOPHIST_has_64 | ||
| 96 | SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); | ||
| 97 | SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); | ||
| 98 | #endif | ||
| 99 | |||
| 100 | /* determine whether pointers are 64-bit */ | ||
| 101 | |||
| 102 | #if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ | ||
| 103 | || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ | ||
| 104 | || defined(__64BIT__) \ | ||
| 105 | || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ | ||
| 106 | || defined(_ADDR64) || defined(_CRAYC) \ | ||
| 107 | |||
| 108 | #define SOPHIST_pointer64 1 | ||
| 109 | |||
| 110 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); | ||
| 111 | |||
| 112 | typedef SOPHIST_int64 SOPHIST_intptr; | ||
| 113 | typedef SOPHIST_uint64 SOPHIST_uintptr; | ||
| 114 | #else | ||
| 115 | |||
| 116 | #define SOPHIST_pointer64 0 | ||
| 117 | |||
| 118 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); | ||
| 119 | |||
| 120 | /* do we care about pointers that are only 16-bit? */ | ||
| 121 | typedef SOPHIST_int32 SOPHIST_intptr; | ||
| 122 | typedef SOPHIST_uint32 SOPHIST_uintptr; | ||
| 123 | |||
| 124 | #endif | ||
| 125 | |||
| 126 | SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); | ||
| 127 | |||
| 128 | /* enumerate known little endian cases; fallback to big-endian */ | ||
| 129 | |||
| 130 | #define SOPHIST_little_endian 1 | ||
| 131 | #define SOPHIST_big_endian 2 | ||
| 132 | |||
| 133 | #if defined(__386__) || defined(i386) || defined(__i386__) \ | ||
| 134 | || defined(__X86) || defined(_M_IX86) \ | ||
| 135 | || defined(_M_X64) || defined(__x86_64__) \ | ||
| 136 | || defined(alpha) || defined(__alpha) || defined(__alpha__) \ | ||
| 137 | || defined(_M_ALPHA) \ | ||
| 138 | || defined(ARM) || defined(_ARM) || defined(__arm__) \ | ||
| 139 | || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ | ||
| 140 | || defined(_WIN32_WCE) || defined(__NT__) \ | ||
| 141 | || defined(__MIPSEL__) | ||
| 142 | #define SOPHIST_endian SOPHIST_little_endian | ||
| 143 | #else | ||
| 144 | #define SOPHIST_endian SOPHIST_big_endian | ||
| 145 | #endif | ||
| 146 | |||
| 147 | #endif /* __INCLUDE_SOPHIST_H__ */ | ||
diff --git a/src/yue.cpp b/src/yue.cpp index 5b4dccc..9ae4c3e 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
| @@ -19,10 +19,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| 19 | #include <sstream> | 19 | #include <sstream> |
| 20 | #include <string_view> | 20 | #include <string_view> |
| 21 | #include <tuple> | 21 | #include <tuple> |
| 22 | #include <chrono> | ||
| 23 | #include <thread> | ||
| 22 | using namespace std::string_view_literals; | 24 | using namespace std::string_view_literals; |
| 23 | using namespace std::string_literals; | 25 | using namespace std::string_literals; |
| 26 | using namespace std::chrono_literals; | ||
| 24 | #include "ghc/fs_std.hpp" | 27 | #include "ghc/fs_std.hpp" |
| 25 | #include "linenoise.hpp" | 28 | #include "linenoise.hpp" |
| 29 | #include "efsw/efsw.hpp" | ||
| 26 | 30 | ||
| 27 | #if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) | 31 | #if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) |
| 28 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { code; }) | 32 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { code; }) |
| @@ -88,8 +92,8 @@ void pushOptions(lua_State* L, int lineOffset) { | |||
| 88 | #ifndef YUE_COMPILER_ONLY | 92 | #ifndef YUE_COMPILER_ONLY |
| 89 | static const char luaminifyCodes[] = | 93 | static const char luaminifyCodes[] = |
| 90 | #include "LuaMinify.h" | 94 | #include "LuaMinify.h" |
| 91 | 95 | // | |
| 92 | static void pushLuaminify(lua_State * L) { | 96 | static void pushLuaminify(lua_State * L) { |
| 93 | if (luaL_loadbuffer(L, luaminifyCodes, sizeof(luaminifyCodes) / sizeof(luaminifyCodes[0]) - 1, "=(luaminify)") != 0) { | 97 | if (luaL_loadbuffer(L, luaminifyCodes, sizeof(luaminifyCodes) / sizeof(luaminifyCodes[0]) - 1, "=(luaminify)") != 0) { |
| 94 | std::string err = "failed to load luaminify module.\n"s + lua_tostring(L, -1); | 98 | std::string err = "failed to load luaminify module.\n"s + lua_tostring(L, -1); |
| 95 | luaL_error(L, err.c_str()); | 99 | luaL_error(L, err.c_str()); |
| @@ -100,6 +104,126 @@ static const char luaminifyCodes[] = | |||
| 100 | } | 104 | } |
| 101 | #endif // YUE_COMPILER_ONLY | 105 | #endif // YUE_COMPILER_ONLY |
| 102 | 106 | ||
| 107 | fs::path getTargetFile(const fs::path& srcFile) { | ||
| 108 | auto ext = srcFile.extension().string(); | ||
| 109 | for (auto& ch : ext) ch = std::tolower(ch); | ||
| 110 | if (!ext.empty() && ext.substr(1) == yue::extension) { | ||
| 111 | auto targetFile = srcFile; | ||
| 112 | targetFile.replace_extension("lua"s); | ||
| 113 | if (fs::exists(targetFile)) { | ||
| 114 | return targetFile; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | return fs::path(); | ||
| 118 | } | ||
| 119 | |||
| 120 | fs::path getTargetFileDirty(const fs::path& srcFile) { | ||
| 121 | if (!fs::exists(srcFile)) return fs::path(); | ||
| 122 | auto ext = srcFile.extension().string(); | ||
| 123 | for (auto& ch : ext) ch = std::tolower(ch); | ||
| 124 | if (!fs::is_directory(srcFile) && !ext.empty() && ext.substr(1) == yue::extension) { | ||
| 125 | auto targetFile = srcFile; | ||
| 126 | targetFile.replace_extension("lua"s); | ||
| 127 | if (fs::exists(targetFile)) { | ||
| 128 | auto time = fs::last_write_time(targetFile); | ||
| 129 | auto targetTime = fs::last_write_time(srcFile); | ||
| 130 | if (time < targetTime) { | ||
| 131 | return targetFile; | ||
| 132 | } | ||
| 133 | } else { | ||
| 134 | return targetFile; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | return fs::path(); | ||
| 138 | } | ||
| 139 | |||
| 140 | static std::string compileFile(const fs::path& srcFile, yue::YueConfig conf, const std::string& workPath) { | ||
| 141 | auto targetFile = getTargetFileDirty(srcFile); | ||
| 142 | if (targetFile.empty()) return std::string(); | ||
| 143 | std::ifstream input(srcFile, std::ios::in); | ||
| 144 | if (input) { | ||
| 145 | std::string s( | ||
| 146 | (std::istreambuf_iterator<char>(input)), | ||
| 147 | std::istreambuf_iterator<char>()); | ||
| 148 | auto modulePath = srcFile.lexically_relative(workPath); | ||
| 149 | conf.module = modulePath.string(); | ||
| 150 | if (!workPath.empty()) { | ||
| 151 | auto it = conf.options.find("path"); | ||
| 152 | if (it != conf.options.end()) { | ||
| 153 | it->second += ';'; | ||
| 154 | it->second += (fs::path(workPath) / "?.lua"sv).string(); | ||
| 155 | } else { | ||
| 156 | conf.options["path"] = (fs::path(workPath) / "?.lua"sv).string(); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | auto result = yue::YueCompiler{YUE_ARGS}.compile(s, conf); | ||
| 160 | if (result.error.empty()) { | ||
| 161 | std::string targetExtension("lua"sv); | ||
| 162 | if (result.options) { | ||
| 163 | auto it = result.options->find("target_extension"s); | ||
| 164 | if (it != result.options->end()) { | ||
| 165 | targetExtension = it->second; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | if (targetFile.has_parent_path()) { | ||
| 169 | fs::create_directories(targetFile.parent_path()); | ||
| 170 | } | ||
| 171 | if (result.codes.empty()) { | ||
| 172 | return "Built "s + modulePath.string() + '\n'; | ||
| 173 | } | ||
| 174 | std::ofstream output(targetFile, std::ios::trunc | std::ios::out); | ||
| 175 | if (output) { | ||
| 176 | const auto& codes = result.codes; | ||
| 177 | if (conf.reserveLineNumber) { | ||
| 178 | auto head = "-- [yue]: "s + modulePath.string() + '\n'; | ||
| 179 | output.write(head.c_str(), head.size()); | ||
| 180 | } | ||
| 181 | output.write(codes.c_str(), codes.size()); | ||
| 182 | return "Built "s + modulePath.string() + '\n'; | ||
| 183 | } else { | ||
| 184 | return "Failed to write file: "s + targetFile.string() + '\n'; | ||
| 185 | } | ||
| 186 | } else { | ||
| 187 | return "Failed to compile: "s + modulePath.string() + '\n' + result.error + '\n'; | ||
| 188 | } | ||
| 189 | } else { | ||
| 190 | return "Failed to read file: "s + srcFile.string() + '\n'; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | class UpdateListener : public efsw::FileWatchListener { | ||
| 195 | public: | ||
| 196 | void handleFileAction(efsw::WatchID, const std::string& dir, const std::string& filename, efsw::Action action, std::string oldFilename) override { | ||
| 197 | switch(action) { | ||
| 198 | case efsw::Actions::Add: | ||
| 199 | if (auto res = compileFile(fs::path(dir) / filename, config, workPath); !res.empty()) { | ||
| 200 | std::cout << res; | ||
| 201 | } | ||
| 202 | break; | ||
| 203 | case efsw::Actions::Delete: { | ||
| 204 | auto srcFile = fs::path(dir) / filename; | ||
| 205 | auto targetFile = getTargetFile(srcFile); | ||
| 206 | if (!targetFile.empty()) { | ||
| 207 | fs::remove(targetFile); | ||
| 208 | std::cout << "Deleted " << targetFile.lexically_relative(workPath).string() << '\n'; | ||
| 209 | } | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | case efsw::Actions::Modified: | ||
| 213 | if (auto res = compileFile(fs::path(dir) / filename, config, workPath); !res.empty()) { | ||
| 214 | std::cout << res; | ||
| 215 | } | ||
| 216 | break; | ||
| 217 | case efsw::Actions::Moved: | ||
| 218 | break; | ||
| 219 | default: | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | yue::YueConfig config; | ||
| 224 | std::string workPath; | ||
| 225 | }; | ||
| 226 | |||
| 103 | int main(int narg, const char** args) { | 227 | int main(int narg, const char** args) { |
| 104 | const char* help = | 228 | const char* help = |
| 105 | "Usage: yue [options|files|directories] ...\n\n" | 229 | "Usage: yue [options|files|directories] ...\n\n" |
| @@ -275,6 +399,7 @@ int main(int narg, const char** args) { | |||
| 275 | bool writeToFile = true; | 399 | bool writeToFile = true; |
| 276 | bool dumpCompileTime = false; | 400 | bool dumpCompileTime = false; |
| 277 | bool lintGlobal = false; | 401 | bool lintGlobal = false; |
| 402 | bool watchFiles = false; | ||
| 278 | std::string targetPath; | 403 | std::string targetPath; |
| 279 | std::string resultFile; | 404 | std::string resultFile; |
| 280 | std::string workPath; | 405 | std::string workPath; |
| @@ -412,6 +537,8 @@ int main(int narg, const char** args) { | |||
| 412 | std::cout << help; | 537 | std::cout << help; |
| 413 | return 1; | 538 | return 1; |
| 414 | } | 539 | } |
| 540 | } else if (arg == "-w"sv) { | ||
| 541 | watchFiles = true; | ||
| 415 | } else if (arg.size() > 2 && arg.substr(0, 2) == "--"sv && arg.substr(2, 1) != "-"sv) { | 542 | } else if (arg.size() > 2 && arg.substr(0, 2) == "--"sv && arg.substr(2, 1) != "-"sv) { |
| 416 | auto argStr = arg.substr(2); | 543 | auto argStr = arg.substr(2); |
| 417 | yue::Utils::trim(argStr); | 544 | yue::Utils::trim(argStr); |
| @@ -437,13 +564,16 @@ int main(int narg, const char** args) { | |||
| 437 | } | 564 | } |
| 438 | } | 565 | } |
| 439 | } | 566 | } |
| 567 | } else if (watchFiles) { | ||
| 568 | std::cout << "Error: -w can not be used with file\n"sv; | ||
| 569 | return 1; | ||
| 440 | } else { | 570 | } else { |
| 441 | workPath = fs::path(arg).parent_path().string(); | 571 | workPath = fs::path(arg).parent_path().string(); |
| 442 | files.emplace_back(arg, arg); | 572 | files.emplace_back(arg, arg); |
| 443 | } | 573 | } |
| 444 | } | 574 | } |
| 445 | } | 575 | } |
| 446 | if (files.empty()) { | 576 | if (!watchFiles && files.empty()) { |
| 447 | std::cout << help; | 577 | std::cout << help; |
| 448 | return 0; | 578 | return 0; |
| 449 | } | 579 | } |
| @@ -451,6 +581,32 @@ int main(int narg, const char** args) { | |||
| 451 | std::cout << "Error: -o can not be used with multiple input files\n"sv; | 581 | std::cout << "Error: -o can not be used with multiple input files\n"sv; |
| 452 | std::cout << help; | 582 | std::cout << help; |
| 453 | } | 583 | } |
| 584 | if (watchFiles) { | ||
| 585 | auto fullWorkPath = fs::absolute(fs::path(workPath)).string(); | ||
| 586 | std::list<std::future<std::string>> results; | ||
| 587 | for (const auto& file : files) { | ||
| 588 | auto task = std::async(std::launch::async, [=]() { | ||
| 589 | return compileFile(fs::absolute(file.first), config, fullWorkPath); | ||
| 590 | }); | ||
| 591 | results.push_back(std::move(task)); | ||
| 592 | } | ||
| 593 | for (auto& result : results) { | ||
| 594 | std::string msg = result.get(); | ||
| 595 | if (!msg.empty()) { | ||
| 596 | std::cout << msg; | ||
| 597 | } | ||
| 598 | } | ||
| 599 | efsw::FileWatcher fileWatcher{}; | ||
| 600 | UpdateListener listener{}; | ||
| 601 | listener.config = config; | ||
| 602 | listener.workPath = fullWorkPath; | ||
| 603 | fileWatcher.addWatch(workPath, &listener, true); | ||
| 604 | fileWatcher.watch(); | ||
| 605 | while (true) { | ||
| 606 | std::this_thread::sleep_for(10000ms); | ||
| 607 | } | ||
| 608 | return 0; | ||
| 609 | } | ||
| 454 | std::list<std::future<std::tuple<int, std::string, std::string>>> results; | 610 | std::list<std::future<std::tuple<int, std::string, std::string>>> results; |
| 455 | for (const auto& file : files) { | 611 | for (const auto& file : files) { |
| 456 | auto task = std::async(std::launch::async, [=]() { | 612 | auto task = std::async(std::launch::async, [=]() { |
| @@ -518,7 +674,7 @@ int main(int narg, const char** args) { | |||
| 518 | } | 674 | } |
| 519 | targetFile.replace_extension('.' + targetExtension); | 675 | targetFile.replace_extension('.' + targetExtension); |
| 520 | } | 676 | } |
| 521 | if (!targetPath.empty()) { | 677 | if (targetFile.has_parent_path()) { |
| 522 | fs::create_directories(targetFile.parent_path()); | 678 | fs::create_directories(targetFile.parent_path()); |
| 523 | } | 679 | } |
| 524 | if (result.codes.empty()) { | 680 | if (result.codes.empty()) { |
diff --git a/win-build/Yuescript/Yuescript.vcxproj b/win-build/Yuescript/Yuescript.vcxproj index c912746..2c3ccb6 100644 --- a/win-build/Yuescript/Yuescript.vcxproj +++ b/win-build/Yuescript/Yuescript.vcxproj | |||
| @@ -176,7 +176,7 @@ | |||
| 176 | <ClCompile> | 176 | <ClCompile> |
| 177 | <WarningLevel>Level3</WarningLevel> | 177 | <WarningLevel>Level3</WarningLevel> |
| 178 | <SDLCheck>true</SDLCheck> | 178 | <SDLCheck>true</SDLCheck> |
| 179 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 179 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 180 | <ConformanceMode>true</ConformanceMode> | 180 | <ConformanceMode>true</ConformanceMode> |
| 181 | <LanguageStandard>stdcpp17</LanguageStandard> | 181 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 182 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 182 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -191,7 +191,7 @@ | |||
| 191 | <ClCompile> | 191 | <ClCompile> |
| 192 | <WarningLevel>Level3</WarningLevel> | 192 | <WarningLevel>Level3</WarningLevel> |
| 193 | <SDLCheck>true</SDLCheck> | 193 | <SDLCheck>true</SDLCheck> |
| 194 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 194 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 195 | <ConformanceMode>true</ConformanceMode> | 195 | <ConformanceMode>true</ConformanceMode> |
| 196 | <LanguageStandard>stdcpp17</LanguageStandard> | 196 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 197 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 197 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -206,7 +206,7 @@ | |||
| 206 | <ClCompile> | 206 | <ClCompile> |
| 207 | <WarningLevel>Level3</WarningLevel> | 207 | <WarningLevel>Level3</WarningLevel> |
| 208 | <SDLCheck>true</SDLCheck> | 208 | <SDLCheck>true</SDLCheck> |
| 209 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 209 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 210 | <ConformanceMode>true</ConformanceMode> | 210 | <ConformanceMode>true</ConformanceMode> |
| 211 | <LanguageStandard>stdcpp17</LanguageStandard> | 211 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 212 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 212 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -221,7 +221,7 @@ | |||
| 221 | <ClCompile> | 221 | <ClCompile> |
| 222 | <WarningLevel>Level3</WarningLevel> | 222 | <WarningLevel>Level3</WarningLevel> |
| 223 | <SDLCheck>true</SDLCheck> | 223 | <SDLCheck>true</SDLCheck> |
| 224 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 224 | <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 225 | <ConformanceMode>true</ConformanceMode> | 225 | <ConformanceMode>true</ConformanceMode> |
| 226 | <LanguageStandard>stdcpp17</LanguageStandard> | 226 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 227 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 227 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -238,7 +238,7 @@ | |||
| 238 | <FunctionLevelLinking>true</FunctionLevelLinking> | 238 | <FunctionLevelLinking>true</FunctionLevelLinking> |
| 239 | <IntrinsicFunctions>true</IntrinsicFunctions> | 239 | <IntrinsicFunctions>true</IntrinsicFunctions> |
| 240 | <SDLCheck>true</SDLCheck> | 240 | <SDLCheck>true</SDLCheck> |
| 241 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 241 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 242 | <ConformanceMode>true</ConformanceMode> | 242 | <ConformanceMode>true</ConformanceMode> |
| 243 | <LanguageStandard>stdcpp17</LanguageStandard> | 243 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 244 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 244 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -257,7 +257,7 @@ | |||
| 257 | <FunctionLevelLinking>true</FunctionLevelLinking> | 257 | <FunctionLevelLinking>true</FunctionLevelLinking> |
| 258 | <IntrinsicFunctions>true</IntrinsicFunctions> | 258 | <IntrinsicFunctions>true</IntrinsicFunctions> |
| 259 | <SDLCheck>true</SDLCheck> | 259 | <SDLCheck>true</SDLCheck> |
| 260 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 260 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 261 | <ConformanceMode>true</ConformanceMode> | 261 | <ConformanceMode>true</ConformanceMode> |
| 262 | <LanguageStandard>stdcpp17</LanguageStandard> | 262 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 263 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 263 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -276,7 +276,7 @@ | |||
| 276 | <FunctionLevelLinking>true</FunctionLevelLinking> | 276 | <FunctionLevelLinking>true</FunctionLevelLinking> |
| 277 | <IntrinsicFunctions>true</IntrinsicFunctions> | 277 | <IntrinsicFunctions>true</IntrinsicFunctions> |
| 278 | <SDLCheck>true</SDLCheck> | 278 | <SDLCheck>true</SDLCheck> |
| 279 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 279 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 280 | <ConformanceMode>true</ConformanceMode> | 280 | <ConformanceMode>true</ConformanceMode> |
| 281 | <LanguageStandard>stdcpp17</LanguageStandard> | 281 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 282 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 282 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -295,7 +295,7 @@ | |||
| 295 | <FunctionLevelLinking>true</FunctionLevelLinking> | 295 | <FunctionLevelLinking>true</FunctionLevelLinking> |
| 296 | <IntrinsicFunctions>true</IntrinsicFunctions> | 296 | <IntrinsicFunctions>true</IntrinsicFunctions> |
| 297 | <SDLCheck>true</SDLCheck> | 297 | <SDLCheck>true</SDLCheck> |
| 298 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 298 | <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 299 | <ConformanceMode>true</ConformanceMode> | 299 | <ConformanceMode>true</ConformanceMode> |
| 300 | <LanguageStandard>stdcpp17</LanguageStandard> | 300 | <LanguageStandard>stdcpp17</LanguageStandard> |
| 301 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> | 301 | <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
| @@ -347,6 +347,29 @@ | |||
| 347 | <ClCompile Include="..\..\src\yuescript\yuescript.cpp" /> | 347 | <ClCompile Include="..\..\src\yuescript\yuescript.cpp" /> |
| 348 | <ClCompile Include="..\..\src\yuescript\yue_compiler.cpp" /> | 348 | <ClCompile Include="..\..\src\yuescript\yue_compiler.cpp" /> |
| 349 | <ClCompile Include="..\..\src\yuescript\yue_parser.cpp" /> | 349 | <ClCompile Include="..\..\src\yuescript\yue_parser.cpp" /> |
| 350 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Debug.cpp" /> | ||
| 351 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshot.cpp" /> | ||
| 352 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshotDiff.cpp" /> | ||
| 353 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirWatcherGeneric.cpp" /> | ||
| 354 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileInfo.cpp" /> | ||
| 355 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileSystem.cpp" /> | ||
| 356 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcher.cpp" /> | ||
| 357 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherCWrapper.cpp" /> | ||
| 358 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherGeneric.cpp" /> | ||
| 359 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherImpl.cpp" /> | ||
| 360 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherWin32.cpp" /> | ||
| 361 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Log.cpp" /> | ||
| 362 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Mutex.cpp" /> | ||
| 363 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\FileSystemImpl.cpp" /> | ||
| 364 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\MutexImpl.cpp" /> | ||
| 365 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\SystemImpl.cpp" /> | ||
| 366 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\ThreadImpl.cpp" /> | ||
| 367 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\String.cpp" /> | ||
| 368 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\System.cpp" /> | ||
| 369 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Thread.cpp" /> | ||
| 370 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Watcher.cpp" /> | ||
| 371 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherGeneric.cpp" /> | ||
| 372 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherWin32.cpp" /> | ||
| 350 | </ItemGroup> | 373 | </ItemGroup> |
| 351 | <ItemGroup> | 374 | <ItemGroup> |
| 352 | <ClInclude Include="..\..\src\3rdParty\lua\lapi.h" /> | 375 | <ClInclude Include="..\..\src\3rdParty\lua\lapi.h" /> |
| @@ -384,6 +407,33 @@ | |||
| 384 | <ClInclude Include="..\..\src\yuescript\yue_ast.h" /> | 407 | <ClInclude Include="..\..\src\yuescript\yue_ast.h" /> |
| 385 | <ClInclude Include="..\..\src\yuescript\yue_compiler.h" /> | 408 | <ClInclude Include="..\..\src\yuescript\yue_compiler.h" /> |
| 386 | <ClInclude Include="..\..\src\yuescript\yue_parser.h" /> | 409 | <ClInclude Include="..\..\src\yuescript\yue_parser.h" /> |
| 410 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Atomic.hpp" /> | ||
| 411 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\base.hpp" /> | ||
| 412 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Debug.hpp" /> | ||
| 413 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshot.hpp" /> | ||
| 414 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshotDiff.hpp" /> | ||
| 415 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirWatcherGeneric.hpp" /> | ||
| 416 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\efsw.h" /> | ||
| 417 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\efsw.hpp" /> | ||
| 418 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileInfo.hpp" /> | ||
| 419 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileSystem.hpp" /> | ||
| 420 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherGeneric.hpp" /> | ||
| 421 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherImpl.hpp" /> | ||
| 422 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherWin32.hpp" /> | ||
| 423 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Lock.hpp" /> | ||
| 424 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Mutex.hpp" /> | ||
| 425 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\FileSystemImpl.hpp" /> | ||
| 426 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\MutexImpl.hpp" /> | ||
| 427 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\SystemImpl.hpp" /> | ||
| 428 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\ThreadImpl.hpp" /> | ||
| 429 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\sophist.h" /> | ||
| 430 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\String.hpp" /> | ||
| 431 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\System.hpp" /> | ||
| 432 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Thread.hpp" /> | ||
| 433 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Utf.hpp" /> | ||
| 434 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Watcher.hpp" /> | ||
| 435 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherGeneric.hpp" /> | ||
| 436 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherWin32.hpp" /> | ||
| 387 | </ItemGroup> | 437 | </ItemGroup> |
| 388 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | 438 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
| 389 | <ImportGroup Label="ExtensionTargets"> | 439 | <ImportGroup Label="ExtensionTargets"> |
diff --git a/win-build/Yuescript/Yuescript.vcxproj.filters b/win-build/Yuescript/Yuescript.vcxproj.filters index 0ebdd76..d5c8d9f 100644 --- a/win-build/Yuescript/Yuescript.vcxproj.filters +++ b/win-build/Yuescript/Yuescript.vcxproj.filters | |||
| @@ -11,6 +11,12 @@ | |||
| 11 | <Filter Include="src\yuescript"> | 11 | <Filter Include="src\yuescript"> |
| 12 | <UniqueIdentifier>{af398a57-cb37-4862-a5e8-5ec539259611}</UniqueIdentifier> | 12 | <UniqueIdentifier>{af398a57-cb37-4862-a5e8-5ec539259611}</UniqueIdentifier> |
| 13 | </Filter> | 13 | </Filter> |
| 14 | <Filter Include="src\efsw"> | ||
| 15 | <UniqueIdentifier>{410f4895-3ea8-4a46-ac6a-0d4737da5cf1}</UniqueIdentifier> | ||
| 16 | </Filter> | ||
| 17 | <Filter Include="src\efsw\win"> | ||
| 18 | <UniqueIdentifier>{4b765224-203c-4df9-ba95-c975f75c4cf1}</UniqueIdentifier> | ||
| 19 | </Filter> | ||
| 14 | </ItemGroup> | 20 | </ItemGroup> |
| 15 | <ItemGroup> | 21 | <ItemGroup> |
| 16 | <ClCompile Include="..\..\src\3rdParty\lua\lapi.c"> | 22 | <ClCompile Include="..\..\src\3rdParty\lua\lapi.c"> |
| @@ -127,6 +133,75 @@ | |||
| 127 | <ClCompile Include="..\..\src\yue.cpp"> | 133 | <ClCompile Include="..\..\src\yue.cpp"> |
| 128 | <Filter>src</Filter> | 134 | <Filter>src</Filter> |
| 129 | </ClCompile> | 135 | </ClCompile> |
| 136 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Debug.cpp"> | ||
| 137 | <Filter>src\efsw</Filter> | ||
| 138 | </ClCompile> | ||
| 139 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshot.cpp"> | ||
| 140 | <Filter>src\efsw</Filter> | ||
| 141 | </ClCompile> | ||
| 142 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshotDiff.cpp"> | ||
| 143 | <Filter>src\efsw</Filter> | ||
| 144 | </ClCompile> | ||
| 145 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirWatcherGeneric.cpp"> | ||
| 146 | <Filter>src\efsw</Filter> | ||
| 147 | </ClCompile> | ||
| 148 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileInfo.cpp"> | ||
| 149 | <Filter>src\efsw</Filter> | ||
| 150 | </ClCompile> | ||
| 151 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileSystem.cpp"> | ||
| 152 | <Filter>src\efsw</Filter> | ||
| 153 | </ClCompile> | ||
| 154 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcher.cpp"> | ||
| 155 | <Filter>src\efsw</Filter> | ||
| 156 | </ClCompile> | ||
| 157 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherCWrapper.cpp"> | ||
| 158 | <Filter>src\efsw</Filter> | ||
| 159 | </ClCompile> | ||
| 160 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherGeneric.cpp"> | ||
| 161 | <Filter>src\efsw</Filter> | ||
| 162 | </ClCompile> | ||
| 163 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherImpl.cpp"> | ||
| 164 | <Filter>src\efsw</Filter> | ||
| 165 | </ClCompile> | ||
| 166 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherWin32.cpp"> | ||
| 167 | <Filter>src\efsw</Filter> | ||
| 168 | </ClCompile> | ||
| 169 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Log.cpp"> | ||
| 170 | <Filter>src\efsw</Filter> | ||
| 171 | </ClCompile> | ||
| 172 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Mutex.cpp"> | ||
| 173 | <Filter>src\efsw</Filter> | ||
| 174 | </ClCompile> | ||
| 175 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\String.cpp"> | ||
| 176 | <Filter>src\efsw</Filter> | ||
| 177 | </ClCompile> | ||
| 178 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\System.cpp"> | ||
| 179 | <Filter>src\efsw</Filter> | ||
| 180 | </ClCompile> | ||
| 181 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Thread.cpp"> | ||
| 182 | <Filter>src\efsw</Filter> | ||
| 183 | </ClCompile> | ||
| 184 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Watcher.cpp"> | ||
| 185 | <Filter>src\efsw</Filter> | ||
| 186 | </ClCompile> | ||
| 187 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherGeneric.cpp"> | ||
| 188 | <Filter>src\efsw</Filter> | ||
| 189 | </ClCompile> | ||
| 190 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherWin32.cpp"> | ||
| 191 | <Filter>src\efsw</Filter> | ||
| 192 | </ClCompile> | ||
| 193 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\FileSystemImpl.cpp"> | ||
| 194 | <Filter>src\efsw\win</Filter> | ||
| 195 | </ClCompile> | ||
| 196 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\MutexImpl.cpp"> | ||
| 197 | <Filter>src\efsw\win</Filter> | ||
| 198 | </ClCompile> | ||
| 199 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\SystemImpl.cpp"> | ||
| 200 | <Filter>src\efsw\win</Filter> | ||
| 201 | </ClCompile> | ||
| 202 | <ClCompile Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\ThreadImpl.cpp"> | ||
| 203 | <Filter>src\efsw\win</Filter> | ||
| 204 | </ClCompile> | ||
| 130 | </ItemGroup> | 205 | </ItemGroup> |
| 131 | <ItemGroup> | 206 | <ItemGroup> |
| 132 | <ClInclude Include="..\..\src\3rdParty\lua\lapi.h"> | 207 | <ClInclude Include="..\..\src\3rdParty\lua\lapi.h"> |
| @@ -234,5 +309,86 @@ | |||
| 234 | <ClInclude Include="..\..\src\yuescript\yuescript.h"> | 309 | <ClInclude Include="..\..\src\yuescript\yuescript.h"> |
| 235 | <Filter>src\yuescript</Filter> | 310 | <Filter>src\yuescript</Filter> |
| 236 | </ClInclude> | 311 | </ClInclude> |
| 312 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\FileSystemImpl.hpp"> | ||
| 313 | <Filter>src\efsw\win</Filter> | ||
| 314 | </ClInclude> | ||
| 315 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\MutexImpl.hpp"> | ||
| 316 | <Filter>src\efsw\win</Filter> | ||
| 317 | </ClInclude> | ||
| 318 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\SystemImpl.hpp"> | ||
| 319 | <Filter>src\efsw\win</Filter> | ||
| 320 | </ClInclude> | ||
| 321 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\platform\win\ThreadImpl.hpp"> | ||
| 322 | <Filter>src\efsw\win</Filter> | ||
| 323 | </ClInclude> | ||
| 324 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\efsw.h"> | ||
| 325 | <Filter>src\efsw</Filter> | ||
| 326 | </ClInclude> | ||
| 327 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\sophist.h"> | ||
| 328 | <Filter>src\efsw</Filter> | ||
| 329 | </ClInclude> | ||
| 330 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Atomic.hpp"> | ||
| 331 | <Filter>src\efsw</Filter> | ||
| 332 | </ClInclude> | ||
| 333 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\base.hpp"> | ||
| 334 | <Filter>src\efsw</Filter> | ||
| 335 | </ClInclude> | ||
| 336 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Debug.hpp"> | ||
| 337 | <Filter>src\efsw</Filter> | ||
| 338 | </ClInclude> | ||
| 339 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshot.hpp"> | ||
| 340 | <Filter>src\efsw</Filter> | ||
| 341 | </ClInclude> | ||
| 342 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirectorySnapshotDiff.hpp"> | ||
| 343 | <Filter>src\efsw</Filter> | ||
| 344 | </ClInclude> | ||
| 345 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\DirWatcherGeneric.hpp"> | ||
| 346 | <Filter>src\efsw</Filter> | ||
| 347 | </ClInclude> | ||
| 348 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\efsw.hpp"> | ||
| 349 | <Filter>src\efsw</Filter> | ||
| 350 | </ClInclude> | ||
| 351 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileInfo.hpp"> | ||
| 352 | <Filter>src\efsw</Filter> | ||
| 353 | </ClInclude> | ||
| 354 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileSystem.hpp"> | ||
| 355 | <Filter>src\efsw</Filter> | ||
| 356 | </ClInclude> | ||
| 357 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherGeneric.hpp"> | ||
| 358 | <Filter>src\efsw</Filter> | ||
| 359 | </ClInclude> | ||
| 360 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherImpl.hpp"> | ||
| 361 | <Filter>src\efsw</Filter> | ||
| 362 | </ClInclude> | ||
| 363 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\FileWatcherWin32.hpp"> | ||
| 364 | <Filter>src\efsw</Filter> | ||
| 365 | </ClInclude> | ||
| 366 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Lock.hpp"> | ||
| 367 | <Filter>src\efsw</Filter> | ||
| 368 | </ClInclude> | ||
| 369 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Mutex.hpp"> | ||
| 370 | <Filter>src\efsw</Filter> | ||
| 371 | </ClInclude> | ||
| 372 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\String.hpp"> | ||
| 373 | <Filter>src\efsw</Filter> | ||
| 374 | </ClInclude> | ||
| 375 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\System.hpp"> | ||
| 376 | <Filter>src\efsw</Filter> | ||
| 377 | </ClInclude> | ||
| 378 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Thread.hpp"> | ||
| 379 | <Filter>src\efsw</Filter> | ||
| 380 | </ClInclude> | ||
| 381 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Utf.hpp"> | ||
| 382 | <Filter>src\efsw</Filter> | ||
| 383 | </ClInclude> | ||
| 384 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\Watcher.hpp"> | ||
| 385 | <Filter>src\efsw</Filter> | ||
| 386 | </ClInclude> | ||
| 387 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherGeneric.hpp"> | ||
| 388 | <Filter>src\efsw</Filter> | ||
| 389 | </ClInclude> | ||
| 390 | <ClInclude Include="\\Mac\Home\Workspace\Yuescript\src\3rdParty\efsw\WatcherWin32.hpp"> | ||
| 391 | <Filter>src\efsw</Filter> | ||
| 392 | </ClInclude> | ||
| 237 | </ItemGroup> | 393 | </ItemGroup> |
| 238 | </Project> \ No newline at end of file | 394 | </Project> \ No newline at end of file |
