aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/outputs/5.1/attrib.lua210
-rw-r--r--spec/outputs/5.1/try_catch.lua6
-rw-r--r--spec/outputs/assign.lua6
-rw-r--r--spec/outputs/attrib.lua18
-rw-r--r--spec/outputs/do.lua6
-rw-r--r--spec/outputs/syntax.lua8
-rw-r--r--spec/outputs/try_catch.lua6
-rw-r--r--spec/outputs/unicode/assign.lua6
-rw-r--r--spec/outputs/unicode/attrib.lua18
-rw-r--r--spec/outputs/unicode/do.lua6
-rw-r--r--spec/outputs/unicode/macro.lua113
-rw-r--r--spec/outputs/unicode/syntax.lua8
-rw-r--r--spec/outputs/unicode/try_catch.lua10
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Atomic.hpp18
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Debug.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Debug.hpp6
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/DirWatcherGeneric.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/DirWatcherGeneric.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/DirectorySnapshot.cpp4
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/DirectorySnapshot.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/DirectorySnapshotDiff.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/DirectorySnapshotDiff.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileInfo.cpp14
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileInfo.hpp10
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileSystem.cpp59
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileSystem.hpp4
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcher.cpp239
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherCWrapper.cpp26
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherFSEvents.cpp114
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherFSEvents.hpp49
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherGeneric.cpp8
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherGeneric.hpp19
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherImpl.cpp57
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherImpl.hpp121
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherInotify.cpp140
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherInotify.hpp22
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherKqueue.cpp8
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherKqueue.hpp17
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherWin32.cpp524
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherWin32.hpp141
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/LICENSE0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Lock.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Log.cpp19
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Mutex.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Mutex.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/String.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/String.hpp3
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/System.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/System.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Thread.cpp3
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Thread.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Utf.hpp1442
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Utf.inl1152
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Watcher.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/Watcher.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherFSEvents.cpp80
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherFSEvents.hpp47
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherGeneric.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherGeneric.hpp2
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherInotify.cpp4
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherInotify.hpp4
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherKqueue.cpp15
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherKqueue.hpp2
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherWin32.cpp214
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/WatcherWin32.hpp25
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/base.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/efsw.h175
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/efsw.hpp456
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/inotify-nosys.h0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/platformimpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/MutexImpl.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/MutexImpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/SystemImpl.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/SystemImpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/ThreadImpl.cpp17
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/posix/ThreadImpl.hpp7
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/FileSystemImpl.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/FileSystemImpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/MutexImpl.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/MutexImpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/SystemImpl.cpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/SystemImpl.hpp0
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/ThreadImpl.cpp2
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/platform/win/ThreadImpl.hpp2
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/sophist.h294
-rw-r--r--src/yuescript/yue_ast.h1
-rw-r--r--src/yuescript/yue_compiler.cpp12
89 files changed, 3270 insertions, 2729 deletions
diff --git a/spec/outputs/5.1/attrib.lua b/spec/outputs/5.1/attrib.lua
index dc1285c..bda24bc 100644
--- a/spec/outputs/5.1/attrib.lua
+++ b/spec/outputs/5.1/attrib.lua
@@ -5,12 +5,36 @@ do
5 return print("closed") 5 return print("closed")
6 end 6 end
7 }) 7 })
8 local _close_0 = assert(getmetatable(a).__close) 8 local _close_0
9 local _close_1 = assert(getmetatable(b).__close); 9 if (function()
10 local _val_0 = type(a)
11 return 'table' == _val_0 or 'userdata' == _val_0
12 end)() then
13 _close_0 = assert(getmetatable(a) and getmetatable(a).__close, "variable 'a' got a non-closable value")
14 elseif a == nil then
15 _close_0 = nil
16 else
17 _close_0 = error("variable 'a' got a non-closable value")
18 end
19 local _close_1
20 if (function()
21 local _val_0 = type(b)
22 return 'table' == _val_0 or 'userdata' == _val_0
23 end)() then
24 _close_1 = assert(getmetatable(b) and getmetatable(b).__close, "variable 'b' got a non-closable value")
25 elseif b == nil then
26 _close_1 = nil
27 else
28 _close_1 = error("variable 'b' got a non-closable value")
29 end
10 (function(_arg_0, ...) 30 (function(_arg_0, ...)
11 local _ok_0 = _arg_0 31 local _ok_0 = _arg_0
12 _close_1(b) 32 if _close_1 ~= nil then
13 _close_0(a) 33 _close_1(b)
34 end
35 if _close_0 ~= nil then
36 _close_0(a)
37 end
14 if _ok_0 then 38 if _ok_0 then
15 return ... 39 return ...
16 else 40 else
@@ -53,10 +77,22 @@ do
53 __close = function(self) end 77 __close = function(self) end
54 }) 78 })
55 end 79 end
56 local _close_0 = assert(getmetatable(v).__close); 80 local _close_0
81 if (function()
82 local _val_0 = type(v)
83 return 'table' == _val_0 or 'userdata' == _val_0
84 end)() then
85 _close_0 = assert(getmetatable(v) and getmetatable(v).__close, "variable 'v' got a non-closable value")
86 elseif v == nil then
87 _close_0 = nil
88 else
89 _close_0 = error("variable 'v' got a non-closable value")
90 end
57 (function(_arg_0, ...) 91 (function(_arg_0, ...)
58 local _ok_0 = _arg_0 92 local _ok_0 = _arg_0
59 _close_0(v) 93 if _close_0 ~= nil then
94 _close_0(v)
95 end
60 if _ok_0 then 96 if _ok_0 then
61 return ... 97 return ...
62 else 98 else
@@ -69,10 +105,22 @@ do
69 _with_0:write("Hello") 105 _with_0:write("Hello")
70 f = _with_0 106 f = _with_0
71 end 107 end
72 local _close_1 = assert(getmetatable(f).__close) 108 local _close_1
109 if (function()
110 local _val_0 = type(f)
111 return 'table' == _val_0 or 'userdata' == _val_0
112 end)() then
113 _close_1 = assert(getmetatable(f) and getmetatable(f).__close, "variable 'f' got a non-closable value")
114 elseif f == nil then
115 _close_1 = nil
116 else
117 _close_1 = error("variable 'f' got a non-closable value")
118 end
73 return (function(_arg_0, ...) 119 return (function(_arg_0, ...)
74 local _ok_0 = _arg_0 120 local _ok_0 = _arg_0
75 _close_1(f) 121 if _close_1 ~= nil then
122 _close_1(f)
123 end
76 if _ok_0 then 124 if _ok_0 then
77 return ... 125 return ...
78 else 126 else
@@ -88,14 +136,28 @@ do
88 end 136 end
89 local b 137 local b
90 if not false then 138 if not false then
91 if x then 139 b = ((function()
92 b = 1 140 if x then
93 end 141 return 1
142 end
143 end)())
144 end
145 local _close_0
146 if (function()
147 local _val_0 = type(b)
148 return 'table' == _val_0 or 'userdata' == _val_0
149 end)() then
150 _close_0 = assert(getmetatable(b) and getmetatable(b).__close, "variable 'b' got a non-closable value")
151 elseif b == nil then
152 _close_0 = nil
153 else
154 _close_0 = error("variable 'b' got a non-closable value")
94 end 155 end
95 local _close_0 = assert(getmetatable(b).__close);
96 (function(_arg_0, ...) 156 (function(_arg_0, ...)
97 local _ok_0 = _arg_0 157 local _ok_0 = _arg_0
98 _close_0(b) 158 if _close_0 ~= nil then
159 _close_0(b)
160 end
99 if _ok_0 then 161 if _ok_0 then
100 return ... 162 return ...
101 else 163 else
@@ -104,10 +166,12 @@ do
104 end)(pcall(function() 166 end)(pcall(function()
105 local c 167 local c
106 if true then 168 if true then
107 local _exp_0 = x 169 c = ((function()
108 if "abc" == _exp_0 then 170 local _exp_0 = x
109 c = 998 171 if "abc" == _exp_0 then
110 end 172 return 998
173 end
174 end)())
111 end 175 end
112 local d 176 local d
113 if (function() 177 if (function()
@@ -121,10 +185,22 @@ do
121 value = value 185 value = value
122 } 186 }
123 end 187 end
124 local _close_1 = assert(getmetatable(d).__close) 188 local _close_1
189 if (function()
190 local _val_0 = type(d)
191 return 'table' == _val_0 or 'userdata' == _val_0
192 end)() then
193 _close_1 = assert(getmetatable(d) and getmetatable(d).__close, "variable 'd' got a non-closable value")
194 elseif d == nil then
195 _close_1 = nil
196 else
197 _close_1 = error("variable 'd' got a non-closable value")
198 end
125 return (function(_arg_0, ...) 199 return (function(_arg_0, ...)
126 local _ok_0 = _arg_0 200 local _ok_0 = _arg_0
127 _close_1(d) 201 if _close_1 ~= nil then
202 _close_1(d)
203 end
128 if _ok_0 then 204 if _ok_0 then
129 return ... 205 return ...
130 else 206 else
@@ -140,10 +216,22 @@ do
140 _with_0:write("Hello") 216 _with_0:write("Hello")
141 _ = _with_0 217 _ = _with_0
142 end 218 end
143 local _close_0 = assert(getmetatable(_).__close); 219 local _close_0
220 if (function()
221 local _val_0 = type(_)
222 return 'table' == _val_0 or 'userdata' == _val_0
223 end)() then
224 _close_0 = assert(getmetatable(_) and getmetatable(_).__close, "variable '_' got a non-closable value")
225 elseif _ == nil then
226 _close_0 = nil
227 else
228 _close_0 = error("variable '_' got a non-closable value")
229 end
144 (function(_arg_0, ...) 230 (function(_arg_0, ...)
145 local _ok_0 = _arg_0 231 local _ok_0 = _arg_0
146 _close_0(_) 232 if _close_0 ~= nil then
233 _close_0(_)
234 end
147 if _ok_0 then 235 if _ok_0 then
148 return ... 236 return ...
149 else 237 else
@@ -155,10 +243,22 @@ do
155 return print("second") 243 return print("second")
156 end 244 end
157 }) 245 })
158 local _close_1 = assert(getmetatable(_).__close) 246 local _close_1
247 if (function()
248 local _val_0 = type(_)
249 return 'table' == _val_0 or 'userdata' == _val_0
250 end)() then
251 _close_1 = assert(getmetatable(_) and getmetatable(_).__close, "variable '_' got a non-closable value")
252 elseif _ == nil then
253 _close_1 = nil
254 else
255 _close_1 = error("variable '_' got a non-closable value")
256 end
159 return (function(_arg_0, ...) 257 return (function(_arg_0, ...)
160 local _ok_0 = _arg_0 258 local _ok_0 = _arg_0
161 _close_1(_) 259 if _close_1 ~= nil then
260 _close_1(_)
261 end
162 if _ok_0 then 262 if _ok_0 then
163 return ... 263 return ...
164 else 264 else
@@ -170,10 +270,22 @@ do
170 return print("first") 270 return print("first")
171 end 271 end
172 }) 272 })
173 local _close_2 = assert(getmetatable(_).__close) 273 local _close_2
274 if (function()
275 local _val_0 = type(_)
276 return 'table' == _val_0 or 'userdata' == _val_0
277 end)() then
278 _close_2 = assert(getmetatable(_) and getmetatable(_).__close, "variable '_' got a non-closable value")
279 elseif _ == nil then
280 _close_2 = nil
281 else
282 _close_2 = error("variable '_' got a non-closable value")
283 end
174 return (function(_arg_0, ...) 284 return (function(_arg_0, ...)
175 local _ok_0 = _arg_0 285 local _ok_0 = _arg_0
176 _close_2(_) 286 if _close_2 ~= nil then
287 _close_2(_)
288 end
177 if _ok_0 then 289 if _ok_0 then
178 return ... 290 return ...
179 else 291 else
@@ -200,10 +312,22 @@ do
200 local _ = def(function() 312 local _ = def(function()
201 return print(3) 313 return print(3)
202 end) 314 end)
203 local _close_0 = assert(getmetatable(_).__close) 315 local _close_0
316 if (function()
317 local _val_0 = type(_)
318 return 'table' == _val_0 or 'userdata' == _val_0
319 end)() then
320 _close_0 = assert(getmetatable(_) and getmetatable(_).__close, "variable '_' got a non-closable value")
321 elseif _ == nil then
322 _close_0 = nil
323 else
324 _close_0 = error("variable '_' got a non-closable value")
325 end
204 return (function(_arg_0, ...) 326 return (function(_arg_0, ...)
205 local _ok_0 = _arg_0 327 local _ok_0 = _arg_0
206 _close_0(_) 328 if _close_0 ~= nil then
329 _close_0(_)
330 end
207 if _ok_0 then 331 if _ok_0 then
208 return ... 332 return ...
209 else 333 else
@@ -213,10 +337,22 @@ do
213 local _ = def(function() 337 local _ = def(function()
214 return print(2) 338 return print(2)
215 end) 339 end)
216 local _close_1 = assert(getmetatable(_).__close) 340 local _close_1
341 if (function()
342 local _val_0 = type(_)
343 return 'table' == _val_0 or 'userdata' == _val_0
344 end)() then
345 _close_1 = assert(getmetatable(_) and getmetatable(_).__close, "variable '_' got a non-closable value")
346 elseif _ == nil then
347 _close_1 = nil
348 else
349 _close_1 = error("variable '_' got a non-closable value")
350 end
217 return (function(_arg_0, ...) 351 return (function(_arg_0, ...)
218 local _ok_0 = _arg_0 352 local _ok_0 = _arg_0
219 _close_1(_) 353 if _close_1 ~= nil then
354 _close_1(_)
355 end
220 if _ok_0 then 356 if _ok_0 then
221 return ... 357 return ...
222 else 358 else
@@ -226,10 +362,22 @@ do
226 local _ = def(function() 362 local _ = def(function()
227 return print(1) 363 return print(1)
228 end) 364 end)
229 local _close_2 = assert(getmetatable(_).__close) 365 local _close_2
366 if (function()
367 local _val_0 = type(_)
368 return 'table' == _val_0 or 'userdata' == _val_0
369 end)() then
370 _close_2 = assert(getmetatable(_) and getmetatable(_).__close, "variable '_' got a non-closable value")
371 elseif _ == nil then
372 _close_2 = nil
373 else
374 _close_2 = error("variable '_' got a non-closable value")
375 end
230 return (function(_arg_0, ...) 376 return (function(_arg_0, ...)
231 local _ok_0 = _arg_0 377 local _ok_0 = _arg_0
232 _close_2(_) 378 if _close_2 ~= nil then
379 _close_2(_)
380 end
233 if _ok_0 then 381 if _ok_0 then
234 return ... 382 return ...
235 else 383 else
diff --git a/spec/outputs/5.1/try_catch.lua b/spec/outputs/5.1/try_catch.lua
index d4c80c1..efd92c6 100644
--- a/spec/outputs/5.1/try_catch.lua
+++ b/spec/outputs/5.1/try_catch.lua
@@ -8,10 +8,10 @@ local _anon_func_2 = function(tb)
8 return tb.func() 8 return tb.func()
9end 9end
10local _anon_func_3 = function(tb) 10local _anon_func_3 = function(tb)
11 return tb.func() 11 return (tb.func())
12end 12end
13local _anon_func_4 = function(tb) 13local _anon_func_4 = function(tb)
14 return tb:func(1, 2, 3) 14 return (tb:func(1, 2, 3))
15end 15end
16local _anon_func_5 = function(tb) 16local _anon_func_5 = function(tb)
17 return tb.func(1) 17 return tb.func(1)
@@ -64,7 +64,7 @@ f = function()
64 print("OK") 64 print("OK")
65 end 65 end
66 if xpcall(function() 66 if xpcall(function()
67 return func(1) 67 return (func(1))
68 end, function(err) 68 end, function(err)
69 return print(err) 69 return print(err)
70 end) then 70 end) then
diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua
index f889865..162c5a8 100644
--- a/spec/outputs/assign.lua
+++ b/spec/outputs/assign.lua
@@ -36,10 +36,10 @@ local x
36do 36do
37 local f = getHandler() 37 local f = getHandler()
38 if f then 38 if f then
39 do 39 x = ((function()
40 f() 40 f()
41 x = 123 41 return 123
42 end 42 end)())
43 end 43 end
44end 44end
45local _anon_func_0 = function(print) 45local _anon_func_0 = function(print)
diff --git a/spec/outputs/attrib.lua b/spec/outputs/attrib.lua
index e48963c..bb9916c 100644
--- a/spec/outputs/attrib.lua
+++ b/spec/outputs/attrib.lua
@@ -56,17 +56,21 @@ do
56 end 56 end
57 local b 57 local b
58 if not false then 58 if not false then
59 if x then 59 b = ((function()
60 b = 1 60 if x then
61 end 61 return 1
62 end
63 end)())
62 end 64 end
63 local _close_0 <close> = b 65 local _close_0 <close> = b
64 local c 66 local c
65 if true then 67 if true then
66 local _exp_0 = x 68 c = ((function()
67 if "abc" == _exp_0 then 69 local _exp_0 = x
68 c = 998 70 if "abc" == _exp_0 then
69 end 71 return 998
72 end
73 end)())
70 end 74 end
71 local d 75 local d
72 if (function() 76 if (function()
diff --git a/spec/outputs/do.lua b/spec/outputs/do.lua
index 6473e03..96d1022 100644
--- a/spec/outputs/do.lua
+++ b/spec/outputs/do.lua
@@ -32,10 +32,10 @@ local t = {
32} 32}
33return function(y, k) 33return function(y, k)
34 if y == nil then 34 if y == nil then
35 do 35 y = ((function()
36 x = 10 + 2 36 x = 10 + 2
37 y = x 37 return x
38 end 38 end)())
39 end 39 end
40 if k == nil then 40 if k == nil then
41 do 41 do
diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua
index 5fd1821..040a325 100644
--- a/spec/outputs/syntax.lua
+++ b/spec/outputs/syntax.lua
@@ -239,9 +239,11 @@ x = 0
239local _list_0 = values 239local _list_0 = values
240for _index_0 = 1, #_list_0 do 240for _index_0 = 1, #_list_0 do
241 local v = _list_0[_index_0] 241 local v = _list_0[_index_0]
242 if ntype(v) == "fndef" then 242 _ = ((function()
243 _ = x + 1 243 if ntype(v) == "fndef" then
244 end 244 return x + 1
245 end
246 end)())
245end 247end
246hello = { 248hello = {
247 something = world, 249 something = world,
diff --git a/spec/outputs/try_catch.lua b/spec/outputs/try_catch.lua
index d4c80c1..efd92c6 100644
--- a/spec/outputs/try_catch.lua
+++ b/spec/outputs/try_catch.lua
@@ -8,10 +8,10 @@ local _anon_func_2 = function(tb)
8 return tb.func() 8 return tb.func()
9end 9end
10local _anon_func_3 = function(tb) 10local _anon_func_3 = function(tb)
11 return tb.func() 11 return (tb.func())
12end 12end
13local _anon_func_4 = function(tb) 13local _anon_func_4 = function(tb)
14 return tb:func(1, 2, 3) 14 return (tb:func(1, 2, 3))
15end 15end
16local _anon_func_5 = function(tb) 16local _anon_func_5 = function(tb)
17 return tb.func(1) 17 return tb.func(1)
@@ -64,7 +64,7 @@ f = function()
64 print("OK") 64 print("OK")
65 end 65 end
66 if xpcall(function() 66 if xpcall(function()
67 return func(1) 67 return (func(1))
68 end, function(err) 68 end, function(err)
69 return print(err) 69 return print(err)
70 end) then 70 end) then
diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua
index bf43953..d4ad56a 100644
--- a/spec/outputs/unicode/assign.lua
+++ b/spec/outputs/unicode/assign.lua
@@ -36,10 +36,10 @@ local _u53d8_u91cfx
36do 36do
37 local _u51fd_u6570 = _u83b7_u53d6_u5904_u7406_u51fd_u6570() 37 local _u51fd_u6570 = _u83b7_u53d6_u5904_u7406_u51fd_u6570()
38 if _u51fd_u6570 then 38 if _u51fd_u6570 then
39 do 39 _u53d8_u91cfx = ((function()
40 _u51fd_u6570() 40 _u51fd_u6570()
41 _u53d8_u91cfx = 123 41 return 123
42 end 42 end)())
43 end 43 end
44end 44end
45local _anon_func_0 = function(_u6253_u5370) 45local _anon_func_0 = function(_u6253_u5370)
diff --git a/spec/outputs/unicode/attrib.lua b/spec/outputs/unicode/attrib.lua
index 1c48de4..5e5bb99 100644
--- a/spec/outputs/unicode/attrib.lua
+++ b/spec/outputs/unicode/attrib.lua
@@ -48,17 +48,21 @@ do
48 end 48 end
49 local _u5173_u95ed_u53d8_u91cfb 49 local _u5173_u95ed_u53d8_u91cfb
50 if not false then 50 if not false then
51 if _u6761_u4ef6x then 51 _u5173_u95ed_u53d8_u91cfb = ((function()
52 _u5173_u95ed_u53d8_u91cfb = 1 52 if _u6761_u4ef6x then
53 end 53 return 1
54 end
55 end)())
54 end 56 end
55 local _close_0 <close> = _u5173_u95ed_u53d8_u91cfb 57 local _close_0 <close> = _u5173_u95ed_u53d8_u91cfb
56 local _u5e38_u91cfc 58 local _u5e38_u91cfc
57 if true then 59 if true then
58 local _exp_0 = _u6761_u4ef6x 60 _u5e38_u91cfc = ((function()
59 if "abc" == _exp_0 then 61 local _exp_0 = _u6761_u4ef6x
60 _u5e38_u91cfc = 998 62 if "abc" == _exp_0 then
61 end 63 return 998
64 end
65 end)())
62 end 66 end
63 local _u5173_u95ed_u53d8_u91cfd 67 local _u5173_u95ed_u53d8_u91cfd
64 if (function() 68 if (function()
diff --git a/spec/outputs/unicode/do.lua b/spec/outputs/unicode/do.lua
index f9c3079..7bf1da3 100644
--- a/spec/outputs/unicode/do.lua
+++ b/spec/outputs/unicode/do.lua
@@ -32,10 +32,10 @@ local _u53d8_u91cft = {
32} 32}
33return function(_u53c2_u6570y, _u53c2_u6570k) 33return function(_u53c2_u6570y, _u53c2_u6570k)
34 if _u53c2_u6570y == nil then 34 if _u53c2_u6570y == nil then
35 do 35 _u53c2_u6570y = ((function()
36 _u53d8_u91cfx = 10 + 2 36 _u53d8_u91cfx = 10 + 2
37 _u53c2_u6570y = _u53d8_u91cfx 37 return _u53d8_u91cfx
38 end 38 end)())
39 end 39 end
40 if _u53c2_u6570k == nil then 40 if _u53c2_u6570k == nil then
41 do 41 do
diff --git a/spec/outputs/unicode/macro.lua b/spec/outputs/unicode/macro.lua
index 099080f..b14f571 100644
--- a/spec/outputs/unicode/macro.lua
+++ b/spec/outputs/unicode/macro.lua
@@ -215,52 +215,85 @@ do
215-- 这有个注释 215-- 这有个注释
216end 216end
217local _ = require('下划线') 217local _ = require('下划线')
218local _call_0 = (_({ 218local _anon_func_0 = function(_)
219 1, 219 do
220 2, 220 local _call_0 = (_({
221 3, 221 1,
222 4, 222 2,
223 -2, 223 3,
224 3 224 4,
225})) 225 -2,
226_call_0 = _call_0["链"](_call_0) 226 3
227_call_0 = _call_0["映射"](_call_0, function(self) 227 }))
228 return self * 2 228 return _call_0["链"](_call_0)
229end) 229 end
230_call_0 = _call_0["过滤"](_call_0, function(self) 230end
231 return self > 3 231local _call_0 = ((function()
232end) 232 local _call_0 = ((function()
233local _u7ed3_u679ca = _call_0["取值"](_call_0) 233 local _call_0 = (_anon_func_0(_))
234do 234 return _call_0["映射"](_call_0, function(self)
235 local _call_1 = (_({ 235 return self * 2
236 1, 236 end)
237 2, 237 end)())
238 3, 238 return _call_0["过滤"](_call_0, function(self)
239 4,
240 -2,
241 3
242 }))
243 _call_1 = _call_1["链"](_call_1)
244 _call_1 = _call_1["映射"](_call_1, function(self)
245 return self * 2
246 end)
247 _call_1 = _call_1["过滤"](_call_1, function(self)
248 return self > 3 239 return self > 3
249 end) 240 end)
241end)())
242local _u7ed3_u679ca = _call_0["取值"](_call_0)
243local _anon_func_1 = function(_)
244 do
245 local _call_1 = (_({
246 1,
247 2,
248 3,
249 4,
250 -2,
251 3
252 }))
253 return _call_1["链"](_call_1)
254 end
255end
256do
257 local _call_1 = ((function()
258 local _call_1 = ((function()
259 local _call_1 = (_anon_func_1(_))
260 return _call_1["映射"](_call_1, function(self)
261 return self * 2
262 end)
263 end)())
264 return _call_1["过滤"](_call_1, function(self)
265 return self > 3
266 end)
267 end)())
250 _call_1["每一个"](_call_1, function(self) 268 _call_1["每一个"](_call_1, function(self)
251 return _u6253_u5370(self) 269 return _u6253_u5370(self)
252 end) 270 end)
253end 271end
254local _call_1 = _u539f_u70b9["变换"]["根节点"]["游戏对象"] 272local _anon_func_2 = function(_u539f_u70b9)
255_call_1 = _call_1["父节点"](_call_1) 273 do
256_call_1 = _call_1["后代"](_call_1) 274 local _call_1 = _u539f_u70b9["变换"]["根节点"]["游戏对象"]
257_call_1 = _call_1["选择启用"](_call_1) 275 return _call_1["父节点"](_call_1)
258_call_1 = _call_1["选择可见"](_call_1) 276 end
259_call_1 = _call_1["标签等于"](_call_1, "fx") 277end
260_call_1 = _call_1["其中"](_call_1, function(x) 278local _call_1 = ((function()
261 local _call_2 = x["名称"] 279 local _call_1 = ((function()
262 return _call_2["结尾为"](_call_2, "(克隆)") 280 local _call_1 = ((function()
263end) 281 local _call_1 = ((function()
282 local _call_1 = ((function()
283 local _call_1 = (_anon_func_2(_u539f_u70b9))
284 return _call_1["后代"](_call_1)
285 end)())
286 return _call_1["选择启用"](_call_1)
287 end)())
288 return _call_1["选择可见"](_call_1)
289 end)())
290 return _call_1["标签等于"](_call_1, "fx")
291 end)())
292 return _call_1["其中"](_call_1, function(x)
293 local _call_2 = x["名称"]
294 return _call_2["结尾为"](_call_2, "(克隆)")
295 end)
296end)())
264_u7ed3_u679c = _call_1["摧毁"](_call_1) 297_u7ed3_u679c = _call_1["摧毁"](_call_1)
265do 298do
266 do 299 do
diff --git a/spec/outputs/unicode/syntax.lua b/spec/outputs/unicode/syntax.lua
index ea97bb9..1984f40 100644
--- a/spec/outputs/unicode/syntax.lua
+++ b/spec/outputs/unicode/syntax.lua
@@ -258,9 +258,11 @@ _u53d8_u91cfx = 0
258local _list_0 = _u503c 258local _list_0 = _u503c
259for _index_0 = 1, #_list_0 do 259for _index_0 = 1, #_list_0 do
260 local _u53d8_u91cfv = _list_0[_index_0] 260 local _u53d8_u91cfv = _list_0[_index_0]
261 if ntype(_u53d8_u91cfv) == "函数定义" then 261 _ = ((function()
262 _ = _u53d8_u91cfx + 1 262 if ntype(_u53d8_u91cfv) == "函数定义" then
263 end 263 return _u53d8_u91cfx + 1
264 end
265 end)())
264end 266end
265_u4f60_u597d = { 267_u4f60_u597d = {
266 ["某物"] = _u4e16_u754c, 268 ["某物"] = _u4e16_u754c,
diff --git a/spec/outputs/unicode/try_catch.lua b/spec/outputs/unicode/try_catch.lua
index 22f29f9..f8c7849 100644
--- a/spec/outputs/unicode/try_catch.lua
+++ b/spec/outputs/unicode/try_catch.lua
@@ -32,11 +32,13 @@ pcall(function()
32 return _u8868["函数"]() 32 return _u8868["函数"]()
33end) 33end)
34pcall(function() 34pcall(function()
35 return _u8868["函数"]() 35 return (_u8868["函数"]())
36end) 36end)
37pcall(function() 37pcall(function()
38 local _call_0 = _u8868 38 return ((function()
39 return _call_0["函数"](_call_0, 1, 2, 3) 39 local _call_0 = _u8868
40 return _call_0["函数"](_call_0, 1, 2, 3)
41 end)())
40end) 42end)
41pcall(function() 43pcall(function()
42 return _u8868["函数"](1) 44 return _u8868["函数"](1)
@@ -52,7 +54,7 @@ end)) then
52 _u6253_u5370("好的") 54 _u6253_u5370("好的")
53end 55end
54if xpcall(function() 56if xpcall(function()
55 return _u51fd_u6570(1) 57 return (_u51fd_u6570(1))
56end, function(_u9519_u8bef) 58end, function(_u9519_u8bef)
57 return _u6253_u5370(_u9519_u8bef) 59 return _u6253_u5370(_u9519_u8bef)
58end) then 60end) then
diff --git a/src/3rdParty/efsw/Atomic.hpp b/src/3rdParty/efsw/Atomic.hpp
index 4008dfc..9015c60 100755..100644
--- a/src/3rdParty/efsw/Atomic.hpp
+++ b/src/3rdParty/efsw/Atomic.hpp
@@ -3,9 +3,7 @@
3 3
4#include <efsw/base.hpp> 4#include <efsw/base.hpp>
5 5
6#ifdef EFSW_USE_CXX11
7#include <atomic> 6#include <atomic>
8#endif
9 7
10namespace efsw { 8namespace efsw {
11 9
@@ -14,36 +12,20 @@ template <typename T> class Atomic {
14 explicit Atomic( T set = false ) : set_( set ) {} 12 explicit Atomic( T set = false ) : set_( set ) {}
15 13
16 Atomic& operator=( T set ) { 14 Atomic& operator=( T set ) {
17#ifdef EFSW_USE_CXX11
18 set_.store( set, std::memory_order_release ); 15 set_.store( set, std::memory_order_release );
19#else
20 set_ = set;
21#endif
22 return *this; 16 return *this;
23 } 17 }
24 18
25 explicit operator T() const { 19 explicit operator T() const {
26#ifdef EFSW_USE_CXX11
27 return set_.load( std::memory_order_acquire ); 20 return set_.load( std::memory_order_acquire );
28#else
29 return set_;
30#endif
31 } 21 }
32 22
33 T load() const { 23 T load() const {
34#ifdef EFSW_USE_CXX11
35 return set_.load( std::memory_order_acquire ); 24 return set_.load( std::memory_order_acquire );
36#else
37 return set_;
38#endif
39 } 25 }
40 26
41 private: 27 private:
42#ifdef EFSW_USE_CXX11
43 std::atomic<T> set_; 28 std::atomic<T> set_;
44#else
45 volatile T set_;
46#endif
47}; 29};
48 30
49} // namespace efsw 31} // namespace efsw
diff --git a/src/3rdParty/efsw/Debug.cpp b/src/3rdParty/efsw/Debug.cpp
index 18cfd31..18cfd31 100755..100644
--- a/src/3rdParty/efsw/Debug.cpp
+++ b/src/3rdParty/efsw/Debug.cpp
diff --git a/src/3rdParty/efsw/Debug.hpp b/src/3rdParty/efsw/Debug.hpp
index 78d3557..fefaec4 100755..100644
--- a/src/3rdParty/efsw/Debug.hpp
+++ b/src/3rdParty/efsw/Debug.hpp
@@ -49,8 +49,10 @@ void efPRINTC( unsigned int cond, const char* format, ... );
49#define efDEBUGC( cond, format, args... ) \ 49#define efDEBUGC( cond, format, args... ) \
50 {} 50 {}
51#else 51#else
52#define efDEBUG 52#define efDEBUG( ... ) \
53#define efDEBUGC 53 {}
54#define efDEBUGC( ... ) \
55 {}
54#endif 56#endif
55 57
56#endif 58#endif
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.cpp b/src/3rdParty/efsw/DirWatcherGeneric.cpp
index 8b6bc8a..8b6bc8a 100755..100644
--- a/src/3rdParty/efsw/DirWatcherGeneric.cpp
+++ b/src/3rdParty/efsw/DirWatcherGeneric.cpp
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.hpp b/src/3rdParty/efsw/DirWatcherGeneric.hpp
index ca52de7..ca52de7 100755..100644
--- a/src/3rdParty/efsw/DirWatcherGeneric.hpp
+++ b/src/3rdParty/efsw/DirWatcherGeneric.hpp
diff --git a/src/3rdParty/efsw/DirectorySnapshot.cpp b/src/3rdParty/efsw/DirectorySnapshot.cpp
index 6049e4a..f78475f 100755..100644
--- a/src/3rdParty/efsw/DirectorySnapshot.cpp
+++ b/src/3rdParty/efsw/DirectorySnapshot.cpp
@@ -44,7 +44,7 @@ void DirectorySnapshot::initFiles() {
44 Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); 44 Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath );
45 45
46 FileInfoMap::iterator it = Files.begin(); 46 FileInfoMap::iterator it = Files.begin();
47 std::list<std::string> eraseFiles; 47 std::vector<std::string> eraseFiles;
48 48
49 /// Remove all non regular files and non directories 49 /// Remove all non regular files and non directories
50 for ( ; it != Files.end(); it++ ) { 50 for ( ; it != Files.end(); it++ ) {
@@ -53,7 +53,7 @@ void DirectorySnapshot::initFiles() {
53 } 53 }
54 } 54 }
55 55
56 for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); 56 for ( std::vector<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end();
57 eit++ ) { 57 eit++ ) {
58 Files.erase( *eit ); 58 Files.erase( *eit );
59 } 59 }
diff --git a/src/3rdParty/efsw/DirectorySnapshot.hpp b/src/3rdParty/efsw/DirectorySnapshot.hpp
index 0e60542..0e60542 100755..100644
--- a/src/3rdParty/efsw/DirectorySnapshot.hpp
+++ b/src/3rdParty/efsw/DirectorySnapshot.hpp
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp
index 37ee507..37ee507 100755..100644
--- a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp
+++ b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp
index 26a29ec..26a29ec 100755..100644
--- a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp
+++ b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp
diff --git a/src/3rdParty/efsw/FileInfo.cpp b/src/3rdParty/efsw/FileInfo.cpp
index 072cd6d..707f617 100755..100644
--- a/src/3rdParty/efsw/FileInfo.cpp
+++ b/src/3rdParty/efsw/FileInfo.cpp
@@ -35,10 +35,6 @@
35#endif 35#endif
36#endif 36#endif
37 37
38#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
39#include <filesystem>
40#endif
41
42namespace efsw { 38namespace efsw {
43 39
44bool FileInfo::exists( const std::string& filePath ) { 40bool FileInfo::exists( const std::string& filePath ) {
@@ -186,12 +182,14 @@ bool FileInfo::isLink() const {
186std::string FileInfo::linksTo() { 182std::string FileInfo::linksTo() {
187#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 183#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32
188 if ( isLink() ) { 184 if ( isLink() ) {
189 std::error_code ec; 185 char* ch = realpath( Filepath.c_str(), NULL );
190 auto ch = std::filesystem::canonical( Filepath, ec ); 186
187 if ( NULL != ch ) {
188 std::string tstr( ch );
191 189
192 if ( !ec ) { 190 free( ch );
193 191
194 return ch.string(); 192 return tstr;
195 } 193 }
196 } 194 }
197#endif 195#endif
diff --git a/src/3rdParty/efsw/FileInfo.hpp b/src/3rdParty/efsw/FileInfo.hpp
index f1bcf4b..1b55c35 100755..100644
--- a/src/3rdParty/efsw/FileInfo.hpp
+++ b/src/3rdParty/efsw/FileInfo.hpp
@@ -2,7 +2,7 @@
2#define EFSW_FILEINFO_HPP 2#define EFSW_FILEINFO_HPP
3 3
4#include <efsw/base.hpp> 4#include <efsw/base.hpp>
5#include <list> 5#include <vector>
6#include <map> 6#include <map>
7#include <string> 7#include <string>
8 8
@@ -18,11 +18,11 @@ class FileInfo {
18 18
19 FileInfo(); 19 FileInfo();
20 20
21 explicit FileInfo( const std::string& filepath ); 21 FileInfo( const std::string& filepath );
22 22
23 FileInfo( const std::string& filepath, bool linkInfo ); 23 FileInfo( const std::string& filepath, bool linkInfo );
24 24
25 FileInfo( const FileInfo& ) = default; 25 FileInfo(const FileInfo&) = default;
26 26
27 bool operator==( const FileInfo& Other ) const; 27 bool operator==( const FileInfo& Other ) const;
28 28
@@ -58,8 +58,8 @@ class FileInfo {
58}; 58};
59 59
60typedef std::map<std::string, FileInfo> FileInfoMap; 60typedef std::map<std::string, FileInfo> FileInfoMap;
61typedef std::list<FileInfo> FileInfoList; 61typedef std::vector<FileInfo> FileInfoList;
62typedef std::list<std::pair<std::string, FileInfo>> MovedList; 62typedef std::vector<std::pair<std::string, FileInfo>> MovedList;
63 63
64} // namespace efsw 64} // namespace efsw
65 65
diff --git a/src/3rdParty/efsw/FileSystem.cpp b/src/3rdParty/efsw/FileSystem.cpp
index 867f120..1ed346c 100755..100644
--- a/src/3rdParty/efsw/FileSystem.cpp
+++ b/src/3rdParty/efsw/FileSystem.cpp
@@ -1,10 +1,19 @@
1#include <cstring>
1#include <efsw/FileSystem.hpp> 2#include <efsw/FileSystem.hpp>
2#include <efsw/platform/platformimpl.hpp> 3#include <efsw/platform/platformimpl.hpp>
4#include <climits>
3 5
4#if EFSW_OS == EFSW_OS_MACOSX 6#if EFSW_OS == EFSW_OS_MACOSX
5#include <CoreFoundation/CoreFoundation.h> 7#include <CoreFoundation/CoreFoundation.h>
6#endif 8#endif
7 9
10#if EFSW_OS == EFSW_OS_WIN
11#ifndef WIN32_LEAN_AND_MEAN
12#define WIN32_LEAN_AND_MEAN
13#endif
14#include <windows.h>
15#endif
16
8namespace efsw { 17namespace efsw {
9 18
10bool FileSystem::isDirectory( const std::string& path ) { 19bool FileSystem::isDirectory( const std::string& path ) {
@@ -26,13 +35,13 @@ bool FileSystem::slashAtEnd( std::string& dir ) {
26} 35}
27 36
28void FileSystem::dirAddSlashAtEnd( std::string& dir ) { 37void FileSystem::dirAddSlashAtEnd( std::string& dir ) {
29 if ( dir.size() > 1 && dir[dir.size() - 1] != getOSSlash() ) { 38 if ( dir.size() >= 1 && dir[dir.size() - 1] != getOSSlash() ) {
30 dir.push_back( getOSSlash() ); 39 dir.push_back( getOSSlash() );
31 } 40 }
32} 41}
33 42
34void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { 43void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) {
35 if ( dir.size() > 1 && dir[dir.size() - 1] == getOSSlash() ) { 44 if ( dir.size() >= 1 && dir[dir.size() - 1] == getOSSlash() ) {
36 dir.erase( dir.size() - 1 ); 45 dir.erase( dir.size() - 1 );
37 } 46 }
38} 47}
@@ -91,13 +100,30 @@ std::string FileSystem::precomposeFileName( const std::string& name ) {
91 100
92 CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); 101 CFStringNormalize( cfMutable, kCFStringNormalizationFormC );
93 102
94 char c_str[255 + 1]; 103 const char* c_str = CFStringGetCStringPtr( cfMutable, kCFStringEncodingUTF8 );
95 CFStringGetCString( cfMutable, c_str, sizeof( c_str ) - 1, kCFStringEncodingUTF8 ); 104 if ( c_str != NULL ) {
96 105 std::string result( c_str );
97 CFRelease( cfStringRef ); 106 CFRelease( cfStringRef );
98 CFRelease( cfMutable ); 107 CFRelease( cfMutable );
108 return result;
109 }
110 CFIndex length = CFStringGetLength( cfMutable );
111 CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 );
112 if ( maxSize == kCFNotFound ) {
113 CFRelease( cfStringRef );
114 CFRelease( cfMutable );
115 return std::string();
116 }
99 117
100 return std::string( c_str ); 118 std::string result( maxSize + 1, '\0' );
119 if ( CFStringGetCString( cfMutable, &result[0], result.size(), kCFStringEncodingUTF8 ) ) {
120 result.resize( std::strlen( result.c_str() ) );
121 CFRelease( cfStringRef );
122 CFRelease( cfMutable );
123 } else {
124 result.clear();
125 }
126 return result;
101#else 127#else
102 return name; 128 return name;
103#endif 129#endif
@@ -115,4 +141,21 @@ std::string FileSystem::getCurrentWorkingDirectory() {
115 return Platform::FileSystem::getCurrentWorkingDirectory(); 141 return Platform::FileSystem::getCurrentWorkingDirectory();
116} 142}
117 143
144std::string FileSystem::getRealPath( const std::string& path ) {
145 std::string realPath;
146#if defined( EFSW_PLATFORM_POSIX )
147 char dir[PATH_MAX];
148 realpath( path.c_str(), &dir[0] );
149 realPath = std::string( dir );
150#elif EFSW_OS == EFSW_OS_WIN
151 wchar_t dir[_MAX_PATH + 1];
152 GetFullPathNameW( String::fromUtf8( path ).toWideString().c_str(), _MAX_PATH, &dir[0],
153 nullptr );
154 realPath = String( dir ).toUtf8();
155#else
156#warning FileSystem::getRealPath() not implemented on this platform.
157#endif
158 return realPath;
159}
160
118} // namespace efsw 161} // namespace efsw
diff --git a/src/3rdParty/efsw/FileSystem.hpp b/src/3rdParty/efsw/FileSystem.hpp
index 6c24386..1d66ece 100755..100644
--- a/src/3rdParty/efsw/FileSystem.hpp
+++ b/src/3rdParty/efsw/FileSystem.hpp
@@ -3,7 +3,6 @@
3 3
4#include <efsw/FileInfo.hpp> 4#include <efsw/FileInfo.hpp>
5#include <efsw/base.hpp> 5#include <efsw/base.hpp>
6#include <map>
7 6
8namespace efsw { 7namespace efsw {
9 8
@@ -34,6 +33,9 @@ class FileSystem {
34 static bool changeWorkingDirectory( const std::string& path ); 33 static bool changeWorkingDirectory( const std::string& path );
35 34
36 static std::string getCurrentWorkingDirectory(); 35 static std::string getCurrentWorkingDirectory();
36
37 static std::string getRealPath( const std::string& path );
38
37}; 39};
38 40
39} // namespace efsw 41} // namespace efsw
diff --git a/src/3rdParty/efsw/FileWatcher.cpp b/src/3rdParty/efsw/FileWatcher.cpp
index 696a46f..f45b243 100755..100644
--- a/src/3rdParty/efsw/FileWatcher.cpp
+++ b/src/3rdParty/efsw/FileWatcher.cpp
@@ -1,119 +1,120 @@
1#include <efsw/FileSystem.hpp> 1#include <efsw/FileSystem.hpp>
2#include <efsw/FileWatcherGeneric.hpp> 2#include <efsw/FileWatcherGeneric.hpp>
3#include <efsw/FileWatcherImpl.hpp> 3#include <efsw/FileWatcherImpl.hpp>
4#include <efsw/efsw.hpp> 4#include <efsw/efsw.hpp>
5 5
6#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 6#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
7#include <efsw/FileWatcherWin32.hpp> 7#include <efsw/FileWatcherWin32.hpp>
8#define FILEWATCHER_IMPL FileWatcherWin32 8#define FILEWATCHER_IMPL FileWatcherWin32
9#define BACKEND_NAME "Win32" 9#define BACKEND_NAME "Win32"
10#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 10#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
11#include <efsw/FileWatcherInotify.hpp> 11#include <efsw/FileWatcherInotify.hpp>
12#define FILEWATCHER_IMPL FileWatcherInotify 12#define FILEWATCHER_IMPL FileWatcherInotify
13#define BACKEND_NAME "Inotify" 13#define BACKEND_NAME "Inotify"
14#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE 14#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
15#include <efsw/FileWatcherKqueue.hpp> 15#include <efsw/FileWatcherKqueue.hpp>
16#define FILEWATCHER_IMPL FileWatcherKqueue 16#define FILEWATCHER_IMPL FileWatcherKqueue
17#define BACKEND_NAME "Kqueue" 17#define BACKEND_NAME "Kqueue"
18#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 18#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
19#include <efsw/FileWatcherFSEvents.hpp> 19#include <efsw/FileWatcherFSEvents.hpp>
20#define FILEWATCHER_IMPL FileWatcherFSEvents 20#define FILEWATCHER_IMPL FileWatcherFSEvents
21#define BACKEND_NAME "FSEvents" 21#define BACKEND_NAME "FSEvents"
22#else 22#else
23#define FILEWATCHER_IMPL FileWatcherGeneric 23#define FILEWATCHER_IMPL FileWatcherGeneric
24#define BACKEND_NAME "Generic" 24#define BACKEND_NAME "Generic"
25#endif 25#endif
26 26
27#include <efsw/Debug.hpp> 27#include <efsw/Debug.hpp>
28 28
29namespace efsw { 29namespace efsw {
30 30
31FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { 31FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) {
32 efDEBUG( "Using backend: %s\n", BACKEND_NAME ); 32 efDEBUG( "Using backend: %s\n", BACKEND_NAME );
33 33
34 mImpl = new FILEWATCHER_IMPL( this ); 34 mImpl = new FILEWATCHER_IMPL( this );
35 35
36 if ( !mImpl->initOK() ) { 36 if ( !mImpl->initOK() ) {
37 efSAFE_DELETE( mImpl ); 37 efSAFE_DELETE( mImpl );
38 38
39 efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); 39 efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
40 40
41 mImpl = new FileWatcherGeneric( this ); 41 mImpl = new FileWatcherGeneric( this );
42 } 42 }
43} 43}
44 44
45FileWatcher::FileWatcher( bool useGenericFileWatcher ) : 45FileWatcher::FileWatcher( bool useGenericFileWatcher ) :
46 mFollowSymlinks( false ), mOutOfScopeLinks( false ) { 46 mFollowSymlinks( false ), mOutOfScopeLinks( false ) {
47 if ( useGenericFileWatcher ) { 47 if ( useGenericFileWatcher ) {
48 efDEBUG( "Using backend: Generic\n" ); 48 efDEBUG( "Using backend: Generic\n" );
49 49
50 mImpl = new FileWatcherGeneric( this ); 50 mImpl = new FileWatcherGeneric( this );
51 } else { 51 } else {
52 efDEBUG( "Using backend: %s\n", BACKEND_NAME ); 52 efDEBUG( "Using backend: %s\n", BACKEND_NAME );
53 53
54 mImpl = new FILEWATCHER_IMPL( this ); 54 mImpl = new FILEWATCHER_IMPL( this );
55 55
56 if ( !mImpl->initOK() ) { 56 if ( !mImpl->initOK() ) {
57 efSAFE_DELETE( mImpl ); 57 efSAFE_DELETE( mImpl );
58 58
59 efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); 59 efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME );
60 60
61 mImpl = new FileWatcherGeneric( this ); 61 mImpl = new FileWatcherGeneric( this );
62 } 62 }
63 } 63 }
64} 64}
65 65
66FileWatcher::~FileWatcher() { 66FileWatcher::~FileWatcher() {
67 efSAFE_DELETE( mImpl ); 67 efSAFE_DELETE( mImpl );
68} 68}
69 69
70WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { 70WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) {
71 if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { 71 return addWatch( directory, watcher, false, {} );
72 return mImpl->addWatch( directory, watcher, false ); 72}
73 } else { 73
74 return Errors::Log::createLastError( Errors::FileRemote, directory ); 74WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher,
75 } 75 bool recursive ) {
76} 76 return addWatch( directory, watcher, recursive, {} );
77 77}
78WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, 78
79 bool recursive ) { 79WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher,
80 if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { 80 bool recursive, const std::vector<WatcherOption>& options ) {
81 return mImpl->addWatch( directory, watcher, recursive ); 81 if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) {
82 } else { 82 return mImpl->addWatch( directory, watcher, recursive, options );
83 return Errors::Log::createLastError( Errors::FileRemote, directory ); 83 } else {
84 } 84 return Errors::Log::createLastError( Errors::FileRemote, directory );
85} 85 }
86 86}
87void FileWatcher::removeWatch( const std::string& directory ) { 87
88 mImpl->removeWatch( directory ); 88void FileWatcher::removeWatch( const std::string& directory ) {
89} 89 mImpl->removeWatch( directory );
90 90}
91void FileWatcher::removeWatch( WatchID watchid ) { 91
92 mImpl->removeWatch( watchid ); 92void FileWatcher::removeWatch( WatchID watchid ) {
93} 93 mImpl->removeWatch( watchid );
94 94}
95void FileWatcher::watch() { 95
96 mImpl->watch(); 96void FileWatcher::watch() {
97} 97 mImpl->watch();
98 98}
99std::list<std::string> FileWatcher::directories() { 99
100 return mImpl->directories(); 100std::vector<std::string> FileWatcher::directories() {
101} 101 return mImpl->directories();
102 102}
103void FileWatcher::followSymlinks( bool follow ) { 103
104 mFollowSymlinks = follow; 104void FileWatcher::followSymlinks( bool follow ) {
105} 105 mFollowSymlinks = follow;
106 106}
107const bool& FileWatcher::followSymlinks() const { 107
108 return mFollowSymlinks; 108const bool& FileWatcher::followSymlinks() const {
109} 109 return mFollowSymlinks;
110 110}
111void FileWatcher::allowOutOfScopeLinks( bool allow ) { 111
112 mOutOfScopeLinks = allow; 112void FileWatcher::allowOutOfScopeLinks( bool allow ) {
113} 113 mOutOfScopeLinks = allow;
114 114}
115const bool& FileWatcher::allowOutOfScopeLinks() const { 115
116 return mOutOfScopeLinks; 116const bool& FileWatcher::allowOutOfScopeLinks() const {
117} 117 return mOutOfScopeLinks;
118 118}
119} // namespace efsw 119
120} // namespace efsw
diff --git a/src/3rdParty/efsw/FileWatcherCWrapper.cpp b/src/3rdParty/efsw/FileWatcherCWrapper.cpp
index 5c49a66..8712d6e 100755..100644
--- a/src/3rdParty/efsw/FileWatcherCWrapper.cpp
+++ b/src/3rdParty/efsw/FileWatcherCWrapper.cpp
@@ -28,12 +28,12 @@ class Watcher_CAPI : public efsw::FileWatchListener {
28 */ 28 */
29static std::vector<Watcher_CAPI*> g_callbacks; 29static std::vector<Watcher_CAPI*> g_callbacks;
30 30
31Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) { 31Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) {
32 for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); 32 for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end();
33 ++i ) { 33 ++i ) {
34 Watcher_CAPI* callback = *i; 34 Watcher_CAPI* callback = *i;
35 35
36 if ( callback->mFn == fn && callback->mWatcher == watcher ) 36 if ( callback->mFn == fn && callback->mWatcher == watcher && callback->mParam == param )
37 return *i; 37 return *i;
38 } 38 }
39 39
@@ -71,17 +71,35 @@ const char* efsw_getlasterror() {
71 return log_str.c_str(); 71 return log_str.c_str();
72} 72}
73 73
74EFSW_API void efsw_clearlasterror() {
75 efsw::Errors::Log::clearLastError();
76}
77
74efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, 78efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory,
75 efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { 79 efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) {
76 Watcher_CAPI* callback = find_callback( watcher, callback_fn ); 80 return efsw_addwatch_withoptions( watcher, directory, callback_fn, recursive, 0, 0, param );
81}
82
83efsw_watchid efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory,
84 efsw_pfn_fileaction_callback callback_fn, int recursive,
85 efsw_watcher_option *options, int options_number,
86 void* param) {
87 Watcher_CAPI* callback = find_callback( watcher, callback_fn, param );
77 88
78 if ( callback == NULL ) { 89 if ( callback == NULL ) {
79 callback = new Watcher_CAPI( watcher, callback_fn, param ); 90 callback = new Watcher_CAPI( watcher, callback_fn, param );
80 g_callbacks.push_back( callback ); 91 g_callbacks.push_back( callback );
81 } 92 }
82 93
94 std::vector<efsw::WatcherOption> watcher_options{};
95 for ( int i = 0; i < options_number; i++ ) {
96 efsw_watcher_option* option = &options[i];
97 watcher_options.emplace_back( efsw::WatcherOption{
98 static_cast<efsw::Option>(option->option), option->value } );
99 }
100
83 return ( (efsw::FileWatcher*)watcher ) 101 return ( (efsw::FileWatcher*)watcher )
84 ->addWatch( std::string( directory ), callback, TOBOOL( recursive ) ); 102 ->addWatch( std::string( directory ), callback, TOBOOL( recursive ), watcher_options );
85} 103}
86 104
87void efsw_removewatch( efsw_watcher watcher, const char* directory ) { 105void efsw_removewatch( efsw_watcher watcher, const char* directory ) {
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.cpp b/src/3rdParty/efsw/FileWatcherFSEvents.cpp
index bcfdbe6..70ec2b1 100755..100644
--- a/src/3rdParty/efsw/FileWatcherFSEvents.cpp
+++ b/src/3rdParty/efsw/FileWatcherFSEvents.cpp
@@ -41,6 +41,32 @@ bool FileWatcherFSEvents::isGranular() {
41 return getOSXReleaseNumber() >= 11; 41 return getOSXReleaseNumber() >= 11;
42} 42}
43 43
44static std::string convertCFStringToStdString( CFStringRef cfString ) {
45 // Try to get the C string pointer directly
46 const char* cStr = CFStringGetCStringPtr( cfString, kCFStringEncodingUTF8 );
47
48 if ( cStr ) {
49 // If the pointer is valid, directly return a std::string from it
50 return std::string( cStr );
51 } else {
52 // If not, manually convert it
53 CFIndex length = CFStringGetLength( cfString );
54 CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) +
55 1; // +1 for null terminator
56
57 char* buffer = new char[maxSize];
58
59 if ( CFStringGetCString( cfString, buffer, maxSize, kCFStringEncodingUTF8 ) ) {
60 std::string result( buffer );
61 delete[] buffer;
62 return result;
63 } else {
64 delete[] buffer;
65 return "";
66 }
67 }
68}
69
44void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData, 70void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData,
45 size_t numEvents, void* eventPaths, 71 size_t numEvents, void* eventPaths,
46 const FSEventStreamEventFlags eventFlags[], 72 const FSEventStreamEventFlags eventFlags[],
@@ -51,8 +77,24 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/,
51 events.reserve( numEvents ); 77 events.reserve( numEvents );
52 78
53 for ( size_t i = 0; i < numEvents; i++ ) { 79 for ( size_t i = 0; i < numEvents; i++ ) {
54 events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i], 80 if ( isGranular() ) {
55 (Uint64)eventIds[i] ) ); 81 CFDictionaryRef pathInfoDict =
82 static_cast<CFDictionaryRef>( CFArrayGetValueAtIndex( (CFArrayRef)eventPaths, i ) );
83 CFStringRef path = static_cast<CFStringRef>(
84 CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedDataPathKey ) );
85 CFNumberRef cfInode = static_cast<CFNumberRef>(
86 CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedFileIDKey ) );
87
88 if ( cfInode ) {
89 unsigned long inode = 0;
90 CFNumberGetValue( cfInode, kCFNumberLongType, &inode );
91 events.push_back( FSEvent( convertCFStringToStdString( path ), (long)eventFlags[i],
92 (Uint64)eventIds[i], inode ) );
93 }
94 } else {
95 events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ),
96 (long)eventFlags[i], (Uint64)eventIds[i] ) );
97 }
56 } 98 }
57 99
58 watcher->handleActions( events ); 100 watcher->handleActions( events );
@@ -63,7 +105,7 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/,
63} 105}
64 106
65FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : 107FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) :
66 FileWatcherImpl( parent ), mRunLoopRef( NULL ), mLastWatchID( 0 ), mThread( NULL ) { 108 FileWatcherImpl( parent ), mLastWatchID( 0 ) {
67 mInitOK = true; 109 mInitOK = true;
68 110
69 watch(); 111 watch();
@@ -72,10 +114,7 @@ FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) :
72FileWatcherFSEvents::~FileWatcherFSEvents() { 114FileWatcherFSEvents::~FileWatcherFSEvents() {
73 mInitOK = false; 115 mInitOK = false;
74 116
75 if ( mRunLoopRef.load() ) 117 mWatchCond.notify_all();
76 CFRunLoopStop( mRunLoopRef.load() );
77
78 efSAFE_DELETE( mThread );
79 118
80 WatchMap::iterator iter = mWatches.begin(); 119 WatchMap::iterator iter = mWatches.begin();
81 120
@@ -84,18 +123,11 @@ FileWatcherFSEvents::~FileWatcherFSEvents() {
84 123
85 efSAFE_DELETE( watch ); 124 efSAFE_DELETE( watch );
86 } 125 }
87
88 mWatches.clear();
89} 126}
90 127
91WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, 128WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher,
92 bool recursive ) { 129 bool recursive, const std::vector<WatcherOption>& options ) {
93 /// Wait to the RunLoopRef to be ready 130 std::string dir( FileSystem::getRealPath( directory ) );
94 while ( NULL == mRunLoopRef.load() ) {
95 System::sleep( 1 );
96 }
97
98 std::string dir( directory );
99 131
100 FileInfo fi( dir ); 132 FileInfo fi( dir );
101 133
@@ -135,12 +167,18 @@ WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchLi
135 pWatch->Directory = dir; 167 pWatch->Directory = dir;
136 pWatch->Recursive = recursive; 168 pWatch->Recursive = recursive;
137 pWatch->FWatcher = this; 169 pWatch->FWatcher = this;
170 pWatch->ModifiedFlags =
171 getOptionValue( options, Option::MacModifiedFilter, efswFSEventsModified );
172 pWatch->SanitizeEvents = getOptionValue( options, Option::MacSanitizeEvents, 0 ) != 0;
138 173
139 pWatch->init(); 174 pWatch->init();
140 175
141 Lock lock( mWatchesLock ); 176 {
142 mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); 177 Lock lock( mWatchesLock );
178 mWatches.insert( std::make_pair( mLastWatchID, pWatch ) );
179 }
143 180
181 mWatchCond.notify_all();
144 return pWatch->ID; 182 return pWatch->ID;
145} 183}
146 184
@@ -174,50 +212,20 @@ void FileWatcherFSEvents::removeWatch( WatchID watchid ) {
174 efSAFE_DELETE( watch ); 212 efSAFE_DELETE( watch );
175} 213}
176 214
177void FileWatcherFSEvents::watch() { 215void 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 216
211void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, 217void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/,
212 unsigned long /*action*/, std::string /*oldFilename*/ ) { 218 unsigned long /*action*/, std::string /*oldFilename*/ ) {
213 /// Not used 219 /// Not used
214} 220}
215 221
216std::list<std::string> FileWatcherFSEvents::directories() { 222std::vector<std::string> FileWatcherFSEvents::directories() {
217 std::list<std::string> dirs; 223 std::vector<std::string> dirs;
218 224
219 Lock lock( mWatchesLock ); 225 Lock lock( mWatchesLock );
220 226
227 dirs.reserve( mWatches.size() );
228
221 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { 229 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
222 dirs.push_back( std::string( it->second->Directory ) ); 230 dirs.push_back( std::string( it->second->Directory ) );
223 } 231 }
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.hpp b/src/3rdParty/efsw/FileWatcherFSEvents.hpp
index 5279847..daa538c 100755..100644
--- a/src/3rdParty/efsw/FileWatcherFSEvents.hpp
+++ b/src/3rdParty/efsw/FileWatcherFSEvents.hpp
@@ -7,33 +7,15 @@
7 7
8#include <CoreFoundation/CoreFoundation.h> 8#include <CoreFoundation/CoreFoundation.h>
9#include <CoreServices/CoreServices.h> 9#include <CoreServices/CoreServices.h>
10#include <dispatch/dispatch.h>
10#include <efsw/WatcherFSEvents.hpp> 11#include <efsw/WatcherFSEvents.hpp>
11#include <list>
12#include <map> 12#include <map>
13#include <vector> 13#include <vector>
14#include <condition_variable>
15#include <mutex>
14 16
15namespace efsw { 17namespace efsw {
16 18
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. 19/// Implementation for Win32 based on ReadDirectoryChangesW.
38/// @class FileWatcherFSEvents 20/// @class FileWatcherFSEvents
39class FileWatcherFSEvents : public FileWatcherImpl { 21class FileWatcherFSEvents : public FileWatcherImpl {
@@ -52,48 +34,43 @@ class FileWatcherFSEvents : public FileWatcherImpl {
52 34
53 /// Add a directory watch 35 /// Add a directory watch
54 /// On error returns WatchID with Error type. 36 /// On error returns WatchID with Error type.
55 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); 37 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
38 const std::vector<WatcherOption> &options ) override;
56 39
57 /// Remove a directory watch. This is a brute force lazy search O(nlogn). 40 /// Remove a directory watch. This is a brute force lazy search O(nlogn).
58 void removeWatch( const std::string& directory ); 41 void removeWatch( const std::string& directory ) override;
59 42
60 /// Remove a directory watch. This is a map lookup O(logn). 43 /// Remove a directory watch. This is a map lookup O(logn).
61 void removeWatch( WatchID watchid ); 44 void removeWatch( WatchID watchid ) override;
62 45
63 /// Updates the watcher. Must be called often. 46 /// Updates the watcher. Must be called often.
64 void watch(); 47 void watch() override;
65 48
66 /// Handles the action 49 /// Handles the action
67 void handleAction( Watcher* watch, const std::string& filename, unsigned long action, 50 void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
68 std::string oldFilename = "" ); 51 std::string oldFilename = "" ) override;
69 52
70 /// @return Returns a list of the directories that are being watched 53 /// @return Returns a list of the directories that are being watched
71 std::list<std::string> directories(); 54 std::vector<std::string> directories() override;
72 55
73 protected: 56 protected:
74 static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, 57 static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents,
75 void* eventPaths, const FSEventStreamEventFlags eventFlags[], 58 void* eventPaths, const FSEventStreamEventFlags eventFlags[],
76 const FSEventStreamEventId eventIds[] ); 59 const FSEventStreamEventId eventIds[] );
77 60
78 Atomic<CFRunLoopRef> mRunLoopRef;
79
80 /// Vector of WatcherWin32 pointers 61 /// Vector of WatcherWin32 pointers
81 WatchMap mWatches; 62 WatchMap mWatches;
82 63
83 /// The last watchid 64 /// The last watchid
84 WatchID mLastWatchID; 65 WatchID mLastWatchID;
85 66
86 Thread* mThread;
87
88 Mutex mWatchesLock; 67 Mutex mWatchesLock;
89 68
90 bool pathInWatches( const std::string& path ); 69 bool pathInWatches( const std::string& path ) override;
91 70
92 std::vector<WatcherFSEvents*> mNeedInit; 71 std::mutex mWatchesMutex;
93 Mutex mNeedInitMutex; 72 std::condition_variable mWatchCond;
94 73
95 private:
96 void run();
97}; 74};
98 75
99} // namespace efsw 76} // namespace efsw
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp
index 074cff1..3f3c52e 100755..100644
--- a/src/3rdParty/efsw/FileWatcherGeneric.cpp
+++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() {
25} 25}
26 26
27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, 27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher,
28 bool recursive ) { 28 bool recursive, const std::vector<WatcherOption>& options ) {
29 std::string dir( directory ); 29 std::string dir( directory );
30 30
31 FileSystem::dirAddSlashAtEnd( dir ); 31 FileSystem::dirAddSlashAtEnd( dir );
@@ -127,11 +127,13 @@ void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned lo
127 /// Not used 127 /// Not used
128} 128}
129 129
130std::list<std::string> FileWatcherGeneric::directories() { 130std::vector<std::string> FileWatcherGeneric::directories() {
131 std::list<std::string> dirs; 131 std::vector<std::string> dirs;
132 132
133 Lock lock( mWatchesLock ); 133 Lock lock( mWatchesLock );
134 134
135 dirs.reserve( mWatches.size() );
136
135 WatchList::iterator it = mWatches.begin(); 137 WatchList::iterator it = mWatches.begin();
136 138
137 for ( ; it != mWatches.end(); ++it ) { 139 for ( ; it != mWatches.end(); ++it ) {
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.hpp b/src/3rdParty/efsw/FileWatcherGeneric.hpp
index 4cb0b67..47f7e04 100755..100644
--- a/src/3rdParty/efsw/FileWatcherGeneric.hpp
+++ b/src/3rdParty/efsw/FileWatcherGeneric.hpp
@@ -4,7 +4,7 @@
4#include <efsw/DirWatcherGeneric.hpp> 4#include <efsw/DirWatcherGeneric.hpp>
5#include <efsw/FileWatcherImpl.hpp> 5#include <efsw/FileWatcherImpl.hpp>
6#include <efsw/WatcherGeneric.hpp> 6#include <efsw/WatcherGeneric.hpp>
7#include <list> 7#include <vector>
8 8
9namespace efsw { 9namespace efsw {
10 10
@@ -12,7 +12,7 @@ namespace efsw {
12/// @class FileWatcherGeneric 12/// @class FileWatcherGeneric
13class FileWatcherGeneric : public FileWatcherImpl { 13class FileWatcherGeneric : public FileWatcherImpl {
14 public: 14 public:
15 typedef std::list<WatcherGeneric*> WatchList; 15 typedef std::vector<WatcherGeneric*> WatchList;
16 16
17 FileWatcherGeneric( FileWatcher* parent ); 17 FileWatcherGeneric( FileWatcher* parent );
18 18
@@ -20,23 +20,24 @@ class FileWatcherGeneric : public FileWatcherImpl {
20 20
21 /// Add a directory watch 21 /// Add a directory watch
22 /// On error returns WatchID with Error type. 22 /// On error returns WatchID with Error type.
23 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); 23 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
24 const std::vector<WatcherOption> &options ) override;
24 25
25 /// Remove a directory watch. This is a brute force lazy search O(nlogn). 26 /// Remove a directory watch. This is a brute force lazy search O(nlogn).
26 void removeWatch( const std::string& directory ); 27 void removeWatch( const std::string& directory ) override;
27 28
28 /// Remove a directory watch. This is a map lookup O(logn). 29 /// Remove a directory watch. This is a map lookup O(logn).
29 void removeWatch( WatchID watchid ); 30 void removeWatch( WatchID watchid ) override;
30 31
31 /// Updates the watcher. Must be called often. 32 /// Updates the watcher. Must be called often.
32 void watch(); 33 void watch() override;
33 34
34 /// Handles the action 35 /// Handles the action
35 void handleAction( Watcher* watch, const std::string& filename, unsigned long action, 36 void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
36 std::string oldFilename = "" ); 37 std::string oldFilename = "" ) override;
37 38
38 /// @return Returns a list of the directories that are being watched 39 /// @return Returns a list of the directories that are being watched
39 std::list<std::string> directories(); 40 std::vector<std::string> directories() override;
40 41
41 protected: 42 protected:
42 Thread* mThread; 43 Thread* mThread;
@@ -49,7 +50,7 @@ class FileWatcherGeneric : public FileWatcherImpl {
49 50
50 Mutex mWatchesLock; 51 Mutex mWatchesLock;
51 52
52 bool pathInWatches( const std::string& path ); 53 bool pathInWatches( const std::string& path ) override;
53 54
54 private: 55 private:
55 void run(); 56 void run();
diff --git a/src/3rdParty/efsw/FileWatcherImpl.cpp b/src/3rdParty/efsw/FileWatcherImpl.cpp
index f6b86a5..bf69a45 100755..100644
--- a/src/3rdParty/efsw/FileWatcherImpl.cpp
+++ b/src/3rdParty/efsw/FileWatcherImpl.cpp
@@ -1,23 +1,34 @@
1#include <efsw/FileWatcherImpl.hpp> 1#include <efsw/FileWatcherImpl.hpp>
2#include <efsw/String.hpp> 2#include <efsw/String.hpp>
3#include <efsw/System.hpp> 3#include <efsw/System.hpp>
4 4
5namespace efsw { 5namespace efsw {
6 6
7FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : 7FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) :
8 mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { 8 mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) {
9 System::maxFD(); 9 System::maxFD();
10} 10}
11 11
12FileWatcherImpl::~FileWatcherImpl() {} 12FileWatcherImpl::~FileWatcherImpl() {}
13 13
14bool FileWatcherImpl::initOK() { 14bool FileWatcherImpl::initOK() {
15 return static_cast<bool>( mInitOK ); 15 return static_cast<bool>( mInitOK );
16} 16}
17 17
18bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { 18bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) {
19 return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || 19 return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) ||
20 -1 != String::strStartsWith( curPath, link ); 20 -1 != String::strStartsWith( curPath, link );
21} 21}
22 22
23} // namespace efsw 23int FileWatcherImpl::getOptionValue( const std::vector<WatcherOption>& options, Option option,
24 int defaultValue ) {
25 for ( size_t i = 0; i < options.size(); i++ ) {
26 if ( options[i].mOption == option ) {
27 return options[i].mValue;
28 }
29 }
30
31 return defaultValue;
32}
33
34} // namespace efsw
diff --git a/src/3rdParty/efsw/FileWatcherImpl.hpp b/src/3rdParty/efsw/FileWatcherImpl.hpp
index ea1beb8..a6ec472 100755..100644
--- a/src/3rdParty/efsw/FileWatcherImpl.hpp
+++ b/src/3rdParty/efsw/FileWatcherImpl.hpp
@@ -1,57 +1,64 @@
1#ifndef EFSW_FILEWATCHERIMPL_HPP 1#ifndef EFSW_FILEWATCHERIMPL_HPP
2#define EFSW_FILEWATCHERIMPL_HPP 2#define EFSW_FILEWATCHERIMPL_HPP
3 3
4#include <efsw/Atomic.hpp> 4#include <efsw/Atomic.hpp>
5#include <efsw/Mutex.hpp> 5#include <efsw/Mutex.hpp>
6#include <efsw/Thread.hpp> 6#include <efsw/Thread.hpp>
7#include <efsw/Watcher.hpp> 7#include <efsw/Watcher.hpp>
8#include <efsw/base.hpp> 8#include <efsw/base.hpp>
9#include <efsw/efsw.hpp> 9#include <efsw/efsw.hpp>
10 10
11namespace efsw { 11namespace efsw {
12 12
13class FileWatcherImpl { 13class FileWatcherImpl {
14 public: 14 public:
15 FileWatcherImpl( FileWatcher* parent ); 15 FileWatcherImpl( FileWatcher* parent );
16 16
17 virtual ~FileWatcherImpl(); 17 virtual ~FileWatcherImpl();
18 18
19 /// Add a directory watch 19 /// Add a directory watch
20 /// On error returns WatchID with Error type. 20 /// On error returns WatchID with Error type.
21 virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, 21 virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher,
22 bool recursive ) = 0; 22 bool recursive, const std::vector<WatcherOption>& options = {} ) = 0;
23 23
24 /// Remove a directory watch. This is a brute force lazy search O(nlogn). 24 /// Remove a directory watch. This is a brute force lazy search O(nlogn).
25 virtual void removeWatch( const std::string& directory ) = 0; 25 virtual void removeWatch( const std::string& directory ) = 0;
26 26
27 /// Remove a directory watch. This is a map lookup O(logn). 27 /// Remove a directory watch. This is a map lookup O(logn).
28 virtual void removeWatch( WatchID watchid ) = 0; 28 virtual void removeWatch( WatchID watchid ) = 0;
29 29
30 /// Updates the watcher. Must be called often. 30 /// Updates the watcher. Must be called often.
31 virtual void watch() = 0; 31 virtual void watch() = 0;
32 32
33 /// Handles the action 33 /// Handles the action
34 virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, 34 virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
35 std::string oldFilename = "" ) = 0; 35 std::string oldFilename = "" ) = 0;
36 36
37 /// @return Returns a list of the directories that are being watched 37 /// @return Returns a list of the directories that are being watched
38 virtual std::list<std::string> directories() = 0; 38 virtual std::vector<std::string> directories() = 0;
39 39
40 /// @return true if the backend init successfully 40 /// @return true if the backend init successfully
41 virtual bool initOK(); 41 virtual bool initOK();
42 42
43 /// @return If the link is allowed according to the current path and the state of out scope 43 /// @return If the link is allowed according to the current path and the state of out scope
44 /// links 44 /// links
45 virtual bool linkAllowed( const std::string& curPath, const std::string& link ); 45 virtual bool linkAllowed( const std::string& curPath, const std::string& link );
46 46
47 /// Search if a directory already exists in the watches 47 /// Search if a directory already exists in the watches
48 virtual bool pathInWatches( const std::string& path ) = 0; 48 virtual bool pathInWatches( const std::string& path ) = 0;
49 49
50 FileWatcher* mFileWatcher; 50 protected:
51 Atomic<bool> mInitOK; 51 friend class FileWatcher;
52 bool mIsGeneric; 52 friend class DirWatcherGeneric;
53}; 53
54 54 FileWatcher* mFileWatcher;
55} // namespace efsw 55 Atomic<bool> mInitOK;
56 56 bool mIsGeneric;
57#endif 57
58 int getOptionValue( const std::vector<WatcherOption>& options, Option option,
59 int defaultValue );
60};
61
62} // namespace efsw
63
64#endif
diff --git a/src/3rdParty/efsw/FileWatcherInotify.cpp b/src/3rdParty/efsw/FileWatcherInotify.cpp
index e0da76b..1ec3d48 100755..100644
--- a/src/3rdParty/efsw/FileWatcherInotify.cpp
+++ b/src/3rdParty/efsw/FileWatcherInotify.cpp
@@ -1,3 +1,4 @@
1#include <algorithm>
1#include <efsw/FileWatcherInotify.hpp> 2#include <efsw/FileWatcherInotify.hpp>
2 3
3#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 4#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
@@ -26,7 +27,7 @@
26namespace efsw { 27namespace efsw {
27 28
28FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : 29FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) :
29 FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ) { 30 FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) {
30 mFD = inotify_init(); 31 mFD = inotify_init();
31 32
32 if ( mFD < 0 ) { 33 if ( mFD < 0 ) {
@@ -38,13 +39,20 @@ FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) :
38 39
39FileWatcherInotify::~FileWatcherInotify() { 40FileWatcherInotify::~FileWatcherInotify() {
40 mInitOK = false; 41 mInitOK = false;
41 42 // There is deadlock when release FileWatcherInotify instance since its handAction
43 // function is still running and hangs in requiring lock without init lock captured.
44 while ( mIsTakingAction ) {
45 // It'd use condition-wait instead of sleep. Actually efsw has no such
46 // implementation so we just skip and sleep while for that to avoid deadlock.
47 usleep( 1000 );
48 };
42 Lock initLock( mInitLock ); 49 Lock initLock( mInitLock );
43 50
44 efSAFE_DELETE( mThread ); 51 efSAFE_DELETE( mThread );
45 52
46 Lock l( mWatchesLock ); 53 Lock l( mWatchesLock );
47 Lock l2( mRealWatchesLock ); 54 Lock l2( mRealWatchesLock );
55
48 WatchMap::iterator iter = mWatches.begin(); 56 WatchMap::iterator iter = mWatches.begin();
49 WatchMap::iterator end = mWatches.end(); 57 WatchMap::iterator end = mWatches.end();
50 58
@@ -61,15 +69,17 @@ FileWatcherInotify::~FileWatcherInotify() {
61} 69}
62 70
63WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, 71WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
64 bool recursive ) { 72 bool recursive, const std::vector<WatcherOption>& options ) {
65 if ( !mInitOK ) 73 if ( !mInitOK )
66 return Errors::Log::createLastError( Errors::Unspecified, directory ); 74 return Errors::Log::createLastError( Errors::Unspecified, directory );
67 Lock initLock( mInitLock ); 75 Lock initLock( mInitLock );
68 return addWatch( directory, watcher, recursive, NULL ); 76 bool syntheticEvents = getOptionValue( options, Options::LinuxProduceSyntheticEvents, 0 ) != 0;
77 return addWatch( directory, watcher, recursive, syntheticEvents, NULL );
69} 78}
70 79
71WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, 80WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
72 bool recursive, WatcherInotify* parent ) { 81 bool recursive, bool syntheticEvents,
82 WatcherInotify* parent, bool fromInternalEvent ) {
73 std::string dir( directory ); 83 std::string dir( directory );
74 84
75 FileSystem::dirAddSlashAtEnd( dir ); 85 FileSystem::dirAddSlashAtEnd( dir );
@@ -133,6 +143,7 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
133 { 143 {
134 Lock lock( mWatchesLock ); 144 Lock lock( mWatchesLock );
135 mWatches.insert( std::make_pair( wd, pWatch ) ); 145 mWatches.insert( std::make_pair( wd, pWatch ) );
146 mWatchesRef[pWatch->Directory] = wd;
136 } 147 }
137 148
138 if ( NULL == pWatch->Parent ) { 149 if ( NULL == pWatch->Parent ) {
@@ -151,7 +162,17 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
151 const FileInfo& cfi = it->second; 162 const FileInfo& cfi = it->second;
152 163
153 if ( cfi.isDirectory() && cfi.isReadable() ) { 164 if ( cfi.isDirectory() && cfi.isReadable() ) {
154 addWatch( cfi.Filepath, watcher, recursive, pWatch ); 165 addWatch( cfi.Filepath, watcher, recursive, syntheticEvents, pWatch );
166 }
167 }
168
169 if ( fromInternalEvent && parent != NULL && syntheticEvents ) {
170 for ( const auto& file : files ) {
171 if ( file.second.isRegularFile() ) {
172 pWatch->Listener->handleFileAction(
173 pWatch->ID, pWatch->Directory,
174 FileSystem::fileNameFromPath( file.second.Filepath ), Actions::Add );
175 }
155 } 176 }
156 } 177 }
157 } 178 }
@@ -161,6 +182,8 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
161 182
162void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { 183void FileWatcherInotify::removeWatchLocked( WatchID watchid ) {
163 WatchMap::iterator iter = mWatches.find( watchid ); 184 WatchMap::iterator iter = mWatches.find( watchid );
185 if ( iter == mWatches.end() )
186 return;
164 187
165 WatcherInotify* watch = iter->second; 188 WatcherInotify* watch = iter->second;
166 189
@@ -173,22 +196,21 @@ void FileWatcherInotify::removeWatchLocked( WatchID watchid ) {
173 } 196 }
174 } 197 }
175 198
176 if ( watch->Recursive ) { 199 if ( watch->Recursive && NULL == watch->Parent ) {
177 WatchMap::iterator it = mWatches.begin(); 200 WatchMap::iterator it = mWatches.begin();
178 std::list<WatchID> eraseWatches; 201 std::vector<WatchID> eraseWatches;
179 202
180 for ( ; it != mWatches.end(); ++it ) { 203 for ( ; it != mWatches.end(); ++it )
181 if ( it->second != watch && it->second->inParentTree( watch ) ) { 204 if ( it->second != watch && it->second->inParentTree( watch ) )
182 eraseWatches.push_back( it->second->InotifyID ); 205 eraseWatches.push_back( it->second->InotifyID );
183 }
184 }
185 206
186 for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); 207 for ( std::vector<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end();
187 ++eit ) { 208 ++eit ) {
188 removeWatch( *eit ); 209 removeWatch( *eit );
189 } 210 }
190 } 211 }
191 212
213 mWatchesRef.erase( watch->Directory );
192 mWatches.erase( iter ); 214 mWatches.erase( iter );
193 215
194 if ( NULL == watch->Parent ) { 216 if ( NULL == watch->Parent ) {
@@ -217,52 +239,11 @@ void FileWatcherInotify::removeWatch( const std::string& directory ) {
217 Lock lock( mWatchesLock ); 239 Lock lock( mWatchesLock );
218 Lock l( mRealWatchesLock ); 240 Lock l( mRealWatchesLock );
219 241
220 WatchMap::iterator iter = mWatches.begin(); 242 std::unordered_map<std::string, WatchID>::iterator ref = mWatchesRef.find( directory );
221 243 if ( ref == mWatchesRef.end() )
222 for ( ; iter != mWatches.end(); ++iter ) { 244 return;
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 245
263 break; 246 removeWatchLocked( ref->second );
264 }
265 }
266} 247}
267 248
268void FileWatcherInotify::removeWatch( WatchID watchid ) { 249void FileWatcherInotify::removeWatch( WatchID watchid ) {
@@ -270,13 +251,6 @@ void FileWatcherInotify::removeWatch( WatchID watchid ) {
270 return; 251 return;
271 Lock initLock( mInitLock ); 252 Lock initLock( mInitLock );
272 Lock lock( mWatchesLock ); 253 Lock lock( mWatchesLock );
273
274 WatchMap::iterator iter = mWatches.find( watchid );
275
276 if ( iter == mWatches.end() ) {
277 return;
278 }
279
280 removeWatchLocked( watchid ); 254 removeWatchLocked( watchid );
281} 255}
282 256
@@ -295,10 +269,8 @@ Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) {
295 269
296 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { 270 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
297 Watcher* watcher = it->second; 271 Watcher* watcher = it->second;
298 272 if ( watcher->Directory == watcherPath )
299 if ( watcher->Directory == watcherPath ) {
300 return watcher; 273 return watcher;
301 }
302 } 274 }
303 275
304 return NULL; 276 return NULL;
@@ -422,7 +394,7 @@ void FileWatcherInotify::run() {
422 const std::string& oldFileName = ( *it ).second; 394 const std::string& oldFileName = ( *it ).second;
423 395
424 /// Check if the file move was a folder already being watched 396 /// Check if the file move was a folder already being watched
425 std::list<Watcher*> eraseWatches; 397 std::vector<Watcher*> eraseWatches;
426 398
427 { 399 {
428 Lock lock( mWatchesLock ); 400 Lock lock( mWatchesLock );
@@ -439,12 +411,15 @@ void FileWatcherInotify::run() {
439 } 411 }
440 412
441 /// Remove invalid watches 413 /// Remove invalid watches
442 eraseWatches.sort(); 414 std::stable_sort( eraseWatches.begin(), eraseWatches.end(),
415 []( const Watcher* left, const Watcher* right ) {
416 return left->Directory < right->Directory;
417 } );
443 418
444 if ( eraseWatches.empty() ) { 419 if ( eraseWatches.empty() ) {
445 handleAction( watch, oldFileName, IN_DELETE ); 420 handleAction( watch, oldFileName, IN_DELETE );
446 } else { 421 } else {
447 for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); 422 for ( std::vector<Watcher*>::reverse_iterator eit = eraseWatches.rbegin();
448 eit != eraseWatches.rend(); ++eit ) { 423 eit != eraseWatches.rend(); ++eit ) {
449 Watcher* rmWatch = *eit; 424 Watcher* rmWatch = *eit;
450 425
@@ -485,8 +460,9 @@ void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath )
485 } 460 }
486 461
487 if ( !found ) { 462 if ( !found ) {
488 addWatch( fpath, watch->Listener, watch->Recursive, 463 WatcherInotify* iWatch = static_cast<WatcherInotify*>( watch );
489 static_cast<WatcherInotify*>( watch ) ); 464 addWatch( fpath, watch->Listener, watch->Recursive, iWatch->syntheticEvents,
465 static_cast<WatcherInotify*>( watch ), true );
490 } 466 }
491 } 467 }
492} 468}
@@ -496,7 +472,7 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena
496 if ( !watch || !watch->Listener || !mInitOK ) { 472 if ( !watch || !watch->Listener || !mInitOK ) {
497 return; 473 return;
498 } 474 }
499 475 mIsTakingAction = true;
500 Lock initLock( mInitLock ); 476 Lock initLock( mInitLock );
501 477
502 std::string fpath( watch->Directory + filename ); 478 std::string fpath( watch->Directory + filename );
@@ -563,18 +539,20 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena
563 } 539 }
564 } 540 }
565 } 541 }
542 mIsTakingAction = false;
566} 543}
567 544
568std::list<std::string> FileWatcherInotify::directories() { 545std::vector<std::string> FileWatcherInotify::directories() {
569 std::list<std::string> dirs; 546 std::vector<std::string> dirs;
570 547
571 Lock l( mRealWatchesLock ); 548 Lock l( mRealWatchesLock );
572 549
550 dirs.reserve( mRealWatches.size() );
551
573 WatchMap::iterator it = mRealWatches.begin(); 552 WatchMap::iterator it = mRealWatches.begin();
574 553
575 for ( ; it != mRealWatches.end(); ++it ) { 554 for ( ; it != mRealWatches.end(); ++it )
576 dirs.push_back( it->second->Directory ); 555 dirs.push_back( it->second->Directory );
577 }
578 556
579 return dirs; 557 return dirs;
580} 558}
@@ -585,11 +563,9 @@ bool FileWatcherInotify::pathInWatches( const std::string& path ) {
585 /// Search in the real watches, since it must allow adding a watch already watched as a subdir 563 /// Search in the real watches, since it must allow adding a watch already watched as a subdir
586 WatchMap::iterator it = mRealWatches.begin(); 564 WatchMap::iterator it = mRealWatches.begin();
587 565
588 for ( ; it != mRealWatches.end(); ++it ) { 566 for ( ; it != mRealWatches.end(); ++it )
589 if ( it->second->Directory == path ) { 567 if ( it->second->Directory == path )
590 return true; 568 return true;
591 }
592 }
593 569
594 return false; 570 return false;
595} 571}
diff --git a/src/3rdParty/efsw/FileWatcherInotify.hpp b/src/3rdParty/efsw/FileWatcherInotify.hpp
index dc922ac..26d2c0b 100755..100644
--- a/src/3rdParty/efsw/FileWatcherInotify.hpp
+++ b/src/3rdParty/efsw/FileWatcherInotify.hpp
@@ -7,6 +7,7 @@
7 7
8#include <efsw/WatcherInotify.hpp> 8#include <efsw/WatcherInotify.hpp>
9#include <map> 9#include <map>
10#include <unordered_map>
10#include <vector> 11#include <vector>
11 12
12namespace efsw { 13namespace efsw {
@@ -24,23 +25,24 @@ class FileWatcherInotify : public FileWatcherImpl {
24 25
25 /// Add a directory watch 26 /// Add a directory watch
26 /// On error returns WatchID with Error type. 27 /// On error returns WatchID with Error type.
27 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); 28 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
29 const std::vector<WatcherOption>& options ) override;
28 30
29 /// Remove a directory watch. This is a brute force lazy search O(nlogn). 31 /// Remove a directory watch. This is a brute force lazy search O(nlogn).
30 void removeWatch( const std::string& directory ); 32 void removeWatch( const std::string& directory ) override;
31 33
32 /// Remove a directory watch. This is a map lookup O(logn). 34 /// Remove a directory watch. This is a map lookup O(logn).
33 void removeWatch( WatchID watchid ); 35 void removeWatch( WatchID watchid ) override;
34 36
35 /// Updates the watcher. Must be called often. 37 /// Updates the watcher. Must be called often.
36 void watch(); 38 void watch() override;
37 39
38 /// Handles the action 40 /// Handles the action
39 void handleAction( Watcher* watch, const std::string& filename, unsigned long action, 41 void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
40 std::string oldFilename = "" ); 42 std::string oldFilename = "" ) override;
41 43
42 /// @return Returns a list of the directories that are being watched 44 /// @return Returns a list of the directories that are being watched
43 std::list<std::string> directories(); 45 std::vector<std::string> directories() override;
44 46
45 protected: 47 protected:
46 /// Map of WatchID to WatchStruct pointers 48 /// Map of WatchID to WatchStruct pointers
@@ -49,6 +51,8 @@ class FileWatcherInotify : public FileWatcherImpl {
49 /// User added watches 51 /// User added watches
50 WatchMap mRealWatches; 52 WatchMap mRealWatches;
51 53
54 std::unordered_map<std::string, WatchID> mWatchesRef;
55
52 /// inotify file descriptor 56 /// inotify file descriptor
53 int mFD; 57 int mFD;
54 58
@@ -57,12 +61,14 @@ class FileWatcherInotify : public FileWatcherImpl {
57 Mutex mWatchesLock; 61 Mutex mWatchesLock;
58 Mutex mRealWatchesLock; 62 Mutex mRealWatchesLock;
59 Mutex mInitLock; 63 Mutex mInitLock;
64 bool mIsTakingAction;
60 std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches; 65 std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches;
61 66
62 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, 67 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
63 WatcherInotify* parent = NULL ); 68 bool syntheticEvents, WatcherInotify* parent = NULL,
69 bool fromInternalEvent = false );
64 70
65 bool pathInWatches( const std::string& path ); 71 bool pathInWatches( const std::string& path ) override;
66 72
67 private: 73 private:
68 void run(); 74 void run();
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.cpp b/src/3rdParty/efsw/FileWatcherKqueue.cpp
index 38ffad9..ad03036 100755..100644
--- a/src/3rdParty/efsw/FileWatcherKqueue.cpp
+++ b/src/3rdParty/efsw/FileWatcherKqueue.cpp
@@ -45,7 +45,7 @@ FileWatcherKqueue::~FileWatcherKqueue() {
45} 45}
46 46
47WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, 47WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher,
48 bool recursive ) { 48 bool recursive, const std::vector<WatcherOption>& /*options*/ ) {
49 static bool s_ug = false; 49 static bool s_ug = false;
50 50
51 std::string dir( directory ); 51 std::string dir( directory );
@@ -184,11 +184,13 @@ void FileWatcherKqueue::run() {
184void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, 184void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/,
185 unsigned long /*action*/, std::string /*oldFilename*/ ) {} 185 unsigned long /*action*/, std::string /*oldFilename*/ ) {}
186 186
187std::list<std::string> FileWatcherKqueue::directories() { 187std::vector<std::string> FileWatcherKqueue::directories() {
188 std::list<std::string> dirs; 188 std::vector<std::string> dirs;
189 189
190 Lock lock( mWatchesLock ); 190 Lock lock( mWatchesLock );
191 191
192 dirs.reserve( mWatches.size() );
193
192 WatchMap::iterator it = mWatches.begin(); 194 WatchMap::iterator it = mWatches.begin();
193 195
194 for ( ; it != mWatches.end(); ++it ) { 196 for ( ; it != mWatches.end(); ++it ) {
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.hpp b/src/3rdParty/efsw/FileWatcherKqueue.hpp
index 1bf3755..ff5327b 100755..100644
--- a/src/3rdParty/efsw/FileWatcherKqueue.hpp
+++ b/src/3rdParty/efsw/FileWatcherKqueue.hpp
@@ -21,23 +21,24 @@ class FileWatcherKqueue : public FileWatcherImpl {
21 21
22 /// Add a directory watch 22 /// Add a directory watch
23 /// On error returns WatchID with Error type. 23 /// On error returns WatchID with Error type.
24 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); 24 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
25 const std::vector<WatcherOption> &options ) override;
25 26
26 /// Remove a directory watch. This is a brute force lazy search O(nlogn). 27 /// Remove a directory watch. This is a brute force lazy search O(nlogn).
27 void removeWatch( const std::string& directory ); 28 void removeWatch( const std::string& directory ) override;
28 29
29 /// Remove a directory watch. This is a map lookup O(logn). 30 /// Remove a directory watch. This is a map lookup O(logn).
30 void removeWatch( WatchID watchid ); 31 void removeWatch( WatchID watchid ) override;
31 32
32 /// Updates the watcher. Must be called often. 33 /// Updates the watcher. Must be called often.
33 void watch(); 34 void watch() override;
34 35
35 /// Handles the action 36 /// Handles the action
36 void handleAction( Watcher* watch, const std::string& filename, unsigned long action, 37 void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
37 std::string oldFilename = "" ); 38 std::string oldFilename = "" ) override;
38 39
39 /// @return Returns a list of the directories that are being watched 40 /// @return Returns a list of the directories that are being watched
40 std::list<std::string> directories(); 41 std::vector<std::string> directories() override;
41 42
42 protected: 43 protected:
43 /// Map of WatchID to WatchStruct pointers 44 /// Map of WatchID to WatchStruct pointers
@@ -53,7 +54,7 @@ class FileWatcherKqueue : public FileWatcherImpl {
53 54
54 Mutex mWatchesLock; 55 Mutex mWatchesLock;
55 56
56 std::list<WatchID> mRemoveList; 57 std::vector<WatchID> mRemoveList;
57 58
58 long mFileDescriptorCount; 59 long mFileDescriptorCount;
59 60
@@ -61,7 +62,7 @@ class FileWatcherKqueue : public FileWatcherImpl {
61 62
62 bool isAddingWatcher() const; 63 bool isAddingWatcher() const;
63 64
64 bool pathInWatches( const std::string& path ); 65 bool pathInWatches( const std::string& path ) override;
65 66
66 void addFD(); 67 void addFD();
67 68
diff --git a/src/3rdParty/efsw/FileWatcherWin32.cpp b/src/3rdParty/efsw/FileWatcherWin32.cpp
index 963dc98..19b71d7 100755..100644
--- a/src/3rdParty/efsw/FileWatcherWin32.cpp
+++ b/src/3rdParty/efsw/FileWatcherWin32.cpp
@@ -1,257 +1,267 @@
1#include <efsw/FileSystem.hpp> 1#include <efsw/FileSystem.hpp>
2#include <efsw/FileWatcherWin32.hpp> 2#include <efsw/FileWatcherWin32.hpp>
3#include <efsw/Lock.hpp> 3#include <efsw/Lock.hpp>
4#include <efsw/String.hpp> 4#include <efsw/String.hpp>
5#include <efsw/System.hpp> 5#include <efsw/System.hpp>
6 6
7#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
8 8
9namespace efsw { 9namespace efsw {
10 10
11FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : 11FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) :
12 FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { 12 FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) {
13 mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); 13 mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 );
14 if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) 14 if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE )
15 mInitOK = true; 15 mInitOK = true;
16} 16}
17 17
18FileWatcherWin32::~FileWatcherWin32() { 18FileWatcherWin32::~FileWatcherWin32() {
19 mInitOK = false; 19 mInitOK = false;
20 20
21 if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { 21 if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) {
22 PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); 22 PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL );
23 } 23 }
24 24
25 efSAFE_DELETE( mThread ); 25 efSAFE_DELETE( mThread );
26 26
27 removeAllWatches(); 27 removeAllWatches();
28 28
29 CloseHandle( mIOCP ); 29 if ( mIOCP )
30} 30 CloseHandle( mIOCP );
31 31}
32WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, 32
33 bool recursive ) { 33WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher,
34 std::string dir( directory ); 34 bool recursive, const std::vector<WatcherOption> &options ) {
35 35 std::string dir( directory );
36 FileInfo fi( dir ); 36
37 37 FileInfo fi( dir );
38 if ( !fi.isDirectory() ) { 38
39 return Errors::Log::createLastError( Errors::FileNotFound, dir ); 39 if ( !fi.isDirectory() ) {
40 } else if ( !fi.isReadable() ) { 40 return Errors::Log::createLastError( Errors::FileNotFound, dir );
41 return Errors::Log::createLastError( Errors::FileNotReadable, dir ); 41 } else if ( !fi.isReadable() ) {
42 } 42 return Errors::Log::createLastError( Errors::FileNotReadable, dir );
43 43 }
44 FileSystem::dirAddSlashAtEnd( dir ); 44
45 45 FileSystem::dirAddSlashAtEnd( dir );
46 Lock lock( mWatchesLock ); 46
47 47 Lock lock( mWatchesLock );
48 if ( pathInWatches( dir ) ) { 48
49 return Errors::Log::createLastError( Errors::FileRepeated, dir ); 49 if ( pathInWatches( dir ) ) {
50 } 50 return Errors::Log::createLastError( Errors::FileRepeated, dir );
51 51 }
52 WatchID watchid = ++mLastWatchID; 52
53 53 WatchID watchid = ++mLastWatchID;
54 WatcherStructWin32* watch = CreateWatch( 54
55 String::fromUtf8( dir ).toWideString().c_str(), recursive, 55 DWORD bufferSize = static_cast<DWORD>( getOptionValue(options, Option::WinBufferSize, 63 * 1024) );
56 FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME | 56 DWORD notifyFilter = static_cast<DWORD>( getOptionValue(options, Option::WinNotifyFilter,
57 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE, 57 FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE |
58 mIOCP ); 58 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
59 59 FILE_NOTIFY_CHANGE_SIZE) );
60 if ( NULL == watch ) { 60
61 return Errors::Log::createLastError( Errors::FileNotFound, dir ); 61 WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(),
62 } 62 recursive, bufferSize, notifyFilter, mIOCP );
63 63
64 // Add the handle to the handles vector 64 if ( NULL == watch ) {
65 watch->Watch->ID = watchid; 65 return Errors::Log::createLastError( Errors::FileNotFound, dir );
66 watch->Watch->Watch = this; 66 }
67 watch->Watch->Listener = watcher; 67
68 watch->Watch->DirName = new char[dir.length() + 1]; 68 // Add the handle to the handles vector
69 strcpy( watch->Watch->DirName, dir.c_str() ); 69 watch->Watch->ID = watchid;
70 70 watch->Watch->Watch = this;
71 mWatches.insert( watch ); 71 watch->Watch->Listener = watcher;
72 72 watch->Watch->DirName = new char[dir.length() + 1];
73 return watchid; 73 strcpy( watch->Watch->DirName, dir.c_str() );
74} 74
75 75 mWatches.insert( watch );
76void FileWatcherWin32::removeWatch( const std::string& directory ) { 76
77 Lock lock( mWatchesLock ); 77 return watchid;
78 78}
79 Watches::iterator iter = mWatches.begin(); 79
80 80void FileWatcherWin32::removeWatch( const std::string& directory ) {
81 for ( ; iter != mWatches.end(); ++iter ) { 81 Lock lock( mWatchesLock );
82 if ( directory == ( *iter )->Watch->DirName ) { 82
83 removeWatch( *iter ); 83 Watches::iterator iter = mWatches.begin();
84 break; 84
85 } 85 for ( ; iter != mWatches.end(); ++iter ) {
86 } 86 if ( directory == ( *iter )->Watch->DirName ) {
87} 87 removeWatch( *iter );
88 88 break;
89void FileWatcherWin32::removeWatch( WatchID watchid ) { 89 }
90 Lock lock( mWatchesLock ); 90 }
91 91}
92 Watches::iterator iter = mWatches.begin(); 92
93 93void FileWatcherWin32::removeWatch( WatchID watchid ) {
94 for ( ; iter != mWatches.end(); ++iter ) { 94 Lock lock( mWatchesLock );
95 // Find the watch ID 95
96 if ( ( *iter )->Watch->ID == watchid ) { 96 Watches::iterator iter = mWatches.begin();
97 removeWatch( *iter ); 97
98 return; 98 for ( ; iter != mWatches.end(); ++iter ) {
99 } 99 // Find the watch ID
100 } 100 if ( ( *iter )->Watch->ID == watchid ) {
101} 101 removeWatch( *iter );
102 102 return;
103void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { 103 }
104 Lock lock( mWatchesLock ); 104 }
105 105}
106 DestroyWatch( watch ); 106
107 mWatches.erase( watch ); 107void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) {
108} 108 Lock lock( mWatchesLock );
109 109
110void FileWatcherWin32::watch() { 110 DestroyWatch( watch );
111 if ( NULL == mThread ) { 111 mWatches.erase( watch );
112 mThread = new Thread( &FileWatcherWin32::run, this ); 112}
113 mThread->launch(); 113
114 } 114void FileWatcherWin32::watch() {
115} 115 if ( NULL == mThread ) {
116 116 mThread = new Thread( &FileWatcherWin32::run, this );
117void FileWatcherWin32::removeAllWatches() { 117 mThread->launch();
118 Lock lock( mWatchesLock ); 118 }
119 119}
120 Watches::iterator iter = mWatches.begin(); 120
121 121void FileWatcherWin32::removeAllWatches() {
122 for ( ; iter != mWatches.end(); ++iter ) { 122 Lock lock( mWatchesLock );
123 DestroyWatch( ( *iter ) ); 123
124 } 124 Watches::iterator iter = mWatches.begin();
125 125
126 mWatches.clear(); 126 for ( ; iter != mWatches.end(); ++iter ) {
127} 127 DestroyWatch( ( *iter ) );
128 128 }
129void FileWatcherWin32::run() { 129
130 do { 130 mWatches.clear();
131 if ( mInitOK && !mWatches.empty() ) { 131}
132 DWORD numOfBytes = 0; 132
133 OVERLAPPED* ov = NULL; 133void FileWatcherWin32::run() {
134 ULONG_PTR compKey = 0; 134 do {
135 BOOL res = FALSE; 135 if ( mInitOK && !mWatches.empty() ) {
136 136 DWORD numOfBytes = 0;
137 while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, 137 OVERLAPPED* ov = NULL;
138 INFINITE ) ) != FALSE ) { 138 ULONG_PTR compKey = 0;
139 if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { 139 BOOL res = FALSE;
140 break; 140
141 } else { 141 while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov,
142 Lock lock( mWatchesLock ); 142 INFINITE ) ) != FALSE ) {
143 WatchCallback( numOfBytes, ov ); 143 if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) {
144 } 144 break;
145 } 145 } else {
146 } else { 146 Lock lock( mWatchesLock );
147 System::sleep( 10 ); 147 if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end())
148 } 148 WatchCallback( numOfBytes, ov );
149 } while ( mInitOK ); 149 }
150 150 }
151 removeAllWatches(); 151 } else {
152} 152 System::sleep( 10 );
153 153 }
154void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, 154 } while ( mInitOK );
155 unsigned long action, std::string /*oldFilename*/ ) { 155
156 Action fwAction; 156 removeAllWatches();
157 157}
158 switch ( action ) { 158
159 case FILE_ACTION_RENAMED_OLD_NAME: 159void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename,
160 watch->OldFileName = filename; 160 unsigned long action, std::string /*oldFilename*/ ) {
161 return; 161 Action fwAction;
162 case FILE_ACTION_ADDED: 162
163 fwAction = Actions::Add; 163 switch ( action ) {
164 break; 164 case FILE_ACTION_RENAMED_OLD_NAME:
165 case FILE_ACTION_RENAMED_NEW_NAME: { 165 watch->OldFileName = filename;
166 fwAction = Actions::Moved; 166 return;
167 167 case FILE_ACTION_ADDED:
168 std::string fpath( watch->Directory + filename ); 168 fwAction = Actions::Add;
169 169 break;
170 // Update the directory path 170 case FILE_ACTION_RENAMED_NEW_NAME: {
171 if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { 171 fwAction = Actions::Moved;
172 // Update the new directory path 172
173 std::string opath( watch->Directory + watch->OldFileName ); 173 std::string fpath( watch->Directory + filename );
174 FileSystem::dirAddSlashAtEnd( opath ); 174
175 FileSystem::dirAddSlashAtEnd( fpath ); 175 // Update the directory path
176 176 if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) {
177 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { 177 // Update the new directory path
178 if ( ( *it )->Watch->Directory == opath ) { 178 std::string opath( watch->Directory + watch->OldFileName );
179 ( *it )->Watch->Directory = fpath; 179 FileSystem::dirAddSlashAtEnd( opath );
180 180 FileSystem::dirAddSlashAtEnd( fpath );
181 break; 181
182 } 182 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
183 } 183 if ( ( *it )->Watch->Directory == opath ) {
184 } 184 ( *it )->Watch->Directory = fpath;
185 185
186 std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); 186 break;
187 std::string realFilename = filename; 187 }
188 std::size_t sepPos = filename.find_last_of( "/\\" ); 188 }
189 std::string oldFolderPath = 189 }
190 static_cast<WatcherWin32*>( watch )->DirName + 190
191 watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); 191 std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName );
192 192 std::string realFilename = filename;
193 if ( sepPos != std::string::npos ) { 193 std::size_t sepPos = filename.find_last_of( "/\\" );
194 folderPath += filename.substr( 0, sepPos ); 194 std::string oldFolderPath =
195 realFilename = filename.substr( sepPos + 1 ); 195 static_cast<WatcherWin32*>( watch )->DirName +
196 } 196 watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) );
197 197
198 if ( folderPath == oldFolderPath ) { 198 if ( sepPos != std::string::npos ) {
199 watch->Listener->handleFileAction( 199 folderPath +=
200 watch->ID, folderPath, realFilename, fwAction, 200 filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos );
201 FileSystem::fileNameFromPath( watch->OldFileName ) ); 201 realFilename = filename.substr( sepPos + 1 );
202 } else { 202 }
203 watch->Listener->handleFileAction( watch->ID, 203
204 static_cast<WatcherWin32*>( watch )->DirName, 204 if ( folderPath == oldFolderPath ) {
205 filename, fwAction, watch->OldFileName ); 205 watch->Listener->handleFileAction(
206 } 206 watch->ID, folderPath, realFilename, fwAction,
207 return; 207 FileSystem::fileNameFromPath( watch->OldFileName ) );
208 } 208 } else {
209 case FILE_ACTION_REMOVED: 209 watch->Listener->handleFileAction( watch->ID,
210 fwAction = Actions::Delete; 210 static_cast<WatcherWin32*>( watch )->DirName,
211 break; 211 filename, fwAction, watch->OldFileName );
212 case FILE_ACTION_MODIFIED: 212 }
213 fwAction = Actions::Modified; 213 return;
214 break; 214 }
215 default: 215 case FILE_ACTION_REMOVED:
216 return; 216 fwAction = Actions::Delete;
217 }; 217 break;
218 218 case FILE_ACTION_MODIFIED:
219 std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); 219 fwAction = Actions::Modified;
220 std::string realFilename = filename; 220 break;
221 std::size_t sepPos = filename.find_last_of( "/\\" ); 221 default:
222 222 return;
223 if ( sepPos != std::string::npos ) { 223 };
224 folderPath += filename.substr( 0, sepPos ); 224
225 realFilename = filename.substr( sepPos + 1 ); 225 std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName );
226 } 226 std::string realFilename = filename;
227 227 std::size_t sepPos = filename.find_last_of( "/\\" );
228 watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); 228
229} 229 if ( sepPos != std::string::npos ) {
230 230 folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos );
231std::list<std::string> FileWatcherWin32::directories() { 231 realFilename = filename.substr( sepPos + 1 );
232 std::list<std::string> dirs; 232 }
233 233
234 Lock lock( mWatchesLock ); 234 FileSystem::dirAddSlashAtEnd( folderPath );
235 235
236 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { 236 watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction );
237 dirs.push_back( std::string( ( *it )->Watch->DirName ) ); 237}
238 } 238
239 239std::vector<std::string> FileWatcherWin32::directories() {
240 return dirs; 240 std::vector<std::string> dirs;
241} 241
242 242 Lock lock( mWatchesLock );
243bool FileWatcherWin32::pathInWatches( const std::string& path ) { 243
244 Lock lock( mWatchesLock ); 244 dirs.reserve( mWatches.size() );
245 245
246 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { 246 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
247 if ( ( *it )->Watch->DirName == path ) { 247 dirs.push_back( std::string( ( *it )->Watch->DirName ) );
248 return true; 248 }
249 } 249
250 } 250 return dirs;
251 251}
252 return false; 252
253} 253bool FileWatcherWin32::pathInWatches( const std::string& path ) {
254 254 Lock lock( mWatchesLock );
255} // namespace efsw 255
256 256 for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
257#endif 257 if ( ( *it )->Watch->DirName == path ) {
258 return true;
259 }
260 }
261
262 return false;
263}
264
265} // namespace efsw
266
267#endif
diff --git a/src/3rdParty/efsw/FileWatcherWin32.hpp b/src/3rdParty/efsw/FileWatcherWin32.hpp
index 94439cf..3016aac 100755..100644
--- a/src/3rdParty/efsw/FileWatcherWin32.hpp
+++ b/src/3rdParty/efsw/FileWatcherWin32.hpp
@@ -1,70 +1,71 @@
1#ifndef EFSW_FILEWATCHERWIN32_HPP 1#ifndef EFSW_FILEWATCHERWIN32_HPP
2#define EFSW_FILEWATCHERWIN32_HPP 2#define EFSW_FILEWATCHERWIN32_HPP
3 3
4#include <efsw/base.hpp> 4#include <efsw/base.hpp>
5 5
6#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 6#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
7 7
8#include <efsw/WatcherWin32.hpp> 8#include <efsw/WatcherWin32.hpp>
9#include <map> 9#include <map>
10#include <set> 10#include <unordered_set>
11#include <vector> 11#include <vector>
12 12
13namespace efsw { 13namespace efsw {
14 14
15/// Implementation for Win32 based on ReadDirectoryChangesW. 15/// Implementation for Win32 based on ReadDirectoryChangesW.
16/// @class FileWatcherWin32 16/// @class FileWatcherWin32
17class FileWatcherWin32 : public FileWatcherImpl { 17class FileWatcherWin32 : public FileWatcherImpl {
18 public: 18 public:
19 /// type for a map from WatchID to WatcherWin32 pointer 19 /// type for a map from WatchID to WatcherWin32 pointer
20 typedef std::set<WatcherStructWin32*> Watches; 20 typedef std::unordered_set<WatcherStructWin32*> Watches;
21 21
22 FileWatcherWin32( FileWatcher* parent ); 22 FileWatcherWin32( FileWatcher* parent );
23 23
24 virtual ~FileWatcherWin32(); 24 virtual ~FileWatcherWin32();
25 25
26 /// Add a directory watch 26 /// Add a directory watch
27 /// On error returns WatchID with Error type. 27 /// On error returns WatchID with Error type.
28 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); 28 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
29 29 const std::vector<WatcherOption> &options ) override;
30 /// Remove a directory watch. This is a brute force lazy search O(nlogn). 30
31 void removeWatch( const std::string& directory ); 31 /// Remove a directory watch. This is a brute force lazy search O(nlogn).
32 32 void removeWatch( const std::string& directory ) override;
33 /// Remove a directory watch. This is a map lookup O(logn). 33
34 void removeWatch( WatchID watchid ); 34 /// Remove a directory watch. This is a map lookup O(logn).
35 35 void removeWatch( WatchID watchid ) override;
36 /// Updates the watcher. Must be called often. 36
37 void watch(); 37 /// Updates the watcher. Must be called often.
38 38 void watch() override;
39 /// Handles the action 39
40 void handleAction( Watcher* watch, const std::string& filename, unsigned long action, 40 /// Handles the action
41 std::string oldFilename = "" ); 41 void handleAction( Watcher* watch, const std::string& filename, unsigned long action,
42 42 std::string oldFilename = "" ) override;
43 /// @return Returns a list of the directories that are being watched 43
44 std::list<std::string> directories(); 44 /// @return Returns a list of the directories that are being watched
45 45 std::vector<std::string> directories() override;
46 protected: 46
47 HANDLE mIOCP; 47 protected:
48 Watches mWatches; 48 HANDLE mIOCP;
49 49 Watches mWatches;
50 /// The last watchid 50
51 WatchID mLastWatchID; 51 /// The last watchid
52 Thread* mThread; 52 WatchID mLastWatchID;
53 Mutex mWatchesLock; 53 Thread* mThread;
54 54 Mutex mWatchesLock;
55 bool pathInWatches( const std::string& path ); 55
56 56 bool pathInWatches( const std::string& path ) override;
57 /// Remove all directory watches. 57
58 void removeAllWatches(); 58 /// Remove all directory watches.
59 59 void removeAllWatches();
60 void removeWatch( WatcherStructWin32* watch ); 60
61 61 void removeWatch( WatcherStructWin32* watch );
62 private: 62
63 void run(); 63 private:
64}; 64 void run();
65 65};
66} // namespace efsw 66
67 67} // namespace efsw
68#endif 68
69 69#endif
70#endif 70
71#endif
diff --git a/src/3rdParty/efsw/LICENSE b/src/3rdParty/efsw/LICENSE
index 37f354a..37f354a 100755..100644
--- a/src/3rdParty/efsw/LICENSE
+++ b/src/3rdParty/efsw/LICENSE
diff --git a/src/3rdParty/efsw/Lock.hpp b/src/3rdParty/efsw/Lock.hpp
index e8c522a..e8c522a 100755..100644
--- a/src/3rdParty/efsw/Lock.hpp
+++ b/src/3rdParty/efsw/Lock.hpp
diff --git a/src/3rdParty/efsw/Log.cpp b/src/3rdParty/efsw/Log.cpp
index ddf7a62..6f32df7 100755..100644
--- a/src/3rdParty/efsw/Log.cpp
+++ b/src/3rdParty/efsw/Log.cpp
@@ -1,20 +1,31 @@
1#include <efsw/efsw.hpp> 1#include <efsw/efsw.hpp>
2#include <efsw/Debug.hpp>
2 3
3namespace efsw { namespace Errors { 4namespace efsw { namespace Errors {
4 5
5static std::string LastError; 6static std::string LastError = "";
7static Error LastErrorCode = NoError;
6 8
7std::string Log::getLastErrorLog() { 9std::string Log::getLastErrorLog() {
8 return LastError; 10 return LastError;
9} 11}
10 12
13Error Log::getLastErrorCode() {
14 return LastErrorCode;
15}
16
17void Log::clearLastError() {
18 LastErrorCode = NoError;
19 LastError = "";
20}
21
11Error Log::createLastError( Error err, std::string log ) { 22Error Log::createLastError( Error err, std::string log ) {
12 switch ( err ) { 23 switch ( err ) {
13 case FileNotFound: 24 case FileNotFound:
14 LastError = "File not found ( " + log + " )"; 25 LastError = "File not found ( " + log + " )";
15 break; 26 break;
16 case FileRepeated: 27 case FileRepeated:
17 LastError = "File reapeated in watches ( " + log + " )"; 28 LastError = "File repeated in watches ( " + log + " )";
18 break; 29 break;
19 case FileOutOfScope: 30 case FileOutOfScope:
20 LastError = "Symlink file out of scope ( " + log + " )"; 31 LastError = "Symlink file out of scope ( " + log + " )";
@@ -23,11 +34,15 @@ Error Log::createLastError( Error err, std::string log ) {
23 LastError = 34 LastError =
24 "File is located in a remote file system, use a generic watcher. ( " + log + " )"; 35 "File is located in a remote file system, use a generic watcher. ( " + log + " )";
25 break; 36 break;
37 case WatcherFailed:
38 LastError = "File system watcher failed ( " + log + " )";
39 break;
26 case Unspecified: 40 case Unspecified:
27 default: 41 default:
28 LastError = log; 42 LastError = log;
29 } 43 }
30 44
45 efDEBUG( "%s\n", LastError.c_str() );
31 return err; 46 return err;
32} 47}
33 48
diff --git a/src/3rdParty/efsw/Mutex.cpp b/src/3rdParty/efsw/Mutex.cpp
index c961db1..c961db1 100755..100644
--- a/src/3rdParty/efsw/Mutex.cpp
+++ b/src/3rdParty/efsw/Mutex.cpp
diff --git a/src/3rdParty/efsw/Mutex.hpp b/src/3rdParty/efsw/Mutex.hpp
index d98ad17..d98ad17 100755..100644
--- a/src/3rdParty/efsw/Mutex.hpp
+++ b/src/3rdParty/efsw/Mutex.hpp
diff --git a/src/3rdParty/efsw/String.cpp b/src/3rdParty/efsw/String.cpp
index e3ba68f..e3ba68f 100755..100644
--- a/src/3rdParty/efsw/String.cpp
+++ b/src/3rdParty/efsw/String.cpp
diff --git a/src/3rdParty/efsw/String.hpp b/src/3rdParty/efsw/String.hpp
index 65bce33..b42b945 100755..100644
--- a/src/3rdParty/efsw/String.hpp
+++ b/src/3rdParty/efsw/String.hpp
@@ -11,7 +11,6 @@
11#include <cstdlib> 11#include <cstdlib>
12#include <cstring> 12#include <cstring>
13#include <efsw/base.hpp> 13#include <efsw/base.hpp>
14#include <fstream>
15#include <iostream> 14#include <iostream>
16#include <locale> 15#include <locale>
17#include <sstream> 16#include <sstream>
@@ -24,7 +23,7 @@ namespace efsw {
24 * **/ 23 * **/
25class String { 24class String {
26 public: 25 public:
27 typedef Uint32 StringBaseType; 26 typedef char32_t StringBaseType;
28 typedef std::basic_string<StringBaseType> StringType; 27 typedef std::basic_string<StringBaseType> StringType;
29 typedef StringType::iterator Iterator; //! Iterator type 28 typedef StringType::iterator Iterator; //! Iterator type
30 typedef StringType::const_iterator ConstIterator; //! Constant iterator type 29 typedef StringType::const_iterator ConstIterator; //! Constant iterator type
diff --git a/src/3rdParty/efsw/System.cpp b/src/3rdParty/efsw/System.cpp
index ba68bf4..ba68bf4 100755..100644
--- a/src/3rdParty/efsw/System.cpp
+++ b/src/3rdParty/efsw/System.cpp
diff --git a/src/3rdParty/efsw/System.hpp b/src/3rdParty/efsw/System.hpp
index 498e121..498e121 100755..100644
--- a/src/3rdParty/efsw/System.hpp
+++ b/src/3rdParty/efsw/System.hpp
diff --git a/src/3rdParty/efsw/Thread.cpp b/src/3rdParty/efsw/Thread.cpp
index e3f0fa0..cfa88b4 100755..100644
--- a/src/3rdParty/efsw/Thread.cpp
+++ b/src/3rdParty/efsw/Thread.cpp
@@ -34,7 +34,8 @@ void Thread::terminate() {
34} 34}
35 35
36void Thread::run() { 36void Thread::run() {
37 mEntryPoint->run(); 37 if ( mEntryPoint )
38 mEntryPoint->run();
38} 39}
39 40
40} // namespace efsw 41} // namespace efsw
diff --git a/src/3rdParty/efsw/Thread.hpp b/src/3rdParty/efsw/Thread.hpp
index b60373c..b60373c 100755..100644
--- a/src/3rdParty/efsw/Thread.hpp
+++ b/src/3rdParty/efsw/Thread.hpp
diff --git a/src/3rdParty/efsw/Utf.hpp b/src/3rdParty/efsw/Utf.hpp
index 6e9ea71..1b042cd 100755..100644
--- a/src/3rdParty/efsw/Utf.hpp
+++ b/src/3rdParty/efsw/Utf.hpp
@@ -1,721 +1,721 @@
1/** NOTE: 1/** NOTE:
2 * This code is based on the Utf implementation from SFML2. License zlib/png ( 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 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. 4 *the original implementation from SFML2.
5 * */ 5 * */
6 6
7#ifndef EFSW_UTF_HPP 7#ifndef EFSW_UTF_HPP
8#define EFSW_UTF_HPP 8#define EFSW_UTF_HPP
9 9
10//////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////
11// Headers 11// Headers
12//////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////
13#include <cstdlib> 13#include <cstdlib>
14#include <efsw/base.hpp> 14#include <efsw/base.hpp>
15#include <locale> 15#include <locale>
16#include <string> 16#include <string>
17 17
18namespace efsw { 18namespace efsw {
19 19
20template <unsigned int N> class Utf; 20template <unsigned int N> class Utf;
21 21
22//////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////
23/// \brief Specialization of the Utf template for UTF-8 23/// \brief Specialization of the Utf template for UTF-8
24/// 24///
25//////////////////////////////////////////////////////////// 25////////////////////////////////////////////////////////////
26template <> class Utf<8> { 26template <> class Utf<8> {
27 public: 27 public:
28 //////////////////////////////////////////////////////////// 28 ////////////////////////////////////////////////////////////
29 /// \brief Decode a single UTF-8 character 29 /// \brief Decode a single UTF-8 character
30 /// 30 ///
31 /// Decoding a character means finding its unique 32-bits 31 /// Decoding a character means finding its unique 32-bits
32 /// code (called the codepoint) in the Unicode standard. 32 /// code (called the codepoint) in the Unicode standard.
33 /// 33 ///
34 /// \param begin Iterator pointing to the beginning of the input sequence 34 /// \param begin Iterator pointing to the beginning of the input sequence
35 /// \param end Iterator pointing to the end 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 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 37 /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
38 /// 38 ///
39 /// \return Iterator pointing to one past the last read element of the input sequence 39 /// \return Iterator pointing to one past the last read element of the input sequence
40 /// 40 ///
41 //////////////////////////////////////////////////////////// 41 ////////////////////////////////////////////////////////////
42 template <typename In> 42 template <typename In>
43 static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); 43 static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 );
44 44
45 //////////////////////////////////////////////////////////// 45 ////////////////////////////////////////////////////////////
46 /// \brief Encode a single UTF-8 character 46 /// \brief Encode a single UTF-8 character
47 /// 47 ///
48 /// Encoding a character means converting a unique 32-bits 48 /// Encoding a character means converting a unique 32-bits
49 /// code (called the codepoint) in the target encoding, UTF-8. 49 /// code (called the codepoint) in the target encoding, UTF-8.
50 /// 50 ///
51 /// \param input Codepoint to encode as UTF-8 51 /// \param input Codepoint to encode as UTF-8
52 /// \param output Iterator pointing to the beginning of the output sequence 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) 53 /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them)
54 /// 54 ///
55 /// \return Iterator to the end of the output sequence which has been written 55 /// \return Iterator to the end of the output sequence which has been written
56 /// 56 ///
57 //////////////////////////////////////////////////////////// 57 ////////////////////////////////////////////////////////////
58 template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); 58 template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 );
59 59
60 //////////////////////////////////////////////////////////// 60 ////////////////////////////////////////////////////////////
61 /// \brief Advance to the next UTF-8 character 61 /// \brief Advance to the next UTF-8 character
62 /// 62 ///
63 /// This function is necessary for multi-elements encodings, as 63 /// This function is necessary for multi-elements encodings, as
64 /// a single character may use more than 1 storage element. 64 /// a single character may use more than 1 storage element.
65 /// 65 ///
66 /// \param begin Iterator pointing to the beginning of the input sequence 66 /// \param begin Iterator pointing to the beginning of the input sequence
67 /// \param end Iterator pointing to the end of the input sequence 67 /// \param end Iterator pointing to the end of the input sequence
68 /// 68 ///
69 /// \return Iterator pointing to one past the last read element of the input sequence 69 /// \return Iterator pointing to one past the last read element of the input sequence
70 /// 70 ///
71 //////////////////////////////////////////////////////////// 71 ////////////////////////////////////////////////////////////
72 template <typename In> static In Next( In begin, In end ); 72 template <typename In> static In Next( In begin, In end );
73 73
74 //////////////////////////////////////////////////////////// 74 ////////////////////////////////////////////////////////////
75 /// \brief Count the number of characters of a UTF-8 sequence 75 /// \brief Count the number of characters of a UTF-8 sequence
76 /// 76 ///
77 /// This function is necessary for multi-elements encodings, as 77 /// This function is necessary for multi-elements encodings, as
78 /// a single character may use more than 1 storage element, thus the 78 /// a single character may use more than 1 storage element, thus the
79 /// total size can be different from (begin - end). 79 /// total size can be different from (begin - end).
80 /// 80 ///
81 /// \param begin Iterator pointing to the beginning of the input sequence 81 /// \param begin Iterator pointing to the beginning of the input sequence
82 /// \param end Iterator pointing to the end of the input sequence 82 /// \param end Iterator pointing to the end of the input sequence
83 /// 83 ///
84 /// \return Iterator pointing to one past the last read element of the input sequence 84 /// \return Iterator pointing to one past the last read element of the input sequence
85 /// 85 ///
86 //////////////////////////////////////////////////////////// 86 ////////////////////////////////////////////////////////////
87 template <typename In> static std::size_t Count( In begin, In end ); 87 template <typename In> static std::size_t Count( In begin, In end );
88 88
89 //////////////////////////////////////////////////////////// 89 ////////////////////////////////////////////////////////////
90 /// \brief Convert an ANSI characters range to UTF-8 90 /// \brief Convert an ANSI characters range to UTF-8
91 /// 91 ///
92 /// The current global locale will be used by default, unless you 92 /// The current global locale will be used by default, unless you
93 /// pass a custom one in the \a locale parameter. 93 /// pass a custom one in the \a locale parameter.
94 /// 94 ///
95 /// \param begin Iterator pointing to the beginning of the input sequence 95 /// \param begin Iterator pointing to the beginning of the input sequence
96 /// \param end Iterator pointing to the end 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 97 /// \param output Iterator pointing to the beginning of the output sequence
98 /// \param locale Locale to use for conversion 98 /// \param locale Locale to use for conversion
99 /// 99 ///
100 /// \return Iterator to the end of the output sequence which has been written 100 /// \return Iterator to the end of the output sequence which has been written
101 /// 101 ///
102 //////////////////////////////////////////////////////////// 102 ////////////////////////////////////////////////////////////
103 template <typename In, typename Out> 103 template <typename In, typename Out>
104 static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); 104 static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() );
105 105
106 //////////////////////////////////////////////////////////// 106 ////////////////////////////////////////////////////////////
107 /// \brief Convert a wide characters range to UTF-8 107 /// \brief Convert a wide characters range to UTF-8
108 /// 108 ///
109 /// \param begin Iterator pointing to the beginning of the input sequence 109 /// \param begin Iterator pointing to the beginning of the input sequence
110 /// \param end Iterator pointing to the end 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 111 /// \param output Iterator pointing to the beginning of the output sequence
112 /// 112 ///
113 /// \return Iterator to the end of the output sequence which has been written 113 /// \return Iterator to the end of the output sequence which has been written
114 /// 114 ///
115 //////////////////////////////////////////////////////////// 115 ////////////////////////////////////////////////////////////
116 template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); 116 template <typename In, typename Out> static Out FromWide( In begin, In end, Out output );
117 117
118 //////////////////////////////////////////////////////////// 118 ////////////////////////////////////////////////////////////
119 /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 119 /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8
120 /// 120 ///
121 /// \param begin Iterator pointing to the beginning of the input sequence 121 /// \param begin Iterator pointing to the beginning of the input sequence
122 /// \param end Iterator pointing to the end 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 123 /// \param output Iterator pointing to the beginning of the output sequence
124 /// \param locale Locale to use for conversion 124 /// \param locale Locale to use for conversion
125 /// 125 ///
126 /// \return Iterator to the end of the output sequence which has been written 126 /// \return Iterator to the end of the output sequence which has been written
127 /// 127 ///
128 //////////////////////////////////////////////////////////// 128 ////////////////////////////////////////////////////////////
129 template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); 129 template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output );
130 130
131 //////////////////////////////////////////////////////////// 131 ////////////////////////////////////////////////////////////
132 /// \brief Convert an UTF-8 characters range to ANSI characters 132 /// \brief Convert an UTF-8 characters range to ANSI characters
133 /// 133 ///
134 /// The current global locale will be used by default, unless you 134 /// The current global locale will be used by default, unless you
135 /// pass a custom one in the \a locale parameter. 135 /// pass a custom one in the \a locale parameter.
136 /// 136 ///
137 /// \param begin Iterator pointing to the beginning of the input sequence 137 /// \param begin Iterator pointing to the beginning of the input sequence
138 /// \param end Iterator pointing to the end 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 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) 140 /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
141 /// \param locale Locale to use for conversion 141 /// \param locale Locale to use for conversion
142 /// 142 ///
143 /// \return Iterator to the end of the output sequence which has been written 143 /// \return Iterator to the end of the output sequence which has been written
144 /// 144 ///
145 //////////////////////////////////////////////////////////// 145 ////////////////////////////////////////////////////////////
146 template <typename In, typename Out> 146 template <typename In, typename Out>
147 static Out ToAnsi( In begin, In end, Out output, char replacement = 0, 147 static Out ToAnsi( In begin, In end, Out output, char replacement = 0,
148 const std::locale& locale = std::locale() ); 148 const std::locale& locale = std::locale() );
149 149
150#ifndef EFSW_NO_WIDECHAR 150#ifndef EFSW_NO_WIDECHAR
151 //////////////////////////////////////////////////////////// 151 ////////////////////////////////////////////////////////////
152 /// \brief Convert an UTF-8 characters range to wide characters 152 /// \brief Convert an UTF-8 characters range to wide characters
153 /// 153 ///
154 /// \param begin Iterator pointing to the beginning of the input sequence 154 /// \param begin Iterator pointing to the beginning of the input sequence
155 /// \param end Iterator pointing to the end 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 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) 157 /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
158 /// 158 ///
159 /// \return Iterator to the end of the output sequence which has been written 159 /// \return Iterator to the end of the output sequence which has been written
160 /// 160 ///
161 //////////////////////////////////////////////////////////// 161 ////////////////////////////////////////////////////////////
162 template <typename In, typename Out> 162 template <typename In, typename Out>
163 static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); 163 static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 );
164#endif 164#endif
165 165
166 //////////////////////////////////////////////////////////// 166 ////////////////////////////////////////////////////////////
167 /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters 167 /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters
168 /// 168 ///
169 /// \param begin Iterator pointing to the beginning of the input sequence 169 /// \param begin Iterator pointing to the beginning of the input sequence
170 /// \param end Iterator pointing to the end 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 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) 172 /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
173 /// 173 ///
174 /// \return Iterator to the end of the output sequence which has been written 174 /// \return Iterator to the end of the output sequence which has been written
175 /// 175 ///
176 //////////////////////////////////////////////////////////// 176 ////////////////////////////////////////////////////////////
177 template <typename In, typename Out> 177 template <typename In, typename Out>
178 static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); 178 static Out ToLatin1( In begin, In end, Out output, char replacement = 0 );
179 179
180 //////////////////////////////////////////////////////////// 180 ////////////////////////////////////////////////////////////
181 /// \brief Convert a UTF-8 characters range to UTF-8 181 /// \brief Convert a UTF-8 characters range to UTF-8
182 /// 182 ///
183 /// This functions does nothing more than a direct copy; 183 /// This functions does nothing more than a direct copy;
184 /// it is defined only to provide the same interface as other 184 /// it is defined only to provide the same interface as other
185 /// specializations of the efsw::Utf<> template, and allow 185 /// specializations of the efsw::Utf<> template, and allow
186 /// generic code to be written on top of it. 186 /// generic code to be written on top of it.
187 /// 187 ///
188 /// \param begin Iterator pointing to the beginning of the input sequence 188 /// \param begin Iterator pointing to the beginning of the input sequence
189 /// \param end Iterator pointing to the end 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 190 /// \param output Iterator pointing to the beginning of the output sequence
191 /// 191 ///
192 /// \return Iterator to the end of the output sequence which has been written 192 /// \return Iterator to the end of the output sequence which has been written
193 /// 193 ///
194 //////////////////////////////////////////////////////////// 194 ////////////////////////////////////////////////////////////
195 template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); 195 template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output );
196 196
197 //////////////////////////////////////////////////////////// 197 ////////////////////////////////////////////////////////////
198 /// \brief Convert a UTF-8 characters range to UTF-16 198 /// \brief Convert a UTF-8 characters range to UTF-16
199 /// 199 ///
200 /// \param begin Iterator pointing to the beginning of the input sequence 200 /// \param begin Iterator pointing to the beginning of the input sequence
201 /// \param end Iterator pointing to the end 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 202 /// \param output Iterator pointing to the beginning of the output sequence
203 /// 203 ///
204 /// \return Iterator to the end of the output sequence which has been written 204 /// \return Iterator to the end of the output sequence which has been written
205 /// 205 ///
206 //////////////////////////////////////////////////////////// 206 ////////////////////////////////////////////////////////////
207 template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); 207 template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output );
208 208
209 //////////////////////////////////////////////////////////// 209 ////////////////////////////////////////////////////////////
210 /// \brief Convert a UTF-8 characters range to UTF-32 210 /// \brief Convert a UTF-8 characters range to UTF-32
211 /// 211 ///
212 /// \param begin Iterator pointing to the beginning of the input sequence 212 /// \param begin Iterator pointing to the beginning of the input sequence
213 /// \param end Iterator pointing to the end 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 214 /// \param output Iterator pointing to the beginning of the output sequence
215 /// 215 ///
216 /// \return Iterator to the end of the output sequence which has been written 216 /// \return Iterator to the end of the output sequence which has been written
217 /// 217 ///
218 //////////////////////////////////////////////////////////// 218 ////////////////////////////////////////////////////////////
219 template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); 219 template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output );
220}; 220};
221 221
222//////////////////////////////////////////////////////////// 222////////////////////////////////////////////////////////////
223/// \brief Specialization of the Utf template for UTF-16 223/// \brief Specialization of the Utf template for UTF-16
224/// 224///
225//////////////////////////////////////////////////////////// 225////////////////////////////////////////////////////////////
226template <> class Utf<16> { 226template <> class Utf<16> {
227 public: 227 public:
228 //////////////////////////////////////////////////////////// 228 ////////////////////////////////////////////////////////////
229 /// \brief Decode a single UTF-16 character 229 /// \brief Decode a single UTF-16 character
230 /// 230 ///
231 /// Decoding a character means finding its unique 32-bits 231 /// Decoding a character means finding its unique 32-bits
232 /// code (called the codepoint) in the Unicode standard. 232 /// code (called the codepoint) in the Unicode standard.
233 /// 233 ///
234 /// \param begin Iterator pointing to the beginning of the input sequence 234 /// \param begin Iterator pointing to the beginning of the input sequence
235 /// \param end Iterator pointing to the end 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 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 237 /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
238 /// 238 ///
239 /// \return Iterator pointing to one past the last read element of the input sequence 239 /// \return Iterator pointing to one past the last read element of the input sequence
240 /// 240 ///
241 //////////////////////////////////////////////////////////// 241 ////////////////////////////////////////////////////////////
242 template <typename In> 242 template <typename In>
243 static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); 243 static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 );
244 244
245 //////////////////////////////////////////////////////////// 245 ////////////////////////////////////////////////////////////
246 /// \brief Encode a single UTF-16 character 246 /// \brief Encode a single UTF-16 character
247 /// 247 ///
248 /// Encoding a character means converting a unique 32-bits 248 /// Encoding a character means converting a unique 32-bits
249 /// code (called the codepoint) in the target encoding, UTF-16. 249 /// code (called the codepoint) in the target encoding, UTF-16.
250 /// 250 ///
251 /// \param input Codepoint to encode as UTF-16 251 /// \param input Codepoint to encode as UTF-16
252 /// \param output Iterator pointing to the beginning of the output sequence 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) 253 /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them)
254 /// 254 ///
255 /// \return Iterator to the end of the output sequence which has been written 255 /// \return Iterator to the end of the output sequence which has been written
256 /// 256 ///
257 //////////////////////////////////////////////////////////// 257 ////////////////////////////////////////////////////////////
258 template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); 258 template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 );
259 259
260 //////////////////////////////////////////////////////////// 260 ////////////////////////////////////////////////////////////
261 /// \brief Advance to the next UTF-16 character 261 /// \brief Advance to the next UTF-16 character
262 /// 262 ///
263 /// This function is necessary for multi-elements encodings, as 263 /// This function is necessary for multi-elements encodings, as
264 /// a single character may use more than 1 storage element. 264 /// a single character may use more than 1 storage element.
265 /// 265 ///
266 /// \param begin Iterator pointing to the beginning of the input sequence 266 /// \param begin Iterator pointing to the beginning of the input sequence
267 /// \param end Iterator pointing to the end of the input sequence 267 /// \param end Iterator pointing to the end of the input sequence
268 /// 268 ///
269 /// \return Iterator pointing to one past the last read element of the input sequence 269 /// \return Iterator pointing to one past the last read element of the input sequence
270 /// 270 ///
271 //////////////////////////////////////////////////////////// 271 ////////////////////////////////////////////////////////////
272 template <typename In> static In Next( In begin, In end ); 272 template <typename In> static In Next( In begin, In end );
273 273
274 //////////////////////////////////////////////////////////// 274 ////////////////////////////////////////////////////////////
275 /// \brief Count the number of characters of a UTF-16 sequence 275 /// \brief Count the number of characters of a UTF-16 sequence
276 /// 276 ///
277 /// This function is necessary for multi-elements encodings, as 277 /// This function is necessary for multi-elements encodings, as
278 /// a single character may use more than 1 storage element, thus the 278 /// a single character may use more than 1 storage element, thus the
279 /// total size can be different from (begin - end). 279 /// total size can be different from (begin - end).
280 /// 280 ///
281 /// \param begin Iterator pointing to the beginning of the input sequence 281 /// \param begin Iterator pointing to the beginning of the input sequence
282 /// \param end Iterator pointing to the end of the input sequence 282 /// \param end Iterator pointing to the end of the input sequence
283 /// 283 ///
284 /// \return Iterator pointing to one past the last read element of the input sequence 284 /// \return Iterator pointing to one past the last read element of the input sequence
285 /// 285 ///
286 //////////////////////////////////////////////////////////// 286 ////////////////////////////////////////////////////////////
287 template <typename In> static std::size_t Count( In begin, In end ); 287 template <typename In> static std::size_t Count( In begin, In end );
288 288
289 //////////////////////////////////////////////////////////// 289 ////////////////////////////////////////////////////////////
290 /// \brief Convert an ANSI characters range to UTF-16 290 /// \brief Convert an ANSI characters range to UTF-16
291 /// 291 ///
292 /// The current global locale will be used by default, unless you 292 /// The current global locale will be used by default, unless you
293 /// pass a custom one in the \a locale parameter. 293 /// pass a custom one in the \a locale parameter.
294 /// 294 ///
295 /// \param begin Iterator pointing to the beginning of the input sequence 295 /// \param begin Iterator pointing to the beginning of the input sequence
296 /// \param end Iterator pointing to the end 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 297 /// \param output Iterator pointing to the beginning of the output sequence
298 /// \param locale Locale to use for conversion 298 /// \param locale Locale to use for conversion
299 /// 299 ///
300 /// \return Iterator to the end of the output sequence which has been written 300 /// \return Iterator to the end of the output sequence which has been written
301 /// 301 ///
302 //////////////////////////////////////////////////////////// 302 ////////////////////////////////////////////////////////////
303 template <typename In, typename Out> 303 template <typename In, typename Out>
304 static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); 304 static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() );
305 305
306 //////////////////////////////////////////////////////////// 306 ////////////////////////////////////////////////////////////
307 /// \brief Convert a wide characters range to UTF-16 307 /// \brief Convert a wide characters range to UTF-16
308 /// 308 ///
309 /// \param begin Iterator pointing to the beginning of the input sequence 309 /// \param begin Iterator pointing to the beginning of the input sequence
310 /// \param end Iterator pointing to the end 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 311 /// \param output Iterator pointing to the beginning of the output sequence
312 /// 312 ///
313 /// \return Iterator to the end of the output sequence which has been written 313 /// \return Iterator to the end of the output sequence which has been written
314 /// 314 ///
315 //////////////////////////////////////////////////////////// 315 ////////////////////////////////////////////////////////////
316 template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); 316 template <typename In, typename Out> static Out FromWide( In begin, In end, Out output );
317 317
318 //////////////////////////////////////////////////////////// 318 ////////////////////////////////////////////////////////////
319 /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 319 /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16
320 /// 320 ///
321 /// \param begin Iterator pointing to the beginning of the input sequence 321 /// \param begin Iterator pointing to the beginning of the input sequence
322 /// \param end Iterator pointing to the end 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 323 /// \param output Iterator pointing to the beginning of the output sequence
324 /// \param locale Locale to use for conversion 324 /// \param locale Locale to use for conversion
325 /// 325 ///
326 /// \return Iterator to the end of the output sequence which has been written 326 /// \return Iterator to the end of the output sequence which has been written
327 /// 327 ///
328 //////////////////////////////////////////////////////////// 328 ////////////////////////////////////////////////////////////
329 template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); 329 template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output );
330 330
331 //////////////////////////////////////////////////////////// 331 ////////////////////////////////////////////////////////////
332 /// \brief Convert an UTF-16 characters range to ANSI characters 332 /// \brief Convert an UTF-16 characters range to ANSI characters
333 /// 333 ///
334 /// The current global locale will be used by default, unless you 334 /// The current global locale will be used by default, unless you
335 /// pass a custom one in the \a locale parameter. 335 /// pass a custom one in the \a locale parameter.
336 /// 336 ///
337 /// \param begin Iterator pointing to the beginning of the input sequence 337 /// \param begin Iterator pointing to the beginning of the input sequence
338 /// \param end Iterator pointing to the end 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 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) 340 /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
341 /// \param locale Locale to use for conversion 341 /// \param locale Locale to use for conversion
342 /// 342 ///
343 /// \return Iterator to the end of the output sequence which has been written 343 /// \return Iterator to the end of the output sequence which has been written
344 /// 344 ///
345 //////////////////////////////////////////////////////////// 345 ////////////////////////////////////////////////////////////
346 template <typename In, typename Out> 346 template <typename In, typename Out>
347 static Out ToAnsi( In begin, In end, Out output, char replacement = 0, 347 static Out ToAnsi( In begin, In end, Out output, char replacement = 0,
348 const std::locale& locale = std::locale() ); 348 const std::locale& locale = std::locale() );
349 349
350#ifndef EFSW_NO_WIDECHAR 350#ifndef EFSW_NO_WIDECHAR
351 //////////////////////////////////////////////////////////// 351 ////////////////////////////////////////////////////////////
352 /// \brief Convert an UTF-16 characters range to wide characters 352 /// \brief Convert an UTF-16 characters range to wide characters
353 /// 353 ///
354 /// \param begin Iterator pointing to the beginning of the input sequence 354 /// \param begin Iterator pointing to the beginning of the input sequence
355 /// \param end Iterator pointing to the end 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 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) 357 /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
358 /// 358 ///
359 /// \return Iterator to the end of the output sequence which has been written 359 /// \return Iterator to the end of the output sequence which has been written
360 /// 360 ///
361 //////////////////////////////////////////////////////////// 361 ////////////////////////////////////////////////////////////
362 template <typename In, typename Out> 362 template <typename In, typename Out>
363 static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); 363 static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 );
364#endif 364#endif
365 365
366 //////////////////////////////////////////////////////////// 366 ////////////////////////////////////////////////////////////
367 /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters 367 /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
368 /// 368 ///
369 /// \param begin Iterator pointing to the beginning of the input sequence 369 /// \param begin Iterator pointing to the beginning of the input sequence
370 /// \param end Iterator pointing to the end 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 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) 372 /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
373 /// 373 ///
374 /// \return Iterator to the end of the output sequence which has been written 374 /// \return Iterator to the end of the output sequence which has been written
375 /// 375 ///
376 //////////////////////////////////////////////////////////// 376 ////////////////////////////////////////////////////////////
377 template <typename In, typename Out> 377 template <typename In, typename Out>
378 static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); 378 static Out ToLatin1( In begin, In end, Out output, char replacement = 0 );
379 379
380 //////////////////////////////////////////////////////////// 380 ////////////////////////////////////////////////////////////
381 /// \brief Convert a UTF-16 characters range to UTF-8 381 /// \brief Convert a UTF-16 characters range to UTF-8
382 /// 382 ///
383 /// \param begin Iterator pointing to the beginning of the input sequence 383 /// \param begin Iterator pointing to the beginning of the input sequence
384 /// \param end Iterator pointing to the end 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 385 /// \param output Iterator pointing to the beginning of the output sequence
386 /// 386 ///
387 /// \return Iterator to the end of the output sequence which has been written 387 /// \return Iterator to the end of the output sequence which has been written
388 /// 388 ///
389 //////////////////////////////////////////////////////////// 389 ////////////////////////////////////////////////////////////
390 template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); 390 template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output );
391 391
392 //////////////////////////////////////////////////////////// 392 ////////////////////////////////////////////////////////////
393 /// \brief Convert a UTF-16 characters range to UTF-16 393 /// \brief Convert a UTF-16 characters range to UTF-16
394 /// 394 ///
395 /// This functions does nothing more than a direct copy; 395 /// This functions does nothing more than a direct copy;
396 /// it is defined only to provide the same interface as other 396 /// it is defined only to provide the same interface as other
397 /// specializations of the efsw::Utf<> template, and allow 397 /// specializations of the efsw::Utf<> template, and allow
398 /// generic code to be written on top of it. 398 /// generic code to be written on top of it.
399 /// 399 ///
400 /// \param begin Iterator pointing to the beginning of the input sequence 400 /// \param begin Iterator pointing to the beginning of the input sequence
401 /// \param end Iterator pointing to the end 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 402 /// \param output Iterator pointing to the beginning of the output sequence
403 /// 403 ///
404 /// \return Iterator to the end of the output sequence which has been written 404 /// \return Iterator to the end of the output sequence which has been written
405 /// 405 ///
406 //////////////////////////////////////////////////////////// 406 ////////////////////////////////////////////////////////////
407 template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); 407 template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output );
408 408
409 //////////////////////////////////////////////////////////// 409 ////////////////////////////////////////////////////////////
410 /// \brief Convert a UTF-16 characters range to UTF-32 410 /// \brief Convert a UTF-16 characters range to UTF-32
411 /// 411 ///
412 /// \param begin Iterator pointing to the beginning of the input sequence 412 /// \param begin Iterator pointing to the beginning of the input sequence
413 /// \param end Iterator pointing to the end 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 414 /// \param output Iterator pointing to the beginning of the output sequence
415 /// 415 ///
416 /// \return Iterator to the end of the output sequence which has been written 416 /// \return Iterator to the end of the output sequence which has been written
417 /// 417 ///
418 //////////////////////////////////////////////////////////// 418 ////////////////////////////////////////////////////////////
419 template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); 419 template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output );
420}; 420};
421 421
422//////////////////////////////////////////////////////////// 422////////////////////////////////////////////////////////////
423/// \brief Specialization of the Utf template for UTF-32 423/// \brief Specialization of the Utf template for UTF-32
424/// 424///
425//////////////////////////////////////////////////////////// 425////////////////////////////////////////////////////////////
426template <> class Utf<32> { 426template <> class Utf<32> {
427 public: 427 public:
428 //////////////////////////////////////////////////////////// 428 ////////////////////////////////////////////////////////////
429 /// \brief Decode a single UTF-32 character 429 /// \brief Decode a single UTF-32 character
430 /// 430 ///
431 /// Decoding a character means finding its unique 32-bits 431 /// Decoding a character means finding its unique 32-bits
432 /// code (called the codepoint) in the Unicode standard. 432 /// code (called the codepoint) in the Unicode standard.
433 /// For UTF-32, the character value is the same as the codepoint. 433 /// For UTF-32, the character value is the same as the codepoint.
434 /// 434 ///
435 /// \param begin Iterator pointing to the beginning of the input sequence 435 /// \param begin Iterator pointing to the beginning of the input sequence
436 /// \param end Iterator pointing to the end 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 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 438 /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
439 /// 439 ///
440 /// \return Iterator pointing to one past the last read element of the input sequence 440 /// \return Iterator pointing to one past the last read element of the input sequence
441 /// 441 ///
442 //////////////////////////////////////////////////////////// 442 ////////////////////////////////////////////////////////////
443 template <typename In> 443 template <typename In>
444 static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); 444 static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 );
445 445
446 //////////////////////////////////////////////////////////// 446 ////////////////////////////////////////////////////////////
447 /// \brief Encode a single UTF-32 character 447 /// \brief Encode a single UTF-32 character
448 /// 448 ///
449 /// Encoding a character means converting a unique 32-bits 449 /// Encoding a character means converting a unique 32-bits
450 /// code (called the codepoint) in the target encoding, UTF-32. 450 /// code (called the codepoint) in the target encoding, UTF-32.
451 /// For UTF-32, the codepoint is the same as the character value. 451 /// For UTF-32, the codepoint is the same as the character value.
452 /// 452 ///
453 /// \param input Codepoint to encode as UTF-32 453 /// \param input Codepoint to encode as UTF-32
454 /// \param output Iterator pointing to the beginning of the output sequence 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) 455 /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them)
456 /// 456 ///
457 /// \return Iterator to the end of the output sequence which has been written 457 /// \return Iterator to the end of the output sequence which has been written
458 /// 458 ///
459 //////////////////////////////////////////////////////////// 459 ////////////////////////////////////////////////////////////
460 template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); 460 template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 );
461 461
462 //////////////////////////////////////////////////////////// 462 ////////////////////////////////////////////////////////////
463 /// \brief Advance to the next UTF-32 character 463 /// \brief Advance to the next UTF-32 character
464 /// 464 ///
465 /// This function is trivial for UTF-32, which can store 465 /// This function is trivial for UTF-32, which can store
466 /// every character in a single storage element. 466 /// every character in a single storage element.
467 /// 467 ///
468 /// \param begin Iterator pointing to the beginning of the input sequence 468 /// \param begin Iterator pointing to the beginning of the input sequence
469 /// \param end Iterator pointing to the end of the input sequence 469 /// \param end Iterator pointing to the end of the input sequence
470 /// 470 ///
471 /// \return Iterator pointing to one past the last read element of the input sequence 471 /// \return Iterator pointing to one past the last read element of the input sequence
472 /// 472 ///
473 //////////////////////////////////////////////////////////// 473 ////////////////////////////////////////////////////////////
474 template <typename In> static In Next( In begin, In end ); 474 template <typename In> static In Next( In begin, In end );
475 475
476 //////////////////////////////////////////////////////////// 476 ////////////////////////////////////////////////////////////
477 /// \brief Count the number of characters of a UTF-32 sequence 477 /// \brief Count the number of characters of a UTF-32 sequence
478 /// 478 ///
479 /// This function is trivial for UTF-32, which can store 479 /// This function is trivial for UTF-32, which can store
480 /// every character in a single storage element. 480 /// every character in a single storage element.
481 /// 481 ///
482 /// \param begin Iterator pointing to the beginning of the input sequence 482 /// \param begin Iterator pointing to the beginning of the input sequence
483 /// \param end Iterator pointing to the end of the input sequence 483 /// \param end Iterator pointing to the end of the input sequence
484 /// 484 ///
485 /// \return Iterator pointing to one past the last read element of the input sequence 485 /// \return Iterator pointing to one past the last read element of the input sequence
486 /// 486 ///
487 //////////////////////////////////////////////////////////// 487 ////////////////////////////////////////////////////////////
488 template <typename In> static std::size_t Count( In begin, In end ); 488 template <typename In> static std::size_t Count( In begin, In end );
489 489
490 //////////////////////////////////////////////////////////// 490 ////////////////////////////////////////////////////////////
491 /// \brief Convert an ANSI characters range to UTF-32 491 /// \brief Convert an ANSI characters range to UTF-32
492 /// 492 ///
493 /// The current global locale will be used by default, unless you 493 /// The current global locale will be used by default, unless you
494 /// pass a custom one in the \a locale parameter. 494 /// pass a custom one in the \a locale parameter.
495 /// 495 ///
496 /// \param begin Iterator pointing to the beginning of the input sequence 496 /// \param begin Iterator pointing to the beginning of the input sequence
497 /// \param end Iterator pointing to the end 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 498 /// \param output Iterator pointing to the beginning of the output sequence
499 /// \param locale Locale to use for conversion 499 /// \param locale Locale to use for conversion
500 /// 500 ///
501 /// \return Iterator to the end of the output sequence which has been written 501 /// \return Iterator to the end of the output sequence which has been written
502 /// 502 ///
503 //////////////////////////////////////////////////////////// 503 ////////////////////////////////////////////////////////////
504 template <typename In, typename Out> 504 template <typename In, typename Out>
505 static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); 505 static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() );
506 506
507 //////////////////////////////////////////////////////////// 507 ////////////////////////////////////////////////////////////
508 /// \brief Convert a wide characters range to UTF-32 508 /// \brief Convert a wide characters range to UTF-32
509 /// 509 ///
510 /// \param begin Iterator pointing to the beginning of the input sequence 510 /// \param begin Iterator pointing to the beginning of the input sequence
511 /// \param end Iterator pointing to the end 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 512 /// \param output Iterator pointing to the beginning of the output sequence
513 /// 513 ///
514 /// \return Iterator to the end of the output sequence which has been written 514 /// \return Iterator to the end of the output sequence which has been written
515 /// 515 ///
516 //////////////////////////////////////////////////////////// 516 ////////////////////////////////////////////////////////////
517 template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); 517 template <typename In, typename Out> static Out FromWide( In begin, In end, Out output );
518 518
519 //////////////////////////////////////////////////////////// 519 ////////////////////////////////////////////////////////////
520 /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 520 /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32
521 /// 521 ///
522 /// \param begin Iterator pointing to the beginning of the input sequence 522 /// \param begin Iterator pointing to the beginning of the input sequence
523 /// \param end Iterator pointing to the end 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 524 /// \param output Iterator pointing to the beginning of the output sequence
525 /// \param locale Locale to use for conversion 525 /// \param locale Locale to use for conversion
526 /// 526 ///
527 /// \return Iterator to the end of the output sequence which has been written 527 /// \return Iterator to the end of the output sequence which has been written
528 /// 528 ///
529 //////////////////////////////////////////////////////////// 529 ////////////////////////////////////////////////////////////
530 template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); 530 template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output );
531 531
532 //////////////////////////////////////////////////////////// 532 ////////////////////////////////////////////////////////////
533 /// \brief Convert an UTF-32 characters range to ANSI characters 533 /// \brief Convert an UTF-32 characters range to ANSI characters
534 /// 534 ///
535 /// The current global locale will be used by default, unless you 535 /// The current global locale will be used by default, unless you
536 /// pass a custom one in the \a locale parameter. 536 /// pass a custom one in the \a locale parameter.
537 /// 537 ///
538 /// \param begin Iterator pointing to the beginning of the input sequence 538 /// \param begin Iterator pointing to the beginning of the input sequence
539 /// \param end Iterator pointing to the end 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 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) 541 /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
542 /// \param locale Locale to use for conversion 542 /// \param locale Locale to use for conversion
543 /// 543 ///
544 /// \return Iterator to the end of the output sequence which has been written 544 /// \return Iterator to the end of the output sequence which has been written
545 /// 545 ///
546 //////////////////////////////////////////////////////////// 546 ////////////////////////////////////////////////////////////
547 template <typename In, typename Out> 547 template <typename In, typename Out>
548 static Out ToAnsi( In begin, In end, Out output, char replacement = 0, 548 static Out ToAnsi( In begin, In end, Out output, char replacement = 0,
549 const std::locale& locale = std::locale() ); 549 const std::locale& locale = std::locale() );
550 550
551#ifndef EFSW_NO_WIDECHAR 551#ifndef EFSW_NO_WIDECHAR
552 //////////////////////////////////////////////////////////// 552 ////////////////////////////////////////////////////////////
553 /// \brief Convert an UTF-32 characters range to wide characters 553 /// \brief Convert an UTF-32 characters range to wide characters
554 /// 554 ///
555 /// \param begin Iterator pointing to the beginning of the input sequence 555 /// \param begin Iterator pointing to the beginning of the input sequence
556 /// \param end Iterator pointing to the end 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 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) 558 /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
559 /// 559 ///
560 /// \return Iterator to the end of the output sequence which has been written 560 /// \return Iterator to the end of the output sequence which has been written
561 /// 561 ///
562 //////////////////////////////////////////////////////////// 562 ////////////////////////////////////////////////////////////
563 template <typename In, typename Out> 563 template <typename In, typename Out>
564 static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); 564 static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 );
565#endif 565#endif
566 566
567 //////////////////////////////////////////////////////////// 567 ////////////////////////////////////////////////////////////
568 /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters 568 /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
569 /// 569 ///
570 /// \param begin Iterator pointing to the beginning of the input sequence 570 /// \param begin Iterator pointing to the beginning of the input sequence
571 /// \param end Iterator pointing to the end 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 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) 573 /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
574 /// 574 ///
575 /// \return Iterator to the end of the output sequence which has been written 575 /// \return Iterator to the end of the output sequence which has been written
576 /// 576 ///
577 //////////////////////////////////////////////////////////// 577 ////////////////////////////////////////////////////////////
578 template <typename In, typename Out> 578 template <typename In, typename Out>
579 static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); 579 static Out ToLatin1( In begin, In end, Out output, char replacement = 0 );
580 580
581 //////////////////////////////////////////////////////////// 581 ////////////////////////////////////////////////////////////
582 /// \brief Convert a UTF-32 characters range to UTF-8 582 /// \brief Convert a UTF-32 characters range to UTF-8
583 /// 583 ///
584 /// \param begin Iterator pointing to the beginning of the input sequence 584 /// \param begin Iterator pointing to the beginning of the input sequence
585 /// \param end Iterator pointing to the end 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 586 /// \param output Iterator pointing to the beginning of the output sequence
587 /// 587 ///
588 /// \return Iterator to the end of the output sequence which has been written 588 /// \return Iterator to the end of the output sequence which has been written
589 /// 589 ///
590 //////////////////////////////////////////////////////////// 590 ////////////////////////////////////////////////////////////
591 template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); 591 template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output );
592 592
593 //////////////////////////////////////////////////////////// 593 ////////////////////////////////////////////////////////////
594 /// \brief Convert a UTF-32 characters range to UTF-16 594 /// \brief Convert a UTF-32 characters range to UTF-16
595 /// 595 ///
596 /// \param begin Iterator pointing to the beginning of the input sequence 596 /// \param begin Iterator pointing to the beginning of the input sequence
597 /// \param end Iterator pointing to the end 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 598 /// \param output Iterator pointing to the beginning of the output sequence
599 /// 599 ///
600 /// \return Iterator to the end of the output sequence which has been written 600 /// \return Iterator to the end of the output sequence which has been written
601 /// 601 ///
602 //////////////////////////////////////////////////////////// 602 ////////////////////////////////////////////////////////////
603 template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); 603 template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output );
604 604
605 //////////////////////////////////////////////////////////// 605 ////////////////////////////////////////////////////////////
606 /// \brief Convert a UTF-32 characters range to UTF-32 606 /// \brief Convert a UTF-32 characters range to UTF-32
607 /// 607 ///
608 /// This functions does nothing more than a direct copy; 608 /// This functions does nothing more than a direct copy;
609 /// it is defined only to provide the same interface as other 609 /// it is defined only to provide the same interface as other
610 /// specializations of the efsw::Utf<> template, and allow 610 /// specializations of the efsw::Utf<> template, and allow
611 /// generic code to be written on top of it. 611 /// generic code to be written on top of it.
612 /// 612 ///
613 /// \param begin Iterator pointing to the beginning of the input sequence 613 /// \param begin Iterator pointing to the beginning of the input sequence
614 /// \param end Iterator pointing to the end 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 615 /// \param output Iterator pointing to the beginning of the output sequence
616 /// 616 ///
617 /// \return Iterator to the end of the output sequence which has been written 617 /// \return Iterator to the end of the output sequence which has been written
618 /// 618 ///
619 //////////////////////////////////////////////////////////// 619 ////////////////////////////////////////////////////////////
620 template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); 620 template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output );
621 621
622 //////////////////////////////////////////////////////////// 622 ////////////////////////////////////////////////////////////
623 /// \brief Decode a single ANSI character to UTF-32 623 /// \brief Decode a single ANSI character to UTF-32
624 /// 624 ///
625 /// This function does not exist in other specializations 625 /// This function does not exist in other specializations
626 /// of efsw::Utf<>, it is defined for convenience (it is used by 626 /// of efsw::Utf<>, it is defined for convenience (it is used by
627 /// several other conversion functions). 627 /// several other conversion functions).
628 /// 628 ///
629 /// \param input Input ANSI character 629 /// \param input Input ANSI character
630 /// \param locale Locale to use for conversion 630 /// \param locale Locale to use for conversion
631 /// 631 ///
632 /// \return Converted character 632 /// \return Converted character
633 /// 633 ///
634 //////////////////////////////////////////////////////////// 634 ////////////////////////////////////////////////////////////
635 template <typename In> 635 template <typename In>
636 static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); 636 static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() );
637 637
638 //////////////////////////////////////////////////////////// 638 ////////////////////////////////////////////////////////////
639 /// \brief Decode a single wide character to UTF-32 639 /// \brief Decode a single wide character to UTF-32
640 /// 640 ///
641 /// This function does not exist in other specializations 641 /// This function does not exist in other specializations
642 /// of efsw::Utf<>, it is defined for convenience (it is used by 642 /// of efsw::Utf<>, it is defined for convenience (it is used by
643 /// several other conversion functions). 643 /// several other conversion functions).
644 /// 644 ///
645 /// \param input Input wide character 645 /// \param input Input wide character
646 /// 646 ///
647 /// \return Converted character 647 /// \return Converted character
648 /// 648 ///
649 //////////////////////////////////////////////////////////// 649 ////////////////////////////////////////////////////////////
650 template <typename In> static Uint32 DecodeWide( In input ); 650 template <typename In> static Uint32 DecodeWide( In input );
651 651
652 //////////////////////////////////////////////////////////// 652 ////////////////////////////////////////////////////////////
653 /// \brief Encode a single UTF-32 character to ANSI 653 /// \brief Encode a single UTF-32 character to ANSI
654 /// 654 ///
655 /// This function does not exist in other specializations 655 /// This function does not exist in other specializations
656 /// of efsw::Utf<>, it is defined for convenience (it is used by 656 /// of efsw::Utf<>, it is defined for convenience (it is used by
657 /// several other conversion functions). 657 /// several other conversion functions).
658 /// 658 ///
659 /// \param codepoint Iterator pointing to the beginning of the input sequence 659 /// \param codepoint Iterator pointing to the beginning of the input sequence
660 /// \param output Iterator pointing to the beginning of the output 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 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 662 /// skip it) \param locale Locale to use for conversion
663 /// 663 ///
664 /// \return Iterator to the end of the output sequence which has been written 664 /// \return Iterator to the end of the output sequence which has been written
665 /// 665 ///
666 //////////////////////////////////////////////////////////// 666 ////////////////////////////////////////////////////////////
667 template <typename Out> 667 template <typename Out>
668 static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, 668 static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0,
669 const std::locale& locale = std::locale() ); 669 const std::locale& locale = std::locale() );
670 670
671#ifndef EFSW_NO_WIDECHAR 671#ifndef EFSW_NO_WIDECHAR
672 //////////////////////////////////////////////////////////// 672 ////////////////////////////////////////////////////////////
673 /// \brief Encode a single UTF-32 character to wide 673 /// \brief Encode a single UTF-32 character to wide
674 /// 674 ///
675 /// This function does not exist in other specializations 675 /// This function does not exist in other specializations
676 /// of efsw::Utf<>, it is defined for convenience (it is used by 676 /// of efsw::Utf<>, it is defined for convenience (it is used by
677 /// several other conversion functions). 677 /// several other conversion functions).
678 /// 678 ///
679 /// \param codepoint Iterator pointing to the beginning of the input sequence 679 /// \param codepoint Iterator pointing to the beginning of the input sequence
680 /// \param output Iterator pointing to the beginning of the output 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 681 /// \param replacement Replacement if the input character is not convertible to wide (use 0 to
682 /// skip it) 682 /// skip it)
683 /// 683 ///
684 /// \return Iterator to the end of the output sequence which has been written 684 /// \return Iterator to the end of the output sequence which has been written
685 /// 685 ///
686 //////////////////////////////////////////////////////////// 686 ////////////////////////////////////////////////////////////
687 template <typename Out> 687 template <typename Out>
688 static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); 688 static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 );
689#endif 689#endif
690}; 690};
691 691
692#include "Utf.inl" 692#include "Utf.inl"
693 693
694// Make typedefs to get rid of the template syntax 694// Make typedefs to get rid of the template syntax
695typedef Utf<8> Utf8; 695typedef Utf<8> Utf8;
696typedef Utf<16> Utf16; 696typedef Utf<16> Utf16;
697typedef Utf<32> Utf32; 697typedef Utf<32> Utf32;
698 698
699} // namespace efsw 699} // namespace efsw
700#endif 700#endif
701 701
702//////////////////////////////////////////////////////////// 702////////////////////////////////////////////////////////////
703/// \class efsw::Utf 703/// \class efsw::Utf
704/// \ingroup system 704/// \ingroup system
705/// 705///
706/// Utility class providing generic functions for UTF conversions. 706/// Utility class providing generic functions for UTF conversions.
707/// 707///
708/// efsw::Utf is a low-level, generic interface for counting, iterating, 708/// efsw::Utf is a low-level, generic interface for counting, iterating,
709/// encoding and decoding Unicode characters and strings. It is able 709/// encoding and decoding Unicode characters and strings. It is able
710/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. 710/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings.
711/// 711///
712/// efsw::Utf<X> functions are all static, these classes are not meant to 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 713/// be instanciated. All the functions are template, so that you
714/// can use any character / string type for a given encoding. 714/// can use any character / string type for a given encoding.
715/// 715///
716/// It has 3 specializations: 716/// It has 3 specializations:
717/// \li efsw::Utf<8> (typedef'd to efsw::Utf8) 717/// \li efsw::Utf<8> (typedef'd to efsw::Utf8)
718/// \li efsw::Utf<16> (typedef'd to efsw::Utf16) 718/// \li efsw::Utf<16> (typedef'd to efsw::Utf16)
719/// \li efsw::Utf<32> (typedef'd to efsw::Utf32) 719/// \li efsw::Utf<32> (typedef'd to efsw::Utf32)
720/// 720///
721//////////////////////////////////////////////////////////// 721////////////////////////////////////////////////////////////
diff --git a/src/3rdParty/efsw/Utf.inl b/src/3rdParty/efsw/Utf.inl
index 5b6c2e0..5c9d7a3 100755..100644
--- a/src/3rdParty/efsw/Utf.inl
+++ b/src/3rdParty/efsw/Utf.inl
@@ -1,576 +1,576 @@
1// References : 1// References :
2// http://www.unicode.org/ 2// http://www.unicode.org/
3// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c 3// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
4// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h 4// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h
5// http://people.w3.org/rishida/scripts/uniview/conversion 5// http://people.w3.org/rishida/scripts/uniview/conversion
6//////////////////////////////////////////////////////////// 6////////////////////////////////////////////////////////////
7 7
8template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { 8template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) {
9 // Some useful precomputed data 9 // Some useful precomputed data
10 static const int trailing[256] = { 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, 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, 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, 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, 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, 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, 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, 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, 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 }; 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, 20 static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080,
21 0x03C82080, 0xFA082080, 0x82082080 }; 21 0x03C82080, 0xFA082080, 0x82082080 };
22 22
23 // Decode the character 23 // Decode the character
24 int trailingBytes = trailing[static_cast<Uint8>( *begin )]; 24 int trailingBytes = trailing[static_cast<Uint8>( *begin )];
25 if ( begin + trailingBytes < end ) { 25 if ( begin + trailingBytes < end ) {
26 output = 0; 26 output = 0;
27 switch ( trailingBytes ) { 27 switch ( trailingBytes ) {
28 case 5: 28 case 5:
29 output += static_cast<Uint8>( *begin++ ); 29 output += static_cast<Uint8>( *begin++ );
30 output <<= 6; 30 output <<= 6;
31 case 4: 31 case 4:
32 output += static_cast<Uint8>( *begin++ ); 32 output += static_cast<Uint8>( *begin++ );
33 output <<= 6; 33 output <<= 6;
34 case 3: 34 case 3:
35 output += static_cast<Uint8>( *begin++ ); 35 output += static_cast<Uint8>( *begin++ );
36 output <<= 6; 36 output <<= 6;
37 case 2: 37 case 2:
38 output += static_cast<Uint8>( *begin++ ); 38 output += static_cast<Uint8>( *begin++ );
39 output <<= 6; 39 output <<= 6;
40 case 1: 40 case 1:
41 output += static_cast<Uint8>( *begin++ ); 41 output += static_cast<Uint8>( *begin++ );
42 output <<= 6; 42 output <<= 6;
43 case 0: 43 case 0:
44 output += static_cast<Uint8>( *begin++ ); 44 output += static_cast<Uint8>( *begin++ );
45 } 45 }
46 output -= offsets[trailingBytes]; 46 output -= offsets[trailingBytes];
47 } else { 47 } else {
48 // Incomplete character 48 // Incomplete character
49 begin = end; 49 begin = end;
50 output = replacement; 50 output = replacement;
51 } 51 }
52 52
53 return begin; 53 return begin;
54} 54}
55 55
56template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { 56template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) {
57 // Some useful precomputed data 57 // Some useful precomputed data
58 static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 58 static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
59 59
60 // Encode the character 60 // Encode the character
61 if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { 61 if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) {
62 // Invalid character 62 // Invalid character
63 if ( replacement ) 63 if ( replacement )
64 *output++ = replacement; 64 *output++ = replacement;
65 } else { 65 } else {
66 // Valid character 66 // Valid character
67 67
68 // Get the number of bytes to write 68 // Get the number of bytes to write
69 int bytesToWrite = 1; 69 int bytesToWrite = 1;
70 if ( input < 0x80 ) 70 if ( input < 0x80 )
71 bytesToWrite = 1; 71 bytesToWrite = 1;
72 else if ( input < 0x800 ) 72 else if ( input < 0x800 )
73 bytesToWrite = 2; 73 bytesToWrite = 2;
74 else if ( input < 0x10000 ) 74 else if ( input < 0x10000 )
75 bytesToWrite = 3; 75 bytesToWrite = 3;
76 else if ( input <= 0x0010FFFF ) 76 else if ( input <= 0x0010FFFF )
77 bytesToWrite = 4; 77 bytesToWrite = 4;
78 78
79 // Extract the bytes to write 79 // Extract the bytes to write
80 Uint8 bytes[4]; 80 Uint8 bytes[4];
81 switch ( bytesToWrite ) { 81 switch ( bytesToWrite ) {
82 case 4: 82 case 4:
83 bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); 83 bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF );
84 input >>= 6; 84 input >>= 6;
85 case 3: 85 case 3:
86 bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); 86 bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF );
87 input >>= 6; 87 input >>= 6;
88 case 2: 88 case 2:
89 bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); 89 bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF );
90 input >>= 6; 90 input >>= 6;
91 case 1: 91 case 1:
92 bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] ); 92 bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] );
93 } 93 }
94 94
95 // Add them to the output 95 // Add them to the output
96 const Uint8* currentByte = bytes; 96 const Uint8* currentByte = bytes;
97 switch ( bytesToWrite ) { 97 switch ( bytesToWrite ) {
98 case 4: 98 case 4:
99 *output++ = *currentByte++; 99 *output++ = *currentByte++;
100 case 3: 100 case 3:
101 *output++ = *currentByte++; 101 *output++ = *currentByte++;
102 case 2: 102 case 2:
103 *output++ = *currentByte++; 103 *output++ = *currentByte++;
104 case 1: 104 case 1:
105 *output++ = *currentByte++; 105 *output++ = *currentByte++;
106 } 106 }
107 } 107 }
108 108
109 return output; 109 return output;
110} 110}
111 111
112template <typename In> In Utf<8>::Next( In begin, In end ) { 112template <typename In> In Utf<8>::Next( In begin, In end ) {
113 Uint32 codepoint; 113 Uint32 codepoint;
114 return Decode( begin, end, codepoint ); 114 return Decode( begin, end, codepoint );
115} 115}
116 116
117template <typename In> std::size_t Utf<8>::Count( In begin, In end ) { 117template <typename In> std::size_t Utf<8>::Count( In begin, In end ) {
118 std::size_t length = 0; 118 std::size_t length = 0;
119 while ( begin < end ) { 119 while ( begin < end ) {
120 begin = Next( begin, end ); 120 begin = Next( begin, end );
121 ++length; 121 ++length;
122 } 122 }
123 123
124 return length; 124 return length;
125} 125}
126 126
127template <typename In, typename Out> 127template <typename In, typename Out>
128Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { 128Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) {
129 while ( begin < end ) { 129 while ( begin < end ) {
130 Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); 130 Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale );
131 output = Encode( codepoint, output ); 131 output = Encode( codepoint, output );
132 } 132 }
133 133
134 return output; 134 return output;
135} 135}
136 136
137template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) { 137template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) {
138 while ( begin < end ) { 138 while ( begin < end ) {
139 Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); 139 Uint32 codepoint = Utf<32>::DecodeWide( *begin++ );
140 output = Encode( codepoint, output ); 140 output = Encode( codepoint, output );
141 } 141 }
142 142
143 return output; 143 return output;
144} 144}
145 145
146template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) { 146template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) {
147 // Latin-1 is directly compatible with Unicode encodings, 147 // Latin-1 is directly compatible with Unicode encodings,
148 // and can thus be treated as (a sub-range of) UTF-32 148 // and can thus be treated as (a sub-range of) UTF-32
149 while ( begin < end ) 149 while ( begin < end )
150 output = Encode( *begin++, output ); 150 output = Encode( *begin++, output );
151 151
152 return output; 152 return output;
153} 153}
154 154
155template <typename In, typename Out> 155template <typename In, typename Out>
156Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { 156Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) {
157 while ( begin < end ) { 157 while ( begin < end ) {
158 Uint32 codepoint; 158 Uint32 codepoint;
159 begin = Decode( begin, end, codepoint ); 159 begin = Decode( begin, end, codepoint );
160 output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); 160 output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale );
161 } 161 }
162 162
163 return output; 163 return output;
164} 164}
165 165
166#ifndef EFSW_NO_WIDECHAR 166#ifndef EFSW_NO_WIDECHAR
167template <typename In, typename Out> 167template <typename In, typename Out>
168Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { 168Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) {
169 while ( begin < end ) { 169 while ( begin < end ) {
170 Uint32 codepoint; 170 Uint32 codepoint;
171 begin = Decode( begin, end, codepoint ); 171 begin = Decode( begin, end, codepoint );
172 output = Utf<32>::EncodeWide( codepoint, output, replacement ); 172 output = Utf<32>::EncodeWide( codepoint, output, replacement );
173 } 173 }
174 174
175 return output; 175 return output;
176} 176}
177#endif 177#endif
178 178
179template <typename In, typename Out> 179template <typename In, typename Out>
180Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { 180Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) {
181 // Latin-1 is directly compatible with Unicode encodings, 181 // Latin-1 is directly compatible with Unicode encodings,
182 // and can thus be treated as (a sub-range of) UTF-32 182 // and can thus be treated as (a sub-range of) UTF-32
183 while ( begin < end ) { 183 while ( begin < end ) {
184 Uint32 codepoint; 184 Uint32 codepoint;
185 begin = Decode( begin, end, codepoint ); 185 begin = Decode( begin, end, codepoint );
186 *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement; 186 *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement;
187 } 187 }
188 188
189 return output; 189 return output;
190} 190}
191 191
192template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) { 192template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) {
193 while ( begin < end ) 193 while ( begin < end )
194 *output++ = *begin++; 194 *output++ = *begin++;
195 195
196 return output; 196 return output;
197} 197}
198 198
199template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) { 199template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) {
200 while ( begin < end ) { 200 while ( begin < end ) {
201 Uint32 codepoint; 201 Uint32 codepoint;
202 begin = Decode( begin, end, codepoint ); 202 begin = Decode( begin, end, codepoint );
203 output = Utf<16>::Encode( codepoint, output ); 203 output = Utf<16>::Encode( codepoint, output );
204 } 204 }
205 205
206 return output; 206 return output;
207} 207}
208 208
209template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) { 209template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) {
210 while ( begin < end ) { 210 while ( begin < end ) {
211 Uint32 codepoint; 211 Uint32 codepoint;
212 begin = Decode( begin, end, codepoint ); 212 begin = Decode( begin, end, codepoint );
213 *output++ = codepoint; 213 *output++ = codepoint;
214 } 214 }
215 215
216 return output; 216 return output;
217} 217}
218 218
219template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { 219template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) {
220 Uint16 first = *begin++; 220 Uint16 first = *begin++;
221 221
222 // If it's a surrogate pair, first convert to a single UTF-32 character 222 // If it's a surrogate pair, first convert to a single UTF-32 character
223 if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { 223 if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) {
224 if ( begin < end ) { 224 if ( begin < end ) {
225 Uint32 second = *begin++; 225 Uint32 second = *begin++;
226 if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { 226 if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) {
227 // The second element is valid: convert the two elements to a UTF-32 character 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 ) + 228 output = static_cast<Uint32>( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) +
229 0x0010000 ); 229 0x0010000 );
230 } else { 230 } else {
231 // Invalid character 231 // Invalid character
232 output = replacement; 232 output = replacement;
233 } 233 }
234 } else { 234 } else {
235 // Invalid character 235 // Invalid character
236 begin = end; 236 begin = end;
237 output = replacement; 237 output = replacement;
238 } 238 }
239 } else { 239 } else {
240 // We can make a direct copy 240 // We can make a direct copy
241 output = first; 241 output = first;
242 } 242 }
243 243
244 return begin; 244 return begin;
245} 245}
246 246
247template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { 247template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) {
248 if ( input < 0xFFFF ) { 248 if ( input < 0xFFFF ) {
249 // The character can be copied directly, we just need to check if it's in the valid range 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 ) ) { 250 if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) {
251 // Invalid character (this range is reserved) 251 // Invalid character (this range is reserved)
252 if ( replacement ) 252 if ( replacement )
253 *output++ = replacement; 253 *output++ = replacement;
254 } else { 254 } else {
255 // Valid character directly convertible to a single UTF-16 character 255 // Valid character directly convertible to a single UTF-16 character
256 *output++ = static_cast<Uint16>( input ); 256 *output++ = static_cast<Uint16>( input );
257 } 257 }
258 } else if ( input > 0x0010FFFF ) { 258 } else if ( input > 0x0010FFFF ) {
259 // Invalid character (greater than the maximum unicode value) 259 // Invalid character (greater than the maximum unicode value)
260 if ( replacement ) 260 if ( replacement )
261 *output++ = replacement; 261 *output++ = replacement;
262 } else { 262 } else {
263 // The input character will be converted to two UTF-16 elements 263 // The input character will be converted to two UTF-16 elements
264 input -= 0x0010000; 264 input -= 0x0010000;
265 *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 ); 265 *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 );
266 *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 ); 266 *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 );
267 } 267 }
268 268
269 return output; 269 return output;
270} 270}
271 271
272template <typename In> In Utf<16>::Next( In begin, In end ) { 272template <typename In> In Utf<16>::Next( In begin, In end ) {
273 Uint32 codepoint; 273 Uint32 codepoint;
274 return Decode( begin, end, codepoint ); 274 return Decode( begin, end, codepoint );
275} 275}
276 276
277template <typename In> std::size_t Utf<16>::Count( In begin, In end ) { 277template <typename In> std::size_t Utf<16>::Count( In begin, In end ) {
278 std::size_t length = 0; 278 std::size_t length = 0;
279 while ( begin < end ) { 279 while ( begin < end ) {
280 begin = Next( begin, end ); 280 begin = Next( begin, end );
281 ++length; 281 ++length;
282 } 282 }
283 283
284 return length; 284 return length;
285} 285}
286 286
287template <typename In, typename Out> 287template <typename In, typename Out>
288Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { 288Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) {
289 while ( begin < end ) { 289 while ( begin < end ) {
290 Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); 290 Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale );
291 output = Encode( codepoint, output ); 291 output = Encode( codepoint, output );
292 } 292 }
293 293
294 return output; 294 return output;
295} 295}
296 296
297template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) { 297template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) {
298 while ( begin < end ) { 298 while ( begin < end ) {
299 Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); 299 Uint32 codepoint = Utf<32>::DecodeWide( *begin++ );
300 output = Encode( codepoint, output ); 300 output = Encode( codepoint, output );
301 } 301 }
302 302
303 return output; 303 return output;
304} 304}
305 305
306template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) { 306template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) {
307 // Latin-1 is directly compatible with Unicode encodings, 307 // Latin-1 is directly compatible with Unicode encodings,
308 // and can thus be treated as (a sub-range of) UTF-32 308 // and can thus be treated as (a sub-range of) UTF-32
309 while ( begin < end ) 309 while ( begin < end )
310 *output++ = *begin++; 310 *output++ = *begin++;
311 311
312 return output; 312 return output;
313} 313}
314 314
315template <typename In, typename Out> 315template <typename In, typename Out>
316Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { 316Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) {
317 while ( begin < end ) { 317 while ( begin < end ) {
318 Uint32 codepoint; 318 Uint32 codepoint;
319 begin = Decode( begin, end, codepoint ); 319 begin = Decode( begin, end, codepoint );
320 output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); 320 output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale );
321 } 321 }
322 322
323 return output; 323 return output;
324} 324}
325 325
326#ifndef EFSW_NO_WIDECHAR 326#ifndef EFSW_NO_WIDECHAR
327template <typename In, typename Out> 327template <typename In, typename Out>
328Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { 328Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) {
329 while ( begin < end ) { 329 while ( begin < end ) {
330 Uint32 codepoint; 330 Uint32 codepoint;
331 begin = Decode( begin, end, codepoint ); 331 begin = Decode( begin, end, codepoint );
332 output = Utf<32>::EncodeWide( codepoint, output, replacement ); 332 output = Utf<32>::EncodeWide( codepoint, output, replacement );
333 } 333 }
334 334
335 return output; 335 return output;
336} 336}
337#endif 337#endif
338 338
339template <typename In, typename Out> 339template <typename In, typename Out>
340Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { 340Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) {
341 // Latin-1 is directly compatible with Unicode encodings, 341 // Latin-1 is directly compatible with Unicode encodings,
342 // and can thus be treated as (a sub-range of) UTF-32 342 // and can thus be treated as (a sub-range of) UTF-32
343 while ( begin < end ) { 343 while ( begin < end ) {
344 *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; 344 *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement;
345 begin++; 345 begin++;
346 } 346 }
347 347
348 return output; 348 return output;
349} 349}
350 350
351template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) { 351template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) {
352 while ( begin < end ) { 352 while ( begin < end ) {
353 Uint32 codepoint; 353 Uint32 codepoint;
354 begin = Decode( begin, end, codepoint ); 354 begin = Decode( begin, end, codepoint );
355 output = Utf<8>::Encode( codepoint, output ); 355 output = Utf<8>::Encode( codepoint, output );
356 } 356 }
357 357
358 return output; 358 return output;
359} 359}
360 360
361template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) { 361template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) {
362 while ( begin < end ) 362 while ( begin < end )
363 *output++ = *begin++; 363 *output++ = *begin++;
364 364
365 return output; 365 return output;
366} 366}
367 367
368template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) { 368template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) {
369 while ( begin < end ) { 369 while ( begin < end ) {
370 Uint32 codepoint; 370 Uint32 codepoint;
371 begin = Decode( begin, end, codepoint ); 371 begin = Decode( begin, end, codepoint );
372 *output++ = codepoint; 372 *output++ = codepoint;
373 } 373 }
374 374
375 return output; 375 return output;
376} 376}
377 377
378template <typename In> In Utf<32>::Decode( In begin, In /*end*/, Uint32& output, Uint32 ) { 378template <typename In> In Utf<32>::Decode( In begin, In /*end*/, Uint32& output, Uint32 ) {
379 output = *begin++; 379 output = *begin++;
380 return begin; 380 return begin;
381} 381}
382 382
383template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 /*replacement*/ ) { 383template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 /*replacement*/ ) {
384 *output++ = input; 384 *output++ = input;
385 return output; 385 return output;
386} 386}
387 387
388template <typename In> In Utf<32>::Next( In begin, In /*end*/ ) { 388template <typename In> In Utf<32>::Next( In begin, In /*end*/ ) {
389 return ++begin; 389 return ++begin;
390} 390}
391 391
392template <typename In> std::size_t Utf<32>::Count( In begin, In end ) { 392template <typename In> std::size_t Utf<32>::Count( In begin, In end ) {
393 return begin - end; 393 return begin - end;
394} 394}
395 395
396template <typename In, typename Out> 396template <typename In, typename Out>
397Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { 397Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) {
398 while ( begin < end ) 398 while ( begin < end )
399 *output++ = DecodeAnsi( *begin++, locale ); 399 *output++ = DecodeAnsi( *begin++, locale );
400 400
401 return output; 401 return output;
402} 402}
403 403
404template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) { 404template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) {
405 while ( begin < end ) 405 while ( begin < end )
406 *output++ = DecodeWide( *begin++ ); 406 *output++ = DecodeWide( *begin++ );
407 407
408 return output; 408 return output;
409} 409}
410 410
411template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) { 411template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) {
412 // Latin-1 is directly compatible with Unicode encodings, 412 // Latin-1 is directly compatible with Unicode encodings,
413 // and can thus be treated as (a sub-range of) UTF-32 413 // and can thus be treated as (a sub-range of) UTF-32
414 while ( begin < end ) 414 while ( begin < end )
415 *output++ = *begin++; 415 *output++ = *begin++;
416 416
417 return output; 417 return output;
418} 418}
419 419
420template <typename In, typename Out> 420template <typename In, typename Out>
421Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { 421Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) {
422 while ( begin < end ) 422 while ( begin < end )
423 output = EncodeAnsi( *begin++, output, replacement, locale ); 423 output = EncodeAnsi( *begin++, output, replacement, locale );
424 424
425 return output; 425 return output;
426} 426}
427 427
428#ifndef EFSW_NO_WIDECHAR 428#ifndef EFSW_NO_WIDECHAR
429template <typename In, typename Out> 429template <typename In, typename Out>
430Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { 430Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) {
431 while ( begin < end ) 431 while ( begin < end )
432 output = EncodeWide( *begin++, output, replacement ); 432 output = EncodeWide( *begin++, output, replacement );
433 433
434 return output; 434 return output;
435} 435}
436#endif 436#endif
437 437
438template <typename In, typename Out> 438template <typename In, typename Out>
439Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { 439Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) {
440 // Latin-1 is directly compatible with Unicode encodings, 440 // Latin-1 is directly compatible with Unicode encodings,
441 // and can thus be treated as (a sub-range of) UTF-32 441 // and can thus be treated as (a sub-range of) UTF-32
442 while ( begin < end ) { 442 while ( begin < end ) {
443 *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; 443 *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement;
444 begin++; 444 begin++;
445 } 445 }
446 446
447 return output; 447 return output;
448} 448}
449 449
450template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) { 450template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) {
451 while ( begin < end ) 451 while ( begin < end )
452 output = Utf<8>::Encode( *begin++, output ); 452 output = Utf<8>::Encode( *begin++, output );
453 453
454 return output; 454 return output;
455} 455}
456 456
457template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) { 457template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) {
458 while ( begin < end ) 458 while ( begin < end )
459 output = Utf<16>::Encode( *begin++, output ); 459 output = Utf<16>::Encode( *begin++, output );
460 460
461 return output; 461 return output;
462} 462}
463 463
464template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) { 464template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) {
465 while ( begin < end ) 465 while ( begin < end )
466 *output++ = *begin++; 466 *output++ = *begin++;
467 467
468 return output; 468 return output;
469} 469}
470 470
471template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { 471template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) {
472 // On Windows, gcc's standard library (glibc++) has almost 472 // On Windows, gcc's standard library (glibc++) has almost
473 // no support for Unicode stuff. As a consequence, in this 473 // no support for Unicode stuff. As a consequence, in this
474 // context we can only use the default locale and ignore 474 // context we can only use the default locale and ignore
475 // the one passed as parameter. 475 // the one passed as parameter.
476 476
477#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ 477#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \
478 ( defined( __GLIBCPP__ ) || \ 478 ( defined( __GLIBCPP__ ) || \
479 defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ 479 defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \
480 !( defined( __SGI_STL_PORT ) || \ 480 !( defined( __SGI_STL_PORT ) || \
481 defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ 481 defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */
482 482
483 wchar_t character = 0; 483 wchar_t character = 0;
484 mbtowc( &character, &input, 1 ); 484 mbtowc( &character, &input, 1 );
485 return static_cast<Uint32>( character ); 485 return static_cast<Uint32>( character );
486 486
487#else 487#else
488// Get the facet of the locale which deals with character conversion 488// Get the facet of the locale which deals with character conversion
489#ifndef EFSW_NO_WIDECHAR 489#ifndef EFSW_NO_WIDECHAR
490 const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); 490 const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale );
491#else 491#else
492 const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); 492 const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale );
493#endif 493#endif
494 494
495 // Use the facet to convert each character of the input string 495 // Use the facet to convert each character of the input string
496 return static_cast<Uint32>( facet.widen( input ) ); 496 return static_cast<Uint32>( facet.widen( input ) );
497 497
498#endif 498#endif
499} 499}
500 500
501template <typename In> Uint32 Utf<32>::DecodeWide( In input ) { 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; 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 503 // however we can safely assume that it is UCS-2 on Windows and
504 // UCS-4 on Unix systems. 504 // UCS-4 on Unix systems.
505 // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, 505 // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4,
506 // and UCS-4 *is* UTF-32). 506 // and UCS-4 *is* UTF-32).
507 507
508 return input; 508 return input;
509} 509}
510 510
511template <typename Out> 511template <typename Out>
512Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, 512Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement,
513 const std::locale& locale ) { 513 const std::locale& locale ) {
514 // On Windows, gcc's standard library (glibc++) has almost 514 // On Windows, gcc's standard library (glibc++) has almost
515 // no support for Unicode stuff. As a consequence, in this 515 // no support for Unicode stuff. As a consequence, in this
516 // context we can only use the default locale and ignore 516 // context we can only use the default locale and ignore
517 // the one passed as parameter. 517 // the one passed as parameter.
518 518
519#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ 519#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \
520 ( defined( __GLIBCPP__ ) || \ 520 ( defined( __GLIBCPP__ ) || \
521 defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ 521 defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \
522 !( defined( __SGI_STL_PORT ) || \ 522 !( defined( __SGI_STL_PORT ) || \
523 defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ 523 defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */
524 524
525 char character = 0; 525 char character = 0;
526 if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 ) 526 if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 )
527 *output++ = character; 527 *output++ = character;
528 else if ( replacement ) 528 else if ( replacement )
529 *output++ = replacement; 529 *output++ = replacement;
530 530
531 return output; 531 return output;
532 532
533#else 533#else
534// Get the facet of the locale which deals with character conversion 534// Get the facet of the locale which deals with character conversion
535#ifndef EFSW_NO_WIDECHAR 535#ifndef EFSW_NO_WIDECHAR
536 const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); 536 const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale );
537#else 537#else
538 const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); 538 const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale );
539#endif 539#endif
540 540
541 // Use the facet to convert each character of the input string 541 // Use the facet to convert each character of the input string
542 *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement ); 542 *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement );
543 543
544 return output; 544 return output;
545 545
546#endif 546#endif
547} 547}
548 548
549#ifndef EFSW_NO_WIDECHAR 549#ifndef EFSW_NO_WIDECHAR
550template <typename Out> 550template <typename Out>
551Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { 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; 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 553 // however we can safely assume that it is UCS-2 on Windows and
554 // UCS-4 on Unix systems. 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). 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). 556 // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32).
557 557
558 switch ( sizeof( wchar_t ) ) { 558 switch ( sizeof( wchar_t ) ) {
559 case 4: { 559 case 4: {
560 *output++ = static_cast<wchar_t>( codepoint ); 560 *output++ = static_cast<wchar_t>( codepoint );
561 break; 561 break;
562 } 562 }
563 563
564 default: { 564 default: {
565 if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { 565 if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) {
566 *output++ = static_cast<wchar_t>( codepoint ); 566 *output++ = static_cast<wchar_t>( codepoint );
567 } else if ( replacement ) { 567 } else if ( replacement ) {
568 *output++ = replacement; 568 *output++ = replacement;
569 } 569 }
570 break; 570 break;
571 } 571 }
572 } 572 }
573 573
574 return output; 574 return output;
575} 575}
576#endif 576#endif
diff --git a/src/3rdParty/efsw/Watcher.cpp b/src/3rdParty/efsw/Watcher.cpp
index 913ae3c..913ae3c 100755..100644
--- a/src/3rdParty/efsw/Watcher.cpp
+++ b/src/3rdParty/efsw/Watcher.cpp
diff --git a/src/3rdParty/efsw/Watcher.hpp b/src/3rdParty/efsw/Watcher.hpp
index 84f0980..84f0980 100755..100644
--- a/src/3rdParty/efsw/Watcher.hpp
+++ b/src/3rdParty/efsw/Watcher.hpp
diff --git a/src/3rdParty/efsw/WatcherFSEvents.cpp b/src/3rdParty/efsw/WatcherFSEvents.cpp
index b562d3c..f963374 100755..100644
--- a/src/3rdParty/efsw/WatcherFSEvents.cpp
+++ b/src/3rdParty/efsw/WatcherFSEvents.cpp
@@ -8,22 +8,11 @@
8namespace efsw { 8namespace efsw {
9 9
10WatcherFSEvents::WatcherFSEvents() : 10WatcherFSEvents::WatcherFSEvents() :
11 Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ), initializedAsync( false ) {} 11 Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ) {}
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 12
21WatcherFSEvents::~WatcherFSEvents() { 13WatcherFSEvents::~WatcherFSEvents() {
22 if ( NULL != FSStream ) { 14 if ( NULL != FSStream ) {
23 if ( initializedAsync ) { 15 FSEventStreamStop( FSStream );
24 FSEventStreamStop( FSStream );
25 }
26
27 FSEventStreamInvalidate( FSStream ); 16 FSEventStreamInvalidate( FSStream );
28 FSEventStreamRelease( FSStream ); 17 FSEventStreamRelease( FSStream );
29 } 18 }
@@ -39,7 +28,9 @@ void WatcherFSEvents::init() {
39 Uint32 streamFlags = kFSEventStreamCreateFlagNone; 28 Uint32 streamFlags = kFSEventStreamCreateFlagNone;
40 29
41 if ( FileWatcherFSEvents::isGranular() ) { 30 if ( FileWatcherFSEvents::isGranular() ) {
42 streamFlags = efswFSEventStreamCreateFlagFileEvents; 31 streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer |
32 efswFSEventStreamCreateFlagUseExtendedData |
33 efswFSEventStreamCreateFlagUseCFTypes;
43 } else { 34 } else {
44 WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); 35 WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive );
45 } 36 }
@@ -52,49 +43,49 @@ void WatcherFSEvents::init() {
52 ctx.release = NULL; 43 ctx.release = NULL;
53 ctx.copyDescription = NULL; 44 ctx.copyDescription = NULL;
54 45
46 dispatch_queue_t queue = dispatch_queue_create( NULL, NULL );
47
55 FSStream = 48 FSStream =
56 FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, 49 FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx,
57 CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); 50 CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0., streamFlags );
58 FWatcher.load()->mNeedInitMutex.lock();
59 FWatcher.load()->mNeedInit.push_back( this );
60 FWatcher.load()->mNeedInitMutex.unlock();
61 51
62 CFRelease( CFDirectoryArray ); 52 FSEventStreamSetDispatchQueue( FSStream, queue );
63 CFRelease( CFDirectory );
64}
65 53
66void WatcherFSEvents::initAsync() {
67 FSEventStreamScheduleWithRunLoop( FSStream, FWatcher.load()->mRunLoopRef.load(),
68 kCFRunLoopDefaultMode );
69 FSEventStreamStart( FSStream ); 54 FSEventStreamStart( FSStream );
70 initializedAsync = true; 55
56 CFRelease( CFDirectoryArray );
57 CFRelease( CFDirectory );
71} 58}
72 59
73void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, 60void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir,
74 const std::string& filename, Action action, 61 const std::string& filename, Action action,
75 std::string oldFilename ) { 62 std::string oldFilename ) {
76 Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), 63 Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ),
77 FileSystem::precomposeFileName( filename ), action, oldFilename ); 64 FileSystem::precomposeFileName( filename ), action,
65 FileSystem::precomposeFileName( oldFilename ) );
78} 66}
79 67
80void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, 68void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path,
81 std::string& dirPath, std::string& filePath ) { 69 std::string& dirPath, std::string& filePath, Uint64 inode ) {
82 if ( flags & efswFSEventStreamEventFlagItemCreated ) { 70 if ( ( flags & efswFSEventStreamEventFlagItemCreated ) && FileInfo::exists( path ) &&
83 if ( FileInfo::exists( path ) ) { 71 ( !SanitizeEvents || FilesAdded.find( inode ) != FilesAdded.end() ) ) {
84 sendFileAction( ID, dirPath, filePath, Actions::Add ); 72 sendFileAction( ID, dirPath, filePath, Actions::Add );
85 } 73
74 if ( SanitizeEvents )
75 FilesAdded.insert( inode );
86 } 76 }
87 77
88 if ( flags & efswFSEventsModified ) { 78 if ( flags & ModifiedFlags ) {
89 sendFileAction( ID, dirPath, filePath, Actions::Modified ); 79 sendFileAction( ID, dirPath, filePath, Actions::Modified );
90 } 80 }
91 81
92 if ( flags & efswFSEventStreamEventFlagItemRemoved ) { 82 if ( ( flags & efswFSEventStreamEventFlagItemRemoved ) && !FileInfo::exists( path ) ) {
93 // Since i don't know the order, at least i try to keep the data consistent with the real 83 // Since i don't know the order, at least i try to keep the data consistent with the real
94 // state 84 // state
95 if ( !FileInfo::exists( path ) ) { 85 sendFileAction( ID, dirPath, filePath, Actions::Delete );
96 sendFileAction( ID, dirPath, filePath, Actions::Delete ); 86
97 } 87 if ( SanitizeEvents )
88 FilesAdded.erase( inode );
98 } 89 }
99} 90}
100 91
@@ -136,19 +127,20 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
136 // been added modified and erased, but i can't know if first was erased and then added 127 // 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 128 // and modified, or added, then modified and then erased. I don't know what they were
138 // thinking by doing this... 129 // thinking by doing this...
139 efDEBUG( "Event in: %s - flags: %ld\n", event.Path.c_str(), event.Flags ); 130 efDEBUG( "Event in: %s - flags: 0x%x\n", event.Path.c_str(), event.Flags );
140 131
141 if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { 132 if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) {
142 if ( ( i + 1 < esize ) && 133 if ( ( i + 1 < esize ) &&
143 ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && 134 ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) &&
144 ( events[i + 1].Id == event.Id + 1 ) ) { 135 ( events[i + 1].inode == event.inode ) ) {
145 FSEvent& nEvent = events[i + 1]; 136 FSEvent& nEvent = events[i + 1];
146 std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); 137 std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) );
147 std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); 138 std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) );
148 139
149 if ( event.Path != nEvent.Path ) { 140 if ( event.Path != nEvent.Path ) {
150 if ( dirPath == newDir ) { 141 if ( dirPath == newDir ) {
151 if ( !FileInfo::exists( event.Path ) ) { 142 if ( !FileInfo::exists( event.Path ) ||
143 0 == strcasecmp( event.Path.c_str(), nEvent.Path.c_str() ) ) {
152 sendFileAction( ID, dirPath, newFilepath, Actions::Moved, 144 sendFileAction( ID, dirPath, newFilepath, Actions::Moved,
153 filePath ); 145 filePath );
154 } else { 146 } else {
@@ -159,12 +151,12 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
159 sendFileAction( ID, dirPath, filePath, Actions::Delete ); 151 sendFileAction( ID, dirPath, filePath, Actions::Delete );
160 sendFileAction( ID, newDir, newFilepath, Actions::Add ); 152 sendFileAction( ID, newDir, newFilepath, Actions::Add );
161 153
162 if ( nEvent.Flags & efswFSEventsModified ) { 154 if ( nEvent.Flags & ModifiedFlags ) {
163 sendFileAction( ID, newDir, newFilepath, Actions::Modified ); 155 sendFileAction( ID, newDir, newFilepath, Actions::Modified );
164 } 156 }
165 } 157 }
166 } else { 158 } else {
167 handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); 159 handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath, event.inode );
168 } 160 }
169 161
170 if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | 162 if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated |
@@ -180,14 +172,14 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
180 } else if ( FileInfo::exists( event.Path ) ) { 172 } else if ( FileInfo::exists( event.Path ) ) {
181 sendFileAction( ID, dirPath, filePath, Actions::Add ); 173 sendFileAction( ID, dirPath, filePath, Actions::Add );
182 174
183 if ( event.Flags & efswFSEventsModified ) { 175 if ( event.Flags & ModifiedFlags ) {
184 sendFileAction( ID, dirPath, filePath, Actions::Modified ); 176 sendFileAction( ID, dirPath, filePath, Actions::Modified );
185 } 177 }
186 } else { 178 } else {
187 sendFileAction( ID, dirPath, filePath, Actions::Delete ); 179 sendFileAction( ID, dirPath, filePath, Actions::Delete );
188 } 180 }
189 } else { 181 } else {
190 handleAddModDel( event.Flags, event.Path, dirPath, filePath ); 182 handleAddModDel( event.Flags, event.Path, dirPath, filePath, event.inode );
191 } 183 }
192 } else { 184 } else {
193 efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); 185 efDEBUG( "Directory: %s changed\n", event.Path.c_str() );
@@ -197,7 +189,7 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
197} 189}
198 190
199void WatcherFSEvents::process() { 191void WatcherFSEvents::process() {
200 std::set<std::string>::iterator it = DirsChanged.begin(); 192 std::unordered_set<std::string>::iterator it = DirsChanged.begin();
201 193
202 for ( ; it != DirsChanged.end(); it++ ) { 194 for ( ; it != DirsChanged.end(); it++ ) {
203 if ( !FileWatcherFSEvents::isGranular() ) { 195 if ( !FileWatcherFSEvents::isGranular() ) {
diff --git a/src/3rdParty/efsw/WatcherFSEvents.hpp b/src/3rdParty/efsw/WatcherFSEvents.hpp
index 4dbb231..f05b094 100755..100644
--- a/src/3rdParty/efsw/WatcherFSEvents.hpp
+++ b/src/3rdParty/efsw/WatcherFSEvents.hpp
@@ -9,51 +9,72 @@
9#include <CoreServices/CoreServices.h> 9#include <CoreServices/CoreServices.h>
10#include <efsw/FileInfo.hpp> 10#include <efsw/FileInfo.hpp>
11#include <efsw/WatcherGeneric.hpp> 11#include <efsw/WatcherGeneric.hpp>
12#include <set> 12#include <unordered_set>
13#include <vector> 13#include <vector>
14 14
15namespace efsw { 15namespace efsw {
16 16
17/* OSX < 10.7 has no file events */
18/* So i declare the events constants */
19enum FSEventEvents {
20 efswFSEventStreamCreateFlagUseCFTypes = 0x00000001,
21 efswFSEventStreamCreateFlagNoDefer = 0x00000002,
22 efswFSEventStreamCreateFlagFileEvents = 0x00000010,
23 efswFSEventStreamCreateFlagUseExtendedData = 0x00000040,
24 efswFSEventStreamEventFlagItemCreated = 0x00000100,
25 efswFSEventStreamEventFlagItemRemoved = 0x00000200,
26 efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400,
27 efswFSEventStreamEventFlagItemRenamed = 0x00000800,
28 efswFSEventStreamEventFlagItemModified = 0x00001000,
29 efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000,
30 efswFSEventStreamEventFlagItemChangeOwner = 0x00004000,
31 efswFSEventStreamEventFlagItemXattrMod = 0x00008000,
32 efswFSEventStreamEventFlagItemIsFile = 0x00010000,
33 efswFSEventStreamEventFlagItemIsDir = 0x00020000,
34 efswFSEventStreamEventFlagItemIsSymlink = 0x00040000,
35 efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod |
36 efswFSEventStreamEventFlagItemModified |
37 efswFSEventStreamEventFlagItemInodeMetaMod
38};
39
17class FileWatcherFSEvents; 40class FileWatcherFSEvents;
18 41
19class FSEvent { 42class FSEvent {
20 public: 43 public:
21 FSEvent( std::string path, long flags, Uint64 id ) : Path( path ), Flags( flags ), Id( id ) {} 44 FSEvent( std::string path, long flags, Uint64 id, Uint64 inode = 0 ) :
45 Path( path ), Flags( flags ), Id( id ), inode( inode ) {}
22 46
23 std::string Path; 47 std::string Path;
24 long Flags; 48 long Flags{ 0 };
25 Uint64 Id; 49 Uint64 Id{ 0 };
50 Uint64 inode{ 0 };
26}; 51};
27 52
28class WatcherFSEvents : public Watcher { 53class WatcherFSEvents : public Watcher {
29 public: 54 public:
30 WatcherFSEvents(); 55 WatcherFSEvents();
31 56
32 WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive,
33 WatcherFSEvents* parent = NULL );
34
35 ~WatcherFSEvents(); 57 ~WatcherFSEvents();
36 58
37 void init(); 59 void init();
38 60
39 void initAsync();
40
41 void handleActions( std::vector<FSEvent>& events ); 61 void handleActions( std::vector<FSEvent>& events );
42 62
43 void process(); 63 void process();
44 64
45 Atomic<FileWatcherFSEvents*> FWatcher; 65 Atomic<FileWatcherFSEvents*> FWatcher;
46 FSEventStreamRef FSStream; 66 FSEventStreamRef FSStream;
67 Uint64 ModifiedFlags{ efswFSEventsModified };
68 bool SanitizeEvents{ false };
47 69
48 protected: 70 protected:
49 void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, 71 void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath,
50 std::string& filePath ); 72 std::string& filePath, Uint64 inode );
51 73
52 WatcherGeneric* WatcherGen; 74 WatcherGeneric* WatcherGen;
53 75
54 Atomic<bool> initializedAsync; 76 std::unordered_set<std::string> DirsChanged;
55 77 std::unordered_set<Uint64> FilesAdded;
56 std::set<std::string> DirsChanged;
57 78
58 void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, 79 void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename,
59 Action action, std::string oldFilename = "" ); 80 Action action, std::string oldFilename = "" );
diff --git a/src/3rdParty/efsw/WatcherGeneric.cpp b/src/3rdParty/efsw/WatcherGeneric.cpp
index a6bb106..a6bb106 100755..100644
--- a/src/3rdParty/efsw/WatcherGeneric.cpp
+++ b/src/3rdParty/efsw/WatcherGeneric.cpp
diff --git a/src/3rdParty/efsw/WatcherGeneric.hpp b/src/3rdParty/efsw/WatcherGeneric.hpp
index 9cf8365..d11ec20 100755..100644
--- a/src/3rdParty/efsw/WatcherGeneric.hpp
+++ b/src/3rdParty/efsw/WatcherGeneric.hpp
@@ -17,7 +17,7 @@ class WatcherGeneric : public Watcher {
17 17
18 ~WatcherGeneric(); 18 ~WatcherGeneric();
19 19
20 void watch(); 20 void watch() override;
21 21
22 void watchDir( std::string dir ); 22 void watchDir( std::string dir );
23 23
diff --git a/src/3rdParty/efsw/WatcherInotify.cpp b/src/3rdParty/efsw/WatcherInotify.cpp
index 7259bb1..812ddae 100755..100644
--- a/src/3rdParty/efsw/WatcherInotify.cpp
+++ b/src/3rdParty/efsw/WatcherInotify.cpp
@@ -4,10 +4,6 @@ namespace efsw {
4 4
5WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} 5WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {}
6 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 ) { 7bool WatcherInotify::inParentTree( WatcherInotify* parent ) {
12 WatcherInotify* tNext = Parent; 8 WatcherInotify* tNext = Parent;
13 9
diff --git a/src/3rdParty/efsw/WatcherInotify.hpp b/src/3rdParty/efsw/WatcherInotify.hpp
index bf2ff5e..ec55ed0 100755..100644
--- a/src/3rdParty/efsw/WatcherInotify.hpp
+++ b/src/3rdParty/efsw/WatcherInotify.hpp
@@ -10,15 +10,13 @@ class WatcherInotify : public Watcher {
10 public: 10 public:
11 WatcherInotify(); 11 WatcherInotify();
12 12
13 WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, bool recursive,
14 WatcherInotify* parent = NULL );
15
16 bool inParentTree( WatcherInotify* parent ); 13 bool inParentTree( WatcherInotify* parent );
17 14
18 WatcherInotify* Parent; 15 WatcherInotify* Parent;
19 WatchID InotifyID; 16 WatchID InotifyID;
20 17
21 FileInfo DirInfo; 18 FileInfo DirInfo;
19 bool syntheticEvents{ false };
22}; 20};
23 21
24} // namespace efsw 22} // namespace efsw
diff --git a/src/3rdParty/efsw/WatcherKqueue.cpp b/src/3rdParty/efsw/WatcherKqueue.cpp
index 441948a..424b989 100755..100644
--- a/src/3rdParty/efsw/WatcherKqueue.cpp
+++ b/src/3rdParty/efsw/WatcherKqueue.cpp
@@ -139,7 +139,7 @@ void WatcherKqueue::addAll() {
139void WatcherKqueue::removeAll() { 139void WatcherKqueue::removeAll() {
140 efDEBUG( "removeAll(): Removing all child watchers\n" ); 140 efDEBUG( "removeAll(): Removing all child watchers\n" );
141 141
142 std::list<WatchID> erase; 142 std::vector<WatchID> erase;
143 143
144 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { 144 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) {
145 efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); 145 efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() );
@@ -147,7 +147,7 @@ void WatcherKqueue::removeAll() {
147 erase.push_back( it->second->ID ); 147 erase.push_back( it->second->ID );
148 } 148 }
149 149
150 for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { 150 for ( std::vector<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) {
151 removeWatch( *eit ); 151 removeWatch( *eit );
152 } 152 }
153} 153}
@@ -354,7 +354,8 @@ void WatcherKqueue::watch() {
354 bool needScan = false; 354 bool needScan = false;
355 355
356 // Then we get the the events of the current folder 356 // Then we get the the events of the current folder
357 while ( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, 357 while ( !mChangeList.empty() &&
358 ( nev = kevent( mKqueue, mChangeList.data(), mChangeListCount + 1, &event, 1,
358 &mWatcher->mTimeOut ) ) != 0 ) { 359 &mWatcher->mTimeOut ) ) != 0 ) {
359 // An error ocurred? 360 // An error ocurred?
360 if ( nev == -1 ) { 361 if ( nev == -1 ) {
@@ -436,7 +437,6 @@ void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, boo
436 437
437WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, 438WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher,
438 bool recursive, WatcherKqueue* parent ) { 439 bool recursive, WatcherKqueue* parent ) {
439 static long s_fc = 0;
440 static bool s_ug = false; 440 static bool s_ug = false;
441 441
442 std::string dir( directory ); 442 std::string dir( directory );
@@ -478,8 +478,6 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener
478 478
479 watch->addAll(); 479 watch->addAll();
480 480
481 s_fc++;
482
483 // if failed to open the directory... erase the watcher 481 // if failed to open the directory... erase the watcher
484 if ( !watch->initOK() ) { 482 if ( !watch->initOK() ) {
485 int le = watch->lastErrno(); 483 int le = watch->lastErrno();
@@ -502,9 +500,8 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener
502 } 500 }
503 } else { 501 } else {
504 if ( !s_ug ) { 502 if ( !s_ug ) {
505 efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders " 503 efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld.\n",
506 "added: %ld\n", 504 mWatcher->mFileDescriptorCount );
507 mWatcher->mFileDescriptorCount, s_fc );
508 s_ug = true; 505 s_ug = true;
509 } 506 }
510 507
diff --git a/src/3rdParty/efsw/WatcherKqueue.hpp b/src/3rdParty/efsw/WatcherKqueue.hpp
index 87d898c..75c0f62 100755..100644
--- a/src/3rdParty/efsw/WatcherKqueue.hpp
+++ b/src/3rdParty/efsw/WatcherKqueue.hpp
@@ -49,7 +49,7 @@ class WatcherKqueue : public Watcher {
49 49
50 WatchID watchingDirectory( std::string dir ); 50 WatchID watchingDirectory( std::string dir );
51 51
52 void watch(); 52 void watch() override;
53 53
54 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, 54 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
55 WatcherKqueue* parent ); 55 WatcherKqueue* parent );
diff --git a/src/3rdParty/efsw/WatcherWin32.cpp b/src/3rdParty/efsw/WatcherWin32.cpp
index 3e8bcc7..712419e 100755..100644
--- a/src/3rdParty/efsw/WatcherWin32.cpp
+++ b/src/3rdParty/efsw/WatcherWin32.cpp
@@ -1,34 +1,114 @@
1#include <efsw/Debug.hpp>
1#include <efsw/String.hpp> 2#include <efsw/String.hpp>
2#include <efsw/WatcherWin32.hpp> 3#include <efsw/WatcherWin32.hpp>
3 4
4#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 5#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
5 6
7#include <algorithm>
8
6namespace efsw { 9namespace efsw {
7 10
8/// Unpacks events and passes them to a user defined callback. 11struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX {
9void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { 12 DWORD NextEntryOffset;
10 if ( dwNumberOfBytesTransfered == 0 || NULL == lpOverlapped ) { 13 DWORD Action;
11 return; 14 LARGE_INTEGER CreationTime;
15 LARGE_INTEGER LastModificationTime;
16 LARGE_INTEGER LastChangeTime;
17 LARGE_INTEGER LastAccessTime;
18 LARGE_INTEGER AllocatedLength;
19 LARGE_INTEGER FileSize;
20 DWORD FileAttributes;
21 DWORD ReparsePointTag;
22 LARGE_INTEGER FileId;
23 LARGE_INTEGER ParentFileId;
24 DWORD FileNameLength;
25 WCHAR FileName[1];
26};
27
28typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX;
29
30typedef BOOL( WINAPI* EFSW_LPREADDIRECTORYCHANGESEXW )( HANDLE hDirectory, LPVOID lpBuffer,
31 DWORD nBufferLength, BOOL bWatchSubtree,
32 DWORD dwNotifyFilter, LPDWORD lpBytesReturned,
33 LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
34 DWORD ReadDirectoryNotifyInformationClass );
35
36static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL;
37
38#define EFSW_ReadDirectoryNotifyExtendedInformation 2
39
40static void initReadDirectoryChangesEx() {
41 static bool hasInit = false;
42 if ( !hasInit ) {
43 hasInit = true;
44
45 HMODULE hModule = GetModuleHandleW( L"Kernel32.dll" );
46 if ( !hModule )
47 return;
48
49 pReadDirectoryChangesExW =
50 (EFSW_LPREADDIRECTORYCHANGESEXW)GetProcAddress( hModule, "ReadDirectoryChangesExW" );
12 } 51 }
52}
13 53
14 char szFile[MAX_PATH]; 54void WatchCallbackOld( WatcherWin32* pWatch ) {
15 PFILE_NOTIFY_INFORMATION pNotify; 55 PFILE_NOTIFY_INFORMATION pNotify;
16 WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
17 WatcherWin32* pWatch = tWatch->Watch;
18 size_t offset = 0; 56 size_t offset = 0;
19
20 do { 57 do {
21 bool skip = false; 58 bool skip = false;
22 59
23 pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; 60 pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset];
24 offset += pNotify->NextEntryOffset; 61 offset += pNotify->NextEntryOffset;
62 int count =
63 WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
64 pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL );
65 if ( count == 0 )
66 continue;
67
68 std::string nfile( count, '\0' );
69
70 count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
71 pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count,
72 NULL, NULL );
73
74 if ( FILE_ACTION_MODIFIED == pNotify->Action ) {
75 FileInfo fifile( std::string( pWatch->DirName ) + nfile );
76
77 if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime &&
78 pWatch->LastModifiedEvent.file.Size == fifile.Size &&
79 pWatch->LastModifiedEvent.fileName == nfile ) {
80 skip = true;
81 }
82
83 pWatch->LastModifiedEvent.fileName = nfile;
84 pWatch->LastModifiedEvent.file = fifile;
85 }
86
87 if ( !skip ) {
88 pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
89 }
90 } while ( pNotify->NextEntryOffset != 0 );
91}
92
93void WatchCallbackEx( WatcherWin32* pWatch ) {
94 EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX pNotify;
95 size_t offset = 0;
96 do {
97 bool skip = false;
98
99 pNotify = (EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX)&pWatch->Buffer[offset];
100 offset += pNotify->NextEntryOffset;
101 int count =
102 WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
103 pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL );
104 if ( count == 0 )
105 continue;
25 106
26 int count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, 107 std::string nfile( count, '\0' );
27 pNotify->FileNameLength / sizeof( WCHAR ), szFile,
28 MAX_PATH - 1, NULL, NULL );
29 szFile[count] = TEXT( '\0' );
30 108
31 std::string nfile( szFile ); 109 count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName,
110 pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count,
111 NULL, NULL );
32 112
33 if ( FILE_ACTION_MODIFIED == pNotify->Action ) { 113 if ( FILE_ACTION_MODIFIED == pNotify->Action ) {
34 FileInfo fifile( std::string( pWatch->DirName ) + nfile ); 114 FileInfo fifile( std::string( pWatch->DirName ) + nfile );
@@ -41,12 +121,59 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve
41 121
42 pWatch->LastModifiedEvent.fileName = nfile; 122 pWatch->LastModifiedEvent.fileName = nfile;
43 pWatch->LastModifiedEvent.file = fifile; 123 pWatch->LastModifiedEvent.file = fifile;
124 } else if ( FILE_ACTION_RENAMED_OLD_NAME == pNotify->Action ) {
125 pWatch->OldFiles.emplace_back( nfile, pNotify->FileId );
126 skip = true;
127 } else if ( FILE_ACTION_RENAMED_NEW_NAME == pNotify->Action ) {
128 std::string oldFile;
129 LARGE_INTEGER oldFileId{};
130
131 for ( auto it = pWatch->OldFiles.begin(); it != pWatch->OldFiles.end(); ++it ) {
132 if ( it->second.QuadPart == pNotify->FileId.QuadPart ) {
133 oldFile = it->first;
134 oldFileId = it->second;
135 it = pWatch->OldFiles.erase( it );
136 break;
137 }
138 }
139
140 if ( oldFile.empty() ) {
141 pWatch->Watch->handleAction( pWatch, nfile, FILE_ACTION_ADDED );
142 skip = true;
143 } else {
144 pWatch->Watch->handleAction( pWatch, oldFile, FILE_ACTION_RENAMED_OLD_NAME );
145 }
44 } 146 }
45 147
46 if ( !skip ) { 148 if ( !skip ) {
47 pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); 149 pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action );
48 } 150 }
49 } while ( pNotify->NextEntryOffset != 0 ); 151 } while ( pNotify->NextEntryOffset != 0 );
152}
153
154/// Unpacks events and passes them to a user defined callback.
155void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) {
156 if ( NULL == lpOverlapped ) {
157 return;
158 }
159
160 WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped;
161 WatcherWin32* pWatch = tWatch->Watch;
162
163 if ( dwNumberOfBytesTransfered == 0 ) {
164 if ( nullptr != pWatch && !pWatch->StopNow ) {
165 RefreshWatch( tWatch );
166 } else {
167 return;
168 }
169 }
170
171 // Fork watch depending on the Windows API supported
172 if ( pWatch->Extended ) {
173 WatchCallbackEx( pWatch );
174 } else {
175 WatchCallbackOld( pWatch );
176 }
50 177
51 if ( !pWatch->StopNow ) { 178 if ( !pWatch->StopNow ) {
52 RefreshWatch( tWatch ); 179 RefreshWatch( tWatch );
@@ -54,11 +181,40 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve
54} 181}
55 182
56/// Refreshes the directory monitoring. 183/// Refreshes the directory monitoring.
57bool RefreshWatch( WatcherStructWin32* pWatch ) { 184RefreshResult RefreshWatch( WatcherStructWin32* pWatch ) {
58 return ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer, 185 initReadDirectoryChangesEx();
59 sizeof( pWatch->Watch->Buffer ), pWatch->Watch->Recursive, 186
60 pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, 187 bool bRet = false;
61 NULL ) != 0; 188 RefreshResult ret = RefreshResult::Failed;
189 pWatch->Watch->Extended = false;
190
191 if ( pReadDirectoryChangesExW ) {
192 bRet = pReadDirectoryChangesExW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
193 (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
194 pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped,
195 NULL, EFSW_ReadDirectoryNotifyExtendedInformation ) != 0;
196 if ( bRet ) {
197 ret = RefreshResult::SucessEx;
198 pWatch->Watch->Extended = true;
199 }
200 }
201
202 if ( !bRet ) {
203 bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(),
204 (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive,
205 pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped,
206 NULL ) != 0;
207
208 if ( bRet )
209 ret = RefreshResult::Success;
210 }
211
212 if ( !bRet ) {
213 std::string error = std::to_string( GetLastError() );
214 Errors::Log::createLastError( Errors::WatcherFailed, error );
215 }
216
217 return ret;
62} 218}
63 219
64/// Stops monitoring a directory. 220/// Stops monitoring a directory.
@@ -70,19 +226,17 @@ void DestroyWatch( WatcherStructWin32* pWatch ) {
70 CloseHandle( pWatch->Watch->DirHandle ); 226 CloseHandle( pWatch->Watch->DirHandle );
71 efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); 227 efSAFE_DELETE_ARRAY( pWatch->Watch->DirName );
72 efSAFE_DELETE( pWatch->Watch ); 228 efSAFE_DELETE( pWatch->Watch );
229 efSAFE_DELETE( pWatch );
73 } 230 }
74} 231}
75 232
76/// Starts monitoring a directory. 233/// Starts monitoring a directory.
77WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, 234WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive,
78 HANDLE iocp ) { 235 DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ) {
79 WatcherStructWin32* tWatch; 236 WatcherStructWin32* tWatch = new WatcherStructWin32();
80 size_t ptrsize = sizeof( *tWatch ); 237 WatcherWin32* pWatch = new WatcherWin32(bufferSize);
81 tWatch = static_cast<WatcherStructWin32*>( 238 if (tWatch)
82 HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize ) ); 239 tWatch->Watch = pWatch;
83
84 WatcherWin32* pWatch = new WatcherWin32();
85 tWatch->Watch = pWatch;
86 240
87 pWatch->DirHandle = CreateFileW( 241 pWatch->DirHandle = CreateFileW(
88 szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 242 szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
@@ -90,17 +244,17 @@ WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD Noti
90 244
91 if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && 245 if ( pWatch->DirHandle != INVALID_HANDLE_VALUE &&
92 CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { 246 CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) {
93 pWatch->NotifyFilter = NotifyFilter; 247 pWatch->NotifyFilter = notifyFilter;
94 pWatch->Recursive = recursive; 248 pWatch->Recursive = recursive;
95 249
96 if ( RefreshWatch( tWatch ) ) { 250 if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) {
97 return tWatch; 251 return tWatch;
98 } 252 }
99 } 253 }
100 254
101 CloseHandle( pWatch->DirHandle ); 255 CloseHandle( pWatch->DirHandle );
102 efSAFE_DELETE( pWatch->Watch ); 256 efSAFE_DELETE( pWatch->Watch );
103 HeapFree( GetProcessHeap(), 0, tWatch ); 257 efSAFE_DELETE( tWatch );
104 return NULL; 258 return NULL;
105} 259}
106 260
diff --git a/src/3rdParty/efsw/WatcherWin32.hpp b/src/3rdParty/efsw/WatcherWin32.hpp
index 71e13be..ea1e8e4 100755..100644
--- a/src/3rdParty/efsw/WatcherWin32.hpp
+++ b/src/3rdParty/efsw/WatcherWin32.hpp
@@ -3,6 +3,7 @@
3 3
4#include <efsw/FileInfo.hpp> 4#include <efsw/FileInfo.hpp>
5#include <efsw/FileWatcherImpl.hpp> 5#include <efsw/FileWatcherImpl.hpp>
6#include <vector>
6 7
7#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 8#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
8 9
@@ -21,6 +22,8 @@ namespace efsw {
21 22
22class WatcherWin32; 23class WatcherWin32;
23 24
25enum RefreshResult { Failed, Success, SucessEx };
26
24/// Internal watch data 27/// Internal watch data
25struct WatcherStructWin32 { 28struct WatcherStructWin32 {
26 OVERLAPPED Overlapped; 29 OVERLAPPED Overlapped;
@@ -32,39 +35,41 @@ struct sLastModifiedEvent {
32 std::string fileName; 35 std::string fileName;
33}; 36};
34 37
35bool RefreshWatch( WatcherStructWin32* pWatch ); 38RefreshResult RefreshWatch( WatcherStructWin32* pWatch );
36 39
37void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); 40void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped );
38 41
39void DestroyWatch( WatcherStructWin32* pWatch ); 42void DestroyWatch( WatcherStructWin32* pWatch );
40 43
41WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, 44WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive,
42 HANDLE iocp ); 45 DWORD bufferSize, DWORD notifyFilter, HANDLE iocp );
43 46
44class WatcherWin32 : public Watcher { 47class WatcherWin32 : public Watcher {
45 public: 48 public:
46 WatcherWin32() : 49 WatcherWin32(DWORD dwBufferSize) :
47 Struct( NULL ), 50 Struct( NULL ),
48 DirHandle( NULL ), 51 DirHandle( NULL ),
52 Buffer(),
49 lParam( 0 ), 53 lParam( 0 ),
50 NotifyFilter( 0 ), 54 NotifyFilter( 0 ),
51 StopNow( false ), 55 StopNow( false ),
56 Extended( false ),
52 Watch( NULL ), 57 Watch( NULL ),
53 DirName( NULL ) {} 58 DirName( NULL ) {
59 Buffer.resize(dwBufferSize);
60 }
54 61
55 WatcherStructWin32* Struct; 62 WatcherStructWin32* Struct;
56 HANDLE DirHandle; 63 HANDLE DirHandle;
57 BYTE Buffer 64 std::vector<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; 65 LPARAM lParam;
63 DWORD NotifyFilter; 66 DWORD NotifyFilter;
64 bool StopNow; 67 bool StopNow;
68 bool Extended;
65 FileWatcherImpl* Watch; 69 FileWatcherImpl* Watch;
66 char* DirName; 70 char* DirName;
67 sLastModifiedEvent LastModifiedEvent; 71 sLastModifiedEvent LastModifiedEvent;
72 std::vector<std::pair<std::string, LARGE_INTEGER>> OldFiles;
68}; 73};
69 74
70} // namespace efsw 75} // namespace efsw
diff --git a/src/3rdParty/efsw/base.hpp b/src/3rdParty/efsw/base.hpp
index 43abc4f..43abc4f 100755..100644
--- a/src/3rdParty/efsw/base.hpp
+++ b/src/3rdParty/efsw/base.hpp
diff --git a/src/3rdParty/efsw/efsw.h b/src/3rdParty/efsw/efsw.h
index 28e63e2..30cf595 100755..100644
--- a/src/3rdParty/efsw/efsw.h
+++ b/src/3rdParty/efsw/efsw.h
@@ -1,7 +1,7 @@
1/** 1/**
2 @author Sepul Sepehr Taghdisian 2 @author Sepul Sepehr Taghdisian
3 3
4 Copyright (c) 2013 Martin Lucas Golini 4 Copyright (c) 2024 Martín Lucas Golini
5 5
6 Permission is hereby granted, free of charge, to any person obtaining a copy 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 7 of this software and associated documentation files (the "Software"), to deal
@@ -32,31 +32,31 @@
32extern "C" { 32extern "C" {
33#endif 33#endif
34 34
35#if defined(_WIN32) 35#if defined( _WIN32 )
36 #ifdef EFSW_DYNAMIC 36#ifdef EFSW_DYNAMIC
37 // Windows platforms 37// Windows platforms
38 #ifdef EFSW_EXPORTS 38#ifdef EFSW_EXPORTS
39 // From DLL side, we must export 39// From DLL side, we must export
40 #define EFSW_API __declspec(dllexport) 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 41#else
52 #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) 42// From client application side, we must import
53 #define EFSW_API __attribute__ ((visibility("default"))) 43#define EFSW_API __declspec( dllimport )
54 #endif 44#endif
55 45#else
56 // Other platforms don't need to define anything 46// No specific directive needed for static build
57 #ifndef EFSW_API 47#ifndef EFSW_API
58 #define EFSW_API 48#define EFSW_API
59 #endif 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 60#endif
61 61
62/// Type for a watch id 62/// Type for a watch id
@@ -65,84 +65,127 @@ typedef long efsw_watchid;
65/// Type for watcher 65/// Type for watcher
66typedef void* efsw_watcher; 66typedef void* efsw_watcher;
67 67
68enum efsw_action 68enum efsw_action {
69{ 69 EFSW_ADD = 1, /// Sent when a file is created or renamed
70 EFSW_ADD = 1, /// Sent when a file is created or renamed 70 EFSW_DELETE = 2, /// Sent when a file is deleted or renamed
71 EFSW_DELETE = 2, /// Sent when a file is deleted or renamed 71 EFSW_MODIFIED = 3, /// Sent when a file is modified
72 EFSW_MODIFIED = 3, /// Sent when a file is modified 72 EFSW_MOVED = 4 /// Sent when a file is moved
73 EFSW_MOVED = 4 /// Sent when a file is moved 73};
74
75enum efsw_error {
76 EFSW_NOTFOUND = -1,
77 EFSW_REPEATED = -2,
78 EFSW_OUTOFSCOPE = -3,
79 EFSW_NOTREADABLE = -4,
80 EFSW_REMOTE = -5,
81 EFSW_WATCHER_FAILED = -6,
82 EFSW_UNSPECIFIED = -7
74}; 83};
75 84
76enum efsw_error 85enum efsw_option {
77{ 86 /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and
78 EFSW_NOTFOUND = -1, 87 /// file system events may be dropped. For that, using a different (bigger) buffer size
79 EFSW_REPEATED = -2, 88 /// can be defined here, but note that this does not work for network drives,
80 EFSW_OUTOFSCOPE = -3, 89 /// because a buffer larger than 64K will fail the folder being watched, see
81 EFSW_NOTREADABLE = -4, 90 /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
82 EFSW_REMOTE = -5, 91 EFSW_OPT_WIN_BUFFER_SIZE = 1,
83 EFSW_UNSPECIFIED = -6 92 /// For Windows, per default all events are captured but we might only be interested
93 /// in a subset; the value of the option should be set to a bitwise or'ed set of
94 /// FILE_NOTIFY_CHANGE_* flags.
95 EFSW_OPT_WIN_NOTIFY_FILTER = 2,
96 /// For macOS (FSEvents backend), per default all modified event types are capture but we might
97 // only be interested in a subset; the value of the option should be set to a set of bitwise
98 // from:
99 // kFSEventStreamEventFlagItemFinderInfoMod
100 // kFSEventStreamEventFlagItemModified
101 // kFSEventStreamEventFlagItemInodeMetaMod
102 // Default configuration will set the 3 flags
103 EFSW_OPT_MAC_MODIFIED_FILTER = 3,
104 /// macOS sometimes informs incorrect or old file states that may confuse the consumer
105 /// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing
106 /// the number of events reported. This will have an small performance and memory impact as a
107 /// consequence.
108 EFSW_OPT_MAC_SANITIZE_EVENTS = 4,
109 /// Linux does not support natively recursive watchers. This means that when using recursive
110 /// watches efsw registers new watchers for each directory. If new file are created between
111 /// the time efsw takes to register the new directory those events might be missed. To avoid
112 /// missing new file notifications efsw will trigger synthetic new file events for existing
113 /// files in the new directroy watched. This might have the unintended consequence of sending
114 /// duplicated created events due to the system also emitting this event.
115 LINUX_PRODUCE_SYNTHETIC_EVENTS = 5,
84}; 116};
85 117
86/// Basic interface for listening for file events. 118/// Basic interface for listening for file events.
87typedef void (*efsw_pfn_fileaction_callback) ( 119typedef void ( *efsw_pfn_fileaction_callback )( efsw_watcher watcher, efsw_watchid watchid,
88 efsw_watcher watcher, 120 const char* dir, const char* filename,
89 efsw_watchid watchid, 121 enum efsw_action action, const char* old_filename,
90 const char* dir, 122 void* param );
91 const char* filename, 123
92 enum efsw_action action, 124typedef struct {
93 const char* old_filename, 125 enum efsw_option option;
94 void* param 126 int value;
95); 127} efsw_watcher_option;
96 128
97/** 129/**
98 * Creates a new file-watcher 130 * Creates a new file-watcher
99 * @param generic_mode Force the use of the Generic file watcher 131 * @param generic_mode Force the use of the Generic file watcher
100 */ 132 */
101efsw_watcher EFSW_API efsw_create(int generic_mode); 133efsw_watcher EFSW_API efsw_create( int generic_mode );
102 134
103/// Release the file-watcher and unwatch any directories 135/// Release the file-watcher and unwatch any directories
104void EFSW_API efsw_release(efsw_watcher watcher); 136void EFSW_API efsw_release( efsw_watcher watcher );
105 137
106/// Retreive last error occured by file-watcher 138/// Retrieve last error occured by file-watcher
107EFSW_API const char* efsw_getlasterror(); 139EFSW_API const char* efsw_getlasterror();
108 140
109/// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. 141/// Reset file-watcher last error
110/// For backwards compatibility. 142EFSW_API void efsw_clearlasterror();
143
144/// Add a directory watch
111/// On error returns WatchID with Error type. 145/// On error returns WatchID with Error type.
112efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory, 146efsw_watchid EFSW_API efsw_addwatch( efsw_watcher watcher, const char* directory,
113 efsw_pfn_fileaction_callback callback_fn, int recursive, void* param); 147 efsw_pfn_fileaction_callback callback_fn, int recursive,
148 void* param );
149
150/// Add a directory watch, specifying options
151/// @param options Pointer to an array of watcher options
152/// @param nr_options Number of options referenced by \p options
153efsw_watchid EFSW_API efsw_addwatch_withoptions( efsw_watcher watcher, const char* directory,
154 efsw_pfn_fileaction_callback callback_fn,
155 int recursive, efsw_watcher_option* options,
156 int options_number, void* param );
114 157
115/// Remove a directory watch. This is a brute force search O(nlogn). 158/// Remove a directory watch. This is a brute force search O(nlogn).
116void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory); 159void EFSW_API efsw_removewatch( efsw_watcher watcher, const char* directory );
117 160
118/// Remove a directory watch. This is a map lookup O(logn). 161/// Remove a directory watch. This is a map lookup O(logn).
119void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid); 162void EFSW_API efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid );
120 163
121/// Starts watching ( in other thread ) 164/// Starts watching ( in other thread )
122void EFSW_API efsw_watch(efsw_watcher watcher); 165void EFSW_API efsw_watch( efsw_watcher watcher );
123 166
124/** 167/**
125 * Allow recursive watchers to follow symbolic links to other directories 168 * Allow recursive watchers to follow symbolic links to other directories
126 * followSymlinks is disabled by default 169 * followSymlinks is disabled by default
127 */ 170 */
128void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable); 171void EFSW_API efsw_follow_symlinks( efsw_watcher watcher, int enable );
129 172
130/** @return If can follow symbolic links to directorioes */ 173/** @return If can follow symbolic links to directorioes */
131int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher); 174int EFSW_API efsw_follow_symlinks_isenabled( efsw_watcher watcher );
132 175
133/** 176/**
134 * When enable this it will allow symlinks to watch recursively out of the pointed directory. 177 * When enable this it will allow symlinks to watch recursively out of the pointed directory.
135 * follorSymlinks must be enabled to this work. 178 * 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, 179 * For example, added symlink to /home/folder, and the symlink points to /, this by default is not
137 * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. 180 * allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid great
138 * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). 181 * levels of recursion. Enabling this could lead in infinite recursion, and crash the watcher ( it
139 * Buy enabling out of scope links, it will allow this behavior. 182 * will try not to avoid this ). Buy enabling out of scope links, it will allow this behavior.
140 * allowOutOfScopeLinks are disabled by default. 183 * allowOutOfScopeLinks are disabled by default.
141 */ 184 */
142void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow); 185void EFSW_API efsw_allow_outofscopelinks( efsw_watcher watcher, int allow );
143 186
144/// @return Returns if out of scope links are allowed 187/// @return Returns if out of scope links are allowed
145int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher); 188int EFSW_API efsw_outofscopelinks_isallowed( efsw_watcher watcher );
146 189
147#ifdef __cplusplus 190#ifdef __cplusplus
148} 191}
diff --git a/src/3rdParty/efsw/efsw.hpp b/src/3rdParty/efsw/efsw.hpp
index 12af116..11a5dec 100755..100644
--- a/src/3rdParty/efsw/efsw.hpp
+++ b/src/3rdParty/efsw/efsw.hpp
@@ -1,195 +1,261 @@
1/** 1/**
2 @author Martín Lucas Golini 2 @author Martín Lucas Golini
3 3
4 Copyright (c) 2013 Martín Lucas Golini 4 Copyright (c) 2024 Martín Lucas Golini
5 5
6 Permission is hereby granted, free of charge, to any person obtaining a copy 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 7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights 8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 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 10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions: 11 furnished to do so, subject to the following conditions:
12 12
13 The above copyright notice and this permission notice shall be included in 13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software. 14 all copies or substantial portions of the Software.
15 15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 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, 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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 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, 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 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE. 22 THE SOFTWARE.
23 23
24 This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) 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. 25 http://code.google.com/p/simplefilewatcher/ also MIT licensed.
26*/ 26*/
27 27
28#ifndef ESFW_HPP 28#ifndef ESFW_HPP
29#define ESFW_HPP 29#define ESFW_HPP
30 30
31#include <list> 31#include <string>
32#include <string> 32#include <vector>
33 33
34#if defined( _WIN32 ) 34#if defined( _WIN32 )
35#ifdef EFSW_DYNAMIC 35#ifdef EFSW_DYNAMIC
36// Windows platforms 36// Windows platforms
37#ifdef EFSW_EXPORTS 37#ifdef EFSW_EXPORTS
38// From DLL side, we must export 38// From DLL side, we must export
39#define EFSW_API __declspec( dllexport ) 39#define EFSW_API __declspec( dllexport )
40#else 40#else
41// From client application side, we must import 41// From client application side, we must import
42#define EFSW_API __declspec( dllimport ) 42#define EFSW_API __declspec( dllimport )
43#endif 43#endif
44#else 44#else
45// No specific directive needed for static build 45// No specific directive needed for static build
46#ifndef EFSW_API 46#ifndef EFSW_API
47#define EFSW_API 47#define EFSW_API
48#endif 48#endif
49#endif 49#endif
50#else 50#else
51#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) 51#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS )
52#ifndef EFSW_API 52#ifndef EFSW_API
53#define EFSW_API __attribute__( ( visibility( "default" ) ) ) 53#define EFSW_API __attribute__( ( visibility( "default" ) ) )
54#endif 54#endif
55#endif 55#endif
56 56
57// Other platforms don't need to define anything 57// Other platforms don't need to define anything
58#ifndef EFSW_API 58#ifndef EFSW_API
59#define EFSW_API 59#define EFSW_API
60#endif 60#endif
61#endif 61#endif
62 62
63namespace efsw { 63namespace efsw {
64 64
65/// Type for a watch id 65/// Type for a watch id
66typedef long WatchID; 66typedef long WatchID;
67 67
68// forward declarations 68// forward declarations
69class FileWatcherImpl; 69class FileWatcherImpl;
70class FileWatchListener; 70class FileWatchListener;
71 71class WatcherOption;
72/// Actions to listen for. Rename will send two events, one for 72
73/// the deletion of the old file, and one for the creation of the 73/// Actions to listen for. Rename will send two events, one for
74/// new file. 74/// the deletion of the old file, and one for the creation of the
75namespace Actions { 75/// new file.
76enum Action { 76namespace Actions {
77 /// Sent when a file is created or renamed 77enum Action {
78 Add = 1, 78 /// Sent when a file is created or renamed
79 /// Sent when a file is deleted or renamed 79 Add = 1,
80 Delete = 2, 80 /// Sent when a file is deleted or renamed
81 /// Sent when a file is modified 81 Delete = 2,
82 Modified = 3, 82 /// Sent when a file is modified
83 /// Sent when a file is moved 83 Modified = 3,
84 Moved = 4 84 /// Sent when a file is moved
85}; 85 Moved = 4
86} 86};
87typedef Actions::Action Action; 87}
88 88typedef Actions::Action Action;
89/// Errors log namespace 89
90namespace Errors { 90/// Errors log namespace
91 91namespace Errors {
92enum Error { 92
93 FileNotFound = -1, 93enum Error {
94 FileRepeated = -2, 94 NoError = 0,
95 FileOutOfScope = -3, 95 FileNotFound = -1,
96 FileNotReadable = -4, 96 FileRepeated = -2,
97 FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to 97 FileOutOfScope = -3,
98 watch this directory ). */ 98 FileNotReadable = -4,
99 Unspecified = -6 99 /// Directory in remote file system
100}; 100 /// ( create a generic FileWatcher instance to watch this directory ).
101 101 FileRemote = -5,
102class EFSW_API Log { 102 /// File system watcher failed to watch for changes.
103 public: 103 WatcherFailed = -6,
104 /// @return The last error logged 104 Unspecified = -7
105 static std::string getLastErrorLog(); 105};
106 106
107 /// Creates an error of the type specified 107class EFSW_API Log {
108 static Error createLastError( Error err, std::string log ); 108 public:
109}; 109 /// @return The last error logged
110 110 static std::string getLastErrorLog();
111} // namespace Errors 111
112typedef Errors::Error Error; 112 /// @return The code of the last error logged
113 113 static Error getLastErrorCode();
114/// Listens to files and directories and dispatches events 114
115/// to notify the listener of files and directories changes. 115 /// Reset last error
116/// @class FileWatcher 116 static void clearLastError();
117class EFSW_API FileWatcher { 117
118 public: 118 /// Creates an error of the type specified
119 /// Default constructor, will use the default platform file watcher 119 static Error createLastError( Error err, std::string log );
120 FileWatcher(); 120};
121 121
122 /// Constructor that lets you force the use of the Generic File Watcher 122} // namespace Errors
123 explicit FileWatcher( bool useGenericFileWatcher ); 123typedef Errors::Error Error;
124 124
125 virtual ~FileWatcher(); 125/// Optional file watcher settings.
126 126namespace Options {
127 /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. 127enum Option {
128 /// For backwards compatibility. 128 /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and
129 /// On error returns WatchID with Error type. 129 /// file system events may be dropped. For that, using a different (bigger) buffer size
130 WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); 130 /// can be defined here, but note that this does not work for network drives,
131 131 /// because a buffer larger than 64K will fail the folder being watched, see
132 /// Add a directory watch 132 /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx)
133 /// On error returns WatchID with Error type. 133 WinBufferSize = 1,
134 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); 134 /// For Windows, per default all events are captured but we might only be interested
135 135 /// in a subset; the value of the option should be set to a bitwise or'ed set of
136 /// Remove a directory watch. This is a brute force search O(nlogn). 136 /// FILE_NOTIFY_CHANGE_* flags.
137 void removeWatch( const std::string& directory ); 137 WinNotifyFilter = 2,
138 138 /// For macOS (FSEvents backend), per default all modified event types are capture but we might
139 /// Remove a directory watch. This is a map lookup O(logn). 139 /// only be interested in a subset; the value of the option should be set to a set of bitwise
140 void removeWatch( WatchID watchid ); 140 /// from:
141 141 /// kFSEventStreamEventFlagItemFinderInfoMod
142 /// Starts watching ( in other thread ) 142 /// kFSEventStreamEventFlagItemModified
143 void watch(); 143 /// kFSEventStreamEventFlagItemInodeMetaMod
144 144 /// Default configuration will set the 3 flags
145 /// @return Returns a list of the directories that are being watched 145 MacModifiedFilter = 3,
146 std::list<std::string> directories(); 146 /// macOS sometimes informs incorrect or old file states that may confuse the consumer
147 147 /// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing
148 /** Allow recursive watchers to follow symbolic links to other directories 148 /// the number of events reported. This will have an small performance and memory impact as a
149 * followSymlinks is disabled by default 149 /// consequence.
150 */ 150 MacSanitizeEvents = 4,
151 void followSymlinks( bool follow ); 151 /// Linux does not support natively recursive watchers. This means that when using recursive
152 152 /// watches efsw registers new watchers for each directory. If new file are created between
153 /** @return If can follow symbolic links to directorioes */ 153 /// the time efsw takes to register the new directory those events might be missed. To avoid
154 const bool& followSymlinks() const; 154 /// missing new file notifications efsw will trigger synthetic created file events for existing
155 155 /// files in the new directroy watched. This might have the unintended consequence of sending
156 /** When enable this it will allow symlinks to watch recursively out of the pointed directory. 156 /// duplicated created events due to the system also emitting this event.
157 * follorSymlinks must be enabled to this work. 157 LinuxProduceSyntheticEvents = 5,
158 * For example, added symlink to /home/folder, and the symlink points to /, this by default is 158};
159 * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid 159}
160 * great levels of recursion. Enabling this could lead in infinite recursion, and crash the 160typedef Options::Option Option;
161 * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow 161
162 * this behavior. allowOutOfScopeLinks are disabled by default. 162/// Listens to files and directories and dispatches events
163 */ 163/// to notify the listener of files and directories changes.
164 void allowOutOfScopeLinks( bool allow ); 164/// @class FileWatcher
165 165class EFSW_API FileWatcher {
166 /// @return Returns if out of scope links are allowed 166 public:
167 const bool& allowOutOfScopeLinks() const; 167 /// Default constructor, will use the default platform file watcher
168 168 FileWatcher();
169 private: 169
170 /// The implementation 170 /// Constructor that lets you force the use of the Generic File Watcher
171 FileWatcherImpl* mImpl; 171 explicit FileWatcher( bool useGenericFileWatcher );
172 bool mFollowSymlinks; 172
173 bool mOutOfScopeLinks; 173 virtual ~FileWatcher();
174}; 174
175 175 /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option.
176/// Basic interface for listening for file events. 176 /// For backwards compatibility.
177/// @class FileWatchListener 177 /// On error returns WatchID with Error type.
178class FileWatchListener { 178 WatchID addWatch( const std::string& directory, FileWatchListener* watcher );
179 public: 179
180 virtual ~FileWatchListener() {} 180 /// Add a directory watch
181 181 /// On error returns WatchID with Error type.
182 /// Handles the action file action 182 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive );
183 /// @param watchid The watch id for the directory 183
184 /// @param dir The directory 184 /// Add a directory watch, allowing customization with options
185 /// @param filename The filename that was accessed (not full path) 185 /// @param directory The folder to be watched
186 /// @param action Action that was performed 186 /// @param watcher The listener to receive events
187 /// @param oldFilename The name of the file or directory moved 187 /// @param recursive Set this to true to include subdirectories
188 virtual void handleFileAction( WatchID watchid, const std::string& dir, 188 /// @param options Allows customization of a watcher
189 const std::string& filename, Action action, 189 /// @return Returns the watch id for the directory or, on error, a WatchID with Error type.
190 std::string oldFilename = "" ) = 0; 190 WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
191}; 191 const std::vector<WatcherOption>& options );
192 192
193} // namespace efsw 193 /// Remove a directory watch. This is a brute force search O(nlogn).
194 194 void removeWatch( const std::string& directory );
195#endif 195
196 /// Remove a directory watch. This is a map lookup O(logn).
197 void removeWatch( WatchID watchid );
198
199 /// Starts watching ( in other thread )
200 void watch();
201
202 /// @return Returns a list of the directories that are being watched
203 std::vector<std::string> directories();
204
205 /** Allow recursive watchers to follow symbolic links to other directories
206 * followSymlinks is disabled by default
207 */
208 void followSymlinks( bool follow );
209
210 /** @return If can follow symbolic links to directorioes */
211 const bool& followSymlinks() const;
212
213 /** When enable this it will allow symlinks to watch recursively out of the pointed directory.
214 * follorSymlinks must be enabled to this work.
215 * For example, added symlink to /home/folder, and the symlink points to /, this by default is
216 * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid
217 * great levels of recursion. Enabling this could lead in infinite recursion, and crash the
218 * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow
219 * this behavior. allowOutOfScopeLinks are disabled by default.
220 */
221 void allowOutOfScopeLinks( bool allow );
222
223 /// @return Returns if out of scope links are allowed
224 const bool& allowOutOfScopeLinks() const;
225
226 private:
227 /// The implementation
228 FileWatcherImpl* mImpl;
229 bool mFollowSymlinks;
230 bool mOutOfScopeLinks;
231};
232
233/// Basic interface for listening for file events.
234/// @class FileWatchListener
235class FileWatchListener {
236 public:
237 virtual ~FileWatchListener() {}
238
239 /// Handles the action file action
240 /// @param watchid The watch id for the directory
241 /// @param dir The directory
242 /// @param filename The filename that was accessed (not full path)
243 /// @param action Action that was performed
244 /// @param oldFilename The name of the file or directory moved
245 virtual void handleFileAction( WatchID watchid, const std::string& dir,
246 const std::string& filename, Action action,
247 std::string oldFilename = "" ) = 0;
248};
249
250/// Optional, typically platform specific parameter for customization of a watcher.
251/// @class WatcherOption
252class WatcherOption {
253 public:
254 WatcherOption( Option option, int value ) : mOption( option ), mValue( value ){};
255 Option mOption;
256 int mValue;
257};
258
259} // namespace efsw
260
261#endif
diff --git a/src/3rdParty/efsw/inotify-nosys.h b/src/3rdParty/efsw/inotify-nosys.h
index be1e627..be1e627 100755..100644
--- a/src/3rdParty/efsw/inotify-nosys.h
+++ b/src/3rdParty/efsw/inotify-nosys.h
diff --git a/src/3rdParty/efsw/platform/platformimpl.hpp b/src/3rdParty/efsw/platform/platformimpl.hpp
index 5442580..5442580 100755..100644
--- a/src/3rdParty/efsw/platform/platformimpl.hpp
+++ b/src/3rdParty/efsw/platform/platformimpl.hpp
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp
index 92eeb47..92eeb47 100755..100644
--- a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp
+++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp
index 0bfba76..0bfba76 100755..100644
--- a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp
+++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp
index 2233798..2233798 100755..100644
--- a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp
+++ b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp
index a33d827..a33d827 100755..100644
--- a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp
+++ b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp
index 37d4120..37d4120 100755..100644
--- a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp
+++ b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp
index 9322b06..9322b06 100755..100644
--- a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp
+++ b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp
index e0ae84f..772fbc9 100755..100644
--- a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp
+++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp
@@ -5,11 +5,10 @@
5 5
6#include <cassert> 6#include <cassert>
7#include <efsw/Debug.hpp> 7#include <efsw/Debug.hpp>
8#include <iostream>
9 8
10namespace efsw { namespace Platform { 9namespace efsw { namespace Platform {
11 10
12ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) { 11ThreadImpl::ThreadImpl( efsw::Thread* owner ) : mIsActive( false ) {
13 mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; 12 mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0;
14 13
15 if ( !mIsActive ) { 14 if ( !mIsActive ) {
@@ -17,14 +16,16 @@ ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) {
17 } 16 }
18} 17}
19 18
19ThreadImpl::~ThreadImpl() {
20 terminate();
21}
22
20void ThreadImpl::wait() { 23void ThreadImpl::wait() {
21 // Wait for the thread to finish, no timeout 24 // Wait for the thread to finish, no timeout
22 if ( mIsActive ) { 25 if ( mIsActive ) {
23 assert( pthread_equal( pthread_self(), mThread ) == 0 ); 26 assert( pthread_equal( pthread_self(), mThread ) == 0 );
24 27
25 pthread_join( mThread, NULL ); 28 mIsActive = pthread_join( mThread, NULL ) != 0;
26
27 mIsActive = false; // Reset the thread state
28 } 29 }
29} 30}
30 31
@@ -41,14 +42,14 @@ void ThreadImpl::terminate() {
41} 42}
42 43
43void* ThreadImpl::entryPoint( void* userData ) { 44void* 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 45// Tell the thread to handle cancel requests immediatly
48#ifdef PTHREAD_CANCEL_ASYNCHRONOUS 46#ifdef PTHREAD_CANCEL_ASYNCHRONOUS
49 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); 47 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
50#endif 48#endif
51 49
50 // The Thread instance is stored in the user data
51 Thread* owner = static_cast<Thread*>( userData );
52
52 // Forward to the owner 53 // Forward to the owner
53 owner->run(); 54 owner->run();
54 55
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp
index ffc6da0..2e02f9a 100755..100644
--- a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp
+++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp
@@ -5,6 +5,7 @@
5 5
6#if defined( EFSW_PLATFORM_POSIX ) 6#if defined( EFSW_PLATFORM_POSIX )
7 7
8#include <efsw/Atomic.hpp>
8#include <pthread.h> 9#include <pthread.h>
9 10
10namespace efsw { 11namespace efsw {
@@ -15,7 +16,9 @@ namespace Platform {
15 16
16class ThreadImpl { 17class ThreadImpl {
17 public: 18 public:
18 ThreadImpl( Thread* owner ); 19 explicit ThreadImpl( efsw::Thread* owner );
20
21 ~ThreadImpl();
19 22
20 void wait(); 23 void wait();
21 24
@@ -25,7 +28,7 @@ class ThreadImpl {
25 static void* entryPoint( void* userData ); 28 static void* entryPoint( void* userData );
26 29
27 pthread_t mThread; 30 pthread_t mThread;
28 bool mIsActive; 31 Atomic<bool> mIsActive;
29}; 32};
30 33
31} // namespace Platform 34} // namespace Platform
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp
index 2b87513..2b87513 100755..100644
--- a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp
+++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp
index e952efc..e952efc 100755..100644
--- a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp
+++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.cpp b/src/3rdParty/efsw/platform/win/MutexImpl.cpp
index 62b7f83..62b7f83 100755..100644
--- a/src/3rdParty/efsw/platform/win/MutexImpl.cpp
+++ b/src/3rdParty/efsw/platform/win/MutexImpl.cpp
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.hpp b/src/3rdParty/efsw/platform/win/MutexImpl.hpp
index 7b06492..7b06492 100755..100644
--- a/src/3rdParty/efsw/platform/win/MutexImpl.hpp
+++ b/src/3rdParty/efsw/platform/win/MutexImpl.hpp
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.cpp b/src/3rdParty/efsw/platform/win/SystemImpl.cpp
index d1f2b21..d1f2b21 100755..100644
--- a/src/3rdParty/efsw/platform/win/SystemImpl.cpp
+++ b/src/3rdParty/efsw/platform/win/SystemImpl.cpp
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.hpp b/src/3rdParty/efsw/platform/win/SystemImpl.hpp
index 99b4867..99b4867 100755..100644
--- a/src/3rdParty/efsw/platform/win/SystemImpl.hpp
+++ b/src/3rdParty/efsw/platform/win/SystemImpl.hpp
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp
index d0fde8b..463934c 100755..100644
--- a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp
+++ b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp
@@ -8,7 +8,7 @@
8 8
9namespace efsw { namespace Platform { 9namespace efsw { namespace Platform {
10 10
11ThreadImpl::ThreadImpl( Thread* owner ) { 11ThreadImpl::ThreadImpl( efsw::Thread* owner ) {
12 mThread = reinterpret_cast<HANDLE>( 12 mThread = reinterpret_cast<HANDLE>(
13 _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); 13 _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) );
14 14
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp
index 1afb593..455f24c 100755..100644
--- a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp
+++ b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp
@@ -19,7 +19,7 @@ namespace Platform {
19 19
20class ThreadImpl { 20class ThreadImpl {
21 public: 21 public:
22 ThreadImpl( Thread* owner ); 22 explicit ThreadImpl( efsw::Thread* owner );
23 23
24 ~ThreadImpl(); 24 ~ThreadImpl();
25 25
diff --git a/src/3rdParty/efsw/sophist.h b/src/3rdParty/efsw/sophist.h
index 3a64504..82e5c36 100755..100644
--- a/src/3rdParty/efsw/sophist.h
+++ b/src/3rdParty/efsw/sophist.h
@@ -1,147 +1,147 @@
1/* sophist.h - 0.3 - public domain - Sean Barrett 2010 1/* sophist.h - 0.3 - public domain - Sean Barrett 2010
2** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net 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 3** Sophist provides portable types; you typedef/#define them to your own names
4** 4**
5** defines: 5** defines:
6** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian 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 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 8** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit
9** 9**
10** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer 10** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer
11** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 11** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16
12** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 12** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64
13** - SOPHIST_int64_constant(number) - macros for creating 64-bit 13** - SOPHIST_int64_constant(number) - macros for creating 64-bit
14** - SOPHIST_uint64_constant(number) integer constants 14** - SOPHIST_uint64_constant(number) integer constants
15** - SOPHIST_printf_format64 - string for printf format for int64 15** - SOPHIST_printf_format64 - string for printf format for int64
16*/ 16*/
17 17
18#ifndef __INCLUDE_SOPHIST_H__ 18#ifndef __INCLUDE_SOPHIST_H__
19#define __INCLUDE_SOPHIST_H__ 19#define __INCLUDE_SOPHIST_H__
20 20
21#define SOPHIST_compiletime_assert(name,val) \ 21#define SOPHIST_compiletime_assert(name,val) \
22 typedef int SOPHIST__assert##name[(val) ? 1 : -1] 22 typedef int SOPHIST__assert##name[(val) ? 1 : -1]
23 23
24/* define a couple synthetic rules to make code more readable */ 24/* define a couple synthetic rules to make code more readable */
25#if (defined(__sparc__) || defined(__sparc)) && \ 25#if (defined(__sparc__) || defined(__sparc)) && \
26 (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) 26 (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__))
27 #define SOPHIST_sparc64 27 #define SOPHIST_sparc64
28#endif 28#endif
29 29
30#if (defined(linux) || defined(__linux__)) && \ 30#if (defined(linux) || defined(__linux__)) && \
31 (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) 31 (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64))
32 #define SOPHIST_linux64 32 #define SOPHIST_linux64
33#endif 33#endif
34 34
35/* basic types */ 35/* basic types */
36typedef signed char SOPHIST_int8; 36typedef signed char SOPHIST_int8;
37typedef unsigned char SOPHIST_uint8; 37typedef unsigned char SOPHIST_uint8;
38 38
39typedef signed short SOPHIST_int16; 39typedef signed short SOPHIST_int16;
40typedef unsigned short SOPHIST_uint16; 40typedef unsigned short SOPHIST_uint16;
41 41
42#ifdef __palmos__ 42#ifdef __palmos__
43 typedef signed long SOPHIST_int32; 43 typedef signed long SOPHIST_int32;
44 typedef unsigned long SOPHIST_uint32; 44 typedef unsigned long SOPHIST_uint32;
45#else 45#else
46 typedef signed int SOPHIST_int32; 46 typedef signed int SOPHIST_int32;
47 typedef unsigned int SOPHIST_uint32; 47 typedef unsigned int SOPHIST_uint32;
48#endif 48#endif
49 49
50#ifndef SOPHIST_NO_64 50#ifndef SOPHIST_NO_64
51 #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ 51 #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \
52 || (defined(__alpha) && defined(__DECC)) 52 || (defined(__alpha) && defined(__DECC))
53 53
54 typedef signed __int64 SOPHIST_int64; 54 typedef signed __int64 SOPHIST_int64;
55 typedef unsigned __int64 SOPHIST_uint64; 55 typedef unsigned __int64 SOPHIST_uint64;
56 #define SOPHIST_has_64 1 56 #define SOPHIST_has_64 1
57 #define SOPHIST_int64_constant(x) (x##i64) 57 #define SOPHIST_int64_constant(x) (x##i64)
58 #define SOPHIST_uint64_constant(x) (x##ui64) 58 #define SOPHIST_uint64_constant(x) (x##ui64)
59 #define SOPHIST_printf_format64 "I64" 59 #define SOPHIST_printf_format64 "I64"
60 60
61 #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) 61 #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64)
62 62
63 typedef signed long SOPHIST_int64; 63 typedef signed long SOPHIST_int64;
64 typedef unsigned long SOPHIST_uint64; 64 typedef unsigned long SOPHIST_uint64;
65 65
66 #define SOPHIST_has_64 1 66 #define SOPHIST_has_64 1
67 #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) 67 #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x)
68 #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) 68 #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x)
69 #define SOPHIST_printf_format64 "l" 69 #define SOPHIST_printf_format64 "l"
70 70
71 #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ 71 #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \
72 || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ 72 || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \
73 || defined(sgi) || defined (__sgi) || defined(__sgi__) \ 73 || defined(sgi) || defined (__sgi) || defined(__sgi__) \
74 || defined(_CRAYC) 74 || defined(_CRAYC)
75 75
76 typedef signed long long SOPHIST_int64; 76 typedef signed long long SOPHIST_int64;
77 typedef unsigned long long SOPHIST_uint64; 77 typedef unsigned long long SOPHIST_uint64;
78 78
79 #define SOPHIST_has_64 1 79 #define SOPHIST_has_64 1
80 #define SOPHIST_int64_constant(x) (x##LL) 80 #define SOPHIST_int64_constant(x) (x##LL)
81 #define SOPHIST_uint64_constant(x) (x##ULL) 81 #define SOPHIST_uint64_constant(x) (x##ULL)
82 #define SOPHIST_printf_format64 "ll" 82 #define SOPHIST_printf_format64 "ll"
83 #endif 83 #endif
84#endif 84#endif
85 85
86#ifndef SOPHIST_has_64 86#ifndef SOPHIST_has_64
87#define SOPHIST_has_64 0 87#define SOPHIST_has_64 0
88#endif 88#endif
89 89
90SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); 90SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1);
91SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); 91SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2);
92SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); 92SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4);
93SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); 93SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4);
94 94
95#if SOPHIST_has_64 95#if SOPHIST_has_64
96 SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); 96 SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8);
97 SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); 97 SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8);
98#endif 98#endif
99 99
100/* determine whether pointers are 64-bit */ 100/* determine whether pointers are 64-bit */
101 101
102#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ 102#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \
103 || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ 103 || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \
104 || defined(__64BIT__) \ 104 || defined(__64BIT__) \
105 || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ 105 || defined(__LP64) || defined(__LP64__) || defined(_LP64) \
106 || defined(_ADDR64) || defined(_CRAYC) \ 106 || defined(_ADDR64) || defined(_CRAYC) \
107 107
108 #define SOPHIST_pointer64 1 108 #define SOPHIST_pointer64 1
109 109
110 SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); 110 SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8);
111 111
112 typedef SOPHIST_int64 SOPHIST_intptr; 112 typedef SOPHIST_int64 SOPHIST_intptr;
113 typedef SOPHIST_uint64 SOPHIST_uintptr; 113 typedef SOPHIST_uint64 SOPHIST_uintptr;
114#else 114#else
115 115
116 #define SOPHIST_pointer64 0 116 #define SOPHIST_pointer64 0
117 117
118 SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); 118 SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4);
119 119
120 /* do we care about pointers that are only 16-bit? */ 120 /* do we care about pointers that are only 16-bit? */
121 typedef SOPHIST_int32 SOPHIST_intptr; 121 typedef SOPHIST_int32 SOPHIST_intptr;
122 typedef SOPHIST_uint32 SOPHIST_uintptr; 122 typedef SOPHIST_uint32 SOPHIST_uintptr;
123 123
124#endif 124#endif
125 125
126SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); 126SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *));
127 127
128/* enumerate known little endian cases; fallback to big-endian */ 128/* enumerate known little endian cases; fallback to big-endian */
129 129
130#define SOPHIST_little_endian 1 130#define SOPHIST_little_endian 1
131#define SOPHIST_big_endian 2 131#define SOPHIST_big_endian 2
132 132
133#if defined(__386__) || defined(i386) || defined(__i386__) \ 133#if defined(__386__) || defined(i386) || defined(__i386__) \
134 || defined(__X86) || defined(_M_IX86) \ 134 || defined(__X86) || defined(_M_IX86) \
135 || defined(_M_X64) || defined(__x86_64__) \ 135 || defined(_M_X64) || defined(__x86_64__) \
136 || defined(alpha) || defined(__alpha) || defined(__alpha__) \ 136 || defined(alpha) || defined(__alpha) || defined(__alpha__) \
137 || defined(_M_ALPHA) \ 137 || defined(_M_ALPHA) \
138 || defined(ARM) || defined(_ARM) || defined(__arm__) \ 138 || defined(ARM) || defined(_ARM) || defined(__arm__) \
139 || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ 139 || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
140 || defined(_WIN32_WCE) || defined(__NT__) \ 140 || defined(_WIN32_WCE) || defined(__NT__) \
141 || defined(__MIPSEL__) 141 || defined(__MIPSEL__)
142 #define SOPHIST_endian SOPHIST_little_endian 142 #define SOPHIST_endian SOPHIST_little_endian
143#else 143#else
144 #define SOPHIST_endian SOPHIST_big_endian 144 #define SOPHIST_endian SOPHIST_big_endian
145#endif 145#endif
146 146
147#endif /* __INCLUDE_SOPHIST_H__ */ 147#endif /* __INCLUDE_SOPHIST_H__ */
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index e670126..5e70645 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -620,6 +620,7 @@ AST_END(Slice)
620 620
621AST_NODE(Parens) 621AST_NODE(Parens)
622 ast_ptr<true, Exp_t> expr; 622 ast_ptr<true, Exp_t> expr;
623 bool extra = false;
623 AST_MEMBER(Parens, &expr) 624 AST_MEMBER(Parens, &expr)
624AST_END(Parens) 625AST_END(Parens)
625 626
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index a2a1864..68ce9b5 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = {
75 "close"s // Lua 5.4 75 "close"s // Lua 5.4
76}; 76};
77 77
78const std::string_view version = "0.27.3"sv; 78const std::string_view version = "0.27.4"sv;
79const std::string_view extension = "yue"sv; 79const std::string_view extension = "yue"sv;
80 80
81class CompileError : public std::logic_error { 81class CompileError : public std::logic_error {
@@ -1080,8 +1080,8 @@ private:
1080 if (unary->ops.empty()) { 1080 if (unary->ops.empty()) {
1081 Value_t* value = static_cast<Value_t*>(unary->expos.back()); 1081 Value_t* value = static_cast<Value_t*>(unary->expos.back());
1082 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { 1082 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) {
1083 if (auto exp = chain->get_by_path<Callable_t, Parens_t, Exp_t>()) { 1083 if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && parens->extra) {
1084 if (auto insideValue = singleValueFrom(exp)) { 1084 if (auto insideValue = singleValueFrom(parens->expr)) {
1085 return insideValue; 1085 return insideValue;
1086 } 1086 }
1087 } 1087 }
@@ -3262,6 +3262,7 @@ private:
3262 } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { 3262 } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) {
3263 auto p = destruct.value.get(); 3263 auto p = destruct.value.get();
3264 auto parens = p->new_ptr<Parens_t>(); 3264 auto parens = p->new_ptr<Parens_t>();
3265 parens->extra = true;
3265 if (auto tableBlock = ast_cast<TableBlock_t>(p)) { 3266 if (auto tableBlock = ast_cast<TableBlock_t>(p)) {
3266 auto tableLit = p->new_ptr<TableLit_t>(); 3267 auto tableLit = p->new_ptr<TableLit_t>();
3267 tableLit->values.dup(tableBlock->values); 3268 tableLit->values.dup(tableBlock->values);
@@ -4750,6 +4751,7 @@ private:
4750 newSimpleValue->value.set(funLit); 4751 newSimpleValue->value.set(funLit);
4751 auto newExpInParens = newExp(newSimpleValue, x); 4752 auto newExpInParens = newExp(newSimpleValue, x);
4752 auto newParens = x->new_ptr<Parens_t>(); 4753 auto newParens = x->new_ptr<Parens_t>();
4754 newParens->extra = true;
4753 newParens->expr.set(newExpInParens); 4755 newParens->expr.set(newExpInParens);
4754 auto newCallable = x->new_ptr<Callable_t>(); 4756 auto newCallable = x->new_ptr<Callable_t>();
4755 newCallable->item.set(newParens); 4757 newCallable->item.set(newParens);
@@ -5570,6 +5572,7 @@ private:
5570 auto x = chainList.front(); 5572 auto x = chainList.front();
5571 if (ast_is<ExistentialOp_t>(chainList.back())) { 5573 if (ast_is<ExistentialOp_t>(chainList.back())) {
5572 auto parens = x->new_ptr<Parens_t>(); 5574 auto parens = x->new_ptr<Parens_t>();
5575 parens->extra = true;
5573 { 5576 {
5574 auto chainValue = x->new_ptr<ChainValue_t>(); 5577 auto chainValue = x->new_ptr<ChainValue_t>();
5575 for (auto item : chainList) { 5578 for (auto item : chainList) {
@@ -6163,6 +6166,7 @@ private:
6163 ++next; 6166 ++next;
6164 if (next != chainList.end()) { 6167 if (next != chainList.end()) {
6165 auto paren = x->new_ptr<Parens_t>(); 6168 auto paren = x->new_ptr<Parens_t>();
6169 paren->extra = true;
6166 paren->expr.set(newExp(chainValue, x)); 6170 paren->expr.set(newExp(chainValue, x));
6167 auto ncallable = x->new_ptr<Callable_t>(); 6171 auto ncallable = x->new_ptr<Callable_t>();
6168 ncallable->item.set(paren); 6172 ncallable->item.set(paren);
@@ -6215,6 +6219,7 @@ private:
6215 simpleValue->value.set(funLit); 6219 simpleValue->value.set(funLit);
6216 auto exp = newExp(simpleValue, x); 6220 auto exp = newExp(simpleValue, x);
6217 auto paren = x->new_ptr<Parens_t>(); 6221 auto paren = x->new_ptr<Parens_t>();
6222 paren->extra = true;
6218 paren->expr.set(exp); 6223 paren->expr.set(exp);
6219 auto callable = x->new_ptr<Callable_t>(); 6224 auto callable = x->new_ptr<Callable_t>();
6220 callable->item.set(paren); 6225 callable->item.set(paren);
@@ -6631,6 +6636,7 @@ private:
6631 exp.set(info.node); 6636 exp.set(info.node);
6632 if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) { 6637 if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) {
6633 auto paren = x->new_ptr<Parens_t>(); 6638 auto paren = x->new_ptr<Parens_t>();
6639 paren->extra = true;
6634 paren->expr.set(exp); 6640 paren->expr.set(exp);
6635 auto callable = x->new_ptr<Callable_t>(); 6641 auto callable = x->new_ptr<Callable_t>();
6636 callable->item.set(paren); 6642 callable->item.set(paren);