diff options
author | Li Jin <dragon-fly@qq.com> | 2022-11-15 17:23:46 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-11-15 17:52:09 +0800 |
commit | 94f8330613877b3582d32bd11abd83a97b4399ad (patch) | |
tree | 5359de314be1ebde17f8d1e48632a97d18f9e50f | |
parent | 60f8f00a022ac08701792b2897b72d8c99b50f52 (diff) | |
download | yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.gz yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.bz2 yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.zip |
adding -w option to Yuescript tool.
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 |