Compare commits
5 Commits
2b88e3928f
...
54b22488af
| Author | SHA1 | Date | |
|---|---|---|---|
| 54b22488af | |||
| ef06afa1ff | |||
| af1cea249f | |||
| ebf898d025 | |||
| 652a43804d |
@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AllowAllConstructorInitializersOnNextLine: 'true'
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
|
||||||
BreakConstructorInitializers: AfterColon
|
|
||||||
ColumnLimit: '100'
|
|
||||||
CompactNamespaces: 'true'
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
|
||||||
ContinuationIndentWidth: '4'
|
|
||||||
IndentCaseLabels: 'true'
|
|
||||||
IndentWidth: '4'
|
|
||||||
PointerAlignment: Left
|
|
||||||
SpacesInParentheses: 'true'
|
|
||||||
TabWidth: '4'
|
|
||||||
UseTab: Always
|
|
||||||
|
|
||||||
...
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,7 +7,6 @@ CMakeFiles/
|
|||||||
/cmake
|
/cmake
|
||||||
/CMakeCache.txt
|
/CMakeCache.txt
|
||||||
/cmake_install.cmake
|
/cmake_install.cmake
|
||||||
/Makefile
|
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
.qtc_clangd
|
.qtc_clangd
|
||||||
.cmake
|
.cmake
|
||||||
|
|||||||
192
CMakeLists.txt
192
CMakeLists.txt
@ -1,192 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
|
||||||
|
|
||||||
project(efsw)
|
|
||||||
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
|
|
||||||
set(ESFW_MAIN_PROJECT OFF)
|
|
||||||
|
|
||||||
if((CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) AND(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME))
|
|
||||||
set(ESFW_MAIN_PROJECT ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
|
|
||||||
option(VERBOSE "Build efsw with verbose mode.")
|
|
||||||
option(BUILD_SHARED_LIBS "Build efsw as a shared library" ON)
|
|
||||||
option(BUILD_STATIC_LIBS "Build efsw as a static library" ON)
|
|
||||||
option(BUILD_TEST_APP "Build the test app" ${ESFW_MAIN_PROJECT})
|
|
||||||
option(EFSW_INSTALL "Add efsw install targets" ${ESFW_MAIN_PROJECT})
|
|
||||||
|
|
||||||
add_library(efsw)
|
|
||||||
|
|
||||||
if(BUILD_STATIC_LIBS)
|
|
||||||
add_library(efsw-static STATIC)
|
|
||||||
|
|
||||||
target_include_directories(efsw-static
|
|
||||||
PRIVATE src/
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
||||||
)
|
|
||||||
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/String.cpp
|
|
||||||
src/efsw/System.cpp
|
|
||||||
src/efsw/Watcher.cpp
|
|
||||||
src/efsw/WatcherGeneric.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(efsw
|
|
||||||
PRIVATE src/
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
||||||
)
|
|
||||||
|
|
||||||
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/SystemImpl.cpp
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
list(APPEND EFSW_CPP_SOURCE
|
|
||||||
src/efsw/platform/posix/FileSystemImpl.cpp
|
|
||||||
src/efsw/platform/posix/SystemImpl.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 $<IF:$<CONFIG:Debug>,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()
|
|
||||||
22
LICENSE
22
LICENSE
@ -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.
|
|
||||||
114
Makefile
Normal file
114
Makefile
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
EXECUTABLE_NAME = joomer-efsw-file-monitoring
|
||||||
|
PLATFORM = $(shell uname)
|
||||||
|
BUILD_TYPE ?= release# Default to release build if not specified
|
||||||
|
|
||||||
|
# Common paths
|
||||||
|
LIBEFSW_PATH = ../efsw
|
||||||
|
|
||||||
|
OBJ_DIR = obj/$(PLATFORM)/$(BUILD_TYPE)
|
||||||
|
BIN_DIR = bin/$(PLATFORM)/$(BUILD_TYPE)
|
||||||
|
OUTPUT_FILE = $(BIN_DIR)/$(EXECUTABLE_NAME)
|
||||||
|
|
||||||
|
# Platform-specific configuration
|
||||||
|
ifeq ($(PLATFORM), Darwin)
|
||||||
|
# macOS configuration
|
||||||
|
SDK_LIB_EXT = dylib
|
||||||
|
EFSW_LIB_NAME = libefsw.$(SDK_LIB_EXT)
|
||||||
|
MACOS_SDK_PATH = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
|
||||||
|
|
||||||
|
# Compiler settings
|
||||||
|
CC = clang
|
||||||
|
CXX = clang++
|
||||||
|
|
||||||
|
# Architecture flags
|
||||||
|
ARCH_FLAGS = -arch arm64 -mmacosx-version-min=11.0 -isysroot $(MACOS_SDK_PATH)
|
||||||
|
|
||||||
|
# Linking flags - Use multiple rpath entries to look in executable directory
|
||||||
|
LINKER_FLAGS = $(ARCH_FLAGS) -framework Cocoa -framework IOKit -fvisibility=hidden -O5 \
|
||||||
|
-rpath @executable_path \
|
||||||
|
-rpath .
|
||||||
|
|
||||||
|
else
|
||||||
|
# Linux configuration
|
||||||
|
SDK_LIB_EXT = so
|
||||||
|
EFSW_LIB_NAME = libefsw.$(SDK_LIB_EXT)
|
||||||
|
|
||||||
|
# Compiler settings
|
||||||
|
CC = gcc
|
||||||
|
CXX = g++
|
||||||
|
|
||||||
|
# Architecture flags
|
||||||
|
ARCH_FLAGS = -m64 -D_FILE_OFFSET_BITS=64
|
||||||
|
|
||||||
|
# Linking flags
|
||||||
|
LINKER_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 -Wl,-rpath,'$$ORIGIN' -Wl,-rpath,'$$ORIGIN/lib'
|
||||||
|
|
||||||
|
# Platform-specific libraries
|
||||||
|
#PLIST_LIB = -lplist
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Common include and library paths
|
||||||
|
INCLUDE_PATHS = -I$(LIBEFSW_PATH)/include -I$(LIBEFSW_PATH)/src
|
||||||
|
EFSW_LIB_PATH = $(LIBEFSW_PATH)/build
|
||||||
|
# Library flags
|
||||||
|
LIB_PATHS = -L$(EFSW_LIB_PATH)
|
||||||
|
LIBRARIES = -lm -ldl -lefsw
|
||||||
|
|
||||||
|
# Build type specific flags
|
||||||
|
ifeq ($(BUILD_TYPE), debug)
|
||||||
|
CPP_DEFINES = -D_DEBUG -DDL_USE_SHARED
|
||||||
|
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -g -O0 $(INCLUDE_PATHS)
|
||||||
|
else
|
||||||
|
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
|
||||||
|
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 $(INCLUDE_PATHS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Language-specific flags
|
||||||
|
C_FLAGS = $(COMMON_FLAGS) -std=c17
|
||||||
|
CXX_FLAGS = $(COMMON_FLAGS) -std=c++17 -Wno-deprecated-declarations
|
||||||
|
|
||||||
|
# Objects
|
||||||
|
OBJECTS = $(EXECUTABLE_NAME).o
|
||||||
|
OBJECT_FILES = $(patsubst %,$(OBJ_DIR)/%,$(OBJECTS))
|
||||||
|
|
||||||
|
# Build rules
|
||||||
|
$(OBJ_DIR)/$(EXECUTABLE_NAME).o: $(EXECUTABLE_NAME).cpp
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CXX) -c -o $@ $< $(CXX_FLAGS) $(CPP_DEFINES)
|
||||||
|
|
||||||
|
$(OUTPUT_FILE): $(OBJECT_FILES)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(CXX) -o $@ $(OBJECT_FILES) $(LINKER_FLAGS) $(LIB_PATHS) $(LIBRARIES)
|
||||||
|
@echo "Copying libraries to $(BIN_DIR)..."
|
||||||
|
@cp $(EFSW_LIB_PATH)/$(EFSW_LIB_NAME) $(BIN_DIR)/$(EFSW_LIB_NAME)
|
||||||
|
@echo "Build complete: $(OUTPUT_FILE)"
|
||||||
|
|
||||||
|
# Add default target
|
||||||
|
all: $(OUTPUT_FILE)
|
||||||
|
|
||||||
|
.PHONY: clean cleanall all
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ_DIR)/$(EXECUTABLE_NAME).o
|
||||||
|
rm -f $(OUTPUT_FILE)
|
||||||
|
rm -f $(BIN_DIR)/*.dylib
|
||||||
|
rmdir $(OBJ_DIR) 2>/dev/null || true
|
||||||
|
rmdir $(BIN_DIR) 2>/dev/null || true
|
||||||
|
|
||||||
|
cleanall:
|
||||||
|
rm -f obj/*/release/*.o
|
||||||
|
rm -f obj/*/debug/*.o
|
||||||
|
rm -f bin/*/release/$(EXECUTABLE_NAME)
|
||||||
|
rm -f bin/*/debug/$(EXECUTABLE_NAME)
|
||||||
|
rm -f bin/*/release/$(SDK_LIB_FILE)
|
||||||
|
rm -f bin/*/debug/$(SDK_LIB_FILE)
|
||||||
|
rm -f bin/*/release/*.dylib
|
||||||
|
rm -f bin/*/debug/*.dylib
|
||||||
|
rmdir obj/*/release 2>/dev/null || true
|
||||||
|
rmdir obj/*/debug 2>/dev/null || true
|
||||||
|
rmdir bin/*/release 2>/dev/null || true
|
||||||
|
rmdir bin/*/debug 2>/dev/null || true
|
||||||
|
rmdir obj/* 2>/dev/null || true
|
||||||
|
rmdir bin/* 2>/dev/null || true
|
||||||
|
rmdir obj 2>/dev/null || true
|
||||||
|
rmdir bin 2>/dev/null || true
|
||||||
59
README.md
59
README.md
@ -17,51 +17,54 @@ joomer-efsw-file-monitoring
|
|||||||
```
|
```
|
||||||
learndir/
|
learndir/
|
||||||
└── joomer-efsw-file-monitoring/
|
└── joomer-efsw-file-monitoring/
|
||||||
|
└── efsw
|
||||||
```
|
```
|
||||||
|
|
||||||
- Download and Install Premake
|
## Ubuntu Linux
|
||||||
|
|
||||||
## Ubuntu Linux (kasm-ubuntu)
|
|
||||||
```
|
```
|
||||||
mkdir learndir
|
mkdir learndir
|
||||||
cd learndir
|
cd learndir
|
||||||
|
git clone https://github.com/SpartanJ/efsw.git
|
||||||
|
mkdir -p efsw/build
|
||||||
|
cd efsw/build
|
||||||
|
cmake ..
|
||||||
|
make -j4
|
||||||
|
cd ../..
|
||||||
git clone https://git.indoodle.com/jason/joomer-efsw-file-monitoring.git
|
git clone https://git.indoodle.com/jason/joomer-efsw-file-monitoring.git
|
||||||
cd joomer-efsw-file-monitoring
|
cd joomer-efsw-file-monitoring
|
||||||
premake5 gmake2
|
git switch ProposedCleanup
|
||||||
cd make/linux
|
wget https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
|
||||||
make joomer-efsw-file-monitoring
|
wget https://raw.githubusercontent.com/nothings/stb/master/stb_image_write.h
|
||||||
cd ../..
|
make all -j4
|
||||||
cd bin
|
mkdir bin/Linux/release/test
|
||||||
mkdir test
|
bin/Linux/release/joomer-efsw-file-monitoring
|
||||||
./joomer-efsw-file-monitoring
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Windows (win10 enterprise)
|
## Windows
|
||||||
- Download Visual Studio Community Edition 2022
|
- Download Visual Studio Community Edition
|
||||||
- Run VisualStudioSetup.exe
|
- Run VisualStudioSetup.exe
|
||||||
- Workload = [x] Desktop developemnt with C++
|
- Workload = [x] Desktop development with C++
|
||||||
- Individial components = [x] Git For Windows
|
- Individual components = [x] Git For Windows
|
||||||
|
|
||||||
Run **x64 Native Tools Command Prompt for VS 2022**
|
Run **x64 Native Tools Command Prompt for VS**
|
||||||
```
|
```
|
||||||
mkdir learndir
|
mkdir learndir
|
||||||
cd learndir
|
cd learndir
|
||||||
|
git clone https://github.com/SpartanJ/efsw.git
|
||||||
|
cd efsw
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
msbuild efsw.sln /p:Configuration=Release /p:Platform=x64
|
||||||
|
cd ..
|
||||||
git clone https://git.indoodle.com/jason/joomer-efsw-file-monitoring.git
|
git clone https://git.indoodle.com/jason/joomer-efsw-file-monitoring.git
|
||||||
cd joomer-efsw-file-monitoring
|
cd joomer-efsw-file-monitoring
|
||||||
premake5 vs2022
|
git switch ProposedCleanup
|
||||||
cd make/windows
|
|
||||||
msbuild joomer-efsw-file-monitoring.vcxproj /t:Build /p:Configuration=Debug /p:Platform=x64
|
|
||||||
cd ../..
|
|
||||||
cd bin
|
|
||||||
mkdir test
|
|
||||||
joomer-efsw-file-monitoring.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
For a prototype app we can just dump the stb headers right into the joomer-efsw-file-monitoring/src dir for simplicity
|
|
||||||
```
|
|
||||||
curl -LO https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
|
curl -LO https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
|
||||||
curl -LO https://raw.githubusercontent.com/nothings/stb/master/stb_image_write.h
|
curl -LO https://raw.githubusercontent.com/nothings/stb/master/stb_image_write.h
|
||||||
make all -j4
|
msbuild joomer-efsw-file-monitoring.vcxproj /p:Configuration=release /p:Platform=x64 /p:PlatformToolset=v145
|
||||||
|
mkdir -p x64\release\test
|
||||||
|
x64\release\joomer-efsw-file-monitoring.exe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -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")
|
|
||||||
@ -1,197 +0,0 @@
|
|||||||
/**
|
|
||||||
@author Sepul Sepehr Taghdisian
|
|
||||||
|
|
||||||
Copyright (c) 2024 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.
|
|
||||||
*/
|
|
||||||
/** 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,
|
|
||||||
/// For macOS (FSEvents backend), per default all modified event types are capture but we might
|
|
||||||
// only be interested in a subset; the value of the option should be set to a set of bitwise
|
|
||||||
// from:
|
|
||||||
// kFSEventStreamEventFlagItemFinderInfoMod
|
|
||||||
// kFSEventStreamEventFlagItemModified
|
|
||||||
// kFSEventStreamEventFlagItemInodeMetaMod
|
|
||||||
// Default configuration will set the 3 flags
|
|
||||||
EFSW_OPT_MAC_MODIFIED_FILTER = 3,
|
|
||||||
/// macOS sometimes informs incorrect or old file states that may confuse the consumer
|
|
||||||
/// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing
|
|
||||||
/// the number of events reported. This will have an small performance and memory impact as a
|
|
||||||
/// consequence.
|
|
||||||
EFSW_OPT_MAC_SANITIZE_EVENTS = 4,
|
|
||||||
/// Linux does not support natively recursive watchers. This means that when using recursive
|
|
||||||
/// watches efsw registers new watchers for each directory. If new file are created between
|
|
||||||
/// the time efsw takes to register the new directory those events might be missed. To avoid
|
|
||||||
/// missing new file notifications efsw will trigger synthetic new file events for existing
|
|
||||||
/// files in the new directroy watched. This might have the unintended consequence of sending
|
|
||||||
/// duplicated created events due to the system also emitting this event.
|
|
||||||
LINUX_PRODUCE_SYNTHETIC_EVENTS = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 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 void ( *efsw_pfn_handle_missed_fileactions )( efsw_watcher watcher, efsw_watchid watchid,
|
|
||||||
const char* dir );
|
|
||||||
|
|
||||||
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,
|
|
||||||
efsw_pfn_handle_missed_fileactions callback_fn_missed_file_actions );
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
@ -1,267 +0,0 @@
|
|||||||
/**
|
|
||||||
@author Martín Lucas Golini
|
|
||||||
|
|
||||||
Copyright (c) 2024 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 <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#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,
|
|
||||||
/// For macOS (FSEvents backend), per default all modified event types are capture but we might
|
|
||||||
/// only be interested in a subset; the value of the option should be set to a set of bitwise
|
|
||||||
/// from:
|
|
||||||
/// kFSEventStreamEventFlagItemFinderInfoMod
|
|
||||||
/// kFSEventStreamEventFlagItemModified
|
|
||||||
/// kFSEventStreamEventFlagItemInodeMetaMod
|
|
||||||
/// Default configuration will set the 3 flags
|
|
||||||
MacModifiedFilter = 3,
|
|
||||||
/// macOS sometimes informs incorrect or old file states that may confuse the consumer
|
|
||||||
/// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing
|
|
||||||
/// the number of events reported. This will have an small performance and memory impact as a
|
|
||||||
/// consequence.
|
|
||||||
MacSanitizeEvents = 4,
|
|
||||||
/// Linux does not support natively recursive watchers. This means that when using recursive
|
|
||||||
/// watches efsw registers new watchers for each directory. If new file are created between
|
|
||||||
/// the time efsw takes to register the new directory those events might be missed. To avoid
|
|
||||||
/// missing new file notifications efsw will trigger synthetic created file events for existing
|
|
||||||
/// files in the new directroy watched. This might have the unintended consequence of sending
|
|
||||||
/// duplicated created events due to the system also emitting this event.
|
|
||||||
LinuxProduceSyntheticEvents = 5,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
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<WatcherOption>& 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<std::string> 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;
|
|
||||||
|
|
||||||
/// Handles that have missed file actions
|
|
||||||
/// @param watchid The watch id for the directory
|
|
||||||
/// @param dir The directory
|
|
||||||
virtual void handleMissedFileActions( WatchID /*watchid*/,
|
|
||||||
const std::string& /*dir*/ ) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
92
joomer-efsw-file-monitoring.vcxproj
Normal file
92
joomer-efsw-file-monitoring.vcxproj
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="PseudoDebug|x64">
|
||||||
|
<Configuration>PseudoDebug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{7AEA0690-36B7-4596-9DEE-C3AB3C11D282}</ProjectGuid>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='PseudoDebug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='PseudoDebug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='PseudoDebug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<SDLCheck>false</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>PSEUDODEBUG;_CONSOLE;DL_USE_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
|
||||||
|
<AdditionalIncludeDirectories>..\efsw\include;..\efsw\src</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalLibraryDirectories>lib;..\efsw\build\Debug</AdditionalLibraryDirectories>
|
||||||
|
<AdditionalDependencies>efsw-static.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>false</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;DL_USE_SHARED;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\efsw\include;..\efsw\src</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalLibraryDirectories>lib;..\efsw\build\Release</AdditionalLibraryDirectories>
|
||||||
|
<AdditionalDependencies>efsw-static.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="$(PlatformToolset.Contains('Intel'))">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
|
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||||
|
<PreprocessorDefinitions>_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<InterproceduralOptimization>NoIPO</InterproceduralOptimization>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<InterproceduralOptimization>false</InterproceduralOptimization>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="joomer-efsw-file-monitoring.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
261
premake4.lua
261
premake4.lua
@ -1,261 +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 = "5"
|
|
||||||
efsw_patch_version = "0"
|
|
||||||
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-test-stdc"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C"
|
|
||||||
links { "efsw-shared-lib" }
|
|
||||||
files { "src/test/*.c" }
|
|
||||||
includedirs { "include", "src" }
|
|
||||||
conf_links()
|
|
||||||
|
|
||||||
configuration "debug"
|
|
||||||
defines { "DEBUG" }
|
|
||||||
flags { "Symbols" }
|
|
||||||
targetname "efsw-test-stdc-debug"
|
|
||||||
conf_warnings()
|
|
||||||
|
|
||||||
configuration "release"
|
|
||||||
defines { "NDEBUG" }
|
|
||||||
flags { "Optimize" }
|
|
||||||
targetname "efsw-test-stdc-release"
|
|
||||||
conf_warnings()
|
|
||||||
|
|
||||||
configuration "relwithdbginfo"
|
|
||||||
defines { "NDEBUG" }
|
|
||||||
flags { "Optimize", "Symbols" }
|
|
||||||
targetname "efsw-test-stdc-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
|
|
||||||
217
premake5.lua
217
premake5.lua
@ -1,217 +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 = "5"
|
|
||||||
efsw_patch_version = "0"
|
|
||||||
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" }
|
|
||||||
|
|
||||||
-- GLOBAL CONFIGURATION (Applies to ALL projects below)
|
|
||||||
filter "configurations:debug"
|
|
||||||
defines { "DEBUG" }
|
|
||||||
symbols "On"
|
|
||||||
runtime "Debug" -- This forces /MDd everywhere
|
|
||||||
|
|
||||||
filter "configurations:release"
|
|
||||||
defines { "NDEBUG" }
|
|
||||||
optimize "On"
|
|
||||||
runtime "Release" -- This forces /MD everywhere
|
|
||||||
|
|
||||||
filter "configurations:relwithdbginfo"
|
|
||||||
defines { "NDEBUG" }
|
|
||||||
symbols "On"
|
|
||||||
optimize "On"
|
|
||||||
runtime "Release"
|
|
||||||
|
|
||||||
-- Reset filter so project-specific settings work
|
|
||||||
filter "*"
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
project "efsw-test"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C++"
|
|
||||||
links { "efsw-static-lib" }
|
|
||||||
files { "src/test/efsw-test.cpp" }
|
|
||||||
includedirs { "include", "src" }
|
|
||||||
conf_links()
|
|
||||||
|
|
||||||
project "joomer-efsw-file-monitoring"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C++"
|
|
||||||
links { "efsw-static-lib" }
|
|
||||||
files { "src/joomer-efsw-file-monitoring.cpp" }
|
|
||||||
includedirs { "include", "src" }
|
|
||||||
conf_links()
|
|
||||||
|
|
||||||
project "efsw-test-stdc"
|
|
||||||
kind "ConsoleApp"
|
|
||||||
language "C"
|
|
||||||
links { "efsw-shared-lib" }
|
|
||||||
files { "src/test/*.c" }
|
|
||||||
includedirs { "include", "src" }
|
|
||||||
conf_links()
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -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
|
|
||||||
@ -1 +0,0 @@
|
|||||||
-std=c11
|
|
||||||
@ -1 +0,0 @@
|
|||||||
// ADD PREDEFINED MACROS HERE!
|
|
||||||
@ -1 +0,0 @@
|
|||||||
[General]
|
|
||||||
@ -1,344 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE QtCreatorProject>
|
|
||||||
<!-- Written by QtCreator 10.0.2, 2023-07-05T00:08:16. -->
|
|
||||||
<qtcreator>
|
|
||||||
<data>
|
|
||||||
<variable>EnvironmentId</variable>
|
|
||||||
<value type="QByteArray">{d43f4693-30c1-436c-b1d1-498aab2c2f8c}</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
|
||||||
<value type="qlonglong">0</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
|
||||||
<value type="QString" key="language">Cpp</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
|
||||||
<value type="QString" key="language">QmlJS</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.2">
|
|
||||||
<value type="QString" key="language">Nim</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">NimGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">3</value>
|
|
||||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
|
||||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
|
||||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
|
||||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
|
||||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
|
||||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
|
||||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
|
||||||
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.BuildSystem</value>
|
|
||||||
<valuemap type="QVariantMap" key="ClangTools">
|
|
||||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">false</value>
|
|
||||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">false</value>
|
|
||||||
<value type="QString" key="ClangTools.DiagnosticConfig"></value>
|
|
||||||
<value type="int" key="ClangTools.ParallelJobs">0</value>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
|
||||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
|
||||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="CppEditor.QuickFix">
|
|
||||||
<value type="bool" key="UseGlobalSettings">true</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="QString" key="DeviceType">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{6d057187-158a-4883-8d5b-d470a6b6b025}</value>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/linux</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">gmake2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Command">premake5</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}../../../</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-j24 -e config=release_x86_64</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">make</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/linux</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">--thread-sanitizer --verbose gmake2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Command">premake5</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}../../../</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-j24</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">make</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=debug_x86_64</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/linux</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">gmake2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Command">premake5</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}../../../</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=relwithdbginfo_x86_64</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">make</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=relwithdbginfo_x86_64</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">relwithdbginfo</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
|
||||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
|
||||||
<value type="QString">cpu-cycles</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">0</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%{buildDir}/../../bin/efsw-test-debug</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
|
||||||
<value type="QString" key="RunConfiguration.Arguments">/home/programming/thebricks/fe/</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseTerminal">true</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}../../../</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
|
||||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
|
||||||
<value type="QString">cpu-cycles</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">0</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%{buildDir}../../../bin/efsw-test-release</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseTerminal">true</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}../../../</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
|
||||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
|
||||||
<value type="QString">cpu-cycles</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">0</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%{buildDir}../../../bin/efsw-test-dbginfo</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">reldbginfo</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseTerminal">true</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}../../../</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">3</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
|
||||||
<value type="qlonglong">1</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>Version</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
</qtcreator>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
-std=c++11
|
|
||||||
@ -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
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
../../include
|
|
||||||
../../src
|
|
||||||
@ -1 +0,0 @@
|
|||||||
-std=c17
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
// ADD PREDEFINED MACROS HERE!
|
|
||||||
#define EFSW_FSEVENTS_SUPPORTED
|
|
||||||
#define EFSW_USE_CXX11
|
|
||||||
@ -1 +0,0 @@
|
|||||||
[General]
|
|
||||||
@ -1,253 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE QtCreatorProject>
|
|
||||||
<!-- Written by QtCreator 12.0.1, 2024-09-03T01:51:40. -->
|
|
||||||
<qtcreator>
|
|
||||||
<data>
|
|
||||||
<variable>EnvironmentId</variable>
|
|
||||||
<value type="QByteArray">{49267ae2-f136-4b84-8041-cf11a20f6a32}</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
|
||||||
<value type="qlonglong">0</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
|
||||||
<value type="QString" key="language">Cpp</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
|
||||||
<value type="QString" key="language">QmlJS</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
|
||||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
|
||||||
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
|
||||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
|
||||||
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
|
||||||
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
|
||||||
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
|
||||||
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
|
||||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
|
||||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="ClangTools">
|
|
||||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
|
||||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
|
||||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
|
||||||
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
|
||||||
<value type="bool" key="ClangTools.PreferConfigFile">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
|
||||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
|
||||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="QString" key="DeviceType">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop (arm-darwin-generic-mach_o-64bit)</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop (arm-darwin-generic-mach_o-64bit)</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{6d6b6d62-1e99-4e76-b5e2-cf731a0dbd92}</value>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/macosx/</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">--file=../../premake4.lua --thread-sanitizer --verbose gmake</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Command">/usr/local/bin/premake4</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-j4</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/macosx/</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">--file=../../premake4.lua gmake</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.Command">/usr/local/bin/premake4</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-j4 config=release</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">config=release</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
|
||||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="qlonglong" key="Analyzer.QmlProfiler.FlushInterval">0</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">/Users/prognoz/programming/efsw/bin/efsw-test-debug</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">debug</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
|
||||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
|
||||||
<value type="int" key="RunConfiguration.UseCppDebugger">0</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
|
||||||
<value type="int" key="RunConfiguration.UseQmlDebugger">1</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseTerminal">false</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}/../../bin</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="qlonglong" key="Analyzer.QmlProfiler.FlushInterval">0</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">efsw-test</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">release</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
|
||||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
|
||||||
<value type="int" key="RunConfiguration.UseCppDebugger">1</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseTerminal">false</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}/../../bin/</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
|
||||||
<value type="qlonglong">1</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>Version</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
</qtcreator>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
-std=c++17
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -1 +0,0 @@
|
|||||||
-std=c17
|
|
||||||
@ -1 +0,0 @@
|
|||||||
// ADD PREDEFINED MACROS HERE!
|
|
||||||
@ -1 +0,0 @@
|
|||||||
[General]
|
|
||||||
@ -1,425 +0,0 @@
|
|||||||
<<<<<<< HEAD
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE QtCreatorProject>
|
|
||||||
<!-- Written by QtCreator 4.10.2, 2019-11-10T01:12:11. -->
|
|
||||||
<qtcreator>
|
|
||||||
<data>
|
|
||||||
<variable>EnvironmentId</variable>
|
|
||||||
<value type="QByteArray">{55fc4913-4acc-49e6-b0d5-ebf25d4d498e}</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
|
||||||
<value type="int">0</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
|
||||||
<value type="QString" key="language">Cpp</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
|
||||||
<value type="QString" key="language">QmlJS</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
|
||||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
|
||||||
<valuemap type="QVariantMap"/>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{eb5b6178-a7a7-439e-ab01-e63b057196a1}</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:\programming\efsw\make\windows</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">all</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">true</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Default</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
|
||||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
|
||||||
<value type="QString">cpu-cycles</value>
|
|
||||||
</valuelist>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
|
|
||||||
<value type="int" key="Analyzer.Perf.Frequency">250</value>
|
|
||||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
|
||||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
|
||||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
|
||||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
|
||||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
|
||||||
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
|
||||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
|
||||||
<value type="int">0</value>
|
|
||||||
<value type="int">1</value>
|
|
||||||
<value type="int">2</value>
|
|
||||||
<value type="int">3</value>
|
|
||||||
<value type="int">4</value>
|
|
||||||
<value type="int">5</value>
|
|
||||||
<value type="int">6</value>
|
|
||||||
<value type="int">7</value>
|
|
||||||
<value type="int">8</value>
|
|
||||||
<value type="int">9</value>
|
|
||||||
<value type="int">10</value>
|
|
||||||
<value type="int">11</value>
|
|
||||||
<value type="int">12</value>
|
|
||||||
<value type="int">13</value>
|
|
||||||
<value type="int">14</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%{buildDir}\..\..\bin\efsw-test-debug.exe</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run C:\programming\efsw\bin\efsw-test-debug.exe</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
|
||||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default"></value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
|
||||||
<value type="int">1</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>Version</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
</qtcreator>
|
|
||||||
=======
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE QtCreatorProject>
|
|
||||||
<!-- Written by QtCreator 4.10.2, 2019-11-10T01:12:11. -->
|
|
||||||
<qtcreator>
|
|
||||||
<data>
|
|
||||||
<variable>EnvironmentId</variable>
|
|
||||||
<value type="QByteArray">{55fc4913-4acc-49e6-b0d5-ebf25d4d498e}</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
|
||||||
<value type="int">0</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
|
||||||
<value type="QString" key="language">Cpp</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
|
||||||
<value type="QString" key="language">QmlJS</value>
|
|
||||||
<valuemap type="QVariantMap" key="value">
|
|
||||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
|
||||||
</valuemap>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
|
||||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
|
||||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
|
||||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
|
||||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
|
||||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
|
||||||
<valuemap type="QVariantMap"/>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
|
||||||
<valuemap type="QVariantMap">
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{eb5b6178-a7a7-439e-ab01-e63b057196a1}</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:\programming\efsw\make\windows</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">all</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
|
||||||
</valuemap>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
|
||||||
<value type="QString">clean</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">true</value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
|
|
||||||
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
|
|
||||||
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
|
||||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
|
||||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Default</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
|
||||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
|
||||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
|
||||||
<value type="QString">cpu-cycles</value>
|
|
||||||
</valuelist>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
|
|
||||||
<value type="int" key="Analyzer.Perf.Frequency">250</value>
|
|
||||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
|
||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
|
||||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
|
||||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
|
||||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
|
||||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
|
||||||
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
|
||||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
|
||||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
|
||||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
|
||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
|
||||||
<value type="int">0</value>
|
|
||||||
<value type="int">1</value>
|
|
||||||
<value type="int">2</value>
|
|
||||||
<value type="int">3</value>
|
|
||||||
<value type="int">4</value>
|
|
||||||
<value type="int">5</value>
|
|
||||||
<value type="int">6</value>
|
|
||||||
<value type="int">7</value>
|
|
||||||
<value type="int">8</value>
|
|
||||||
<value type="int">9</value>
|
|
||||||
<value type="int">10</value>
|
|
||||||
<value type="int">11</value>
|
|
||||||
<value type="int">12</value>
|
|
||||||
<value type="int">13</value>
|
|
||||||
<value type="int">14</value>
|
|
||||||
</valuelist>
|
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
|
||||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%{buildDir}\..\..\bin\efsw-test-debug.exe</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run C:\programming\efsw\bin\efsw-test-debug.exe</value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
|
||||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
|
||||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory">%{buildDir}</value>
|
|
||||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default"></value>
|
|
||||||
</valuemap>
|
|
||||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
|
||||||
</valuemap>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
|
||||||
<value type="int">1</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
|
||||||
<variable>Version</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
</qtcreator>
|
|
||||||
>>>>>>> 0adf96dcdb6ba38e789d409ca1bf1fc149e60808
|
|
||||||
@ -1 +0,0 @@
|
|||||||
-std=c++17
|
|
||||||
@ -1,433 +0,0 @@
|
|||||||
<<<<<<< HEAD
|
|
||||||
../../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
|
|
||||||
=======
|
|
||||||
../../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
|
|
||||||
>>>>>>> 0adf96dcdb6ba38e789d409ca1bf1fc149e60808
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
../../src
|
|
||||||
../../include
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#ifndef EFSW_ATOMIC_BOOL_HPP
|
|
||||||
#define EFSW_ATOMIC_BOOL_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
template <typename T> 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<T> set_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifdef EFSW_COMPILER_MSVC
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <crtdbg.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
#ifndef EFSW_DEBUG_HPP
|
|
||||||
#define EFSW_DEBUG_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,388 +0,0 @@
|
|||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/DirWatcherGeneric.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
|
|
||||||
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<std::string> 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
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
#ifndef EFSW_DIRWATCHERGENERIC_HPP
|
|
||||||
#define EFSW_DIRWATCHERGENERIC_HPP
|
|
||||||
|
|
||||||
#include <efsw/DirectorySnapshot.hpp>
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/WatcherGeneric.hpp>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
class DirWatcherGeneric {
|
|
||||||
public:
|
|
||||||
typedef std::map<std::string, DirWatcherGeneric*> 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
|
|
||||||
@ -1,212 +0,0 @@
|
|||||||
#include <efsw/DirectorySnapshot.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
|
|
||||||
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<std::string> 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<std::string>::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
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
#ifndef EFSW_DIRECTORYSNAPSHOT_HPP
|
|
||||||
#define EFSW_DIRECTORYSNAPSHOT_HPP
|
|
||||||
|
|
||||||
#include <efsw/DirectorySnapshotDiff.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#include <efsw/DirectorySnapshotDiff.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP
|
|
||||||
#define EFSW_DIRECTORYSNAPSHOTDIFF_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,240 +0,0 @@
|
|||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
|
|
||||||
#ifndef _DARWIN_FEATURE_64_BIT_INODE
|
|
||||||
#define _DARWIN_FEATURE_64_BIT_INODE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _FILE_OFFSET_BITS
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#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 <unistd.h>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
#ifndef EFSW_FILEINFO_HPP
|
|
||||||
#define EFSW_FILEINFO_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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<std::string, FileInfo> FileInfoMap;
|
|
||||||
typedef std::vector<FileInfo> FileInfoList;
|
|
||||||
typedef std::vector<std::pair<std::string, FileInfo>> MovedList;
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,161 +0,0 @@
|
|||||||
#include <cstring>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/platform/platformimpl.hpp>
|
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
#if EFSW_OS == EFSW_OS_MACOSX
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if EFSW_OS == EFSW_OS_WIN
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#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();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FileSystem::getRealPath( const std::string& path ) {
|
|
||||||
std::string realPath;
|
|
||||||
#if defined( EFSW_PLATFORM_POSIX )
|
|
||||||
char dir[PATH_MAX];
|
|
||||||
realpath( path.c_str(), &dir[0] );
|
|
||||||
realPath = std::string( dir );
|
|
||||||
#elif EFSW_OS == EFSW_OS_WIN
|
|
||||||
wchar_t dir[_MAX_PATH + 1];
|
|
||||||
GetFullPathNameW( String::fromUtf8( path ).toWideString().c_str(), _MAX_PATH, &dir[0],
|
|
||||||
nullptr );
|
|
||||||
realPath = String( dir ).toUtf8();
|
|
||||||
#else
|
|
||||||
#warning FileSystem::getRealPath() not implemented on this platform.
|
|
||||||
#endif
|
|
||||||
return realPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
#ifndef EFSW_FILESYSTEM_HPP
|
|
||||||
#define EFSW_FILESYSTEM_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
static std::string getRealPath( const std::string& path );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/FileWatcherGeneric.hpp>
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
#include <efsw/efsw.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
#include <efsw/FileWatcherWin32.hpp>
|
|
||||||
#define FILEWATCHER_IMPL FileWatcherWin32
|
|
||||||
#define BACKEND_NAME "Win32"
|
|
||||||
#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
|
|
||||||
#include <efsw/FileWatcherInotify.hpp>
|
|
||||||
#define FILEWATCHER_IMPL FileWatcherInotify
|
|
||||||
#define BACKEND_NAME "Inotify"
|
|
||||||
#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE
|
|
||||||
#include <efsw/FileWatcherKqueue.hpp>
|
|
||||||
#define FILEWATCHER_IMPL FileWatcherKqueue
|
|
||||||
#define BACKEND_NAME "Kqueue"
|
|
||||||
#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
#include <efsw/FileWatcherFSEvents.hpp>
|
|
||||||
#define FILEWATCHER_IMPL FileWatcherFSEvents
|
|
||||||
#define BACKEND_NAME "FSEvents"
|
|
||||||
#else
|
|
||||||
#define FILEWATCHER_IMPL FileWatcherGeneric
|
|
||||||
#define BACKEND_NAME "Generic"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <efsw/Debug.hpp>
|
|
||||||
|
|
||||||
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<WatcherOption>& 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<std::string> 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
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
#include <efsw/efsw.h>
|
|
||||||
#include <efsw/efsw.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#define TOBOOL( i ) ( ( i ) == 0 ? false : true )
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
class Watcher_CAPI : public efsw::FileWatchListener {
|
|
||||||
public:
|
|
||||||
efsw_watcher mWatcher;
|
|
||||||
efsw_pfn_fileaction_callback mFn;
|
|
||||||
void* mParam;
|
|
||||||
efsw_pfn_handle_missed_fileactions mFnMissedFa;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Watcher_CAPI( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param,
|
|
||||||
efsw_pfn_handle_missed_fileactions fnfa ) :
|
|
||||||
mWatcher( watcher ), mFn( fn ), mParam( param ), mFnMissedFa( fnfa ) {}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleMissedFileActions( efsw::WatchID watchid, const std::string& dir ) {
|
|
||||||
if ( mFnMissedFa ) {
|
|
||||||
mFnMissedFa( mWatcher, watchid, dir.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*************************************************************************************************
|
|
||||||
* globals
|
|
||||||
*/
|
|
||||||
static std::vector<Watcher_CAPI*> g_callbacks;
|
|
||||||
|
|
||||||
Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) {
|
|
||||||
for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end();
|
|
||||||
++i ) {
|
|
||||||
Watcher_CAPI* callback = *i;
|
|
||||||
|
|
||||||
if ( callback->mFn == fn && callback->mWatcher == watcher && callback->mParam == param )
|
|
||||||
return *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Watcher_CAPI* remove_callback( efsw_watcher watcher ) {
|
|
||||||
std::vector<Watcher_CAPI*>::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,
|
|
||||||
nullptr );
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
efsw_pfn_handle_missed_fileactions callback_fn_missed_file_actions ) {
|
|
||||||
Watcher_CAPI* callback = find_callback( watcher, callback_fn, param );
|
|
||||||
|
|
||||||
if ( callback == NULL ) {
|
|
||||||
callback = new Watcher_CAPI( watcher, callback_fn, param, callback_fn_missed_file_actions );
|
|
||||||
g_callbacks.push_back( callback );
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<efsw::WatcherOption> watcher_options{};
|
|
||||||
for ( int i = 0; i < options_number; i++ ) {
|
|
||||||
efsw_watcher_option* option = &options[i];
|
|
||||||
watcher_options.emplace_back(
|
|
||||||
efsw::WatcherOption{ static_cast<efsw::Option>( 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();
|
|
||||||
}
|
|
||||||
@ -1,248 +0,0 @@
|
|||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/FileWatcherFSEvents.hpp>
|
|
||||||
#include <efsw/Lock.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <sys/utsname.h>
|
|
||||||
|
|
||||||
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<int>( 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<WatcherFSEvents*>( userData );
|
|
||||||
|
|
||||||
std::vector<FSEvent> events;
|
|
||||||
events.reserve( numEvents );
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < numEvents; i++ ) {
|
|
||||||
if ( isGranular() ) {
|
|
||||||
CFDictionaryRef pathInfoDict =
|
|
||||||
static_cast<CFDictionaryRef>( CFArrayGetValueAtIndex( (CFArrayRef)eventPaths, i ) );
|
|
||||||
CFStringRef path = static_cast<CFStringRef>(
|
|
||||||
CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedDataPathKey ) );
|
|
||||||
CFNumberRef cfInode = static_cast<CFNumberRef>(
|
|
||||||
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<WatcherOption>& options ) {
|
|
||||||
std::string dir( FileSystem::getRealPath( 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->ModifiedFlags =
|
|
||||||
getOptionValue( options, Option::MacModifiedFilter, efswFSEventsModified );
|
|
||||||
pWatch->SanitizeEvents = getOptionValue( options, Option::MacSanitizeEvents, 0 ) != 0;
|
|
||||||
|
|
||||||
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<std::string> FileWatcherFSEvents::directories() {
|
|
||||||
std::vector<std::string> 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
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
#ifndef EFSW_FILEWATCHERFSEVENTS_HPP
|
|
||||||
#define EFSW_FILEWATCHERFSEVENTS_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include <CoreServices/CoreServices.h>
|
|
||||||
#include <dispatch/dispatch.h>
|
|
||||||
#include <efsw/WatcherFSEvents.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
/// 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<WatchID, WatcherFSEvents*> 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<WatcherOption> &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<std::string> 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
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/FileWatcherGeneric.hpp>
|
|
||||||
#include <efsw/Lock.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
|
|
||||||
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<WatcherOption>& 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([this]{run();});
|
|
||||||
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<std::string> FileWatcherGeneric::directories() {
|
|
||||||
std::vector<std::string> 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
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
#ifndef EFSW_FILEWATCHERGENERIC_HPP
|
|
||||||
#define EFSW_FILEWATCHERGENERIC_HPP
|
|
||||||
|
|
||||||
#include <efsw/DirWatcherGeneric.hpp>
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
#include <efsw/WatcherGeneric.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
/// Implementation for Generic File Watcher.
|
|
||||||
/// @class FileWatcherGeneric
|
|
||||||
class FileWatcherGeneric : public FileWatcherImpl {
|
|
||||||
public:
|
|
||||||
typedef std::vector<WatcherGeneric*> 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<WatcherOption> &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<std::string> 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
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) :
|
|
||||||
mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) {
|
|
||||||
System::maxFD();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileWatcherImpl::~FileWatcherImpl() {}
|
|
||||||
|
|
||||||
bool FileWatcherImpl::initOK() {
|
|
||||||
return static_cast<bool>( 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<WatcherOption>& 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
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
#ifndef EFSW_FILEWATCHERIMPL_HPP
|
|
||||||
#define EFSW_FILEWATCHERIMPL_HPP
|
|
||||||
|
|
||||||
#include <efsw/Atomic.hpp>
|
|
||||||
#include <efsw/Mutex.hpp>
|
|
||||||
#include <efsw/Thread.hpp>
|
|
||||||
#include <efsw/Watcher.hpp>
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
#include <efsw/efsw.hpp>
|
|
||||||
|
|
||||||
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<WatcherOption>& 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<std::string> 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<bool> mInitOK;
|
|
||||||
bool mIsGeneric;
|
|
||||||
|
|
||||||
int getOptionValue( const std::vector<WatcherOption>& options, Option option,
|
|
||||||
int defaultValue );
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,612 +0,0 @@
|
|||||||
#include <algorithm>
|
|
||||||
#include <efsw/FileWatcherInotify.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifdef EFSW_INOTIFY_NOSYS
|
|
||||||
#include <efsw/inotify-nosys.h>
|
|
||||||
#else
|
|
||||||
#include <sys/inotify.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/Lock.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
|
|
||||||
#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<WatcherOption>& options ) {
|
|
||||||
if ( !mInitOK )
|
|
||||||
return Errors::Log::createLastError( Errors::Unspecified, directory );
|
|
||||||
Lock initLock( mInitLock );
|
|
||||||
bool syntheticEvents = getOptionValue( options, Options::LinuxProduceSyntheticEvents, 0 ) != 0;
|
|
||||||
return addWatch( directory, watcher, recursive, syntheticEvents, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
|
|
||||||
bool recursive, bool syntheticEvents, WatcherInotify* parent,
|
|
||||||
bool fromInternalEvent ) {
|
|
||||||
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;
|
|
||||||
pWatch->syntheticEvents = syntheticEvents;
|
|
||||||
|
|
||||||
{
|
|
||||||
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<std::string, FileInfo> files = FileSystem::filesInfoFromPath( pWatch->Directory );
|
|
||||||
|
|
||||||
if ( fromInternalEvent && parent != NULL && syntheticEvents ) {
|
|
||||||
for ( const auto& file : files ) {
|
|
||||||
if ( file.second.isRegularFile() || file.second.isDirectory() ||
|
|
||||||
file.second.isLink() ) {
|
|
||||||
pWatch->Listener->handleFileAction(
|
|
||||||
pWatch->ID, pWatch->Directory,
|
|
||||||
FileSystem::fileNameFromPath( file.second.Filepath ), Actions::Add );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, FileInfo>::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, syntheticEvents, pWatch,
|
|
||||||
fromInternalEvent );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<std::pair<WatcherInotify*, std::string>>::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<WatchID> eraseWatches;
|
|
||||||
|
|
||||||
for ( ; it != mWatches.end(); ++it )
|
|
||||||
if ( it->second != watch && it->second->inParentTree( watch ) )
|
|
||||||
eraseWatches.push_back( it->second->InotifyID );
|
|
||||||
|
|
||||||
for ( std::vector<WatchID>::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<std::string, WatchID>::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( [this] { run(); } );
|
|
||||||
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 );
|
|
||||||
|
|
||||||
WatcherInotify* curWatcher = NULL;
|
|
||||||
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];
|
|
||||||
|
|
||||||
{
|
|
||||||
curWatcher = NULL;
|
|
||||||
|
|
||||||
{
|
|
||||||
Lock lock( mWatchesLock );
|
|
||||||
|
|
||||||
auto wit = mWatches.find( pevent->wd );
|
|
||||||
|
|
||||||
if ( wit != mWatches.end() )
|
|
||||||
curWatcher = wit->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( curWatcher ) {
|
|
||||||
handleAction( curWatcher, (char*)pevent->name, pevent->mask );
|
|
||||||
|
|
||||||
if ( ( pevent->mask & IN_MOVED_TO ) && curWatcher == 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 = curWatcher;
|
|
||||||
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 ) {
|
|
||||||
if ( std::find_if( mMovedOutsideWatches.begin(),
|
|
||||||
mMovedOutsideWatches.end(),
|
|
||||||
[currentMoveFrom](
|
|
||||||
const std::pair<WatcherInotify*,
|
|
||||||
std::string>& moved ) {
|
|
||||||
return moved.first == currentMoveFrom;
|
|
||||||
} ) == mMovedOutsideWatches.end() ) {
|
|
||||||
mMovedOutsideWatches.push_back(
|
|
||||||
std::make_pair( currentMoveFrom, prevOldFileName ) );
|
|
||||||
} else {
|
|
||||||
efDEBUG( "Info: Tried to add watch to the moved outside "
|
|
||||||
"watches but it was already there, Watch ID: %d - "
|
|
||||||
"Address: %p - Path: \"%s\" - prevOldFileName: "
|
|
||||||
"\"%s\"\n",
|
|
||||||
pevent->wd, currentMoveFrom,
|
|
||||||
currentMoveFrom->Directory.c_str(),
|
|
||||||
prevOldFileName.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ) {
|
|
||||||
if ( std::find_if(
|
|
||||||
mMovedOutsideWatches.begin(), mMovedOutsideWatches.end(),
|
|
||||||
[currentMoveFrom]( const std::pair<WatcherInotify*, std::string>& moved ) {
|
|
||||||
return moved.first == currentMoveFrom;
|
|
||||||
} ) == mMovedOutsideWatches.end() ) {
|
|
||||||
mMovedOutsideWatches.push_back(
|
|
||||||
std::make_pair( currentMoveFrom, currentMoveFrom->OldFileName ) );
|
|
||||||
} else {
|
|
||||||
efDEBUG( "Warning: Tried to add watch to the moved outside "
|
|
||||||
"watches but it was already there, Watch Address: %p\n",
|
|
||||||
currentMoveFrom );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<std::pair<WatcherInotify*, std::string>> movedOutsideWatches(
|
|
||||||
mMovedOutsideWatches );
|
|
||||||
|
|
||||||
/// In case that the IN_MOVED_TO is never fired means that the file was moved to other
|
|
||||||
/// folder
|
|
||||||
for ( std::vector<std::pair<WatcherInotify*, std::string>>::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<std::pair<WatcherInotify*, std::string>>::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<Watcher*> eraseWatches;
|
|
||||||
|
|
||||||
{
|
|
||||||
Lock lock( mWatchesLock );
|
|
||||||
|
|
||||||
for ( auto wit : mWatches ) {
|
|
||||||
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<Watcher*>::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 ) {
|
|
||||||
WatcherInotify* iWatch = static_cast<WatcherInotify*>( watch );
|
|
||||||
addWatch( fpath, watch->Listener, watch->Recursive, iWatch->syntheticEvents,
|
|
||||||
static_cast<WatcherInotify*>( watch ), true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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_Q_OVERFLOW & action ) {
|
|
||||||
watch->Listener->handleMissedFileActions( watch->ID, watch->Directory );
|
|
||||||
} else 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<std::string> FileWatcherInotify::directories() {
|
|
||||||
std::vector<std::string> 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
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
#ifndef EFSW_FILEWATCHERLINUX_HPP
|
|
||||||
#define EFSW_FILEWATCHERLINUX_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
|
|
||||||
|
|
||||||
#include <efsw/WatcherInotify.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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<WatchID, WatcherInotify*> 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<WatcherOption>& 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<std::string> directories() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/// Map of WatchID to WatchStruct pointers
|
|
||||||
WatchMap mWatches;
|
|
||||||
|
|
||||||
/// User added watches
|
|
||||||
WatchMap mRealWatches;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, WatchID> mWatchesRef;
|
|
||||||
|
|
||||||
/// inotify file descriptor
|
|
||||||
int mFD;
|
|
||||||
|
|
||||||
Thread* mThread;
|
|
||||||
|
|
||||||
Mutex mWatchesLock;
|
|
||||||
Mutex mRealWatchesLock;
|
|
||||||
Mutex mInitLock;
|
|
||||||
bool mIsTakingAction;
|
|
||||||
std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches;
|
|
||||||
|
|
||||||
WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive,
|
|
||||||
bool syntheticEvents, WatcherInotify* parent = NULL,
|
|
||||||
bool fromInternalEvent = false );
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
#include <efsw/FileWatcherKqueue.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/Lock.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
#include <efsw/WatcherGeneric.hpp>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
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<WatcherOption>& 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([this]{run();});
|
|
||||||
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<std::string> FileWatcherKqueue::directories() {
|
|
||||||
std::vector<std::string> 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
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
#ifndef EFSW_FILEWATCHEROSX_HPP
|
|
||||||
#define EFSW_FILEWATCHEROSX_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <efsw/WatcherKqueue.hpp>
|
|
||||||
|
|
||||||
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<WatcherOption> &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<std::string> 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<WatchID> 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
|
|
||||||
@ -1,267 +0,0 @@
|
|||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/FileWatcherWin32.hpp>
|
|
||||||
#include <efsw/Lock.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
|
|
||||||
#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<ULONG_PTR>( this ), NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
efSAFE_DELETE( mThread );
|
|
||||||
|
|
||||||
removeAllWatches();
|
|
||||||
|
|
||||||
if ( mIOCP )
|
|
||||||
CloseHandle( mIOCP );
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher,
|
|
||||||
bool recursive, const std::vector<WatcherOption> &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<DWORD>( getOptionValue(options, Option::WinBufferSize, 63 * 1024) );
|
|
||||||
DWORD notifyFilter = static_cast<DWORD>( 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([this]{run();});
|
|
||||||
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<ULONG_PTR>( 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<WatcherWin32*>( watch )->DirName );
|
|
||||||
std::string realFilename = filename;
|
|
||||||
std::size_t sepPos = filename.find_last_of( "/\\" );
|
|
||||||
std::string oldFolderPath =
|
|
||||||
static_cast<WatcherWin32*>( 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<WatcherWin32*>( 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<WatcherWin32*>( 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<std::string> FileWatcherWin32::directories() {
|
|
||||||
std::vector<std::string> 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
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
#ifndef EFSW_FILEWATCHERWIN32_HPP
|
|
||||||
#define EFSW_FILEWATCHERWIN32_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
|
|
||||||
#include <efsw/WatcherWin32.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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<WatcherStructWin32*> 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<WatcherOption> &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<std::string> 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
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
#ifndef EFSW_LOCK_HPP
|
|
||||||
#define EFSW_LOCK_HPP
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <efsw/Mutex.hpp>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
using Lock = std::unique_lock<Mutex>;
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
#include <efsw/efsw.hpp>
|
|
||||||
#include <efsw/Debug.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#ifndef EFSW_MUTEX_HPP
|
|
||||||
#define EFSW_MUTEX_HPP
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
using Mutex = std::recursive_mutex;
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,669 +0,0 @@
|
|||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/Utf.hpp>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
const std::size_t String::InvalidPos = StringType::npos;
|
|
||||||
|
|
||||||
std::vector<std::string> String::split( const std::string& str, const char& splitchar,
|
|
||||||
const bool& pushEmptyString ) {
|
|
||||||
std::vector<std::string> 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> String::split( const String& str, const Uint32& splitchar,
|
|
||||||
const bool& pushEmptyString ) {
|
|
||||||
std::vector<String> 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
|
|
||||||
@ -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 <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <locale>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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<StringBaseType> 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 <class T> static std::string toStr( const T& i ) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << i;
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Converts from a string to type */
|
|
||||||
template <class T>
|
|
||||||
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 <class T>
|
|
||||||
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<std::string> split( const std::string& str, const char& splitchar,
|
|
||||||
const bool& pushEmptyString = false );
|
|
||||||
|
|
||||||
/** Split a string and hold it on a vector */
|
|
||||||
static std::vector<String> 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 <class InputIterator>
|
|
||||||
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 <class InputIterator> 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 <class InputIterator> 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 <class InputIterator>
|
|
||||||
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.
|
|
||||||
**/
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#include <efsw/System.hpp>
|
|
||||||
#include <efsw/platform/platformimpl.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#ifndef EFSW_SYSTEM_HPP
|
|
||||||
#define EFSW_SYSTEM_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
#ifndef EFSW_THREAD_HPP
|
|
||||||
#define EFSW_THREAD_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
/** @brief Thread manager class */
|
|
||||||
class Thread {
|
|
||||||
public:
|
|
||||||
|
|
||||||
Thread(std::function<void()> fun)
|
|
||||||
: mFun{std::move(fun)}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Thread()
|
|
||||||
{
|
|
||||||
wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Launch the thread */
|
|
||||||
void launch()
|
|
||||||
{
|
|
||||||
if (!mThread)
|
|
||||||
mThread.reset(new std::thread{std::move(mFun)});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Wait the thread until end */
|
|
||||||
void wait()
|
|
||||||
{
|
|
||||||
if (mThread)
|
|
||||||
{
|
|
||||||
mThread->join();
|
|
||||||
mThread.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::unique_ptr<std::thread> mThread;
|
|
||||||
std::function<void()> mFun;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
721
src/efsw/Utf.hpp
721
src/efsw/Utf.hpp
@ -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 <cstdlib>
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
#include <locale>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
template <unsigned int N> 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 <typename In>
|
|
||||||
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 <typename Out> 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 <typename In> 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 <typename In> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In>
|
|
||||||
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 <typename Out> 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 <typename In> 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 <typename In> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In>
|
|
||||||
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 <typename Out> 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 <typename In> 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 <typename In> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In>
|
|
||||||
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 <typename In> 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 <typename Out>
|
|
||||||
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 <typename Out>
|
|
||||||
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<X> 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)
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
576
src/efsw/Utf.inl
576
src/efsw/Utf.inl
@ -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 <typename In> 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<Uint8>( *begin )];
|
|
||||||
if ( begin + trailingBytes < end ) {
|
|
||||||
output = 0;
|
|
||||||
switch ( trailingBytes ) {
|
|
||||||
case 5:
|
|
||||||
output += static_cast<Uint8>( *begin++ );
|
|
||||||
output <<= 6;
|
|
||||||
case 4:
|
|
||||||
output += static_cast<Uint8>( *begin++ );
|
|
||||||
output <<= 6;
|
|
||||||
case 3:
|
|
||||||
output += static_cast<Uint8>( *begin++ );
|
|
||||||
output <<= 6;
|
|
||||||
case 2:
|
|
||||||
output += static_cast<Uint8>( *begin++ );
|
|
||||||
output <<= 6;
|
|
||||||
case 1:
|
|
||||||
output += static_cast<Uint8>( *begin++ );
|
|
||||||
output <<= 6;
|
|
||||||
case 0:
|
|
||||||
output += static_cast<Uint8>( *begin++ );
|
|
||||||
}
|
|
||||||
output -= offsets[trailingBytes];
|
|
||||||
} else {
|
|
||||||
// Incomplete character
|
|
||||||
begin = end;
|
|
||||||
output = replacement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Out> 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<Uint8>( ( input | 0x80 ) & 0xBF );
|
|
||||||
input >>= 6;
|
|
||||||
case 3:
|
|
||||||
bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF );
|
|
||||||
input >>= 6;
|
|
||||||
case 2:
|
|
||||||
bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF );
|
|
||||||
input >>= 6;
|
|
||||||
case 1:
|
|
||||||
bytes[0] = static_cast<Uint8>( 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 <typename In> In Utf<8>::Next( In begin, In end ) {
|
|
||||||
Uint32 codepoint;
|
|
||||||
return Decode( begin, end, codepoint );
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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<char>( codepoint ) : replacement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) {
|
|
||||||
while ( begin < end )
|
|
||||||
*output++ = *begin++;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In> 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<Uint32>( ( ( 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 <typename Out> 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<Uint16>( 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<Uint16>( ( input >> 10 ) + 0xD800 );
|
|
||||||
*output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> In Utf<16>::Next( In begin, In end ) {
|
|
||||||
Uint32 codepoint;
|
|
||||||
return Decode( begin, end, codepoint );
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out> 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 <typename In, typename Out> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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<char>( *begin ) : replacement;
|
|
||||||
begin++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> 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 <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) {
|
|
||||||
while ( begin < end )
|
|
||||||
*output++ = *begin++;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> 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 <typename In> In Utf<32>::Decode( In begin, In end, Uint32& output, Uint32 ) {
|
|
||||||
output = *begin++;
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 replacement ) {
|
|
||||||
*output++ = input;
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> In Utf<32>::Next( In begin, In end ) {
|
|
||||||
return ++begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> std::size_t Utf<32>::Count( In begin, In end ) {
|
|
||||||
return begin - end;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out>
|
|
||||||
Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) {
|
|
||||||
while ( begin < end )
|
|
||||||
*output++ = DecodeAnsi( *begin++, locale );
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) {
|
|
||||||
while ( begin < end )
|
|
||||||
*output++ = DecodeWide( *begin++ );
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> 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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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 <typename In, typename Out>
|
|
||||||
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<char>( *begin ) : replacement;
|
|
||||||
begin++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) {
|
|
||||||
while ( begin < end )
|
|
||||||
output = Utf<8>::Encode( *begin++, output );
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) {
|
|
||||||
while ( begin < end )
|
|
||||||
output = Utf<16>::Encode( *begin++, output );
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) {
|
|
||||||
while ( begin < end )
|
|
||||||
*output++ = *begin++;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> 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<Uint32>( character );
|
|
||||||
|
|
||||||
#else
|
|
||||||
// Get the facet of the locale which deals with character conversion
|
|
||||||
#ifndef EFSW_NO_WIDECHAR
|
|
||||||
const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale );
|
|
||||||
#else
|
|
||||||
const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Use the facet to convert each character of the input string
|
|
||||||
return static_cast<Uint32>( facet.widen( input ) );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename In> 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 <typename Out>
|
|
||||||
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<wchar_t>( 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<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale );
|
|
||||||
#else
|
|
||||||
const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Use the facet to convert each character of the input string
|
|
||||||
*output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement );
|
|
||||||
|
|
||||||
return output;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef EFSW_NO_WIDECHAR
|
|
||||||
template <typename Out>
|
|
||||||
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<wchar_t>( codepoint );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) {
|
|
||||||
*output++ = static_cast<wchar_t>( codepoint );
|
|
||||||
} else if ( replacement ) {
|
|
||||||
*output++ = replacement;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#include <efsw/Watcher.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
#ifndef EFSW_WATCHERIMPL_HPP
|
|
||||||
#define EFSW_WATCHERIMPL_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
#include <efsw/efsw.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,223 +0,0 @@
|
|||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/FileWatcherFSEvents.hpp>
|
|
||||||
#include <efsw/WatcherFSEvents.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
WatcherFSEvents::WatcherFSEvents() :
|
|
||||||
Watcher(), 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::sendMissedFileActions( WatchID watchid,
|
|
||||||
const std::string& dir) {
|
|
||||||
Listener->handleMissedFileActions( watchid,
|
|
||||||
FileSystem::precomposeFileName( dir ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path,
|
|
||||||
std::string& dirPath, std::string& filePath, Uint64 inode ) {
|
|
||||||
if ( ( flags & efswFSEventStreamEventFlagItemCreated ) && FileInfo::exists( path ) &&
|
|
||||||
( !SanitizeEvents || FilesAdded.find( inode ) != FilesAdded.end() ) ) {
|
|
||||||
sendFileAction( ID, dirPath, filePath, Actions::Add );
|
|
||||||
|
|
||||||
if ( SanitizeEvents )
|
|
||||||
FilesAdded.insert( inode );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( flags & ModifiedFlags ) {
|
|
||||||
sendFileAction( ID, dirPath, filePath, Actions::Modified );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ( flags & efswFSEventStreamEventFlagItemRemoved ) && !FileInfo::exists( path ) ) {
|
|
||||||
// Since i don't know the order, at least i try to keep the data consistent with the real
|
|
||||||
// state
|
|
||||||
sendFileAction( ID, dirPath, filePath, Actions::Delete );
|
|
||||||
|
|
||||||
if ( SanitizeEvents )
|
|
||||||
FilesAdded.erase( inode );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) {
|
|
||||||
size_t esize = events.size();
|
|
||||||
|
|
||||||
for ( size_t i = 0; i < esize; i++ ) {
|
|
||||||
FSEvent& event = events[i];
|
|
||||||
|
|
||||||
if ( event.Flags &
|
|
||||||
( kFSEventStreamEventFlagUserDropped | kFSEventStreamEventFlagKernelDropped |
|
|
||||||
kFSEventStreamEventFlagMustScanSubDirs) ) {
|
|
||||||
efDEBUG( "Rescan/Drop event for watch: %s - flags: 0x%x\n", Directory.c_str(), event.Flags );
|
|
||||||
std::string dirPath = Directory;
|
|
||||||
FileSystem::dirRemoveSlashAtEnd( dirPath );
|
|
||||||
sendMissedFileActions(ID, dirPath );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( event.Flags &
|
|
||||||
( 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 & ModifiedFlags ) {
|
|
||||||
sendFileAction( ID, newDir, newFilepath, Actions::Modified );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath, event.inode );
|
|
||||||
}
|
|
||||||
|
|
||||||
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 & ModifiedFlags ) {
|
|
||||||
sendFileAction( ID, dirPath, filePath, Actions::Modified );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendFileAction( ID, dirPath, filePath, Actions::Delete );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleAddModDel( event.Flags, event.Path, dirPath, filePath, event.inode );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
efDEBUG( "Directory: %s changed\n", event.Path.c_str() );
|
|
||||||
DirsChanged.insert( event.Path );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatcherFSEvents::process() {
|
|
||||||
std::unordered_set<std::string>::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
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
#ifndef EFSW_WATCHERINOTIFY_HPP
|
|
||||||
#define EFSW_WATCHERINOTIFY_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#include <CoreServices/CoreServices.h>
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/WatcherGeneric.hpp>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
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{ 0 };
|
|
||||||
Uint64 Id{ 0 };
|
|
||||||
Uint64 inode{ 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
class WatcherFSEvents : public Watcher {
|
|
||||||
public:
|
|
||||||
WatcherFSEvents();
|
|
||||||
|
|
||||||
~WatcherFSEvents();
|
|
||||||
|
|
||||||
void init();
|
|
||||||
|
|
||||||
void handleActions( std::vector<FSEvent>& events );
|
|
||||||
|
|
||||||
void process();
|
|
||||||
|
|
||||||
Atomic<FileWatcherFSEvents*> FWatcher;
|
|
||||||
FSEventStreamRef FSStream;
|
|
||||||
Uint64 ModifiedFlags{ efswFSEventsModified };
|
|
||||||
bool SanitizeEvents{ false };
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath,
|
|
||||||
std::string& filePath, Uint64 inode );
|
|
||||||
|
|
||||||
WatcherGeneric* WatcherGen;
|
|
||||||
|
|
||||||
std::unordered_set<std::string> DirsChanged;
|
|
||||||
std::unordered_set<Uint64> FilesAdded;
|
|
||||||
|
|
||||||
void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename,
|
|
||||||
Action action, std::string oldFilename = "" );
|
|
||||||
|
|
||||||
void sendMissedFileActions( WatchID watchid, const std::string& dir);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#include <efsw/DirWatcherGeneric.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/WatcherGeneric.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
#ifndef EFSW_WATCHERGENERIC_HPP
|
|
||||||
#define EFSW_WATCHERGENERIC_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
#include <efsw/WatcherInotify.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
#ifndef EFSW_WATCHERINOTIFY_HPP
|
|
||||||
#define EFSW_WATCHERINOTIFY_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
class WatcherInotify : public Watcher {
|
|
||||||
public:
|
|
||||||
WatcherInotify();
|
|
||||||
|
|
||||||
bool inParentTree( WatcherInotify* parent );
|
|
||||||
|
|
||||||
WatcherInotify* Parent;
|
|
||||||
WatchID InotifyID;
|
|
||||||
|
|
||||||
FileInfo DirInfo;
|
|
||||||
bool syntheticEvents{ false };
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,566 +0,0 @@
|
|||||||
#include <efsw/WatcherKqueue.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/FileWatcherKqueue.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/System.hpp>
|
|
||||||
#include <efsw/WatcherGeneric.hpp>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#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<const KEvent*>( ke1 );
|
|
||||||
const KEvent* kev2 = reinterpret_cast<const KEvent*>( ke2 );
|
|
||||||
|
|
||||||
if ( NULL != kev2->udata ) {
|
|
||||||
FileInfo* fi1 = reinterpret_cast<FileInfo*>( kev1->udata );
|
|
||||||
FileInfo* fi2 = reinterpret_cast<FileInfo*>( 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<FileInfo*>( 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<WatchID> 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<WatchID>::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<FileInfo*>( 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<FileInfo*>( 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
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
#ifndef EFSW_WATCHEROSX_HPP
|
|
||||||
#define EFSW_WATCHEROSX_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
|
|
||||||
|
|
||||||
#include <efsw/DirectorySnapshot.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <sys/event.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace efsw {
|
|
||||||
|
|
||||||
class FileWatcherKqueue;
|
|
||||||
class WatcherKqueue;
|
|
||||||
|
|
||||||
typedef struct kevent KEvent;
|
|
||||||
|
|
||||||
/// type for a map from WatchID to WatcherKqueue pointer
|
|
||||||
typedef std::map<WatchID, Watcher*> 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<KEvent> 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
|
|
||||||
@ -1,268 +0,0 @@
|
|||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/WatcherWin32.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
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" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if ( dwNumberOfBytesTransfered == 0 ) {
|
|
||||||
if ( nullptr != pWatch && !pWatch->StopNow ) {
|
|
||||||
/// Missed file actions due to buffer overflowed
|
|
||||||
std::string dir = pWatch->DirName;
|
|
||||||
FileSystem::dirRemoveSlashAtEnd( dir );
|
|
||||||
pWatch->Listener->handleMissedFileActions( pWatch->ID, dir );
|
|
||||||
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;
|
|
||||||
|
|
||||||
if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) {
|
|
||||||
return tWatch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle( pWatch->DirHandle );
|
|
||||||
efSAFE_DELETE( pWatch->Watch );
|
|
||||||
efSAFE_DELETE( tWatch );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
#ifndef EFSW_WATCHERWIN32_HPP
|
|
||||||
#define EFSW_WATCHERWIN32_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/FileWatcherImpl.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
std::vector<BYTE> Buffer;
|
|
||||||
LPARAM lParam;
|
|
||||||
DWORD NotifyFilter;
|
|
||||||
bool StopNow;
|
|
||||||
bool Extended;
|
|
||||||
FileWatcherImpl* Watch;
|
|
||||||
char* DirName;
|
|
||||||
sLastModifiedEvent LastModifiedEvent;
|
|
||||||
std::vector<std::pair<std::string, LARGE_INTEGER>> OldFiles;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace efsw
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
#ifndef EFSW_BASE
|
|
||||||
#define EFSW_BASE
|
|
||||||
|
|
||||||
#include <efsw/efsw.hpp>
|
|
||||||
#include <efsw/sophist.h>
|
|
||||||
|
|
||||||
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 <TargetConditionals.h>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@ -1,164 +0,0 @@
|
|||||||
#ifndef _LINUX_INOTIFY_H
|
|
||||||
#define _LINUX_INOTIFY_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
#ifndef EFSW_PLATFORMIMPL_HPP
|
|
||||||
#define EFSW_PLATFORMIMPL_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#if defined( EFSW_PLATFORM_POSIX )
|
|
||||||
#include <efsw/platform/posix/SystemImpl.hpp>
|
|
||||||
#include <efsw/platform/posix/FileSystemImpl.hpp>
|
|
||||||
#elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
#include <efsw/platform/win/SystemImpl.hpp>
|
|
||||||
#include <efsw/platform/win/FileSystemImpl.hpp>
|
|
||||||
#else
|
|
||||||
#error Thread, Mutex, and System not implemented for this platform.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,251 +0,0 @@
|
|||||||
#include <efsw/platform/posix/FileSystemImpl.hpp>
|
|
||||||
|
|
||||||
#if defined( EFSW_PLATFORM_POSIX )
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifndef _DARWIN_FEATURE_64_BIT_INODE
|
|
||||||
#define _DARWIN_FEATURE_64_BIT_INODE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _FILE_OFFSET_BITS
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <climits>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_SOLARIS || EFSW_OS == EFSW_OS_ANDROID
|
|
||||||
#include <sys/vfs.h>
|
|
||||||
#elif EFSW_OS == EFSW_OS_MACOSX || EFSW_OS == EFSW_OS_BSD || EFSW_OS == EFSW_OS_IOS
|
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#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 <cstdio>
|
|
||||||
#include <mntent.h>
|
|
||||||
#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<bool>( 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
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
#ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP
|
|
||||||
#define EFSW_FILESYSTEMIMPLPOSIX_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@ -1,168 +0,0 @@
|
|||||||
#include <efsw/platform/posix/SystemImpl.hpp>
|
|
||||||
|
|
||||||
#if defined( EFSW_PLATFORM_POSIX )
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
#include <efsw/Debug.hpp>
|
|
||||||
#include <efsw/FileSystem.hpp>
|
|
||||||
|
|
||||||
#if EFSW_OS == EFSW_OS_MACOSX
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
|
||||||
#elif EFSW_OS == EFSW_OS_LINUX || EFSW_OS == EFSW_OS_ANDROID
|
|
||||||
#include <libgen.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#elif EFSW_OS == EFSW_OS_HAIKU
|
|
||||||
#include <kernel/OS.h>
|
|
||||||
#include <kernel/image.h>
|
|
||||||
#elif EFSW_OS == EFSW_OS_SOLARIS
|
|
||||||
#include <stdlib.h>
|
|
||||||
#elif EFSW_OS == EFSW_OS_BSD
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace efsw { namespace Platform {
|
|
||||||
|
|
||||||
void System::sleep( const unsigned long& ms ) {
|
|
||||||
// usleep( static_cast<unsigned long>( 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
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#ifndef EFSW_SYSTEMIMPLPOSIX_HPP
|
|
||||||
#define EFSW_SYSTEMIMPLPOSIX_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
#include <efsw/platform/win/FileSystemImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
|
|
||||||
#include <climits>
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#ifndef EFSW_COMPILER_MSVC
|
|
||||||
#include <dirent.h>
|
|
||||||
#else
|
|
||||||
#include <direct.h>
|
|
||||||
#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
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
#ifndef EFSW_FILESYSTEMIMPLWIN_HPP
|
|
||||||
#define EFSW_FILESYSTEMIMPLWIN_HPP
|
|
||||||
|
|
||||||
#include <efsw/FileInfo.hpp>
|
|
||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
#include <efsw/String.hpp>
|
|
||||||
#include <efsw/platform/win/SystemImpl.hpp>
|
|
||||||
|
|
||||||
#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32
|
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#ifndef EFSW_SYSTEMIMPLWIN_HPP
|
|
||||||
#define EFSW_SYSTEMIMPLWIN_HPP
|
|
||||||
|
|
||||||
#include <efsw/base.hpp>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@ -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__ */
|
|
||||||
7988
src/stb_image.h
7988
src/stb_image.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,164 +0,0 @@
|
|||||||
#include <efsw/efsw.h>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <Windows.h>
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#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[512];
|
|
||||||
snprintf( path1, sizeof( path1 ), "%s%ctest", cwd, PATH_SEPARATOR );
|
|
||||||
handleWatchID( efsw_addwatch_withoptions( fileWatcher, path1, handleFileAction, true, 0, 0,
|
|
||||||
0, NULL ) );
|
|
||||||
|
|
||||||
/// adds another watch after started watching...
|
|
||||||
sleepMsecs( 100 );
|
|
||||||
|
|
||||||
char path2[512];
|
|
||||||
snprintf( path2, sizeof( path2 ), "%s%ctest2", cwd, PATH_SEPARATOR );
|
|
||||||
efsw_watchid watchID = handleWatchID( efsw_addwatch_withoptions(
|
|
||||||
fileWatcher, path2, handleFileAction, true, 0, 0, 0, NULL ) );
|
|
||||||
|
|
||||||
/// 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;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user