From 6614e3cfce63935ce1c8d0b82b465fa693370176 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Wed, 10 Jun 2026 17:05:35 -0700 Subject: [PATCH 01/10] =?UTF-8?q?Introduce=20an=20alternative=20Linux=20im?= =?UTF-8?q?plementation=20using=20`inotify`=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …that fits our feature set better than EFSW’s does and doesn’t have the complexity of recursive watching. --- binding.gyp | 5 + lib/core.cc | 2 +- lib/core.h | 7 +- lib/platform/InotifyFileWatcher.cpp | 268 ++++++++++++++++++++++++++++ lib/platform/InotifyFileWatcher.hpp | 77 ++++++++ 5 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 lib/platform/InotifyFileWatcher.cpp create mode 100644 lib/platform/InotifyFileWatcher.hpp diff --git a/binding.gyp b/binding.gyp index 058c809..6e63c06 100644 --- a/binding.gyp +++ b/binding.gyp @@ -119,6 +119,11 @@ "vendor/efsw", ], "conditions": [ + ['OS=="linux"', { + "sources+": [ + "lib/platform/InotifyFileWatcher.cpp" + ], + }], ['OS=="mac"', { "sources+": [ "lib/platform/FSEventsFileWatcher.cpp", diff --git a/lib/core.cc b/lib/core.cc index 5b93cfe..880c470 100644 --- a/lib/core.cc +++ b/lib/core.cc @@ -431,7 +431,7 @@ Napi::Value PathWatcher::Watch(const Napi::CallbackInfo &info) { listener = new PathWatcherListener(env, tsfn); -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__linux__) fileWatcher = new FileWatcher(); #else fileWatcher = new efsw::FileWatcher(); diff --git a/lib/core.h b/lib/core.h index 8db334e..3414983 100644 --- a/lib/core.h +++ b/lib/core.h @@ -17,6 +17,11 @@ typedef FSEventsFileWatcher FileWatcher; #endif // USE_KQUEUE #endif // __APPLE__ +#ifdef __linux__ +#include "./platform/InotifyFileWatcher.hpp" +typedef InotifyFileWatcher FileWatcher; +#endif // __linux__ + #ifndef _WIN32 #include #endif @@ -27,7 +32,7 @@ typedef FSEventsFileWatcher FileWatcher; #define PATH_SEPARATOR '/' #endif -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__linux__) typedef efsw::FileWatcher FileWatcher; #endif diff --git a/lib/platform/InotifyFileWatcher.cpp b/lib/platform/InotifyFileWatcher.cpp new file mode 100644 index 0000000..d8a75c7 --- /dev/null +++ b/lib/platform/InotifyFileWatcher.cpp @@ -0,0 +1,268 @@ + +#include "InotifyFileWatcher.hpp" + +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +namespace { + +// IN_CREATE/IN_DELETE/IN_MOVED_*: children appearing, disappearing, or being +// renamed within the watched directory. +// IN_MODIFY/IN_CLOSE_WRITE: content changes to children. +// IN_DELETE_SELF/IN_MOVE_SELF: the watched directory itself goes away. +constexpr uint32_t kWatchMask = IN_CREATE | IN_DELETE | IN_DELETE_SELF | + IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO | + IN_MODIFY | IN_CLOSE_WRITE; + +constexpr size_t kEventBufLen = + 64 * (sizeof(struct inotify_event) + NAME_MAX + 1); + +} // namespace + +InotifyFileWatcher::InotifyFileWatcher() { + inotifyFd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); + if (inotifyFd == -1) { + isValid = false; + return; + } + + // A pipe lets the destructor unblock poll() cleanly without signals. + if (pipe(wakeupPipe) == -1) { + close(inotifyFd); + inotifyFd = -1; + isValid = false; + return; + } + + eventThread = std::thread(&InotifyFileWatcher::eventLoop, this); +} + +InotifyFileWatcher::~InotifyFileWatcher() { + isValid = false; + stopping = true; + + // Unblock the event loop thread. + char byte = 0; + write(wakeupPipe[1], &byte, 1); + + if (eventThread.joinable()) + eventThread.join(); + + close(wakeupPipe[0]); + close(wakeupPipe[1]); + // Closing the inotify fd automatically removes all of its watches. + if (inotifyFd >= 0) + close(inotifyFd); +} + +efsw::WatchID InotifyFileWatcher::addWatch(const std::string &path, + efsw::FileWatchListener *listener, + bool /* _useRecursion */) { +#ifdef DEBUG + std::cout << "InotifyFileWatcher::addWatch: " << path << std::endl; +#endif + if (!isValid) + return efsw::Errors::WatcherFailed; + + std::string dir = path; + if (dir.empty() || dir.back() != '/') + dir += '/'; + + int wd = inotify_add_watch(inotifyFd, dir.c_str(), kWatchMask); + if (wd < 0) { + switch (errno) { + case ENOENT: + return efsw::Errors::FileNotFound; + case EACCES: + return efsw::Errors::FileNotReadable; + default: + return efsw::Errors::WatcherFailed; + } + } + + std::lock_guard lock(mapMutex); + efsw::WatchID handle = nextHandleID++; + handlesToWatches[handle] = {dir, listener, wd}; + wdToHandles.insert({wd, handle}); + return handle; +} + +void InotifyFileWatcher::removeWatch(efsw::WatchID handle) { + int wd = -1; + bool wasLastHandleForWd = false; + { + std::lock_guard lock(mapMutex); + auto it = handlesToWatches.find(handle); + if (it == handlesToWatches.end()) + return; + wd = it->second.wd; + handlesToWatches.erase(it); + + auto range = wdToHandles.equal_range(wd); + for (auto wit = range.first; wit != range.second; ++wit) { + if (wit->second == handle) { + wdToHandles.erase(wit); + break; + } + } + wasLastHandleForWd = (wdToHandles.find(wd) == wdToHandles.end()); + } + + if (wasLastHandleForWd) { + // EINVAL here just means the kernel already removed this watch (e.g. the + // directory was deleted); safe to ignore. + inotify_rm_watch(inotifyFd, wd); + } +} + +void InotifyFileWatcher::forgetWatch(int wd) { + std::lock_guard lock(mapMutex); + auto range = wdToHandles.equal_range(wd); + for (auto it = range.first; it != range.second;) { + handlesToWatches.erase(it->second); + it = wdToHandles.erase(it); + } +} + +void InotifyFileWatcher::sendFileAction(int wd, const std::string &filename, + efsw::Action action, + const std::string &oldFilename) { + // Copy out (handle, dir, listener) under the lock, then call into listener + // code without holding it. + std::vector> + targets; + { + std::lock_guard lock(mapMutex); + auto range = wdToHandles.equal_range(wd); + for (auto it = range.first; it != range.second; ++it) { + auto hit = handlesToWatches.find(it->second); + if (hit != handlesToWatches.end()) + targets.emplace_back(it->second, hit->second.dir, hit->second.listener); + } + } + + for (auto &[handle, dir, listener] : targets) + listener->handleFileAction(handle, dir, filename, action, oldFilename); +} + +void InotifyFileWatcher::eventLoop() { + char buf[kEventBufLen]; + + // State for pairing IN_MOVED_FROM with a following IN_MOVED_TO that shares + // its cookie and watch — i.e. a rename within the same directory. + bool hasPendingMove = false; + int pendingWd = -1; + uint32_t pendingCookie = 0; + std::string pendingFilename; + + auto flushPendingMove = [&]() { + if (!hasPendingMove) + return; + // No matching IN_MOVED_TO arrived: the file was moved somewhere we're not + // watching (or out of the filesystem entirely). + sendFileAction(pendingWd, pendingFilename, efsw::Actions::Delete); + hasPendingMove = false; + }; + + while (!stopping) { + struct pollfd fds[2]; + fds[0] = {inotifyFd, POLLIN, 0}; + fds[1] = {wakeupPipe[0], POLLIN, 0}; + + // If we're sitting on an unpaired IN_MOVED_FROM, don't block forever — + // give its IN_MOVED_TO a brief window to show up, then resolve it. + int timeoutMs = hasPendingMove ? 10 : -1; + + int r = poll(fds, 2, timeoutMs); + if (r < 0) { + if (errno == EINTR) + continue; + break; + } + + if (stopping || (fds[1].revents & POLLIN)) + break; + + if (r == 0) { + flushPendingMove(); + continue; + } + + if (!(fds[0].revents & POLLIN)) + continue; + + ssize_t len = read(inotifyFd, buf, sizeof(buf)); + if (len <= 0) + continue; + + ssize_t i = 0; + while (i < len) { + auto *event = reinterpret_cast(&buf[i]); + i += sizeof(struct inotify_event) + event->len; + + if (event->mask & IN_Q_OVERFLOW) + continue; + + std::string filename = event->len > 0 ? std::string(event->name) : ""; + + if (hasPendingMove) { + if ((event->mask & IN_MOVED_TO) && event->wd == pendingWd && + event->cookie == pendingCookie) { + // Same-directory rename — almost always an atomic save. + sendFileAction(event->wd, filename, efsw::Actions::Moved, + pendingFilename); + hasPendingMove = false; + continue; + } + flushPendingMove(); + // fall through and process this event normally + } + + if (event->mask & IN_IGNORED) { + // The kernel already removed this watch (explicit removeWatch, + // directory deleted, or filesystem unmounted). + forgetWatch(event->wd); + continue; + } + + if (event->mask & IN_MOVED_FROM) { + hasPendingMove = true; + pendingWd = event->wd; + pendingCookie = event->cookie; + pendingFilename = filename; + continue; + } + + if (event->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) { + // The watched directory itself is gone or has moved. Report it as a + // deletion of the directory; the caller can re-addWatch if it cares + // to keep following it (we have no way to learn its new path). + sendFileAction(event->wd, "", efsw::Actions::Delete); + continue; + } + + if (event->mask & IN_CREATE) { + sendFileAction(event->wd, filename, efsw::Actions::Add); + } else if (event->mask & IN_DELETE) { + sendFileAction(event->wd, filename, efsw::Actions::Delete); + } else if (event->mask & IN_MOVED_TO) { + // Arrived from outside this directory (or its IN_MOVED_FROM partner + // already timed out): treat it as a brand-new file. + sendFileAction(event->wd, filename, efsw::Actions::Add); + sendFileAction(event->wd, filename, efsw::Actions::Modified); + } else if (event->mask & (IN_MODIFY | IN_CLOSE_WRITE)) { + sendFileAction(event->wd, filename, efsw::Actions::Modified); + } + } + } + + flushPendingMove(); +} diff --git a/lib/platform/InotifyFileWatcher.hpp b/lib/platform/InotifyFileWatcher.hpp new file mode 100644 index 0000000..277e1e5 --- /dev/null +++ b/lib/platform/InotifyFileWatcher.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include "../../vendor/efsw/include/efsw/efsw.hpp" +#include +#include +#include +#include +#include + +// An API-compatible replacement for `efsw::FileWatcher` that talks to inotify +// directly. Plays the same role on Linux that `KqueueFileWatcher` and +// `FSEventsFileWatcher` play on macOS. +// +// Key differences from `FileWatcherInotify`: +// +// * A single `inotify` instance backs every watch; `addWatch()` just calls +// `inotify_add_watch()` against it and gets back a watch descriptor (wd). No +// per-path file descriptors, and no fd-limit juggling. +// * No recursion: the `_useRecursion` flag is ignored, and only the directory +// passed to addWatch() is watched. The existing JS layer only ever calls +// `addWatch()` with a directory path — either the directory being watched +// directly, or the parent of a watched file — so this matches how the old +// inotify backend was used in practice anyway. +// * Renames are reconstructed from `IN_MOVED_FROM`/`IN_MOVED_TO` pairs that +// share a cookie and land on the same watch. This is how editors' atomic +// saves (write tmp file, rename over target) show up, and it's reported as +// `Moved`, which the existing JS rename-handling collapses into a `change` +// event for the watched file. Cross-directory moves are reported as a Delete +// (on the source watch) plus an Add+Modified (on the destination watch), +// matching the old inotify-based behavior. +// * If the watched directory itself is removed or renamed (`IN_DELETE_SELF` / +// `IN_MOVE_SELF`), we report a single Delete for the directory. `inotify` +// gives us no way to recover the new path of a moved directory, so the +// caller must re-`addWatch` if it wants to keep following it. +// +class InotifyFileWatcher { +public: + InotifyFileWatcher(); + ~InotifyFileWatcher(); + + efsw::WatchID addWatch(const std::string &path, + efsw::FileWatchListener *listener, + bool _useRecursion = false); + + void removeWatch(efsw::WatchID handle); + + bool isValid = true; + +private: + struct Watch { + std::string dir; // always ends with '/' + efsw::FileWatchListener *listener; + int wd; + }; + + void eventLoop(); + + // Looks up every handle registered for `wd` and dispatches `action` to each + // of their listeners. + void sendFileAction(int wd, const std::string &filename, efsw::Action action, + const std::string &oldFilename = ""); + + // Drops all bookkeeping for `wd` without calling `inotify_rm_watch()`; used + // when the kernel tells us (via IN_IGNORED) that it already dropped the + // watch on its own (e.g. the directory was deleted or unmounted). + void forgetWatch(int wd); + + long nextHandleID = 1; + int inotifyFd = -1; + int wakeupPipe[2] = {-1, -1}; + std::atomic stopping{false}; + std::mutex mapMutex; + std::thread eventThread; + + std::unordered_map handlesToWatches; + std::unordered_multimap wdToHandles; +}; From b91eddfba0505986e2431c568a1648b10b1ec662 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 11 Sep 2026 10:20:59 -0700 Subject: [PATCH 02/10] Address minor issues with Linux implementaiton --- lib/platform/InotifyFileWatcher.cpp | 141 ++++++++++++++++++++++------ lib/platform/InotifyFileWatcher.hpp | 24 ++++- spec/pathwatcher-spec.js | 55 +++++++++++ 3 files changed, 188 insertions(+), 32 deletions(-) diff --git a/lib/platform/InotifyFileWatcher.cpp b/lib/platform/InotifyFileWatcher.cpp index d8a75c7..330d059 100644 --- a/lib/platform/InotifyFileWatcher.cpp +++ b/lib/platform/InotifyFileWatcher.cpp @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include #ifdef DEBUG #include @@ -49,9 +51,11 @@ InotifyFileWatcher::~InotifyFileWatcher() { isValid = false; stopping = true; - // Unblock the event loop thread. + // Unblock the event loop thread. Nothing useful to do if this fails, but + // `write` is declared `warn_unused_result`, so discard the result + // explicitly rather than let it warn. char byte = 0; - write(wakeupPipe[1], &byte, 1); + (void)write(wakeupPipe[1], &byte, 1); if (eventThread.joinable()) eventThread.join(); @@ -76,6 +80,14 @@ efsw::WatchID InotifyFileWatcher::addWatch(const std::string &path, if (dir.empty() || dir.back() != '/') dir += '/'; + // We hold `mapMutex` across the `inotify_add_watch()` call below, just as + // `removeWatch()` does for its removal. The kernel can start queueing events + // for this watch the moment it exists, and the event loop needs the same + // lock to find the listeners for a wd — so taking it first means the event + // loop waits for us to finish registering rather than reading events for a + // wd we haven't recorded yet and dropping them on the floor. + std::lock_guard lock(mapMutex); + int wd = inotify_add_watch(inotifyFd, dir.c_str(), kWatchMask); if (wd < 0) { switch (errno) { @@ -88,7 +100,6 @@ efsw::WatchID InotifyFileWatcher::addWatch(const std::string &path, } } - std::lock_guard lock(mapMutex); efsw::WatchID handle = nextHandleID++; handlesToWatches[handle] = {dir, listener, wd}; wdToHandles.insert({wd, handle}); @@ -96,35 +107,53 @@ efsw::WatchID InotifyFileWatcher::addWatch(const std::string &path, } void InotifyFileWatcher::removeWatch(efsw::WatchID handle) { - int wd = -1; - bool wasLastHandleForWd = false; - { - std::lock_guard lock(mapMutex); - auto it = handlesToWatches.find(handle); - if (it == handlesToWatches.end()) - return; - wd = it->second.wd; - handlesToWatches.erase(it); + // We hold `mapMutex` across the `inotify_rm_watch()` call below. That's + // load-bearing: it ensures we've recorded that we're expecting an + // IN_IGNORED before the event loop — which takes the same lock in + // `forgetWatch()` — can possibly read it. + std::lock_guard lock(mapMutex); + auto it = handlesToWatches.find(handle); + if (it == handlesToWatches.end()) + return; + int wd = it->second.wd; + handlesToWatches.erase(it); - auto range = wdToHandles.equal_range(wd); - for (auto wit = range.first; wit != range.second; ++wit) { - if (wit->second == handle) { - wdToHandles.erase(wit); - break; - } + auto range = wdToHandles.equal_range(wd); + for (auto wit = range.first; wit != range.second; ++wit) { + if (wit->second == handle) { + wdToHandles.erase(wit); + break; } - wasLastHandleForWd = (wdToHandles.find(wd) == wdToHandles.end()); } - if (wasLastHandleForWd) { - // EINVAL here just means the kernel already removed this watch (e.g. the - // directory was deleted); safe to ignore. - inotify_rm_watch(inotifyFd, wd); - } + // Other handles still care about this wd, so leave the kernel watch alone. + if (wdToHandles.find(wd) != wdToHandles.end()) + return; + + // Removing the watch makes the kernel queue an IN_IGNORED for this wd. Note + // that we're expecting it, so the event loop doesn't mistake it for a + // kernel-initiated removal of whatever watch holds this number by the time + // we get around to reading it. EINVAL means the kernel already dropped the + // watch on its own (e.g. the directory was deleted), in which case nothing + // new is coming from us and there's nothing to account for. + if (inotify_rm_watch(inotifyFd, wd) == 0) + pendingIgnored[wd]++; } void InotifyFileWatcher::forgetWatch(int wd) { std::lock_guard lock(mapMutex); + + auto pending = pendingIgnored.find(wd); + if (pending != pendingIgnored.end()) { + // This IN_IGNORED is the echo of our own `inotify_rm_watch()`; + // `removeWatch()` already dropped the bookkeeping. Anything registered + // under this wd now is a newer watch that reuses the number, so we leave + // it alone. + if (--pending->second <= 0) + pendingIgnored.erase(pending); + return; + } + auto range = wdToHandles.equal_range(wd); for (auto it = range.first; it != range.second;) { handlesToWatches.erase(it->second); @@ -132,6 +161,22 @@ void InotifyFileWatcher::forgetWatch(int wd) { } } +void InotifyFileWatcher::stopWatch(int wd) { + std::lock_guard lock(mapMutex); + + auto range = wdToHandles.equal_range(wd); + for (auto it = range.first; it != range.second;) { + handlesToWatches.erase(it->second); + it = wdToHandles.erase(it); + } + + // Same accounting as `removeWatch()`: the kernel queues an IN_IGNORED for + // every watch we remove, and `forgetWatch()` needs to know we asked for it. + // A failure here means the watch was already gone, so nothing is coming. + if (inotify_rm_watch(inotifyFd, wd) == 0) + pendingIgnored[wd]++; +} + void InotifyFileWatcher::sendFileAction(int wd, const std::string &filename, efsw::Action action, const std::string &oldFilename) { @@ -154,7 +199,9 @@ void InotifyFileWatcher::sendFileAction(int wd, const std::string &filename, } void InotifyFileWatcher::eventLoop() { - char buf[kEventBufLen]; + // `alignas` because we cast into this buffer to read `inotify_event`s out of + // it, and that type has stricter alignment than `char`. + alignas(struct inotify_event) char buf[kEventBufLen]; // State for pairing IN_MOVED_FROM with a following IN_MOVED_TO that shares // its cookie and watch — i.e. a rename within the same directory. @@ -185,12 +232,25 @@ void InotifyFileWatcher::eventLoop() { if (r < 0) { if (errno == EINTR) continue; + // Any other poll() failure is not something we can recover from. + isValid = false; break; } if (stopping || (fds[1].revents & POLLIN)) break; + // An error on either descriptor is fatal, and we must not `continue` past + // it: poll() reports the condition immediately and forever, ignoring our + // timeout, so looping would spin at 100% CPU without ever reading + // anything. Better to stop the thread and mark ourselves invalid, which + // makes subsequent `addWatch()` calls fail loudly instead of silently + // never delivering events. + if ((fds[0].revents | fds[1].revents) & (POLLERR | POLLHUP | POLLNVAL)) { + isValid = false; + break; + } + if (r == 0) { flushPendingMove(); continue; @@ -208,8 +268,19 @@ void InotifyFileWatcher::eventLoop() { auto *event = reinterpret_cast(&buf[i]); i += sizeof(struct inotify_event) + event->len; - if (event->mask & IN_Q_OVERFLOW) + if (event->mask & IN_Q_OVERFLOW) { + // The kernel's event queue filled up and it dropped events to make + // room. There's nothing we can do to recover them, and no way to know + // what we missed, so every watch is potentially out of sync from here + // on. Worth logging, since it's otherwise invisible and would look + // like the watcher simply stopped noticing some edits. +#ifdef DEBUG + std::cout << "InotifyFileWatcher: event queue overflowed; some events " + "were dropped by the kernel" + << std::endl; +#endif continue; + } std::string filename = event->len > 0 ? std::string(event->name) : ""; @@ -227,8 +298,9 @@ void InotifyFileWatcher::eventLoop() { } if (event->mask & IN_IGNORED) { - // The kernel already removed this watch (explicit removeWatch, - // directory deleted, or filesystem unmounted). + // The watch is gone: either we removed it ourselves, or the kernel + // dropped it (directory deleted, filesystem unmounted). + // `forgetWatch` tells those two cases apart. forgetWatch(event->wd); continue; } @@ -245,7 +317,20 @@ void InotifyFileWatcher::eventLoop() { // The watched directory itself is gone or has moved. Report it as a // deletion of the directory; the caller can re-addWatch if it cares // to keep following it (we have no way to learn its new path). + // + // This must happen before any teardown below, since `sendFileAction` + // finds its listeners by looking up `wd` in our bookkeeping. sendFileAction(event->wd, "", efsw::Actions::Delete); + + if (event->mask & IN_MOVE_SELF) { + // Unlike a deletion, a move leaves the watch alive — the directory + // still exists, just somewhere else — and the kernel sends no + // IN_IGNORED. Left alone, it would keep reporting events for the + // directory's children under the stale path we recorded in + // `Watch::dir`. We've just told the caller the directory is gone, + // so make that true and shut the watch down. + stopWatch(event->wd); + } continue; } diff --git a/lib/platform/InotifyFileWatcher.hpp b/lib/platform/InotifyFileWatcher.hpp index 277e1e5..f96da96 100644 --- a/lib/platform/InotifyFileWatcher.hpp +++ b/lib/platform/InotifyFileWatcher.hpp @@ -44,7 +44,10 @@ class InotifyFileWatcher { void removeWatch(efsw::WatchID handle); - bool isValid = true; + // Atomic because the event loop thread clears it when it hits an + // unrecoverable poll() error, while `addWatch()` reads it on the main + // thread. + std::atomic isValid{true}; private: struct Watch { @@ -60,11 +63,19 @@ class InotifyFileWatcher { void sendFileAction(int wd, const std::string &filename, efsw::Action action, const std::string &oldFilename = ""); - // Drops all bookkeeping for `wd` without calling `inotify_rm_watch()`; used - // when the kernel tells us (via IN_IGNORED) that it already dropped the - // watch on its own (e.g. the directory was deleted or unmounted). + // Responds to an IN_IGNORED for `wd`. If we provoked it ourselves by + // calling `inotify_rm_watch()`, it's already accounted for and we do + // nothing. Otherwise the kernel dropped the watch on its own (e.g. the + // directory was deleted or unmounted), so we drop all bookkeeping for `wd`. void forgetWatch(int wd); + // Tears down a watch that the kernel is still holding open, dropping all + // bookkeeping for `wd` and telling the kernel to stop watching. Used when + // the watched directory moves (IN_MOVE_SELF): the watch survives the move, + // but it would report every subsequent event under the directory's old, + // now-wrong path, so we shut it down instead. + void stopWatch(int wd); + long nextHandleID = 1; int inotifyFd = -1; int wakeupPipe[2] = {-1, -1}; @@ -74,4 +85,9 @@ class InotifyFileWatcher { std::unordered_map handlesToWatches; std::unordered_multimap wdToHandles; + + // wd -> number of IN_IGNORED events we've asked the kernel for (via + // `inotify_rm_watch()`) but haven't read yet. Lets the event loop tell our + // own removals apart from kernel-initiated ones. + std::unordered_map pendingIgnored; }; diff --git a/spec/pathwatcher-spec.js b/spec/pathwatcher-spec.js index 05f45b0..bed3010 100644 --- a/spec/pathwatcher-spec.js +++ b/spec/pathwatcher-spec.js @@ -197,6 +197,61 @@ describe('PathWatcher', () => { }); } + // Once the directory containing a watched file is renamed away, the file we + // were asked to watch no longer exists at the path we were asked to watch. + // Writes to the file at its new location should not be reported as changes + // to the old path. This should hold on every platform, so this block also + // serves to keep the backends in agreement with each other. + // + // Linux got this wrong: we watch a file there by watching its parent + // directory, and `inotify` watches that directory itself rather than its + // name. A rename leaves the watch alive — the directory still exists, just + // somewhere else — while giving us no way to learn its new path, so the + // watch went on reporting events under the path the directory had when we + // started watching it. + describe('when the parent directory of a watched file is renamed', () => { + let movedDir; + + afterEach(() => { + if (movedDir && fs.existsSync(movedDir)) { + fs.rmSync(movedDir, { recursive: true }); + } + movedDir = null; + }); + + it('stops reporting changes against the old path', async () => { + let subDir = path.join(tempDir, 'renamed-parent'); + fs.mkdirSync(subDir); + let watchedFile = path.join(subDir, 'file'); + fs.writeFileSync(watchedFile, ''); + + let spy = jasmine.createSpy('spy'); + PathWatcher.watch(watchedFile, spy); + await wait(20); + + // First prove that the watcher works at all, so that the assertion at + // the end can't pass merely because we set something up wrong. + fs.writeFileSync(watchedFile, 'changed'); + await condition(() => spy.calls.count() > 0); + expect(spy).toHaveBeenCalledWith('change', ''); + + // Now rename the directory that contains the file we're watching. + movedDir = path.join(tempDir, 'renamed-parent-moved'); + fs.renameSync(subDir, movedDir); + await wait(200); + + spy.calls.reset(); + + // A write to the file at its _new_ path must not be reported as a change + // to the old one. + fs.writeFileSync(path.join(movedDir, 'file'), 'changed again'); + await wait(200); + + expect(fs.existsSync(watchedFile)).toBe(false); + expect(spy).not.toHaveBeenCalled(); + }); + }); + describe('when a file under a watched directory is deleted', () => { it('fires the callback with the change event and empty path', async () => { let fileUnderDir = path.join(tempDir, 'file'); From fe573fbd9c8b46f1d399ac23f8bf248ad8b8f729 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 11 Sep 2026 10:24:41 -0700 Subject: [PATCH 03/10] Point to `windows-2022` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 918017d..4439645 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: os: - ubuntu-latest - macos-latest - - windows-latest + - windows-2022 node_version: # - 14 # - 18 From 3737f096f27247ae598b78c66dd734e27e7adaaf Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 11 Sep 2026 10:55:45 -0700 Subject: [PATCH 04/10] Get Windows to pass the new spec --- vendor/efsw/src/efsw/WatcherWin32.cpp | 44 +++++++++++++++++++++++++++ vendor/efsw/src/efsw/WatcherWin32.hpp | 6 ++++ 2 files changed, 50 insertions(+) diff --git a/vendor/efsw/src/efsw/WatcherWin32.cpp b/vendor/efsw/src/efsw/WatcherWin32.cpp index 712419e..957f987 100644 --- a/vendor/efsw/src/efsw/WatcherWin32.cpp +++ b/vendor/efsw/src/efsw/WatcherWin32.cpp @@ -51,6 +51,34 @@ static void initReadDirectoryChangesEx() { } } +/// PULSAR PATCH: Returns the path that `handle` currently resolves to, or an +/// empty string if it can't be determined — which includes the case where the +/// directory has been deleted. Not part of upstream efsw. +static std::wstring GetHandlePath( HANDLE handle ) { + if ( NULL == handle || INVALID_HANDLE_VALUE == handle ) + return std::wstring(); + + // Called with a NULL buffer, this returns the length required *including* + // the null terminator; called with a buffer, it returns the number of + // characters written *excluding* it. + DWORD len = + GetFinalPathNameByHandleW( handle, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS ); + + if ( 0 == len ) + return std::wstring(); + + std::wstring path( len, L'\0' ); + + DWORD written = GetFinalPathNameByHandleW( handle, &path[0], len, + FILE_NAME_NORMALIZED | VOLUME_NAME_DOS ); + + if ( 0 == written || written >= len ) + return std::wstring(); + + path.resize( written ); + return path; +} + void WatchCallbackOld( WatcherWin32* pWatch ) { PFILE_NOTIFY_INFORMATION pNotify; size_t offset = 0; @@ -160,6 +188,19 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; WatcherWin32* pWatch = tWatch->Watch; + // PULSAR PATCH: The directory handle stays valid when the directory is + // renamed or moved, so the watch keeps reporting changes to its children — + // but every path we report is rebuilt from the directory path we were given + // at watch time. Once the handle resolves somewhere else, every path we'd + // emit names a file that isn't there. Stop the watch instead: returning + // without reaching `RefreshWatch` below leaves it un-rearmed, so it goes + // quiet for good. The handle is released later, when the watch is removed. + if ( NULL != pWatch && !pWatch->CanonicalPath.empty() && + pWatch->CanonicalPath != GetHandlePath( pWatch->DirHandle ) ) { + pWatch->StopNow = true; + return; + } + if ( dwNumberOfBytesTransfered == 0 ) { if ( nullptr != pWatch && !pWatch->StopNow ) { RefreshWatch( tWatch ); @@ -246,6 +287,9 @@ WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { pWatch->NotifyFilter = notifyFilter; pWatch->Recursive = recursive; + // PULSAR PATCH: remember where this handle points now, so `WatchCallback` + // can notice later if the directory has been moved out from under it. + pWatch->CanonicalPath = GetHandlePath( pWatch->DirHandle ); if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) { return tWatch; diff --git a/vendor/efsw/src/efsw/WatcherWin32.hpp b/vendor/efsw/src/efsw/WatcherWin32.hpp index ea1e8e4..08da867 100644 --- a/vendor/efsw/src/efsw/WatcherWin32.hpp +++ b/vendor/efsw/src/efsw/WatcherWin32.hpp @@ -61,6 +61,12 @@ class WatcherWin32 : public Watcher { WatcherStructWin32* Struct; HANDLE DirHandle; + // PULSAR PATCH: the path `DirHandle` resolved to when the watch was + // created, as reported by `GetFinalPathNameByHandleW`. Compared against the + // handle's current path on each completion so that we can detect when the + // watched directory is renamed or moved out from under us. Not part of + // upstream efsw; see `WatchCallback`. + std::wstring CanonicalPath; std::vector Buffer; LPARAM lParam; DWORD NotifyFilter; From 5af96c8b94e97985056b13e2ead51d61d6311a3e Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 11 Sep 2026 11:43:59 -0700 Subject: [PATCH 05/10] Update README for accuracy --- README.md | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 457fe2e..ad64f2a 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,9 @@ Watch files and directories for changes. > [!IMPORTANT] -> This library is used in [Pulsar][] in several places for compatibility reasons. The [nsfw](https://www.npmjs.com/package/nsfw) library is more robust and more widely used; it is available in Pulsar via `atom.watchPath` and is usually a better choice. +> This library is used in [Pulsar][] in several places for compatibility reasons. If you’re here because you want a general-purpose file-watching library for Node, use `nsfw` or `@parcel/watcher` instead. > -> If you’re here because you want a general-purpose file-watching library for Node, use `nsfw` instead. -> -> The purpose of this library’s continued inclusion in Pulsar is to provide the [File][] and [Directory][] classes that have long been available as exports via `require('atom')`. +> The purpose of this library’s continued inclusion in Pulsar is to provide the [File][] and [Directory][] classes that have long been available as exports via `require('atom')`. It also delivers reliable file-watching on macOS on volumes that `FSEvents` cannot support (i.e., network volumes and drives that use incompatible filesystems). ## Installing @@ -29,10 +27,12 @@ This module is context-aware and context-safe; it can be used from multiple work If you’re using it in an Electron renderer process, you must take extra care in page reloading scenarios. Be sure to use `closeAllWatchers` well before the page environment is terminated — e.g., by attaching a `beforeunload` listener. +Be sure to read the more specific file-watching caveats below. + ## Using ```js -const PathWatcher = require('pathwatcher'); +const { watch, closeAllWatchers, getWatchedPaths } = require('pathwatcher'); ``` ### `watch(filename, listener)` @@ -47,14 +47,11 @@ Returns an instance of `PathWatcher`. This instance is useful primarily for the #### Caveats -* Watching a specific file or directory will not notify you when that file or directory is created, since the file must already exist before you start watching the path. +* All watching is **non-recursive**. If you watch `/foo/bar`, you will be notified about a change to `/foo/bar/index.js`, or the creation of the directory `/foo/bar/baz`; but you will not be told about a change to `/foo/bar/baz/something.js`. +* You may not watch a nonexistent path. Thus watching a specific file or directory can never notify you when that file or directory is created. * When watching a file, `event` can be any of `rename`, `delete`, or `change`, where `change` means that the file’s contents changed somehow. -* When watching a directory, `event` can only be `change`, and in this context `change` signifies that one or more of the directory’s children changed (by being renamed, deleted, added, or modified). -* A watched directory will not report when it is renamed or deleted. If you want to detect when a given directory is deleted, watch its parent directory and test for the child directory’s existence when you receive a `change` event. - -### `PathWatcher::close()` - -Stop watching for changes on the given `PathWatcher`. +* When watching a directory, `event` can **only** be `change`, and in this context `change` signifies that one or more of the directory’s children changed (by being renamed, deleted, added, or modified). +* A watched directory will not report when it is renamed or deleted; it will simply stop reporting events. If you want to detect when a given directory is renamed or deleted, watch its parent directory and test for the child directory’s existence when you receive a `change` event. (But if the parent directory itself can possibly be renamed or deleted, you’re in a pickle! This scenario is better suited to a recursive watcher.) ### `closeAllWatchers()` @@ -62,9 +59,16 @@ Stop watching on all subscribed paths. All existing `PathWatcher` instances wil ### `getWatchedPaths()` -Returns an array of strings representing the actual paths that are being watched on disk. +Returns an array of strings representing the **actual paths** that are being watched on disk. -`pathwatcher` watches directories in all instances, since it’s easy to do so in a cross-platform manner. +These paths may not correlate to the paths that a consumer asked to watch for two reasons: + +* Some platforms, when asked to watch `/foo/bar.js`, watch `/foo` instead. This allows for watcher reuse in some scenarios and would explain why the number of watched paths may not correlate to the number of active watchers. +* `pathwatcher` does `realpath` resolution and watches at a path’s canonical location on disk — which may or may not match the path you asked to watch. + +### `PathWatcher::close()` + +Stop watching for changes on the given `PathWatcher`. ### `File` and `Directory` From bbb9d50d08a97ab7bdcb3f4dc590d7689b8ae506 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 11 Sep 2026 12:05:59 -0700 Subject: [PATCH 06/10] Add an extra atomic-save spec for safety --- spec/pathwatcher-spec.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spec/pathwatcher-spec.js b/spec/pathwatcher-spec.js index bed3010..1d56f03 100644 --- a/spec/pathwatcher-spec.js +++ b/spec/pathwatcher-spec.js @@ -40,6 +40,38 @@ describe('PathWatcher', () => { expect(eventType).toBe('change'); expect(eventPath).toBe(''); }); + + it('keeps watching the file that replaced the original', async () => { + // An atomic save doesn't modify the watched file; it replaces it with a + // different one. Platforms that watch the file itself (rather than its + // parent directory) therefore have to notice this and re-attach to + // whatever now lives at that path — otherwise the save gets reported and + // nothing ever is again. + let spy = jasmine.createSpy('spy'); + PathWatcher.watch(tempFile, spy); + + await wait(20); + + let tempFileCopy = path.join(tempDir, 'file-copy'); + fs.writeFileSync(tempFileCopy, 'atomic save content'); + fs.renameSync(tempFileCopy, tempFile); + + await condition(() => spy.calls.count() > 0); + expect(spy).toHaveBeenCalledWith('change', ''); + + // Let any further events from the save itself land before we reset, so + // that a straggler can't be mistaken for the event we're about to + // provoke. + await wait(200); + spy.calls.reset(); + + // The real test: an ordinary write to the file that now occupies the + // watched path must still be reported. + fs.writeFileSync(tempFile, 'subsequent change'); + + await condition(() => spy.calls.count() > 0); + expect(spy).toHaveBeenCalledWith('change', ''); + }); }); describe('getWatchedPaths', () => { From 584ac46ee2642605e97e9a1034b0a447ecb5238b Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Fri, 25 Sep 2026 15:19:00 -0700 Subject: [PATCH 07/10] Experiment with a custom Windows adapter --- binding.gyp | 3 + lib/core.cc | 6 - lib/core.h | 9 +- .../ReadDirectoryChangesFileWatcher.cpp | 508 ++++++++++++++++++ .../ReadDirectoryChangesFileWatcher.hpp | 110 ++++ 5 files changed, 626 insertions(+), 10 deletions(-) create mode 100644 lib/platform/ReadDirectoryChangesFileWatcher.cpp create mode 100644 lib/platform/ReadDirectoryChangesFileWatcher.hpp diff --git a/binding.gyp b/binding.gyp index 6e63c06..e5a25b1 100644 --- a/binding.gyp +++ b/binding.gyp @@ -134,6 +134,9 @@ ] }], ['OS=="win"', { + "sources+": [ + "lib/platform/ReadDirectoryChangesFileWatcher.cpp" + ], 'msvs_settings': { 'VCCLCompilerTool': { 'ExceptionHandling': 1, # /EHsc diff --git a/lib/core.cc b/lib/core.cc index 880c470..a44ad6d 100644 --- a/lib/core.cc +++ b/lib/core.cc @@ -431,13 +431,7 @@ Napi::Value PathWatcher::Watch(const Napi::CallbackInfo &info) { listener = new PathWatcherListener(env, tsfn); -#if defined(__APPLE__) || defined(__linux__) fileWatcher = new FileWatcher(); -#else - fileWatcher = new efsw::FileWatcher(); - fileWatcher->followSymlinks(true); - fileWatcher->watch(); -#endif isWatching = true; } diff --git a/lib/core.h b/lib/core.h index 3414983..2d660d4 100644 --- a/lib/core.h +++ b/lib/core.h @@ -22,6 +22,11 @@ typedef FSEventsFileWatcher FileWatcher; typedef InotifyFileWatcher FileWatcher; #endif // __linux__ +#ifdef _WIN32 +#include "./platform/ReadDirectoryChangesFileWatcher.hpp" +typedef ReadDirectoryChangesFileWatcher FileWatcher; +#endif // _WIN32 + #ifndef _WIN32 #include #endif @@ -32,10 +37,6 @@ typedef InotifyFileWatcher FileWatcher; #define PATH_SEPARATOR '/' #endif -#if !defined(__APPLE__) && !defined(__linux__) -typedef efsw::FileWatcher FileWatcher; -#endif - typedef efsw::WatchID WatcherHandle; #ifdef _WIN32 diff --git a/lib/platform/ReadDirectoryChangesFileWatcher.cpp b/lib/platform/ReadDirectoryChangesFileWatcher.cpp new file mode 100644 index 0000000..05f77b0 --- /dev/null +++ b/lib/platform/ReadDirectoryChangesFileWatcher.cpp @@ -0,0 +1,508 @@ +#include "ReadDirectoryChangesFileWatcher.hpp" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include + +#include +#include + +#ifdef DEBUG +#include +#endif + +namespace { + +// Children appearing, disappearing, being renamed, or having their contents +// changed. We don't ask for attribute, security, or last-access changes. +constexpr DWORD kNotifyFilter = + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_SIZE; + +// Must stay under 64KB: `ReadDirectoryChangesW` fails with +// `ERROR_INVALID_PARAMETER` for larger buffers when the directory is on a +// network share. +constexpr DWORD kBufferBytes = 63 * 1024; + +std::wstring Utf8ToWide(const std::string &str) { + if (str.empty()) + return std::wstring(); + int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), + nullptr, 0); + if (len <= 0) + return std::wstring(); + std::wstring result(len, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &result[0], + len); + return result; +} + +std::string WideToUtf8(const wchar_t *str, size_t length) { + if (length == 0) + return std::string(); + int len = WideCharToMultiByte(CP_UTF8, 0, str, (int)length, nullptr, 0, + nullptr, nullptr); + if (len <= 0) + return std::string(); + std::string result(len, '\0'); + WideCharToMultiByte(CP_UTF8, 0, str, (int)length, &result[0], len, nullptr, + nullptr); + return result; +} + +// Converts a UTF-8 path to a wide path that Win32 file APIs will accept at any +// length. Past a certain length they need the `\\?\` prefix, which in turn +// means the path must be absolute and use only backslashes. +std::wstring ToWidePath(const std::string &path) { + std::wstring wide = Utf8ToWide(path); + // `CreateFileW` on a directory tops out 12 characters short of `MAX_PATH`, + // leaving room for an 8.3 filename. + if (wide.size() < MAX_PATH - 12 || wide.rfind(L"\\\\?\\", 0) == 0) + return wide; + + for (auto &ch : wide) { + if (ch == L'/') + ch = L'\\'; + } + + if (wide.size() >= 3 && wide[1] == L':' && wide[2] == L'\\') + return L"\\\\?\\" + wide; + if (wide.rfind(L"\\\\", 0) == 0) + return L"\\\\?\\UNC\\" + wide.substr(2); + return wide; +} + +// Returns the path that `handle` currently resolves to, or an empty string if +// it can't be determined — which includes the case where the directory has +// been deleted. +std::wstring GetHandlePath(HANDLE handle) { + if (handle == nullptr || handle == INVALID_HANDLE_VALUE) + return std::wstring(); + + // Called with a null buffer, this returns the length required *including* + // the null terminator; called with a buffer, it returns the number of + // characters written *excluding* it. + DWORD len = GetFinalPathNameByHandleW(handle, nullptr, 0, + FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + if (len == 0) + return std::wstring(); + + std::wstring path(len, L'\0'); + DWORD written = GetFinalPathNameByHandleW( + handle, &path[0], len, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + if (written == 0 || written >= len) + return std::wstring(); + + path.resize(written); + return path; +} + +} // namespace + +// A file action waiting to be delivered to a listener. We gather these while +// holding `mapMutex` and deliver them after releasing it. +struct ReadDirectoryChangesFileWatcher::Event { + efsw::FileWatchListener *listener; + efsw::WatchID handle; + std::string dir; + std::string filename; + efsw::Action action; + std::string oldFilename; +}; + +struct ReadDirectoryChangesFileWatcher::Watch { + // The kernel writes into `overlapped` and `buffer` when an operation + // completes, so neither may be freed while `inFlight` is true. See + // `retire()`. + OVERLAPPED overlapped{}; + // `DWORD` elements because `ReadDirectoryChangesW` requires a DWORD-aligned + // buffer. + std::vector buffer = std::vector(kBufferBytes / sizeof(DWORD)); + + HANDLE dirHandle = INVALID_HANDLE_VALUE; + efsw::WatchID handle = 0; + std::string dir; // UTF-8; always ends with '\\' + efsw::FileWatchListener *listener = nullptr; + + // The path `dirHandle` resolved to when the watch was created. We compare + // it against the handle's current path on each completion so that we can + // tell when the directory has been renamed or moved out from under us. + std::wstring canonicalPath; + + // Whether a `ReadDirectoryChangesW` is outstanding. + bool inFlight = false; + // Whether `removeWatch()` has given this watch up. A retired watch that's + // still in flight is freed by the completion thread. + bool retired = false; + + // The first half of a rename, waiting for its `RENAMED_NEW_NAME` partner. + bool hasPendingOldName = false; + std::string pendingOldName; + + // The most recent `Modified` we reported, along with the file's last-write + // time and size at that moment. Windows tends to report a single write as + // several `FILE_ACTION_MODIFIED`s (one for the data, one for the metadata), + // and this lets us collapse them. + bool hasLastModified = false; + std::string lastModifiedName; + ULONGLONG lastModifiedTime = 0; + ULONGLONG lastModifiedSize = 0; + + bool isDuplicateModification(const std::string &filename) { + ULONGLONG time = 0; + ULONGLONG size = 0; + WIN32_FILE_ATTRIBUTE_DATA data; + if (GetFileAttributesExW(ToWidePath(dir + filename).c_str(), + GetFileExInfoStandard, &data)) { + time = ((ULONGLONG)data.ftLastWriteTime.dwHighDateTime << 32) | + data.ftLastWriteTime.dwLowDateTime; + size = ((ULONGLONG)data.nFileSizeHigh << 32) | data.nFileSizeLow; + } + + bool isDuplicate = hasLastModified && lastModifiedName == filename && + lastModifiedTime == time && lastModifiedSize == size; + + hasLastModified = true; + lastModifiedName = filename; + lastModifiedTime = time; + lastModifiedSize = size; + return isDuplicate; + } + + // Translates one `FILE_NOTIFY_INFORMATION` record into zero or more events. + void translate(DWORD action, const std::string &filename, + std::vector &events) { + auto emit = [&](const std::string &name, efsw::Action fwAction, + const std::string &oldName = "") { + events.push_back({listener, handle, dir, name, fwAction, oldName}); + }; + + switch (action) { + case FILE_ACTION_ADDED: + emit(filename, efsw::Actions::Add); + break; + case FILE_ACTION_REMOVED: + emit(filename, efsw::Actions::Delete); + break; + case FILE_ACTION_MODIFIED: + if (!isDuplicateModification(filename)) + emit(filename, efsw::Actions::Modified); + break; + case FILE_ACTION_RENAMED_OLD_NAME: + // Hold on to this until its partner arrives. A rename out of the + // watched directory shows up as `FILE_ACTION_REMOVED` rather than as an + // unpaired old name, so in practice every old name gets a partner. + hasPendingOldName = true; + pendingOldName = filename; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + if (hasPendingOldName) { + // A rename within the watched directory — often an atomic save. + emit(filename, efsw::Actions::Moved, pendingOldName); + hasPendingOldName = false; + } else { + emit(filename, efsw::Actions::Add); + } + break; + default: + break; + } + } +}; + +ReadDirectoryChangesFileWatcher::ReadDirectoryChangesFileWatcher() { + iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1); + if (iocp == nullptr) { + isValid = false; + return; + } + + completionThread = + std::thread(&ReadDirectoryChangesFileWatcher::completionLoop, this); +} + +ReadDirectoryChangesFileWatcher::~ReadDirectoryChangesFileWatcher() { + isValid = false; + if (iocp == nullptr) + return; + + { + std::lock_guard lock(mapMutex); + for (auto &entry : handlesToWatches) + retire(entry.second); + handlesToWatches.clear(); + stopping = true; + } + + // Every watch we just retired will produce a completion packet that wakes + // the completion thread. But if nothing was in flight, the thread is + // blocked with nothing coming, so wake it ourselves. + PostQueuedCompletionStatus((HANDLE)iocp, 0, 0, nullptr); + + if (completionThread.joinable()) + completionThread.join(); + + // Ordinarily `retiredWatches` is empty by now: the completion thread + // doesn't exit until every operation has completed. If the completion port + // failed and the thread exited early, then anything left in it may still + // have an operation the kernel will complete someday, so we leak it rather + // than free memory the kernel might write to. + CloseHandle((HANDLE)iocp); +} + +efsw::WatchID +ReadDirectoryChangesFileWatcher::addWatch(const std::string &path, + efsw::FileWatchListener *listener, + bool /* _useRecursion */) { +#ifdef DEBUG + std::cout << "ReadDirectoryChangesFileWatcher::addWatch: " << path + << std::endl; +#endif + if (!isValid) + return efsw::Errors::WatcherFailed; + + std::wstring widePath = ToWidePath(path); + + DWORD attributes = GetFileAttributesW(widePath.c_str()); + if (attributes == INVALID_FILE_ATTRIBUTES) { + return GetLastError() == ERROR_ACCESS_DENIED + ? efsw::Errors::FileNotReadable + : efsw::Errors::FileNotFound; + } + if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) + return efsw::Errors::FileNotFound; + + // `FILE_SHARE_DELETE` so that we don't prevent anyone from renaming or + // deleting the directory we're watching. + HANDLE dirHandle = CreateFileW( + widePath.c_str(), FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + nullptr); + if (dirHandle == INVALID_HANDLE_VALUE) { + switch (GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return efsw::Errors::FileNotFound; + case ERROR_ACCESS_DENIED: + return efsw::Errors::FileNotReadable; + default: + return efsw::Errors::WatcherFailed; + } + } + + Watch *watch = new Watch(); + watch->dirHandle = dirHandle; + watch->listener = listener; + watch->dir = path; + if (watch->dir.empty() || watch->dir.back() != '\\') + watch->dir += '\\'; + watch->canonicalPath = GetHandlePath(dirHandle); + + // The completion key is the watch itself. That's safe to dereference when a + // packet arrives, because a watch is never freed while an operation is in + // flight — and every packet corresponds to an operation. + if (CreateIoCompletionPort(dirHandle, (HANDLE)iocp, + reinterpret_cast(watch), + 0) == nullptr) { + destroy(watch); + return efsw::Errors::WatcherFailed; + } + + // We hold `mapMutex` while arming the watch so that, if a completion packet + // arrives immediately, the completion thread can't process it until we've + // finished registering the watch. + std::lock_guard lock(mapMutex); + + if (!arm(watch)) { + destroy(watch); + return efsw::Errors::WatcherFailed; + } + + watch->handle = nextHandleID++; + handlesToWatches[watch->handle] = watch; + return watch->handle; +} + +void ReadDirectoryChangesFileWatcher::removeWatch(efsw::WatchID handle) { + std::lock_guard lock(mapMutex); + auto it = handlesToWatches.find(handle); + if (it == handlesToWatches.end()) + return; + Watch *watch = it->second; + handlesToWatches.erase(it); + retire(watch); +} + +bool ReadDirectoryChangesFileWatcher::arm(Watch *watch) { + watch->overlapped = OVERLAPPED{}; + BOOL ok = ReadDirectoryChangesW(watch->dirHandle, watch->buffer.data(), + kBufferBytes, FALSE, kNotifyFilter, nullptr, + &watch->overlapped, nullptr); + if (!ok) { +#ifdef DEBUG + std::cout << "ReadDirectoryChangesFileWatcher: couldn't arm watch for " + << watch->dir << " (error " << GetLastError() << ")" + << std::endl; +#endif + return false; + } + + watch->inFlight = true; + operationsInFlight++; + return true; +} + +void ReadDirectoryChangesFileWatcher::goDormant(Watch *watch) { + if (watch->dirHandle != INVALID_HANDLE_VALUE) { + CloseHandle(watch->dirHandle); + watch->dirHandle = INVALID_HANDLE_VALUE; + } +} + +void ReadDirectoryChangesFileWatcher::retire(Watch *watch) { + if (!watch->inFlight) { + destroy(watch); + return; + } + + watch->retired = true; + retiredWatches.insert(watch); + + // This only *requests* cancellation. The operation completes some time + // later, and its completion packet is how we learn that the kernel is done + // with `watch`. If the operation has already completed, this fails with + // `ERROR_NOT_FOUND` — but then its packet is already queued, so the outcome + // is the same. + CancelIoEx(watch->dirHandle, &watch->overlapped); +} + +void ReadDirectoryChangesFileWatcher::destroy(Watch *watch) { + if (watch->dirHandle != INVALID_HANDLE_VALUE) + CloseHandle(watch->dirHandle); + delete watch; +} + +void ReadDirectoryChangesFileWatcher::completionLoop() { + for (;;) { + { + std::lock_guard lock(mapMutex); + if (stopping && operationsInFlight == 0) + break; + } + + DWORD bytes = 0; + ULONG_PTR key = 0; + OVERLAPPED *overlapped = nullptr; + BOOL ok = GetQueuedCompletionStatus((HANDLE)iocp, &bytes, &key, + &overlapped, INFINITE); + DWORD error = ok ? ERROR_SUCCESS : GetLastError(); + + if (overlapped == nullptr) { + if (!ok) { + // The completion port itself has failed, so nothing more will arrive. + isValid = false; + break; + } + // A wakeup from the destructor. + continue; + } + + Watch *watch = reinterpret_cast(key); + std::vector events; + { + std::lock_guard lock(mapMutex); + operationsInFlight--; + watch->inFlight = false; + + if (watch->retired) { + // This is the final packet for a watch that `removeWatch()` gave up; + // the kernel is done with it, so now we can free it. + retiredWatches.erase(watch); + destroy(watch); + continue; + } + + handleCompletion(watch, ok != FALSE, bytes, error, events); + } + + // Deliver events without holding the lock. Everything we need has been + // copied into `events`: once we release the lock, `removeWatch()` may + // free `watch`. + for (auto &event : events) { + event.listener->handleFileAction(event.handle, event.dir, event.filename, + event.action, event.oldFilename); + } + } +} + +void ReadDirectoryChangesFileWatcher::handleCompletion( + Watch *watch, bool succeeded, unsigned long bytes, unsigned long error, + std::vector &events) { + if (!succeeded) { + if (error == ERROR_NOTIFY_ENUM_DIR) { + // Too many changes to fit in the buffer; they're lost. Keep watching. + if (!arm(watch)) + goDormant(watch); + return; + } + // Most likely `ERROR_ACCESS_DENIED`, meaning the directory has been + // deleted. Nothing more will arrive, so let go of the directory; holding + // it open would keep its deletion pending. +#ifdef DEBUG + std::cout << "ReadDirectoryChangesFileWatcher: watch for " << watch->dir + << " failed (error " << error << ")" << std::endl; +#endif + goDormant(watch); + return; + } + + // The directory handle stays valid when the directory is renamed or moved, + // so we'd keep hearing about changes to its children — but every path we + // report is built from the directory's original location. Once the handle + // resolves somewhere else, those paths would name files that aren't there, + // so we stop watching instead. + if (!watch->canonicalPath.empty() && + watch->canonicalPath != GetHandlePath(watch->dirHandle)) { + goDormant(watch); + return; + } + + if (bytes == 0) { + // The buffer overflowed and the kernel discarded its contents. There's + // nothing to parse, and no way to know what we missed. Keep watching. + if (!arm(watch)) + goDormant(watch); + return; + } + + // Parse everything out of the buffer before re-arming, since re-arming + // hands the buffer back to the kernel. + const BYTE *base = reinterpret_cast(watch->buffer.data()); + const size_t headerBytes = offsetof(FILE_NOTIFY_INFORMATION, FileName); + size_t offset = 0; + for (;;) { + if (offset + headerBytes > bytes) + break; + auto *info = + reinterpret_cast(base + offset); + if (offset + headerBytes + info->FileNameLength > bytes) + break; + + std::string filename = + WideToUtf8(info->FileName, info->FileNameLength / sizeof(WCHAR)); + watch->translate(info->Action, filename, events); + + if (info->NextEntryOffset == 0) + break; + offset += info->NextEntryOffset; + } + + if (!arm(watch)) + goDormant(watch); +} diff --git a/lib/platform/ReadDirectoryChangesFileWatcher.hpp b/lib/platform/ReadDirectoryChangesFileWatcher.hpp new file mode 100644 index 0000000..2fe5d4d --- /dev/null +++ b/lib/platform/ReadDirectoryChangesFileWatcher.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include "../../vendor/efsw/include/efsw/efsw.hpp" +#include +#include +#include +#include +#include +#include +#include + +// An API-compatible replacement for `efsw::FileWatcher` that talks to +// `ReadDirectoryChangesW` directly. Plays the same role on Windows that +// `InotifyFileWatcher` plays on Linux. +// +// Key differences from `FileWatcherWin32`: +// +// * Ownership of in-flight I/O. Every live watch has a +// `ReadDirectoryChangesW` outstanding, and the kernel writes into that +// watch's `OVERLAPPED` and buffer when the operation completes — including +// when it completes because we cancelled it. `CancelIoEx` doesn't wait for +// that to happen. So `removeWatch()` never frees a watch with an operation +// in flight: it cancels the operation and leaves the watch for the +// completion thread, which frees it once it dequeues the final completion +// packet. (efsw freed it immediately, and the kernel's write of +// `STATUS_CANCELLED` would land in whatever had since been allocated there.) +// * No recursion: the `_useRecursion` flag is ignored, and only the directory +// passed to `addWatch()` is watched. The JS layer only ever watches a +// directory — either the one it cares about, or the parent of a watched +// file. +// * Renames within the watched directory arrive as a `RENAMED_OLD_NAME` / +// `RENAMED_NEW_NAME` pair and are reported as `Moved`. A `RENAMED_NEW_NAME` +// with no partner (something moved in from elsewhere) is reported as `Add`; +// something moved out of the directory arrives as `REMOVED`. This matches +// what efsw reported. +// * If the watched directory is renamed or moved, the watch stops quietly: +// every path it reported would be built from the directory's old location. +// If the directory is deleted, the watch likewise goes dormant. Either way, +// the caller still owns the handle and should `removeWatch()` it. +// +class ReadDirectoryChangesFileWatcher { +public: + ReadDirectoryChangesFileWatcher(); + ~ReadDirectoryChangesFileWatcher(); + + efsw::WatchID addWatch(const std::string &path, + efsw::FileWatchListener *listener, + bool _useRecursion = false); + + void removeWatch(efsw::WatchID handle); + + // Atomic because the completion thread clears it if the completion port + // fails, while `addWatch()` reads it on the main thread. + std::atomic isValid{true}; + +private: + // Defined in the .cpp file so that this header needn't include + // ``. (`core.cc` includes libuv — and thus `winsock2.h` — after + // this header, and `` must not get there first.) + struct Watch; + struct Event; + + void completionLoop(); + + // Handles a completion packet for `watch`, re-arming it if appropriate. + // Appends any file actions to `events` rather than delivering them, since + // listeners must be called without `mapMutex` held. Called on the + // completion thread with `mapMutex` held. + void handleCompletion(Watch *watch, bool succeeded, unsigned long bytes, + unsigned long error, std::vector &events); + + // Issues a new `ReadDirectoryChangesW` for `watch`. Returns `false` if it + // couldn't be issued, in which case `watch` has no operation in flight. + // Caller must hold `mapMutex`. + bool arm(Watch *watch); + + // Closes `watch`'s directory handle and marks it as having no operation in + // flight; the watch stays registered but will never report again. Caller + // must hold `mapMutex`, and no operation may be in flight. + void goDormant(Watch *watch); + + // Stops `watch` and gives up our reference to it. If it has an operation in + // flight, the operation is cancelled and the completion thread frees the + // watch once the final packet arrives; otherwise the watch is freed now. + // Caller must hold `mapMutex`, and must already have removed `watch` from + // `handlesToWatches`. + void retire(Watch *watch); + + // Closes the directory handle (if still open) and deletes `watch`. + static void destroy(Watch *watch); + + long nextHandleID = 1; + void *iocp = nullptr; + bool stopping = false; + std::mutex mapMutex; + std::thread completionThread; + + std::unordered_map handlesToWatches; + + // Watches that have been removed but still have an operation in flight. + // The completion thread deletes each one when its final packet arrives. + std::unordered_set retiredWatches; + + // The number of `ReadDirectoryChangesW` operations that have been issued + // but whose completion packets haven't yet been dequeued. The completion + // thread won't exit until this reaches zero, since exiting any earlier + // would leave the kernel with pointers into memory we can no longer free + // safely. + size_t operationsInFlight = 0; +}; From 74ab55f80c7894b659165b3ec8b461718649e299 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sat, 26 Sep 2026 00:48:55 -0700 Subject: [PATCH 08/10] Strip out the rest of EFSW --- binding.gyp | 99 +-- lib/core.cc | 55 +- lib/core.h | 26 +- lib/efsw_core.h | 42 - lib/efsw_core_listener.h | 41 - lib/platform/FSEventsFileWatcher.cpp | 62 +- lib/platform/FSEventsFileWatcher.hpp | 22 +- lib/platform/InotifyFileWatcher.cpp | 36 +- lib/platform/InotifyFileWatcher.hpp | 24 +- lib/platform/KqueueFileWatcher.cpp | 46 +- lib/platform/KqueueFileWatcher.hpp | 24 +- .../ReadDirectoryChangesFileWatcher.cpp | 46 +- .../ReadDirectoryChangesFileWatcher.hpp | 18 +- lib/watcher.h | 66 ++ vendor/efsw/.DS_Store | Bin 6148 -> 0 bytes vendor/efsw/.clang-format | 18 - vendor/efsw/.ecode/project_build.json | 170 ----- vendor/efsw/.github/workflows/main.yml | 52 -- vendor/efsw/.gitignore | 21 - vendor/efsw/CMakeLists.txt | 198 ----- vendor/efsw/LICENSE | 22 - vendor/efsw/README.md | 149 ---- vendor/efsw/compile_flags.txt | 16 - vendor/efsw/efswConfig.cmake.in | 10 - vendor/efsw/include/efsw/efsw.h | 180 ----- vendor/efsw/include/efsw/efsw.hpp | 242 ------ vendor/efsw/premake4.lua | 235 ------ vendor/efsw/premake5.lua | 238 ------ vendor/efsw/project/build.reldbginfo.sh | 9 - .../efsw/project/qtcreator-linux/efsw.cflags | 1 - .../efsw/project/qtcreator-linux/efsw.config | 1 - .../efsw/project/qtcreator-linux/efsw.creator | 1 - .../project/qtcreator-linux/efsw.creator.user | 344 --------- .../project/qtcreator-linux/efsw.cxxflags | 1 - .../efsw/project/qtcreator-linux/efsw.files | 118 --- .../project/qtcreator-linux/efsw.includes | 2 - vendor/efsw/project/qtcreator-osx/efsw.cflags | 1 - vendor/efsw/project/qtcreator-osx/efsw.config | 3 - .../efsw/project/qtcreator-osx/efsw.creator | 1 - .../project/qtcreator-osx/efsw.creator.user | 253 ------ .../efsw/project/qtcreator-osx/efsw.cxxflags | 1 - vendor/efsw/project/qtcreator-osx/efsw.files | 185 ----- .../efsw/project/qtcreator-osx/efsw.includes | 7 - vendor/efsw/project/qtcreator-win/efsw.cflags | 1 - vendor/efsw/project/qtcreator-win/efsw.config | 1 - .../efsw/project/qtcreator-win/efsw.creator | 1 - .../project/qtcreator-win/efsw.creator.user | 211 ----- .../efsw/project/qtcreator-win/efsw.cxxflags | 1 - vendor/efsw/project/qtcreator-win/efsw.files | 215 ------ .../efsw/project/qtcreator-win/efsw.includes | 2 - vendor/efsw/src/efsw/Atomic.hpp | 33 - vendor/efsw/src/efsw/Debug.cpp | 81 -- vendor/efsw/src/efsw/Debug.hpp | 62 -- vendor/efsw/src/efsw/DirWatcherGeneric.cpp | 388 ---------- vendor/efsw/src/efsw/DirWatcherGeneric.hpp | 57 -- vendor/efsw/src/efsw/DirectorySnapshot.cpp | 212 ----- vendor/efsw/src/efsw/DirectorySnapshot.hpp | 45 -- .../efsw/src/efsw/DirectorySnapshotDiff.cpp | 22 - .../efsw/src/efsw/DirectorySnapshotDiff.hpp | 35 - vendor/efsw/src/efsw/FileInfo.cpp | 240 ------ vendor/efsw/src/efsw/FileInfo.hpp | 64 -- vendor/efsw/src/efsw/FileSystem.cpp | 136 ---- vendor/efsw/src/efsw/FileSystem.hpp | 40 - vendor/efsw/src/efsw/FileWatcher.cpp | 120 --- vendor/efsw/src/efsw/FileWatcherCWrapper.cpp | 131 ---- vendor/efsw/src/efsw/FileWatcherFSEvents.cpp | 245 ------ vendor/efsw/src/efsw/FileWatcherFSEvents.hpp | 103 --- vendor/efsw/src/efsw/FileWatcherGeneric.cpp | 158 ---- vendor/efsw/src/efsw/FileWatcherGeneric.hpp | 61 -- vendor/efsw/src/efsw/FileWatcherImpl.cpp | 34 - vendor/efsw/src/efsw/FileWatcherImpl.hpp | 64 -- vendor/efsw/src/efsw/FileWatcherInotify.cpp | 562 -------------- vendor/efsw/src/efsw/FileWatcherInotify.hpp | 86 --- vendor/efsw/src/efsw/FileWatcherKqueue.cpp | 229 ------ vendor/efsw/src/efsw/FileWatcherKqueue.hpp | 81 -- vendor/efsw/src/efsw/FileWatcherWin32.cpp | 267 ------- vendor/efsw/src/efsw/FileWatcherWin32.hpp | 71 -- vendor/efsw/src/efsw/Lock.hpp | 21 - vendor/efsw/src/efsw/Log.cpp | 49 -- vendor/efsw/src/efsw/Mutex.cpp | 20 - vendor/efsw/src/efsw/Mutex.hpp | 31 - vendor/efsw/src/efsw/String.cpp | 669 ---------------- vendor/efsw/src/efsw/String.hpp | 630 --------------- vendor/efsw/src/efsw/System.cpp | 22 - vendor/efsw/src/efsw/System.hpp | 25 - vendor/efsw/src/efsw/Thread.cpp | 41 - vendor/efsw/src/efsw/Thread.hpp | 100 --- vendor/efsw/src/efsw/Utf.hpp | 721 ------------------ vendor/efsw/src/efsw/Utf.inl | 576 -------------- vendor/efsw/src/efsw/Watcher.cpp | 10 - vendor/efsw/src/efsw/Watcher.hpp | 29 - vendor/efsw/src/efsw/WatcherFSEvents.cpp | 211 ----- vendor/efsw/src/efsw/WatcherFSEvents.hpp | 64 -- vendor/efsw/src/efsw/WatcherGeneric.cpp | 33 - vendor/efsw/src/efsw/WatcherGeneric.hpp | 29 - vendor/efsw/src/efsw/WatcherInotify.cpp | 21 - vendor/efsw/src/efsw/WatcherInotify.hpp | 23 - vendor/efsw/src/efsw/WatcherKqueue.cpp | 566 -------------- vendor/efsw/src/efsw/WatcherKqueue.hpp | 97 --- vendor/efsw/src/efsw/WatcherWin32.cpp | 307 -------- vendor/efsw/src/efsw/WatcherWin32.hpp | 85 --- vendor/efsw/src/efsw/base.hpp | 129 ---- vendor/efsw/src/efsw/inotify-nosys.h | 164 ---- .../efsw/src/efsw/platform/platformimpl.hpp | 20 - .../efsw/platform/posix/FileSystemImpl.cpp | 251 ------ .../efsw/platform/posix/FileSystemImpl.hpp | 30 - .../src/efsw/platform/posix/MutexImpl.cpp | 28 - .../src/efsw/platform/posix/MutexImpl.hpp | 30 - .../src/efsw/platform/posix/SystemImpl.cpp | 168 ---- .../src/efsw/platform/posix/SystemImpl.hpp | 25 - .../src/efsw/platform/posix/ThreadImpl.cpp | 62 -- .../src/efsw/platform/posix/ThreadImpl.hpp | 39 - .../src/efsw/platform/win/FileSystemImpl.cpp | 111 --- .../src/efsw/platform/win/FileSystemImpl.hpp | 31 - .../efsw/src/efsw/platform/win/MutexImpl.cpp | 25 - .../efsw/src/efsw/platform/win/MutexImpl.hpp | 33 - .../efsw/src/efsw/platform/win/SystemImpl.cpp | 46 -- .../efsw/src/efsw/platform/win/SystemImpl.hpp | 25 - .../efsw/src/efsw/platform/win/ThreadImpl.cpp | 56 -- .../efsw/src/efsw/platform/win/ThreadImpl.hpp | 42 - vendor/efsw/src/efsw/sophist.h | 147 ---- vendor/efsw/src/test/efsw-test.c | 164 ---- vendor/efsw/src/test/efsw-test.cpp | 139 ---- 123 files changed, 247 insertions(+), 13043 deletions(-) delete mode 100644 lib/efsw_core.h delete mode 100644 lib/efsw_core_listener.h create mode 100644 lib/watcher.h delete mode 100644 vendor/efsw/.DS_Store delete mode 100644 vendor/efsw/.clang-format delete mode 100644 vendor/efsw/.ecode/project_build.json delete mode 100644 vendor/efsw/.github/workflows/main.yml delete mode 100644 vendor/efsw/.gitignore delete mode 100644 vendor/efsw/CMakeLists.txt delete mode 100644 vendor/efsw/LICENSE delete mode 100644 vendor/efsw/README.md delete mode 100644 vendor/efsw/compile_flags.txt delete mode 100644 vendor/efsw/efswConfig.cmake.in delete mode 100644 vendor/efsw/include/efsw/efsw.h delete mode 100644 vendor/efsw/include/efsw/efsw.hpp delete mode 100644 vendor/efsw/premake4.lua delete mode 100644 vendor/efsw/premake5.lua delete mode 100644 vendor/efsw/project/build.reldbginfo.sh delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.cflags delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.config delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.creator delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.creator.user delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.cxxflags delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.files delete mode 100644 vendor/efsw/project/qtcreator-linux/efsw.includes delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.cflags delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.config delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.creator delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.creator.user delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.cxxflags delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.files delete mode 100644 vendor/efsw/project/qtcreator-osx/efsw.includes delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.cflags delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.config delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.creator delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.creator.user delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.cxxflags delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.files delete mode 100644 vendor/efsw/project/qtcreator-win/efsw.includes delete mode 100644 vendor/efsw/src/efsw/Atomic.hpp delete mode 100644 vendor/efsw/src/efsw/Debug.cpp delete mode 100644 vendor/efsw/src/efsw/Debug.hpp delete mode 100644 vendor/efsw/src/efsw/DirWatcherGeneric.cpp delete mode 100644 vendor/efsw/src/efsw/DirWatcherGeneric.hpp delete mode 100644 vendor/efsw/src/efsw/DirectorySnapshot.cpp delete mode 100644 vendor/efsw/src/efsw/DirectorySnapshot.hpp delete mode 100644 vendor/efsw/src/efsw/DirectorySnapshotDiff.cpp delete mode 100644 vendor/efsw/src/efsw/DirectorySnapshotDiff.hpp delete mode 100644 vendor/efsw/src/efsw/FileInfo.cpp delete mode 100644 vendor/efsw/src/efsw/FileInfo.hpp delete mode 100644 vendor/efsw/src/efsw/FileSystem.cpp delete mode 100644 vendor/efsw/src/efsw/FileSystem.hpp delete mode 100644 vendor/efsw/src/efsw/FileWatcher.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherCWrapper.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherFSEvents.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherFSEvents.hpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherGeneric.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherGeneric.hpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherImpl.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherImpl.hpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherInotify.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherInotify.hpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherKqueue.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherKqueue.hpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherWin32.cpp delete mode 100644 vendor/efsw/src/efsw/FileWatcherWin32.hpp delete mode 100644 vendor/efsw/src/efsw/Lock.hpp delete mode 100644 vendor/efsw/src/efsw/Log.cpp delete mode 100644 vendor/efsw/src/efsw/Mutex.cpp delete mode 100644 vendor/efsw/src/efsw/Mutex.hpp delete mode 100644 vendor/efsw/src/efsw/String.cpp delete mode 100644 vendor/efsw/src/efsw/String.hpp delete mode 100644 vendor/efsw/src/efsw/System.cpp delete mode 100644 vendor/efsw/src/efsw/System.hpp delete mode 100644 vendor/efsw/src/efsw/Thread.cpp delete mode 100644 vendor/efsw/src/efsw/Thread.hpp delete mode 100644 vendor/efsw/src/efsw/Utf.hpp delete mode 100644 vendor/efsw/src/efsw/Utf.inl delete mode 100644 vendor/efsw/src/efsw/Watcher.cpp delete mode 100644 vendor/efsw/src/efsw/Watcher.hpp delete mode 100644 vendor/efsw/src/efsw/WatcherFSEvents.cpp delete mode 100644 vendor/efsw/src/efsw/WatcherFSEvents.hpp delete mode 100644 vendor/efsw/src/efsw/WatcherGeneric.cpp delete mode 100644 vendor/efsw/src/efsw/WatcherGeneric.hpp delete mode 100644 vendor/efsw/src/efsw/WatcherInotify.cpp delete mode 100644 vendor/efsw/src/efsw/WatcherInotify.hpp delete mode 100644 vendor/efsw/src/efsw/WatcherKqueue.cpp delete mode 100644 vendor/efsw/src/efsw/WatcherKqueue.hpp delete mode 100644 vendor/efsw/src/efsw/WatcherWin32.cpp delete mode 100644 vendor/efsw/src/efsw/WatcherWin32.hpp delete mode 100644 vendor/efsw/src/efsw/base.hpp delete mode 100644 vendor/efsw/src/efsw/inotify-nosys.h delete mode 100644 vendor/efsw/src/efsw/platform/platformimpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/FileSystemImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/FileSystemImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/MutexImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/MutexImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/SystemImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/SystemImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/ThreadImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/posix/ThreadImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/win/FileSystemImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/win/FileSystemImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/win/MutexImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/win/MutexImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/win/SystemImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/win/SystemImpl.hpp delete mode 100644 vendor/efsw/src/efsw/platform/win/ThreadImpl.cpp delete mode 100644 vendor/efsw/src/efsw/platform/win/ThreadImpl.hpp delete mode 100644 vendor/efsw/src/efsw/sophist.h delete mode 100644 vendor/efsw/src/test/efsw-test.c delete mode 100644 vendor/efsw/src/test/efsw-test.cpp diff --git a/binding.gyp b/binding.gyp index e5a25b1..8ce6750 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,105 +1,10 @@ { "targets": [ - { - "target_name": "efsw", - "type": "static_library", - "sources": [ - "./vendor/efsw/src/efsw/Debug.cpp", - "./vendor/efsw/src/efsw/DirWatcherGeneric.cpp", - "./vendor/efsw/src/efsw/DirectorySnapshot.cpp", - "./vendor/efsw/src/efsw/DirectorySnapshotDiff.cpp", - "./vendor/efsw/src/efsw/FileInfo.cpp", - "./vendor/efsw/src/efsw/FileSystem.cpp", - "./vendor/efsw/src/efsw/FileWatcher.cpp", - "./vendor/efsw/src/efsw/FileWatcherCWrapper.cpp", - "./vendor/efsw/src/efsw/FileWatcherFSEvents.cpp", - "./vendor/efsw/src/efsw/FileWatcherGeneric.cpp", - "./vendor/efsw/src/efsw/FileWatcherImpl.cpp", - "./vendor/efsw/src/efsw/FileWatcherInotify.cpp", - "./vendor/efsw/src/efsw/FileWatcherKqueue.cpp", - "./vendor/efsw/src/efsw/FileWatcherWin32.cpp", - "./vendor/efsw/src/efsw/Log.cpp", - "./vendor/efsw/src/efsw/Mutex.cpp", - "./vendor/efsw/src/efsw/String.cpp", - "./vendor/efsw/src/efsw/System.cpp", - "./vendor/efsw/src/efsw/Thread.cpp", - "./vendor/efsw/src/efsw/Watcher.cpp", - "./vendor/efsw/src/efsw/WatcherFSEvents.cpp", - "./vendor/efsw/src/efsw/WatcherGeneric.cpp", - "./vendor/efsw/src/efsw/WatcherInotify.cpp", - "./vendor/efsw/src/efsw/WatcherKqueue.cpp", - "./vendor/efsw/src/efsw/WatcherWin32.cpp" - ], - "include_dirs": [ - "./vendor/efsw/include", - "./vendor/efsw/src" - ], - "conditions": [ - ["OS==\"win\"", { - "sources!": [ - "./vendor/efsw/src/efsw/WatcherKqueue.cpp", - "./vendor/efsw/src/efsw/WatcherFSEvents.cpp", - "./vendor/efsw/src/efsw/WatcherInotify.cpp", - "./vendor/efsw/src/efsw/FileWatcherKqueue.cpp", - "./vendor/efsw/src/efsw/FileWatcherInotify.cpp", - "./vendor/efsw/src/efsw/FileWatcherFSEvents.cpp" - ], - "sources": [ - "./vendor/efsw/src/efsw/platform/win/FileSystemImpl.cpp", - "./vendor/efsw/src/efsw/platform/win/MutexImpl.cpp", - "./vendor/efsw/src/efsw/platform/win/SystemImpl.cpp", - "./vendor/efsw/src/efsw/platform/win/ThreadImpl.cpp" - ], - }], - ["OS!=\"win\"", { - "sources": [ - "./vendor/efsw/src/efsw/platform/posix/FileSystemImpl.cpp", - "./vendor/efsw/src/efsw/platform/posix/MutexImpl.cpp", - "./vendor/efsw/src/efsw/platform/posix/SystemImpl.cpp", - "./vendor/efsw/src/efsw/platform/posix/ThreadImpl.cpp" - ], - "cflags": ["-Wall", "-Wno-long-long"] - }], - ["OS==\"linux\"", { - "sources!": [ - "./vendor/efsw/src/efsw/WatcherKqueue.cpp", - "./vendor/efsw/src/efsw/WatcherFSEvents.cpp", - "./vendor/efsw/src/efsw/WatcherWin32.cpp", - "./vendor/efsw/src/efsw/FileWatcherKqueue.cpp", - "./vendor/efsw/src/efsw/FileWatcherWin32.cpp", - "./vendor/efsw/src/efsw/FileWatcherFSEvents.cpp" - ], - "libraries": [ - "-lpthread" - ], - "defines": [ - "EFSW_VERBOSE" - ] - }], - ["OS==\"mac\"", { - "sources!": [ - "./vendor/efsw/src/efsw/WatcherInotify.cpp", - "./vendor/efsw/src/efsw/WatcherWin32.cpp", - "./vendor/efsw/src/efsw/FileWatcherInotify.cpp", - "./vendor/efsw/src/efsw/FileWatcherWin32.cpp" - ], - "defines": [ - "EFSW_FSEVENTS_SUPPORTED" - ], - "xcode_settings": { - "OTHER_LDFLAGS": [ - "-framework CoreFoundation -framework CoreServices" - ] - } - }] - ] - }, { "target_name": "pathwatcher", "defines": [ "NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS" ], - "dependencies": ["efsw"], "cflags!": ["-fno-exceptions"], "cflags_cc!": ["-fno-exceptions"], "xcode_settings": { @@ -112,11 +17,11 @@ }, "sources": [ "lib/core.cc", - "lib/core.h" + "lib/core.h", + "lib/watcher.h" ], "include_dirs": [ " #include @@ -38,30 +37,30 @@ static bool PredatesWatchStart(struct timespec fileSpec, timeval startTime) { } #endif -static Napi::BigInt WatcherHandleToBigInt(Napi::Env env, efsw::WatchID handle) { +static Napi::BigInt WatcherHandleToBigInt(Napi::Env env, pathwatcher::WatchID handle) { int64_t handleAsInt64 = static_cast(handle); return Napi::BigInt::New(env, handleAsInt64); } -static efsw::WatchID BigIntToWatcherHandle(Napi::BigInt value) { +static pathwatcher::WatchID BigIntToWatcherHandle(Napi::BigInt value) { // JavaScript `BigInt`s can be arbitrarily large, so they may not fit inside // a `long` or `int64_t`. But if this value needs truncation, something shady // is going on, since that value certainly didn't come from us. We conform to // the API here, but we don't need to check whether the value was truncated. bool lossless = false; - efsw::WatchID handle = value.Int64Value(&lossless); + pathwatcher::WatchID handle = value.Int64Value(&lossless); return handle; } -static std::string EventType(efsw::Action action, bool isChild) { +static std::string EventType(pathwatcher::Action action, bool isChild) { switch (action) { - case efsw::Actions::Add: + case pathwatcher::Actions::Add: return isChild ? "child-create" : "create"; - case efsw::Actions::Delete: + case pathwatcher::Actions::Delete: return isChild ? "child-delete" : "delete"; - case efsw::Actions::Modified: + case pathwatcher::Actions::Modified: return isChild ? "child-change" : "change"; - case efsw::Actions::Moved: + case pathwatcher::Actions::Moved: return isChild ? "child-rename" : "rename"; default: return "unknown"; @@ -101,7 +100,7 @@ static void ProcessEvent(Napi::Env env, Napi::Function callback, // // NOTE: This library previously envisioned that some platforms would allow // watching of files directly and some would require watching of a file's - // parent folder. EFSW uses the parent-folder approach on all platforms, so + // parent folder. We use the parent-folder approach on all platforms, so // in practice we're not using half of the event names we used to use. That's // why the second argument below is `true`. // @@ -170,14 +169,14 @@ void PathWatcherListener::Stop(FileWatcher *fileWatcher) { // Correlate a watch ID to a path/timestamp pair. void PathWatcherListener::AddPath(PathTimestampPair pair, - efsw::WatchID handle) { + pathwatcher::WatchID handle) { std::lock_guard lock(pathsMutex); paths[handle] = pair; pathsToHandles[pair.path] = handle; } // Remove metadata for a given watch ID. -void PathWatcherListener::RemovePath(efsw::WatchID handle) { +void PathWatcherListener::RemovePath(pathwatcher::WatchID handle) { std::string path; if (isShuttingDown) return; @@ -210,7 +209,7 @@ bool PathWatcherListener::HasPath(std::string path) { return it != pathsToHandles.end(); } -efsw::WatchID PathWatcherListener::GetHandleForPath(std::string path) { +pathwatcher::WatchID PathWatcherListener::GetHandleForPath(std::string path) { std::lock_guard lock(pathsToHandlesMutex); auto it = pathsToHandles.find(path); return it->second; @@ -221,10 +220,10 @@ bool PathWatcherListener::IsEmpty() { return paths.empty(); } -void PathWatcherListener::handleFileAction(efsw::WatchID watchId, +void PathWatcherListener::handleFileAction(pathwatcher::WatchID watchId, const std::string &dir, const std::string &filename, - efsw::Action action, + pathwatcher::Action action, std::string oldFilename) { #ifdef DEBUG std::cout << "PathWatcherListener::handleFileAction dir: " << dir @@ -277,14 +276,14 @@ void PathWatcherListener::handleFileAction(efsw::WatchID watchId, { struct stat file; if (stat(newPathStr.c_str(), &file) != 0 && - action != efsw::Action::Delete) { + action != pathwatcher::Action::Delete) { // If this was a delete action, the file is _expected_ not to exist // anymore. Otherwise it's a strange outcome and it means we should // ignore this event. return; } - if (action == efsw::Action::Add) { + if (action == pathwatcher::Action::Add) { // One easy way to check if a file was truly just created: does its // creation time match its modification time? If not, the file has been // written to since its creation. @@ -302,7 +301,7 @@ void PathWatcherListener::handleFileAction(efsw::WatchID watchId, #endif return; } - } else if (action == efsw::Action::Modified) { + } else if (action == pathwatcher::Action::Modified) { if (PredatesWatchStart(file.st_mtimespec, startTime)) { #ifdef DEBUG std::cout << "File was modified before we started this path watcher! " @@ -392,8 +391,8 @@ Napi::Value PathWatcher::Watch(const Napi::CallbackInfo &info) { } // The wrapper JS will resolve this to the file's real path. We expect to be - // dealing with real locations on disk, since that's what EFSW will report to - // us anyway. + // dealing with real locations on disk, since that's what the watcher will + // report to us anyway. Napi::String path = info[0].ToString(); std::string cppPath(path); @@ -416,7 +415,7 @@ Napi::Value PathWatcher::Watch(const Napi::CallbackInfo &info) { #endif int myGeneration = ++watchGeneration; tsfn = Napi::ThreadSafeFunction::New( - env, callback.Value(), "pathwatcher-efsw-listener", 0, 1, + env, callback.Value(), "pathwatcher-listener", 0, 1, [this, myGeneration](Napi::Env env) { // This is unexpected. We should try to do some cleanup before the // environment terminates. @@ -436,8 +435,8 @@ Napi::Value PathWatcher::Watch(const Napi::CallbackInfo &info) { isWatching = true; } - // EFSW represents watchers as unsigned `int`s; we can easily convert these - // to JavaScript. + // The watcher represents watches as integers; we can easily convert these to + // JavaScript. WatcherHandle handle = fileWatcher->addWatch(cppPath, listener, useRecursiveWatcher); @@ -461,8 +460,8 @@ Napi::Value PathWatcher::Watch(const Napi::CallbackInfo &info) { // `setInterval` would; this is the handle that the wrapper JavaScript can // use to unwatch the path later. // - // But EFSW defines a WatchID as a `long`, which means it's 64-bits and - // therefore possibly larger than the JS `Number` type can handle. We'll use + // But a `WatchID` is a `long`, which can be 64 bits and therefore possibly + // larger than the JS `Number` type can handle. We'll use // `BigInt`s instead because we live in the future. return WatcherHandleToBigInt(env, handle); } @@ -487,10 +486,10 @@ Napi::Value PathWatcher::Unwatch(const Napi::CallbackInfo &info) { if (!listener) return env.Undefined(); - efsw::WatchID handle = BigIntToWatcherHandle(info[0].As()); + pathwatcher::WatchID handle = BigIntToWatcherHandle(info[0].As()); - // EFSW doesn’t mind if we give it a handle that it doesn’t recognize; it’ll - // just silently do nothing. + // The watcher doesn’t mind if we give it a handle that it doesn’t recognize; + // it’ll just silently do nothing. // // This is useful because removing watcher can innocuously error anyway on // certain platforms. For instance, Linux will automatically stop watching a diff --git a/lib/core.h b/lib/core.h index 2d660d4..9ad2eba 100644 --- a/lib/core.h +++ b/lib/core.h @@ -1,6 +1,6 @@ #pragma once -#include "../vendor/efsw/include/efsw/efsw.hpp" +#include "watcher.h" #include #include #include @@ -37,7 +37,7 @@ typedef ReadDirectoryChangesFileWatcher FileWatcher; #define PATH_SEPARATOR '/' #endif -typedef efsw::WatchID WatcherHandle; +typedef pathwatcher::WatchID WatcherHandle; #ifdef _WIN32 struct PathTimestampPair { @@ -52,8 +52,8 @@ struct PathTimestampPair { #endif struct PathWatcherEvent { - efsw::Action type; - efsw::WatchID handle; + pathwatcher::Action type; + pathwatcher::WatchID handle; std::vector new_path; std::vector old_path; @@ -63,7 +63,7 @@ struct PathWatcherEvent { PathWatcherEvent() = default; // Constructor - PathWatcherEvent(efsw::Action t, efsw::WatchID h, const std::vector &np, + PathWatcherEvent(pathwatcher::Action t, pathwatcher::WatchID h, const std::vector &np, const std::vector &op = std::vector(), const std::string &wp = "") : type(t), handle(h), new_path(np), old_path(op), watcher_path(wp) {} @@ -105,18 +105,18 @@ struct PathWatcherEvent { } }; -class PathWatcherListener : public efsw::FileWatchListener { +class PathWatcherListener : public pathwatcher::FileWatchListener { public: PathWatcherListener(Napi::Env env, Napi::ThreadSafeFunction tsfn); - void handleFileAction(efsw::WatchID watchId, const std::string &dir, - const std::string &filename, efsw::Action action, + void handleFileAction(pathwatcher::WatchID watchId, const std::string &dir, + const std::string &filename, pathwatcher::Action action, std::string oldFilename) override; - void AddPath(PathTimestampPair pair, efsw::WatchID handle); - void RemovePath(efsw::WatchID handle); + void AddPath(PathTimestampPair pair, pathwatcher::WatchID handle); + void RemovePath(pathwatcher::WatchID handle); bool HasPath(std::string path); - efsw::WatchID GetHandleForPath(std::string path); + pathwatcher::WatchID GetHandleForPath(std::string path); bool IsEmpty(); void Stop(); void Stop(FileWatcher *fileWatcher); @@ -127,8 +127,8 @@ class PathWatcherListener : public efsw::FileWatchListener { std::mutex pathsMutex; std::mutex pathsToHandlesMutex; Napi::ThreadSafeFunction tsfn; - std::unordered_map paths; - std::unordered_map pathsToHandles; + std::unordered_map paths; + std::unordered_map pathsToHandles; }; class PathWatcher : public Napi::Addon { diff --git a/lib/efsw_core.h b/lib/efsw_core.h deleted file mode 100644 index c342c66..0000000 --- a/lib/efsw_core.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * node-efsw - Node.js binding for EFSW - * - * Copyright (c) 2017 XadillaX - * - * MIT License - */ -#ifndef __EFSW_CORE_H__ -#define __EFSW_CORE_H__ -#include -#include -#include "../vendor/efsw/include/efsw/efsw.hpp" -#include "efsw_core_listener.h" - -namespace efsw_core { - -class EFSWCore : public Nan::ObjectWrap { -public: - static NAN_MODULE_INIT(Init); - -private: - explicit EFSWCore(const char* path, Nan::Callback* listener); - ~EFSWCore(); - - efsw::WatchId Start(); - void Stop(); - - static NAN_METHOD(New); - static NAN_METHOD(Start); - static NAN_METHOD(Stop); - -private: - std::string path; - Nan::Callback* listener; - efsw::FileWatcher* watcher; - efsw::WatchId watch_id; - EFSWCoreListener core_listener; -}; - -} - -#endif diff --git a/lib/efsw_core_listener.h b/lib/efsw_core_listener.h deleted file mode 100644 index 7ff76f7..0000000 --- a/lib/efsw_core_listener.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * node-efsw - Node.js binding for EFSW - * - * Copyright (c) 2017 XadillaX - * - * MIT License - */ -#ifndef __EFSW_CORE_LISTENER_H__ -#define __EFSW_CORE_LISTENER_H__ -#include -#include -#include "./deps/efsw/include/efsw/efsw.hpp" - -namespace efsw_core { - -#define Watch watch -#define AddWatch addWatch -#define RemoveWatch removeWatch -#define HandleFileAction handleFileAction -#define GetLastErrorLog getLastErrorLog -#define WatchId WatchID - -// class EFSWCoreListener : public efsw::FileWatchListener { -// public: -// EFSWCoreListener(Nan::Callback* listener); -// ~EFSWCoreListener(); -// -// void HandleFileAction( -// efsw::WatchId, -// const std::string& dir, -// const std::string& filename, -// efsw::Action action, -// std::string old_filename = ""); -// -// private: -// Nan::Callback* listener; -// }; -// -// } - -#endif diff --git a/lib/platform/FSEventsFileWatcher.cpp b/lib/platform/FSEventsFileWatcher.cpp index b913d2c..4bcc58c 100644 --- a/lib/platform/FSEventsFileWatcher.cpp +++ b/lib/platform/FSEventsFileWatcher.cpp @@ -7,7 +7,7 @@ #include #endif -// This is an API-compatible replacement for `efsw::FileWatcher` on macOS. It +// This is an API-compatible replacement for efsw’s `FileWatcher` on macOS. It // uses its own implementation of `FSEvents` so it can minimize the number of // streams created in comparison to `efsw`’s approach of using one stream per // watched path. @@ -191,9 +191,9 @@ FSEventsFileWatcher::~FSEventsFileWatcher() { } } -efsw::WatchID FSEventsFileWatcher::addWatch( +pathwatcher::WatchID FSEventsFileWatcher::addWatch( const std::string& directory, - efsw::FileWatchListener* listener, + pathwatcher::FileWatchListener* listener, // The `_useRecursion` flag is ignored; it's present for API compatibility. bool _useRecursion ) { @@ -209,7 +209,7 @@ efsw::WatchID FSEventsFileWatcher::addWatch( watchDir = PathWithoutFileName(directory, false); } - efsw::WatchID handle = nextHandleID++; + pathwatcher::WatchID handle = nextHandleID++; { std::lock_guard lock(mapMutex); handlesToPaths[handle] = watchDir; @@ -228,26 +228,26 @@ efsw::WatchID FSEventsFileWatcher::addWatch( // so the new path is the most likely culprit.) if (stat(watchDir.c_str(), &st) != 0) { if (errno == EACCES || errno == EPERM) { - return efsw::Errors::FileNotReadable; + return pathwatcher::Errors::FileNotReadable; } - return efsw::Errors::FileNotFound; + return pathwatcher::Errors::FileNotFound; } struct statfs sfsb; if (statfs(watchDir.c_str(), &sfsb) == 0) { if (!(sfsb.f_flags & MNT_LOCAL)) { - return efsw::Errors::FileRemote; + return pathwatcher::Errors::FileRemote; } } - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } return handle; } void FSEventsFileWatcher::removeWatch( - efsw::WatchID handle + pathwatcher::WatchID handle ) { auto remainingCount = removeHandle(handle); @@ -314,13 +314,13 @@ void FSEventsFileWatcher::FSEventCallback( } void FSEventsFileWatcher::sendFileAction( - efsw::WatchID watchid, + pathwatcher::WatchID watchid, const std::string& dir, const std::string& filename, - efsw::Action action, + pathwatcher::Action action, std::string oldFilename ) { - efsw::FileWatchListener* listener; + pathwatcher::FileWatchListener* listener; auto it = handlesToListeners.find(watchid); if (it == handlesToListeners.end()) return; listener = it->second; @@ -335,7 +335,7 @@ void FSEventsFileWatcher::sendFileAction( } struct FileEventMatch { - efsw::WatchID handle; + pathwatcher::WatchID handle; std::string path; }; @@ -356,7 +356,7 @@ void FSEventsFileWatcher::handleActions(std::vector& events) { kFSEventStreamEventFlagRootChanged )) continue; - efsw::WatchID handle; + pathwatcher::WatchID handle; std::string path; { @@ -443,10 +443,10 @@ void FSEventsFileWatcher::handleActions(std::vector& events) { 0 == strcasecmp(event.path.c_str(), nEvent.path.c_str()) ) { // Move from one path to the other. - sendFileAction(handle, dirPath, newFilepath, efsw::Actions::Moved, filePath); + sendFileAction(handle, dirPath, newFilepath, pathwatcher::Actions::Moved, filePath); } else { // Move in the opposite direction. - sendFileAction(handle, dirPath, filePath, efsw::Actions::Moved, newFilepath); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Moved, newFilepath); } } else { // This is a move from one directory to another. Use PathExists to @@ -457,15 +457,15 @@ void FSEventsFileWatcher::handleActions(std::vector& events) { // directory is renamed over the target file inside it. if (!PathExists(event.path)) { // event is the source; the file moved out of our watched dir. - sendFileAction(handle, dirPath, filePath, efsw::Actions::Delete); - sendFileAction(handle, newDir, newFilepath, efsw::Actions::Add); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Delete); + sendFileAction(handle, newDir, newFilepath, pathwatcher::Actions::Add); } else { // event is the destination; the file was moved into our watched // dir (e.g. an atomic save from a temp directory). - sendFileAction(handle, newDir, newFilepath, efsw::Actions::Delete); - sendFileAction(handle, dirPath, filePath, efsw::Actions::Add); + sendFileAction(handle, newDir, newFilepath, pathwatcher::Actions::Delete); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Add); if (nEvent.flags & shorthandFSEventsModified) { - sendFileAction(handle, dirPath, filePath, efsw::Actions::Modified); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Modified); } } } @@ -490,14 +490,14 @@ void FSEventsFileWatcher::handleActions(std::vector& events) { } else if (PathExists(event.path)) { // Treat remaining renames as creations when we know the path still // exists… - sendFileAction(handle, dirPath, filePath, efsw::Actions::Add); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Add); if (event.flags & shorthandFSEventsModified) { - sendFileAction(handle, dirPath, filePath, efsw::Actions::Modified); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Modified); } } else { // …and as deletions when we know the path doesn’t still exist. - sendFileAction(handle, dirPath, filePath, efsw::Actions::Delete); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Delete); } } else { // Ordinary business — new files, changed, files, deleted files. @@ -507,7 +507,7 @@ void FSEventsFileWatcher::handleActions(std::vector& events) { } void FSEventsFileWatcher::handleAddModDel( - efsw::WatchID handle, + pathwatcher::WatchID handle, const uint32_t& flags, const std::string& path, std::string& dirPath, @@ -517,25 +517,25 @@ void FSEventsFileWatcher::handleAddModDel( // This claims to be a file creation; make sure it exists on disk before // triggering an event. if (PathExists(path)) { - sendFileAction(handle, dirPath, filePath, efsw::Actions::Add); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Add); } } if (flags & shorthandFSEventsModified) { - sendFileAction(handle, dirPath, filePath, efsw::Actions::Modified); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Modified); } if (flags & kFSEventStreamEventFlagItemRemoved) { // This claims to be a file deletion; make sure it doesn't exist on disk // before triggering an event. if (!PathExists(path)) { - sendFileAction(handle, dirPath, filePath, efsw::Actions::Delete); + sendFileAction(handle, dirPath, filePath, pathwatcher::Actions::Delete); } } } // Private: clean up a handle from both unordered maps. -size_t FSEventsFileWatcher::removeHandle(efsw::WatchID handle) { +size_t FSEventsFileWatcher::removeHandle(pathwatcher::WatchID handle) { // If we're destroyed (or about to destroy ourselves), don't try to do // anything to these maps; the mutex lock will fail. if (!isValid || pendingDestruction) return 0; @@ -579,7 +579,7 @@ void FSEventsFileWatcher::process() { for (const auto& dir : dirsCopy) { if (pendingDestruction) return; - efsw::WatchID handle; + pathwatcher::WatchID handle; std::string path; { @@ -597,7 +597,7 @@ void FSEventsFileWatcher::process() { handle, PathWithoutFileName(dir), FileNameFromPath(dir), - efsw::Actions::Modified + pathwatcher::Actions::Modified ); if (pendingDestruction) return; diff --git a/lib/platform/FSEventsFileWatcher.hpp b/lib/platform/FSEventsFileWatcher.hpp index 3d2a180..27e4cee 100644 --- a/lib/platform/FSEventsFileWatcher.hpp +++ b/lib/platform/FSEventsFileWatcher.hpp @@ -7,7 +7,7 @@ #include #include #include -#include "../../vendor/efsw/include/efsw/efsw.hpp" +#include "../watcher.h" class FSEvent { public: @@ -28,21 +28,21 @@ class FSEventsFileWatcher { public: FSEventsFileWatcher() {}; ~FSEventsFileWatcher(); - efsw::WatchID addWatch( + pathwatcher::WatchID addWatch( const std::string& directory, - efsw::FileWatchListener* watcher, + pathwatcher::FileWatchListener* watcher, bool _useRecursion = false ); void removeWatch( - efsw::WatchID watchID + pathwatcher::WatchID watchID ); void handleActions(std::vector& events); void sendFileAction( - efsw::WatchID watchid, + pathwatcher::WatchID watchid, const std::string& dir, const std::string& filename, - efsw::Action action, + pathwatcher::Action action, std::string oldFilename = "" ); @@ -56,7 +56,7 @@ class FSEventsFileWatcher { ); void handleAddModDel( - efsw::WatchID handle, + pathwatcher::WatchID handle, const uint32_t& flags, const std::string& path, std::string& dirPath, @@ -81,7 +81,7 @@ class FSEventsFileWatcher { } }; - size_t removeHandle(efsw::WatchID handle); + size_t removeHandle(pathwatcher::WatchID handle); bool startNewStream(); long nextHandleID = 1; @@ -99,7 +99,7 @@ class FSEventsFileWatcher { std::set dirsChanged; - std::unordered_map handlesToPaths; - std::unordered_map pathsToHandles; - std::unordered_map handlesToListeners; + std::unordered_map handlesToPaths; + std::unordered_map pathsToHandles; + std::unordered_map handlesToListeners; }; diff --git a/lib/platform/InotifyFileWatcher.cpp b/lib/platform/InotifyFileWatcher.cpp index 330d059..85b46ed 100644 --- a/lib/platform/InotifyFileWatcher.cpp +++ b/lib/platform/InotifyFileWatcher.cpp @@ -67,14 +67,14 @@ InotifyFileWatcher::~InotifyFileWatcher() { close(inotifyFd); } -efsw::WatchID InotifyFileWatcher::addWatch(const std::string &path, - efsw::FileWatchListener *listener, +pathwatcher::WatchID InotifyFileWatcher::addWatch(const std::string &path, + pathwatcher::FileWatchListener *listener, bool /* _useRecursion */) { #ifdef DEBUG std::cout << "InotifyFileWatcher::addWatch: " << path << std::endl; #endif if (!isValid) - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; std::string dir = path; if (dir.empty() || dir.back() != '/') @@ -92,21 +92,21 @@ efsw::WatchID InotifyFileWatcher::addWatch(const std::string &path, if (wd < 0) { switch (errno) { case ENOENT: - return efsw::Errors::FileNotFound; + return pathwatcher::Errors::FileNotFound; case EACCES: - return efsw::Errors::FileNotReadable; + return pathwatcher::Errors::FileNotReadable; default: - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } } - efsw::WatchID handle = nextHandleID++; + pathwatcher::WatchID handle = nextHandleID++; handlesToWatches[handle] = {dir, listener, wd}; wdToHandles.insert({wd, handle}); return handle; } -void InotifyFileWatcher::removeWatch(efsw::WatchID handle) { +void InotifyFileWatcher::removeWatch(pathwatcher::WatchID handle) { // We hold `mapMutex` across the `inotify_rm_watch()` call below. That's // load-bearing: it ensures we've recorded that we're expecting an // IN_IGNORED before the event loop — which takes the same lock in @@ -178,11 +178,11 @@ void InotifyFileWatcher::stopWatch(int wd) { } void InotifyFileWatcher::sendFileAction(int wd, const std::string &filename, - efsw::Action action, + pathwatcher::Action action, const std::string &oldFilename) { // Copy out (handle, dir, listener) under the lock, then call into listener // code without holding it. - std::vector> + std::vector> targets; { std::lock_guard lock(mapMutex); @@ -215,7 +215,7 @@ void InotifyFileWatcher::eventLoop() { return; // No matching IN_MOVED_TO arrived: the file was moved somewhere we're not // watching (or out of the filesystem entirely). - sendFileAction(pendingWd, pendingFilename, efsw::Actions::Delete); + sendFileAction(pendingWd, pendingFilename, pathwatcher::Actions::Delete); hasPendingMove = false; }; @@ -288,7 +288,7 @@ void InotifyFileWatcher::eventLoop() { if ((event->mask & IN_MOVED_TO) && event->wd == pendingWd && event->cookie == pendingCookie) { // Same-directory rename — almost always an atomic save. - sendFileAction(event->wd, filename, efsw::Actions::Moved, + sendFileAction(event->wd, filename, pathwatcher::Actions::Moved, pendingFilename); hasPendingMove = false; continue; @@ -320,7 +320,7 @@ void InotifyFileWatcher::eventLoop() { // // This must happen before any teardown below, since `sendFileAction` // finds its listeners by looking up `wd` in our bookkeeping. - sendFileAction(event->wd, "", efsw::Actions::Delete); + sendFileAction(event->wd, "", pathwatcher::Actions::Delete); if (event->mask & IN_MOVE_SELF) { // Unlike a deletion, a move leaves the watch alive — the directory @@ -335,16 +335,16 @@ void InotifyFileWatcher::eventLoop() { } if (event->mask & IN_CREATE) { - sendFileAction(event->wd, filename, efsw::Actions::Add); + sendFileAction(event->wd, filename, pathwatcher::Actions::Add); } else if (event->mask & IN_DELETE) { - sendFileAction(event->wd, filename, efsw::Actions::Delete); + sendFileAction(event->wd, filename, pathwatcher::Actions::Delete); } else if (event->mask & IN_MOVED_TO) { // Arrived from outside this directory (or its IN_MOVED_FROM partner // already timed out): treat it as a brand-new file. - sendFileAction(event->wd, filename, efsw::Actions::Add); - sendFileAction(event->wd, filename, efsw::Actions::Modified); + sendFileAction(event->wd, filename, pathwatcher::Actions::Add); + sendFileAction(event->wd, filename, pathwatcher::Actions::Modified); } else if (event->mask & (IN_MODIFY | IN_CLOSE_WRITE)) { - sendFileAction(event->wd, filename, efsw::Actions::Modified); + sendFileAction(event->wd, filename, pathwatcher::Actions::Modified); } } } diff --git a/lib/platform/InotifyFileWatcher.hpp b/lib/platform/InotifyFileWatcher.hpp index f96da96..2613206 100644 --- a/lib/platform/InotifyFileWatcher.hpp +++ b/lib/platform/InotifyFileWatcher.hpp @@ -1,17 +1,17 @@ #pragma once -#include "../../vendor/efsw/include/efsw/efsw.hpp" +#include "../watcher.h" #include #include #include #include #include -// An API-compatible replacement for `efsw::FileWatcher` that talks to inotify -// directly. Plays the same role on Linux that `KqueueFileWatcher` and -// `FSEventsFileWatcher` play on macOS. +// A watcher that talks to inotify directly. Plays the same role on Linux that +// `KqueueFileWatcher` and `FSEventsFileWatcher` play on macOS. See `watcher.h` +// for the interface. // -// Key differences from `FileWatcherInotify`: +// Key differences from efsw’s `FileWatcherInotify`, which this replaced: // // * A single `inotify` instance backs every watch; `addWatch()` just calls // `inotify_add_watch()` against it and gets back a watch descriptor (wd). No @@ -38,11 +38,11 @@ class InotifyFileWatcher { InotifyFileWatcher(); ~InotifyFileWatcher(); - efsw::WatchID addWatch(const std::string &path, - efsw::FileWatchListener *listener, + pathwatcher::WatchID addWatch(const std::string &path, + pathwatcher::FileWatchListener *listener, bool _useRecursion = false); - void removeWatch(efsw::WatchID handle); + void removeWatch(pathwatcher::WatchID handle); // Atomic because the event loop thread clears it when it hits an // unrecoverable poll() error, while `addWatch()` reads it on the main @@ -52,7 +52,7 @@ class InotifyFileWatcher { private: struct Watch { std::string dir; // always ends with '/' - efsw::FileWatchListener *listener; + pathwatcher::FileWatchListener *listener; int wd; }; @@ -60,7 +60,7 @@ class InotifyFileWatcher { // Looks up every handle registered for `wd` and dispatches `action` to each // of their listeners. - void sendFileAction(int wd, const std::string &filename, efsw::Action action, + void sendFileAction(int wd, const std::string &filename, pathwatcher::Action action, const std::string &oldFilename = ""); // Responds to an IN_IGNORED for `wd`. If we provoked it ourselves by @@ -83,8 +83,8 @@ class InotifyFileWatcher { std::mutex mapMutex; std::thread eventThread; - std::unordered_map handlesToWatches; - std::unordered_multimap wdToHandles; + std::unordered_map handlesToWatches; + std::unordered_multimap wdToHandles; // wd -> number of IN_IGNORED events we've asked the kernel for (via // `inotify_rm_watch()`) but haven't read yet. Lets the event loop tell our diff --git a/lib/platform/KqueueFileWatcher.cpp b/lib/platform/KqueueFileWatcher.cpp index c49e842..23f587e 100644 --- a/lib/platform/KqueueFileWatcher.cpp +++ b/lib/platform/KqueueFileWatcher.cpp @@ -99,28 +99,28 @@ KqueueFileWatcher::~KqueueFileWatcher() { close(kqueueFd); } -efsw::WatchID KqueueFileWatcher::addWatch(const std::string &path, - efsw::FileWatchListener *listener, +pathwatcher::WatchID KqueueFileWatcher::addWatch(const std::string &path, + pathwatcher::FileWatchListener *listener, bool /* _useRecursion */ ) { if (!isValid) { - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } int fd = open(path.c_str(), O_EVTONLY); if (fd < 0) { switch (errno) { case ENOENT: - return efsw::Errors::FileNotFound; + return pathwatcher::Errors::FileNotFound; case EACCES: case EPERM: - return efsw::Errors::FileNotReadable; + return pathwatcher::Errors::FileNotReadable; default: - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } } - efsw::WatchID handle; + pathwatcher::WatchID handle; { std::lock_guard lock(mapMutex); handle = nextHandleID++; @@ -145,13 +145,13 @@ efsw::WatchID KqueueFileWatcher::addWatch(const std::string &path, handlesToPaths.erase(handle); handlesToListeners.erase(handle); close(fd); - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } return handle; } -void KqueueFileWatcher::removeWatch(efsw::WatchID handle) { +void KqueueFileWatcher::removeWatch(pathwatcher::WatchID handle) { int fd = -1; { std::lock_guard lock(mapMutex); @@ -172,12 +172,12 @@ void KqueueFileWatcher::removeWatch(efsw::WatchID handle) { close(fd); } -void KqueueFileWatcher::sendFileAction(efsw::WatchID handle, +void KqueueFileWatcher::sendFileAction(pathwatcher::WatchID handle, const std::string &dir, const std::string &filename, - efsw::Action action, + pathwatcher::Action action, const std::string &oldFilename) { - efsw::FileWatchListener *listener = nullptr; + pathwatcher::FileWatchListener *listener = nullptr; { std::lock_guard lock(mapMutex); auto it = handlesToListeners.find(handle); @@ -188,7 +188,7 @@ void KqueueFileWatcher::sendFileAction(efsw::WatchID handle, listener->handleFileAction(handle, dir, filename, action, oldFilename); } -void KqueueFileWatcher::closeFd(efsw::WatchID handle, int fd) { +void KqueueFileWatcher::closeFd(pathwatcher::WatchID handle, int fd) { { std::lock_guard lock(mapMutex); handlesToFds.erase(handle); @@ -197,7 +197,7 @@ void KqueueFileWatcher::closeFd(efsw::WatchID handle, int fd) { close(fd); } -bool KqueueFileWatcher::reopenFd(efsw::WatchID handle, +bool KqueueFileWatcher::reopenFd(pathwatcher::WatchID handle, const std::string &path) { int newFd = open(path.c_str(), O_EVTONLY); if (newFd < 0) @@ -245,8 +245,8 @@ void KqueueFileWatcher::eventLoop() { // Recover the handle from the udata we stored at registration time. // This avoids a map lookup on the fd, which could be stale if the fd // was closed and its number reused by the OS. - efsw::WatchID handle = - static_cast(reinterpret_cast(event.udata)); + pathwatcher::WatchID handle = + static_cast(reinterpret_cast(event.udata)); // Confirm the handle is still registered. If removeWatch() was called // between the event being queued and us processing it, skip. @@ -280,14 +280,14 @@ void KqueueFileWatcher::eventLoop() { std::pair newParts = SplitPath(newPath); if (parts.first != newParts.first) { // Treat moves outside of the directory as deletions. - sendFileAction(handle, dir, filename, efsw::Actions::Delete); + sendFileAction(handle, dir, filename, pathwatcher::Actions::Delete); } else { sendFileAction(handle, newParts.first, newParts.second, - efsw::Actions::Moved, filename); + pathwatcher::Actions::Moved, filename); } } else { // F_GETPATH failed or returned the same path — treat as a deletion. - sendFileAction(handle, dir, filename, efsw::Actions::Delete); + sendFileAction(handle, dir, filename, pathwatcher::Actions::Delete); } } else if (event.fflags & NOTE_DELETE) { @@ -301,19 +301,19 @@ void KqueueFileWatcher::eventLoop() { if (stat(watchedPath.c_str(), &st) == 0 && reopenFd(handle, watchedPath)) { // A new file appeared at the same path: atomic save. - sendFileAction(handle, dir, filename, efsw::Actions::Modified); + sendFileAction(handle, dir, filename, pathwatcher::Actions::Modified); } else { // The path is genuinely gone. - sendFileAction(handle, dir, filename, efsw::Actions::Delete); + sendFileAction(handle, dir, filename, pathwatcher::Actions::Delete); } } else if (event.fflags & NOTE_WRITE) { - sendFileAction(handle, dir, filename, efsw::Actions::Modified); + sendFileAction(handle, dir, filename, pathwatcher::Actions::Modified); } else if (event.fflags & NOTE_ATTRIB) { // macOS sometimes skips NOTE_WRITE when a file is truncated to empty, // firing NOTE_ATTRIB instead. Detect this by seeking to the end. if (lseek(fd, 0, SEEK_END) == 0) { - sendFileAction(handle, dir, filename, efsw::Actions::Modified); + sendFileAction(handle, dir, filename, pathwatcher::Actions::Modified); } } } diff --git a/lib/platform/KqueueFileWatcher.hpp b/lib/platform/KqueueFileWatcher.hpp index aca1c9e..7080d02 100644 --- a/lib/platform/KqueueFileWatcher.hpp +++ b/lib/platform/KqueueFileWatcher.hpp @@ -5,7 +5,7 @@ #include #include #include -#include "../../vendor/efsw/include/efsw/efsw.hpp" +#include "../watcher.h" // An API-compatible replacement for FSEventsFileWatcher that uses kqueue // instead of FSEvents. Intended for experimentation; swap in via core.h. @@ -23,13 +23,13 @@ class KqueueFileWatcher { KqueueFileWatcher(); ~KqueueFileWatcher(); - efsw::WatchID addWatch( + pathwatcher::WatchID addWatch( const std::string& path, - efsw::FileWatchListener* listener, + pathwatcher::FileWatchListener* listener, bool _useRecursion = false ); - void removeWatch(efsw::WatchID handle); + void removeWatch(pathwatcher::WatchID handle); bool isValid = true; @@ -37,20 +37,20 @@ class KqueueFileWatcher { void eventLoop(); void sendFileAction( - efsw::WatchID handle, + pathwatcher::WatchID handle, const std::string& dir, const std::string& filename, - efsw::Action action, + pathwatcher::Action action, const std::string& oldFilename = "" ); // Closes the fd and removes it from the fd maps, but leaves the handle in // handlesToPaths / handlesToListeners so that removeWatch() still works. - void closeFd(efsw::WatchID handle, int fd); + void closeFd(pathwatcher::WatchID handle, int fd); // Opens a new fd for the given path and registers it with kqueue under an // existing handle. Used after an atomic save replaces the watched inode. - bool reopenFd(efsw::WatchID handle, const std::string& path); + bool reopenFd(pathwatcher::WatchID handle, const std::string& path); long nextHandleID = 1; int kqueueFd = -1; @@ -59,8 +59,8 @@ class KqueueFileWatcher { std::mutex mapMutex; std::thread eventThread; - std::unordered_map handlesToFds; - std::unordered_map fdsToHandles; - std::unordered_map handlesToPaths; - std::unordered_map handlesToListeners; + std::unordered_map handlesToFds; + std::unordered_map fdsToHandles; + std::unordered_map handlesToPaths; + std::unordered_map handlesToListeners; }; diff --git a/lib/platform/ReadDirectoryChangesFileWatcher.cpp b/lib/platform/ReadDirectoryChangesFileWatcher.cpp index 05f77b0..9733cc2 100644 --- a/lib/platform/ReadDirectoryChangesFileWatcher.cpp +++ b/lib/platform/ReadDirectoryChangesFileWatcher.cpp @@ -107,11 +107,11 @@ std::wstring GetHandlePath(HANDLE handle) { // A file action waiting to be delivered to a listener. We gather these while // holding `mapMutex` and deliver them after releasing it. struct ReadDirectoryChangesFileWatcher::Event { - efsw::FileWatchListener *listener; - efsw::WatchID handle; + pathwatcher::FileWatchListener *listener; + pathwatcher::WatchID handle; std::string dir; std::string filename; - efsw::Action action; + pathwatcher::Action action; std::string oldFilename; }; @@ -125,9 +125,9 @@ struct ReadDirectoryChangesFileWatcher::Watch { std::vector buffer = std::vector(kBufferBytes / sizeof(DWORD)); HANDLE dirHandle = INVALID_HANDLE_VALUE; - efsw::WatchID handle = 0; + pathwatcher::WatchID handle = 0; std::string dir; // UTF-8; always ends with '\\' - efsw::FileWatchListener *listener = nullptr; + pathwatcher::FileWatchListener *listener = nullptr; // The path `dirHandle` resolved to when the watch was created. We compare // it against the handle's current path on each completion so that we can @@ -177,21 +177,21 @@ struct ReadDirectoryChangesFileWatcher::Watch { // Translates one `FILE_NOTIFY_INFORMATION` record into zero or more events. void translate(DWORD action, const std::string &filename, std::vector &events) { - auto emit = [&](const std::string &name, efsw::Action fwAction, + auto emit = [&](const std::string &name, pathwatcher::Action fwAction, const std::string &oldName = "") { events.push_back({listener, handle, dir, name, fwAction, oldName}); }; switch (action) { case FILE_ACTION_ADDED: - emit(filename, efsw::Actions::Add); + emit(filename, pathwatcher::Actions::Add); break; case FILE_ACTION_REMOVED: - emit(filename, efsw::Actions::Delete); + emit(filename, pathwatcher::Actions::Delete); break; case FILE_ACTION_MODIFIED: if (!isDuplicateModification(filename)) - emit(filename, efsw::Actions::Modified); + emit(filename, pathwatcher::Actions::Modified); break; case FILE_ACTION_RENAMED_OLD_NAME: // Hold on to this until its partner arrives. A rename out of the @@ -203,10 +203,10 @@ struct ReadDirectoryChangesFileWatcher::Watch { case FILE_ACTION_RENAMED_NEW_NAME: if (hasPendingOldName) { // A rename within the watched directory — often an atomic save. - emit(filename, efsw::Actions::Moved, pendingOldName); + emit(filename, pathwatcher::Actions::Moved, pendingOldName); hasPendingOldName = false; } else { - emit(filename, efsw::Actions::Add); + emit(filename, pathwatcher::Actions::Add); } break; default: @@ -255,27 +255,27 @@ ReadDirectoryChangesFileWatcher::~ReadDirectoryChangesFileWatcher() { CloseHandle((HANDLE)iocp); } -efsw::WatchID +pathwatcher::WatchID ReadDirectoryChangesFileWatcher::addWatch(const std::string &path, - efsw::FileWatchListener *listener, + pathwatcher::FileWatchListener *listener, bool /* _useRecursion */) { #ifdef DEBUG std::cout << "ReadDirectoryChangesFileWatcher::addWatch: " << path << std::endl; #endif if (!isValid) - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; std::wstring widePath = ToWidePath(path); DWORD attributes = GetFileAttributesW(widePath.c_str()); if (attributes == INVALID_FILE_ATTRIBUTES) { return GetLastError() == ERROR_ACCESS_DENIED - ? efsw::Errors::FileNotReadable - : efsw::Errors::FileNotFound; + ? pathwatcher::Errors::FileNotReadable + : pathwatcher::Errors::FileNotFound; } if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) - return efsw::Errors::FileNotFound; + return pathwatcher::Errors::FileNotFound; // `FILE_SHARE_DELETE` so that we don't prevent anyone from renaming or // deleting the directory we're watching. @@ -288,11 +288,11 @@ ReadDirectoryChangesFileWatcher::addWatch(const std::string &path, switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: - return efsw::Errors::FileNotFound; + return pathwatcher::Errors::FileNotFound; case ERROR_ACCESS_DENIED: - return efsw::Errors::FileNotReadable; + return pathwatcher::Errors::FileNotReadable; default: - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } } @@ -311,7 +311,7 @@ ReadDirectoryChangesFileWatcher::addWatch(const std::string &path, reinterpret_cast(watch), 0) == nullptr) { destroy(watch); - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } // We hold `mapMutex` while arming the watch so that, if a completion packet @@ -321,7 +321,7 @@ ReadDirectoryChangesFileWatcher::addWatch(const std::string &path, if (!arm(watch)) { destroy(watch); - return efsw::Errors::WatcherFailed; + return pathwatcher::Errors::WatcherFailed; } watch->handle = nextHandleID++; @@ -329,7 +329,7 @@ ReadDirectoryChangesFileWatcher::addWatch(const std::string &path, return watch->handle; } -void ReadDirectoryChangesFileWatcher::removeWatch(efsw::WatchID handle) { +void ReadDirectoryChangesFileWatcher::removeWatch(pathwatcher::WatchID handle) { std::lock_guard lock(mapMutex); auto it = handlesToWatches.find(handle); if (it == handlesToWatches.end()) diff --git a/lib/platform/ReadDirectoryChangesFileWatcher.hpp b/lib/platform/ReadDirectoryChangesFileWatcher.hpp index 2fe5d4d..66f301b 100644 --- a/lib/platform/ReadDirectoryChangesFileWatcher.hpp +++ b/lib/platform/ReadDirectoryChangesFileWatcher.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../vendor/efsw/include/efsw/efsw.hpp" +#include "../watcher.h" #include #include #include @@ -9,11 +9,11 @@ #include #include -// An API-compatible replacement for `efsw::FileWatcher` that talks to -// `ReadDirectoryChangesW` directly. Plays the same role on Windows that -// `InotifyFileWatcher` plays on Linux. +// A watcher that talks to `ReadDirectoryChangesW` directly. Plays the same +// role on Windows that `InotifyFileWatcher` plays on Linux. See `watcher.h` for +// the interface. // -// Key differences from `FileWatcherWin32`: +// Key differences from efsw’s `FileWatcherWin32`, which this replaced: // // * Ownership of in-flight I/O. Every live watch has a // `ReadDirectoryChangesW` outstanding, and the kernel writes into that @@ -43,11 +43,11 @@ class ReadDirectoryChangesFileWatcher { ReadDirectoryChangesFileWatcher(); ~ReadDirectoryChangesFileWatcher(); - efsw::WatchID addWatch(const std::string &path, - efsw::FileWatchListener *listener, + pathwatcher::WatchID addWatch(const std::string &path, + pathwatcher::FileWatchListener *listener, bool _useRecursion = false); - void removeWatch(efsw::WatchID handle); + void removeWatch(pathwatcher::WatchID handle); // Atomic because the completion thread clears it if the completion port // fails, while `addWatch()` reads it on the main thread. @@ -95,7 +95,7 @@ class ReadDirectoryChangesFileWatcher { std::mutex mapMutex; std::thread completionThread; - std::unordered_map handlesToWatches; + std::unordered_map handlesToWatches; // Watches that have been removed but still have an operation in flight. // The completion thread deletes each one when its final packet arrives. diff --git a/lib/watcher.h b/lib/watcher.h new file mode 100644 index 0000000..6dfde81 --- /dev/null +++ b/lib/watcher.h @@ -0,0 +1,66 @@ +#pragma once + +#include + +// Types shared between `core.cc` and the per-platform watcher implementations +// in `platform/`. Each platform defines a class with this interface: +// +// WatchID addWatch(const std::string &path, FileWatchListener *listener, +// bool _useRecursion = false); +// void removeWatch(WatchID handle); +// +// …and `core.h` picks one of them as `FileWatcher`. +// +// This interface originally came from efsw +// (https://github.com/SpartanJ/efsw), which this library used to vendor. +namespace pathwatcher { + +// Identifies a watch. `addWatch()` returns a positive `WatchID` on success, +// or one of the negative `Errors::Error` values on failure. +typedef long WatchID; + +namespace Actions { +enum Action { + // A file was created, or renamed into the watched directory. + Add = 1, + // A file was deleted, or renamed out of the watched directory. + Delete = 2, + // A file's contents changed. + Modified = 3, + // A file was renamed within the watched directory. + Moved = 4 +}; +} +typedef Actions::Action Action; + +// These values reach JavaScript as the `code` of the error thrown when a +// watch can't be added, so they shouldn't change. +namespace Errors { +enum Error { + NoError = 0, + FileNotFound = -1, + FileRepeated = -2, + FileOutOfScope = -3, + FileNotReadable = -4, + // The directory is on a remote file system. + FileRemote = -5, + // The watcher failed to watch for changes. + WatcherFailed = -6, + Unspecified = -7 +}; +} + +// Receives file actions from a watcher. Called on the watcher's own thread. +class FileWatchListener { +public: + virtual ~FileWatchListener() {} + + // `dir` is the watched directory, with a trailing path separator; + // `filename` is relative to it. For `Moved`, `oldFilename` is the file's + // previous name, also relative to `dir`. + virtual void handleFileAction(WatchID watchid, const std::string &dir, + const std::string &filename, Action action, + std::string oldFilename = "") = 0; +}; + +} // namespace pathwatcher diff --git a/vendor/efsw/.DS_Store b/vendor/efsw/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 - $ - $ - ) -endif() - -set(EFSW_CPP_SOURCE - src/efsw/Debug.cpp - src/efsw/DirectorySnapshot.cpp - src/efsw/DirectorySnapshotDiff.cpp - src/efsw/DirWatcherGeneric.cpp - src/efsw/FileInfo.cpp - src/efsw/FileSystem.cpp - src/efsw/FileWatcher.cpp - src/efsw/FileWatcherCWrapper.cpp - src/efsw/FileWatcherGeneric.cpp - src/efsw/FileWatcherImpl.cpp - src/efsw/Log.cpp - src/efsw/Mutex.cpp - src/efsw/String.cpp - src/efsw/System.cpp - src/efsw/Thread.cpp - src/efsw/Watcher.cpp - src/efsw/WatcherGeneric.cpp -) - -target_include_directories(efsw - PRIVATE src/ - PUBLIC - $ - $ - $ -) - -if(VERBOSE) - target_compile_definitions(efsw PRIVATE EFSW_VERBOSE) -endif() - -target_compile_features(efsw PRIVATE cxx_std_11) - -if(BUILD_SHARED_LIBS) - target_compile_definitions(efsw PRIVATE EFSW_DYNAMIC EFSW_EXPORTS) -endif() - -# platforms -if(WIN32) - list(APPEND EFSW_CPP_SOURCE - src/efsw/platform/win/FileSystemImpl.cpp - src/efsw/platform/win/MutexImpl.cpp - src/efsw/platform/win/SystemImpl.cpp - src/efsw/platform/win/ThreadImpl.cpp - ) -else() - list(APPEND EFSW_CPP_SOURCE - src/efsw/platform/posix/FileSystemImpl.cpp - src/efsw/platform/posix/MutexImpl.cpp - src/efsw/platform/posix/SystemImpl.cpp - src/efsw/platform/posix/ThreadImpl.cpp - ) -endif() - -# watcher implementations -if(APPLE) - list(APPEND EFSW_CPP_SOURCE - src/efsw/FileWatcherFSEvents.cpp - src/efsw/FileWatcherKqueue.cpp - src/efsw/WatcherFSEvents.cpp - src/efsw/WatcherKqueue.cpp - ) -elseif(WIN32) - list(APPEND EFSW_CPP_SOURCE - src/efsw/FileWatcherWin32.cpp - src/efsw/WatcherWin32.cpp - ) -elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - list(APPEND EFSW_CPP_SOURCE - src/efsw/FileWatcherInotify.cpp - src/efsw/WatcherInotify.cpp - ) - - find_path(EFSW_INOTIFY_H NAMES sys/inotify.h NO_CACHE) - if(EFSW_INOTIFY_H STREQUAL "EFSW_INOTIFY_H-NOTFOUND") - target_compile_definitions(efsw PRIVATE EFSW_INOTIFY_NOSYS) - endif() -elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") - list(APPEND EFSW_CPP_SOURCE - src/efsw/FileWatcherKqueue.cpp - src/efsw/WatcherKqueue.cpp - ) -endif() - -if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR - (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")) - target_compile_definitions(efsw PRIVATE _SCL_SECURE_NO_WARNINGS) -else() - target_compile_options(efsw PRIVATE -Wall -Wno-long-long -fPIC) -endif() - -target_compile_definitions(efsw PRIVATE $,DEBUG,NDEBUG>) - -if(APPLE) - set(MAC_LIBS "-framework CoreFoundation" "-framework CoreServices") - target_link_libraries(efsw PRIVATE ${MAC_LIBS}) - if(BUILD_STATIC_LIBS) - target_link_libraries(efsw-static PRIVATE ${MAC_LIBS}) - endif() -elseif(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Haiku") AND NOT WIN32) - target_link_libraries(efsw PRIVATE Threads::Threads) -endif() - -target_sources(efsw PRIVATE ${EFSW_CPP_SOURCE}) - -if(BUILD_STATIC_LIBS) - target_sources(efsw-static PRIVATE ${EFSW_CPP_SOURCE}) -endif() - -include(CMakePackageConfigHelpers) - -set(packageDestDir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/efswConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/cmake/efswConfig.cmake - INSTALL_DESTINATION "${packageDestDir}" - NO_SET_AND_CHECK_MACRO - NO_CHECK_REQUIRED_COMPONENTS_MACRO -) - -export(TARGETS efsw NAMESPACE efsw:: FILE ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Targets.cmake) -if(BUILD_STATIC_LIBS) - export(TARGETS efsw-static NAMESPACE efsw:: APPEND FILE ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Targets.cmake) -endif() - -if(EFSW_INSTALL) - install(TARGETS efsw EXPORT efswExport - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ) - - install( - FILES - include/efsw/efsw.h include/efsw/efsw.hpp - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/efsw - ) - - if(BUILD_STATIC_LIBS) - install(TARGETS efsw-static EXPORT efswExport - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ) - endif() - - install(EXPORT efswExport NAMESPACE efsw:: DESTINATION "${packageDestDir}" FILE ${PROJECT_NAME}Targets.cmake) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/efswConfig.cmake DESTINATION "${packageDestDir}") -endif() - -if(BUILD_TEST_APP) - # C++ test application - add_executable(efsw-test src/test/efsw-test.cpp) - target_link_libraries(efsw-test efsw-static) - - # C test application - add_executable(efsw-test-stdc src/test/efsw-test.c) - target_link_libraries(efsw-test-stdc efsw-static) -endif() diff --git a/vendor/efsw/LICENSE b/vendor/efsw/LICENSE deleted file mode 100644 index 37f354a..0000000 --- a/vendor/efsw/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2020 Martín Lucas Golini - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) -http://code.google.com/p/simplefilewatcher/ also MIT licensed. diff --git a/vendor/efsw/README.md b/vendor/efsw/README.md deleted file mode 100644 index 1c71940..0000000 --- a/vendor/efsw/README.md +++ /dev/null @@ -1,149 +0,0 @@ -Entropia File System Watcher ![efsw](https://web.ensoft.dev/efsw/efsw-logo.svg) -============================ - -[![build status](https://img.shields.io/github/actions/workflow/status/SpartanJ/efsw/main.yml?branch=master)](https://github.com/SpartanJ/efsw/actions?query=workflow%3Abuild) - -**efsw** is a C++ cross-platform file system watcher and notifier. - -**efsw** monitors the file system asynchronously for changes to files and directories by watching a list of specified paths, and raises events when a directory or file change. - -**efsw** supports recursive directories watch, tracking the entire sub directory tree. - -**efsw** currently supports the following platforms: - -* Linux via [inotify](http://en.wikipedia.org/wiki/Inotify) - -* Windows via [I/O Completion Ports](http://en.wikipedia.org/wiki/IOCP) - -* Mac OS X via [FSEvents](http://en.wikipedia.org/wiki/FSEvents) or [kqueue](http://en.wikipedia.org/wiki/Kqueue) - -* FreeBSD/BSD via [kqueue](http://en.wikipedia.org/wiki/Kqueue) - -* OS-independent generic watcher -(polling the disk for directory snapshots and comparing them periodically) - -If any of the backend fails to start for any reason, it will fallback to the OS-independent implementation. -This should never happen, except for the Kqueue implementation; see `Platform limitations and clarifications`. - -**Code License** --------------- -[MIT License](http://www.opensource.org/licenses/mit-license.php) - -**Some example code:** --------------------- - -```c++ -// Inherits from the abstract listener class, and implements the the file action handler -class UpdateListener : public efsw::FileWatchListener { - public: - void handleFileAction( efsw::WatchID watchid, const std::string& dir, - const std::string& filename, efsw::Action action, - std::string oldFilename ) override { - switch ( action ) { - case efsw::Actions::Add: - std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Added" - << std::endl; - break; - case efsw::Actions::Delete: - std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Delete" - << std::endl; - break; - case efsw::Actions::Modified: - std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Modified" - << std::endl; - break; - case efsw::Actions::Moved: - std::cout << "DIR (" << dir << ") FILE (" << filename << ") has event Moved from (" - << oldFilename << ")" << std::endl; - break; - default: - std::cout << "Should never happen!" << std::endl; - } - } -}; - -// Create the file system watcher instance -// efsw::FileWatcher allow a first boolean parameter that indicates if it should start with the -// generic file watcher instead of the platform specific backend -efsw::FileWatcher* fileWatcher = new efsw::FileWatcher(); - -// Create the instance of your efsw::FileWatcherListener implementation -UpdateListener* listener = new UpdateListener(); - -// Add a folder to watch, and get the efsw::WatchID -// It will watch the /tmp folder recursively ( the third parameter indicates that is recursive ) -// Reporting the files and directories changes to the instance of the listener -efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true ); - -// Adds another directory to watch. This time as non-recursive. -efsw::WatchID watchID2 = fileWatcher->addWatch( "/usr", listener, false ); - -// For Windows, adds another watch, specifying to use a bigger buffer, to not miss events -// (do not use for network locations, see efsw.hpp for details). -efsw::WatchID watchID3 = fileWatcher->addWatch( "c:\\temp", listener, true, { (BufferSize, 128*1024) } ); - -// Start watching asynchronously the directories -fileWatcher->watch(); - -// Remove the second watcher added -// You can also call removeWatch by passing the watch path ( it must end with an slash or backslash -// in windows, since that's how internally it's saved ) -fileWatcher->removeWatch( watchID2 ); -``` - -**Dependencies** --------------- -None :) - -**Compiling** ------------- -To generate project files you will need to [download and install](https://premake.github.io/download) [Premake](https://premake.github.io/docs/What-Is-Premake) - -Then you can generate the project for your platform by just going to the project directory where the premake4.lua file is located and executing: - -`premake5 gmake2` to generate project Makefiles, then `cd make/*YOURPLATFORM*/`, and finally `make` or `make config=release_x86_64` ( it will generate the static lib, the shared lib and the test application ). - -or - -`premake5 vs2022` to generate Visual Studio 2022 project. - -or - -`premake5 xcode4` to generate Xcode 4 project. - -There is also a cmake file that I don't officially support but it works just fine, provided by [Mohammed Nafees](https://github.com/mnafees) and improved by [Eugene Shalygin](https://github.com/zeule). - -**Platform limitations and clarifications** -------------------------------------------- - -Directory paths are expected to be encoded as UTF-8 strings in all platforms. - -handleFileAction returns UTF-8 strings in all platforms. - -Windows and FSEvents Mac OS X implementation can't follow symlinks ( it will ignore followSymlinks() and allowOutOfScopeLinks() ). - -Kqueue implementation is limited by the maximum number of file descriptors allowed per process by the OS. In the case of reaching the file descriptors limit ( in BSD around 18000 and in OS X around 10240 ), it will fallback to the generic file watcher. - -OS X will use only Kqueue if the OS X version is below 10.5. This implementation needs to be compiled separately from the OS X >= 10.5 implementation, since there's no way to compile FSEvents backend in OS X below 10.5. - -FSEvents for OS X Lion and beyond in some cases will generate more actions than in reality ocurred, since fine-grained implementation of FSEvents doesn't give the order of the actions retrieved. In some cases I need to guess/approximate the order of them. - -Generic watcher relies on the inode information to detect file and directories renames/move. Since Windows has no concept of inodes as Unix platforms do, there is no current reliable way of determining file/directory movement on Windows without help from the Windows API ( this is replaced with Add/Delete events ). - -Linux versions below 2.6.13 are not supported, since inotify wasn't implemented yet. I'm not interested in supporting older kernels, since I don't see the point. If someone needs this, open an issue in the issue tracker and I may consider implementing a dnotify backend. - -OS-independent watcher, Kqueue and FSEvents for OS X below 10.5 keep cache of the directories structures, to be able to detect changes in the directories. This means that there's a memory overhead for these backends. - -**Useful information** --------------------- -The project also comes with a C API wrapper, contributed by [Sepul Sepehr Taghdisian](https://github.com/septag). - -There's a string manipulation class not exposed in the efsw header ( efsw::String ) that can be used to make string encoding conversion. - - -**Clarifications** ----------------- - -This software started as a fork of the [simplefilewatcher](http://code.google.com/p/simplefilewatcher/) by James Wynn (james[at]jameswynn.com), [MIT licensed](http://www.opensource.org/licenses/mit-license.html). - -The icon used for the project is part of the [Haiku®'s Icons](http://www.haiku-inc.org/haiku-icons.html), [MIT licensed](http://www.opensource.org/licenses/mit-license.html). diff --git a/vendor/efsw/compile_flags.txt b/vendor/efsw/compile_flags.txt deleted file mode 100644 index d87aa27..0000000 --- a/vendor/efsw/compile_flags.txt +++ /dev/null @@ -1,16 +0,0 @@ --Wno-documentation-unknown-command --Wno-unknown-warning-option --Wno-unknown-pragmas --std=c++11 --fsyntax-only --Isrc --Iinclude --fmessage-length=0 --fdiagnostics-show-note-include-stack --fretain-comments-from-system-headers --fmacro-backtrace-limit=0 --ferror-limit=1000 --Wall --Wextra --x -c++-header diff --git a/vendor/efsw/efswConfig.cmake.in b/vendor/efsw/efswConfig.cmake.in deleted file mode 100644 index 5340f33..0000000 --- a/vendor/efsw/efswConfig.cmake.in +++ /dev/null @@ -1,10 +0,0 @@ -# - Config file for the @CMAKE_PROJECT_NAME@ package - -@PACKAGE_INIT@ - -@DEPENDENCIES_SECTION@ -include(CMakeFindDependencyMacro) - -find_dependency(Threads) - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/vendor/efsw/include/efsw/efsw.h b/vendor/efsw/include/efsw/efsw.h deleted file mode 100644 index ecb9ec4..0000000 --- a/vendor/efsw/include/efsw/efsw.h +++ /dev/null @@ -1,180 +0,0 @@ -/** - @author Sepul Sepehr Taghdisian - - Copyright (c) 2013 Martin Lucas Golini - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) - http://code.google.com/p/simplefilewatcher/ also MIT licensed. -*/ -/** This is the C API wrapper of EFSW */ -#ifndef ESFW_H -#define ESFW_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_WIN32) - #ifdef EFSW_DYNAMIC - // Windows platforms - #ifdef EFSW_EXPORTS - // From DLL side, we must export - #define EFSW_API __declspec(dllexport) - #else - // From client application side, we must import - #define EFSW_API __declspec(dllimport) - #endif - #else - // No specific directive needed for static build - #ifndef EFSW_API - #define EFSW_API - #endif - #endif -#else - #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) - #define EFSW_API __attribute__ ((visibility("default"))) - #endif - - // Other platforms don't need to define anything - #ifndef EFSW_API - #define EFSW_API - #endif -#endif - -/// Type for a watch id -typedef long efsw_watchid; - -/// Type for watcher -typedef void* efsw_watcher; - -enum efsw_action -{ - EFSW_ADD = 1, /// Sent when a file is created or renamed - EFSW_DELETE = 2, /// Sent when a file is deleted or renamed - EFSW_MODIFIED = 3, /// Sent when a file is modified - EFSW_MOVED = 4 /// Sent when a file is moved -}; - -enum efsw_error -{ - EFSW_NOTFOUND = -1, - EFSW_REPEATED = -2, - EFSW_OUTOFSCOPE = -3, - EFSW_NOTREADABLE = -4, - EFSW_REMOTE = -5, - EFSW_WATCHER_FAILED = -6, - EFSW_UNSPECIFIED = -7 -}; - -enum efsw_option -{ - /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and - /// file system events may be dropped. For that, using a different (bigger) buffer size - /// can be defined here, but note that this does not work for network drives, - /// because a buffer larger than 64K will fail the folder being watched, see - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) - EFSW_OPT_WIN_BUFFER_SIZE = 1, - /// For Windows, per default all events are captured but we might only be interested - /// in a subset; the value of the option should be set to a bitwise or'ed set of - /// FILE_NOTIFY_CHANGE_* flags. - EFSW_OPT_WIN_NOTIFY_FILTER = 2 -}; - -/// Basic interface for listening for file events. -typedef void (*efsw_pfn_fileaction_callback) ( - efsw_watcher watcher, - efsw_watchid watchid, - const char* dir, - const char* filename, - enum efsw_action action, - const char* old_filename, - void* param -); - -typedef struct { - enum efsw_option option; - int value; -} efsw_watcher_option; - -/** - * Creates a new file-watcher - * @param generic_mode Force the use of the Generic file watcher - */ -efsw_watcher EFSW_API efsw_create(int generic_mode); - -/// Release the file-watcher and unwatch any directories -void EFSW_API efsw_release(efsw_watcher watcher); - -/// Retrieve last error occured by file-watcher -EFSW_API const char* efsw_getlasterror(); - -/// Reset file-watcher last error -EFSW_API void efsw_clearlasterror(); - -/// Add a directory watch -/// On error returns WatchID with Error type. -efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory, - efsw_pfn_fileaction_callback callback_fn, int recursive, void* param); - -/// Add a directory watch, specifying options -/// @param options Pointer to an array of watcher options -/// @param nr_options Number of options referenced by \p options -efsw_watchid EFSW_API efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory, - efsw_pfn_fileaction_callback callback_fn, int recursive, efsw_watcher_option *options, - int options_number, void* param); - -/// Remove a directory watch. This is a brute force search O(nlogn). -void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory); - -/// Remove a directory watch. This is a map lookup O(logn). -void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid); - -/// Starts watching ( in other thread ) -void EFSW_API efsw_watch(efsw_watcher watcher); - -/** - * Allow recursive watchers to follow symbolic links to other directories - * followSymlinks is disabled by default - */ -void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable); - -/** @return If can follow symbolic links to directorioes */ -int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher); - -/** - * When enable this it will allow symlinks to watch recursively out of the pointed directory. - * follorSymlinks must be enabled to this work. - * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, - * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. - * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). - * Buy enabling out of scope links, it will allow this behavior. - * allowOutOfScopeLinks are disabled by default. - */ -void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow); - -/// @return Returns if out of scope links are allowed -int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/vendor/efsw/include/efsw/efsw.hpp b/vendor/efsw/include/efsw/efsw.hpp deleted file mode 100644 index b6519b6..0000000 --- a/vendor/efsw/include/efsw/efsw.hpp +++ /dev/null @@ -1,242 +0,0 @@ -/** - @author Martín Lucas Golini - - Copyright (c) 2013 Martín Lucas Golini - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) - http://code.google.com/p/simplefilewatcher/ also MIT licensed. -*/ - -#ifndef ESFW_HPP -#define ESFW_HPP - -#include -#include -#include - -#if defined( _WIN32 ) -#ifdef EFSW_DYNAMIC -// Windows platforms -#ifdef EFSW_EXPORTS -// From DLL side, we must export -#define EFSW_API __declspec( dllexport ) -#else -// From client application side, we must import -#define EFSW_API __declspec( dllimport ) -#endif -#else -// No specific directive needed for static build -#ifndef EFSW_API -#define EFSW_API -#endif -#endif -#else -#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) -#ifndef EFSW_API -#define EFSW_API __attribute__( ( visibility( "default" ) ) ) -#endif -#endif - -// Other platforms don't need to define anything -#ifndef EFSW_API -#define EFSW_API -#endif -#endif - -namespace efsw { - -/// Type for a watch id -typedef long WatchID; - -// forward declarations -class FileWatcherImpl; -class FileWatchListener; -class WatcherOption; - -/// Actions to listen for. Rename will send two events, one for -/// the deletion of the old file, and one for the creation of the -/// new file. -namespace Actions { -enum Action { - /// Sent when a file is created or renamed - Add = 1, - /// Sent when a file is deleted or renamed - Delete = 2, - /// Sent when a file is modified - Modified = 3, - /// Sent when a file is moved - Moved = 4 -}; -} -typedef Actions::Action Action; - -/// Errors log namespace -namespace Errors { - -enum Error { - NoError = 0, - FileNotFound = -1, - FileRepeated = -2, - FileOutOfScope = -3, - FileNotReadable = -4, - /// Directory in remote file system - /// ( create a generic FileWatcher instance to watch this directory ). - FileRemote = -5, - /// File system watcher failed to watch for changes. - WatcherFailed = -6, - Unspecified = -7 -}; - -class EFSW_API Log { - public: - /// @return The last error logged - static std::string getLastErrorLog(); - - /// @return The code of the last error logged - static Error getLastErrorCode(); - - /// Reset last error - static void clearLastError(); - - /// Creates an error of the type specified - static Error createLastError( Error err, std::string log ); -}; - -} // namespace Errors -typedef Errors::Error Error; - -/// Optional file watcher settings. -namespace Options { -enum Option { - /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and - /// file system events may be dropped. For that, using a different (bigger) buffer size - /// can be defined here, but note that this does not work for network drives, - /// because a buffer larger than 64K will fail the folder being watched, see - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) - WinBufferSize = 1, - /// For Windows, per default all events are captured but we might only be interested - /// in a subset; the value of the option should be set to a bitwise or'ed set of - /// FILE_NOTIFY_CHANGE_* flags. - WinNotifyFilter = 2 -}; -} -typedef Options::Option Option; - -/// Listens to files and directories and dispatches events -/// to notify the listener of files and directories changes. -/// @class FileWatcher -class EFSW_API FileWatcher { - public: - /// Default constructor, will use the default platform file watcher - FileWatcher(); - - /// Constructor that lets you force the use of the Generic File Watcher - explicit FileWatcher( bool useGenericFileWatcher ); - - virtual ~FileWatcher(); - - /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. - /// For backwards compatibility. - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); - - /// Add a directory watch, allowing customization with options - /// @param directory The folder to be watched - /// @param watcher The listener to receive events - /// @param recursive Set this to true to include subdirectories - /// @param options Allows customization of a watcher - /// @return Returns the watch id for the directory or, on error, a WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector &options ); - - /// Remove a directory watch. This is a brute force search O(nlogn). - void removeWatch( const std::string& directory ); - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ); - - /// Starts watching ( in other thread ) - void watch(); - - /// @return Returns a list of the directories that are being watched - std::vector directories(); - - /** Allow recursive watchers to follow symbolic links to other directories - * followSymlinks is disabled by default - */ - void followSymlinks( bool follow ); - - /** @return If can follow symbolic links to directorioes */ - const bool& followSymlinks() const; - - /** When enable this it will allow symlinks to watch recursively out of the pointed directory. - * follorSymlinks must be enabled to this work. - * For example, added symlink to /home/folder, and the symlink points to /, this by default is - * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid - * great levels of recursion. Enabling this could lead in infinite recursion, and crash the - * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow - * this behavior. allowOutOfScopeLinks are disabled by default. - */ - void allowOutOfScopeLinks( bool allow ); - - /// @return Returns if out of scope links are allowed - const bool& allowOutOfScopeLinks() const; - - private: - /// The implementation - FileWatcherImpl* mImpl; - bool mFollowSymlinks; - bool mOutOfScopeLinks; -}; - -/// Basic interface for listening for file events. -/// @class FileWatchListener -class FileWatchListener { - public: - virtual ~FileWatchListener() {} - - /// Handles the action file action - /// @param watchid The watch id for the directory - /// @param dir The directory - /// @param filename The filename that was accessed (not full path) - /// @param action Action that was performed - /// @param oldFilename The name of the file or directory moved - virtual void handleFileAction( WatchID watchid, const std::string& dir, - const std::string& filename, Action action, - std::string oldFilename = "" ) = 0; -}; - -/// Optional, typically platform specific parameter for customization of a watcher. -/// @class WatcherOption -class WatcherOption { - public: - WatcherOption(Option option, int value) : mOption(option), mValue(value) {}; - Option mOption; - int mValue; -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/premake4.lua b/vendor/efsw/premake4.lua deleted file mode 100644 index 2918390..0000000 --- a/vendor/efsw/premake4.lua +++ /dev/null @@ -1,235 +0,0 @@ -newoption { trigger = "verbose", description = "Build efsw with verbose mode." } -newoption { trigger = "strip-symbols", description = "Strip debugging symbols in other file ( only for relwithdbginfo configuration )." } -newoption { trigger = "thread-sanitizer", description ="Compile with ThreadSanitizer." } - -efsw_major_version = "1" -efsw_minor_version = "0" -efsw_patch_version = "2" -efsw_version = efsw_major_version .. "." .. efsw_minor_version .. "." .. efsw_patch_version - -function get_include_paths() - local function _insert_include_paths( file ) - local function _trim(s) - return (s:gsub("^%s*(.-)%s*$", "%1")) - end - - local paths = { } - local lines = file:read('*all') - - for line in string.gmatch(lines, '([^\n]+)') - do - table.insert( paths, _trim( line ) ) - end - - file:close() - - return paths - end - - local file = io.popen( "echo | gcc -Wp,-v -x c++ - -fsyntax-only 2>&1 | grep -v '#' | grep '/'", 'r' ) - local include_paths = _insert_include_paths( file ) - - if next(include_paths) == nil then - file = io.popen( "echo | clang++ -Wp,-v -x c++ - -fsyntax-only 2>&1 | grep -v '#' | grep '/' | grep -v 'nonexistent'", 'r' ) - - include_paths = _insert_include_paths( file ) - - if next(include_paths) == nil then - table.insert( include_paths, "/usr/include" ) - table.insert( include_paths, "/usr/local/include" ) - end - end - - return include_paths -end - -function inotify_header_exists() - local efsw_include_paths = get_include_paths() - - for _,v in pairs( efsw_include_paths ) - do - local cur_path = v .. "/sys/inotify.h" - - if os.isfile( cur_path ) then - return true - end - end - - return false -end - -function string.starts(String,Start) - if ( _ACTION ) then - return string.sub(String,1,string.len(Start))==Start - end - - return false -end - -function is_vs() - return ( string.starts(_ACTION,"vs") ) -end - -function conf_warnings() - if not is_vs() then - buildoptions{ "-Wall -Wno-long-long" } - - if not os.is("windows") then - buildoptions{ "-fPIC" } - end - else - defines { "_SCL_SECURE_NO_WARNINGS" } - end - - if _OPTIONS["thread-sanitizer"] then - buildoptions { "-fsanitize=thread" } - linkoptions { "-fsanitize=thread" } - if not os.is("macosx") then - links { "tsan" } - end - end -end - -function conf_links() - if not os.is("windows") and not os.is("haiku") then - links { "pthread" } - end - - if os.is("macosx") then - links { "CoreFoundation.framework", "CoreServices.framework" } - end -end - -function conf_excludes() - if os.is("windows") then - excludes { "src/efsw/WatcherKqueue.cpp", "src/efsw/WatcherFSEvents.cpp", "src/efsw/WatcherInotify.cpp", "src/efsw/FileWatcherKqueue.cpp", "src/efsw/FileWatcherInotify.cpp", "src/efsw/FileWatcherFSEvents.cpp" } - elseif os.is("linux") then - excludes { "src/efsw/WatcherKqueue.cpp", "src/efsw/WatcherFSEvents.cpp", "src/efsw/WatcherWin32.cpp", "src/efsw/FileWatcherKqueue.cpp", "src/efsw/FileWatcherWin32.cpp", "src/efsw/FileWatcherFSEvents.cpp" } - elseif os.is("macosx") then - excludes { "src/efsw/WatcherInotify.cpp", "src/efsw/WatcherWin32.cpp", "src/efsw/FileWatcherInotify.cpp", "src/efsw/FileWatcherWin32.cpp" } - elseif os.is("freebsd") then - excludes { "src/efsw/WatcherInotify.cpp", "src/efsw/WatcherWin32.cpp", "src/efsw/WatcherFSEvents.cpp", "src/efsw/FileWatcherInotify.cpp", "src/efsw/FileWatcherWin32.cpp", "src/efsw/FileWatcherFSEvents.cpp" } - end - - if os.is("linux") and not inotify_header_exists() then - defines { "EFSW_INOTIFY_NOSYS" } - end -end - -solution "efsw" - location("./make/" .. os.get() .. "/") - targetdir("./bin") - configurations { "debug", "release", "relwithdbginfo" } - - if os.is("windows") then - osfiles = "src/efsw/platform/win/*.cpp" - else - osfiles = "src/efsw/platform/posix/*.cpp" - end - - -- Activates verbose mode - if _OPTIONS["verbose"] then - defines { "EFSW_VERBOSE" } - end - - if not is_vs() then - buildoptions { "-std=c++11" } - end - - if os.is("macosx") then - -- Premake 4.4 needed for this - if not string.match(_PREMAKE_VERSION, "^4.[123]") then - local ver = os.getversion(); - - if not ( ver.majorversion >= 10 and ver.minorversion >= 5 ) then - defines { "EFSW_FSEVENTS_NOT_SUPPORTED" } - end - end - end - - objdir("obj/" .. os.get() .. "/") - - project "efsw-static-lib" - kind "StaticLib" - language "C++" - targetdir("./lib") - includedirs { "include", "src" } - files { "src/efsw/*.cpp", osfiles } - conf_excludes() - - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } - targetname "efsw-static-debug" - conf_warnings() - - configuration "release" - defines { "NDEBUG" } - flags { "Optimize" } - targetname "efsw-static-release" - conf_warnings() - - configuration "relwithdbginfo" - defines { "NDEBUG" } - flags { "Optimize", "Symbols" } - targetname "efsw-static-reldbginfo" - conf_warnings() - - project "efsw-test" - kind "ConsoleApp" - language "C++" - links { "efsw-static-lib" } - files { "src/test/*.cpp" } - includedirs { "include", "src" } - conf_links() - - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } - targetname "efsw-test-debug" - conf_warnings() - - configuration "release" - defines { "NDEBUG" } - flags { "Optimize" } - targetname "efsw-test-release" - conf_warnings() - - configuration "relwithdbginfo" - defines { "NDEBUG" } - flags { "Optimize", "Symbols" } - targetname "efsw-test-reldbginfo" - conf_warnings() - - project "efsw-shared-lib" - kind "SharedLib" - language "C++" - targetdir("./lib") - includedirs { "include", "src" } - files { "src/efsw/*.cpp", osfiles } - defines { "EFSW_DYNAMIC", "EFSW_EXPORTS" } - conf_excludes() - conf_links() - - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } - targetname "efsw-debug" - conf_warnings() - - configuration "release" - defines { "NDEBUG" } - flags { "Optimize" } - targetname "efsw" - conf_warnings() - - configuration "relwithdbginfo" - defines { "NDEBUG" } - flags { "Optimize", "Symbols" } - targetname "efsw" - conf_warnings() - - if os.is("linux") or os.is("bsd") or os.is("haiku") then - targetextension ( ".so." .. efsw_version ) - postbuildcommands { "sh ../../project/build.reldbginfo.sh " .. efsw_major_version .. " " .. efsw_minor_version .. " " .. efsw_patch_version .. " " .. iif( _OPTIONS["strip-symbols"], "strip-symbols", "" ) } - end diff --git a/vendor/efsw/premake5.lua b/vendor/efsw/premake5.lua deleted file mode 100644 index 9f993b1..0000000 --- a/vendor/efsw/premake5.lua +++ /dev/null @@ -1,238 +0,0 @@ -newoption { trigger = "verbose", description = "Build efsw with verbose mode." } -newoption { trigger = "strip-symbols", description = "Strip debugging symbols in other file ( only for relwithdbginfo configuration )." } -newoption { trigger = "thread-sanitizer", description ="Compile with ThreadSanitizer" } - -efsw_major_version = "1" -efsw_minor_version = "0" -efsw_patch_version = "2" -efsw_version = efsw_major_version .. "." .. efsw_minor_version .. "." .. efsw_patch_version - -function get_include_paths() - local function _insert_include_paths( file ) - local function _trim(s) - return (s:gsub("^%s*(.-)%s*$", "%1")) - end - - local paths = { } - local lines = file:read('*all') - - for line in string.gmatch(lines, '([^\n]+)') - do - table.insert( paths, _trim( line ) ) - end - - file:close() - - return paths - end - - local file = io.popen( "echo | gcc -Wp,-v -x c++ - -fsyntax-only 2>&1 | grep -v '#' | grep '/'", 'r' ) - local include_paths = _insert_include_paths( file ) - - if next(include_paths) == nil then - file = io.popen( "echo | clang++ -Wp,-v -x c++ - -fsyntax-only 2>&1 | grep -v '#' | grep '/' | grep -v 'nonexistent'", 'r' ) - - include_paths = _insert_include_paths( file ) - - if next(include_paths) == nil then - table.insert( include_paths, "/usr/include" ) - table.insert( include_paths, "/usr/local/include" ) - end - end - - return include_paths -end - -function inotify_header_exists() - local efsw_include_paths = get_include_paths() - - for _,v in pairs( efsw_include_paths ) - do - local cur_path = v .. "/sys/inotify.h" - - if os.isfile( cur_path ) then - return true - end - end - - return false -end - -function string.starts(String,Start) - if ( _ACTION ) then - return string.sub(String,1,string.len(Start))==Start - end - - return false -end - -function is_vs() - return ( string.starts(_ACTION,"vs") ) -end - -function conf_warnings() - if not is_vs() then - buildoptions{ "-Wall -Wno-long-long" } - - if not os.istarget("windows") then - buildoptions{ "-fPIC" } - end - else - defines { "_SCL_SECURE_NO_WARNINGS" } - end - - if _OPTIONS["thread-sanitizer"] then - buildoptions { "-fsanitize=thread" } - linkoptions { "-fsanitize=thread" } - if not os.istarget("macosx") then - links { "tsan" } - end - end -end - -function conf_links() - if not os.istarget("windows") and not os.istarget("haiku") then - links { "pthread" } - end - - if os.istarget("macosx") then - links { "CoreFoundation.framework", "CoreServices.framework" } - end -end - -function conf_excludes() - if os.istarget("windows") then - excludes { "src/efsw/WatcherKqueue.cpp", "src/efsw/WatcherFSEvents.cpp", "src/efsw/WatcherInotify.cpp", "src/efsw/FileWatcherKqueue.cpp", "src/efsw/FileWatcherInotify.cpp", "src/efsw/FileWatcherFSEvents.cpp" } - elseif os.istarget("linux") then - excludes { "src/efsw/WatcherKqueue.cpp", "src/efsw/WatcherFSEvents.cpp", "src/efsw/WatcherWin32.cpp", "src/efsw/FileWatcherKqueue.cpp", "src/efsw/FileWatcherWin32.cpp", "src/efsw/FileWatcherFSEvents.cpp" } - elseif os.istarget("macosx") then - excludes { "src/efsw/WatcherInotify.cpp", "src/efsw/WatcherWin32.cpp", "src/efsw/FileWatcherInotify.cpp", "src/efsw/FileWatcherWin32.cpp" } - elseif os.istarget("bsd") then - excludes { "src/efsw/WatcherInotify.cpp", "src/efsw/WatcherWin32.cpp", "src/efsw/WatcherFSEvents.cpp", "src/efsw/FileWatcherInotify.cpp", "src/efsw/FileWatcherWin32.cpp", "src/efsw/FileWatcherFSEvents.cpp" } - end - - if os.istarget("linux") and not inotify_header_exists() then - defines { "EFSW_INOTIFY_NOSYS" } - end -end - -workspace "efsw" - location("./make/" .. os.target() .. "/") - targetdir("./bin") - configurations { "debug", "release", "relwithdbginfo" } - platforms { "x86_64", "x86", "ARM", "ARM64" } - - if os.istarget("windows") then - osfiles = "src/efsw/platform/win/*.cpp" - else - osfiles = "src/efsw/platform/posix/*.cpp" - end - - -- Activates verbose mode - if _OPTIONS["verbose"] then - defines { "EFSW_VERBOSE" } - end - - cppdialect "C++11" - - objdir("obj/" .. os.target() .. "/") - - filter "platforms:x86" - architecture "x86" - - filter "platforms:x86_64" - architecture "x86_64" - - filter "platforms:arm" - architecture "ARM" - - filter "platforms:arm64" - architecture "ARM64" - - project "efsw-static-lib" - kind "StaticLib" - language "C++" - targetdir("./lib") - includedirs { "include", "src" } - files { "src/efsw/*.cpp", osfiles } - conf_excludes() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-static-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw-static-release" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - targetname "efsw-static-reldbginfo" - conf_warnings() - - project "efsw-test" - kind "ConsoleApp" - language "C++" - links { "efsw-static-lib" } - files { "src/test/*.cpp" } - includedirs { "include", "src" } - conf_links() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-test-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw-test-release" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - targetname "efsw-test-reldbginfo" - conf_warnings() - - project "efsw-shared-lib" - kind "SharedLib" - language "C++" - targetdir("./lib") - includedirs { "include", "src" } - files { "src/efsw/*.cpp", osfiles } - defines { "EFSW_DYNAMIC", "EFSW_EXPORTS" } - conf_excludes() - conf_links() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - targetname "efsw" - conf_warnings() - - if os.istarget("linux") or os.istarget("bsd") or os.istarget("haiku") then - targetextension ( ".so." .. efsw_version ) - postbuildcommands { "sh ../../project/build.reldbginfo.sh " .. efsw_major_version .. " " .. efsw_minor_version .. " " .. efsw_patch_version .. " " .. iif( _OPTIONS["strip-symbols"], "strip-symbols", "" ) } - end diff --git a/vendor/efsw/project/build.reldbginfo.sh b/vendor/efsw/project/build.reldbginfo.sh deleted file mode 100644 index 5ec272b..0000000 --- a/vendor/efsw/project/build.reldbginfo.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -cd ../../lib -ln -fs libefsw.so.$1.$2.$3 libefsw.so.$1 -ln -fs libefsw.so.$1 libefsw.so - -if [ "$4" == "strip-symbols" ]; then - objcopy --only-keep-debug libefsw.so.$1.$2.$3 libefsw.debug - objcopy --strip-debug libefsw.so.$1.$2.$3 -fi diff --git a/vendor/efsw/project/qtcreator-linux/efsw.cflags b/vendor/efsw/project/qtcreator-linux/efsw.cflags deleted file mode 100644 index 5905d6d..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.cflags +++ /dev/null @@ -1 +0,0 @@ --std=c11 diff --git a/vendor/efsw/project/qtcreator-linux/efsw.config b/vendor/efsw/project/qtcreator-linux/efsw.config deleted file mode 100644 index 8cec188..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.config +++ /dev/null @@ -1 +0,0 @@ -// ADD PREDEFINED MACROS HERE! diff --git a/vendor/efsw/project/qtcreator-linux/efsw.creator b/vendor/efsw/project/qtcreator-linux/efsw.creator deleted file mode 100644 index e94cbbd..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.creator +++ /dev/null @@ -1 +0,0 @@ -[General] diff --git a/vendor/efsw/project/qtcreator-linux/efsw.creator.user b/vendor/efsw/project/qtcreator-linux/efsw.creator.user deleted file mode 100644 index 0bcd422..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.creator.user +++ /dev/null @@ -1,344 +0,0 @@ - - - - - - EnvironmentId - {d43f4693-30c1-436c-b1d1-498aab2c2f8c} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - - Nim - - NimGlobal - - - 3 - UTF-8 - false - 4 - false - 80 - true - true - 1 - false - true - false - 0 - true - true - 0 - 8 - true - false - 1 - true - true - true - *.md, *.MD, Makefile - false - true - true - - - - ProjectExplorer.Project.PluginSettings - - - true - false - true - true - true - true - - - 0 - true - - true - Builtin.BuildSystem - - false - false - - 0 - - - - true - - false - - - - true - - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - Desktop - {6d057187-158a-4883-8d5b-d470a6b6b025} - 1 - 0 - 0 - - ../../make/linux - - - true - gmake2 - premake5 - %{buildDir}../../../ - ProjectExplorer.ProcessStep - - - -j24 -e config=release_x86_64 - make - true - GenericProjectManager.GenericMakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - clean - - -e config=release_x86_64 - true - GenericProjectManager.GenericMakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - release - GenericProjectManager.GenericBuildConfiguration - - - ../../make/linux - - - true - --thread-sanitizer --verbose gmake2 - premake5 - %{buildDir}../../../ - ProjectExplorer.ProcessStep - - - -j24 - make - true - GenericProjectManager.GenericMakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - clean - - -e config=debug_x86_64 - true - GenericProjectManager.GenericMakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - debug - GenericProjectManager.GenericBuildConfiguration - - - ../../make/linux - - - true - gmake2 - premake5 - %{buildDir}../../../ - ProjectExplorer.ProcessStep - - - -e config=relwithdbginfo_x86_64 - make - true - GenericProjectManager.GenericMakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - clean - - -e config=relwithdbginfo_x86_64 - true - GenericProjectManager.GenericMakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - relwithdbginfo - GenericProjectManager.GenericBuildConfiguration - - 3 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - 1 - - dwarf - - cpu-cycles - - -F - true - 0 - true - true - - 2 - - %{buildDir}/../../bin/efsw-test-debug - debug - ProjectExplorer.CustomExecutableRunConfiguration - - /home/programming/thebricks/fe/ - true - false - false - true - true - %{buildDir}../../../ - - - dwarf - - cpu-cycles - - -F - true - 0 - true - true - - 2 - - %{buildDir}../../../bin/efsw-test-release - release - ProjectExplorer.CustomExecutableRunConfiguration - - true - false - false - true - true - %{buildDir}../../../ - - - dwarf - - cpu-cycles - - -F - true - 0 - true - true - - 2 - - %{buildDir}../../../bin/efsw-test-dbginfo - reldbginfo - ProjectExplorer.CustomExecutableRunConfiguration - - true - false - false - true - true - %{buildDir}../../../ - - 3 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/vendor/efsw/project/qtcreator-linux/efsw.cxxflags b/vendor/efsw/project/qtcreator-linux/efsw.cxxflags deleted file mode 100644 index c24e3b5..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.cxxflags +++ /dev/null @@ -1 +0,0 @@ --std=c++11 diff --git a/vendor/efsw/project/qtcreator-linux/efsw.files b/vendor/efsw/project/qtcreator-linux/efsw.files deleted file mode 100644 index 2eb9989..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.files +++ /dev/null @@ -1,118 +0,0 @@ -../../CMakeLists.txt -../../include/efsw/efsw.hpp -../../premake5.lua -../../src/efsw/Atomic.hpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/Thread.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/System.cpp -../../src/efsw/platform/platformimpl.hpp -../../src/efsw/platform/posix/ThreadImpl.hpp -../../src/efsw/platform/posix/MutexImpl.hpp -../../src/efsw/platform/posix/SystemImpl.hpp -../../src/efsw/platform/posix/ThreadImpl.cpp -../../src/efsw/platform/posix/MutexImpl.cpp -../../src/efsw/platform/posix/SystemImpl.cpp -../../src/efsw/platform/win/ThreadImpl.hpp -../../src/efsw/platform/win/MutexImpl.hpp -../../src/efsw/platform/win/SystemImpl.hpp -../../src/efsw/platform/win/ThreadImpl.cpp -../../src/efsw/platform/win/MutexImpl.cpp -../../src/efsw/platform/win/SystemImpl.cpp -../../src/efsw/base.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/platform/posix/FileSystemImpl.hpp -../../src/efsw/platform/posix/FileSystemImpl.cpp -../../src/efsw/platform/win/FileSystemImpl.hpp -../../src/efsw/platform/win/FileSystemImpl.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/base.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/sophist.h -../../src/efsw/base.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/Utf.inl -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/test/efsw-test.cpp -../../premake4.lua -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/Debug.hpp -../../src/efsw/Debug.cpp -../../src/efsw/WatcherGeneric.hpp -../../src/efsw/WatcherGeneric.cpp -../../src/efsw/DirWatcherGeneric.hpp -../../src/efsw/DirWatcherGeneric.cpp -../../src/efsw/Log.cpp -../../src/efsw/WatcherInotify.hpp -../../src/efsw/WatcherInotify.cpp -../../src/efsw/FileWatcherImpl.cpp -../../src/efsw/DirectorySnapshot.hpp -../../src/efsw/DirectorySnapshot.cpp -../../src/efsw/DirectorySnapshotDiff.hpp -../../src/efsw/DirectorySnapshotDiff.cpp -../../src/efsw/WatcherFSEvents.hpp -../../src/efsw/FileWatcherFSEvents.hpp -../../src/efsw/WatcherFSEvents.cpp -../../src/efsw/FileWatcherFSEvents.cpp -../../src/efsw/Watcher.hpp -../../src/efsw/Watcher.cpp -../../src/efsw/WatcherWin32.hpp -../../src/efsw/WatcherWin32.cpp -../../README.md -../../include/efsw/efsw.h -../../src/efsw/FileWatcherCWrapper.cpp -../../src/efsw/inotify-nosys.h diff --git a/vendor/efsw/project/qtcreator-linux/efsw.includes b/vendor/efsw/project/qtcreator-linux/efsw.includes deleted file mode 100644 index 1ab792a..0000000 --- a/vendor/efsw/project/qtcreator-linux/efsw.includes +++ /dev/null @@ -1,2 +0,0 @@ -../../include -../../src diff --git a/vendor/efsw/project/qtcreator-osx/efsw.cflags b/vendor/efsw/project/qtcreator-osx/efsw.cflags deleted file mode 100644 index 68d5165..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.cflags +++ /dev/null @@ -1 +0,0 @@ --std=c17 \ No newline at end of file diff --git a/vendor/efsw/project/qtcreator-osx/efsw.config b/vendor/efsw/project/qtcreator-osx/efsw.config deleted file mode 100644 index 685bb2d..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.config +++ /dev/null @@ -1,3 +0,0 @@ -// ADD PREDEFINED MACROS HERE! -#define EFSW_FSEVENTS_SUPPORTED -#define EFSW_USE_CXX11 diff --git a/vendor/efsw/project/qtcreator-osx/efsw.creator b/vendor/efsw/project/qtcreator-osx/efsw.creator deleted file mode 100644 index e94cbbd..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.creator +++ /dev/null @@ -1 +0,0 @@ -[General] diff --git a/vendor/efsw/project/qtcreator-osx/efsw.creator.user b/vendor/efsw/project/qtcreator-osx/efsw.creator.user deleted file mode 100644 index c1e8795..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.creator.user +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - EnvironmentId - {49267ae2-f136-4b84-8041-cf11a20f6a32} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - true - 80 - true - true - 1 - 0 - false - true - false - 0 - true - true - 0 - 8 - true - false - 1 - true - true - true - *.md, *.MD, Makefile - false - true - true - - - - ProjectExplorer.Project.PluginSettings - - - true - false - true - true - true - true - - - 0 - true - - true - - true - true - Builtin.DefaultTidyAndClazy - 4 - false - - - - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop (arm-darwin-generic-mach_o-64bit) - Desktop (arm-darwin-generic-mach_o-64bit) - {6d6b6d62-1e99-4e76-b5e2-cf731a0dbd92} - 0 - 0 - 0 - - ../../make/macosx/ - - - true - --file=../../premake4.lua --thread-sanitizer --verbose gmake - /usr/local/bin/premake4 - %{buildDir} - ProjectExplorer.ProcessStep - - - -j4 - true - GenericProjectManager.GenericMakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - clean - - true - GenericProjectManager.GenericMakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - debug - GenericProjectManager.GenericBuildConfiguration - - - ../../make/macosx/ - - - true - --file=../../premake4.lua gmake - /usr/local/bin/premake4 - %{buildDir} - ProjectExplorer.ProcessStep - - - -j4 config=release - true - GenericProjectManager.GenericMakeStep - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - clean - - config=release - true - GenericProjectManager.GenericMakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - release - GenericProjectManager.GenericBuildConfiguration - - 2 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - 1 - - true - 0 - true - true - - 2 - - false - /Users/prognoz/programming/efsw/bin/efsw-test-debug - debug - ProjectExplorer.CustomExecutableRunConfiguration - - true - 0 - false - 1 - false - false - %{buildDir}/../../bin - - - true - 0 - true - true - - 2 - - false - efsw-test - release - ProjectExplorer.CustomExecutableRunConfiguration - - false - 1 - false - true - false - %{buildDir}/../../bin/ - - 2 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/vendor/efsw/project/qtcreator-osx/efsw.cxxflags b/vendor/efsw/project/qtcreator-osx/efsw.cxxflags deleted file mode 100644 index 6435dfc..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.cxxflags +++ /dev/null @@ -1 +0,0 @@ --std=c++17 \ No newline at end of file diff --git a/vendor/efsw/project/qtcreator-osx/efsw.files b/vendor/efsw/project/qtcreator-osx/efsw.files deleted file mode 100644 index 0ab369f..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.files +++ /dev/null @@ -1,185 +0,0 @@ -../../include/efsw/efsw.hpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/Thread.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/System.cpp -../../src/efsw/platform/platformimpl.hpp -../../src/efsw/platform/posix/ThreadImpl.hpp -../../src/efsw/platform/posix/MutexImpl.hpp -../../src/efsw/platform/posix/SystemImpl.hpp -../../src/efsw/platform/posix/ThreadImpl.cpp -../../src/efsw/platform/posix/MutexImpl.cpp -../../src/efsw/platform/posix/SystemImpl.cpp -../../src/efsw/platform/win/ThreadImpl.hpp -../../src/efsw/platform/win/MutexImpl.hpp -../../src/efsw/platform/win/SystemImpl.hpp -../../src/efsw/platform/win/ThreadImpl.cpp -../../src/efsw/platform/win/MutexImpl.cpp -../../src/efsw/platform/win/SystemImpl.cpp -../../src/efsw/base.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/platform/posix/FileSystemImpl.hpp -../../src/efsw/platform/posix/FileSystemImpl.cpp -../../src/efsw/platform/win/FileSystemImpl.hpp -../../src/efsw/platform/win/FileSystemImpl.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/base.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/sophist.h -../../src/efsw/base.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/Utf.inl -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/test/efsw-test.cpp -../../premake4.lua -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherInotify.hpp -../../src/efsw/WatcherGeneric.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/sophist.h -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/DirWatcherGeneric.hpp -../../src/efsw/Debug.hpp -../../src/efsw/base.hpp -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/WatcherInotify.cpp -../../src/efsw/WatcherGeneric.cpp -../../src/efsw/Utf.inl -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/Log.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/DirWatcherGeneric.cpp -../../src/efsw/Debug.cpp -../../src/efsw/FileWatcherImpl.cpp -../../src/efsw/DirectorySnapshotDiff.hpp -../../src/efsw/DirectorySnapshot.hpp -../../src/efsw/DirectorySnapshotDiff.cpp -../../src/efsw/DirectorySnapshot.cpp -../../src/efsw/WatcherFSEvents.hpp -../../src/efsw/FileWatcherFSEvents.hpp -../../src/efsw/WatcherFSEvents.cpp -../../src/efsw/FileWatcherFSEvents.cpp -../../src/efsw/WatcherWin32.hpp -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherInotify.hpp -../../src/efsw/WatcherGeneric.hpp -../../src/efsw/WatcherFSEvents.hpp -../../src/efsw/Watcher.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/sophist.h -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileWatcherFSEvents.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/DirWatcherGeneric.hpp -../../src/efsw/DirectorySnapshotDiff.hpp -../../src/efsw/DirectorySnapshot.hpp -../../src/efsw/Debug.hpp -../../src/efsw/base.hpp -../../src/efsw/WatcherWin32.cpp -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/WatcherInotify.cpp -../../src/efsw/WatcherGeneric.cpp -../../src/efsw/WatcherFSEvents.cpp -../../src/efsw/Watcher.cpp -../../src/efsw/Utf.inl -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/Log.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherImpl.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcherFSEvents.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/DirWatcherGeneric.cpp -../../src/efsw/DirectorySnapshotDiff.cpp -../../src/efsw/DirectorySnapshot.cpp -../../src/efsw/Debug.cpp diff --git a/vendor/efsw/project/qtcreator-osx/efsw.includes b/vendor/efsw/project/qtcreator-osx/efsw.includes deleted file mode 100644 index 1f6e72e..0000000 --- a/vendor/efsw/project/qtcreator-osx/efsw.includes +++ /dev/null @@ -1,7 +0,0 @@ -../../src -../../include -/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1 -/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/include -/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include -/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks diff --git a/vendor/efsw/project/qtcreator-win/efsw.cflags b/vendor/efsw/project/qtcreator-win/efsw.cflags deleted file mode 100644 index 68d5165..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.cflags +++ /dev/null @@ -1 +0,0 @@ --std=c17 \ No newline at end of file diff --git a/vendor/efsw/project/qtcreator-win/efsw.config b/vendor/efsw/project/qtcreator-win/efsw.config deleted file mode 100644 index 8cec188..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.config +++ /dev/null @@ -1 +0,0 @@ -// ADD PREDEFINED MACROS HERE! diff --git a/vendor/efsw/project/qtcreator-win/efsw.creator b/vendor/efsw/project/qtcreator-win/efsw.creator deleted file mode 100644 index e94cbbd..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.creator +++ /dev/null @@ -1 +0,0 @@ -[General] diff --git a/vendor/efsw/project/qtcreator-win/efsw.creator.user b/vendor/efsw/project/qtcreator-win/efsw.creator.user deleted file mode 100644 index deadd7e..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.creator.user +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - EnvironmentId - {55fc4913-4acc-49e6-b0d5-ebf25d4d498e} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - {eb5b6178-a7a7-439e-ab01-e63b057196a1} - 0 - 0 - 0 - - C:\programming\efsw\make\windows - - - - all - - false - - - false - true - Make - - GenericProjectManager.GenericMakeStep - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - - clean - - true - - - false - true - Make - - GenericProjectManager.GenericMakeStep - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Default - Default - GenericProjectManager.GenericBuildConfiguration - - 1 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy locally - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - dwarf - - cpu-cycles - - - 250 - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - %{buildDir}\..\..\bin\efsw-test-debug.exe - Run C:\programming\efsw\bin\efsw-test-debug.exe - - ProjectExplorer.CustomExecutableRunConfiguration - - 3768 - false - true - false - false - true - %{buildDir} - - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/vendor/efsw/project/qtcreator-win/efsw.cxxflags b/vendor/efsw/project/qtcreator-win/efsw.cxxflags deleted file mode 100644 index 6435dfc..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.cxxflags +++ /dev/null @@ -1 +0,0 @@ --std=c++17 \ No newline at end of file diff --git a/vendor/efsw/project/qtcreator-win/efsw.files b/vendor/efsw/project/qtcreator-win/efsw.files deleted file mode 100644 index 8efe50d..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.files +++ /dev/null @@ -1,215 +0,0 @@ -../../include/efsw/efsw.hpp -../../premake5.lua -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/Thread.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/System.cpp -../../src/efsw/platform/platformimpl.hpp -../../src/efsw/platform/posix/ThreadImpl.hpp -../../src/efsw/platform/posix/MutexImpl.hpp -../../src/efsw/platform/posix/SystemImpl.hpp -../../src/efsw/platform/posix/ThreadImpl.cpp -../../src/efsw/platform/posix/MutexImpl.cpp -../../src/efsw/platform/posix/SystemImpl.cpp -../../src/efsw/platform/win/ThreadImpl.hpp -../../src/efsw/platform/win/MutexImpl.hpp -../../src/efsw/platform/win/SystemImpl.hpp -../../src/efsw/platform/win/ThreadImpl.cpp -../../src/efsw/platform/win/MutexImpl.cpp -../../src/efsw/platform/win/SystemImpl.cpp -../../src/efsw/base.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/platform/posix/FileSystemImpl.hpp -../../src/efsw/platform/posix/FileSystemImpl.cpp -../../src/efsw/platform/win/FileSystemImpl.hpp -../../src/efsw/platform/win/FileSystemImpl.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/base.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/sophist.h -../../src/efsw/base.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/Utf.inl -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/test/efsw-test.cpp -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherInotify.hpp -../../src/efsw/WatcherGeneric.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/DirWatcherGeneric.hpp -../../src/efsw/Debug.hpp -../../src/efsw/base.hpp -../../src/efsw/sophist.h -../../src/efsw/Utf.inl -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/WatcherInotify.cpp -../../src/efsw/WatcherGeneric.cpp -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/Log.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/DirWatcherGeneric.cpp -../../src/efsw/Debug.cpp -../../premake4.lua -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherInotify.hpp -../../src/efsw/WatcherGeneric.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/sophist.h -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/DirWatcherGeneric.hpp -../../src/efsw/Debug.hpp -../../src/efsw/base.hpp -../../src/efsw/Utf.inl -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/WatcherInotify.cpp -../../src/efsw/WatcherGeneric.cpp -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/Log.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherImpl.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/DirWatcherGeneric.cpp -../../src/efsw/Debug.cpp -../../src/efsw/WatcherWin32.hpp -../../src/efsw/WatcherKqueue.hpp -../../src/efsw/WatcherInotify.hpp -../../src/efsw/WatcherGeneric.hpp -../../src/efsw/WatcherFSEvents.hpp -../../src/efsw/Watcher.hpp -../../src/efsw/Utf.hpp -../../src/efsw/Thread.hpp -../../src/efsw/System.hpp -../../src/efsw/String.hpp -../../src/efsw/sophist.h -../../src/efsw/Mutex.hpp -../../src/efsw/FileWatcherWin32.hpp -../../src/efsw/FileWatcherKqueue.hpp -../../src/efsw/FileWatcherInotify.hpp -../../src/efsw/FileWatcherImpl.hpp -../../src/efsw/FileWatcherGeneric.hpp -../../src/efsw/FileWatcherFSEvents.hpp -../../src/efsw/FileSystem.hpp -../../src/efsw/FileInfo.hpp -../../src/efsw/DirWatcherGeneric.hpp -../../src/efsw/DirectorySnapshotDiff.hpp -../../src/efsw/DirectorySnapshot.hpp -../../src/efsw/Debug.hpp -../../src/efsw/base.hpp -../../src/efsw/Utf.inl -../../src/efsw/WatcherWin32.cpp -../../src/efsw/WatcherKqueue.cpp -../../src/efsw/WatcherInotify.cpp -../../src/efsw/WatcherGeneric.cpp -../../src/efsw/WatcherFSEvents.cpp -../../src/efsw/Watcher.cpp -../../src/efsw/Thread.cpp -../../src/efsw/System.cpp -../../src/efsw/String.cpp -../../src/efsw/Mutex.cpp -../../src/efsw/Log.cpp -../../src/efsw/FileWatcherWin32.cpp -../../src/efsw/FileWatcherKqueue.cpp -../../src/efsw/FileWatcherInotify.cpp -../../src/efsw/FileWatcherImpl.cpp -../../src/efsw/FileWatcherGeneric.cpp -../../src/efsw/FileWatcherFSEvents.cpp -../../src/efsw/FileWatcher.cpp -../../src/efsw/FileSystem.cpp -../../src/efsw/FileInfo.cpp -../../src/efsw/DirWatcherGeneric.cpp -../../src/efsw/DirectorySnapshotDiff.cpp -../../src/efsw/DirectorySnapshot.cpp -../../src/efsw/Debug.cpp -../../include/efsw/efsw.h -../../src/efsw/FileWatcherCWrapper.cpp diff --git a/vendor/efsw/project/qtcreator-win/efsw.includes b/vendor/efsw/project/qtcreator-win/efsw.includes deleted file mode 100644 index 0eeab56..0000000 --- a/vendor/efsw/project/qtcreator-win/efsw.includes +++ /dev/null @@ -1,2 +0,0 @@ -../../src -../../include diff --git a/vendor/efsw/src/efsw/Atomic.hpp b/vendor/efsw/src/efsw/Atomic.hpp deleted file mode 100644 index 9015c60..0000000 --- a/vendor/efsw/src/efsw/Atomic.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EFSW_ATOMIC_BOOL_HPP -#define EFSW_ATOMIC_BOOL_HPP - -#include - -#include - -namespace efsw { - -template class Atomic { - public: - explicit Atomic( T set = false ) : set_( set ) {} - - Atomic& operator=( T set ) { - set_.store( set, std::memory_order_release ); - return *this; - } - - explicit operator T() const { - return set_.load( std::memory_order_acquire ); - } - - T load() const { - return set_.load( std::memory_order_acquire ); - } - - private: - std::atomic set_; -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/Debug.cpp b/vendor/efsw/src/efsw/Debug.cpp deleted file mode 100644 index 18cfd31..0000000 --- a/vendor/efsw/src/efsw/Debug.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include - -#ifdef EFSW_COMPILER_MSVC -#define WIN32_LEAN_AND_MEAN -#include -#include -#endif - -#include -#include -#include - -namespace efsw { - -#ifdef DEBUG - -void efREPORT_ASSERT( const char* File, int Line, const char* Exp ) { -#ifdef EFSW_COMPILER_MSVC - _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp ); - - DebugBreak(); -#else - std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl; - -#if defined( EFSW_COMPILER_GCC ) && defined( EFSW_32BIT ) && !defined( EFSW_ARM ) - asm( "int3" ); -#else - assert( false ); -#endif -#endif -} - -void efPRINT( const char* format, ... ) { - char buf[2048]; - va_list args; - - va_start( args, format ); - -#ifdef EFSW_COMPILER_MSVC - _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0] ), format, args ); -#else - vsnprintf( buf, sizeof( buf ) / sizeof( buf[0] ), format, args ); -#endif - - va_end( args ); - -#ifdef EFSW_COMPILER_MSVC - OutputDebugStringA( buf ); -#else - std::cout << buf; -#endif -} - -void efPRINTC( unsigned int cond, const char* format, ... ) { - if ( 0 == cond ) - return; - - char buf[2048]; - va_list args; - - va_start( args, format ); - -#ifdef EFSW_COMPILER_MSVC - _vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args ); -#else - vsnprintf( buf, sizeof( buf ) / sizeof( buf[0] ), format, args ); -#endif - - va_end( args ); - -#ifdef EFSW_COMPILER_MSVC - OutputDebugStringA( buf ); -#else - std::cout << buf; -#endif -} - -#endif - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/Debug.hpp b/vendor/efsw/src/efsw/Debug.hpp deleted file mode 100644 index fefaec4..0000000 --- a/vendor/efsw/src/efsw/Debug.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef EFSW_DEBUG_HPP -#define EFSW_DEBUG_HPP - -#include - -namespace efsw { - -#ifdef DEBUG - -void efREPORT_ASSERT( const char* File, const int Line, const char* Exp ); - -#define efASSERT( expr ) \ - if ( !( expr ) ) { \ - efREPORT_ASSERT( __FILE__, __LINE__, #expr ); \ - } -#define efASSERTM( expr, msg ) \ - if ( !( expr ) ) { \ - efREPORT_ASSERT( __FILE__, __LINE__, #msg ); \ - } - -void efPRINT( const char* format, ... ); -void efPRINTC( unsigned int cond, const char* format, ... ); - -#else - -#define efASSERT( expr ) -#define efASSERTM( expr, msg ) - -#ifndef EFSW_COMPILER_MSVC -#define efPRINT( format, args... ) \ - {} -#define efPRINTC( cond, format, args... ) \ - {} -#else -#define efPRINT -#define efPRINTC -#endif - -#endif - -#ifdef EFSW_VERBOSE -#define efDEBUG efPRINT -#define efDEBUGC efPRINTC -#else - -#ifndef EFSW_COMPILER_MSVC -#define efDEBUG( format, args... ) \ - {} -#define efDEBUGC( cond, format, args... ) \ - {} -#else -#define efDEBUG( ... ) \ - {} -#define efDEBUGC( ... ) \ - {} -#endif - -#endif - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/DirWatcherGeneric.cpp b/vendor/efsw/src/efsw/DirWatcherGeneric.cpp deleted file mode 100644 index 8b6bc8a..0000000 --- a/vendor/efsw/src/efsw/DirWatcherGeneric.cpp +++ /dev/null @@ -1,388 +0,0 @@ -#include -#include -#include -#include - -namespace efsw { - -DirWatcherGeneric::DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws, - const std::string& directory, bool recursive, - bool reportNewFiles ) : - Parent( parent ), Watch( ws ), Recursive( recursive ), Deleted( false ) { - resetDirectory( directory ); - - if ( !reportNewFiles ) { - DirSnap.scan(); - } else { - DirectorySnapshotDiff Diff = DirSnap.scan(); - - if ( Diff.changed() ) { - FileInfoList::iterator it; - - DiffIterator( FilesCreated ) { - handleAction( ( *it ).Filepath, Actions::Add ); - } - } - } -} - -DirWatcherGeneric::~DirWatcherGeneric() { - /// If the directory was deleted mark the files as deleted - if ( Deleted ) { - DirectorySnapshotDiff Diff = DirSnap.scan(); - - if ( !DirSnap.exists() ) { - FileInfoList::iterator it; - - DiffIterator( FilesDeleted ) { - handleAction( ( *it ).Filepath, Actions::Delete ); - } - - DiffIterator( DirsDeleted ) { - handleAction( ( *it ).Filepath, Actions::Delete ); - } - } - } - - DirWatchMap::iterator it = Directories.begin(); - - for ( ; it != Directories.end(); ++it ) { - if ( Deleted ) { - /// If the directory was deleted, mark the flag for file deletion - it->second->Deleted = true; - } - - efSAFE_DELETE( it->second ); - } -} - -void DirWatcherGeneric::resetDirectory( std::string directory ) { - std::string dir( directory ); - - /// Is this a recursive watch? - if ( Watch->Directory != directory ) { - if ( !( directory.size() && - ( directory.at( 0 ) == FileSystem::getOSSlash() || - directory.at( directory.size() - 1 ) == FileSystem::getOSSlash() ) ) ) { - /// Get the real directory - if ( NULL != Parent ) { - std::string parentPath( Parent->DirSnap.DirectoryInfo.Filepath ); - FileSystem::dirAddSlashAtEnd( parentPath ); - FileSystem::dirAddSlashAtEnd( directory ); - - dir = parentPath + directory; - } else { - efDEBUG( "resetDirectory(): Parent is NULL. Fatal error." ); - } - } - } - - DirSnap.setDirectoryInfo( dir ); -} - -void DirWatcherGeneric::handleAction( const std::string& filename, unsigned long action, - std::string oldFilename ) { - Watch->Listener->handleFileAction( Watch->ID, DirSnap.DirectoryInfo.Filepath, - FileSystem::fileNameFromPath( filename ), (Action)action, - oldFilename ); -} - -void DirWatcherGeneric::addChilds( bool reportNewFiles ) { - if ( Recursive ) { - /// Create the subdirectories watchers - std::string dir; - - for ( FileInfoMap::iterator it = DirSnap.Files.begin(); it != DirSnap.Files.end(); it++ ) { - if ( it->second.isDirectory() && it->second.isReadable() && - !FileSystem::isRemoteFS( it->second.Filepath ) ) { - /// Check if the directory is a symbolic link - std::string curPath; - std::string link( FileSystem::getLinkRealPath( it->second.Filepath, curPath ) ); - - dir = it->first; - - if ( "" != link ) { - /// Avoid adding symlinks directories if it's now enabled - if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) { - continue; - } - - /// If it's a symlink check if the realpath exists as a watcher, or - /// if the path is outside the current dir - if ( Watch->WatcherImpl->pathInWatches( link ) || - Watch->pathInWatches( link ) || - !Watch->WatcherImpl->linkAllowed( curPath, link ) ) { - continue; - } else { - dir = link; - } - } else { - if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) { - continue; - } - } - - if ( reportNewFiles ) { - handleAction( dir, Actions::Add ); - } - - Directories[dir] = - new DirWatcherGeneric( this, Watch, dir, Recursive, reportNewFiles ); - - Directories[dir]->addChilds( reportNewFiles ); - } - } - } -} - -void DirWatcherGeneric::watch( bool reportOwnChange ) { - DirectorySnapshotDiff Diff = DirSnap.scan(); - - if ( reportOwnChange && Diff.DirChanged && NULL != Parent ) { - Watch->Listener->handleFileAction( - Watch->ID, FileSystem::pathRemoveFileName( DirSnap.DirectoryInfo.Filepath ), - FileSystem::fileNameFromPath( DirSnap.DirectoryInfo.Filepath ), Actions::Modified ); - } - - if ( Diff.changed() ) { - FileInfoList::iterator it; - MovedList::iterator mit; - - /// Files - DiffIterator( FilesCreated ) { - handleAction( ( *it ).Filepath, Actions::Add ); - } - - DiffIterator( FilesModified ) { - handleAction( ( *it ).Filepath, Actions::Modified ); - } - - DiffIterator( FilesDeleted ) { - handleAction( ( *it ).Filepath, Actions::Delete ); - } - - DiffMovedIterator( FilesMoved ) { - handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first ); - } - - /// Directories - DiffIterator( DirsCreated ) { - createDirectory( ( *it ).Filepath ); - } - - DiffIterator( DirsModified ) { - handleAction( ( *it ).Filepath, Actions::Modified ); - } - - DiffIterator( DirsDeleted ) { - handleAction( ( *it ).Filepath, Actions::Delete ); - removeDirectory( ( *it ).Filepath ); - } - - DiffMovedIterator( DirsMoved ) { - handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first ); - moveDirectory( ( *mit ).first, ( *mit ).second.Filepath ); - } - } - - /// Process the subdirectories looking for changes - for ( DirWatchMap::iterator dit = Directories.begin(); dit != Directories.end(); ++dit ) { - /// Just watch - dit->second->watch(); - } -} - -void DirWatcherGeneric::watchDir( std::string& dir ) { - DirWatcherGeneric* watcher = Watch->WatcherImpl->mFileWatcher->allowOutOfScopeLinks() - ? findDirWatcher( dir ) - : findDirWatcherFast( dir ); - - if ( NULL != watcher ) { - watcher->watch( true ); - } -} - -DirWatcherGeneric* DirWatcherGeneric::findDirWatcherFast( std::string dir ) { - // remove the common base ( dir should always start with the same base as the watcher ) - efASSERT( !dir.empty() ); - efASSERT( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ); - efASSERT( DirSnap.DirectoryInfo.Filepath == - dir.substr( 0, DirSnap.DirectoryInfo.Filepath.size() ) ); - - if ( dir.size() >= DirSnap.DirectoryInfo.Filepath.size() ) { - dir = dir.substr( DirSnap.DirectoryInfo.Filepath.size() - 1 ); - } - - if ( dir.size() == 1 ) { - efASSERT( dir[0] == FileSystem::getOSSlash() ); - return this; - } - - size_t level = 0; - std::vector dirv = String::split( dir, FileSystem::getOSSlash(), false ); - - DirWatcherGeneric* watcher = this; - - while ( level < dirv.size() ) { - // search the dir level in the current watcher - DirWatchMap::iterator it = watcher->Directories.find( dirv[level] ); - - // found? continue with the next level - if ( it != watcher->Directories.end() ) { - watcher = it->second; - - level++; - } else { - // couldn't found the folder level? - // directory not watched - return NULL; - } - } - - return watcher; -} - -DirWatcherGeneric* DirWatcherGeneric::findDirWatcher( std::string dir ) { - if ( DirSnap.DirectoryInfo.Filepath == dir ) { - return this; - } else { - DirWatcherGeneric* watcher = NULL; - - for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) { - watcher = it->second->findDirWatcher( dir ); - - if ( NULL != watcher ) { - return watcher; - } - } - } - - return NULL; -} - -DirWatcherGeneric* DirWatcherGeneric::createDirectory( std::string newdir ) { - FileSystem::dirRemoveSlashAtEnd( newdir ); - newdir = FileSystem::fileNameFromPath( newdir ); - - DirWatcherGeneric* dw = NULL; - - /// Check if the directory is a symbolic link - std::string parentPath( DirSnap.DirectoryInfo.Filepath ); - FileSystem::dirAddSlashAtEnd( parentPath ); - std::string dir( parentPath + newdir ); - - FileSystem::dirAddSlashAtEnd( dir ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() || !fi.isReadable() || FileSystem::isRemoteFS( dir ) ) { - return NULL; - } - - std::string curPath; - std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - bool skip = false; - - if ( "" != link ) { - /// Avoid adding symlinks directories if it's now enabled - if ( !Watch->WatcherImpl->mFileWatcher->followSymlinks() ) { - skip = true; - } - - /// If it's a symlink check if the realpath exists as a watcher, or - /// if the path is outside the current dir - if ( Watch->WatcherImpl->pathInWatches( link ) || Watch->pathInWatches( link ) || - !Watch->WatcherImpl->linkAllowed( curPath, link ) ) { - skip = true; - } else { - dir = link; - } - } else { - if ( Watch->pathInWatches( dir ) || Watch->WatcherImpl->pathInWatches( dir ) ) { - skip = true; - } - } - - if ( !skip ) { - handleAction( newdir, Actions::Add ); - - /// Creates the new directory watcher of the subfolder and check for new files - dw = new DirWatcherGeneric( this, Watch, dir, Recursive ); - - dw->addChilds(); - - dw->watch(); - - /// Add it to the list of directories - Directories[newdir] = dw; - } - - return dw; -} - -void DirWatcherGeneric::removeDirectory( std::string dir ) { - FileSystem::dirRemoveSlashAtEnd( dir ); - dir = FileSystem::fileNameFromPath( dir ); - - DirWatcherGeneric* dw = NULL; - DirWatchMap::iterator dit; - - /// Folder deleted - - /// Search the folder, it should exists - dit = Directories.find( dir ); - - if ( dit != Directories.end() ) { - dw = dit->second; - - /// Flag it as deleted so it fire the event for every file inside deleted - dw->Deleted = true; - - /// Delete the DirWatcherGeneric - efSAFE_DELETE( dw ); - - /// Remove the directory from the map - Directories.erase( dit->first ); - } -} - -void DirWatcherGeneric::moveDirectory( std::string oldDir, std::string newDir ) { - FileSystem::dirRemoveSlashAtEnd( oldDir ); - oldDir = FileSystem::fileNameFromPath( oldDir ); - - FileSystem::dirRemoveSlashAtEnd( newDir ); - newDir = FileSystem::fileNameFromPath( newDir ); - - DirWatcherGeneric* dw = NULL; - DirWatchMap::iterator dit; - - /// Directory existed? - dit = Directories.find( oldDir ); - - if ( dit != Directories.end() ) { - dw = dit->second; - - /// Remove the directory from the map - Directories.erase( dit->first ); - - Directories[newDir] = dw; - - dw->resetDirectory( newDir ); - } -} - -bool DirWatcherGeneric::pathInWatches( std::string path ) { - if ( DirSnap.DirectoryInfo.Filepath == path ) { - return true; - } - - for ( DirWatchMap::iterator it = Directories.begin(); it != Directories.end(); ++it ) { - if ( it->second->pathInWatches( path ) ) { - return true; - } - } - - return false; -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/DirWatcherGeneric.hpp b/vendor/efsw/src/efsw/DirWatcherGeneric.hpp deleted file mode 100644 index ca52de7..0000000 --- a/vendor/efsw/src/efsw/DirWatcherGeneric.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef EFSW_DIRWATCHERGENERIC_HPP -#define EFSW_DIRWATCHERGENERIC_HPP - -#include -#include -#include -#include - -namespace efsw { - -class DirWatcherGeneric { - public: - typedef std::map DirWatchMap; - - DirWatcherGeneric* Parent; - WatcherGeneric* Watch; - DirectorySnapshot DirSnap; - DirWatchMap Directories; - bool Recursive; - - DirWatcherGeneric( DirWatcherGeneric* parent, WatcherGeneric* ws, const std::string& directory, - bool recursive, bool reportNewFiles = false ); - - ~DirWatcherGeneric(); - - void watch( bool reportOwnChange = false ); - - void watchDir( std::string& dir ); - - static bool isDir( const std::string& directory ); - - bool pathInWatches( std::string path ); - - void addChilds( bool reportNewFiles = true ); - - DirWatcherGeneric* findDirWatcher( std::string dir ); - - DirWatcherGeneric* findDirWatcherFast( std::string dir ); - - protected: - bool Deleted; - - DirWatcherGeneric* createDirectory( std::string newdir ); - - void removeDirectory( std::string dir ); - - void moveDirectory( std::string oldDir, std::string newDir ); - - void resetDirectory( std::string directory ); - - void handleAction( const std::string& filename, unsigned long action, - std::string oldFilename = "" ); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/DirectorySnapshot.cpp b/vendor/efsw/src/efsw/DirectorySnapshot.cpp deleted file mode 100644 index f78475f..0000000 --- a/vendor/efsw/src/efsw/DirectorySnapshot.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#include -#include - -namespace efsw { - -DirectorySnapshot::DirectorySnapshot() {} - -DirectorySnapshot::DirectorySnapshot( std::string directory ) { - init( directory ); -} - -DirectorySnapshot::~DirectorySnapshot() {} - -void DirectorySnapshot::init( std::string directory ) { - setDirectoryInfo( directory ); - initFiles(); -} - -bool DirectorySnapshot::exists() { - return DirectoryInfo.exists(); -} - -void DirectorySnapshot::deleteAll( DirectorySnapshotDiff& Diff ) { - FileInfo fi; - - for ( FileInfoMap::iterator it = Files.begin(); it != Files.end(); it++ ) { - fi = it->second; - - if ( fi.isDirectory() ) { - Diff.DirsDeleted.push_back( fi ); - } else { - Diff.FilesDeleted.push_back( fi ); - } - } - - Files.clear(); -} - -void DirectorySnapshot::setDirectoryInfo( std::string directory ) { - DirectoryInfo = FileInfo( directory ); -} - -void DirectorySnapshot::initFiles() { - Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); - - FileInfoMap::iterator it = Files.begin(); - std::vector eraseFiles; - - /// Remove all non regular files and non directories - for ( ; it != Files.end(); it++ ) { - if ( !it->second.isRegularFile() && !it->second.isDirectory() ) { - eraseFiles.push_back( it->first ); - } - } - - for ( std::vector::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); - eit++ ) { - Files.erase( *eit ); - } -} - -DirectorySnapshotDiff DirectorySnapshot::scan() { - DirectorySnapshotDiff Diff; - - Diff.clear(); - - FileInfo curFI( DirectoryInfo.Filepath ); - - Diff.DirChanged = DirectoryInfo != curFI; - - if ( Diff.DirChanged ) { - DirectoryInfo = curFI; - } - - /// If the directory was erased, create the events for files and directories deletion - if ( !curFI.exists() ) { - deleteAll( Diff ); - - return Diff; - } - - FileInfoMap files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); - - if ( files.empty() && Files.empty() ) { - return Diff; - } - - FileInfo fi; - FileInfoMap FilesCpy; - FileInfoMap::iterator it; - FileInfoMap::iterator fiIt; - - if ( Diff.DirChanged ) { - FilesCpy = Files; - } - - for ( it = files.begin(); it != files.end(); it++ ) { - fi = it->second; - - /// File existed before? - fiIt = Files.find( it->first ); - - if ( fiIt != Files.end() ) { - /// Erase from the file list copy - FilesCpy.erase( it->first ); - - /// File changed? - if ( ( *fiIt ).second != fi ) { - /// Update the new file info - Files[it->first] = fi; - - /// handle modified event - if ( fi.isDirectory() ) { - Diff.DirsModified.push_back( fi ); - } else { - Diff.FilesModified.push_back( fi ); - } - } - } - /// Only add regular files or directories - else if ( fi.isRegularFile() || fi.isDirectory() ) { - /// New file found - Files[it->first] = fi; - - FileInfoMap::iterator fit; - std::string oldFile = ""; - - /// Check if the same inode already existed - if ( ( fit = nodeInFiles( fi ) ) != Files.end() ) { - oldFile = fit->first; - - /// Avoid firing a Delete event - FilesCpy.erase( fit->first ); - - /// Delete the old file name - Files.erase( fit->first ); - - if ( fi.isDirectory() ) { - Diff.DirsMoved.push_back( std::make_pair( oldFile, fi ) ); - } else { - Diff.FilesMoved.push_back( std::make_pair( oldFile, fi ) ); - } - } else { - if ( fi.isDirectory() ) { - Diff.DirsCreated.push_back( fi ); - } else { - Diff.FilesCreated.push_back( fi ); - } - } - } - } - - if ( !Diff.DirChanged ) { - return Diff; - } - - /// The files or directories that remains were deleted - for ( it = FilesCpy.begin(); it != FilesCpy.end(); it++ ) { - fi = it->second; - - if ( fi.isDirectory() ) { - Diff.DirsDeleted.push_back( fi ); - } else { - Diff.FilesDeleted.push_back( fi ); - } - - /// Remove the file or directory from the list of files - Files.erase( it->first ); - } - - return Diff; -} - -FileInfoMap::iterator DirectorySnapshot::nodeInFiles( FileInfo& fi ) { - FileInfoMap::iterator it; - - if ( FileInfo::inodeSupported() ) { - for ( it = Files.begin(); it != Files.end(); it++ ) { - if ( it->second.sameInode( fi ) && it->second.Filepath != fi.Filepath ) { - return it; - } - } - } - - return Files.end(); -} - -void DirectorySnapshot::addFile( std::string path ) { - std::string name( FileSystem::fileNameFromPath( path ) ); - Files[name] = FileInfo( path ); -} - -void DirectorySnapshot::removeFile( std::string path ) { - std::string name( FileSystem::fileNameFromPath( path ) ); - - FileInfoMap::iterator it = Files.find( name ); - - if ( Files.end() != it ) { - Files.erase( it ); - } -} - -void DirectorySnapshot::moveFile( std::string oldPath, std::string newPath ) { - removeFile( oldPath ); - addFile( newPath ); -} - -void DirectorySnapshot::updateFile( std::string path ) { - addFile( path ); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/DirectorySnapshot.hpp b/vendor/efsw/src/efsw/DirectorySnapshot.hpp deleted file mode 100644 index 0e60542..0000000 --- a/vendor/efsw/src/efsw/DirectorySnapshot.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef EFSW_DIRECTORYSNAPSHOT_HPP -#define EFSW_DIRECTORYSNAPSHOT_HPP - -#include - -namespace efsw { - -class DirectorySnapshot { - public: - FileInfo DirectoryInfo; - FileInfoMap Files; - - void setDirectoryInfo( std::string directory ); - - DirectorySnapshot(); - - DirectorySnapshot( std::string directory ); - - ~DirectorySnapshot(); - - void init( std::string directory ); - - bool exists(); - - DirectorySnapshotDiff scan(); - - FileInfoMap::iterator nodeInFiles( FileInfo& fi ); - - void addFile( std::string path ); - - void removeFile( std::string path ); - - void moveFile( std::string oldPath, std::string newPath ); - - void updateFile( std::string path ); - - protected: - void initFiles(); - - void deleteAll( DirectorySnapshotDiff& Diff ); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/DirectorySnapshotDiff.cpp b/vendor/efsw/src/efsw/DirectorySnapshotDiff.cpp deleted file mode 100644 index 37ee507..0000000 --- a/vendor/efsw/src/efsw/DirectorySnapshotDiff.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include - -namespace efsw { - -void DirectorySnapshotDiff::clear() { - FilesCreated.clear(); - FilesModified.clear(); - FilesMoved.clear(); - FilesDeleted.clear(); - DirsCreated.clear(); - DirsModified.clear(); - DirsMoved.clear(); - DirsDeleted.clear(); -} - -bool DirectorySnapshotDiff::changed() { - return !FilesCreated.empty() || !FilesModified.empty() || !FilesMoved.empty() || - !FilesDeleted.empty() || !DirsCreated.empty() || !DirsModified.empty() || - !DirsMoved.empty() || !DirsDeleted.empty(); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/DirectorySnapshotDiff.hpp b/vendor/efsw/src/efsw/DirectorySnapshotDiff.hpp deleted file mode 100644 index 26a29ec..0000000 --- a/vendor/efsw/src/efsw/DirectorySnapshotDiff.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP -#define EFSW_DIRECTORYSNAPSHOTDIFF_HPP - -#include - -namespace efsw { - -class DirectorySnapshotDiff { - public: - FileInfoList FilesDeleted; - FileInfoList FilesCreated; - FileInfoList FilesModified; - MovedList FilesMoved; - FileInfoList DirsDeleted; - FileInfoList DirsCreated; - FileInfoList DirsModified; - MovedList DirsMoved; - bool DirChanged; - - void clear(); - - bool changed(); -}; - -#define DiffIterator( FileInfoListName ) \ - it = Diff.FileInfoListName.begin(); \ - for ( ; it != Diff.FileInfoListName.end(); it++ ) - -#define DiffMovedIterator( MovedListName ) \ - mit = Diff.MovedListName.begin(); \ - for ( ; mit != Diff.MovedListName.end(); mit++ ) - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileInfo.cpp b/vendor/efsw/src/efsw/FileInfo.cpp deleted file mode 100644 index 707f617..0000000 --- a/vendor/efsw/src/efsw/FileInfo.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include -#include - -#ifndef _DARWIN_FEATURE_64_BIT_INODE -#define _DARWIN_FEATURE_64_BIT_INODE -#endif - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif - -#include - -#include -#include - -#ifdef EFSW_COMPILER_MSVC -#ifndef S_ISDIR -#define S_ISDIR( f ) ( (f)&_S_IFDIR ) -#endif - -#ifndef S_ISREG -#define S_ISREG( f ) ( (f)&_S_IFREG ) -#endif - -#ifndef S_ISRDBL -#define S_ISRDBL( f ) ( (f)&_S_IREAD ) -#endif -#else -#include - -#ifndef S_ISRDBL -#define S_ISRDBL( f ) ( (f)&S_IRUSR ) -#endif -#endif - -namespace efsw { - -bool FileInfo::exists( const std::string& filePath ) { - FileInfo fi( filePath ); - return fi.exists(); -} - -bool FileInfo::isLink( const std::string& filePath ) { - FileInfo fi( filePath, true ); - return fi.isLink(); -} - -bool FileInfo::inodeSupported() { -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - return true; -#else - return false; -#endif -} - -FileInfo::FileInfo() : - ModificationTime( 0 ), OwnerId( 0 ), GroupId( 0 ), Permissions( 0 ), Inode( 0 ) {} - -FileInfo::FileInfo( const std::string& filepath ) : - Filepath( filepath ), - ModificationTime( 0 ), - OwnerId( 0 ), - GroupId( 0 ), - Permissions( 0 ), - Inode( 0 ) { - getInfo(); -} - -FileInfo::FileInfo( const std::string& filepath, bool linkInfo ) : - Filepath( filepath ), - ModificationTime( 0 ), - OwnerId( 0 ), - GroupId( 0 ), - Permissions( 0 ), - Inode( 0 ) { - if ( linkInfo ) { - getRealInfo(); - } else { - getInfo(); - } -} - -void FileInfo::getInfo() { -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - if ( Filepath.size() == 3 && Filepath[1] == ':' && Filepath[2] == FileSystem::getOSSlash() ) { - Filepath += FileSystem::getOSSlash(); - } -#endif - - /// Why i'm doing this? stat in mingw32 doesn't work for directories if the dir path ends with a - /// path slash - bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); - - if ( slashAtEnd ) { - FileSystem::dirRemoveSlashAtEnd( Filepath ); - } - -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - struct stat st; - int res = stat( Filepath.c_str(), &st ); -#else - struct _stat st; - int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); -#endif - - if ( 0 == res ) { - ModificationTime = st.st_mtime; - Size = st.st_size; - OwnerId = st.st_uid; - GroupId = st.st_gid; - Permissions = st.st_mode; - Inode = st.st_ino; - } - - if ( slashAtEnd ) { - FileSystem::dirAddSlashAtEnd( Filepath ); - } -} - -void FileInfo::getRealInfo() { - bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); - - if ( slashAtEnd ) { - FileSystem::dirRemoveSlashAtEnd( Filepath ); - } - -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - struct stat st; - int res = lstat( Filepath.c_str(), &st ); -#else - struct _stat st; - int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); -#endif - - if ( 0 == res ) { - ModificationTime = st.st_mtime; - Size = st.st_size; - OwnerId = st.st_uid; - GroupId = st.st_gid; - Permissions = st.st_mode; - Inode = st.st_ino; - } - - if ( slashAtEnd ) { - FileSystem::dirAddSlashAtEnd( Filepath ); - } -} - -bool FileInfo::operator==( const FileInfo& Other ) const { - return ( ModificationTime == Other.ModificationTime && Size == Other.Size && - OwnerId == Other.OwnerId && GroupId == Other.GroupId && - Permissions == Other.Permissions && Inode == Other.Inode ); -} - -bool FileInfo::isDirectory() const { - return 0 != S_ISDIR( Permissions ); -} - -bool FileInfo::isRegularFile() const { - return 0 != S_ISREG( Permissions ); -} - -bool FileInfo::isReadable() const { -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - static bool isRoot = getuid() == 0; - return isRoot || 0 != S_ISRDBL( Permissions ); -#else - return 0 != S_ISRDBL( Permissions ); -#endif -} - -bool FileInfo::isLink() const { -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - return S_ISLNK( Permissions ); -#else - return false; -#endif -} - -std::string FileInfo::linksTo() { -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - if ( isLink() ) { - char* ch = realpath( Filepath.c_str(), NULL ); - - if ( NULL != ch ) { - std::string tstr( ch ); - - free( ch ); - - return tstr; - } - } -#endif - return std::string( "" ); -} - -bool FileInfo::exists() { - bool slashAtEnd = FileSystem::slashAtEnd( Filepath ); - - if ( slashAtEnd ) { - FileSystem::dirRemoveSlashAtEnd( Filepath ); - } - -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 - struct stat st; - int res = stat( Filepath.c_str(), &st ); -#else - struct _stat st; - int res = _wstat( String::fromUtf8( Filepath ).toWideString().c_str(), &st ); -#endif - - if ( slashAtEnd ) { - FileSystem::dirAddSlashAtEnd( Filepath ); - } - - return 0 == res; -} - -FileInfo& FileInfo::operator=( const FileInfo& Other ) { - this->Filepath = Other.Filepath; - this->Size = Other.Size; - this->ModificationTime = Other.ModificationTime; - this->GroupId = Other.GroupId; - this->OwnerId = Other.OwnerId; - this->Permissions = Other.Permissions; - this->Inode = Other.Inode; - return *this; -} - -bool FileInfo::sameInode( const FileInfo& Other ) const { - return inodeSupported() && Inode == Other.Inode; -} - -bool FileInfo::operator!=( const FileInfo& Other ) const { - return !( *this == Other ); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/FileInfo.hpp b/vendor/efsw/src/efsw/FileInfo.hpp deleted file mode 100644 index 1aca2a8..0000000 --- a/vendor/efsw/src/efsw/FileInfo.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef EFSW_FILEINFO_HPP -#define EFSW_FILEINFO_HPP - -#include -#include -#include -#include - -namespace efsw { - -class FileInfo { - public: - static bool exists( const std::string& filePath ); - - static bool isLink( const std::string& filePath ); - - static bool inodeSupported(); - - FileInfo(); - - FileInfo( const std::string& filepath ); - - FileInfo( const std::string& filepath, bool linkInfo ); - - bool operator==( const FileInfo& Other ) const; - - bool operator!=( const FileInfo& Other ) const; - - FileInfo& operator=( const FileInfo& Other ); - - bool isDirectory() const; - - bool isRegularFile() const; - - bool isReadable() const; - - bool sameInode( const FileInfo& Other ) const; - - bool isLink() const; - - std::string linksTo(); - - bool exists(); - - void getInfo(); - - void getRealInfo(); - - std::string Filepath; - Uint64 ModificationTime; - Uint64 Size; - Uint32 OwnerId; - Uint32 GroupId; - Uint32 Permissions; - Uint64 Inode; -}; - -typedef std::map FileInfoMap; -typedef std::vector FileInfoList; -typedef std::vector> MovedList; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileSystem.cpp b/vendor/efsw/src/efsw/FileSystem.cpp deleted file mode 100644 index b6d2d63..0000000 --- a/vendor/efsw/src/efsw/FileSystem.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include - -#if EFSW_OS == EFSW_OS_MACOSX -#include -#endif - -namespace efsw { - -bool FileSystem::isDirectory( const std::string& path ) { - return Platform::FileSystem::isDirectory( path ); -} - -FileInfoMap FileSystem::filesInfoFromPath( std::string path ) { - dirAddSlashAtEnd( path ); - - return Platform::FileSystem::filesInfoFromPath( path ); -} - -char FileSystem::getOSSlash() { - return Platform::FileSystem::getOSSlash(); -} - -bool FileSystem::slashAtEnd( std::string& dir ) { - return ( dir.size() && dir[dir.size() - 1] == getOSSlash() ); -} - -void FileSystem::dirAddSlashAtEnd( std::string& dir ) { - if ( dir.size() >= 1 && dir[dir.size() - 1] != getOSSlash() ) { - dir.push_back( getOSSlash() ); - } -} - -void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { - if ( dir.size() >= 1 && dir[dir.size() - 1] == getOSSlash() ) { - dir.erase( dir.size() - 1 ); - } -} - -std::string FileSystem::fileNameFromPath( std::string filepath ) { - dirRemoveSlashAtEnd( filepath ); - - size_t pos = filepath.find_last_of( getOSSlash() ); - - if ( pos != std::string::npos ) { - return filepath.substr( pos + 1 ); - } - - return filepath; -} - -std::string FileSystem::pathRemoveFileName( std::string filepath ) { - dirRemoveSlashAtEnd( filepath ); - - size_t pos = filepath.find_last_of( getOSSlash() ); - - if ( pos != std::string::npos ) { - return filepath.substr( 0, pos + 1 ); - } - - return filepath; -} - -std::string FileSystem::getLinkRealPath( std::string dir, std::string& curPath ) { - FileSystem::dirRemoveSlashAtEnd( dir ); - FileInfo fi( dir, true ); - - /// Check with lstat and see if it's a link - if ( fi.isLink() ) { - /// get the real path of the link - std::string link( fi.linksTo() ); - - /// get the current path of the directory without the link dir path - curPath = FileSystem::pathRemoveFileName( dir ); - - /// ensure that ends with the os directory slash - FileSystem::dirAddSlashAtEnd( link ); - - return link; - } - - /// if it's not a link return nothing - return ""; -} - -std::string FileSystem::precomposeFileName( const std::string& name ) { -#if EFSW_OS == EFSW_OS_MACOSX - CFStringRef cfStringRef = - CFStringCreateWithCString( kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8 ); - CFMutableStringRef cfMutable = CFStringCreateMutableCopy( NULL, 0, cfStringRef ); - - CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); - - const char* c_str = CFStringGetCStringPtr( cfMutable, kCFStringEncodingUTF8 ); - if ( c_str != NULL ) { - std::string result( c_str ); - CFRelease( cfStringRef ); - CFRelease( cfMutable ); - return result; - } - CFIndex length = CFStringGetLength( cfMutable ); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ); - if ( maxSize == kCFNotFound ) { - CFRelease( cfStringRef ); - CFRelease( cfMutable ); - return std::string(); - } - - std::string result( maxSize + 1, '\0' ); - if ( CFStringGetCString( cfMutable, &result[0], result.size(), kCFStringEncodingUTF8 ) ) { - result.resize( std::strlen( result.c_str() ) ); - CFRelease( cfStringRef ); - CFRelease( cfMutable ); - } else { - result.clear(); - } - return result; -#else - return name; -#endif -} - -bool FileSystem::isRemoteFS( const std::string& directory ) { - return Platform::FileSystem::isRemoteFS( directory ); -} - -bool FileSystem::changeWorkingDirectory( const std::string& directory ) { - return Platform::FileSystem::changeWorkingDirectory( directory ); -} - -std::string FileSystem::getCurrentWorkingDirectory() { - return Platform::FileSystem::getCurrentWorkingDirectory(); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/FileSystem.hpp b/vendor/efsw/src/efsw/FileSystem.hpp deleted file mode 100644 index d8e11a0..0000000 --- a/vendor/efsw/src/efsw/FileSystem.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef EFSW_FILESYSTEM_HPP -#define EFSW_FILESYSTEM_HPP - -#include -#include - -namespace efsw { - -class FileSystem { - public: - static bool isDirectory( const std::string& path ); - - static FileInfoMap filesInfoFromPath( std::string path ); - - static char getOSSlash(); - - static bool slashAtEnd( std::string& dir ); - - static void dirAddSlashAtEnd( std::string& dir ); - - static void dirRemoveSlashAtEnd( std::string& dir ); - - static std::string fileNameFromPath( std::string filepath ); - - static std::string pathRemoveFileName( std::string filepath ); - - static std::string getLinkRealPath( std::string dir, std::string& curPath ); - - static std::string precomposeFileName( const std::string& name ); - - static bool isRemoteFS( const std::string& directory ); - - static bool changeWorkingDirectory( const std::string& path ); - - static std::string getCurrentWorkingDirectory(); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcher.cpp b/vendor/efsw/src/efsw/FileWatcher.cpp deleted file mode 100644 index f45b243..0000000 --- a/vendor/efsw/src/efsw/FileWatcher.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 -#include -#define FILEWATCHER_IMPL FileWatcherWin32 -#define BACKEND_NAME "Win32" -#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY -#include -#define FILEWATCHER_IMPL FileWatcherInotify -#define BACKEND_NAME "Inotify" -#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE -#include -#define FILEWATCHER_IMPL FileWatcherKqueue -#define BACKEND_NAME "Kqueue" -#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS -#include -#define FILEWATCHER_IMPL FileWatcherFSEvents -#define BACKEND_NAME "FSEvents" -#else -#define FILEWATCHER_IMPL FileWatcherGeneric -#define BACKEND_NAME "Generic" -#endif - -#include - -namespace efsw { - -FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { - efDEBUG( "Using backend: %s\n", BACKEND_NAME ); - - mImpl = new FILEWATCHER_IMPL( this ); - - if ( !mImpl->initOK() ) { - efSAFE_DELETE( mImpl ); - - efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); - - mImpl = new FileWatcherGeneric( this ); - } -} - -FileWatcher::FileWatcher( bool useGenericFileWatcher ) : - mFollowSymlinks( false ), mOutOfScopeLinks( false ) { - if ( useGenericFileWatcher ) { - efDEBUG( "Using backend: Generic\n" ); - - mImpl = new FileWatcherGeneric( this ); - } else { - efDEBUG( "Using backend: %s\n", BACKEND_NAME ); - - mImpl = new FILEWATCHER_IMPL( this ); - - if ( !mImpl->initOK() ) { - efSAFE_DELETE( mImpl ); - - efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); - - mImpl = new FileWatcherGeneric( this ); - } - } -} - -FileWatcher::~FileWatcher() { - efSAFE_DELETE( mImpl ); -} - -WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { - return addWatch( directory, watcher, false, {} ); -} - -WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive ) { - return addWatch( directory, watcher, recursive, {} ); -} - -WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& options ) { - if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { - return mImpl->addWatch( directory, watcher, recursive, options ); - } else { - return Errors::Log::createLastError( Errors::FileRemote, directory ); - } -} - -void FileWatcher::removeWatch( const std::string& directory ) { - mImpl->removeWatch( directory ); -} - -void FileWatcher::removeWatch( WatchID watchid ) { - mImpl->removeWatch( watchid ); -} - -void FileWatcher::watch() { - mImpl->watch(); -} - -std::vector FileWatcher::directories() { - return mImpl->directories(); -} - -void FileWatcher::followSymlinks( bool follow ) { - mFollowSymlinks = follow; -} - -const bool& FileWatcher::followSymlinks() const { - return mFollowSymlinks; -} - -void FileWatcher::allowOutOfScopeLinks( bool allow ) { - mOutOfScopeLinks = allow; -} - -const bool& FileWatcher::allowOutOfScopeLinks() const { - return mOutOfScopeLinks; -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/FileWatcherCWrapper.cpp b/vendor/efsw/src/efsw/FileWatcherCWrapper.cpp deleted file mode 100644 index 860d7d5..0000000 --- a/vendor/efsw/src/efsw/FileWatcherCWrapper.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include - -#define TOBOOL( i ) ( ( i ) == 0 ? false : true ) - -/*************************************************************************************************/ -class Watcher_CAPI : public efsw::FileWatchListener { - public: - efsw_watcher mWatcher; - efsw_pfn_fileaction_callback mFn; - void* mParam; - - public: - Watcher_CAPI( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) : - mWatcher( watcher ), mFn( fn ), mParam( param ) {} - - void handleFileAction( efsw::WatchID watchid, const std::string& dir, - const std::string& filename, efsw::Action action, - std::string oldFilename = "" ) { - mFn( mWatcher, watchid, dir.c_str(), filename.c_str(), (enum efsw_action)action, - oldFilename.c_str(), mParam ); - } -}; - -/************************************************************************************************* - * globals - */ -static std::vector g_callbacks; - -Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) { - for ( std::vector::iterator i = g_callbacks.begin(); i != g_callbacks.end(); - ++i ) { - Watcher_CAPI* callback = *i; - - if ( callback->mFn == fn && callback->mWatcher == watcher ) - return *i; - } - - return NULL; -} - -Watcher_CAPI* remove_callback( efsw_watcher watcher ) { - std::vector::iterator i = g_callbacks.begin(); - - while ( i != g_callbacks.end() ) { - Watcher_CAPI* callback = *i; - - if ( callback->mWatcher == watcher ) - i = g_callbacks.erase( i ); - else - ++i; - } - - return NULL; -} - -/*************************************************************************************************/ -efsw_watcher efsw_create( int generic_mode ) { - return ( efsw_watcher ) new efsw::FileWatcher( TOBOOL( generic_mode ) ); -} - -void efsw_release( efsw_watcher watcher ) { - remove_callback( watcher ); - delete (efsw::FileWatcher*)watcher; -} - -const char* efsw_getlasterror() { - static std::string log_str; - log_str = efsw::Errors::Log::getLastErrorLog(); - return log_str.c_str(); -} - -EFSW_API void efsw_clearlasterror() { - efsw::Errors::Log::clearLastError(); -} - -efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, - efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { - return efsw_addwatch_withoptions( watcher, directory, callback_fn, recursive, 0, 0, param ); -} - -efsw_watchid efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory, - efsw_pfn_fileaction_callback callback_fn, int recursive, - efsw_watcher_option *options, int options_number, - void* param) { - Watcher_CAPI* callback = find_callback( watcher, callback_fn ); - - if ( callback == NULL ) { - callback = new Watcher_CAPI( watcher, callback_fn, param ); - g_callbacks.push_back( callback ); - } - - std::vector watcher_options{}; - for ( int i = 0; i < options_number; i++ ) { - efsw_watcher_option* option = &options[i]; - watcher_options.emplace_back( efsw::WatcherOption{ - static_cast(option->option), option->value } ); - } - - return ( (efsw::FileWatcher*)watcher ) - ->addWatch( std::string( directory ), callback, TOBOOL( recursive ), watcher_options ); -} - -void efsw_removewatch( efsw_watcher watcher, const char* directory ) { - ( (efsw::FileWatcher*)watcher )->removeWatch( std::string( directory ) ); -} - -void efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid ) { - ( (efsw::FileWatcher*)watcher )->removeWatch( watchid ); -} - -void efsw_watch( efsw_watcher watcher ) { - ( (efsw::FileWatcher*)watcher )->watch(); -} - -void efsw_follow_symlinks( efsw_watcher watcher, int enable ) { - ( (efsw::FileWatcher*)watcher )->followSymlinks( TOBOOL( enable ) ); -} - -int efsw_follow_symlinks_isenabled( efsw_watcher watcher ) { - return (int)( (efsw::FileWatcher*)watcher )->followSymlinks(); -} - -void efsw_allow_outofscopelinks( efsw_watcher watcher, int allow ) { - ( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks( TOBOOL( allow ) ); -} - -int efsw_outofscopelinks_isallowed( efsw_watcher watcher ) { - return (int)( (efsw::FileWatcher*)watcher )->allowOutOfScopeLinks(); -} diff --git a/vendor/efsw/src/efsw/FileWatcherFSEvents.cpp b/vendor/efsw/src/efsw/FileWatcherFSEvents.cpp deleted file mode 100644 index 6ea960d..0000000 --- a/vendor/efsw/src/efsw/FileWatcherFSEvents.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include - -namespace efsw { - -int getOSXReleaseNumber() { - static int osxR = -1; - - if ( -1 == osxR ) { - struct utsname os; - - if ( -1 != uname( &os ) ) { - std::string release( os.release ); - - size_t pos = release.find_first_of( '.' ); - - if ( pos != std::string::npos ) { - release = release.substr( 0, pos ); - } - - int rel = 0; - - if ( String::fromString( rel, release ) ) { - osxR = rel; - } - } - } - - return osxR; -} - -bool FileWatcherFSEvents::isGranular() { - return getOSXReleaseNumber() >= 11; -} - -static std::string convertCFStringToStdString( CFStringRef cfString ) { - // Try to get the C string pointer directly - const char* cStr = CFStringGetCStringPtr( cfString, kCFStringEncodingUTF8 ); - - if ( cStr ) { - // If the pointer is valid, directly return a std::string from it - return std::string( cStr ); - } else { - // If not, manually convert it - CFIndex length = CFStringGetLength( cfString ); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) + - 1; // +1 for null terminator - - char* buffer = new char[maxSize]; - - if ( CFStringGetCString( cfString, buffer, maxSize, kCFStringEncodingUTF8 ) ) { - std::string result( buffer ); - delete[] buffer; - return result; - } else { - delete[] buffer; - return ""; - } - } -} - -void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, - size_t numEvents, void* eventPaths, - const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[] ) { - WatcherFSEvents* watcher = static_cast( userData ); - - std::vector events; - events.reserve( numEvents ); - - for ( size_t i = 0; i < numEvents; i++ ) { - if ( isGranular() ) { - CFDictionaryRef pathInfoDict = - static_cast( CFArrayGetValueAtIndex( (CFArrayRef)eventPaths, i ) ); - CFStringRef path = static_cast( - CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedDataPathKey ) ); - CFNumberRef cfInode = static_cast( - CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedFileIDKey ) ); - - if ( cfInode ) { - unsigned long inode = 0; - CFNumberGetValue( cfInode, kCFNumberLongType, &inode ); - events.push_back( FSEvent( convertCFStringToStdString( path ), (long)eventFlags[i], - (Uint64)eventIds[i], inode ) ); - } - } else { - events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), - (long)eventFlags[i], (Uint64)eventIds[i] ) ); - } - } - - watcher->handleActions( events ); - - watcher->process(); - - efDEBUG( "\n" ); -} - -FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : - FileWatcherImpl( parent ), mLastWatchID( 0 ) { - mInitOK = true; - - watch(); -} - -FileWatcherFSEvents::~FileWatcherFSEvents() { - mInitOK = false; - - mWatchCond.notify_all(); - - WatchMap::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - WatcherFSEvents* watch = iter->second; - - efSAFE_DELETE( watch ); - } -} - -WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector &options ) { - std::string dir( directory ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( !fi.isReadable() ) { - return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } - - FileSystem::dirAddSlashAtEnd( dir ); - - if ( pathInWatches( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } - - /// Check if the directory is a symbolic link - std::string curPath; - std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - - if ( "" != link ) { - /// If it's a symlink check if the realpath exists as a watcher, or - /// if the path is outside the current dir - if ( pathInWatches( link ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } else if ( !linkAllowed( curPath, link ) ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } else { - dir = link; - } - } - - mLastWatchID++; - - WatcherFSEvents* pWatch = new WatcherFSEvents(); - pWatch->Listener = watcher; - pWatch->ID = mLastWatchID; - pWatch->Directory = dir; - pWatch->Recursive = recursive; - pWatch->FWatcher = this; - - pWatch->init(); - - { - Lock lock( mWatchesLock ); - mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); - } - - mWatchCond.notify_all(); - return pWatch->ID; -} - -void FileWatcherFSEvents::removeWatch( const std::string& directory ) { - Lock lock( mWatchesLock ); - - WatchMap::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - if ( directory == iter->second->Directory ) { - removeWatch( iter->second->ID ); - return; - } - } -} - -void FileWatcherFSEvents::removeWatch( WatchID watchid ) { - Lock lock( mWatchesLock ); - - WatchMap::iterator iter = mWatches.find( watchid ); - - if ( iter == mWatches.end() ) - return; - - WatcherFSEvents* watch = iter->second; - - mWatches.erase( iter ); - - efDEBUG( "Removed watch %s\n", watch->Directory.c_str() ); - - efSAFE_DELETE( watch ); -} - -void FileWatcherFSEvents::watch() {} - -void FileWatcherFSEvents::handleAction( Watcher* watch, const std::string& filename, - unsigned long action, std::string oldFilename ) { - /// Not used -} - -std::vector FileWatcherFSEvents::directories() { - std::vector dirs; - - Lock lock( mWatchesLock ); - - dirs.reserve( mWatches.size() ); - - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - dirs.push_back( std::string( it->second->Directory ) ); - } - - return dirs; -} - -bool FileWatcherFSEvents::pathInWatches( const std::string& path ) { - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( it->second->Directory == path ) { - return true; - } - } - - return false; -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherFSEvents.hpp b/vendor/efsw/src/efsw/FileWatcherFSEvents.hpp deleted file mode 100644 index 2a192a5..0000000 --- a/vendor/efsw/src/efsw/FileWatcherFSEvents.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef EFSW_FILEWATCHERFSEVENTS_HPP -#define EFSW_FILEWATCHERFSEVENTS_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace efsw { - -/* OSX < 10.7 has no file events */ -/* So i declare the events constants */ -enum FSEventEvents { - efswFSEventStreamCreateFlagUseCFTypes = 0x00000001, - efswFSEventStreamCreateFlagNoDefer = 0x00000002, - efswFSEventStreamCreateFlagFileEvents = 0x00000010, - efswFSEventStreamCreateFlagUseExtendedData = 0x00000040, - efswFSEventStreamEventFlagItemCreated = 0x00000100, - efswFSEventStreamEventFlagItemRemoved = 0x00000200, - efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, - efswFSEventStreamEventFlagItemRenamed = 0x00000800, - efswFSEventStreamEventFlagItemModified = 0x00001000, - efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, - efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, - efswFSEventStreamEventFlagItemXattrMod = 0x00008000, - efswFSEventStreamEventFlagItemIsFile = 0x00010000, - efswFSEventStreamEventFlagItemIsDir = 0x00020000, - efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, - efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | - efswFSEventStreamEventFlagItemModified | - efswFSEventStreamEventFlagItemInodeMetaMod -}; - -/// Implementation for Win32 based on ReadDirectoryChangesW. -/// @class FileWatcherFSEvents -class FileWatcherFSEvents : public FileWatcherImpl { - friend class WatcherFSEvents; - - public: - /// @return If FSEvents supports file-level notifications ( true if OS X >= 10.7 ) - static bool isGranular(); - - /// type for a map from WatchID to WatcherWin32 pointer - typedef std::map WatchMap; - - FileWatcherFSEvents( FileWatcher* parent ); - - virtual ~FileWatcherFSEvents(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector &options ) override; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - void removeWatch( const std::string& directory ) override; - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ) override; - - /// Updates the watcher. Must be called often. - void watch() override; - - /// Handles the action - void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) override; - - /// @return Returns a list of the directories that are being watched - std::vector directories() override; - - protected: - static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, - void* eventPaths, const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[] ); - - /// Vector of WatcherWin32 pointers - WatchMap mWatches; - - /// The last watchid - WatchID mLastWatchID; - - Mutex mWatchesLock; - - bool pathInWatches( const std::string& path ) override; - - std::mutex mWatchesMutex; - std::condition_variable mWatchCond; - -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherGeneric.cpp b/vendor/efsw/src/efsw/FileWatcherGeneric.cpp deleted file mode 100644 index 3f3c52e..0000000 --- a/vendor/efsw/src/efsw/FileWatcherGeneric.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include -#include -#include - -namespace efsw { - -FileWatcherGeneric::FileWatcherGeneric( FileWatcher* parent ) : - FileWatcherImpl( parent ), mThread( NULL ), mLastWatchID( 0 ) { - mInitOK = true; - mIsGeneric = true; -} - -FileWatcherGeneric::~FileWatcherGeneric() { - mInitOK = false; - - efSAFE_DELETE( mThread ); - - /// Delete the watches - WatchList::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - efSAFE_DELETE( ( *it ) ); - } -} - -WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& options ) { - std::string dir( directory ); - - FileSystem::dirAddSlashAtEnd( dir ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( !fi.isReadable() ) { - return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } else if ( pathInWatches( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, dir ); - } - - std::string curPath; - std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - - if ( "" != link ) { - if ( pathInWatches( link ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, dir ); - } else if ( !linkAllowed( curPath, link ) ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } else { - dir = link; - } - } - - mLastWatchID++; - - WatcherGeneric* pWatch = new WatcherGeneric( mLastWatchID, dir, watcher, this, recursive ); - - Lock lock( mWatchesLock ); - mWatches.push_back( pWatch ); - - return pWatch->ID; -} - -void FileWatcherGeneric::removeWatch( const std::string& directory ) { - WatchList::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - if ( ( *it )->Directory == directory ) { - WatcherGeneric* watch = ( *it ); - - Lock lock( mWatchesLock ); - - mWatches.erase( it ); - - efSAFE_DELETE( watch ); - - return; - } - } -} - -void FileWatcherGeneric::removeWatch( WatchID watchid ) { - WatchList::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - if ( ( *it )->ID == watchid ) { - WatcherGeneric* watch = ( *it ); - - Lock lock( mWatchesLock ); - - mWatches.erase( it ); - - efSAFE_DELETE( watch ); - - return; - } - } -} - -void FileWatcherGeneric::watch() { - if ( NULL == mThread ) { - mThread = new Thread( &FileWatcherGeneric::run, this ); - mThread->launch(); - } -} - -void FileWatcherGeneric::run() { - do { - { - Lock lock( mWatchesLock ); - - WatchList::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - ( *it )->watch(); - } - } - - if ( mInitOK ) - System::sleep( 1000 ); - } while ( mInitOK ); -} - -void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned long, std::string ) { - /// Not used -} - -std::vector FileWatcherGeneric::directories() { - std::vector dirs; - - Lock lock( mWatchesLock ); - - dirs.reserve( mWatches.size() ); - - WatchList::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - dirs.push_back( ( *it )->Directory ); - } - - return dirs; -} - -bool FileWatcherGeneric::pathInWatches( const std::string& path ) { - WatchList::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - if ( ( *it )->Directory == path || ( *it )->pathInWatches( path ) ) { - return true; - } - } - - return false; -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/FileWatcherGeneric.hpp b/vendor/efsw/src/efsw/FileWatcherGeneric.hpp deleted file mode 100644 index 47f7e04..0000000 --- a/vendor/efsw/src/efsw/FileWatcherGeneric.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef EFSW_FILEWATCHERGENERIC_HPP -#define EFSW_FILEWATCHERGENERIC_HPP - -#include -#include -#include -#include - -namespace efsw { - -/// Implementation for Generic File Watcher. -/// @class FileWatcherGeneric -class FileWatcherGeneric : public FileWatcherImpl { - public: - typedef std::vector WatchList; - - FileWatcherGeneric( FileWatcher* parent ); - - virtual ~FileWatcherGeneric(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector &options ) override; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - void removeWatch( const std::string& directory ) override; - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ) override; - - /// Updates the watcher. Must be called often. - void watch() override; - - /// Handles the action - void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) override; - - /// @return Returns a list of the directories that are being watched - std::vector directories() override; - - protected: - Thread* mThread; - - /// The last watchid - WatchID mLastWatchID; - - /// Map of WatchID to WatchStruct pointers - WatchList mWatches; - - Mutex mWatchesLock; - - bool pathInWatches( const std::string& path ) override; - - private: - void run(); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherImpl.cpp b/vendor/efsw/src/efsw/FileWatcherImpl.cpp deleted file mode 100644 index bf69a45..0000000 --- a/vendor/efsw/src/efsw/FileWatcherImpl.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -namespace efsw { - -FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : - mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { - System::maxFD(); -} - -FileWatcherImpl::~FileWatcherImpl() {} - -bool FileWatcherImpl::initOK() { - return static_cast( mInitOK ); -} - -bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { - return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || - -1 != String::strStartsWith( curPath, link ); -} - -int FileWatcherImpl::getOptionValue( const std::vector& options, Option option, - int defaultValue ) { - for ( size_t i = 0; i < options.size(); i++ ) { - if ( options[i].mOption == option ) { - return options[i].mValue; - } - } - - return defaultValue; -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/FileWatcherImpl.hpp b/vendor/efsw/src/efsw/FileWatcherImpl.hpp deleted file mode 100644 index a6ec472..0000000 --- a/vendor/efsw/src/efsw/FileWatcherImpl.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef EFSW_FILEWATCHERIMPL_HPP -#define EFSW_FILEWATCHERIMPL_HPP - -#include -#include -#include -#include -#include -#include - -namespace efsw { - -class FileWatcherImpl { - public: - FileWatcherImpl( FileWatcher* parent ); - - virtual ~FileWatcherImpl(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& options = {} ) = 0; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - virtual void removeWatch( const std::string& directory ) = 0; - - /// Remove a directory watch. This is a map lookup O(logn). - virtual void removeWatch( WatchID watchid ) = 0; - - /// Updates the watcher. Must be called often. - virtual void watch() = 0; - - /// Handles the action - virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) = 0; - - /// @return Returns a list of the directories that are being watched - virtual std::vector directories() = 0; - - /// @return true if the backend init successfully - virtual bool initOK(); - - /// @return If the link is allowed according to the current path and the state of out scope - /// links - virtual bool linkAllowed( const std::string& curPath, const std::string& link ); - - /// Search if a directory already exists in the watches - virtual bool pathInWatches( const std::string& path ) = 0; - - protected: - friend class FileWatcher; - friend class DirWatcherGeneric; - - FileWatcher* mFileWatcher; - Atomic mInitOK; - bool mIsGeneric; - - int getOptionValue( const std::vector& options, Option option, - int defaultValue ); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherInotify.cpp b/vendor/efsw/src/efsw/FileWatcherInotify.cpp deleted file mode 100644 index 29be12b..0000000 --- a/vendor/efsw/src/efsw/FileWatcherInotify.cpp +++ /dev/null @@ -1,562 +0,0 @@ -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY - -#include -#include -#include -#include -#include -#include - -#ifdef EFSW_INOTIFY_NOSYS -#include -#else -#include -#endif - -#include -#include -#include -#include -#include - -#define BUFF_SIZE ( ( sizeof( struct inotify_event ) + FILENAME_MAX ) * 1024 ) - -namespace efsw { - -FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : - FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) { - mFD = inotify_init(); - - if ( mFD < 0 ) { - efDEBUG( "Error: %s\n", strerror( errno ) ); - } else { - mInitOK = true; - } -} - -FileWatcherInotify::~FileWatcherInotify() { - mInitOK = false; - // There is deadlock when release FileWatcherInotify instance since its handAction - // function is still running and hangs in requiring lock without init lock captured. - while ( mIsTakingAction ) { - // It'd use condition-wait instead of sleep. Actually efsw has no such - // implementation so we just skip and sleep while for that to avoid deadlock. - usleep( 1000 ); - }; - Lock initLock( mInitLock ); - - efSAFE_DELETE( mThread ); - - Lock l( mWatchesLock ); - Lock l2( mRealWatchesLock ); - - WatchMap::iterator iter = mWatches.begin(); - WatchMap::iterator end = mWatches.end(); - - for ( ; iter != end; ++iter ) { - efSAFE_DELETE( iter->second ); - } - - mWatches.clear(); - - if ( mFD != -1 ) { - close( mFD ); - mFD = -1; - } -} - -WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& ) { - if ( !mInitOK ) - return Errors::Log::createLastError( Errors::Unspecified, directory ); - Lock initLock( mInitLock ); - return addWatch( directory, watcher, recursive, NULL ); -} - -WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, WatcherInotify* parent ) { - std::string dir( directory ); - - FileSystem::dirAddSlashAtEnd( dir ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( !fi.isReadable() ) { - return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } else if ( pathInWatches( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) { - return Errors::Log::createLastError( Errors::FileRemote, dir ); - } - - /// Check if the directory is a symbolic link - std::string curPath; - std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - - if ( "" != link ) { - /// Avoid adding symlinks directories if it's now enabled - if ( NULL != parent && !mFileWatcher->followSymlinks() ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } - - /// If it's a symlink check if the realpath exists as a watcher, or - /// if the path is outside the current dir - if ( pathInWatches( link ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } else if ( !linkAllowed( curPath, link ) ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } else { - dir = link; - } - } - - int wd = inotify_add_watch( mFD, dir.c_str(), - IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | - IN_DELETE | IN_MODIFY ); - - if ( wd < 0 ) { - if ( errno == ENOENT ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else { - return Errors::Log::createLastError( Errors::Unspecified, - std::string( strerror( errno ) ) ); - } - } - - efDEBUG( "Added watch %s with id: %d\n", dir.c_str(), wd ); - - WatcherInotify* pWatch = new WatcherInotify(); - pWatch->Listener = watcher; - pWatch->ID = parent ? parent->ID : wd; - pWatch->InotifyID = wd; - pWatch->Directory = dir; - pWatch->Recursive = recursive; - pWatch->Parent = parent; - - { - Lock lock( mWatchesLock ); - mWatches.insert( std::make_pair( wd, pWatch ) ); - mWatchesRef[pWatch->Directory] = wd; - } - - if ( NULL == pWatch->Parent ) { - Lock l( mRealWatchesLock ); - mRealWatches[pWatch->InotifyID] = pWatch; - } - - if ( pWatch->Recursive ) { - std::map files = FileSystem::filesInfoFromPath( pWatch->Directory ); - std::map::iterator it = files.begin(); - - for ( ; it != files.end(); ++it ) { - if ( !mInitOK ) - break; - - const FileInfo& cfi = it->second; - - if ( cfi.isDirectory() && cfi.isReadable() ) { - addWatch( cfi.Filepath, watcher, recursive, pWatch ); - } - } - } - - return wd; -} - -void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { - WatchMap::iterator iter = mWatches.find( watchid ); - if ( iter == mWatches.end() ) - return; - - WatcherInotify* watch = iter->second; - - for ( std::vector>::iterator itm = - mMovedOutsideWatches.begin(); - mMovedOutsideWatches.end() != itm; ++itm ) { - if ( itm->first == watch ) { - mMovedOutsideWatches.erase( itm ); - break; - } - } - - if ( watch->Recursive && NULL == watch->Parent ) { - WatchMap::iterator it = mWatches.begin(); - std::vector eraseWatches; - - for ( ; it != mWatches.end(); ++it ) - if ( it->second != watch && it->second->inParentTree( watch ) ) - eraseWatches.push_back( it->second->InotifyID ); - - for ( std::vector::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); - ++eit ) { - removeWatch( *eit ); - } - } - - mWatchesRef.erase( watch->Directory ); - mWatches.erase( iter ); - - if ( NULL == watch->Parent ) { - WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); - - if ( eraseit != mRealWatches.end() ) { - mRealWatches.erase( eraseit ); - } - } - - int err = inotify_rm_watch( mFD, watchid ); - - if ( err < 0 ) { - efDEBUG( "Error removing watch %d: %s\n", watchid, strerror( errno ) ); - } else { - efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), watchid ); - } - - efSAFE_DELETE( watch ); -} - -void FileWatcherInotify::removeWatch( const std::string& directory ) { - if ( !mInitOK ) - return; - Lock initLock( mInitLock ); - Lock lock( mWatchesLock ); - Lock l( mRealWatchesLock ); - - std::unordered_map::iterator ref = mWatchesRef.find( directory ); - if ( ref == mWatchesRef.end() ) - return; - - removeWatchLocked( ref->second ); -} - -void FileWatcherInotify::removeWatch( WatchID watchid ) { - if ( !mInitOK ) - return; - Lock initLock( mInitLock ); - Lock lock( mWatchesLock ); - removeWatchLocked( watchid ); -} - -void FileWatcherInotify::watch() { - if ( NULL == mThread ) { - mThread = new Thread( &FileWatcherInotify::run, this ); - mThread->launch(); - } -} - -Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) { - FileSystem::dirRemoveSlashAtEnd( dir ); - std::string watcherPath = FileSystem::pathRemoveFileName( dir ); - FileSystem::dirAddSlashAtEnd( watcherPath ); - Lock lock( mWatchesLock ); - - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - Watcher* watcher = it->second; - if ( watcher->Directory == watcherPath ) - return watcher; - } - - return NULL; -} - -void FileWatcherInotify::run() { - char* buff = new char[BUFF_SIZE]; - memset( buff, 0, BUFF_SIZE ); - WatchMap::iterator wit; - - WatcherInotify* currentMoveFrom = NULL; - u_int32_t currentMoveCookie = -1; - bool lastWasMovedFrom = false; - std::string prevOldFileName; - - do { - fd_set rfds; - FD_ZERO( &rfds ); - FD_SET( mFD, &rfds ); - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - - if ( select( FD_SETSIZE, &rfds, NULL, NULL, &timeout ) > 0 ) { - ssize_t len; - - len = read( mFD, buff, BUFF_SIZE ); - - if ( len != -1 ) { - ssize_t i = 0; - - while ( i < len ) { - struct inotify_event* pevent = (struct inotify_event*)&buff[i]; - - { - { - Lock lock( mWatchesLock ); - - wit = mWatches.find( pevent->wd ); - } - - if ( wit != mWatches.end() ) { - handleAction( wit->second, (char*)pevent->name, pevent->mask ); - - if ( ( pevent->mask & IN_MOVED_TO ) && wit->second == currentMoveFrom && - pevent->cookie == currentMoveCookie ) { - /// make pair success - currentMoveFrom = NULL; - currentMoveCookie = -1; - } else if ( pevent->mask & IN_MOVED_FROM ) { - // Previous event was moved from and current event is moved from - // Treat it as a DELETE or moved ouside watches - if ( lastWasMovedFrom && currentMoveFrom ) { - mMovedOutsideWatches.push_back( - std::make_pair( currentMoveFrom, prevOldFileName ) ); - } - - currentMoveFrom = wit->second; - currentMoveCookie = pevent->cookie; - } else { - /// Keep track of the IN_MOVED_FROM events to know - /// if the IN_MOVED_TO event is also fired - if ( currentMoveFrom ) { - mMovedOutsideWatches.push_back( - std::make_pair( currentMoveFrom, prevOldFileName ) ); - } - - currentMoveFrom = NULL; - currentMoveCookie = -1; - } - } - - lastWasMovedFrom = ( pevent->mask & IN_MOVED_FROM ) != 0; - if ( pevent->mask & IN_MOVED_FROM ) - prevOldFileName = std::string( (char*)pevent->name ); - } - - i += sizeof( struct inotify_event ) + pevent->len; - } - } - } else { - // Here means no event received - // If last event is IN_MOVED_FROM, we assume no IN_MOVED_TO - if ( currentMoveFrom ) { - mMovedOutsideWatches.push_back( - std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) ); - } - - currentMoveFrom = NULL; - currentMoveCookie = -1; - } - - if ( !mMovedOutsideWatches.empty() ) { - // We need to make a copy since the element mMovedOutsideWatches could be modified - // during the iteration. - std::vector> movedOutsideWatches( - mMovedOutsideWatches ); - - /// In case that the IN_MOVED_TO is never fired means that the file was moved to other - /// folder - for ( std::vector>::iterator it = - movedOutsideWatches.begin(); - it != movedOutsideWatches.end(); ++it ) { - - // Skip if the watch has already being removed - if ( mMovedOutsideWatches.size() != movedOutsideWatches.size() ) { - bool found = false; - for ( std::vector>::iterator itm = - mMovedOutsideWatches.begin(); - mMovedOutsideWatches.end() != itm; ++itm ) { - if ( itm->first == it->first ) { - found = true; - break; - } - } - if ( !found ) - continue; - } - - Watcher* watch = ( *it ).first; - const std::string& oldFileName = ( *it ).second; - - /// Check if the file move was a folder already being watched - std::vector eraseWatches; - - { - Lock lock( mWatchesLock ); - - for ( ; wit != mWatches.end(); ++wit ) { - Watcher* oldWatch = wit->second; - - if ( oldWatch != watch && - -1 != String::strStartsWith( watch->Directory + oldFileName + "/", - oldWatch->Directory ) ) { - eraseWatches.push_back( oldWatch ); - } - } - } - - /// Remove invalid watches - std::stable_sort( eraseWatches.begin(), eraseWatches.end(), - []( const Watcher* left, const Watcher* right ) { - return left->Directory < right->Directory; - } ); - - if ( eraseWatches.empty() ) { - handleAction( watch, oldFileName, IN_DELETE ); - } else { - for ( std::vector::reverse_iterator eit = eraseWatches.rbegin(); - eit != eraseWatches.rend(); ++eit ) { - Watcher* rmWatch = *eit; - - /// Create Delete event for removed watches that have been moved too - if ( Watcher* cntWatch = watcherContainsDirectory( rmWatch->Directory ) ) { - handleAction( cntWatch, - FileSystem::fileNameFromPath( rmWatch->Directory ), - IN_DELETE ); - } - } - } - } - - mMovedOutsideWatches.clear(); - } - } while ( mInitOK ); - - delete[] buff; -} - -void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) { - FileSystem::dirAddSlashAtEnd( fpath ); - - /// If the watcher is recursive, checks if the new file is a folder, and creates a watcher - if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { - bool found = false; - - { - Lock lock( mWatchesLock ); - - /// First check if exists - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( it->second->Directory == fpath ) { - found = true; - break; - } - } - } - - if ( !found ) { - addWatch( fpath, watch->Listener, watch->Recursive, - static_cast( watch ) ); - } - } -} - -void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filename, - unsigned long action, std::string ) { - if ( !watch || !watch->Listener || !mInitOK ) { - return; - } - mIsTakingAction = true; - Lock initLock( mInitLock ); - - std::string fpath( watch->Directory + filename ); - - if ( ( IN_CLOSE_WRITE & action ) || ( IN_MODIFY & action ) ) { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, - Actions::Modified ); - } else if ( IN_MOVED_TO & action ) { - /// If OldFileName doesn't exist means that the file has been moved from other folder, so we - /// just send the Add event - if ( watch->OldFileName.empty() ) { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, - Actions::Add ); - - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, - Actions::Modified ); - - checkForNewWatcher( watch, fpath ); - } else { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, - Actions::Moved, watch->OldFileName ); - } - - if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { - /// Update the new directory path - std::string opath( watch->Directory + watch->OldFileName ); - FileSystem::dirAddSlashAtEnd( opath ); - FileSystem::dirAddSlashAtEnd( fpath ); - - Lock lock( mWatchesLock ); - - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( it->second->Directory == opath ) { - it->second->Directory = fpath; - it->second->DirInfo = FileInfo( fpath ); - } else if ( -1 != String::strStartsWith( opath, it->second->Directory ) ) { - it->second->Directory = fpath + it->second->Directory.substr( opath.size() ); - it->second->DirInfo.Filepath = it->second->Directory; - } - } - } - - watch->OldFileName = ""; - } else if ( IN_CREATE & action ) { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Add ); - - checkForNewWatcher( watch, fpath ); - } else if ( IN_MOVED_FROM & action ) { - watch->OldFileName = filename; - } else if ( IN_DELETE & action ) { - watch->Listener->handleFileAction( watch->ID, watch->Directory, filename, Actions::Delete ); - - FileSystem::dirAddSlashAtEnd( fpath ); - - /// If the file erased is a directory and recursive is enabled, removes the directory erased - if ( watch->Recursive ) { - Lock l( mWatchesLock ); - - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( it->second->Directory == fpath ) { - removeWatchLocked( it->second->InotifyID ); - break; - } - } - } - } - mIsTakingAction = false; -} - -std::vector FileWatcherInotify::directories() { - std::vector dirs; - - Lock l( mRealWatchesLock ); - - dirs.reserve( mRealWatches.size() ); - - WatchMap::iterator it = mRealWatches.begin(); - - for ( ; it != mRealWatches.end(); ++it ) - dirs.push_back( it->second->Directory ); - - return dirs; -} - -bool FileWatcherInotify::pathInWatches( const std::string& path ) { - Lock l( mRealWatchesLock ); - - /// Search in the real watches, since it must allow adding a watch already watched as a subdir - WatchMap::iterator it = mRealWatches.begin(); - - for ( ; it != mRealWatches.end(); ++it ) - if ( it->second->Directory == path ) - return true; - - return false; -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherInotify.hpp b/vendor/efsw/src/efsw/FileWatcherInotify.hpp deleted file mode 100644 index 84174a0..0000000 --- a/vendor/efsw/src/efsw/FileWatcherInotify.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef EFSW_FILEWATCHERLINUX_HPP -#define EFSW_FILEWATCHERLINUX_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY - -#include -#include -#include -#include - -namespace efsw { - -/// Implementation for Linux based on inotify. -/// @class FileWatcherInotify -class FileWatcherInotify : public FileWatcherImpl { - public: - /// type for a map from WatchID to WatchStruct pointer - typedef std::map WatchMap; - - FileWatcherInotify( FileWatcher* parent ); - - virtual ~FileWatcherInotify(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector& options ) override; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - void removeWatch( const std::string& directory ) override; - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ) override; - - /// Updates the watcher. Must be called often. - void watch() override; - - /// Handles the action - void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) override; - - /// @return Returns a list of the directories that are being watched - std::vector directories() override; - - protected: - /// Map of WatchID to WatchStruct pointers - WatchMap mWatches; - - /// User added watches - WatchMap mRealWatches; - - std::unordered_map mWatchesRef; - - /// inotify file descriptor - int mFD; - - Thread* mThread; - - Mutex mWatchesLock; - Mutex mRealWatchesLock; - Mutex mInitLock; - bool mIsTakingAction; - std::vector> mMovedOutsideWatches; - - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - WatcherInotify* parent = NULL ); - - bool pathInWatches( const std::string& path ) override; - - private: - void run(); - - void removeWatchLocked( WatchID watchid ); - - void checkForNewWatcher( Watcher* watch, std::string fpath ); - - Watcher* watcherContainsDirectory( std::string dir ); -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherKqueue.cpp b/vendor/efsw/src/efsw/FileWatcherKqueue.cpp deleted file mode 100644 index 32ef3dc..0000000 --- a/vendor/efsw/src/efsw/FileWatcherKqueue.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace efsw { - -FileWatcherKqueue::FileWatcherKqueue( FileWatcher* parent ) : - FileWatcherImpl( parent ), - mLastWatchID( 0 ), - mThread( NULL ), - mFileDescriptorCount( 1 ), - mAddingWatcher( false ) { - mTimeOut.tv_sec = 0; - mTimeOut.tv_nsec = 0; - mInitOK = true; -} - -FileWatcherKqueue::~FileWatcherKqueue() { - WatchMap::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - efSAFE_DELETE( iter->second ); - } - - mWatches.clear(); - - mInitOK = false; - - efSAFE_DELETE( mThread ); -} - -WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& options ) { - static bool s_ug = false; - - std::string dir( directory ); - - FileSystem::dirAddSlashAtEnd( dir ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( !fi.isReadable() ) { - return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } else if ( pathInWatches( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } - - std::string curPath; - std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - - if ( "" != link ) { - if ( pathInWatches( link ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } else if ( !linkAllowed( curPath, link ) ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } else { - dir = link; - } - } - - /// Check first if are enough file descriptors available to create another kqueue watcher, - /// otherwise it creates a generic watcher - if ( availablesFD() ) { - mAddingWatcher = true; - - WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this ); - - { - Lock lock( mWatchesLock ); - mWatches.insert( std::make_pair( mLastWatchID, watch ) ); - } - - watch->addAll(); - - // if failed to open the directory... erase the watcher - if ( !watch->initOK() ) { - int le = watch->lastErrno(); - - mWatches.erase( watch->ID ); - - efSAFE_DELETE( watch ); - - mLastWatchID--; - - // Probably the folder has too many files, create a generic watcher - if ( EACCES != le ) { - WatcherGeneric* genericWatch = - new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); - - Lock lock( mWatchesLock ); - mWatches.insert( std::make_pair( mLastWatchID, genericWatch ) ); - } else { - return Errors::Log::createLastError( Errors::Unspecified, link ); - } - } - - mAddingWatcher = false; - } else { - if ( !s_ug ) { - efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", - mFileDescriptorCount ); - s_ug = true; - } - - WatcherGeneric* watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); - - Lock lock( mWatchesLock ); - mWatches.insert( std::make_pair( mLastWatchID, watch ) ); - } - - return mLastWatchID; -} - -void FileWatcherKqueue::removeWatch( const std::string& directory ) { - Lock lock( mWatchesLock ); - - WatchMap::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - if ( directory == iter->second->Directory ) { - removeWatch( iter->first ); - return; - } - } -} - -void FileWatcherKqueue::removeWatch( WatchID watchid ) { - Lock lock( mWatchesLock ); - - WatchMap::iterator iter = mWatches.find( watchid ); - - if ( iter == mWatches.end() ) - return; - - Watcher* watch = iter->second; - - mWatches.erase( iter ); - - efSAFE_DELETE( watch ); -} - -bool FileWatcherKqueue::isAddingWatcher() const { - return mAddingWatcher; -} - -void FileWatcherKqueue::watch() { - if ( NULL == mThread ) { - mThread = new Thread( &FileWatcherKqueue::run, this ); - mThread->launch(); - } -} - -void FileWatcherKqueue::run() { - do { - { - Lock lock( mWatchesLock ); - - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - it->second->watch(); - } - } - - System::sleep( 500 ); - } while ( mInitOK ); -} - -void FileWatcherKqueue::handleAction( Watcher* watch, const std::string& filename, - unsigned long action, std::string oldFilename ) {} - -std::vector FileWatcherKqueue::directories() { - std::vector dirs; - - Lock lock( mWatchesLock ); - - dirs.reserve( mWatches.size() ); - - WatchMap::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - dirs.push_back( it->second->Directory ); - } - - return dirs; -} - -bool FileWatcherKqueue::pathInWatches( const std::string& path ) { - WatchMap::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); ++it ) { - if ( it->second->Directory == path ) { - return true; - } - } - - return false; -} - -void FileWatcherKqueue::addFD() { - mFileDescriptorCount++; -} - -void FileWatcherKqueue::removeFD() { - mFileDescriptorCount--; -} - -bool FileWatcherKqueue::availablesFD() { - return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500; -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherKqueue.hpp b/vendor/efsw/src/efsw/FileWatcherKqueue.hpp deleted file mode 100644 index ff5327b..0000000 --- a/vendor/efsw/src/efsw/FileWatcherKqueue.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef EFSW_FILEWATCHEROSX_HPP -#define EFSW_FILEWATCHEROSX_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include - -namespace efsw { - -/// Implementation for OSX based on kqueue. -/// @class FileWatcherKqueue -class FileWatcherKqueue : public FileWatcherImpl { - friend class WatcherKqueue; - - public: - FileWatcherKqueue( FileWatcher* parent ); - - virtual ~FileWatcherKqueue(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector &options ) override; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - void removeWatch( const std::string& directory ) override; - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ) override; - - /// Updates the watcher. Must be called often. - void watch() override; - - /// Handles the action - void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) override; - - /// @return Returns a list of the directories that are being watched - std::vector directories() override; - - protected: - /// Map of WatchID to WatchStruct pointers - WatchMap mWatches; - - /// time out data - struct timespec mTimeOut; - - /// WatchID allocator - int mLastWatchID; - - Thread* mThread; - - Mutex mWatchesLock; - - std::vector mRemoveList; - - long mFileDescriptorCount; - - bool mAddingWatcher; - - bool isAddingWatcher() const; - - bool pathInWatches( const std::string& path ) override; - - void addFD(); - - void removeFD(); - - bool availablesFD(); - - private: - void run(); -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherWin32.cpp b/vendor/efsw/src/efsw/FileWatcherWin32.cpp deleted file mode 100644 index 19b71d7..0000000 --- a/vendor/efsw/src/efsw/FileWatcherWin32.cpp +++ /dev/null @@ -1,267 +0,0 @@ -#include -#include -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -namespace efsw { - -FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : - FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { - mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); - if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) - mInitOK = true; -} - -FileWatcherWin32::~FileWatcherWin32() { - mInitOK = false; - - if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { - PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast( this ), NULL ); - } - - efSAFE_DELETE( mThread ); - - removeAllWatches(); - - if ( mIOCP ) - CloseHandle( mIOCP ); -} - -WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector &options ) { - std::string dir( directory ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( !fi.isReadable() ) { - return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } - - FileSystem::dirAddSlashAtEnd( dir ); - - Lock lock( mWatchesLock ); - - if ( pathInWatches( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, dir ); - } - - WatchID watchid = ++mLastWatchID; - - DWORD bufferSize = static_cast( getOptionValue(options, Option::WinBufferSize, 63 * 1024) ); - DWORD notifyFilter = static_cast( getOptionValue(options, Option::WinNotifyFilter, - FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | - FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE) ); - - WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), - recursive, bufferSize, notifyFilter, mIOCP ); - - if ( NULL == watch ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } - - // Add the handle to the handles vector - watch->Watch->ID = watchid; - watch->Watch->Watch = this; - watch->Watch->Listener = watcher; - watch->Watch->DirName = new char[dir.length() + 1]; - strcpy( watch->Watch->DirName, dir.c_str() ); - - mWatches.insert( watch ); - - return watchid; -} - -void FileWatcherWin32::removeWatch( const std::string& directory ) { - Lock lock( mWatchesLock ); - - Watches::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - if ( directory == ( *iter )->Watch->DirName ) { - removeWatch( *iter ); - break; - } - } -} - -void FileWatcherWin32::removeWatch( WatchID watchid ) { - Lock lock( mWatchesLock ); - - Watches::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - // Find the watch ID - if ( ( *iter )->Watch->ID == watchid ) { - removeWatch( *iter ); - return; - } - } -} - -void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { - Lock lock( mWatchesLock ); - - DestroyWatch( watch ); - mWatches.erase( watch ); -} - -void FileWatcherWin32::watch() { - if ( NULL == mThread ) { - mThread = new Thread( &FileWatcherWin32::run, this ); - mThread->launch(); - } -} - -void FileWatcherWin32::removeAllWatches() { - Lock lock( mWatchesLock ); - - Watches::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - DestroyWatch( ( *iter ) ); - } - - mWatches.clear(); -} - -void FileWatcherWin32::run() { - do { - if ( mInitOK && !mWatches.empty() ) { - DWORD numOfBytes = 0; - OVERLAPPED* ov = NULL; - ULONG_PTR compKey = 0; - BOOL res = FALSE; - - while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, - INFINITE ) ) != FALSE ) { - if ( compKey != 0 && compKey == reinterpret_cast( this ) ) { - break; - } else { - Lock lock( mWatchesLock ); - if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end()) - WatchCallback( numOfBytes, ov ); - } - } - } else { - System::sleep( 10 ); - } - } while ( mInitOK ); - - removeAllWatches(); -} - -void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, - unsigned long action, std::string /*oldFilename*/ ) { - Action fwAction; - - switch ( action ) { - case FILE_ACTION_RENAMED_OLD_NAME: - watch->OldFileName = filename; - return; - case FILE_ACTION_ADDED: - fwAction = Actions::Add; - break; - case FILE_ACTION_RENAMED_NEW_NAME: { - fwAction = Actions::Moved; - - std::string fpath( watch->Directory + filename ); - - // Update the directory path - if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { - // Update the new directory path - std::string opath( watch->Directory + watch->OldFileName ); - FileSystem::dirAddSlashAtEnd( opath ); - FileSystem::dirAddSlashAtEnd( fpath ); - - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( ( *it )->Watch->Directory == opath ) { - ( *it )->Watch->Directory = fpath; - - break; - } - } - } - - std::string folderPath( static_cast( watch )->DirName ); - std::string realFilename = filename; - std::size_t sepPos = filename.find_last_of( "/\\" ); - std::string oldFolderPath = - static_cast( watch )->DirName + - watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); - - if ( sepPos != std::string::npos ) { - folderPath += - filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); - realFilename = filename.substr( sepPos + 1 ); - } - - if ( folderPath == oldFolderPath ) { - watch->Listener->handleFileAction( - watch->ID, folderPath, realFilename, fwAction, - FileSystem::fileNameFromPath( watch->OldFileName ) ); - } else { - watch->Listener->handleFileAction( watch->ID, - static_cast( watch )->DirName, - filename, fwAction, watch->OldFileName ); - } - return; - } - case FILE_ACTION_REMOVED: - fwAction = Actions::Delete; - break; - case FILE_ACTION_MODIFIED: - fwAction = Actions::Modified; - break; - default: - return; - }; - - std::string folderPath( static_cast( watch )->DirName ); - std::string realFilename = filename; - std::size_t sepPos = filename.find_last_of( "/\\" ); - - if ( sepPos != std::string::npos ) { - folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); - realFilename = filename.substr( sepPos + 1 ); - } - - FileSystem::dirAddSlashAtEnd( folderPath ); - - watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); -} - -std::vector FileWatcherWin32::directories() { - std::vector dirs; - - Lock lock( mWatchesLock ); - - dirs.reserve( mWatches.size() ); - - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - dirs.push_back( std::string( ( *it )->Watch->DirName ) ); - } - - return dirs; -} - -bool FileWatcherWin32::pathInWatches( const std::string& path ) { - Lock lock( mWatchesLock ); - - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( ( *it )->Watch->DirName == path ) { - return true; - } - } - - return false; -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/FileWatcherWin32.hpp b/vendor/efsw/src/efsw/FileWatcherWin32.hpp deleted file mode 100644 index 3016aac..0000000 --- a/vendor/efsw/src/efsw/FileWatcherWin32.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef EFSW_FILEWATCHERWIN32_HPP -#define EFSW_FILEWATCHERWIN32_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#include -#include -#include -#include - -namespace efsw { - -/// Implementation for Win32 based on ReadDirectoryChangesW. -/// @class FileWatcherWin32 -class FileWatcherWin32 : public FileWatcherImpl { - public: - /// type for a map from WatchID to WatcherWin32 pointer - typedef std::unordered_set Watches; - - FileWatcherWin32( FileWatcher* parent ); - - virtual ~FileWatcherWin32(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector &options ) override; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - void removeWatch( const std::string& directory ) override; - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ) override; - - /// Updates the watcher. Must be called often. - void watch() override; - - /// Handles the action - void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) override; - - /// @return Returns a list of the directories that are being watched - std::vector directories() override; - - protected: - HANDLE mIOCP; - Watches mWatches; - - /// The last watchid - WatchID mLastWatchID; - Thread* mThread; - Mutex mWatchesLock; - - bool pathInWatches( const std::string& path ) override; - - /// Remove all directory watches. - void removeAllWatches(); - - void removeWatch( WatcherStructWin32* watch ); - - private: - void run(); -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/Lock.hpp b/vendor/efsw/src/efsw/Lock.hpp deleted file mode 100644 index e8c522a..0000000 --- a/vendor/efsw/src/efsw/Lock.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef EFSW_LOCK_HPP -#define EFSW_LOCK_HPP - -#include - -namespace efsw { - -/** Simple mutex class */ -class Lock { - public: - explicit Lock( Mutex& mutex ) : mMutex( mutex ) { mMutex.lock(); } - - ~Lock() { mMutex.unlock(); } - - private: - Mutex& mMutex; -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/Log.cpp b/vendor/efsw/src/efsw/Log.cpp deleted file mode 100644 index 6f32df7..0000000 --- a/vendor/efsw/src/efsw/Log.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -namespace efsw { namespace Errors { - -static std::string LastError = ""; -static Error LastErrorCode = NoError; - -std::string Log::getLastErrorLog() { - return LastError; -} - -Error Log::getLastErrorCode() { - return LastErrorCode; -} - -void Log::clearLastError() { - LastErrorCode = NoError; - LastError = ""; -} - -Error Log::createLastError( Error err, std::string log ) { - switch ( err ) { - case FileNotFound: - LastError = "File not found ( " + log + " )"; - break; - case FileRepeated: - LastError = "File repeated in watches ( " + log + " )"; - break; - case FileOutOfScope: - LastError = "Symlink file out of scope ( " + log + " )"; - break; - case FileRemote: - LastError = - "File is located in a remote file system, use a generic watcher. ( " + log + " )"; - break; - case WatcherFailed: - LastError = "File system watcher failed ( " + log + " )"; - break; - case Unspecified: - default: - LastError = log; - } - - efDEBUG( "%s\n", LastError.c_str() ); - return err; -} - -}} // namespace efsw::Errors diff --git a/vendor/efsw/src/efsw/Mutex.cpp b/vendor/efsw/src/efsw/Mutex.cpp deleted file mode 100644 index c961db1..0000000 --- a/vendor/efsw/src/efsw/Mutex.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -namespace efsw { - -Mutex::Mutex() : mMutexImpl( new Platform::MutexImpl() ) {} - -Mutex::~Mutex() { - efSAFE_DELETE( mMutexImpl ); -} - -void Mutex::lock() { - mMutexImpl->lock(); -} - -void Mutex::unlock() { - mMutexImpl->unlock(); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/Mutex.hpp b/vendor/efsw/src/efsw/Mutex.hpp deleted file mode 100644 index d98ad17..0000000 --- a/vendor/efsw/src/efsw/Mutex.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef EFSW_MUTEX_HPP -#define EFSW_MUTEX_HPP - -#include - -namespace efsw { - -namespace Platform { -class MutexImpl; -} - -/** Simple mutex class */ -class Mutex { - public: - Mutex(); - - ~Mutex(); - - /** Lock the mutex */ - void lock(); - - /** Unlock the mutex */ - void unlock(); - - private: - Platform::MutexImpl* mMutexImpl; -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/String.cpp b/vendor/efsw/src/efsw/String.cpp deleted file mode 100644 index 8c9a3cc..0000000 --- a/vendor/efsw/src/efsw/String.cpp +++ /dev/null @@ -1,669 +0,0 @@ -#include -#include -#include - -namespace efsw { - -const std::size_t String::InvalidPos = StringType::npos; - -std::vector String::split( const std::string& str, const char& splitchar, - const bool& pushEmptyString ) { - std::vector tmp; - std::string tmpstr; - - for ( size_t i = 0; i < str.size(); i++ ) { - if ( str[i] == splitchar ) { - if ( pushEmptyString || tmpstr.size() ) { - tmp.push_back( tmpstr ); - tmpstr = ""; - } - } else { - tmpstr += str[i]; - } - } - - if ( tmpstr.size() ) { - tmp.push_back( tmpstr ); - } - - return tmp; -} - -std::vector String::split( const String& str, const Uint32& splitchar, - const bool& pushEmptyString ) { - std::vector tmp; - String tmpstr; - - for ( size_t i = 0; i < str.size(); i++ ) { - if ( str[i] == splitchar ) { - if ( pushEmptyString || tmpstr.size() ) { - tmp.push_back( tmpstr ); - tmpstr = ""; - } - } else { - tmpstr += str[i]; - } - } - - if ( tmpstr.size() ) { - tmp.push_back( tmpstr ); - } - - return tmp; -} - -int String::strStartsWith( const std::string& start, const std::string& str ) { - int pos = -1; - size_t size = start.size(); - - if ( str.size() >= size ) { - for ( std::size_t i = 0; i < size; i++ ) { - if ( start[i] == str[i] ) { - pos = (int)i; - } else { - pos = -1; - break; - } - } - } - - return pos; -} - -int String::strStartsWith( const String& start, const String& str ) { - int pos = -1; - size_t size = start.size(); - - if ( str.size() >= size ) { - for ( std::size_t i = 0; i < size; i++ ) { - if ( start[i] == str[i] ) { - pos = (int)i; - } else { - pos = -1; - break; - } - } - } - - return pos; -} - -String::String() {} - -String::String( char ansiChar, const std::locale& locale ) { - mString += Utf32::DecodeAnsi( ansiChar, locale ); -} - -#ifndef EFSW_NO_WIDECHAR -String::String( wchar_t wideChar ) { - mString += Utf32::DecodeWide( wideChar ); -} -#endif - -String::String( StringBaseType utf32Char ) { - mString += utf32Char; -} - -String::String( const char* uf8String ) { - if ( uf8String ) { - std::size_t length = strlen( uf8String ); - - if ( length > 0 ) { - mString.reserve( length + 1 ); - - Utf8::ToUtf32( uf8String, uf8String + length, std::back_inserter( mString ) ); - } - } -} - -String::String( const std::string& utf8String ) { - mString.reserve( utf8String.length() + 1 ); - - Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( mString ) ); -} - -String::String( const char* ansiString, const std::locale& locale ) { - if ( ansiString ) { - std::size_t length = strlen( ansiString ); - if ( length > 0 ) { - mString.reserve( length + 1 ); - Utf32::FromAnsi( ansiString, ansiString + length, std::back_inserter( mString ), - locale ); - } - } -} - -String::String( const std::string& ansiString, const std::locale& locale ) { - mString.reserve( ansiString.length() + 1 ); - Utf32::FromAnsi( ansiString.begin(), ansiString.end(), std::back_inserter( mString ), locale ); -} - -#ifndef EFSW_NO_WIDECHAR -String::String( const wchar_t* wideString ) { - if ( wideString ) { - std::size_t length = std::wcslen( wideString ); - if ( length > 0 ) { - mString.reserve( length + 1 ); - Utf32::FromWide( wideString, wideString + length, std::back_inserter( mString ) ); - } - } -} - -String::String( const std::wstring& wideString ) { - mString.reserve( wideString.length() + 1 ); - Utf32::FromWide( wideString.begin(), wideString.end(), std::back_inserter( mString ) ); -} -#endif - -String::String( const StringBaseType* utf32String ) { - if ( utf32String ) - mString = utf32String; -} - -String::String( const StringType& utf32String ) : mString( utf32String ) {} - -String::String( const String& str ) : mString( str.mString ) {} - -String String::fromUtf8( const std::string& utf8String ) { - String::StringType utf32; - - utf32.reserve( utf8String.length() + 1 ); - - Utf8::ToUtf32( utf8String.begin(), utf8String.end(), std::back_inserter( utf32 ) ); - - return String( utf32 ); -} - -String::operator std::string() const { - return toAnsiString(); -} - -std::string String::toAnsiString( const std::locale& locale ) const { - // Prepare the output string - std::string output; - output.reserve( mString.length() + 1 ); - - // Convert - Utf32::ToAnsi( mString.begin(), mString.end(), std::back_inserter( output ), 0, locale ); - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -std::wstring String::toWideString() const { - // Prepare the output string - std::wstring output; - output.reserve( mString.length() + 1 ); - - // Convert - Utf32::ToWide( mString.begin(), mString.end(), std::back_inserter( output ), 0 ); - - return output; -} -#endif - -std::string String::toUtf8() const { - // Prepare the output string - std::string output; - output.reserve( mString.length() + 1 ); - - // Convert - Utf32::toUtf8( mString.begin(), mString.end(), std::back_inserter( output ) ); - - return output; -} - -String& String::operator=( const String& right ) { - mString = right.mString; - return *this; -} - -String& String::operator=( const StringBaseType& right ) { - mString = right; - return *this; -} - -String& String::operator+=( const String& right ) { - mString += right.mString; - return *this; -} - -String& String::operator+=( const StringBaseType& right ) { - mString += right; - return *this; -} - -String::StringBaseType String::operator[]( std::size_t index ) const { - return mString[index]; -} - -String::StringBaseType& String::operator[]( std::size_t index ) { - return mString[index]; -} - -String::StringBaseType String::at( std::size_t index ) const { - return mString.at( index ); -} - -void String::push_back( StringBaseType c ) { - mString.push_back( c ); -} - -void String::swap( String& str ) { - mString.swap( str.mString ); -} - -void String::clear() { - mString.clear(); -} - -std::size_t String::size() const { - return mString.size(); -} - -std::size_t String::length() const { - return mString.length(); -} - -bool String::empty() const { - return mString.empty(); -} - -void String::erase( std::size_t position, std::size_t count ) { - mString.erase( position, count ); -} - -String& String::insert( std::size_t position, const String& str ) { - mString.insert( position, str.mString ); - return *this; -} - -String& String::insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ) { - mString.insert( pos1, str.mString, pos2, n ); - return *this; -} - -String& String::insert( size_t pos1, const char* s, size_t n ) { - String tmp( s ); - - mString.insert( pos1, tmp.data(), n ); - - return *this; -} - -String& String::insert( size_t pos1, size_t n, char c ) { - mString.insert( pos1, n, c ); - return *this; -} - -String& String::insert( size_t pos1, const char* s ) { - String tmp( s ); - - mString.insert( pos1, tmp.data() ); - - return *this; -} - -String::Iterator String::insert( Iterator p, char c ) { - return mString.insert( p, c ); -} - -void String::insert( Iterator p, size_t n, char c ) { - mString.insert( p, n, c ); -} - -const String::StringBaseType* String::c_str() const { - return mString.c_str(); -} - -const String::StringBaseType* String::data() const { - return mString.data(); -} - -String::Iterator String::begin() { - return mString.begin(); -} - -String::ConstIterator String::begin() const { - return mString.begin(); -} - -String::Iterator String::end() { - return mString.end(); -} - -String::ConstIterator String::end() const { - return mString.end(); -} - -String::ReverseIterator String::rbegin() { - return mString.rbegin(); -} - -String::ConstReverseIterator String::rbegin() const { - return mString.rbegin(); -} - -String::ReverseIterator String::rend() { - return mString.rend(); -} - -String::ConstReverseIterator String::rend() const { - return mString.rend(); -} - -void String::resize( std::size_t n, StringBaseType c ) { - mString.resize( n, c ); -} - -void String::resize( std::size_t n ) { - mString.resize( n ); -} - -std::size_t String::max_size() const { - return mString.max_size(); -} - -void String::reserve( size_t res_arg ) { - mString.reserve( res_arg ); -} - -std::size_t String::capacity() const { - return mString.capacity(); -} - -String& String::assign( const String& str ) { - mString.assign( str.mString ); - return *this; -} - -String& String::assign( const String& str, size_t pos, size_t n ) { - mString.assign( str.mString, pos, n ); - return *this; -} - -String& String::assign( const char* s, size_t n ) { - String tmp( s ); - - mString.assign( tmp.mString ); - - return *this; -} - -String& String::assign( const char* s ) { - String tmp( s ); - - mString.assign( tmp.mString ); - - return *this; -} - -String& String::assign( size_t n, char c ) { - mString.assign( n, c ); - - return *this; -} - -String& String::append( const String& str ) { - mString.append( str.mString ); - - return *this; -} - -String& String::append( const String& str, size_t pos, size_t n ) { - mString.append( str.mString, pos, n ); - - return *this; -} - -String& String::append( const char* s, size_t n ) { - String tmp( s ); - - mString.append( tmp.mString ); - - return *this; -} - -String& String::append( const char* s ) { - String tmp( s ); - - mString.append( tmp.mString ); - - return *this; -} - -String& String::append( size_t n, char c ) { - mString.append( n, c ); - - return *this; -} - -String& String::append( std::size_t n, StringBaseType c ) { - mString.append( n, c ); - - return *this; -} - -String& String::replace( size_t pos1, size_t n1, const String& str ) { - mString.replace( pos1, n1, str.mString ); - - return *this; -} - -String& String::replace( Iterator i1, Iterator i2, const String& str ) { - mString.replace( i1, i2, str.mString ); - - return *this; -} - -String& String::replace( size_t pos1, size_t n1, const String& str, size_t pos2, size_t n2 ) { - mString.replace( pos1, n1, str.mString, pos2, n2 ); - - return *this; -} - -String& String::replace( size_t pos1, size_t n1, const char* s, size_t n2 ) { - String tmp( s ); - - mString.replace( pos1, n1, tmp.data(), n2 ); - - return *this; -} - -String& String::replace( Iterator i1, Iterator i2, const char* s, size_t n2 ) { - String tmp( s ); - - mString.replace( i1, i2, tmp.data(), n2 ); - - return *this; -} - -String& String::replace( size_t pos1, size_t n1, const char* s ) { - String tmp( s ); - - mString.replace( pos1, n1, tmp.mString ); - - return *this; -} - -String& String::replace( Iterator i1, Iterator i2, const char* s ) { - String tmp( s ); - - mString.replace( i1, i2, tmp.mString ); - - return *this; -} - -String& String::replace( size_t pos1, size_t n1, size_t n2, char c ) { - mString.replace( pos1, n1, n2, (StringBaseType)c ); - - return *this; -} - -String& String::replace( Iterator i1, Iterator i2, size_t n2, char c ) { - mString.replace( i1, i2, n2, (StringBaseType)c ); - - return *this; -} - -std::size_t String::find( const String& str, std::size_t start ) const { - return mString.find( str.mString, start ); -} - -std::size_t String::find( const char* s, std::size_t pos, std::size_t n ) const { - return find( String( s ), pos ); -} - -std::size_t String::find( const char* s, std::size_t pos ) const { - return find( String( s ), pos ); -} - -size_t String::find( char c, std::size_t pos ) const { - return mString.find( (StringBaseType)c, pos ); -} - -std::size_t String::rfind( const String& str, std::size_t pos ) const { - return mString.rfind( str.mString, pos ); -} - -std::size_t String::rfind( const char* s, std::size_t pos, std::size_t n ) const { - return rfind( String( s ), pos ); -} - -std::size_t String::rfind( const char* s, std::size_t pos ) const { - return rfind( String( s ), pos ); -} - -std::size_t String::rfind( char c, std::size_t pos ) const { - return mString.rfind( c, pos ); -} - -std::size_t String::copy( StringBaseType* s, std::size_t n, std::size_t pos ) const { - return mString.copy( s, n, pos ); -} - -String String::substr( std::size_t pos, std::size_t n ) const { - return String( mString.substr( pos, n ) ); -} - -int String::compare( const String& str ) const { - return mString.compare( str.mString ); -} - -int String::compare( const char* s ) const { - return compare( String( s ) ); -} - -int String::compare( std::size_t pos1, std::size_t n1, const String& str ) const { - return mString.compare( pos1, n1, str.mString ); -} - -int String::compare( std::size_t pos1, std::size_t n1, const char* s ) const { - return compare( pos1, n1, String( s ) ); -} - -int String::compare( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, - std::size_t n2 ) const { - return mString.compare( pos1, n1, str.mString, pos2, n2 ); -} - -int String::compare( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ) const { - return compare( pos1, n1, String( s ), 0, n2 ); -} - -std::size_t String::find_first_of( const String& str, std::size_t pos ) const { - return mString.find_first_of( str.mString, pos ); -} - -std::size_t String::find_first_of( const char* s, std::size_t pos, std::size_t n ) const { - return find_first_of( String( s ), pos ); -} - -std::size_t String::find_first_of( const char* s, std::size_t pos ) const { - return find_first_of( String( s ), pos ); -} - -std::size_t String::find_first_of( StringBaseType c, std::size_t pos ) const { - return mString.find_first_of( c, pos ); -} - -std::size_t String::find_last_of( const String& str, std::size_t pos ) const { - return mString.find_last_of( str.mString, pos ); -} - -std::size_t String::find_last_of( const char* s, std::size_t pos, std::size_t n ) const { - return find_last_of( String( s ), pos ); -} - -std::size_t String::find_last_of( const char* s, std::size_t pos ) const { - return find_last_of( String( s ), pos ); -} - -std::size_t String::find_last_of( StringBaseType c, std::size_t pos ) const { - return mString.find_last_of( c, pos ); -} - -std::size_t String::find_first_not_of( const String& str, std::size_t pos ) const { - return mString.find_first_not_of( str.mString, pos ); -} - -std::size_t String::find_first_not_of( const char* s, std::size_t pos, std::size_t n ) const { - return find_first_not_of( String( s ), pos ); -} - -std::size_t String::find_first_not_of( const char* s, std::size_t pos ) const { - return find_first_not_of( String( s ), pos ); -} - -std::size_t String::find_first_not_of( StringBaseType c, std::size_t pos ) const { - return mString.find_first_not_of( c, pos ); -} - -std::size_t String::find_last_not_of( const String& str, std::size_t pos ) const { - return mString.find_last_not_of( str.mString, pos ); -} - -std::size_t String::find_last_not_of( const char* s, std::size_t pos, std::size_t n ) const { - return find_last_not_of( String( s ), pos ); -} - -std::size_t String::find_last_not_of( const char* s, std::size_t pos ) const { - return find_last_not_of( String( s ), pos ); -} - -std::size_t String::find_last_not_of( StringBaseType c, std::size_t pos ) const { - return mString.find_last_not_of( c, pos ); -} - -bool operator==( const String& left, const String& right ) { - return left.mString == right.mString; -} - -bool operator!=( const String& left, const String& right ) { - return !( left == right ); -} - -bool operator<( const String& left, const String& right ) { - return left.mString < right.mString; -} - -bool operator>( const String& left, const String& right ) { - return right < left; -} - -bool operator<=( const String& left, const String& right ) { - return !( right < left ); -} - -bool operator>=( const String& left, const String& right ) { - return !( left < right ); -} - -String operator+( const String& left, const String& right ) { - String string = left; - string += right; - - return string; -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/String.hpp b/vendor/efsw/src/efsw/String.hpp deleted file mode 100644 index b42b945..0000000 --- a/vendor/efsw/src/efsw/String.hpp +++ /dev/null @@ -1,630 +0,0 @@ -/** NOTE: - * This code is based on the Utf implementation from SFML2. License zlib/png ( - *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not - *the original implementation from SFML2. Functions and methods are the same that in std::string to - *facilitate portability. - **/ - -#ifndef EFSW_STRING_HPP -#define EFSW_STRING_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace efsw { - -/** @brief Utility string class that automatically handles conversions between types and encodings - * **/ -class String { - public: - typedef char32_t StringBaseType; - typedef std::basic_string StringType; - typedef StringType::iterator Iterator; //! Iterator type - typedef StringType::const_iterator ConstIterator; //! Constant iterator type - typedef StringType::reverse_iterator ReverseIterator; //! Reverse Iterator type - typedef StringType::const_reverse_iterator ConstReverseIterator; //! Constant iterator type - - static const std::size_t InvalidPos; ///< Represents an invalid position in the string - - template static std::string toStr( const T& i ) { - std::ostringstream ss; - ss << i; - return ss.str(); - } - - /** Converts from a string to type */ - template - static bool fromString( T& t, const std::string& s, - std::ios_base& ( *f )( std::ios_base& ) = std::dec ) { - std::istringstream iss( s ); - return !( iss >> f >> t ).fail(); - } - - /** Converts from a String to type */ - template - static bool fromString( T& t, const String& s, - std::ios_base& ( *f )( std::ios_base& ) = std::dec ) { - std::istringstream iss( s.toUtf8() ); - return !( iss >> f >> t ).fail(); - } - - /** Split a string and hold it on a vector */ - static std::vector split( const std::string& str, const char& splitchar, - const bool& pushEmptyString = false ); - - /** Split a string and hold it on a vector */ - static std::vector split( const String& str, const Uint32& splitchar, - const bool& pushEmptyString = false ); - - /** Determine if a string starts with the string passed - ** @param start The substring expected to start - ** @param str The string to compare - ** @return -1 if the substring is no in str, otherwise the size of the substring - */ - static int strStartsWith( const std::string& start, const std::string& str ); - - static int strStartsWith( const String& start, const String& str ); - - /** @brief Construct from an UTF-8 string to UTF-32 according - ** @param uf8String UTF-8 string to convert - **/ - static String fromUtf8( const std::string& utf8String ); - - /** @brief Default constructor - ** This constructor creates an empty string. - **/ - String(); - - /** @brief Construct from a single ANSI character and a locale - ** The source character is converted to UTF-32 according - ** to the given locale. If you want to use the current global - ** locale, rather use the other constructor. - ** @param ansiChar ANSI character to convert - ** @param locale Locale to use for conversion - **/ - String( char ansiChar, const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - /** @brief Construct from single wide character - ** @param wideChar Wide character to convert - **/ - String( wchar_t wideChar ); -#endif - - /** @brief Construct from single UTF-32 character - ** @param utf32Char UTF-32 character to convert - **/ - String( StringBaseType utf32Char ); - - /** @brief Construct from an from a null-terminated C-style UTF-8 string to UTF-32 - ** @param uf8String UTF-8 string to convert - **/ - String( const char* uf8String ); - - /** @brief Construct from an UTF-8 string to UTF-32 according - ** @param uf8String UTF-8 string to convert - **/ - String( const std::string& utf8String ); - - /** @brief Construct from a null-terminated C-style ANSI string and a locale - ** The source string is converted to UTF-32 according - ** to the given locale. If you want to use the current global - ** locale, rather use the other constructor. - ** @param ansiString ANSI string to convert - ** @param locale Locale to use for conversion - **/ - String( const char* ansiString, const std::locale& locale ); - - /** @brief Construct from an ANSI string and a locale - ** The source string is converted to UTF-32 according - ** to the given locale. If you want to use the current global - ** locale, rather use the other constructor. - ** @param ansiString ANSI string to convert - ** @param locale Locale to use for conversion - **/ - String( const std::string& ansiString, const std::locale& locale ); - -#ifndef EFSW_NO_WIDECHAR - /** @brief Construct from null-terminated C-style wide string - ** @param wideString Wide string to convert - **/ - String( const wchar_t* wideString ); - - /** @brief Construct from a wide string - ** @param wideString Wide string to convert - **/ - String( const std::wstring& wideString ); -#endif - - /** @brief Construct from a null-terminated C-style UTF-32 string - ** @param utf32String UTF-32 string to assign - **/ - String( const StringBaseType* utf32String ); - - /** @brief Construct from an UTF-32 string - ** @param utf32String UTF-32 string to assign - **/ - String( const StringType& utf32String ); - - /** @brief Copy constructor - ** @param str Instance to copy - **/ - String( const String& str ); - - /** @brief Implicit cast operator to std::string (ANSI string) - ** The current global locale is used for conversion. If you - ** want to explicitely specify a locale, see toAnsiString. - ** Characters that do not fit in the target encoding are - ** discarded from the returned string. - ** This operator is defined for convenience, and is equivalent - ** to calling toAnsiString(). - ** @return Converted ANSI string - ** @see toAnsiString, operator String - **/ - operator std::string() const; - - /** @brief Convert the unicode string to an ANSI string - ** The UTF-32 string is converted to an ANSI string in - ** the encoding defined by \a locale. If you want to use - ** the current global locale, see the other overload - ** of toAnsiString. - ** Characters that do not fit in the target encoding are - ** discarded from the returned string. - ** @param locale Locale to use for conversion - ** @return Converted ANSI string - ** @see toWideString, operator std::string - **/ - std::string toAnsiString( const std::locale& locale = std::locale() ) const; - -#ifndef EFSW_NO_WIDECHAR - /** @brief Convert the unicode string to a wide string - ** Characters that do not fit in the target encoding are - ** discarded from the returned string. - ** @return Converted wide string - ** @see toAnsiString, operator String - **/ - std::wstring toWideString() const; -#endif - - std::string toUtf8() const; - - /** @brief Overload of assignment operator - ** @param right Instance to assign - ** @return Reference to self - **/ - String& operator=( const String& right ); - - String& operator=( const StringBaseType& right ); - - /** @brief Overload of += operator to append an UTF-32 string - ** @param right String to append - ** @return Reference to self - **/ - String& operator+=( const String& right ); - - String& operator+=( const StringBaseType& right ); - - /** @brief Overload of [] operator to access a character by its position - ** This function provides read-only access to characters. - ** Note: this function doesn't throw if \a index is out of range. - ** @param index Index of the character to get - ** @return Character at position \a index - **/ - StringBaseType operator[]( std::size_t index ) const; - - /** @brief Overload of [] operator to access a character by its position - ** This function provides read and write access to characters. - ** Note: this function doesn't throw if \a index is out of range. - ** @param index Index of the character to get - ** @return Reference to the character at position \a index - **/ - - StringBaseType& operator[]( std::size_t index ); - - /** @brief Get character in string - ** Performs a range check, throwing an exception of type out_of_range in case that pos is not an - *actual position in the string. - ** @return The character at position pos in the string. - */ - StringBaseType at( std::size_t index ) const; - - /** @brief clear the string - ** This function removes all the characters from the string. - ** @see empty, erase - **/ - void clear(); - - /** @brief Get the size of the string - ** @return Number of characters in the string - ** @see empty - **/ - std::size_t size() const; - - /** @see size() */ - std::size_t length() const; - - /** @brief Check whether the string is empty or not - ** @return True if the string is empty (i.e. contains no character) - ** @see clear, size - **/ - bool empty() const; - - /** @brief Erase one or more characters from the string - ** This function removes a sequence of \a count characters - ** starting from \a position. - ** @param position Position of the first character to erase - ** @param count Number of characters to erase - **/ - void erase( std::size_t position, std::size_t count = 1 ); - - /** @brief Insert one or more characters into the string - ** This function inserts the characters of \a str - ** into the string, starting from \a position. - ** @param position Position of insertion - ** @param str Characters to insert - **/ - String& insert( std::size_t position, const String& str ); - - String& insert( std::size_t pos1, const String& str, std::size_t pos2, std::size_t n ); - - String& insert( std::size_t pos1, const char* s, std::size_t n ); - - String& insert( std::size_t pos1, const char* s ); - - String& insert( std::size_t pos1, size_t n, char c ); - - Iterator insert( Iterator p, char c ); - - void insert( Iterator p, std::size_t n, char c ); - - template - void insert( Iterator p, InputIterator first, InputIterator last ) { - mString.insert( p, first, last ); - } - - /** @brief Find a sequence of one or more characters in the string - ** This function searches for the characters of \a str - ** into the string, starting from \a start. - ** @param str Characters to find - ** @param start Where to begin searching - ** @return Position of \a str in the string, or String::InvalidPos if not found - **/ - std::size_t find( const String& str, std::size_t start = 0 ) const; - - std::size_t find( const char* s, std::size_t pos, std::size_t n ) const; - - std::size_t find( const char* s, std::size_t pos = 0 ) const; - - std::size_t find( char c, std::size_t pos = 0 ) const; - - /** @brief Get a pointer to the C-style array of characters - ** This functions provides a read-only access to a - ** null-terminated C-style representation of the string. - ** The returned pointer is temporary and is meant only for - ** immediate use, thus it is not recommended to store it. - ** @return Read-only pointer to the array of characters - **/ - const StringBaseType* c_str() const; - - /** @brief Get string data - ** Notice that no terminating null character is appended (see member c_str for such a - *functionality). - ** The returned array points to an internal location which should not be modified directly in - *the program. - ** Its contents are guaranteed to remain unchanged only until the next call to a non-constant - *member function of the string object. - ** @return Pointer to an internal array containing the same content as the string. - **/ - const StringBaseType* data() const; - - /** @brief Return an iterator to the beginning of the string - ** @return Read-write iterator to the beginning of the string characters - ** @see end - **/ - Iterator begin(); - - /** @brief Return an iterator to the beginning of the string - ** @return Read-only iterator to the beginning of the string characters - ** @see end - **/ - ConstIterator begin() const; - - /** @brief Return an iterator to the beginning of the string - ** The end iterator refers to 1 position past the last character; - ** thus it represents an invalid character and should never be - ** accessed. - ** @return Read-write iterator to the end of the string characters - ** @see begin - **/ - Iterator end(); - - /** @brief Return an iterator to the beginning of the string - ** The end iterator refers to 1 position past the last character; - ** thus it represents an invalid character and should never be - ** accessed. - ** @return Read-only iterator to the end of the string characters - ** @see begin - **/ - ConstIterator end() const; - - /** @brief Return an reverse iterator to the beginning of the string - ** @return Read-write reverse iterator to the beginning of the string characters - ** @see end - **/ - ReverseIterator rbegin(); - - /** @brief Return an reverse iterator to the beginning of the string - ** @return Read-only reverse iterator to the beginning of the string characters - ** @see end - **/ - ConstReverseIterator rbegin() const; - - /** @brief Return an reverse iterator to the beginning of the string - ** The end reverse iterator refers to 1 position past the last character; - ** thus it represents an invalid character and should never be - ** accessed. - ** @return Read-write reverse iterator to the end of the string characters - ** @see begin - **/ - ReverseIterator rend(); - - /** @brief Return an reverse iterator to the beginning of the string - ** The end reverse iterator refers to 1 position past the last character; - ** thus it represents an invalid character and should never be - ** accessed. - ** @return Read-only reverse iterator to the end of the string characters - ** @see begin - **/ - ConstReverseIterator rend() const; - - /** @brief Resize String */ - void resize( std::size_t n, StringBaseType c ); - - /** @brief Resize String */ - void resize( std::size_t n ); - - /** @return Maximum size of string */ - std::size_t max_size() const; - - /** @brief Request a change in capacity */ - void reserve( size_t res_arg = 0 ); - - /** @return Size of allocated storage */ - std::size_t capacity() const; - - /** @brief Append character to string */ - void push_back( StringBaseType c ); - - /** @brief Swap contents with another string */ - void swap( String& str ); - - String& assign( const String& str ); - - String& assign( const String& str, std::size_t pos, std::size_t n ); - - String& assign( const char* s, std::size_t n ); - - String& assign( const char* s ); - - String& assign( std::size_t n, char c ); - - template String& assign( InputIterator first, InputIterator last ) { - mString.assign( first, last ); - return *this; - } - - String& append( const String& str ); - - String& append( const String& str, std::size_t pos, std::size_t n ); - - String& append( const char* s, std::size_t n ); - - String& append( const char* s ); - - String& append( std::size_t n, char c ); - - String& append( std::size_t n, StringBaseType c ); - - template String& append( InputIterator first, InputIterator last ) { - mString.append( first, last ); - return *this; - } - - String& replace( std::size_t pos1, std::size_t n1, const String& str ); - - String& replace( Iterator i1, Iterator i2, const String& str ); - - String& replace( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, - std::size_t n2 ); - - String& replace( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ); - - String& replace( Iterator i1, Iterator i2, const char* s, std::size_t n2 ); - - String& replace( std::size_t pos1, std::size_t n1, const char* s ); - - String& replace( Iterator i1, Iterator i2, const char* s ); - - String& replace( std::size_t pos1, std::size_t n1, std::size_t n2, char c ); - - String& replace( Iterator i1, Iterator i2, std::size_t n2, char c ); - - template - String& replace( Iterator i1, Iterator i2, InputIterator j1, InputIterator j2 ) { - mString.replace( i1, i2, j1, j2 ); - return *this; - } - - std::size_t rfind( const String& str, std::size_t pos = StringType::npos ) const; - - std::size_t rfind( const char* s, std::size_t pos, std::size_t n ) const; - - std::size_t rfind( const char* s, std::size_t pos = StringType::npos ) const; - - std::size_t rfind( char c, std::size_t pos = StringType::npos ) const; - - String substr( std::size_t pos = 0, std::size_t n = StringType::npos ) const; - - std::size_t copy( StringBaseType* s, std::size_t n, std::size_t pos = 0 ) const; - - int compare( const String& str ) const; - - int compare( const char* s ) const; - - int compare( std::size_t pos1, std::size_t n1, const String& str ) const; - - int compare( std::size_t pos1, std::size_t n1, const char* s ) const; - - int compare( std::size_t pos1, std::size_t n1, const String& str, std::size_t pos2, - std::size_t n2 ) const; - - int compare( std::size_t pos1, std::size_t n1, const char* s, std::size_t n2 ) const; - - std::size_t find_first_of( const String& str, std::size_t pos = 0 ) const; - - std::size_t find_first_of( const char* s, std::size_t pos, std::size_t n ) const; - - std::size_t find_first_of( const char* s, std::size_t pos = 0 ) const; - - std::size_t find_first_of( StringBaseType c, std::size_t pos = 0 ) const; - - std::size_t find_last_of( const String& str, std::size_t pos = StringType::npos ) const; - - std::size_t find_last_of( const char* s, std::size_t pos, std::size_t n ) const; - - std::size_t find_last_of( const char* s, std::size_t pos = StringType::npos ) const; - - std::size_t find_last_of( StringBaseType c, std::size_t pos = StringType::npos ) const; - - std::size_t find_first_not_of( const String& str, std::size_t pos = 0 ) const; - - std::size_t find_first_not_of( const char* s, std::size_t pos, std::size_t n ) const; - - std::size_t find_first_not_of( const char* s, std::size_t pos = 0 ) const; - - std::size_t find_first_not_of( StringBaseType c, std::size_t pos = 0 ) const; - - std::size_t find_last_not_of( const String& str, std::size_t pos = StringType::npos ) const; - - std::size_t find_last_not_of( const char* s, std::size_t pos, std::size_t n ) const; - - std::size_t find_last_not_of( const char* s, std::size_t pos = StringType::npos ) const; - - std::size_t find_last_not_of( StringBaseType c, std::size_t pos = StringType::npos ) const; - - private: - friend bool operator==( const String& left, const String& right ); - friend bool operator<( const String& left, const String& right ); - - StringType mString; ///< Internal string of UTF-32 characters -}; - -/** @relates String -** @brief Overload of == operator to compare two UTF-32 strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return True if both strings are equal -**/ -bool operator==( const String& left, const String& right ); - -/** @relates String -** @brief Overload of != operator to compare two UTF-32 strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return True if both strings are different -**/ -bool operator!=( const String& left, const String& right ); - -/** @relates String -** @brief Overload of < operator to compare two UTF-32 strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return True if \a left is alphabetically lesser than \a right -**/ -bool operator<( const String& left, const String& right ); - -/** @relates String -** @brief Overload of > operator to compare two UTF-32 strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return True if \a left is alphabetically greater than \a right -**/ -bool operator>( const String& left, const String& right ); - -/** @relates String -** @brief Overload of <= operator to compare two UTF-32 strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return True if \a left is alphabetically lesser or equal than \a right -**/ -bool operator<=( const String& left, const String& right ); - -/** @relates String -** @brief Overload of >= operator to compare two UTF-32 strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return True if \a left is alphabetically greater or equal than \a right -**/ -bool operator>=( const String& left, const String& right ); - -/** @relates String -** @brief Overload of binary + operator to concatenate two strings -** @param left Left operand (a string) -** @param right Right operand (a string) -** @return Concatenated string -**/ -String operator+( const String& left, const String& right ); - -} // namespace efsw - -#endif - -/** @class efsw::String -** @ingroup system -** efsw::String is a utility string class defined mainly for -** convenience. It is a Unicode string (implemented using -** UTF-32), thus it can store any character in the world -** (european, chinese, arabic, hebrew, etc.). -** It automatically handles conversions from/to ANSI and -** wide strings, so that you can work with standard string -** classes and still be compatible with functions taking a -** efsw::String. -** @code -** efsw::String s; -** std::string s1 = s; // automatically converted to ANSI string -** String s2 = s; // automatically converted to wide string -** s = "hello"; // automatically converted from ANSI string -** s = L"hello"; // automatically converted from wide string -** s += 'a'; // automatically converted from ANSI string -** s += L'a'; // automatically converted from wide string -** @endcode -** Conversions involving ANSI strings use the default user locale. However -** it is possible to use a custom locale if necessary: -** @code -** std::locale locale; -** efsw::String s; -** ... -** std::string s1 = s.toAnsiString(locale); -** s = efsw::String("hello", locale); -** @endcode -** -** efsw::String defines the most important functions of the -** standard std::string class: removing, random access, iterating, -** appending, comparing, etc. However it is a simple class -** provided for convenience, and you may have to consider using -** a more optimized class if your program requires complex string -** handling. The automatic conversion functions will then take -** care of converting your string to efsw::String whenever EE -** requires it. -** -** Please note that EE also defines a low-level, generic -** interface for Unicode handling, see the efsw::Utf classes. -** -** All credits to Laurent Gomila, i just modified and expanded a little bit the implementation. -**/ diff --git a/vendor/efsw/src/efsw/System.cpp b/vendor/efsw/src/efsw/System.cpp deleted file mode 100644 index ba68bf4..0000000 --- a/vendor/efsw/src/efsw/System.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -namespace efsw { - -void System::sleep( const unsigned long& ms ) { - Platform::System::sleep( ms ); -} - -std::string System::getProcessPath() { - return Platform::System::getProcessPath(); -} - -void System::maxFD() { - Platform::System::maxFD(); -} - -Uint64 System::getMaxFD() { - return Platform::System::getMaxFD(); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/System.hpp b/vendor/efsw/src/efsw/System.hpp deleted file mode 100644 index 498e121..0000000 --- a/vendor/efsw/src/efsw/System.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EFSW_SYSTEM_HPP -#define EFSW_SYSTEM_HPP - -#include - -namespace efsw { - -class System { - public: - /// Sleep for x milliseconds - static void sleep( const unsigned long& ms ); - - /// @return The process binary path - static std::string getProcessPath(); - - /// Maximize the number of file descriptors allowed per process in the current OS - static void maxFD(); - - /// @return The number of supported file descriptors for the process - static Uint64 getMaxFD(); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/Thread.cpp b/vendor/efsw/src/efsw/Thread.cpp deleted file mode 100644 index cfa88b4..0000000 --- a/vendor/efsw/src/efsw/Thread.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -namespace efsw { - -Thread::Thread() : mThreadImpl( NULL ), mEntryPoint( NULL ) {} - -Thread::~Thread() { - wait(); - - efSAFE_DELETE( mEntryPoint ); -} - -void Thread::launch() { - wait(); - - mThreadImpl = new Platform::ThreadImpl( this ); -} - -void Thread::wait() { - if ( mThreadImpl ) { - mThreadImpl->wait(); - - efSAFE_DELETE( mThreadImpl ); - } -} - -void Thread::terminate() { - if ( mThreadImpl ) { - mThreadImpl->terminate(); - - efSAFE_DELETE( mThreadImpl ); - } -} - -void Thread::run() { - if ( mEntryPoint ) - mEntryPoint->run(); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/Thread.hpp b/vendor/efsw/src/efsw/Thread.hpp deleted file mode 100644 index b60373c..0000000 --- a/vendor/efsw/src/efsw/Thread.hpp +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef EFSW_THREAD_HPP -#define EFSW_THREAD_HPP - -#include - -namespace efsw { - -namespace Platform { -class ThreadImpl; -} -namespace Private { -struct ThreadFunc; -} - -/** @brief Thread manager class */ -class Thread { - public: - typedef void ( *FuncType )( void* ); - - template Thread( F function ); - - template Thread( F function, A argument ); - - template Thread( void ( C::*function )(), C* object ); - - virtual ~Thread(); - - /** Launch the thread */ - virtual void launch(); - - /** Wait the thread until end */ - void wait(); - - /** Terminate the thread */ - void terminate(); - - protected: - Thread(); - - private: - friend class Platform::ThreadImpl; - - /** The virtual function to run in the thread */ - virtual void run(); - - Platform::ThreadImpl* mThreadImpl; ///< OS-specific implementation of the thread - Private::ThreadFunc* mEntryPoint; ///< Abstraction of the function to run -}; - -//! NOTE: Taken from SFML2 threads -namespace Private { - -// Base class for abstract thread functions -struct ThreadFunc { - virtual ~ThreadFunc() {} - virtual void run() = 0; -}; - -// Specialization using a functor (including free functions) with no argument -template struct ThreadFunctor : ThreadFunc { - ThreadFunctor( T functor ) : m_functor( functor ) {} - virtual void run() { m_functor(); } - T m_functor; -}; - -// Specialization using a functor (including free functions) with one argument -template struct ThreadFunctorWithArg : ThreadFunc { - ThreadFunctorWithArg( F function, A arg ) : m_function( function ), m_arg( arg ) {} - virtual void run() { m_function( m_arg ); } - F m_function; - A m_arg; -}; - -// Specialization using a member function -template struct ThreadMemberFunc : ThreadFunc { - ThreadMemberFunc( void ( C::*function )(), C* object ) : - m_function( function ), m_object( object ) {} - virtual void run() { ( m_object->*m_function )(); } - void ( C::*m_function )(); - C* m_object; -}; - -} // namespace Private - -template -Thread::Thread( F functor ) : - mThreadImpl( NULL ), mEntryPoint( new Private::ThreadFunctor( functor ) ) {} - -template -Thread::Thread( F function, A argument ) : - mThreadImpl( NULL ), - mEntryPoint( new Private::ThreadFunctorWithArg( function, argument ) ) {} - -template -Thread::Thread( void ( C::*function )(), C* object ) : - mThreadImpl( NULL ), mEntryPoint( new Private::ThreadMemberFunc( function, object ) ) {} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/Utf.hpp b/vendor/efsw/src/efsw/Utf.hpp deleted file mode 100644 index 1b042cd..0000000 --- a/vendor/efsw/src/efsw/Utf.hpp +++ /dev/null @@ -1,721 +0,0 @@ -/** NOTE: - * This code is based on the Utf implementation from SFML2. License zlib/png ( - *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not - *the original implementation from SFML2. - * */ - -#ifndef EFSW_UTF_HPP -#define EFSW_UTF_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include -#include -#include - -namespace efsw { - -template class Utf; - -//////////////////////////////////////////////////////////// -/// \brief Specialization of the Utf template for UTF-8 -/// -//////////////////////////////////////////////////////////// -template <> class Utf<8> { - public: - //////////////////////////////////////////////////////////// - /// \brief Decode a single UTF-8 character - /// - /// Decoding a character means finding its unique 32-bits - /// code (called the codepoint) in the Unicode standard. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Codepoint of the decoded UTF-8 character - /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template - static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-8 character - /// - /// Encoding a character means converting a unique 32-bits - /// code (called the codepoint) in the target encoding, UTF-8. - /// - /// \param input Codepoint to encode as UTF-8 - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Advance to the next UTF-8 character - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static In Next( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Count the number of characters of a UTF-8 sequence - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element, thus the - /// total size can be different from (begin - end). - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static std::size_t Count( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an ANSI characters range to UTF-8 - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a wide characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromWide( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromLatin1( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-8 characters range to ANSI characters - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToAnsi( In begin, In end, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-8 characters range to wide characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); -#endif - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-8 characters range to UTF-8 - /// - /// This functions does nothing more than a direct copy; - /// it is defined only to provide the same interface as other - /// specializations of the efsw::Utf<> template, and allow - /// generic code to be written on top of it. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out toUtf8( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-8 characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf16( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-8 characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf32( In begin, In end, Out output ); -}; - -//////////////////////////////////////////////////////////// -/// \brief Specialization of the Utf template for UTF-16 -/// -//////////////////////////////////////////////////////////// -template <> class Utf<16> { - public: - //////////////////////////////////////////////////////////// - /// \brief Decode a single UTF-16 character - /// - /// Decoding a character means finding its unique 32-bits - /// code (called the codepoint) in the Unicode standard. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Codepoint of the decoded UTF-16 character - /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template - static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-16 character - /// - /// Encoding a character means converting a unique 32-bits - /// code (called the codepoint) in the target encoding, UTF-16. - /// - /// \param input Codepoint to encode as UTF-16 - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Advance to the next UTF-16 character - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static In Next( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Count the number of characters of a UTF-16 sequence - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element, thus the - /// total size can be different from (begin - end). - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static std::size_t Count( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an ANSI characters range to UTF-16 - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a wide characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromWide( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromLatin1( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to ANSI characters - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToAnsi( In begin, In end, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to wide characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); -#endif - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-16 characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out toUtf8( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-16 characters range to UTF-16 - /// - /// This functions does nothing more than a direct copy; - /// it is defined only to provide the same interface as other - /// specializations of the efsw::Utf<> template, and allow - /// generic code to be written on top of it. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf16( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-16 characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf32( In begin, In end, Out output ); -}; - -//////////////////////////////////////////////////////////// -/// \brief Specialization of the Utf template for UTF-32 -/// -//////////////////////////////////////////////////////////// -template <> class Utf<32> { - public: - //////////////////////////////////////////////////////////// - /// \brief Decode a single UTF-32 character - /// - /// Decoding a character means finding its unique 32-bits - /// code (called the codepoint) in the Unicode standard. - /// For UTF-32, the character value is the same as the codepoint. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Codepoint of the decoded UTF-32 character - /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template - static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-32 character - /// - /// Encoding a character means converting a unique 32-bits - /// code (called the codepoint) in the target encoding, UTF-32. - /// For UTF-32, the codepoint is the same as the character value. - /// - /// \param input Codepoint to encode as UTF-32 - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Advance to the next UTF-32 character - /// - /// This function is trivial for UTF-32, which can store - /// every character in a single storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static In Next( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Count the number of characters of a UTF-32 sequence - /// - /// This function is trivial for UTF-32, which can store - /// every character in a single storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static std::size_t Count( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an ANSI characters range to UTF-32 - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a wide characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromWide( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromLatin1( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-32 characters range to ANSI characters - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToAnsi( In begin, In end, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-32 characters range to wide characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); -#endif - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-32 characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out toUtf8( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-32 characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf16( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-32 characters range to UTF-32 - /// - /// This functions does nothing more than a direct copy; - /// it is defined only to provide the same interface as other - /// specializations of the efsw::Utf<> template, and allow - /// generic code to be written on top of it. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf32( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Decode a single ANSI character to UTF-32 - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param input Input ANSI character - /// \param locale Locale to use for conversion - /// - /// \return Converted character - /// - //////////////////////////////////////////////////////////// - template - static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Decode a single wide character to UTF-32 - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param input Input wide character - /// - /// \return Converted character - /// - //////////////////////////////////////////////////////////// - template static Uint32 DecodeWide( In input ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-32 character to ANSI - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param codepoint Iterator pointing to the beginning of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to - /// skip it) \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-32 character to wide - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param codepoint Iterator pointing to the beginning of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement if the input character is not convertible to wide (use 0 to - /// skip it) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); -#endif -}; - -#include "Utf.inl" - -// Make typedefs to get rid of the template syntax -typedef Utf<8> Utf8; -typedef Utf<16> Utf16; -typedef Utf<32> Utf32; - -} // namespace efsw -#endif - -//////////////////////////////////////////////////////////// -/// \class efsw::Utf -/// \ingroup system -/// -/// Utility class providing generic functions for UTF conversions. -/// -/// efsw::Utf is a low-level, generic interface for counting, iterating, -/// encoding and decoding Unicode characters and strings. It is able -/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. -/// -/// efsw::Utf functions are all static, these classes are not meant to -/// be instanciated. All the functions are template, so that you -/// can use any character / string type for a given encoding. -/// -/// It has 3 specializations: -/// \li efsw::Utf<8> (typedef'd to efsw::Utf8) -/// \li efsw::Utf<16> (typedef'd to efsw::Utf16) -/// \li efsw::Utf<32> (typedef'd to efsw::Utf32) -/// -//////////////////////////////////////////////////////////// diff --git a/vendor/efsw/src/efsw/Utf.inl b/vendor/efsw/src/efsw/Utf.inl deleted file mode 100644 index ef71bc8..0000000 --- a/vendor/efsw/src/efsw/Utf.inl +++ /dev/null @@ -1,576 +0,0 @@ -// References : -// http://www.unicode.org/ -// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c -// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h -// http://people.w3.org/rishida/scripts/uniview/conversion -//////////////////////////////////////////////////////////// - -template In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { - // Some useful precomputed data - static const int trailing[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; - static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, - 0x03C82080, 0xFA082080, 0x82082080 }; - - // Decode the character - int trailingBytes = trailing[static_cast( *begin )]; - if ( begin + trailingBytes < end ) { - output = 0; - switch ( trailingBytes ) { - case 5: - output += static_cast( *begin++ ); - output <<= 6; - case 4: - output += static_cast( *begin++ ); - output <<= 6; - case 3: - output += static_cast( *begin++ ); - output <<= 6; - case 2: - output += static_cast( *begin++ ); - output <<= 6; - case 1: - output += static_cast( *begin++ ); - output <<= 6; - case 0: - output += static_cast( *begin++ ); - } - output -= offsets[trailingBytes]; - } else { - // Incomplete character - begin = end; - output = replacement; - } - - return begin; -} - -template Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { - // Some useful precomputed data - static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - // Encode the character - if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { - // Invalid character - if ( replacement ) - *output++ = replacement; - } else { - // Valid character - - // Get the number of bytes to write - int bytesToWrite = 1; - if ( input < 0x80 ) - bytesToWrite = 1; - else if ( input < 0x800 ) - bytesToWrite = 2; - else if ( input < 0x10000 ) - bytesToWrite = 3; - else if ( input <= 0x0010FFFF ) - bytesToWrite = 4; - - // Extract the bytes to write - Uint8 bytes[4]; - switch ( bytesToWrite ) { - case 4: - bytes[3] = static_cast( ( input | 0x80 ) & 0xBF ); - input >>= 6; - case 3: - bytes[2] = static_cast( ( input | 0x80 ) & 0xBF ); - input >>= 6; - case 2: - bytes[1] = static_cast( ( input | 0x80 ) & 0xBF ); - input >>= 6; - case 1: - bytes[0] = static_cast( input | firstBytes[bytesToWrite] ); - } - - // Add them to the output - const Uint8* currentByte = bytes; - switch ( bytesToWrite ) { - case 4: - *output++ = *currentByte++; - case 3: - *output++ = *currentByte++; - case 2: - *output++ = *currentByte++; - case 1: - *output++ = *currentByte++; - } - } - - return output; -} - -template In Utf<8>::Next( In begin, In end ) { - Uint32 codepoint; - return Decode( begin, end, codepoint ); -} - -template std::size_t Utf<8>::Count( In begin, In end ) { - std::size_t length = 0; - while ( begin < end ) { - begin = Next( begin, end ); - ++length; - } - - return length; -} - -template -Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<8>::FromWide( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<8>::FromLatin1( In begin, In end, Out output ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) - output = Encode( *begin++, output ); - - return output; -} - -template -Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); - } - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeWide( codepoint, output, replacement ); - } - - return output; -} -#endif - -template -Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - *output++ = codepoint < 256 ? static_cast( codepoint ) : replacement; - } - - return output; -} - -template Out Utf<8>::toUtf8( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template Out Utf<8>::ToUtf16( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<16>::Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<8>::ToUtf32( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - *output++ = codepoint; - } - - return output; -} - -template In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { - Uint16 first = *begin++; - - // If it's a surrogate pair, first convert to a single UTF-32 character - if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { - if ( begin < end ) { - Uint32 second = *begin++; - if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { - // The second element is valid: convert the two elements to a UTF-32 character - output = static_cast( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + - 0x0010000 ); - } else { - // Invalid character - output = replacement; - } - } else { - // Invalid character - begin = end; - output = replacement; - } - } else { - // We can make a direct copy - output = first; - } - - return begin; -} - -template Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { - if ( input < 0xFFFF ) { - // The character can be copied directly, we just need to check if it's in the valid range - if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { - // Invalid character (this range is reserved) - if ( replacement ) - *output++ = replacement; - } else { - // Valid character directly convertible to a single UTF-16 character - *output++ = static_cast( input ); - } - } else if ( input > 0x0010FFFF ) { - // Invalid character (greater than the maximum unicode value) - if ( replacement ) - *output++ = replacement; - } else { - // The input character will be converted to two UTF-16 elements - input -= 0x0010000; - *output++ = static_cast( ( input >> 10 ) + 0xD800 ); - *output++ = static_cast( ( input & 0x3FFUL ) + 0xDC00 ); - } - - return output; -} - -template In Utf<16>::Next( In begin, In end ) { - Uint32 codepoint; - return Decode( begin, end, codepoint ); -} - -template std::size_t Utf<16>::Count( In begin, In end ) { - std::size_t length = 0; - while ( begin < end ) { - begin = Next( begin, end ); - ++length; - } - - return length; -} - -template -Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<16>::FromWide( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<16>::FromLatin1( In begin, In end, Out output ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template -Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); - } - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeWide( codepoint, output, replacement ); - } - - return output; -} -#endif - -template -Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) { - *output++ = *begin < 256 ? static_cast( *begin ) : replacement; - begin++; - } - - return output; -} - -template Out Utf<16>::toUtf8( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<8>::Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<16>::ToUtf16( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template Out Utf<16>::ToUtf32( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - *output++ = codepoint; - } - - return output; -} - -template In Utf<32>::Decode( In begin, In end, Uint32& output, Uint32 ) { - output = *begin++; - return begin; -} - -template Out Utf<32>::Encode( Uint32 input, Out output, Uint32 replacement ) { - *output++ = input; - return output; -} - -template In Utf<32>::Next( In begin, In end ) { - return ++begin; -} - -template std::size_t Utf<32>::Count( In begin, In end ) { - return begin - end; -} - -template -Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { - while ( begin < end ) - *output++ = DecodeAnsi( *begin++, locale ); - - return output; -} - -template Out Utf<32>::FromWide( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = DecodeWide( *begin++ ); - - return output; -} - -template Out Utf<32>::FromLatin1( In begin, In end, Out output ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template -Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { - while ( begin < end ) - output = EncodeAnsi( *begin++, output, replacement, locale ); - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { - while ( begin < end ) - output = EncodeWide( *begin++, output, replacement ); - - return output; -} -#endif - -template -Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) { - *output++ = *begin < 256 ? static_cast( *begin ) : replacement; - begin++; - } - - return output; -} - -template Out Utf<32>::toUtf8( In begin, In end, Out output ) { - while ( begin < end ) - output = Utf<8>::Encode( *begin++, output ); - - return output; -} - -template Out Utf<32>::ToUtf16( In begin, In end, Out output ) { - while ( begin < end ) - output = Utf<16>::Encode( *begin++, output ); - - return output; -} - -template Out Utf<32>::ToUtf32( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { - // On Windows, gcc's standard library (glibc++) has almost - // no support for Unicode stuff. As a consequence, in this - // context we can only use the default locale and ignore - // the one passed as parameter. - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ - ( defined( __GLIBCPP__ ) || \ - defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ - !( defined( __SGI_STL_PORT ) || \ - defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ - - wchar_t character = 0; - mbtowc( &character, &input, 1 ); - return static_cast( character ); - -#else -// Get the facet of the locale which deals with character conversion -#ifndef EFSW_NO_WIDECHAR - const std::ctype& facet = std::use_facet>( locale ); -#else - const std::ctype& facet = std::use_facet>( locale ); -#endif - - // Use the facet to convert each character of the input string - return static_cast( facet.widen( input ) ); - -#endif -} - -template Uint32 Utf<32>::DecodeWide( In input ) { - // The encoding of wide characters is not well defined and is left to the system; - // however we can safely assume that it is UCS-2 on Windows and - // UCS-4 on Unix systems. - // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, - // and UCS-4 *is* UTF-32). - - return input; -} - -template -Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, - const std::locale& locale ) { - // On Windows, gcc's standard library (glibc++) has almost - // no support for Unicode stuff. As a consequence, in this - // context we can only use the default locale and ignore - // the one passed as parameter. - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ - ( defined( __GLIBCPP__ ) || \ - defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ - !( defined( __SGI_STL_PORT ) || \ - defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ - - char character = 0; - if ( wctomb( &character, static_cast( codepoint ) ) >= 0 ) - *output++ = character; - else if ( replacement ) - *output++ = replacement; - - return output; - -#else -// Get the facet of the locale which deals with character conversion -#ifndef EFSW_NO_WIDECHAR - const std::ctype& facet = std::use_facet>( locale ); -#else - const std::ctype& facet = std::use_facet>( locale ); -#endif - - // Use the facet to convert each character of the input string - *output++ = facet.narrow( static_cast( codepoint ), replacement ); - - return output; - -#endif -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { - // The encoding of wide characters is not well defined and is left to the system; - // however we can safely assume that it is UCS-2 on Windows and - // UCS-4 on Unix systems. - // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). - // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). - - switch ( sizeof( wchar_t ) ) { - case 4: { - *output++ = static_cast( codepoint ); - break; - } - - default: { - if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { - *output++ = static_cast( codepoint ); - } else if ( replacement ) { - *output++ = replacement; - } - break; - } - } - - return output; -} -#endif diff --git a/vendor/efsw/src/efsw/Watcher.cpp b/vendor/efsw/src/efsw/Watcher.cpp deleted file mode 100644 index 913ae3c..0000000 --- a/vendor/efsw/src/efsw/Watcher.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -namespace efsw { - -Watcher::Watcher() : ID( 0 ), Directory( "" ), Listener( NULL ), Recursive( false ) {} - -Watcher::Watcher( WatchID id, std::string directory, FileWatchListener* listener, bool recursive ) : - ID( id ), Directory( directory ), Listener( listener ), Recursive( recursive ) {} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/Watcher.hpp b/vendor/efsw/src/efsw/Watcher.hpp deleted file mode 100644 index 84f0980..0000000 --- a/vendor/efsw/src/efsw/Watcher.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef EFSW_WATCHERIMPL_HPP -#define EFSW_WATCHERIMPL_HPP - -#include -#include - -namespace efsw { - -/** @brief Base Watcher class */ -class Watcher { - public: - Watcher(); - - Watcher( WatchID id, std::string directory, FileWatchListener* listener, bool recursive ); - - virtual ~Watcher() {} - - virtual void watch() {} - - WatchID ID; - std::string Directory; - FileWatchListener* Listener; - bool Recursive; - std::string OldFileName; -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/WatcherFSEvents.cpp b/vendor/efsw/src/efsw/WatcherFSEvents.cpp deleted file mode 100644 index e9b6b70..0000000 --- a/vendor/efsw/src/efsw/WatcherFSEvents.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -namespace efsw { - -WatcherFSEvents::WatcherFSEvents() : - Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ) {} - -WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, - bool recursive, WatcherFSEvents* parent ) : - Watcher( id, directory, listener, recursive ), - FWatcher( NULL ), - FSStream( NULL ), - WatcherGen( NULL ) {} - -WatcherFSEvents::~WatcherFSEvents() { - if ( NULL != FSStream ) { - FSEventStreamStop( FSStream ); - FSEventStreamInvalidate( FSStream ); - FSEventStreamRelease( FSStream ); - } - - efSAFE_DELETE( WatcherGen ); -} - -void WatcherFSEvents::init() { - CFStringRef CFDirectory = - CFStringCreateWithCString( NULL, Directory.c_str(), kCFStringEncodingUTF8 ); - CFArrayRef CFDirectoryArray = CFArrayCreate( NULL, (const void**)&CFDirectory, 1, NULL ); - - Uint32 streamFlags = kFSEventStreamCreateFlagNone; - - if ( FileWatcherFSEvents::isGranular() ) { - streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer | - efswFSEventStreamCreateFlagUseExtendedData | - efswFSEventStreamCreateFlagUseCFTypes; - } else { - WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); - } - - FSEventStreamContext ctx; - /* Initialize context */ - ctx.version = 0; - ctx.info = this; - ctx.retain = NULL; - ctx.release = NULL; - ctx.copyDescription = NULL; - - dispatch_queue_t queue = dispatch_queue_create(NULL, NULL); - - FSStream = - FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, - CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0., streamFlags ); - - FSEventStreamSetDispatchQueue(FSStream, queue); - - FSEventStreamStart( FSStream ); - - CFRelease( CFDirectoryArray ); - CFRelease( CFDirectory ); -} - -void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, - const std::string& filename, Action action, - std::string oldFilename ) { - Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), - FileSystem::precomposeFileName( filename ), action, FileSystem::precomposeFileName( oldFilename ) ); -} - -void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, - std::string& dirPath, std::string& filePath ) { - if ( flags & efswFSEventStreamEventFlagItemCreated ) { - if ( FileInfo::exists( path ) ) { - sendFileAction( ID, dirPath, filePath, Actions::Add ); - } - } - - if ( flags & efswFSEventsModified ) { - sendFileAction( ID, dirPath, filePath, Actions::Modified ); - } - - if ( flags & efswFSEventStreamEventFlagItemRemoved ) { - // Since i don't know the order, at least i try to keep the data consistent with the real - // state - if ( !FileInfo::exists( path ) ) { - sendFileAction( ID, dirPath, filePath, Actions::Delete ); - } - } -} - -void WatcherFSEvents::handleActions( std::vector& events ) { - size_t esize = events.size(); - - for ( size_t i = 0; i < esize; i++ ) { - FSEvent& event = events[i]; - - if ( event.Flags & - ( kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped | - kFSEventStreamEventFlagEventIdsWrapped | kFSEventStreamEventFlagHistoryDone | - kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount | - kFSEventStreamEventFlagRootChanged ) ) { - continue; - } - - if ( !Recursive ) { - /** In case that is not recursive the watcher, ignore the events from subfolders */ - if ( event.Path.find_last_of( FileSystem::getOSSlash() ) != Directory.size() - 1 ) { - continue; - } - } - - if ( FileWatcherFSEvents::isGranular() ) { - std::string dirPath( FileSystem::pathRemoveFileName( event.Path ) ); - std::string filePath( FileSystem::fileNameFromPath( event.Path ) ); - - if ( event.Flags & - ( efswFSEventStreamEventFlagItemCreated | efswFSEventStreamEventFlagItemRemoved | - efswFSEventStreamEventFlagItemRenamed ) ) { - if ( dirPath != Directory ) { - DirsChanged.insert( dirPath ); - } - } - - // This is a mess. But it's FSEvents faults, because shrinks events from the same file - // in one single event ( so there's no order for them ) For example a file could have - // been added modified and erased, but i can't know if first was erased and then added - // and modified, or added, then modified and then erased. I don't know what they were - // thinking by doing this... - efDEBUG( "Event in: %s - flags: 0x%x\n", event.Path.c_str(), event.Flags ); - - if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { - if ( ( i + 1 < esize ) && - ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && - ( events[i + 1].inode == event.inode ) ) { - FSEvent& nEvent = events[i + 1]; - std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); - std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); - - if ( event.Path != nEvent.Path ) { - if ( dirPath == newDir ) { - if ( !FileInfo::exists( event.Path ) || - 0 == strcasecmp( event.Path.c_str(), nEvent.Path.c_str() ) ) { - sendFileAction( ID, dirPath, newFilepath, Actions::Moved, - filePath ); - } else { - sendFileAction( ID, dirPath, filePath, Actions::Moved, - newFilepath ); - } - } else { - sendFileAction( ID, dirPath, filePath, Actions::Delete ); - sendFileAction( ID, newDir, newFilepath, Actions::Add ); - - if ( nEvent.Flags & efswFSEventsModified ) { - sendFileAction( ID, newDir, newFilepath, Actions::Modified ); - } - } - } else { - handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); - } - - if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | - efswFSEventStreamEventFlagItemRemoved | - efswFSEventStreamEventFlagItemRenamed ) ) { - if ( newDir != Directory ) { - DirsChanged.insert( newDir ); - } - } - - // Skip the renamed file - i++; - } else if ( FileInfo::exists( event.Path ) ) { - sendFileAction( ID, dirPath, filePath, Actions::Add ); - - if ( event.Flags & efswFSEventsModified ) { - sendFileAction( ID, dirPath, filePath, Actions::Modified ); - } - } else { - sendFileAction( ID, dirPath, filePath, Actions::Delete ); - } - } else { - handleAddModDel( event.Flags, event.Path, dirPath, filePath ); - } - } else { - efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); - DirsChanged.insert( event.Path ); - } - } -} - -void WatcherFSEvents::process() { - std::set::iterator it = DirsChanged.begin(); - - for ( ; it != DirsChanged.end(); it++ ) { - if ( !FileWatcherFSEvents::isGranular() ) { - WatcherGen->watchDir( ( *it ) ); - } else { - sendFileAction( ID, FileSystem::pathRemoveFileName( ( *it ) ), - FileSystem::fileNameFromPath( ( *it ) ), Actions::Modified ); - } - } - - DirsChanged.clear(); -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/WatcherFSEvents.hpp b/vendor/efsw/src/efsw/WatcherFSEvents.hpp deleted file mode 100644 index 1c6047c..0000000 --- a/vendor/efsw/src/efsw/WatcherFSEvents.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef EFSW_WATCHERINOTIFY_HPP -#define EFSW_WATCHERINOTIFY_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include -#include -#include -#include -#include -#include - -namespace efsw { - -class FileWatcherFSEvents; - -class FSEvent { - public: - FSEvent( std::string path, long flags, Uint64 id, Uint64 inode = 0 ) : - Path( path ), Flags( flags ), Id( id ), inode( inode ) {} - - std::string Path; - long Flags; - Uint64 Id; - Uint64 inode{ 0 }; -}; - -class WatcherFSEvents : public Watcher { - public: - WatcherFSEvents(); - - WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, - WatcherFSEvents* parent = NULL ); - - ~WatcherFSEvents(); - - void init(); - - void handleActions( std::vector& events ); - - void process(); - - Atomic FWatcher; - FSEventStreamRef FSStream; - - protected: - void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, - std::string& filePath ); - - WatcherGeneric* WatcherGen; - - std::set DirsChanged; - - void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, - Action action, std::string oldFilename = "" ); -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/WatcherGeneric.cpp b/vendor/efsw/src/efsw/WatcherGeneric.cpp deleted file mode 100644 index a6bb106..0000000 --- a/vendor/efsw/src/efsw/WatcherGeneric.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include - -namespace efsw { - -WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener* fwl, - FileWatcherImpl* fw, bool recursive ) : - Watcher( id, directory, fwl, recursive ), WatcherImpl( fw ), DirWatch( NULL ) { - FileSystem::dirAddSlashAtEnd( Directory ); - - DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false ); - - DirWatch->addChilds( false ); -} - -WatcherGeneric::~WatcherGeneric() { - efSAFE_DELETE( DirWatch ); -} - -void WatcherGeneric::watch() { - DirWatch->watch(); -} - -void WatcherGeneric::watchDir( std::string dir ) { - DirWatch->watchDir( dir ); -} - -bool WatcherGeneric::pathInWatches( std::string path ) { - return DirWatch->pathInWatches( path ); -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/WatcherGeneric.hpp b/vendor/efsw/src/efsw/WatcherGeneric.hpp deleted file mode 100644 index d11ec20..0000000 --- a/vendor/efsw/src/efsw/WatcherGeneric.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef EFSW_WATCHERGENERIC_HPP -#define EFSW_WATCHERGENERIC_HPP - -#include - -namespace efsw { - -class DirWatcherGeneric; - -class WatcherGeneric : public Watcher { - public: - FileWatcherImpl* WatcherImpl; - DirWatcherGeneric* DirWatch; - - WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener* fwl, - FileWatcherImpl* fw, bool recursive ); - - ~WatcherGeneric(); - - void watch() override; - - void watchDir( std::string dir ); - - bool pathInWatches( std::string path ); -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/WatcherInotify.cpp b/vendor/efsw/src/efsw/WatcherInotify.cpp deleted file mode 100644 index 812ddae..0000000 --- a/vendor/efsw/src/efsw/WatcherInotify.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -namespace efsw { - -WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} - -bool WatcherInotify::inParentTree( WatcherInotify* parent ) { - WatcherInotify* tNext = Parent; - - while ( NULL != tNext ) { - if ( tNext == parent ) { - return true; - } - - tNext = tNext->Parent; - } - - return false; -} - -} // namespace efsw diff --git a/vendor/efsw/src/efsw/WatcherInotify.hpp b/vendor/efsw/src/efsw/WatcherInotify.hpp deleted file mode 100644 index d43935c..0000000 --- a/vendor/efsw/src/efsw/WatcherInotify.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef EFSW_WATCHERINOTIFY_HPP -#define EFSW_WATCHERINOTIFY_HPP - -#include -#include - -namespace efsw { - -class WatcherInotify : public Watcher { - public: - WatcherInotify(); - - bool inParentTree( WatcherInotify* parent ); - - WatcherInotify* Parent; - WatchID InotifyID; - - FileInfo DirInfo; -}; - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/WatcherKqueue.cpp b/vendor/efsw/src/efsw/WatcherKqueue.cpp deleted file mode 100644 index 424b989..0000000 --- a/vendor/efsw/src/efsw/WatcherKqueue.cpp +++ /dev/null @@ -1,566 +0,0 @@ -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KEVENT_RESERVE_VALUE ( 10 ) - -#ifndef O_EVTONLY -#define O_EVTONLY ( O_RDONLY | O_NONBLOCK ) -#endif - -namespace efsw { - -int comparator( const void* ke1, const void* ke2 ) { - const KEvent* kev1 = reinterpret_cast( ke1 ); - const KEvent* kev2 = reinterpret_cast( ke2 ); - - if ( NULL != kev2->udata ) { - FileInfo* fi1 = reinterpret_cast( kev1->udata ); - FileInfo* fi2 = reinterpret_cast( kev2->udata ); - - return strcmp( fi1->Filepath.c_str(), fi2->Filepath.c_str() ); - } - - return 1; -} - -WatcherKqueue::WatcherKqueue( WatchID watchid, const std::string& dirname, - FileWatchListener* listener, bool recursive, - FileWatcherKqueue* watcher, WatcherKqueue* parent ) : - Watcher( watchid, dirname, listener, recursive ), - mLastWatchID( 0 ), - mChangeListCount( 0 ), - mKqueue( kqueue() ), - mWatcher( watcher ), - mParent( parent ), - mInitOK( true ), - mErrno( 0 ) { - if ( -1 == mKqueue ) { - efDEBUG( - "kqueue() returned invalid descriptor for directory %s. File descriptors count: %ld\n", - Directory.c_str(), mWatcher->mFileDescriptorCount ); - - mInitOK = false; - mErrno = errno; - } else { - mWatcher->addFD(); - } -} - -WatcherKqueue::~WatcherKqueue() { - // Remove the childs watchers ( sub-folders watches ) - removeAll(); - - for ( size_t i = 0; i < mChangeListCount; i++ ) { - if ( NULL != mChangeList[i].udata ) { - FileInfo* fi = reinterpret_cast( mChangeList[i].udata ); - - efSAFE_DELETE( fi ); - } - } - - close( mKqueue ); - - mWatcher->removeFD(); -} - -void WatcherKqueue::addAll() { - if ( -1 == mKqueue ) { - return; - } - - // scan directory and call addFile(name, false) on each file - FileSystem::dirAddSlashAtEnd( Directory ); - - efDEBUG( "addAll(): Added folder: %s\n", Directory.c_str() ); - - // add base dir - int fd = open( Directory.c_str(), O_EVTONLY ); - - if ( -1 == fd ) { - efDEBUG( "addAll(): Couldn't open folder: %s\n", Directory.c_str() ); - - if ( EACCES != errno ) { - mInitOK = false; - } - - mErrno = errno; - - return; - } - - mDirSnap.setDirectoryInfo( Directory ); - mDirSnap.scan(); - - mChangeList.resize( KEVENT_RESERVE_VALUE ); - - // Creates the kevent for the folder - EV_SET( &mChangeList[0], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, - NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 0, 0 ); - - mWatcher->addFD(); - - // Get the files and directories from the directory - FileInfoMap files = FileSystem::filesInfoFromPath( Directory ); - - for ( FileInfoMap::iterator it = files.begin(); it != files.end(); it++ ) { - FileInfo& fi = it->second; - - if ( fi.isRegularFile() ) { - // Add the regular files kevent - addFile( fi.Filepath, false ); - } else if ( Recursive && fi.isDirectory() && fi.isReadable() ) { - // Create another watcher for the subfolders ( if recursive ) - WatchID id = addWatch( fi.Filepath, Listener, Recursive, this ); - - // If the watcher is not adding the watcher means that the directory was created - if ( id > 0 && !mWatcher->isAddingWatcher() ) { - handleFolderAction( fi.Filepath, Actions::Add ); - } - } - } -} - -void WatcherKqueue::removeAll() { - efDEBUG( "removeAll(): Removing all child watchers\n" ); - - std::vector erase; - - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { - efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); - - erase.push_back( it->second->ID ); - } - - for ( std::vector::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { - removeWatch( *eit ); - } -} - -void WatcherKqueue::addFile( const std::string& name, bool emitEvents ) { - efDEBUG( "addFile(): Added: %s\n", name.c_str() ); - - // Open the file to get the file descriptor - int fd = open( name.c_str(), O_EVTONLY ); - - if ( fd == -1 ) { - efDEBUG( "addFile(): Could open file descriptor for %s. File descriptor count: %ld\n", - name.c_str(), mWatcher->mFileDescriptorCount ); - - Errors::Log::createLastError( Errors::FileNotReadable, name ); - - if ( EACCES != errno ) { - mInitOK = false; - } - - mErrno = errno; - - return; - } - - mWatcher->addFD(); - - // increase the file kevent file count - mChangeListCount++; - - if ( mChangeListCount + KEVENT_RESERVE_VALUE > mChangeList.size() && - mChangeListCount % KEVENT_RESERVE_VALUE == 0 ) { - size_t reserve_size = mChangeList.size() + KEVENT_RESERVE_VALUE; - mChangeList.resize( reserve_size ); - efDEBUG( "addFile(): Reserverd more KEvents space for %s, space reserved %ld, list actual " - "size %ld.\n", - Directory.c_str(), reserve_size, mChangeListCount ); - } - - // create entry - FileInfo* entry = new FileInfo( name ); - - // set the event data at the end of the list - EV_SET( &mChangeList[mChangeListCount], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, - NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME, 0, (void*)entry ); - - // qsort sort the list by name - qsort( &mChangeList[1], mChangeListCount, sizeof( KEvent ), comparator ); - - // handle action - if ( emitEvents ) { - handleAction( name, Actions::Add ); - } -} - -void WatcherKqueue::removeFile( const std::string& name, bool emitEvents ) { - efDEBUG( "removeFile(): Trying to remove file: %s\n", name.c_str() ); - - // bsearch - KEvent target; - - // Create a temporary file info to search the kevent ( searching the directory ) - FileInfo tempEntry( name ); - - target.udata = &tempEntry; - - // Search the kevent - KEvent* ke = (KEvent*)bsearch( &target, &mChangeList[0], mChangeListCount + 1, sizeof( KEvent ), - comparator ); - - // Trying to remove a non-existing file? - if ( !ke ) { - Errors::Log::createLastError( Errors::FileNotFound, name ); - efDEBUG( "File not removed\n" ); - return; - } - - efDEBUG( "File removed\n" ); - - // handle action - if ( emitEvents ) { - handleAction( name, Actions::Delete ); - } - - // Delete the user data ( FileInfo ) from the kevent closed - FileInfo* del = reinterpret_cast( ke->udata ); - - efSAFE_DELETE( del ); - - // close the file descriptor from the kevent - close( ke->ident ); - - mWatcher->removeFD(); - - memset( ke, 0, sizeof( KEvent ) ); - - // move end to current - memcpy( ke, &mChangeList[mChangeListCount], sizeof( KEvent ) ); - memset( &mChangeList[mChangeListCount], 0, sizeof( KEvent ) ); - --mChangeListCount; -} - -void WatcherKqueue::rescan() { - efDEBUG( "rescan(): Rescanning: %s\n", Directory.c_str() ); - - DirectorySnapshotDiff Diff = mDirSnap.scan(); - - if ( Diff.DirChanged ) { - sendDirChanged(); - } - - if ( Diff.changed() ) { - FileInfoList::iterator it; - MovedList::iterator mit; - - /// Files - DiffIterator( FilesCreated ) { - addFile( ( *it ).Filepath ); - } - - DiffIterator( FilesModified ) { - handleAction( ( *it ).Filepath, Actions::Modified ); - } - - DiffIterator( FilesDeleted ) { - removeFile( ( *it ).Filepath ); - } - - DiffMovedIterator( FilesMoved ) { - handleAction( ( *mit ).second.Filepath, Actions::Moved, ( *mit ).first ); - removeFile( Directory + ( *mit ).first, false ); - addFile( ( *mit ).second.Filepath, false ); - } - - /// Directories - DiffIterator( DirsCreated ) { - handleFolderAction( ( *it ).Filepath, Actions::Add ); - addWatch( ( *it ).Filepath, Listener, Recursive, this ); - } - - DiffIterator( DirsModified ) { - handleFolderAction( ( *it ).Filepath, Actions::Modified ); - } - - DiffIterator( DirsDeleted ) { - handleFolderAction( ( *it ).Filepath, Actions::Delete ); - - Watcher* watch = findWatcher( ( *it ).Filepath ); - - if ( NULL != watch ) { - removeWatch( watch->ID ); - } - } - - DiffMovedIterator( DirsMoved ) { - moveDirectory( Directory + ( *mit ).first, ( *mit ).second.Filepath ); - } - } -} - -WatchID WatcherKqueue::watchingDirectory( std::string dir ) { - Watcher* watch = findWatcher( dir ); - - if ( NULL != watch ) { - return watch->ID; - } - - return Errors::FileNotFound; -} - -void WatcherKqueue::handleAction( const std::string& filename, efsw::Action action, - const std::string& oldFilename ) { - Listener->handleFileAction( ID, Directory, FileSystem::fileNameFromPath( filename ), action, - FileSystem::fileNameFromPath( oldFilename ) ); -} - -void WatcherKqueue::handleFolderAction( std::string filename, efsw::Action action, - const std::string& oldFilename ) { - FileSystem::dirRemoveSlashAtEnd( filename ); - - handleAction( filename, action, oldFilename ); -} - -void WatcherKqueue::sendDirChanged() { - if ( NULL != mParent ) { - Listener->handleFileAction( mParent->ID, mParent->Directory, - FileSystem::fileNameFromPath( Directory ), Actions::Modified ); - } -} - -void WatcherKqueue::watch() { - if ( -1 == mKqueue ) { - return; - } - - int nev = 0; - KEvent event; - - // First iterate the childs, to get the events from the deepest folder, to the watcher childs - for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - it->second->watch(); - } - - bool needScan = false; - - // Then we get the the events of the current folder - while ( !mChangeList.empty() && - ( nev = kevent( mKqueue, mChangeList.data(), mChangeListCount + 1, &event, 1, - &mWatcher->mTimeOut ) ) != 0 ) { - // An error ocurred? - if ( nev == -1 ) { - efDEBUG( "watch(): Error on directory %s\n", Directory.c_str() ); - perror( "kevent" ); - break; - } else { - FileInfo* entry = NULL; - - // If udate == NULL means that it is the fisrt element of the change list, the folder. - // otherwise it is an event of some file inside the folder - if ( ( entry = reinterpret_cast( event.udata ) ) != NULL ) { - efDEBUG( "watch(): File: %s ", entry->Filepath.c_str() ); - - // If the event flag is delete... the file was deleted - if ( event.fflags & NOTE_DELETE ) { - efDEBUG( "deleted\n" ); - - mDirSnap.removeFile( entry->Filepath ); - - removeFile( entry->Filepath ); - } else if ( event.fflags & NOTE_EXTEND || event.fflags & NOTE_WRITE || - event.fflags & NOTE_ATTRIB ) { - // The file was modified - efDEBUG( "modified\n" ); - - FileInfo fi( entry->Filepath ); - - if ( fi != *entry ) { - *entry = fi; - - mDirSnap.updateFile( entry->Filepath ); - - handleAction( entry->Filepath, efsw::Actions::Modified ); - } - } else if ( event.fflags & NOTE_RENAME ) { - efDEBUG( "moved\n" ); - - needScan = true; - } - } else { - needScan = true; - } - } - } - - if ( needScan ) { - rescan(); - } -} - -Watcher* WatcherKqueue::findWatcher( const std::string path ) { - WatchMap::iterator it = mWatches.begin(); - - for ( ; it != mWatches.end(); it++ ) { - if ( it->second->Directory == path ) { - return it->second; - } - } - - return NULL; -} - -void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, bool emitEvents ) { - // Update the directory path if it's a watcher - std::string opath2( oldPath ); - FileSystem::dirAddSlashAtEnd( opath2 ); - - Watcher* watch = findWatcher( opath2 ); - - if ( NULL != watch ) { - watch->Directory = opath2; - } - - if ( emitEvents ) { - handleFolderAction( newPath, efsw::Actions::Moved, oldPath ); - } -} - -WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, WatcherKqueue* parent ) { - static bool s_ug = false; - - std::string dir( directory ); - - FileSystem::dirAddSlashAtEnd( dir ); - - // This should never happen here - if ( !FileSystem::isDirectory( dir ) ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( pathInWatches( dir ) || pathInParent( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, directory ); - } else if ( NULL != parent && FileSystem::isRemoteFS( dir ) ) { - return Errors::Log::createLastError( Errors::FileRemote, dir ); - } - - std::string curPath; - std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); - - if ( "" != link ) { - /// Avoid adding symlinks directories if it's now enabled - if ( NULL != parent && !mWatcher->mFileWatcher->followSymlinks() ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); - } - - if ( pathInWatches( link ) || pathInParent( link ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, link ); - } else if ( !mWatcher->linkAllowed( curPath, link ) ) { - return Errors::Log::createLastError( Errors::FileOutOfScope, link ); - } else { - dir = link; - } - } - - if ( mWatcher->availablesFD() ) { - WatcherKqueue* watch = - new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, mWatcher, parent ); - - mWatches.insert( std::make_pair( mLastWatchID, watch ) ); - - watch->addAll(); - - // if failed to open the directory... erase the watcher - if ( !watch->initOK() ) { - int le = watch->lastErrno(); - - mWatches.erase( watch->ID ); - - efSAFE_DELETE( watch ); - - mLastWatchID--; - - // Probably the folder has too many files, create a generic watcher - if ( EACCES != le ) { - WatcherGeneric* watch = - new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); - - mWatches.insert( std::make_pair( mLastWatchID, watch ) ); - } else { - return Errors::Log::createLastError( Errors::Unspecified, link ); - } - } - } else { - if ( !s_ug ) { - efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld.\n", - mWatcher->mFileDescriptorCount ); - s_ug = true; - } - - WatcherGeneric* watch = - new WatcherGeneric( ++mLastWatchID, dir, watcher, mWatcher, recursive ); - - mWatches.insert( std::make_pair( mLastWatchID, watch ) ); - } - - return mLastWatchID; -} - -bool WatcherKqueue::initOK() { - return mInitOK; -} - -void WatcherKqueue::removeWatch( WatchID watchid ) { - WatchMap::iterator iter = mWatches.find( watchid ); - - if ( iter == mWatches.end() ) - return; - - Watcher* watch = iter->second; - - mWatches.erase( iter ); - - efSAFE_DELETE( watch ); -} - -bool WatcherKqueue::pathInWatches( const std::string& path ) { - return NULL != findWatcher( path ); -} - -bool WatcherKqueue::pathInParent( const std::string& path ) { - WatcherKqueue* pNext = mParent; - - while ( NULL != pNext ) { - if ( pNext->pathInWatches( path ) ) { - return true; - } - - pNext = pNext->mParent; - } - - if ( mWatcher->pathInWatches( path ) ) { - return true; - } - - if ( path == Directory ) { - return true; - } - - return false; -} - -int WatcherKqueue::lastErrno() { - return mErrno; -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/WatcherKqueue.hpp b/vendor/efsw/src/efsw/WatcherKqueue.hpp deleted file mode 100644 index 75c0f62..0000000 --- a/vendor/efsw/src/efsw/WatcherKqueue.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef EFSW_WATCHEROSX_HPP -#define EFSW_WATCHEROSX_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS - -#include -#include -#include -#include -#include - -namespace efsw { - -class FileWatcherKqueue; -class WatcherKqueue; - -typedef struct kevent KEvent; - -/// type for a map from WatchID to WatcherKqueue pointer -typedef std::map WatchMap; - -class WatcherKqueue : public Watcher { - public: - WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, - bool recursive, FileWatcherKqueue* watcher, WatcherKqueue* parent = NULL ); - - virtual ~WatcherKqueue(); - - void addFile( const std::string& name, bool emitEvents = true ); - - void removeFile( const std::string& name, bool emitEvents = true ); - - // called when the directory is actually changed - // means a file has been added or removed - // rescans the watched directory adding/removing files and sending notices - void rescan(); - - void handleAction( const std::string& filename, efsw::Action action, - const std::string& oldFilename = "" ); - - void handleFolderAction( std::string filename, efsw::Action action, - const std::string& oldFilename = "" ); - - void addAll(); - - void removeAll(); - - WatchID watchingDirectory( std::string dir ); - - void watch() override; - - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - WatcherKqueue* parent ); - - void removeWatch( WatchID watchid ); - - bool initOK(); - - int lastErrno(); - - protected: - WatchMap mWatches; - int mLastWatchID; - - // index 0 is always the directory - std::vector mChangeList; - size_t mChangeListCount; - DirectorySnapshot mDirSnap; - - /// The descriptor for the kqueue - int mKqueue; - - FileWatcherKqueue* mWatcher; - - WatcherKqueue* mParent; - - bool mInitOK; - int mErrno; - - bool pathInWatches( const std::string& path ); - - bool pathInParent( const std::string& path ); - - Watcher* findWatcher( const std::string path ); - - void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true ); - - void sendDirChanged(); -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/WatcherWin32.cpp b/vendor/efsw/src/efsw/WatcherWin32.cpp deleted file mode 100644 index 957f987..0000000 --- a/vendor/efsw/src/efsw/WatcherWin32.cpp +++ /dev/null @@ -1,307 +0,0 @@ -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#include - -namespace efsw { - -struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX { - DWORD NextEntryOffset; - DWORD Action; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastModificationTime; - LARGE_INTEGER LastChangeTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER AllocatedLength; - LARGE_INTEGER FileSize; - DWORD FileAttributes; - DWORD ReparsePointTag; - LARGE_INTEGER FileId; - LARGE_INTEGER ParentFileId; - DWORD FileNameLength; - WCHAR FileName[1]; -}; - -typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX; - -typedef BOOL( WINAPI* EFSW_LPREADDIRECTORYCHANGESEXW )( HANDLE hDirectory, LPVOID lpBuffer, - DWORD nBufferLength, BOOL bWatchSubtree, - DWORD dwNotifyFilter, LPDWORD lpBytesReturned, - LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - DWORD ReadDirectoryNotifyInformationClass ); - -static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL; - -#define EFSW_ReadDirectoryNotifyExtendedInformation 2 - -static void initReadDirectoryChangesEx() { - static bool hasInit = false; - if ( !hasInit ) { - hasInit = true; - - HMODULE hModule = GetModuleHandleW( L"Kernel32.dll" ); - if ( !hModule ) - return; - - pReadDirectoryChangesExW = - (EFSW_LPREADDIRECTORYCHANGESEXW)GetProcAddress( hModule, "ReadDirectoryChangesExW" ); - } -} - -/// PULSAR PATCH: Returns the path that `handle` currently resolves to, or an -/// empty string if it can't be determined — which includes the case where the -/// directory has been deleted. Not part of upstream efsw. -static std::wstring GetHandlePath( HANDLE handle ) { - if ( NULL == handle || INVALID_HANDLE_VALUE == handle ) - return std::wstring(); - - // Called with a NULL buffer, this returns the length required *including* - // the null terminator; called with a buffer, it returns the number of - // characters written *excluding* it. - DWORD len = - GetFinalPathNameByHandleW( handle, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS ); - - if ( 0 == len ) - return std::wstring(); - - std::wstring path( len, L'\0' ); - - DWORD written = GetFinalPathNameByHandleW( handle, &path[0], len, - FILE_NAME_NORMALIZED | VOLUME_NAME_DOS ); - - if ( 0 == written || written >= len ) - return std::wstring(); - - path.resize( written ); - return path; -} - -void WatchCallbackOld( WatcherWin32* pWatch ) { - PFILE_NOTIFY_INFORMATION pNotify; - size_t offset = 0; - do { - bool skip = false; - - pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; - offset += pNotify->NextEntryOffset; - int count = - WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, - pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL ); - if ( count == 0 ) - continue; - - std::string nfile( count, '\0' ); - - count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, - pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count, - NULL, NULL ); - - if ( FILE_ACTION_MODIFIED == pNotify->Action ) { - FileInfo fifile( std::string( pWatch->DirName ) + nfile ); - - if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && - pWatch->LastModifiedEvent.file.Size == fifile.Size && - pWatch->LastModifiedEvent.fileName == nfile ) { - skip = true; - } - - pWatch->LastModifiedEvent.fileName = nfile; - pWatch->LastModifiedEvent.file = fifile; - } - - if ( !skip ) { - pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); - } - } while ( pNotify->NextEntryOffset != 0 ); -} - -void WatchCallbackEx( WatcherWin32* pWatch ) { - EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX pNotify; - size_t offset = 0; - do { - bool skip = false; - - pNotify = (EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX)&pWatch->Buffer[offset]; - offset += pNotify->NextEntryOffset; - int count = - WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, - pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL ); - if ( count == 0 ) - continue; - - std::string nfile( count, '\0' ); - - count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, - pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count, - NULL, NULL ); - - if ( FILE_ACTION_MODIFIED == pNotify->Action ) { - FileInfo fifile( std::string( pWatch->DirName ) + nfile ); - - if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && - pWatch->LastModifiedEvent.file.Size == fifile.Size && - pWatch->LastModifiedEvent.fileName == nfile ) { - skip = true; - } - - pWatch->LastModifiedEvent.fileName = nfile; - pWatch->LastModifiedEvent.file = fifile; - } else if ( FILE_ACTION_RENAMED_OLD_NAME == pNotify->Action ) { - pWatch->OldFiles.emplace_back( nfile, pNotify->FileId ); - skip = true; - } else if ( FILE_ACTION_RENAMED_NEW_NAME == pNotify->Action ) { - std::string oldFile; - LARGE_INTEGER oldFileId{}; - - for ( auto it = pWatch->OldFiles.begin(); it != pWatch->OldFiles.end(); ++it ) { - if ( it->second.QuadPart == pNotify->FileId.QuadPart ) { - oldFile = it->first; - oldFileId = it->second; - it = pWatch->OldFiles.erase( it ); - break; - } - } - - if ( oldFile.empty() ) { - pWatch->Watch->handleAction( pWatch, nfile, FILE_ACTION_ADDED ); - skip = true; - } else { - pWatch->Watch->handleAction( pWatch, oldFile, FILE_ACTION_RENAMED_OLD_NAME ); - } - } - - if ( !skip ) { - pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); - } - } while ( pNotify->NextEntryOffset != 0 ); -} - -/// Unpacks events and passes them to a user defined callback. -void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { - if ( NULL == lpOverlapped ) { - return; - } - - WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; - WatcherWin32* pWatch = tWatch->Watch; - - // PULSAR PATCH: The directory handle stays valid when the directory is - // renamed or moved, so the watch keeps reporting changes to its children — - // but every path we report is rebuilt from the directory path we were given - // at watch time. Once the handle resolves somewhere else, every path we'd - // emit names a file that isn't there. Stop the watch instead: returning - // without reaching `RefreshWatch` below leaves it un-rearmed, so it goes - // quiet for good. The handle is released later, when the watch is removed. - if ( NULL != pWatch && !pWatch->CanonicalPath.empty() && - pWatch->CanonicalPath != GetHandlePath( pWatch->DirHandle ) ) { - pWatch->StopNow = true; - return; - } - - if ( dwNumberOfBytesTransfered == 0 ) { - if ( nullptr != pWatch && !pWatch->StopNow ) { - RefreshWatch( tWatch ); - } else { - return; - } - } - - // Fork watch depending on the Windows API supported - if ( pWatch->Extended ) { - WatchCallbackEx( pWatch ); - } else { - WatchCallbackOld( pWatch ); - } - - if ( !pWatch->StopNow ) { - RefreshWatch( tWatch ); - } -} - -/// Refreshes the directory monitoring. -RefreshResult RefreshWatch( WatcherStructWin32* pWatch ) { - initReadDirectoryChangesEx(); - - bool bRet = false; - RefreshResult ret = RefreshResult::Failed; - pWatch->Watch->Extended = false; - - if ( pReadDirectoryChangesExW ) { - bRet = pReadDirectoryChangesExW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(), - (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive, - pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, - NULL, EFSW_ReadDirectoryNotifyExtendedInformation ) != 0; - if ( bRet ) { - ret = RefreshResult::SucessEx; - pWatch->Watch->Extended = true; - } - } - - if ( !bRet ) { - bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(), - (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive, - pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, - NULL ) != 0; - - if ( bRet ) - ret = RefreshResult::Success; - } - - if ( !bRet ) { - std::string error = std::to_string( GetLastError() ); - Errors::Log::createLastError( Errors::WatcherFailed, error ); - } - - return ret; -} - -/// Stops monitoring a directory. -void DestroyWatch( WatcherStructWin32* pWatch ) { - if ( pWatch ) { - WatcherWin32* tWatch = pWatch->Watch; - tWatch->StopNow = true; - CancelIoEx( pWatch->Watch->DirHandle, &pWatch->Overlapped ); - CloseHandle( pWatch->Watch->DirHandle ); - efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); - efSAFE_DELETE( pWatch->Watch ); - efSAFE_DELETE( pWatch ); - } -} - -/// Starts monitoring a directory. -WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, - DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ) { - WatcherStructWin32* tWatch = new WatcherStructWin32(); - WatcherWin32* pWatch = new WatcherWin32(bufferSize); - if (tWatch) - tWatch->Watch = pWatch; - - pWatch->DirHandle = CreateFileW( - szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL ); - - if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && - CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { - pWatch->NotifyFilter = notifyFilter; - pWatch->Recursive = recursive; - // PULSAR PATCH: remember where this handle points now, so `WatchCallback` - // can notice later if the directory has been moved out from under it. - pWatch->CanonicalPath = GetHandlePath( pWatch->DirHandle ); - - if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) { - return tWatch; - } - } - - CloseHandle( pWatch->DirHandle ); - efSAFE_DELETE( pWatch->Watch ); - efSAFE_DELETE( tWatch ); - return NULL; -} - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/WatcherWin32.hpp b/vendor/efsw/src/efsw/WatcherWin32.hpp deleted file mode 100644 index 08da867..0000000 --- a/vendor/efsw/src/efsw/WatcherWin32.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef EFSW_WATCHERWIN32_HPP -#define EFSW_WATCHERWIN32_HPP - -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#include - -#ifdef EFSW_COMPILER_MSVC -#pragma comment( lib, "comctl32.lib" ) -#pragma comment( lib, "user32.lib" ) -#pragma comment( lib, "ole32.lib" ) - -// disable secure warnings -#pragma warning( disable : 4996 ) -#endif - -namespace efsw { - -class WatcherWin32; - -enum RefreshResult { Failed, Success, SucessEx }; - -/// Internal watch data -struct WatcherStructWin32 { - OVERLAPPED Overlapped; - WatcherWin32* Watch; -}; - -struct sLastModifiedEvent { - FileInfo file; - std::string fileName; -}; - -RefreshResult RefreshWatch( WatcherStructWin32* pWatch ); - -void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); - -void DestroyWatch( WatcherStructWin32* pWatch ); - -WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, - DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ); - -class WatcherWin32 : public Watcher { - public: - WatcherWin32(DWORD dwBufferSize) : - Struct( NULL ), - DirHandle( NULL ), - Buffer(), - lParam( 0 ), - NotifyFilter( 0 ), - StopNow( false ), - Extended( false ), - Watch( NULL ), - DirName( NULL ) { - Buffer.resize(dwBufferSize); - } - - WatcherStructWin32* Struct; - HANDLE DirHandle; - // PULSAR PATCH: the path `DirHandle` resolved to when the watch was - // created, as reported by `GetFinalPathNameByHandleW`. Compared against the - // handle's current path on each completion so that we can detect when the - // watched directory is renamed or moved out from under us. Not part of - // upstream efsw; see `WatchCallback`. - std::wstring CanonicalPath; - std::vector Buffer; - LPARAM lParam; - DWORD NotifyFilter; - bool StopNow; - bool Extended; - FileWatcherImpl* Watch; - char* DirName; - sLastModifiedEvent LastModifiedEvent; - std::vector> OldFiles; -}; - -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/base.hpp b/vendor/efsw/src/efsw/base.hpp deleted file mode 100644 index 43abc4f..0000000 --- a/vendor/efsw/src/efsw/base.hpp +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef EFSW_BASE -#define EFSW_BASE - -#include -#include - -namespace efsw { - -typedef SOPHIST_int8 Int8; -typedef SOPHIST_uint8 Uint8; -typedef SOPHIST_int16 Int16; -typedef SOPHIST_uint16 Uint16; -typedef SOPHIST_int32 Int32; -typedef SOPHIST_uint32 Uint32; -typedef SOPHIST_int64 Int64; -typedef SOPHIST_uint64 Uint64; - -#define EFSW_OS_WIN 1 -#define EFSW_OS_LINUX 2 -#define EFSW_OS_MACOSX 3 -#define EFSW_OS_BSD 4 -#define EFSW_OS_SOLARIS 5 -#define EFSW_OS_HAIKU 6 -#define EFSW_OS_ANDROID 7 -#define EFSW_OS_IOS 8 - -#define EFSW_PLATFORM_WIN32 1 -#define EFSW_PLATFORM_INOTIFY 2 -#define EFSW_PLATFORM_KQUEUE 3 -#define EFSW_PLATFORM_FSEVENTS 4 -#define EFSW_PLATFORM_GENERIC 5 - -#if defined( _WIN32 ) -/// Any Windows platform -#define EFSW_OS EFSW_OS_WIN -#define EFSW_PLATFORM EFSW_PLATFORM_WIN32 - -#if ( defined( _MSCVER ) || defined( _MSC_VER ) ) -#define EFSW_COMPILER_MSVC -#endif - -/// Force windows target version above or equal to Windows Server 2008 or Windows Vista -#if _WIN32_WINNT < 0x600 -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x600 -#endif -#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) || \ - defined( __DragonFly__ ) -#define EFSW_OS EFSW_OS_BSD -#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE - -#elif defined( __APPLE_CC__ ) || defined( __APPLE__ ) -#include - -#if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || \ - ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR ) -#define EFSW_OS EFSW_OS_IOS -#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE -#else -#define EFSW_OS EFSW_OS_MACOSX - -#if defined( EFSW_FSEVENTS_NOT_SUPPORTED ) -#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE -#else -#define EFSW_PLATFORM EFSW_PLATFORM_FSEVENTS -#endif -#endif - -#elif defined( __linux__ ) -/// This includes Linux and Android -#ifndef EFSW_KQUEUE -#define EFSW_PLATFORM EFSW_PLATFORM_INOTIFY -#else -/// This is for testing libkqueue, sadly it doesnt work -#define EFSW_PLATFORM EFSW_PLATFORM_KQUEUE -#endif - -#if defined( __ANDROID__ ) || defined( ANDROID ) -#define EFSW_OS EFSW_OS_ANDROID -#else -#define EFSW_OS EFSW_OS_LINUX -#endif - -#else -#if defined( __SVR4 ) -#define EFSW_OS EFSW_OS_SOLARIS -#elif defined( __HAIKU__ ) || defined( __BEOS__ ) -#define EFSW_OS EFSW_OS_HAIKU -#endif - -/// Everything else -#define EFSW_PLATFORM EFSW_PLATFORM_GENERIC -#endif - -#if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 -#define EFSW_PLATFORM_POSIX -#endif - -#if 1 == SOPHIST_pointer64 -#define EFSW_64BIT -#else -#define EFSW_32BIT -#endif - -#if defined( arm ) || defined( __arm__ ) -#define EFSW_ARM -#endif - -#define efCOMMA , - -#define efSAFE_DELETE( p ) \ - { \ - if ( p ) { \ - delete ( p ); \ - ( p ) = NULL; \ - } \ - } -#define efSAFE_DELETE_ARRAY( p ) \ - { \ - if ( p ) { \ - delete[] ( p ); \ - ( p ) = NULL; \ - } \ - } -#define efARRAY_SIZE( __array ) ( sizeof( __array ) / sizeof( __array[0] ) ) - -} // namespace efsw - -#endif diff --git a/vendor/efsw/src/efsw/inotify-nosys.h b/vendor/efsw/src/efsw/inotify-nosys.h deleted file mode 100644 index be1e627..0000000 --- a/vendor/efsw/src/efsw/inotify-nosys.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef _LINUX_INOTIFY_H -#define _LINUX_INOTIFY_H - -#include -#include -#include - -/* - * struct inotify_event - structure read from the inotify device for each event - * - * When you are watching a directory, you will receive the filename for events - * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd. - */ -struct inotify_event { - int wd; /* watch descriptor */ - uint32_t mask; /* watch mask */ - uint32_t cookie; /* cookie to synchronize two events */ - uint32_t len; /* length (including nulls) of name */ - char name __flexarr; /* stub for possible name */ -}; - -/* the following are legal, implemented events that user-space can watch for */ -#define IN_ACCESS 0x00000001 /* File was accessed */ -#define IN_MODIFY 0x00000002 /* File was modified */ -#define IN_ATTRIB 0x00000004 /* Metadata changed */ -#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ -#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ -#define IN_OPEN 0x00000020 /* File was opened */ -#define IN_MOVED_FROM 0x00000040 /* File was moved from X */ -#define IN_MOVED_TO 0x00000080 /* File was moved to Y */ -#define IN_CREATE 0x00000100 /* Subfile was created */ -#define IN_DELETE 0x00000200 /* Subfile was deleted */ -#define IN_DELETE_SELF 0x00000400 /* Self was deleted */ -#define IN_MOVE_SELF 0x00000800 /* Self was moved */ - -/* the following are legal events. they are sent as needed to any watch */ -#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */ -#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ -#define IN_IGNORED 0x00008000 /* File was ignored */ - -/* helper events */ -#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */ -#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */ - -/* special flags */ -#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */ -#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */ -#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */ -#define IN_ISDIR 0x40000000 /* event occurred against dir */ -#define IN_ONESHOT 0x80000000 /* only send event once */ - -/* - * All of the events - we build the list by hand so that we can add flags in - * the future and not break backward compatibility. Apps will get only the - * events that they originally wanted. Be sure to add new events here! - */ -#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \ - IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \ - IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \ - IN_MOVE_SELF) - -#if defined (__alpha__) -# define __NR_inotify_init 444 -# define __NR_inotify_add_watch 445 -# define __NR_inotify_rm_watch 446 - -#elif defined (__arm__) -# define __NR_inotify_init (__NR_SYSCALL_BASE+316) -# define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317) -# define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318) - -#elif defined (__aarch64__) -# define __NR_inotify_init 1043 -# define __NR_inotify_add_watch 27 -# define __NR_inotify_rm_watch 28 - -#elif defined (__frv__) -# define __NR_inotify_init 291 -# define __NR_inotify_add_watch 292 -# define __NR_inotify_rm_watch 293 - -#elif defined(__i386__) -# define __NR_inotify_init 291 -# define __NR_inotify_add_watch 292 -# define __NR_inotify_rm_watch 293 - -#elif defined (__ia64__) -# define __NR_inotify_init 1277 -# define __NR_inotify_add_watch 1278 -# define __NR_inotify_rm_watch 1279 - -#elif defined (__mips__) -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_inotify_init (__NR_Linux + 284) -# define __NR_inotify_add_watch (__NR_Linux + 285) -# define __NR_inotify_rm_watch (__NR_Linux + 286) -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_inotify_init (__NR_Linux + 243) -# define __NR_inotify_add_watch (__NR_Linux + 243) -# define __NR_inotify_rm_watch (__NR_Linux + 243) -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_inotify_init (__NR_Linux + 247) -# define __NR_inotify_add_watch (__NR_Linux + 248) -# define __NR_inotify_rm_watch (__NR_Linux + 249) -# endif - -#elif defined(__parisc__) -# define __NR_inotify_init (__NR_Linux + 269) -# define __NR_inotify_add_watch (__NR_Linux + 270) -# define __NR_inotify_rm_watch (__NR_Linux + 271) - -#elif defined(__powerpc__) || defined(__powerpc64__) -# define __NR_inotify_init 275 -# define __NR_inotify_add_watch 276 -# define __NR_inotify_rm_watch 277 - -#elif defined (__s390__) -# define __NR_inotify_init 284 -# define __NR_inotify_add_watch 285 -# define __NR_inotify_rm_watch 286 - -#elif defined (__sh__) -# define __NR_inotify_init 290 -# define __NR_inotify_add_watch 291 -# define __NR_inotify_rm_watch 292 - -#elif defined (__sh64__) -# define __NR_inotify_init 318 -# define __NR_inotify_add_watch 319 -# define __NR_inotify_rm_watch 320 - -#elif defined (__sparc__) || defined (__sparc64__) -# define __NR_inotify_init 151 -# define __NR_inotify_add_watch 152 -# define __NR_inotify_rm_watch 156 - -#elif defined(__x86_64__) -# define __NR_inotify_init 253 -# define __NR_inotify_add_watch 254 -# define __NR_inotify_rm_watch 255 - -#else -# error "Unsupported architecture!" -#endif - -static inline int inotify_init (void) -{ - return syscall (__NR_inotify_init); -} - -static inline int inotify_add_watch (int fd, const char *name, uint32_t mask) -{ - return syscall (__NR_inotify_add_watch, fd, name, mask); -} - -static inline int inotify_rm_watch (int fd, uint32_t wd) -{ - return syscall (__NR_inotify_rm_watch, fd, wd); -} - - -#endif /* _LINUX_INOTIFY_H */ diff --git a/vendor/efsw/src/efsw/platform/platformimpl.hpp b/vendor/efsw/src/efsw/platform/platformimpl.hpp deleted file mode 100644 index 5442580..0000000 --- a/vendor/efsw/src/efsw/platform/platformimpl.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef EFSW_PLATFORMIMPL_HPP -#define EFSW_PLATFORMIMPL_HPP - -#include - -#if defined( EFSW_PLATFORM_POSIX ) -#include -#include -#include -#include -#elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32 -#include -#include -#include -#include -#else -#error Thread, Mutex, and System not implemented for this platform. -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/FileSystemImpl.cpp b/vendor/efsw/src/efsw/platform/posix/FileSystemImpl.cpp deleted file mode 100644 index 92eeb47..0000000 --- a/vendor/efsw/src/efsw/platform/posix/FileSystemImpl.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -#include -#include -#include -#include -#include - -#ifndef _DARWIN_FEATURE_64_BIT_INODE -#define _DARWIN_FEATURE_64_BIT_INODE -#endif - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif - -#include -#include -#include - -#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID -#include -#elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS -#include -#include -#endif - -/** Remote file systems codes */ -#define S_MAGIC_AFS 0x5346414F -#define S_MAGIC_AUFS 0x61756673 -#define S_MAGIC_CEPH 0x00C36400 -#define S_MAGIC_CIFS 0xFF534D42 -#define S_MAGIC_CODA 0x73757245 -#define S_MAGIC_FHGFS 0x19830326 -#define S_MAGIC_FUSEBLK 0x65735546 -#define S_MAGIC_FUSECTL 0x65735543 -#define S_MAGIC_GFS 0x01161970 -#define S_MAGIC_GPFS 0x47504653 -#define S_MAGIC_KAFS 0x6B414653 -#define S_MAGIC_LUSTRE 0x0BD00BD0 -#define S_MAGIC_NCP 0x564C -#define S_MAGIC_NFS 0x6969 -#define S_MAGIC_NFSD 0x6E667364 -#define S_MAGIC_OCFS2 0x7461636F -#define S_MAGIC_PANFS 0xAAD7AAEA -#define S_MAGIC_PIPEFS 0x50495045 -#define S_MAGIC_SMB 0x517B -#define S_MAGIC_SNFS 0xBEEFDEAD -#define S_MAGIC_VMHGFS 0xBACBACBC -#define S_MAGIC_VXFS 0xA501FCF5 - -#if EFSW_OS == EFSW_OS_LINUX -#include -#include -#endif - -namespace efsw { namespace Platform { - -#if EFSW_OS == EFSW_OS_LINUX - -std::string findMountPoint( std::string file ) { - std::string cwd = FileSystem::getCurrentWorkingDirectory(); - struct stat last_stat; - struct stat file_stat; - - stat( file.c_str(), &file_stat ); - - std::string mp; - - if ( efsw::FileSystem::isDirectory( file ) ) { - last_stat = file_stat; - - if ( !FileSystem::changeWorkingDirectory( file ) ) - return ""; - } else { - std::string dir = efsw::FileSystem::pathRemoveFileName( file ); - - if ( !FileSystem::changeWorkingDirectory( dir ) ) - return ""; - - if ( stat( ".", &last_stat ) < 0 ) - return ""; - } - - while ( true ) { - struct stat st; - - if ( stat( "..", &st ) < 0 ) - goto done; - - if ( st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino ) - break; - - if ( !FileSystem::changeWorkingDirectory( ".." ) ) { - goto done; - } - - last_stat = st; - } - - /* Finally reached a mount point, see what it's called. */ - mp = FileSystem::getCurrentWorkingDirectory(); - -done: - FileSystem::changeWorkingDirectory( cwd ); - - return mp; -} - -std::string findDevicePath( const std::string& directory ) { - struct mntent* ent; - FILE* aFile; - - aFile = setmntent( "/proc/mounts", "r" ); - - if ( aFile == NULL ) - return ""; - - while ( NULL != ( ent = getmntent( aFile ) ) ) { - std::string dirName( ent->mnt_dir ); - - if ( dirName == directory ) { - std::string fsName( ent->mnt_fsname ); - - endmntent( aFile ); - - return fsName; - } - } - - endmntent( aFile ); - - return ""; -} - -bool isLocalFUSEDirectory( std::string directory ) { - efsw::FileSystem::dirRemoveSlashAtEnd( directory ); - - directory = findMountPoint( directory ); - - if ( !directory.empty() ) { - std::string devicePath = findDevicePath( directory ); - - return !devicePath.empty(); - } - - return false; -} - -#endif - -bool FileSystem::changeWorkingDirectory( const std::string& path ) { - return -1 != chdir( path.c_str() ); -} - -std::string FileSystem::getCurrentWorkingDirectory() { - char dir[PATH_MAX + 1]; - char* result = getcwd( dir, PATH_MAX + 1 ); - return result != NULL ? std::string( result ) : std::string(); -} - -FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) { - FileInfoMap files; - - DIR* dp; - struct dirent* dirp; - - if ( ( dp = opendir( path.c_str() ) ) == NULL ) - return files; - - while ( ( dirp = readdir( dp ) ) != NULL ) { - if ( strcmp( dirp->d_name, ".." ) != 0 && strcmp( dirp->d_name, "." ) != 0 ) { - std::string name( dirp->d_name ); - std::string fpath( path + name ); - - files[name] = FileInfo( fpath ); - } - } - - closedir( dp ); - - return files; -} - -char FileSystem::getOSSlash() { - return '/'; -} - -bool FileSystem::isDirectory( const std::string& path ) { - struct stat st; - int res = stat( path.c_str(), &st ); - - if ( 0 == res ) { - return static_cast( S_ISDIR( st.st_mode ) ); - } - - return false; -} - -bool FileSystem::isRemoteFS( const std::string& directory ) { -#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || \ - EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID || EFSW_OS == EFSW_OS_IOS - struct statfs statfsbuf; - - statfs( directory.c_str(), &statfsbuf ); - - switch ( statfsbuf.f_type | 0UL ) { - case S_MAGIC_FUSEBLK: /* 0x65735546 remote */ - { -#if EFSW_OS == EFSW_OS_LINUX - return !isLocalFUSEDirectory( directory ); -#endif - } - case S_MAGIC_AFS: /* 0x5346414F remote */ - case S_MAGIC_AUFS: /* 0x61756673 remote */ - case S_MAGIC_CEPH: /* 0x00C36400 remote */ - case S_MAGIC_CIFS: /* 0xFF534D42 remote */ - case S_MAGIC_CODA: /* 0x73757245 remote */ - case S_MAGIC_FHGFS: /* 0x19830326 remote */ - case S_MAGIC_FUSECTL: /* 0x65735543 remote */ - case S_MAGIC_GFS: /* 0x01161970 remote */ - case S_MAGIC_GPFS: /* 0x47504653 remote */ - case S_MAGIC_KAFS: /* 0x6B414653 remote */ - case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */ - case S_MAGIC_NCP: /* 0x564C remote */ - case S_MAGIC_NFS: /* 0x6969 remote */ - case S_MAGIC_NFSD: /* 0x6E667364 remote */ - case S_MAGIC_OCFS2: /* 0x7461636F remote */ - case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */ - case S_MAGIC_PIPEFS: /* 0x50495045 remote */ - case S_MAGIC_SMB: /* 0x517B remote */ - case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */ - case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */ - case S_MAGIC_VXFS: /* 0xA501FCF5 remote */ - { - return true; - } - default: { - return false; - } - } -#endif - - return false; -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/FileSystemImpl.hpp b/vendor/efsw/src/efsw/platform/posix/FileSystemImpl.hpp deleted file mode 100644 index 0bfba76..0000000 --- a/vendor/efsw/src/efsw/platform/posix/FileSystemImpl.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP -#define EFSW_FILESYSTEMIMPLPOSIX_HPP - -#include -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -namespace efsw { namespace Platform { - -class FileSystem { - public: - static FileInfoMap filesInfoFromPath( const std::string& path ); - - static char getOSSlash(); - - static bool isDirectory( const std::string& path ); - - static bool isRemoteFS( const std::string& directory ); - - static bool changeWorkingDirectory( const std::string& path ); - - static std::string getCurrentWorkingDirectory(); -}; - -}} // namespace efsw::Platform - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/MutexImpl.cpp b/vendor/efsw/src/efsw/platform/posix/MutexImpl.cpp deleted file mode 100644 index 2233798..0000000 --- a/vendor/efsw/src/efsw/platform/posix/MutexImpl.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -namespace efsw { namespace Platform { - -MutexImpl::MutexImpl() { - pthread_mutexattr_t attributes; - pthread_mutexattr_init( &attributes ); - pthread_mutexattr_settype( &attributes, PTHREAD_MUTEX_RECURSIVE ); - pthread_mutex_init( &mMutex, &attributes ); -} - -MutexImpl::~MutexImpl() { - pthread_mutex_destroy( &mMutex ); -} - -void MutexImpl::lock() { - pthread_mutex_lock( &mMutex ); -} - -void MutexImpl::unlock() { - pthread_mutex_unlock( &mMutex ); -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/MutexImpl.hpp b/vendor/efsw/src/efsw/platform/posix/MutexImpl.hpp deleted file mode 100644 index a33d827..0000000 --- a/vendor/efsw/src/efsw/platform/posix/MutexImpl.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef EFSW_MUTEXIMPLPOSIX_HPP -#define EFSW_MUTEXIMPLPOSIX_HPP - -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -#include - -namespace efsw { namespace Platform { - -class MutexImpl { - public: - MutexImpl(); - - ~MutexImpl(); - - void lock(); - - void unlock(); - - private: - pthread_mutex_t mMutex; -}; - -}} // namespace efsw::Platform - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/SystemImpl.cpp b/vendor/efsw/src/efsw/platform/posix/SystemImpl.cpp deleted file mode 100644 index 37d4120..0000000 --- a/vendor/efsw/src/efsw/platform/posix/SystemImpl.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -#include -#include -#include -#include -#include - -#include -#include - -#if EFSW_OS == EFSW_OS_MACOSX -#include -#elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID -#include -#include -#elif EFSW_OS == EFSW_OS_HAIKU -#include -#include -#elif EFSW_OS == EFSW_OS_SOLARIS -#include -#elif EFSW_OS == EFSW_OS_BSD -#include -#endif - -namespace efsw { namespace Platform { - -void System::sleep( const unsigned long& ms ) { - // usleep( static_cast( ms * 1000 ) ); - - // usleep is not reliable enough (it might block the - // whole process instead of just the current thread) - // so we must use pthread_cond_timedwait instead - - // this implementation is inspired from Qt - // and taken from SFML - - unsigned long long usecs = ms * 1000; - - // get the current time - timeval tv; - gettimeofday( &tv, NULL ); - - // construct the time limit (current time + time to wait) - timespec ti; - ti.tv_nsec = ( tv.tv_usec + ( usecs % 1000000 ) ) * 1000; - ti.tv_sec = tv.tv_sec + ( usecs / 1000000 ) + ( ti.tv_nsec / 1000000000 ); - ti.tv_nsec %= 1000000000; - - // create a mutex and thread condition - pthread_mutex_t mutex; - pthread_mutex_init( &mutex, 0 ); - pthread_cond_t condition; - pthread_cond_init( &condition, 0 ); - - // wait... - pthread_mutex_lock( &mutex ); - pthread_cond_timedwait( &condition, &mutex, &ti ); - pthread_mutex_unlock( &mutex ); - - // destroy the mutex and condition - pthread_cond_destroy( &condition ); -} - -std::string System::getProcessPath() { -#if EFSW_OS == EFSW_OS_MACOSX - char exe_file[FILENAME_MAX + 1]; - - CFBundleRef mainBundle = CFBundleGetMainBundle(); - - if ( mainBundle ) { - CFURLRef mainURL = CFBundleCopyBundleURL( mainBundle ); - - if ( mainURL ) { - int ok = CFURLGetFileSystemRepresentation( mainURL, ( Boolean ) true, (UInt8*)exe_file, - FILENAME_MAX ); - - if ( ok ) { - return std::string( exe_file ) + "/"; - } - } - } - - return "./"; -#elif EFSW_OS == EFSW_OS_LINUX - char exe_file[FILENAME_MAX + 1]; - - int size; - - size = readlink( "/proc/self/exe", exe_file, FILENAME_MAX ); - - if ( size < 0 ) { - return std::string( "./" ); - } else { - exe_file[size] = '\0'; - return std::string( dirname( exe_file ) ) + "/"; - } - -#elif EFSW_OS == EFSW_OS_BSD - int mib[4]; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; - mib[3] = -1; - char buf[1024]; - size_t cb = sizeof( buf ); - sysctl( mib, 4, buf, &cb, NULL, 0 ); - - return FileSystem::pathRemoveFileName( std::string( buf ) ); - -#elif EFSW_OS == EFSW_OS_SOLARIS - return FileSystem::pathRemoveFileName( std::string( getexecname() ) ); - -#elif EFSW_OS == EFSW_OS_HAIKU - image_info info; - int32 cookie = 0; - - while ( B_OK == get_next_image_info( 0, &cookie, &info ) ) { - if ( info.type == B_APP_IMAGE ) - break; - } - - return FileSystem::pathRemoveFileName( std::string( info.name ) ); - -#elif EFSW_OS == EFSW_OS_ANDROID - return "/sdcard/"; - -#else -#warning getProcessPath() not implemented on this platform. ( will return "./" ) - return "./"; - -#endif -} - -void System::maxFD() { - static bool maxed = false; - - if ( !maxed ) { - struct rlimit limit; - getrlimit( RLIMIT_NOFILE, &limit ); - limit.rlim_cur = limit.rlim_max; - setrlimit( RLIMIT_NOFILE, &limit ); - - getrlimit( RLIMIT_NOFILE, &limit ); - - efDEBUG( "File descriptor limit %ld\n", limit.rlim_cur ); - - maxed = true; - } -} - -Uint64 System::getMaxFD() { - static rlim_t max_fd = 0; - - if ( max_fd == 0 ) { - struct rlimit limit; - getrlimit( RLIMIT_NOFILE, &limit ); - max_fd = limit.rlim_cur; - } - - return max_fd; -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/SystemImpl.hpp b/vendor/efsw/src/efsw/platform/posix/SystemImpl.hpp deleted file mode 100644 index 9322b06..0000000 --- a/vendor/efsw/src/efsw/platform/posix/SystemImpl.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EFSW_SYSTEMIMPLPOSIX_HPP -#define EFSW_SYSTEMIMPLPOSIX_HPP - -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -namespace efsw { namespace Platform { - -class System { - public: - static void sleep( const unsigned long& ms ); - - static std::string getProcessPath(); - - static void maxFD(); - - static Uint64 getMaxFD(); -}; - -}} // namespace efsw::Platform - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/ThreadImpl.cpp b/vendor/efsw/src/efsw/platform/posix/ThreadImpl.cpp deleted file mode 100644 index 0f96bca..0000000 --- a/vendor/efsw/src/efsw/platform/posix/ThreadImpl.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -#include -#include -#include - -namespace efsw { namespace Platform { - -ThreadImpl::ThreadImpl( efsw::Thread* owner ) : mIsActive( false ) { - mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; - - if ( !mIsActive ) { - efDEBUG( "Failed to create thread\n" ); - } -} - -ThreadImpl::~ThreadImpl() { - terminate(); -} - -void ThreadImpl::wait() { - // Wait for the thread to finish, no timeout - if ( mIsActive ) { - assert( pthread_equal( pthread_self(), mThread ) == 0 ); - - mIsActive = pthread_join( mThread, NULL ) != 0; - } -} - -void ThreadImpl::terminate() { - if ( mIsActive ) { -#if !defined( __ANDROID__ ) && !defined( ANDROID ) - pthread_cancel( mThread ); -#else - pthread_kill( mThread, SIGUSR1 ); -#endif - - mIsActive = false; - } -} - -void* ThreadImpl::entryPoint( void* userData ) { -// Tell the thread to handle cancel requests immediatly -#ifdef PTHREAD_CANCEL_ASYNCHRONOUS - pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); -#endif - - // The Thread instance is stored in the user data - Thread* owner = static_cast( userData ); - - // Forward to the owner - owner->run(); - - return NULL; -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/posix/ThreadImpl.hpp b/vendor/efsw/src/efsw/platform/posix/ThreadImpl.hpp deleted file mode 100644 index 2e02f9a..0000000 --- a/vendor/efsw/src/efsw/platform/posix/ThreadImpl.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef EFSW_THREADIMPLPOSIX_HPP -#define EFSW_THREADIMPLPOSIX_HPP - -#include - -#if defined( EFSW_PLATFORM_POSIX ) - -#include -#include - -namespace efsw { - -class Thread; - -namespace Platform { - -class ThreadImpl { - public: - explicit ThreadImpl( efsw::Thread* owner ); - - ~ThreadImpl(); - - void wait(); - - void terminate(); - - protected: - static void* entryPoint( void* userData ); - - pthread_t mThread; - Atomic mIsActive; -}; - -} // namespace Platform -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/FileSystemImpl.cpp b/vendor/efsw/src/efsw/platform/win/FileSystemImpl.cpp deleted file mode 100644 index 2b87513..0000000 --- a/vendor/efsw/src/efsw/platform/win/FileSystemImpl.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#include -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include - -#ifndef EFSW_COMPILER_MSVC -#include -#else -#include -#endif - -namespace efsw { namespace Platform { - -bool FileSystem::changeWorkingDirectory( const std::string& path ) { - int res; -#ifdef EFSW_COMPILER_MSVC -#ifdef UNICODE - res = _wchdir( String::fromUtf8( path.c_str() ).toWideString().c_str() ); -#else - res = _chdir( String::fromUtf8( path.c_str() ).toAnsiString().c_str() ); -#endif -#else - res = chdir( path.c_str() ); -#endif - return -1 != res; -} - -std::string FileSystem::getCurrentWorkingDirectory() { -#ifdef EFSW_COMPILER_MSVC -#if defined( UNICODE ) && !defined( EFSW_NO_WIDECHAR ) - wchar_t dir[_MAX_PATH]; - return ( 0 != GetCurrentDirectoryW( _MAX_PATH, dir ) ) ? String( dir ).toUtf8() : std::string(); -#else - char dir[_MAX_PATH]; - return ( 0 != GetCurrentDirectory( _MAX_PATH, dir ) ) ? String( dir, std::locale() ).toUtf8() - : std::string(); -#endif -#else - char dir[PATH_MAX + 1]; - getcwd( dir, PATH_MAX + 1 ); - return std::string( dir ); -#endif -} - -FileInfoMap FileSystem::filesInfoFromPath( const std::string& path ) { - FileInfoMap files; - - String tpath( path ); - - if ( tpath[tpath.size() - 1] == '/' || tpath[tpath.size() - 1] == '\\' ) { - tpath += "*"; - } else { - tpath += "\\*"; - } - - WIN32_FIND_DATAW findFileData; - HANDLE hFind = FindFirstFileW( (LPCWSTR)tpath.toWideString().c_str(), &findFileData ); - - if ( hFind != INVALID_HANDLE_VALUE ) { - std::string name( String( findFileData.cFileName ).toUtf8() ); - std::string fpath( path + name ); - - if ( name != "." && name != ".." ) { - files[name] = FileInfo( fpath ); - } - - while ( FindNextFileW( hFind, &findFileData ) ) { - name = String( findFileData.cFileName ).toUtf8(); - fpath = path + name; - - if ( name != "." && name != ".." ) { - files[name] = FileInfo( fpath ); - } - } - - FindClose( hFind ); - } - - return files; -} - -char FileSystem::getOSSlash() { - return '\\'; -} - -bool FileSystem::isDirectory( const std::string& path ) { - DWORD attrs = GetFileAttributesW( String( path ).toWideString().c_str() ); - return attrs != INVALID_FILE_ATTRIBUTES && ( attrs & FILE_ATTRIBUTE_DIRECTORY ) != 0; -} - -bool FileSystem::isRemoteFS( const std::string& directory ) { - if ( ( directory[0] == '\\' || directory[0] == '/' ) && - ( directory[1] == '\\' || directory[1] == '/' ) ) { - return true; - } - - if ( directory.size() >= 3 ) { - return 4 == GetDriveTypeA( directory.substr( 0, 3 ).c_str() ); - } - - return false; -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/FileSystemImpl.hpp b/vendor/efsw/src/efsw/platform/win/FileSystemImpl.hpp deleted file mode 100644 index e952efc..0000000 --- a/vendor/efsw/src/efsw/platform/win/FileSystemImpl.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef EFSW_FILESYSTEMIMPLWIN_HPP -#define EFSW_FILESYSTEMIMPLWIN_HPP - -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -namespace efsw { namespace Platform { - -class FileSystem { - public: - static FileInfoMap filesInfoFromPath( const std::string& path ); - - static char getOSSlash(); - - static bool isDirectory( const std::string& path ); - - static bool isRemoteFS( const std::string& directory ); - - static bool changeWorkingDirectory( const std::string& path ); - - static std::string getCurrentWorkingDirectory(); -}; - -}} // namespace efsw::Platform - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/MutexImpl.cpp b/vendor/efsw/src/efsw/platform/win/MutexImpl.cpp deleted file mode 100644 index 62b7f83..0000000 --- a/vendor/efsw/src/efsw/platform/win/MutexImpl.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -namespace efsw { namespace Platform { - -MutexImpl::MutexImpl() { - InitializeCriticalSection( &mMutex ); -} - -MutexImpl::~MutexImpl() { - DeleteCriticalSection( &mMutex ); -} - -void MutexImpl::lock() { - EnterCriticalSection( &mMutex ); -} - -void MutexImpl::unlock() { - LeaveCriticalSection( &mMutex ); -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/MutexImpl.hpp b/vendor/efsw/src/efsw/platform/win/MutexImpl.hpp deleted file mode 100644 index 7b06492..0000000 --- a/vendor/efsw/src/efsw/platform/win/MutexImpl.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EFSW_MUTEXIMPLWIN_HPP -#define EFSW_MUTEXIMPLWIN_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include - -namespace efsw { namespace Platform { - -class MutexImpl { - public: - MutexImpl(); - - ~MutexImpl(); - - void lock(); - - void unlock(); - - private: - CRITICAL_SECTION mMutex; -}; - -}} // namespace efsw::Platform - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/SystemImpl.cpp b/vendor/efsw/src/efsw/platform/win/SystemImpl.cpp deleted file mode 100644 index d1f2b21..0000000 --- a/vendor/efsw/src/efsw/platform/win/SystemImpl.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include - -namespace efsw { namespace Platform { - -void System::sleep( const unsigned long& ms ) { - ::Sleep( ms ); -} - -std::string System::getProcessPath() { - // Get path to executable: - WCHAR szDrive[_MAX_DRIVE]; - WCHAR szDir[_MAX_DIR]; - WCHAR szFilename[_MAX_DIR]; - WCHAR szExt[_MAX_DIR]; - std::wstring dllName( _MAX_DIR, 0 ); - - GetModuleFileNameW( 0, &dllName[0], _MAX_PATH ); - -#ifdef EFSW_COMPILER_MSVC - _wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, - szExt, _MAX_DIR ); -#else - _wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt ); -#endif - - return String( szDrive ).toUtf8() + String( szDir ).toUtf8(); -} - -void System::maxFD() {} - -Uint64 System::getMaxFD() { // Number of ReadDirectory per thread - return 60; -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/SystemImpl.hpp b/vendor/efsw/src/efsw/platform/win/SystemImpl.hpp deleted file mode 100644 index 99b4867..0000000 --- a/vendor/efsw/src/efsw/platform/win/SystemImpl.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EFSW_SYSTEMIMPLWIN_HPP -#define EFSW_SYSTEMIMPLWIN_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -namespace efsw { namespace Platform { - -class System { - public: - static void sleep( const unsigned long& ms ); - - static std::string getProcessPath(); - - static void maxFD(); - - static Uint64 getMaxFD(); -}; - -}} // namespace efsw::Platform - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/ThreadImpl.cpp b/vendor/efsw/src/efsw/platform/win/ThreadImpl.cpp deleted file mode 100644 index 463934c..0000000 --- a/vendor/efsw/src/efsw/platform/win/ThreadImpl.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#include - -namespace efsw { namespace Platform { - -ThreadImpl::ThreadImpl( efsw::Thread* owner ) { - mThread = reinterpret_cast( - _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); - - if ( !mThread ) { - efDEBUG( "Failed to create thread\n" ); - } -} - -ThreadImpl::~ThreadImpl() { - if ( mThread ) { - CloseHandle( mThread ); - } -} - -void ThreadImpl::wait() { - // Wait for the thread to finish, no timeout - if ( mThread ) { - assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself! - - WaitForSingleObject( mThread, INFINITE ); - } -} - -void ThreadImpl::terminate() { - if ( mThread ) { - TerminateThread( mThread, 0 ); - } -} - -unsigned int __stdcall ThreadImpl::entryPoint( void* userData ) { - // The Thread instance is stored in the user data - Thread* owner = static_cast( userData ); - - // Forward to the owner - owner->run(); - - // Optional, but it is cleaner - _endthreadex( 0 ); - - return 0; -} - -}} // namespace efsw::Platform - -#endif diff --git a/vendor/efsw/src/efsw/platform/win/ThreadImpl.hpp b/vendor/efsw/src/efsw/platform/win/ThreadImpl.hpp deleted file mode 100644 index 455f24c..0000000 --- a/vendor/efsw/src/efsw/platform/win/ThreadImpl.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef EFSW_THREADIMPLWIN_HPP -#define EFSW_THREADIMPLWIN_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include - -namespace efsw { - -class Thread; - -namespace Platform { - -class ThreadImpl { - public: - explicit ThreadImpl( efsw::Thread* owner ); - - ~ThreadImpl(); - - void wait(); - - void terminate(); - - protected: - static unsigned int __stdcall entryPoint( void* userData ); - - HANDLE mThread; - unsigned int mThreadId; -}; - -} // namespace Platform -} // namespace efsw - -#endif - -#endif diff --git a/vendor/efsw/src/efsw/sophist.h b/vendor/efsw/src/efsw/sophist.h deleted file mode 100644 index 82e5c36..0000000 --- a/vendor/efsw/src/efsw/sophist.h +++ /dev/null @@ -1,147 +0,0 @@ -/* sophist.h - 0.3 - public domain - Sean Barrett 2010 -** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net -** Sophist provides portable types; you typedef/#define them to your own names -** -** defines: -** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian -** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined -** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit -** -** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer -** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 -** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 -** - SOPHIST_int64_constant(number) - macros for creating 64-bit -** - SOPHIST_uint64_constant(number) integer constants -** - SOPHIST_printf_format64 - string for printf format for int64 -*/ - -#ifndef __INCLUDE_SOPHIST_H__ -#define __INCLUDE_SOPHIST_H__ - -#define SOPHIST_compiletime_assert(name,val) \ - typedef int SOPHIST__assert##name[(val) ? 1 : -1] - -/* define a couple synthetic rules to make code more readable */ -#if (defined(__sparc__) || defined(__sparc)) && \ - (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) - #define SOPHIST_sparc64 -#endif - -#if (defined(linux) || defined(__linux__)) && \ - (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) - #define SOPHIST_linux64 -#endif - -/* basic types */ -typedef signed char SOPHIST_int8; -typedef unsigned char SOPHIST_uint8; - -typedef signed short SOPHIST_int16; -typedef unsigned short SOPHIST_uint16; - -#ifdef __palmos__ - typedef signed long SOPHIST_int32; - typedef unsigned long SOPHIST_uint32; -#else - typedef signed int SOPHIST_int32; - typedef unsigned int SOPHIST_uint32; -#endif - -#ifndef SOPHIST_NO_64 - #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ - || (defined(__alpha) && defined(__DECC)) - - typedef signed __int64 SOPHIST_int64; - typedef unsigned __int64 SOPHIST_uint64; - #define SOPHIST_has_64 1 - #define SOPHIST_int64_constant(x) (x##i64) - #define SOPHIST_uint64_constant(x) (x##ui64) - #define SOPHIST_printf_format64 "I64" - - #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) - - typedef signed long SOPHIST_int64; - typedef unsigned long SOPHIST_uint64; - - #define SOPHIST_has_64 1 - #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) - #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) - #define SOPHIST_printf_format64 "l" - - #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ - || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ - || defined(sgi) || defined (__sgi) || defined(__sgi__) \ - || defined(_CRAYC) - - typedef signed long long SOPHIST_int64; - typedef unsigned long long SOPHIST_uint64; - - #define SOPHIST_has_64 1 - #define SOPHIST_int64_constant(x) (x##LL) - #define SOPHIST_uint64_constant(x) (x##ULL) - #define SOPHIST_printf_format64 "ll" - #endif -#endif - -#ifndef SOPHIST_has_64 -#define SOPHIST_has_64 0 -#endif - -SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); -SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); -SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); -SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); - -#if SOPHIST_has_64 - SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); - SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); -#endif - -/* determine whether pointers are 64-bit */ - -#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ - || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ - || defined(__64BIT__) \ - || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ - || defined(_ADDR64) || defined(_CRAYC) \ - - #define SOPHIST_pointer64 1 - - SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); - - typedef SOPHIST_int64 SOPHIST_intptr; - typedef SOPHIST_uint64 SOPHIST_uintptr; -#else - - #define SOPHIST_pointer64 0 - - SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); - - /* do we care about pointers that are only 16-bit? */ - typedef SOPHIST_int32 SOPHIST_intptr; - typedef SOPHIST_uint32 SOPHIST_uintptr; - -#endif - -SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); - -/* enumerate known little endian cases; fallback to big-endian */ - -#define SOPHIST_little_endian 1 -#define SOPHIST_big_endian 2 - -#if defined(__386__) || defined(i386) || defined(__i386__) \ - || defined(__X86) || defined(_M_IX86) \ - || defined(_M_X64) || defined(__x86_64__) \ - || defined(alpha) || defined(__alpha) || defined(__alpha__) \ - || defined(_M_ALPHA) \ - || defined(ARM) || defined(_ARM) || defined(__arm__) \ - || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ - || defined(_WIN32_WCE) || defined(__NT__) \ - || defined(__MIPSEL__) - #define SOPHIST_endian SOPHIST_little_endian -#else - #define SOPHIST_endian SOPHIST_big_endian -#endif - -#endif /* __INCLUDE_SOPHIST_H__ */ diff --git a/vendor/efsw/src/test/efsw-test.c b/vendor/efsw/src/test/efsw-test.c deleted file mode 100644 index 54a3e21..0000000 --- a/vendor/efsw/src/test/efsw-test.c +++ /dev/null @@ -1,164 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 - #include -#else - #include -#endif - -const char PATH_SEPARATOR = -#ifdef _WIN32 - '\\'; -#else - '/'; -#endif - -bool STOP = false; - -void sigend( int sig ) { - printf( "Bye bye" ); - STOP = true; -} - -void sleepMsecs( int msecs ) { -#ifdef _WIN32 - Sleep( msecs ); -#else - sleep( msecs ); -#endif -} - -const char * getActionName( enum efsw_action action ) { - switch ( action ) { - case EFSW_ADD: - return "Add"; - case EFSW_MODIFIED: - return "Modified"; - case EFSW_DELETE: - return "Delete"; - case EFSW_MOVED: - return "Moved"; - default: - return "Bad Action"; - } -} - -void handleFileAction( efsw_watcher watcher, efsw_watchid watchid, - const char* dir, const char* filename, - enum efsw_action action, const char* oldFilename, - void* param ) { - if ( strlen( oldFilename ) == 0 ) { - printf( "Watch ID %ld DIR (%s) FILE (%s) has event %s\n", - watchid, dir, filename, getActionName( action )); - } else { - printf( "Watch ID %ld DIR (%s) FILE (from file %s to %s) has event %s\n", - watchid, dir, oldFilename, filename, getActionName( action )); - } -} - -efsw_watchid handleWatchID( efsw_watchid watchid ) { - switch ( watchid ) { - case EFSW_NOTFOUND: - case EFSW_REPEATED: - case EFSW_OUTOFSCOPE: - case EFSW_REMOTE: - case EFSW_WATCHER_FAILED: - case EFSW_UNSPECIFIED: { - printf( "%s\n", efsw_getlasterror() ); - break; - } - default: { - printf( "Added WatchID: %ld\n", watchid ); - } - } - - return watchid; -} - -int main( int argc, char** argv ) { - signal( SIGABRT, sigend ); - signal( SIGINT, sigend ); - signal( SIGTERM, sigend ); - - printf("Press ^C to exit demo\n"); - - bool commonTest = true; - bool useGeneric = false; - char *path = 0; - - if ( argc >= 2 ) { - path = argv[1]; - - struct stat s; - if( stat(path,&s) == 0 && (s.st_mode & S_IFDIR) == S_IFDIR ) { - commonTest = false; - } - - if ( argc >= 3 ) { - if ( strcmp( argv[2], "true" ) == 0 ) { - useGeneric = true; - } - } - } - - /// create the file watcher object - efsw_watcher fileWatcher = efsw_create( useGeneric ); - efsw_follow_symlinks( fileWatcher, false ); - efsw_allow_outofscopelinks( fileWatcher, false ); - - if ( commonTest ) { - char cwd[256]; - getcwd( cwd, sizeof(cwd) ); - printf( "CurPath: %s\n", cwd ); - - /// starts watching - efsw_watch( fileWatcher ); - - /// add a watch to the system - char path1[256]; - sprintf(path1, "%s%ctest", cwd, PATH_SEPARATOR ); - handleWatchID( efsw_addwatch_withoptions( fileWatcher, path1, handleFileAction, true, 0, 0, 0 ) ); - - /// adds another watch after started watching... - sleepMsecs( 100 ); - - char path2[256]; - sprintf(path2, "%s%ctest2", cwd, PATH_SEPARATOR ); - efsw_watchid watchID = handleWatchID( - efsw_addwatch_withoptions( fileWatcher, path2, handleFileAction, true, 0, 0, 0 ) ); - - /// delete the watch - if ( watchID > 0 ) { - sleepMsecs( 1000 ); - efsw_removewatch_byid( fileWatcher, watchID ); - } - } else { - if ( efsw_addwatch( fileWatcher, path, handleFileAction, true, 0 ) > 0 ) { - efsw_watch( fileWatcher ); - - printf( "Watching directory: %s\n", path ); - - if ( useGeneric ) { - printf( "Using generic backend watcher\n" ); - } - } else { - printf( "Error trying to watch directory: %s\n", path ); - printf( "%s\n", efsw_getlasterror() ); - } - } - - while ( !STOP ) { - sleepMsecs( 100 ); - } - - efsw_release( fileWatcher ); - - return 0; -} diff --git a/vendor/efsw/src/test/efsw-test.cpp b/vendor/efsw/src/test/efsw-test.cpp deleted file mode 100644 index 99f6086..0000000 --- a/vendor/efsw/src/test/efsw-test.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include -#include - -bool STOP = false; - -void sigend( int ) { - std::cout << std::endl << "Bye bye" << std::endl; - STOP = true; -} - -/// Processes a file action -class UpdateListener : public efsw::FileWatchListener { - public: - UpdateListener() {} - - std::string getActionName( efsw::Action action ) { - switch ( action ) { - case efsw::Actions::Add: - return "Add"; - case efsw::Actions::Modified: - return "Modified"; - case efsw::Actions::Delete: - return "Delete"; - case efsw::Actions::Moved: - return "Moved"; - default: - return "Bad Action"; - } - } - - void handleFileAction( efsw::WatchID watchid, const std::string& dir, - const std::string& filename, efsw::Action action, - std::string oldFilename = "" ) override { - std::cout << "Watch ID " << watchid << " DIR (" - << dir + ") FILE (" + - ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + - filename + ") has event " - << getActionName( action ) << std::endl; - } -}; - -efsw::WatchID handleWatchID( efsw::WatchID watchid ) { - switch ( watchid ) { - case efsw::Errors::FileNotFound: - case efsw::Errors::FileRepeated: - case efsw::Errors::FileOutOfScope: - case efsw::Errors::FileRemote: - case efsw::Errors::WatcherFailed: - case efsw::Errors::Unspecified: { - std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; - break; - } - default: { - std::cout << "Added WatchID: " << watchid << std::endl; - } - } - - return watchid; -} - -int main( int argc, char** argv ) { - signal( SIGABRT, sigend ); - signal( SIGINT, sigend ); - signal( SIGTERM, sigend ); - - std::cout << "Press ^C to exit demo" << std::endl; - - bool commonTest = true; - bool useGeneric = false; - std::string path; - - if ( argc >= 2 ) { - path = std::string( argv[1] ); - - if ( efsw::FileSystem::isDirectory( path ) ) { - commonTest = false; - } - - if ( argc >= 3 ) { - if ( std::string( argv[2] ) == "true" ) { - useGeneric = true; - } - } - } - - UpdateListener* ul = new UpdateListener(); - - /// create the file watcher object - efsw::FileWatcher fileWatcher( useGeneric ); - - fileWatcher.followSymlinks( false ); - fileWatcher.allowOutOfScopeLinks( false ); - - if ( commonTest ) { - std::string CurPath( efsw::System::getProcessPath() ); - - std::cout << "CurPath: " << CurPath.c_str() << std::endl; - - /// starts watching - fileWatcher.watch(); - - /// add a watch to the system - handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) ); - - /// adds another watch after started watching... - efsw::System::sleep( 100 ); - - efsw::WatchID watchID = - handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) ); - - /// delete the watch - if ( watchID > 0 ) { - efsw::System::sleep( 1000 ); - fileWatcher.removeWatch( watchID ); - } - } else { - if ( fileWatcher.addWatch( path, ul, true ) > 0 ) { - fileWatcher.watch(); - - std::cout << "Watching directory: " << path.c_str() << std::endl; - - if ( useGeneric ) { - std::cout << "Using generic backend watcher" << std::endl; - } - } else { - std::cout << "Error trying to watch directory: " << path.c_str() << std::endl; - std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; - } - } - - while ( !STOP ) { - efsw::System::sleep( 100 ); - } - - return 0; -} From 6d3f44c1fe6327098e91a44cce979bd9700e1585 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sat, 26 Sep 2026 09:49:41 -0700 Subject: [PATCH 09/10] Fix macOS behavior on renamed file when the original path still exists --- lib/core.cc | 6 ++-- lib/platform/KqueueFileWatcher.cpp | 23 ++++++++++++ lib/platform/KqueueFileWatcher.hpp | 5 ++- spec/pathwatcher-spec.js | 58 +++++++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/lib/core.cc b/lib/core.cc index 8fb68bf..5d2c37c 100644 --- a/lib/core.cc +++ b/lib/core.cc @@ -100,9 +100,9 @@ static void ProcessEvent(Napi::Env env, Napi::Function callback, // // NOTE: This library previously envisioned that some platforms would allow // watching of files directly and some would require watching of a file's - // parent folder. We use the parent-folder approach on all platforms, so - // in practice we're not using half of the event names we used to use. That's - // why the second argument below is `true`. + // parent folder. We frequently use the parent-folder approach, so in + // practice we're sometimes not using half of the event names we used to use. + // That's why the second argument below is `true`. // // There might be some edge cases that we need to handle here; for instance, // if we're watching a directory and that directory itself is deleted, then diff --git a/lib/platform/KqueueFileWatcher.cpp b/lib/platform/KqueueFileWatcher.cpp index 23f587e..2122618 100644 --- a/lib/platform/KqueueFileWatcher.cpp +++ b/lib/platform/KqueueFileWatcher.cpp @@ -36,6 +36,17 @@ static std::pair SplitPath(const std::string &path) { return {p.substr(0, pos + 1), p.substr(pos + 1)}; } +// Whether `path` still names the file that `fd` is open on. Compares inode +// identity rather than paths, so it isn't fooled by hard links or by different +// spellings of the same path (e.g., `/var` vs. `/private/var`). +static bool IsStillAtPath(int fd, const std::string &path) { + struct stat atPath; + struct stat watched; + if (stat(path.c_str(), &atPath) != 0 || fstat(fd, &watched) != 0) + return false; + return atPath.st_dev == watched.st_dev && atPath.st_ino == watched.st_ino; +} + // Raise the process soft fd limit to the hard limit. On macOS the hard limit // for unprivileged processes is KERN_MAXFILESPERPROC (10240 by default), which // is sufficient headroom for any realistic editor workload. This is a @@ -307,6 +318,18 @@ void KqueueFileWatcher::eventLoop() { sendFileAction(handle, dir, filename, pathwatcher::Actions::Delete); } + } else if (!IsStillAtPath(fd, watchedPath)) { + // The file we're watching no longer lives at the path we were asked to + // watch. The file itself didn't move — we'd have gotten NOTE_RENAME — + // so one of its ancestor directories did. The fd follows the inode, so + // it would go on reporting changes to the file at its new location + // under the old path, which by now may name some other file entirely. + // + // Stop watching instead, and report nothing, just as the other + // platforms' watchers stop when a watched directory moves. We can't + // notice this until the file changes, but until then there's nothing + // to report anyway. + closeFd(handle, fd); } else if (event.fflags & NOTE_WRITE) { sendFileAction(handle, dir, filename, pathwatcher::Actions::Modified); } else if (event.fflags & NOTE_ATTRIB) { diff --git a/lib/platform/KqueueFileWatcher.hpp b/lib/platform/KqueueFileWatcher.hpp index 7080d02..cf1e991 100644 --- a/lib/platform/KqueueFileWatcher.hpp +++ b/lib/platform/KqueueFileWatcher.hpp @@ -8,7 +8,7 @@ #include "../watcher.h" // An API-compatible replacement for FSEventsFileWatcher that uses kqueue -// instead of FSEvents. Intended for experimentation; swap in via core.h. +// instead of FSEvents. // // Key differences from FSEventsFileWatcher: // - No daemon dependency (no fseventsd); pure kernel interface. @@ -17,6 +17,9 @@ // - Watches inode identity, not path identity: when a file is renamed, the // fd follows the inode. Atomic saves (which replace the inode) are detected // via stat() after NOTE_DELETE and reported as Modified rather than Delete. +// If an ancestor directory moves, the fd follows the file to its new +// location; we notice on the file's next change, when the watched path no +// longer names the same inode, and stop watching without reporting. // - No recursive watching; the _useRecursion flag is ignored. class KqueueFileWatcher { public: diff --git a/spec/pathwatcher-spec.js b/spec/pathwatcher-spec.js index 1d56f03..2473d8a 100644 --- a/spec/pathwatcher-spec.js +++ b/spec/pathwatcher-spec.js @@ -242,18 +242,23 @@ describe('PathWatcher', () => { // watch went on reporting events under the path the directory had when we // started watching it. describe('when the parent directory of a watched file is renamed', () => { - let movedDir; + // Directories each spec creates under the shared `tempDir`, which must be + // gone before the next spec runs. + let dirsToClean = []; afterEach(() => { - if (movedDir && fs.existsSync(movedDir)) { - fs.rmSync(movedDir, { recursive: true }); + for (let dir of dirsToClean) { + if (fs.existsSync(dir)) { + fs.rmSync(dir, { recursive: true }); + } } - movedDir = null; + dirsToClean = []; }); it('stops reporting changes against the old path', async () => { let subDir = path.join(tempDir, 'renamed-parent'); fs.mkdirSync(subDir); + dirsToClean.push(subDir); let watchedFile = path.join(subDir, 'file'); fs.writeFileSync(watchedFile, ''); @@ -268,7 +273,8 @@ describe('PathWatcher', () => { expect(spy).toHaveBeenCalledWith('change', ''); // Now rename the directory that contains the file we're watching. - movedDir = path.join(tempDir, 'renamed-parent-moved'); + let movedDir = path.join(tempDir, 'renamed-parent-moved'); + dirsToClean.push(movedDir); fs.renameSync(subDir, movedDir); await wait(200); @@ -282,6 +288,48 @@ describe('PathWatcher', () => { expect(fs.existsSync(watchedFile)).toBe(false); expect(spy).not.toHaveBeenCalled(); }); + + // The previous spec can pass merely because nothing exists at the old + // path anymore. The mistake it guards against is easier to see once + // something does: a watcher that is still following the moved file, and + // still reporting under the old path, would now attribute changes to the + // wrong file. + it('still stops reporting changes against the old path once a new file exists there', async () => { + let subDir = path.join(tempDir, 'recreated-parent'); + fs.mkdirSync(subDir); + dirsToClean.push(subDir); + let watchedFile = path.join(subDir, 'file'); + fs.writeFileSync(watchedFile, ''); + + let spy = jasmine.createSpy('spy'); + PathWatcher.watch(watchedFile, spy); + await wait(20); + + fs.writeFileSync(watchedFile, 'changed'); + await condition(() => spy.calls.count() > 0); + expect(spy).toHaveBeenCalledWith('change', ''); + + let movedDir = path.join(tempDir, 'recreated-parent-moved'); + dirsToClean.push(movedDir); + fs.renameSync(subDir, movedDir); + await wait(200); + + // Put a different file at the path we were asked to watch. We don't + // assert anything about how this is reported; backends are free to + // notice it or not. + fs.mkdirSync(subDir); + fs.writeFileSync(watchedFile, 'a different file'); + await wait(200); + + spy.calls.reset(); + + // A write to the _moved_ file must not be reported as a change to the + // file that now lives at the old path. + fs.writeFileSync(path.join(movedDir, 'file'), 'changed again'); + await wait(200); + + expect(spy).not.toHaveBeenCalled(); + }); }); describe('when a file under a watched directory is deleted', () => { From a6fca146f28b3d1f0fe5526b13ef09b70db04b62 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sat, 26 Sep 2026 09:52:45 -0700 Subject: [PATCH 10/10] Remove useless line --- binding.gyp | 1 - 1 file changed, 1 deletion(-) diff --git a/binding.gyp b/binding.gyp index 8ce6750..2790dbb 100644 --- a/binding.gyp +++ b/binding.gyp @@ -58,7 +58,6 @@ 4577, # 'noexcept' used with no exception handling mode specified; # termination on exception is not guaranteed 4996, # function was declared deprecated - 2220, # warning treated as error - no object file generated 4309, # 'conversion' : truncation of constant value 4101, # unreferenced local variable ],