aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-11-15 17:23:46 +0800
committerLi Jin <dragon-fly@qq.com>2022-11-15 17:52:09 +0800
commit94f8330613877b3582d32bd11abd83a97b4399ad (patch)
tree5359de314be1ebde17f8d1e48632a97d18f9e50f
parent60f8f00a022ac08701792b2897b72d8c99b50f52 (diff)
downloadyuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.gz
yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.tar.bz2
yuescript-94f8330613877b3582d32bd11abd83a97b4399ad.zip
adding -w option to Yuescript tool.
-rw-r--r--CMakeLists.txt108
-rw-r--r--makefile7
-rwxr-xr-xsrc/3rdParty/efsw/Atomic.hpp51
-rwxr-xr-xsrc/3rdParty/efsw/Debug.cpp81
-rwxr-xr-xsrc/3rdParty/efsw/Debug.hpp60
-rwxr-xr-xsrc/3rdParty/efsw/DirWatcherGeneric.cpp388
-rwxr-xr-xsrc/3rdParty/efsw/DirWatcherGeneric.hpp57
-rwxr-xr-xsrc/3rdParty/efsw/DirectorySnapshot.cpp212
-rwxr-xr-xsrc/3rdParty/efsw/DirectorySnapshot.hpp45
-rwxr-xr-xsrc/3rdParty/efsw/DirectorySnapshotDiff.cpp22
-rwxr-xr-xsrc/3rdParty/efsw/DirectorySnapshotDiff.hpp35
-rwxr-xr-xsrc/3rdParty/efsw/FileInfo.cpp240
-rwxr-xr-xsrc/3rdParty/efsw/FileInfo.hpp64
-rwxr-xr-xsrc/3rdParty/efsw/FileSystem.cpp118
-rwxr-xr-xsrc/3rdParty/efsw/FileSystem.hpp41
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcher.cpp119
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherCWrapper.cpp113
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherFSEvents.cpp240
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherFSEvents.hpp103
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherGeneric.cpp156
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherGeneric.hpp60
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherImpl.cpp23
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherImpl.hpp57
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherInotify.cpp599
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherInotify.hpp81
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherKqueue.cpp227
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherKqueue.hpp80
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherWin32.cpp257
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherWin32.hpp70
-rwxr-xr-xsrc/3rdParty/efsw/LICENSE22
-rwxr-xr-xsrc/3rdParty/efsw/Lock.hpp21
-rwxr-xr-xsrc/3rdParty/efsw/Log.cpp34
-rwxr-xr-xsrc/3rdParty/efsw/Mutex.cpp20
-rwxr-xr-xsrc/3rdParty/efsw/Mutex.hpp31
-rwxr-xr-xsrc/3rdParty/efsw/String.cpp669
-rwxr-xr-xsrc/3rdParty/efsw/String.hpp631
-rwxr-xr-xsrc/3rdParty/efsw/System.cpp22
-rwxr-xr-xsrc/3rdParty/efsw/System.hpp25
-rwxr-xr-xsrc/3rdParty/efsw/Thread.cpp40
-rwxr-xr-xsrc/3rdParty/efsw/Thread.hpp100
-rwxr-xr-xsrc/3rdParty/efsw/Utf.hpp721
-rwxr-xr-xsrc/3rdParty/efsw/Utf.inl576
-rwxr-xr-xsrc/3rdParty/efsw/Watcher.cpp10
-rwxr-xr-xsrc/3rdParty/efsw/Watcher.hpp29
-rwxr-xr-xsrc/3rdParty/efsw/WatcherFSEvents.cpp216
-rwxr-xr-xsrc/3rdParty/efsw/WatcherFSEvents.hpp66
-rwxr-xr-xsrc/3rdParty/efsw/WatcherGeneric.cpp33
-rwxr-xr-xsrc/3rdParty/efsw/WatcherGeneric.hpp29
-rwxr-xr-xsrc/3rdParty/efsw/WatcherInotify.cpp25
-rwxr-xr-xsrc/3rdParty/efsw/WatcherInotify.hpp26
-rwxr-xr-xsrc/3rdParty/efsw/WatcherKqueue.cpp569
-rwxr-xr-xsrc/3rdParty/efsw/WatcherKqueue.hpp97
-rwxr-xr-xsrc/3rdParty/efsw/WatcherWin32.cpp109
-rwxr-xr-xsrc/3rdParty/efsw/WatcherWin32.hpp74
-rwxr-xr-xsrc/3rdParty/efsw/base.hpp129
-rwxr-xr-xsrc/3rdParty/efsw/efsw.h151
-rwxr-xr-xsrc/3rdParty/efsw/efsw.hpp195
-rwxr-xr-xsrc/3rdParty/efsw/inotify-nosys.h164
-rwxr-xr-xsrc/3rdParty/efsw/platform/platformimpl.hpp20
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/FileSystemImpl.cpp251
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/FileSystemImpl.hpp30
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/MutexImpl.cpp28
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/MutexImpl.hpp30
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/SystemImpl.cpp168
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/SystemImpl.hpp25
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/ThreadImpl.cpp60
-rwxr-xr-xsrc/3rdParty/efsw/platform/posix/ThreadImpl.hpp36
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/FileSystemImpl.cpp111
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/FileSystemImpl.hpp31
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/MutexImpl.cpp25
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/MutexImpl.hpp33
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/SystemImpl.cpp46
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/SystemImpl.hpp25
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/ThreadImpl.cpp56
-rwxr-xr-xsrc/3rdParty/efsw/platform/win/ThreadImpl.hpp42
-rwxr-xr-xsrc/3rdParty/efsw/sophist.h147
-rw-r--r--src/yue.cpp164
-rw-r--r--win-build/Yuescript/Yuescript.vcxproj66
-rw-r--r--win-build/Yuescript/Yuescript.vcxproj.filters156
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)
31include_directories(src src/3rdParty ${LUA_INCLUDE_DIR}) 31include_directories(src src/3rdParty ${LUA_INCLUDE_DIR})
32add_definitions(-std=c++17 -O3 -fPIC) 32add_definitions(-std=c++17 -O3 -fPIC)
33 33
34add_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) 34add_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)
35set_target_properties(libyue PROPERTIES PREFIX "") 41set_target_properties(libyue PROPERTIES PREFIX "")
36set_target_properties(libyue PROPERTIES OUTPUT_NAME "yue") 42set_target_properties(libyue PROPERTIES OUTPUT_NAME "yue")
37target_link_libraries(libyue ${LUA_LIBRARIES}) 43target_link_libraries(libyue ${LUA_LIBRARIES})
38 44
45add_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
54target_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
74if (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 )
81else ()
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 )
88endif()
89
90if (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()
101elseif (WIN32)
102 target_sources(yue PRIVATE
103 src/3rdParty/efsw/FileWatcherWin32.cpp
104 src/3rdParty/efsw/WatcherWin32.cpp
105 )
106elseif (${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()
115elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
116 target_sources(yue PRIVATE
117 src/3rdParty/efsw/FileWatcherKqueue.cpp
118 src/3rdParty/efsw/WatcherKqueue.cpp
119 )
120endif()
121
122if (MSVC)
123 target_compile_definitions(yue PRIVATE _SCL_SECURE_NO_WARNINGS)
124else ()
125 target_compile_options(yue PRIVATE -Wall -Wno-long-long -fPIC)
126endif()
127
128if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
129 target_compile_definitions(yue PRIVATE DEBUG)
130elseif (${CMAKE_BUILD_TYPE} MATCHES "Release")
131 target_compile_definitions(yue PRIVATE NDEBUG)
132endif()
133
39find_package(Threads REQUIRED) 134find_package(Threads REQUIRED)
40add_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) 135if (APPLE)
41target_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)
138elseif (NOT (${CMAKE_SYSTEM_NAME} MATCHES "Haiku") AND NOT WIN32)
139 target_link_libraries(yue PRIVATE ${LUA_LIBRARIES} Threads::Threads)
140else ()
141 target_link_libraries(yue PRIVATE ${LUA_LIBRARIES})
142endif()
143
42IF(CMAKE_DL_LIBS) 144IF(CMAKE_DL_LIBS)
43 target_link_libraries(yue ${CMAKE_DL_LIBS}) 145 target_link_libraries(yue ${CMAKE_DL_LIBS})
44ENDIF(CMAKE_DL_LIBS) 146ENDIF(CMAKE_DL_LIBS)
diff --git a/makefile b/makefile
index cb1274b..43f39f1 100644
--- a/makefile
+++ b/makefile
@@ -59,6 +59,8 @@ endif
59ifneq ($(UNAME_S),Darwin) 59ifneq ($(UNAME_S),Darwin)
60 LINK_FLAGS += -lstdc++fs -Wl,-E 60 LINK_FLAGS += -lstdc++fs -Wl,-E
61 PLAT = linux 61 PLAT = linux
62else
63 LINK_FLAGS += -framework CoreFoundation -framework CoreServices
62endif 64endif
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),)
123endif 125endif
124 126
125SOURCES := $(filter-out $(SRC_PATH)/yue_wasm.cpp, $(SOURCES)) 127SOURCES := $(filter-out $(SRC_PATH)/yue_wasm.cpp, $(SOURCES))
128SOURCES := $(filter-out $(SRC_PATH)/3rdParty/%, $(SOURCES))
126 129
127ifeq ($(NO_LUA),true) 130ifeq ($(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
135DEPS = $(OBJECTS:.o=.d) 138DEPS = $(OBJECTS:.o=.d)
136 139
140SOURCES += $(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
138ifeq ($(UNAME_S),Darwin) 143ifeq ($(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
146else 152else
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
153endif 160endif
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
10namespace efsw {
11
12template <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
14namespace efsw {
15
16#ifdef DEBUG
17
18void 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
34void 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
55void 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
6namespace efsw {
7
8#ifdef DEBUG
9
10void 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
21void efPRINT( const char* format, ... );
22void 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
6namespace efsw {
7
8DirWatcherGeneric::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
29DirWatcherGeneric::~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
59void 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
83void 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
90void 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
138void 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
195void 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
205DirWatcherGeneric* 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
245DirWatcherGeneric* 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
263DirWatcherGeneric* 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
323void 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
349void 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
374bool 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
9namespace efsw {
10
11class 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
4namespace efsw {
5
6DirectorySnapshot::DirectorySnapshot() {}
7
8DirectorySnapshot::DirectorySnapshot( std::string directory ) {
9 init( directory );
10}
11
12DirectorySnapshot::~DirectorySnapshot() {}
13
14void DirectorySnapshot::init( std::string directory ) {
15 setDirectoryInfo( directory );
16 initFiles();
17}
18
19bool DirectorySnapshot::exists() {
20 return DirectoryInfo.exists();
21}
22
23void 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
39void DirectorySnapshot::setDirectoryInfo( std::string directory ) {
40 DirectoryInfo = FileInfo( directory );
41}
42
43void 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
62DirectorySnapshotDiff 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
174FileInfoMap::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
188void DirectorySnapshot::addFile( std::string path ) {
189 std::string name( FileSystem::fileNameFromPath( path ) );
190 Files[name] = FileInfo( path );
191}
192
193void 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
203void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath ) {
204 removeFile( oldPath );
205 addFile( newPath );
206}
207
208void 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
6namespace efsw {
7
8class 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
3namespace efsw {
4
5void 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
16bool 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
6namespace efsw {
7
8class 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
38namespace efsw {
39
40bool FileInfo::exists( const std::string& filePath ) {
41 FileInfo fi( filePath );
42 return fi.exists();
43}
44
45bool FileInfo::isLink( const std::string& filePath ) {
46 FileInfo fi( filePath, true );
47 return fi.isLink();
48}
49
50bool FileInfo::inodeSupported() {
51#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
52 return true;
53#else
54 return false;
55#endif
56}
57
58FileInfo::FileInfo() :
59 ModificationTime( 0 ), OwnerId( 0 ), GroupId( 0 ), Permissions( 0 ), Inode( 0 ) {}
60
61FileInfo::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
71FileInfo::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
85void 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
122void 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
151bool 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
157bool FileInfo::isDirectory() const {
158 return 0 != S_ISDIR( Permissions );
159}
160
161bool FileInfo::isRegularFile() const {
162 return 0 != S_ISREG( Permissions );
163}
164
165bool 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
174bool FileInfo::isLink() const {
175#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
176 return S_ISLNK( Permissions );
177#else
178 return false;
179#endif
180}
181
182std::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
199bool 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
221FileInfo& 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
232bool FileInfo::sameInode( const FileInfo& Other ) const {
233 return inodeSupported() && Inode == Other.Inode;
234}
235
236bool 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
9namespace efsw {
10
11class 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
58typedef std::map<std::string, FileInfo> FileInfoMap;
59typedef std::list<FileInfo> FileInfoList;
60typedef 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
8namespace efsw {
9
10bool FileSystem::isDirectory( const std::string& path ) {
11 return Platform::FileSystem::isDirectory( path );
12}
13
14FileInfoMap FileSystem::filesInfoFromPath( std::string path ) {
15 dirAddSlashAtEnd( path );
16
17 return Platform::FileSystem::filesInfoFromPath( path );
18}
19
20char FileSystem::getOSSlash() {
21 return Platform::FileSystem::getOSSlash();
22}
23
24bool FileSystem::slashAtEnd( std::string& dir ) {
25 return ( dir.size() && dir[dir.size() - 1] == getOSSlash() );
26}
27
28void FileSystem::dirAddSlashAtEnd( std::string& dir ) {
29 if ( dir.size() > 1 && dir[dir.size() - 1] != getOSSlash() ) {
30 dir.push_back( getOSSlash() );
31 }
32}
33
34void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) {
35 if ( dir.size() > 1 && dir[dir.size() - 1] == getOSSlash() ) {
36 dir.erase( dir.size() - 1 );
37 }
38}
39
40std::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
52std::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
64std::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
86std::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
106bool FileSystem::isRemoteFS( const std::string& directory ) {
107 return Platform::FileSystem::isRemoteFS( directory );
108}
109
110bool FileSystem::changeWorkingDirectory( const std::string& directory ) {
111 return Platform::FileSystem::changeWorkingDirectory( directory );
112}
113
114std::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
8namespace efsw {
9
10class 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
29namespace efsw {
30
31FileWatcher::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
45FileWatcher::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
66FileWatcher::~FileWatcher() {
67 efSAFE_DELETE( mImpl );
68}
69
70WatchID 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
78WatchID 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
87void FileWatcher::removeWatch( const std::string& directory ) {
88 mImpl->removeWatch( directory );
89}
90
91void FileWatcher::removeWatch( WatchID watchid ) {
92 mImpl->removeWatch( watchid );
93}
94
95void FileWatcher::watch() {
96 mImpl->watch();
97}
98
99std::list<std::string> FileWatcher::directories() {
100 return mImpl->directories();
101}
102
103void FileWatcher::followSymlinks( bool follow ) {
104 mFollowSymlinks = follow;
105}
106
107const bool& FileWatcher::followSymlinks() const {
108 return mFollowSymlinks;
109}
110
111void FileWatcher::allowOutOfScopeLinks( bool allow ) {
112 mOutOfScopeLinks = allow;
113}
114
115const 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/*************************************************************************************************/
8class 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 */
29static std::vector<Watcher_CAPI*> g_callbacks;
30
31Watcher_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
43Watcher_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/*************************************************************************************************/
59efsw_watcher efsw_create( int generic_mode ) {
60 return ( efsw_watcher ) new efsw::FileWatcher( TOBOOL( generic_mode ) );
61}
62
63void efsw_release( efsw_watcher watcher ) {
64 remove_callback( watcher );
65 delete (efsw::FileWatcher*)watcher;
66}
67
68const char* efsw_getlasterror() {
69 static std::string log_str;
70 log_str = efsw::Errors::Log::getLastErrorLog();
71 return log_str.c_str();
72}
73
74efsw_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
87void efsw_removewatch( efsw_watcher watcher, const char* directory ) {
88 ( (efsw::FileWatcher*)watcher )->removeWatch( std::string( directory ) );
89}
90
91void efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid ) {
92 ( (efsw::FileWatcher*)watcher )->removeWatch( watchid );
93}
94
95void efsw_watch( efsw_watcher watcher ) {
96 ( (efsw::FileWatcher*)watcher )->watch();
97}
98
99void efsw_follow_symlinks( efsw_watcher watcher, int enable ) {
100 ( (efsw::FileWatcher*)watcher )->followSymlinks( TOBOOL( enable ) );
101}
102
103int efsw_follow_symlinks_isenabled( efsw_watcher watcher ) {
104 return (int)( (efsw::FileWatcher*)watcher )->followSymlinks();
105}
106
107void efsw_allow_outofscopelinks( efsw_watcher watcher, int allow ) {
108 ( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks( TOBOOL( allow ) );
109}
110
111int 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
12namespace efsw {
13
14int 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
40bool FileWatcherFSEvents::isGranular() {
41 return getOSXReleaseNumber() >= 11;
42}
43
44void 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
65FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) :
66 FileWatcherImpl( parent ), mRunLoopRef( NULL ), mLastWatchID( 0 ), mThread( NULL ) {
67 mInitOK = true;
68
69 watch();
70}
71
72FileWatcherFSEvents::~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
91WatchID 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
147void 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
160void 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
177void FileWatcherFSEvents::watch() {
178 if ( NULL == mThread ) {
179 mThread = new Thread( &FileWatcherFSEvents::run, this );
180 mThread->launch();
181 }
182}
183
184void 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
211void FileWatcherFSEvents::handleAction( Watcher* watch, const std::string& filename,
212 unsigned long action, std::string oldFilename ) {
213 /// Not used
214}
215
216std::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
228bool 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
15namespace efsw {
16
17/* OSX < 10.7 has no file events */
18/* So i declare the events constants */
19enum 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
39class 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
6namespace efsw {
7
8FileWatcherGeneric::FileWatcherGeneric( FileWatcher* parent ) :
9 FileWatcherImpl( parent ), mThread( NULL ), mLastWatchID( 0 ) {
10 mInitOK = true;
11 mIsGeneric = true;
12}
13
14FileWatcherGeneric::~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
27WatchID 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
66void 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
84void 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
102void FileWatcherGeneric::watch() {
103 if ( NULL == mThread ) {
104 mThread = new Thread( &FileWatcherGeneric::run, this );
105 mThread->launch();
106 }
107}
108
109void 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
126void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned long, std::string ) {
127 /// Not used
128}
129
130std::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
144bool 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
9namespace efsw {
10
11/// Implementation for Generic File Watcher.
12/// @class FileWatcherGeneric
13class 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
5namespace efsw {
6
7FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) :
8 mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) {
9 System::maxFD();
10}
11
12FileWatcherImpl::~FileWatcherImpl() {}
13
14bool FileWatcherImpl::initOK() {
15 return static_cast<bool>( mInitOK );
16}
17
18bool 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
11namespace efsw {
12
13class 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
26namespace efsw {
27
28FileWatcherInotify::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
39FileWatcherInotify::~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
63WatchID 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
71WatchID 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
162void 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
213void 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
268void 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
283void FileWatcherInotify::watch() {
284 if ( NULL == mThread ) {
285 mThread = new Thread( &FileWatcherInotify::run, this );
286 mThread->launch();
287 }
288}
289
290Watcher* 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
307void 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
468void 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
494void 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
568std::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
582bool 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
12namespace efsw {
13
14/// Implementation for Linux based on inotify.
15/// @class FileWatcherInotify
16class 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
20namespace efsw {
21
22FileWatcherKqueue::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
33FileWatcherKqueue::~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
47WatchID 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
131void 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
144void 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
159bool FileWatcherKqueue::isAddingWatcher() const {
160 return mAddingWatcher;
161}
162
163void FileWatcherKqueue::watch() {
164 if ( NULL == mThread ) {
165 mThread = new Thread( &FileWatcherKqueue::run, this );
166 mThread->launch();
167 }
168}
169
170void 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
184void FileWatcherKqueue::handleAction( Watcher* watch, const std::string& filename,
185 unsigned long action, std::string oldFilename ) {}
186
187std::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
201bool 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
213void FileWatcherKqueue::addFD() {
214 mFileDescriptorCount++;
215}
216
217void FileWatcherKqueue::removeFD() {
218 mFileDescriptorCount--;
219}
220
221bool 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
10namespace efsw {
11
12/// Implementation for OSX based on kqueue.
13/// @class FileWatcherKqueue
14class 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
9namespace efsw {
10
11FileWatcherWin32::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
18FileWatcherWin32::~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
32WatchID 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
76void 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
89void 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
103void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) {
104 Lock lock( mWatchesLock );
105
106 DestroyWatch( watch );
107 mWatches.erase( watch );
108}
109
110void FileWatcherWin32::watch() {
111 if ( NULL == mThread ) {
112 mThread = new Thread( &FileWatcherWin32::run, this );
113 mThread->launch();
114 }
115}
116
117void 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
129void 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
154void 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
231std::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
243bool 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
13namespace efsw {
14
15/// Implementation for Win32 based on ReadDirectoryChangesW.
16/// @class FileWatcherWin32
17class 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 @@
1Copyright (c) 2020 Martín Lucas Golini
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE.
20
21This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com)
22http://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
6namespace efsw {
7
8/** Simple mutex class */
9class 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
3namespace efsw { namespace Errors {
4
5static std::string LastError;
6
7std::string Log::getLastErrorLog() {
8 return LastError;
9}
10
11Error 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
4namespace efsw {
5
6Mutex::Mutex() : mMutexImpl( new Platform::MutexImpl() ) {}
7
8Mutex::~Mutex() {
9 efSAFE_DELETE( mMutexImpl );
10}
11
12void Mutex::lock() {
13 mMutexImpl->lock();
14}
15
16void 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
6namespace efsw {
7
8namespace Platform {
9class MutexImpl;
10}
11
12/** Simple mutex class */
13class 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
5namespace efsw {
6
7const std::size_t String::InvalidPos = StringType::npos;
8
9std::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
32std::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
55int 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
73int 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
91String::String() {}
92
93String::String( char ansiChar, const std::locale& locale ) {
94 mString += Utf32::DecodeAnsi( ansiChar, locale );
95}
96
97#ifndef EFSW_NO_WIDECHAR
98String::String( wchar_t wideChar ) {
99 mString += Utf32::DecodeWide( wideChar );
100}
101#endif
102
103String::String( StringBaseType utf32Char ) {
104 mString += utf32Char;
105}
106
107String::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
119String::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
125String::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
136String::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
142String::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
152String::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
158String::String( const StringBaseType* utf32String ) {
159 if ( utf32String )
160 mString = utf32String;
161}
162
163String::String( const StringType& utf32String ) : mString( utf32String ) {}
164
165String::String( const String& str ) : mString( str.mString ) {}
166
167String 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
177String::operator std::string() const {
178 return toAnsiString();
179}
180
181std::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
193std::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
205std::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
216String& String::operator=( const String& right ) {
217 mString = right.mString;
218 return *this;
219}
220
221String& String::operator=( const StringBaseType& right ) {
222 mString = right;
223 return *this;
224}
225
226String& String::operator+=( const String& right ) {
227 mString += right.mString;
228 return *this;
229}
230
231String& String::operator+=( const StringBaseType& right ) {
232 mString += right;
233 return *this;
234}
235
236String::StringBaseType String::operator[]( std::size_t index ) const {
237 return mString[index];
238}
239
240String::StringBaseType& String::operator[]( std::size_t index ) {
241 return mString[index];
242}
243
244String::StringBaseType String::at( std::size_t index ) const {
245 return mString.at( index );
246}
247
248void String::push_back( StringBaseType c ) {
249 mString.push_back( c );
250}
251
252void String::swap( String& str ) {
253 mString.swap( str.mString );
254}
255
256void String::clear() {
257 mString.clear();
258}
259
260std::size_t String::size() const {
261 return mString.size();
262}
263
264std::size_t String::length() const {
265 return mString.length();
266}
267
268bool String::empty() const {
269 return mString.empty();
270}
271
272void String::erase( std::size_t position, std::size_t count ) {
273 mString.erase( position, count );
274}
275
276String& String::insert( std::size_t position, const String& str ) {
277 mString.insert( position, str.mString );
278 return *this;
279}
280
281String& 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
286String& 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
294String& String::insert( size_t pos1, size_t n, char c ) {
295 mString.insert( pos1, n, c );
296 return *this;
297}
298
299String& 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
307String::Iterator String::insert( Iterator p, char c ) {
308 return mString.insert( p, c );
309}
310
311void String::insert( Iterator p, size_t n, char c ) {
312 mString.insert( p, n, c );
313}
314
315const String::StringBaseType* String::c_str() const {
316 return mString.c_str();
317}
318
319const String::StringBaseType* String::data() const {
320 return mString.data();
321}
322
323String::Iterator String::begin() {
324 return mString.begin();
325}
326
327String::ConstIterator String::begin() const {
328 return mString.begin();
329}
330
331String::Iterator String::end() {
332 return mString.end();
333}
334
335String::ConstIterator String::end() const {
336 return mString.end();
337}
338
339String::ReverseIterator String::rbegin() {
340 return mString.rbegin();
341}
342
343String::ConstReverseIterator String::rbegin() const {
344 return mString.rbegin();
345}
346
347String::ReverseIterator String::rend() {
348 return mString.rend();
349}
350
351String::ConstReverseIterator String::rend() const {
352 return mString.rend();
353}
354
355void String::resize( std::size_t n, StringBaseType c ) {
356 mString.resize( n, c );
357}
358
359void String::resize( std::size_t n ) {
360 mString.resize( n );
361}
362
363std::size_t String::max_size() const {
364 return mString.max_size();
365}
366
367void String::reserve( size_t res_arg ) {
368 mString.reserve( res_arg );
369}
370
371std::size_t String::capacity() const {
372 return mString.capacity();
373}
374
375String& String::assign( const String& str ) {
376 mString.assign( str.mString );
377 return *this;
378}
379
380String& String::assign( const String& str, size_t pos, size_t n ) {
381 mString.assign( str.mString, pos, n );
382 return *this;
383}
384
385String& String::assign( const char* s, size_t n ) {
386 String tmp( s );
387
388 mString.assign( tmp.mString );
389
390 return *this;
391}
392
393String& String::assign( const char* s ) {
394 String tmp( s );
395
396 mString.assign( tmp.mString );
397
398 return *this;
399}
400
401String& String::assign( size_t n, char c ) {
402 mString.assign( n, c );
403
404 return *this;
405}
406
407String& String::append( const String& str ) {
408 mString.append( str.mString );
409
410 return *this;
411}
412
413String& String::append( const String& str, size_t pos, size_t n ) {
414 mString.append( str.mString, pos, n );
415
416 return *this;
417}
418
419String& String::append( const char* s, size_t n ) {
420 String tmp( s );
421
422 mString.append( tmp.mString );
423
424 return *this;
425}
426
427String& String::append( const char* s ) {
428 String tmp( s );
429
430 mString.append( tmp.mString );
431
432 return *this;
433}
434
435String& String::append( size_t n, char c ) {
436 mString.append( n, c );
437
438 return *this;
439}
440
441String& String::append( std::size_t n, StringBaseType c ) {
442 mString.append( n, c );
443
444 return *this;
445}
446
447String& String::replace( size_t pos1, size_t n1, const String& str ) {
448 mString.replace( pos1, n1, str.mString );
449
450 return *this;
451}
452
453String& String::replace( Iterator i1, Iterator i2, const String& str ) {
454 mString.replace( i1, i2, str.mString );
455
456 return *this;
457}
458
459String& 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
465String& 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
473String& 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
481String& 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
489String& 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
497String& 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
503String& 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
509std::size_t String::find( const String& str, std::size_t start ) const {
510 return mString.find( str.mString, start );
511}
512
513std::size_t String::find( const char* s, std::size_t pos, std::size_t n ) const {
514 return find( String( s ), pos );
515}
516
517std::size_t String::find( const char* s, std::size_t pos ) const {
518 return find( String( s ), pos );
519}
520
521size_t String::find( char c, std::size_t pos ) const {
522 return mString.find( (StringBaseType)c, pos );
523}
524
525std::size_t String::rfind( const String& str, std::size_t pos ) const {
526 return mString.rfind( str.mString, pos );
527}
528
529std::size_t String::rfind( const char* s, std::size_t pos, std::size_t n ) const {
530 return rfind( String( s ), pos );
531}
532
533std::size_t String::rfind( const char* s, std::size_t pos ) const {
534 return rfind( String( s ), pos );
535}
536
537std::size_t String::rfind( char c, std::size_t pos ) const {
538 return mString.rfind( c, pos );
539}
540
541std::size_t String::copy( StringBaseType* s, std::size_t n, std::size_t pos ) const {
542 return mString.copy( s, n, pos );
543}
544
545String String::substr( std::size_t pos, std::size_t n ) const {
546 return String( mString.substr( pos, n ) );
547}
548
549int String::compare( const String& str ) const {
550 return mString.compare( str.mString );
551}
552
553int String::compare( const char* s ) const {
554 return compare( String( s ) );
555}
556
557int String::compare( std::size_t pos1, std::size_t n1, const String& str ) const {
558 return mString.compare( pos1, n1, str.mString );
559}
560
561int String::compare( std::size_t pos1, std::size_t n1, const char* s ) const {
562 return compare( pos1, n1, String( s ) );
563}
564
565int 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
570int 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
574std::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
578std::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
582std::size_t String::find_first_of( const char* s, std::size_t pos ) const {
583 return find_first_of( String( s ), pos );
584}
585
586std::size_t String::find_first_of( StringBaseType c, std::size_t pos ) const {
587 return mString.find_first_of( c, pos );
588}
589
590std::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
594std::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
598std::size_t String::find_last_of( const char* s, std::size_t pos ) const {
599 return find_last_of( String( s ), pos );
600}
601
602std::size_t String::find_last_of( StringBaseType c, std::size_t pos ) const {
603 return mString.find_last_of( c, pos );
604}
605
606std::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
610std::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
614std::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
618std::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
622std::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
626std::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
630std::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
634std::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
638bool operator==( const String& left, const String& right ) {
639 return left.mString == right.mString;
640}
641
642bool operator!=( const String& left, const String& right ) {
643 return !( left == right );
644}
645
646bool operator<( const String& left, const String& right ) {
647 return left.mString < right.mString;
648}
649
650bool operator>( const String& left, const String& right ) {
651 return right < left;
652}
653
654bool operator<=( const String& left, const String& right ) {
655 return !( right < left );
656}
657
658bool operator>=( const String& left, const String& right ) {
659 return !( left < right );
660}
661
662String 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
21namespace efsw {
22
23/** @brief Utility string class that automatically handles conversions between types and encodings
24 * **/
25class 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**/
535bool 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**/
543bool 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**/
551bool 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**/
559bool 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**/
567bool 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**/
575bool 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**/
583String 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
4namespace efsw {
5
6void System::sleep( const unsigned long& ms ) {
7 Platform::System::sleep( ms );
8}
9
10std::string System::getProcessPath() {
11 return Platform::System::getProcessPath();
12}
13
14void System::maxFD() {
15 Platform::System::maxFD();
16}
17
18Uint64 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
6namespace efsw {
7
8class 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
4namespace efsw {
5
6Thread::Thread() : mThreadImpl( NULL ), mEntryPoint( NULL ) {}
7
8Thread::~Thread() {
9 wait();
10
11 efSAFE_DELETE( mEntryPoint );
12}
13
14void Thread::launch() {
15 wait();
16
17 mThreadImpl = new Platform::ThreadImpl( this );
18}
19
20void Thread::wait() {
21 if ( mThreadImpl ) {
22 mThreadImpl->wait();
23
24 efSAFE_DELETE( mThreadImpl );
25 }
26}
27
28void Thread::terminate() {
29 if ( mThreadImpl ) {
30 mThreadImpl->terminate();
31
32 efSAFE_DELETE( mThreadImpl );
33 }
34}
35
36void 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
6namespace efsw {
7
8namespace Platform {
9class ThreadImpl;
10}
11namespace Private {
12struct ThreadFunc;
13}
14
15/** @brief Thread manager class */
16class 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
51namespace Private {
52
53// Base class for abstract thread functions
54struct ThreadFunc {
55 virtual ~ThreadFunc() {}
56 virtual void run() = 0;
57};
58
59// Specialization using a functor (including free functions) with no argument
60template <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
67template <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
75template <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
85template <typename F>
86Thread::Thread( F functor ) :
87 mThreadImpl( NULL ), mEntryPoint( new Private::ThreadFunctor<F>( functor ) ) {}
88
89template <typename F, typename A>
90Thread::Thread( F function, A argument ) :
91 mThreadImpl( NULL ),
92 mEntryPoint( new Private::ThreadFunctorWithArg<F efCOMMA A>( function, argument ) ) {}
93
94template <typename C>
95Thread::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
18namespace efsw {
19
20template <unsigned int N> class Utf;
21
22////////////////////////////////////////////////////////////
23/// \brief Specialization of the Utf template for UTF-8
24///
25////////////////////////////////////////////////////////////
26template <> 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////////////////////////////////////////////////////////////
226template <> 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////////////////////////////////////////////////////////////
426template <> 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
695typedef Utf<8> Utf8;
696typedef Utf<16> Utf16;
697typedef 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
8template <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
56template <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
112template <typename In> In Utf<8>::Next( In begin, In end ) {
113 Uint32 codepoint;
114 return Decode( begin, end, codepoint );
115}
116
117template <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
127template <typename In, typename Out>
128Out 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
137template <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
146template <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
155template <typename In, typename Out>
156Out 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
167template <typename In, typename Out>
168Out 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
179template <typename In, typename Out>
180Out 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
192template <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
199template <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
209template <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
219template <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
247template <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
272template <typename In> In Utf<16>::Next( In begin, In end ) {
273 Uint32 codepoint;
274 return Decode( begin, end, codepoint );
275}
276
277template <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
287template <typename In, typename Out>
288Out 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
297template <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
306template <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
315template <typename In, typename Out>
316Out 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
327template <typename In, typename Out>
328Out 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
339template <typename In, typename Out>
340Out 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
351template <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
361template <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
368template <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
378template <typename In> In Utf<32>::Decode( In begin, In end, Uint32& output, Uint32 ) {
379 output = *begin++;
380 return begin;
381}
382
383template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 replacement ) {
384 *output++ = input;
385 return output;
386}
387
388template <typename In> In Utf<32>::Next( In begin, In end ) {
389 return ++begin;
390}
391
392template <typename In> std::size_t Utf<32>::Count( In begin, In end ) {
393 return begin - end;
394}
395
396template <typename In, typename Out>
397Out 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
404template <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
411template <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
420template <typename In, typename Out>
421Out 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
429template <typename In, typename Out>
430Out 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
438template <typename In, typename Out>
439Out 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
450template <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
457template <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
464template <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
471template <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
501template <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
511template <typename Out>
512Out 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
550template <typename Out>
551Out 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
3namespace efsw {
4
5Watcher::Watcher() : ID( 0 ), Directory( "" ), Listener( NULL ), Recursive( false ) {}
6
7Watcher::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
7namespace efsw {
8
9/** @brief Base Watcher class */
10class 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
8namespace efsw {
9
10WatcherFSEvents::WatcherFSEvents() :
11 Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ), initializedAsync( false ) {}
12
13WatcherFSEvents::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
21WatcherFSEvents::~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
34void 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
66void WatcherFSEvents::initAsync() {
67 FSEventStreamScheduleWithRunLoop( FSStream, FWatcher.load()->mRunLoopRef.load(),
68 kCFRunLoopDefaultMode );
69 FSEventStreamStart( FSStream );
70 initializedAsync = true;
71}
72
73void 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
80void 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
101void 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
199void 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
15namespace efsw {
16
17class FileWatcherFSEvents;
18
19class 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
28class 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
5namespace efsw {
6
7WatcherGeneric::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
17WatcherGeneric::~WatcherGeneric() {
18 efSAFE_DELETE( DirWatch );
19}
20
21void WatcherGeneric::watch() {
22 DirWatch->watch();
23}
24
25void WatcherGeneric::watchDir( std::string dir ) {
26 DirWatch->watchDir( dir );
27}
28
29bool 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
6namespace efsw {
7
8class DirWatcherGeneric;
9
10class 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
3namespace efsw {
4
5WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {}
6
7WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener,
8 bool recursive, WatcherInotify* parent ) :
9 Watcher( id, directory, listener, recursive ), Parent( parent ), DirInfo( directory ) {}
10
11bool 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
7namespace efsw {
8
9class 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
26namespace efsw {
27
28int 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
42WatcherKqueue::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
65WatcherKqueue::~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
82void 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
139void 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
155void 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
206void 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
253void 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
311WatchID 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
321void 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
327void 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
334void WatcherKqueue::sendDirChanged() {
335 if ( NULL != mParent ) {
336 Listener->handleFileAction( mParent->ID, mParent->Directory,
337 FileSystem::fileNameFromPath( Directory ), Actions::Modified );
338 }
339}
340
341void 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
409Watcher* 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
421void 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
437WatchID 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
520bool WatcherKqueue::initOK() {
521 return mInitOK;
522}
523
524void 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
537bool WatcherKqueue::pathInWatches( const std::string& path ) {
538 return NULL != findWatcher( path );
539}
540
541bool 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
563int 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
14namespace efsw {
15
16class FileWatcherKqueue;
17class WatcherKqueue;
18
19typedef struct kevent KEvent;
20
21/// type for a map from WatchID to WatcherKqueue pointer
22typedef std::map<WatchID, Watcher*> WatchMap;
23
24class 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
6namespace efsw {
7
8/// Unpacks events and passes them to a user defined callback.
9void 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.
57bool 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.
65void 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.
77WatcherStructWin32* 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
20namespace efsw {
21
22class WatcherWin32;
23
24/// Internal watch data
25struct WatcherStructWin32 {
26 OVERLAPPED Overlapped;
27 WatcherWin32* Watch;
28};
29
30struct sLastModifiedEvent {
31 FileInfo file;
32 std::string fileName;
33};
34
35bool RefreshWatch( WatcherStructWin32* pWatch );
36
37void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped );
38
39void DestroyWatch( WatcherStructWin32* pWatch );
40
41WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter,
42 HANDLE iocp );
43
44class 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
7namespace efsw {
8
9typedef SOPHIST_int8 Int8;
10typedef SOPHIST_uint8 Uint8;
11typedef SOPHIST_int16 Int16;
12typedef SOPHIST_uint16 Uint16;
13typedef SOPHIST_int32 Int32;
14typedef SOPHIST_uint32 Uint32;
15typedef SOPHIST_int64 Int64;
16typedef 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
32extern "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
63typedef long efsw_watchid;
64
65/// Type for watcher
66typedef void* efsw_watcher;
67
68enum 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
76enum 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.
87typedef 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 */
101efsw_watcher EFSW_API efsw_create(int generic_mode);
102
103/// Release the file-watcher and unwatch any directories
104void EFSW_API efsw_release(efsw_watcher watcher);
105
106/// Retreive last error occured by file-watcher
107EFSW_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.
112efsw_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).
116void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory);
117
118/// Remove a directory watch. This is a map lookup O(logn).
119void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid);
120
121/// Starts watching ( in other thread )
122void 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 */
128void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable);
129
130/** @return If can follow symbolic links to directorioes */
131int 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 */
142void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow);
143
144/// @return Returns if out of scope links are allowed
145int 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
63namespace efsw {
64
65/// Type for a watch id
66typedef long WatchID;
67
68// forward declarations
69class FileWatcherImpl;
70class 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.
75namespace Actions {
76enum 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}
87typedef Actions::Action Action;
88
89/// Errors log namespace
90namespace Errors {
91
92enum 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
102class 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
112typedef 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
117class 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
178class 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 */
14struct 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
148static inline int inotify_init (void)
149{
150 return syscall (__NR_inotify_init);
151}
152
153static 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
158static 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
59namespace efsw { namespace Platform {
60
61#if EFSW_OS == EFSW_OS_LINUX
62
63std::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
106done:
107 FileSystem::changeWorkingDirectory( cwd );
108
109 return mp;
110}
111
112std::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
138bool 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
154bool FileSystem::changeWorkingDirectory( const std::string& path ) {
155 return -1 != chdir( path.c_str() );
156}
157
158std::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
164FileInfoMap 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
187char FileSystem::getOSSlash() {
188 return '/';
189}
190
191bool 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
202bool 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
9namespace efsw { namespace Platform {
10
11class 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
5namespace efsw { namespace Platform {
6
7MutexImpl::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
14MutexImpl::~MutexImpl() {
15 pthread_mutex_destroy( &mMutex );
16}
17
18void MutexImpl::lock() {
19 pthread_mutex_lock( &mMutex );
20}
21
22void 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
10namespace efsw { namespace Platform {
11
12class 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
28namespace efsw { namespace Platform {
29
30void 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
67std::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
137void 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
154Uint64 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
8namespace efsw { namespace Platform {
9
10class 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
10namespace efsw { namespace Platform {
11
12ThreadImpl::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
20void 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
31void 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
43void* 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
10namespace efsw {
11
12class Thread;
13
14namespace Platform {
15
16class 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
17namespace efsw { namespace Platform {
18
19bool 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
33std::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
50FileInfoMap 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
87char FileSystem::getOSSlash() {
88 return '\\';
89}
90
91bool 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
96bool 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
10namespace efsw { namespace Platform {
11
12class 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
5namespace efsw { namespace Platform {
6
7MutexImpl::MutexImpl() {
8 InitializeCriticalSection( &mMutex );
9}
10
11MutexImpl::~MutexImpl() {
12 DeleteCriticalSection( &mMutex );
13}
14
15void MutexImpl::lock() {
16 EnterCriticalSection( &mMutex );
17}
18
19void 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
13namespace efsw { namespace Platform {
14
15class 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
12namespace efsw { namespace Platform {
13
14void System::sleep( const unsigned long& ms ) {
15 ::Sleep( ms );
16}
17
18std::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
38void System::maxFD() {}
39
40Uint64 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
8namespace efsw { namespace Platform {
9
10class 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
9namespace efsw { namespace Platform {
10
11ThreadImpl::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
20ThreadImpl::~ThreadImpl() {
21 if ( mThread ) {
22 CloseHandle( mThread );
23 }
24}
25
26void 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
35void ThreadImpl::terminate() {
36 if ( mThread ) {
37 TerminateThread( mThread, 0 );
38 }
39}
40
41unsigned 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
14namespace efsw {
15
16class Thread;
17
18namespace Platform {
19
20class 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 */
36typedef signed char SOPHIST_int8;
37typedef unsigned char SOPHIST_uint8;
38
39typedef signed short SOPHIST_int16;
40typedef 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
90SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1);
91SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2);
92SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4);
93SOPHIST_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
126SOPHIST_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>
22using namespace std::string_view_literals; 24using namespace std::string_view_literals;
23using namespace std::string_literals; 25using namespace std::string_literals;
26using 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
89static const char luaminifyCodes[] = 93static const char luaminifyCodes[] =
90#include "LuaMinify.h" 94#include "LuaMinify.h"
91 95//
92 static void pushLuaminify(lua_State * L) { 96static 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
107fs::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
120fs::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
140static 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
194class UpdateListener : public efsw::FileWatchListener {
195public:
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
103int main(int narg, const char** args) { 227int 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