diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7a55b3d --- /dev/null +++ b/.clang-format @@ -0,0 +1,18 @@ +--- +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 + +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abba35d --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +bin/ +build/ +obj/ +make/ +lib/ +CMakeFiles/ +/cmake +/CMakeCache.txt +/cmake_install.cmake +/Makefile +*.DS_Store +.qtc_clangd +.cmake +.vscode/ +*.so +*.a +*.dylib +*.lib +/.cache +/efsw-test +/efsw-test-stdc diff --git a/README.md b/README.md index d18973d..b1a7e1c 100644 --- a/README.md +++ b/README.md @@ -42,13 +42,15 @@ Run **x64 Native Tools Command Prompt for VS 2022** ``` mkdir learndir cd learndir -git clone https://git.indoodle.com/jason/joomer-ftxui-file-monitoring.git -cd joomer-ftxui-file-monitoring +git clone https://git.indoodle.com/jason/joomer-efsw-file-monitoring.git +premake5 vs2022 +cd joomer-ftxui-file-monitoring/make/windows msbuild joomer-ftxui-file-monitoring.vcxproj /t:Build /p:Configuration=Debug /p:Platform=x64 +cd ../.. bin\Debug\joomer-ftxui-file-monitoring.exe ``` -For a prototype app we can just dump the stb headers right into the helloworld dir for simplicity +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_write.h diff --git a/include/efsw/efsw.hpp b/include/efsw/efsw.hpp index 4787978..60d0029 100644 --- a/include/efsw/efsw.hpp +++ b/include/efsw/efsw.hpp @@ -1,267 +1,267 @@ -/** - @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 -#include - -#if defined( _WIN32 ) -#ifdef EFSW_DYNAMIC -// Windows platforms -#ifdef EFSW_EXPORTS -// From DLL side, we must export -#define EFSW_API __declspec( dllexport ) -#else -// From client application side, we must import -#define EFSW_API __declspec( dllimport ) -#endif -#else -// No specific directive needed for static build -#ifndef EFSW_API -#define EFSW_API -#endif -#endif -#else -#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) -#ifndef EFSW_API -#define EFSW_API __attribute__( ( visibility( "default" ) ) ) -#endif -#endif - -// Other platforms don't need to define anything -#ifndef EFSW_API -#define EFSW_API -#endif -#endif - -namespace efsw { - -/// Type for a watch id -typedef long WatchID; - -// forward declarations -class FileWatcherImpl; -class FileWatchListener; -class WatcherOption; - -/// Actions to listen for. Rename will send two events, one for -/// the deletion of the old file, and one for the creation of the -/// new file. -namespace Actions { -enum Action { - /// Sent when a file is created or renamed - Add = 1, - /// Sent when a file is deleted or renamed - Delete = 2, - /// Sent when a file is modified - Modified = 3, - /// Sent when a file is moved - Moved = 4 -}; -} -typedef Actions::Action Action; - -/// Errors log namespace -namespace Errors { - -enum Error { - NoError = 0, - FileNotFound = -1, - FileRepeated = -2, - FileOutOfScope = -3, - FileNotReadable = -4, - /// Directory in remote file system - /// ( create a generic FileWatcher instance to watch this directory ). - FileRemote = -5, - /// File system watcher failed to watch for changes. - WatcherFailed = -6, - Unspecified = -7 -}; - -class EFSW_API Log { - public: - /// @return The last error logged - static std::string getLastErrorLog(); - - /// @return The code of the last error logged - static Error getLastErrorCode(); - - /// Reset last error - static void clearLastError(); - - /// Creates an error of the type specified - static Error createLastError( Error err, std::string log ); -}; - -} // namespace Errors -typedef Errors::Error Error; - -/// Optional file watcher settings. -namespace Options { -enum Option { - /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and - /// file system events may be dropped. For that, using a different (bigger) buffer size - /// can be defined here, but note that this does not work for network drives, - /// because a buffer larger than 64K will fail the folder being watched, see - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) - WinBufferSize = 1, - /// For Windows, per default all events are captured but we might only be interested - /// in a subset; the value of the option should be set to a bitwise or'ed set of - /// FILE_NOTIFY_CHANGE_* flags. - WinNotifyFilter = 2, - /// 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& options ); - - /// Remove a directory watch. This is a brute force search O(nlogn). - void removeWatch( const std::string& directory ); - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ); - - /// Starts watching ( in other thread ) - void watch(); - - /// @return Returns a list of the directories that are being watched - std::vector directories(); - - /** Allow recursive watchers to follow symbolic links to other directories - * followSymlinks is disabled by default - */ - void followSymlinks( bool follow ); - - /** @return If can follow symbolic links to directorioes */ - const bool& followSymlinks() const; - - /** When enable this it will allow symlinks to watch recursively out of the pointed directory. - * follorSymlinks must be enabled to this work. - * For example, added symlink to /home/folder, and the symlink points to /, this by default is - * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid - * great levels of recursion. Enabling this could lead in infinite recursion, and crash the - * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow - * this behavior. allowOutOfScopeLinks are disabled by default. - */ - void allowOutOfScopeLinks( bool allow ); - - /// @return Returns if out of scope links are allowed - const bool& allowOutOfScopeLinks() const; - - private: - /// The implementation - FileWatcherImpl* mImpl; - bool mFollowSymlinks; - bool mOutOfScopeLinks; -}; - -/// Basic interface for listening for file events. -/// @class FileWatchListener -class FileWatchListener { - public: - virtual ~FileWatchListener() {} - - /// Handles the action file action - /// @param watchid The watch id for the directory - /// @param dir The directory - /// @param filename The filename that was accessed (not full path) - /// @param action Action that was performed - /// @param oldFilename The name of the file or directory moved - virtual void handleFileAction( WatchID watchid, const std::string& dir, - const std::string& filename, Action action, - std::string oldFilename = "" ) = 0; - - /// 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 +/** + @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 +#include + +#if defined( _WIN32 ) +#ifdef EFSW_DYNAMIC +// Windows platforms +#ifdef EFSW_EXPORTS +// From DLL side, we must export +#define EFSW_API __declspec( dllexport ) +#else +// From client application side, we must import +#define EFSW_API __declspec( dllimport ) +#endif +#else +// No specific directive needed for static build +#ifndef EFSW_API +#define EFSW_API +#endif +#endif +#else +#if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) +#ifndef EFSW_API +#define EFSW_API __attribute__( ( visibility( "default" ) ) ) +#endif +#endif + +// Other platforms don't need to define anything +#ifndef EFSW_API +#define EFSW_API +#endif +#endif + +namespace efsw { + +/// Type for a watch id +typedef long WatchID; + +// forward declarations +class FileWatcherImpl; +class FileWatchListener; +class WatcherOption; + +/// Actions to listen for. Rename will send two events, one for +/// the deletion of the old file, and one for the creation of the +/// new file. +namespace Actions { +enum Action { + /// Sent when a file is created or renamed + Add = 1, + /// Sent when a file is deleted or renamed + Delete = 2, + /// Sent when a file is modified + Modified = 3, + /// Sent when a file is moved + Moved = 4 +}; +} +typedef Actions::Action Action; + +/// Errors log namespace +namespace Errors { + +enum Error { + NoError = 0, + FileNotFound = -1, + FileRepeated = -2, + FileOutOfScope = -3, + FileNotReadable = -4, + /// Directory in remote file system + /// ( create a generic FileWatcher instance to watch this directory ). + FileRemote = -5, + /// File system watcher failed to watch for changes. + WatcherFailed = -6, + Unspecified = -7 +}; + +class EFSW_API Log { + public: + /// @return The last error logged + static std::string getLastErrorLog(); + + /// @return The code of the last error logged + static Error getLastErrorCode(); + + /// Reset last error + static void clearLastError(); + + /// Creates an error of the type specified + static Error createLastError( Error err, std::string log ); +}; + +} // namespace Errors +typedef Errors::Error Error; + +/// Optional file watcher settings. +namespace Options { +enum Option { + /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and + /// file system events may be dropped. For that, using a different (bigger) buffer size + /// can be defined here, but note that this does not work for network drives, + /// because a buffer larger than 64K will fail the folder being watched, see + /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) + WinBufferSize = 1, + /// For Windows, per default all events are captured but we might only be interested + /// in a subset; the value of the option should be set to a bitwise or'ed set of + /// FILE_NOTIFY_CHANGE_* flags. + WinNotifyFilter = 2, + /// 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& options ); + + /// Remove a directory watch. This is a brute force search O(nlogn). + void removeWatch( const std::string& directory ); + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch( WatchID watchid ); + + /// Starts watching ( in other thread ) + void watch(); + + /// @return Returns a list of the directories that are being watched + std::vector directories(); + + /** Allow recursive watchers to follow symbolic links to other directories + * followSymlinks is disabled by default + */ + void followSymlinks( bool follow ); + + /** @return If can follow symbolic links to directorioes */ + const bool& followSymlinks() const; + + /** When enable this it will allow symlinks to watch recursively out of the pointed directory. + * follorSymlinks must be enabled to this work. + * For example, added symlink to /home/folder, and the symlink points to /, this by default is + * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid + * great levels of recursion. Enabling this could lead in infinite recursion, and crash the + * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow + * this behavior. allowOutOfScopeLinks are disabled by default. + */ + void allowOutOfScopeLinks( bool allow ); + + /// @return Returns if out of scope links are allowed + const bool& allowOutOfScopeLinks() const; + + private: + /// The implementation + FileWatcherImpl* mImpl; + bool mFollowSymlinks; + bool mOutOfScopeLinks; +}; + +/// Basic interface for listening for file events. +/// @class FileWatchListener +class FileWatchListener { + public: + virtual ~FileWatchListener() {} + + /// Handles the action file action + /// @param watchid The watch id for the directory + /// @param dir The directory + /// @param filename The filename that was accessed (not full path) + /// @param action Action that was performed + /// @param oldFilename The name of the file or directory moved + virtual void handleFileAction( WatchID watchid, const std::string& dir, + const std::string& filename, Action action, + std::string oldFilename = "" ) = 0; + + /// 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 diff --git a/premake4.lua b/premake4.lua index ab02dd2..8a675ac 100644 --- a/premake4.lua +++ b/premake4.lua @@ -1,261 +1,261 @@ -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 +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 diff --git a/premake5.lua b/premake5.lua index 941c695..def8e24 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1,273 +1,273 @@ -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" } - - if os.istarget("windows") then - osfiles = "src/efsw/platform/win/*.cpp" - else - osfiles = "src/efsw/platform/posix/*.cpp" - end - - -- Activates verbose mode - if _OPTIONS["verbose"] then - defines { "EFSW_VERBOSE" } - end - - cppdialect "C++11" - - objdir("obj/" .. os.target() .. "/") - - filter "platforms:x86" - architecture "x86" - - filter "platforms:x86_64" - architecture "x86_64" - - filter "platforms:arm" - architecture "ARM" - - filter "platforms:arm64" - architecture "ARM64" - - project "efsw-static-lib" - kind "StaticLib" - language "C++" - targetdir("./lib") - includedirs { "include", "src" } - files { "src/efsw/*.cpp", osfiles } - conf_excludes() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-static-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw-static-release" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - targetname "efsw-static-reldbginfo" - conf_warnings() - - project "efsw-test" - kind "ConsoleApp" - language "C++" - links { "efsw-static-lib" } - files { "src/test/efsw-test.cpp" } - includedirs { "include", "src" } - conf_links() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-test-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw-test-release" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - targetname "efsw-test-reldbginfo" - conf_warnings() - - project "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() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-test-stdc-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw-test-stdc-release" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - 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() - - filter "configurations:debug" - defines { "DEBUG" } - symbols "On" - targetname "efsw-debug" - conf_warnings() - - filter "configurations:release" - defines { "NDEBUG" } - optimize "On" - targetname "efsw" - conf_warnings() - - filter "configurations:relwithdbginfo" - defines { "NDEBUG" } - symbols "On" - optimize "On" - targetname "efsw" - conf_warnings() - - if os.istarget("linux") or os.istarget("bsd") or os.istarget("haiku") then - targetextension ( ".so." .. efsw_version ) - postbuildcommands { "sh ../../project/build.reldbginfo.sh " .. efsw_major_version .. " " .. efsw_minor_version .. " " .. efsw_patch_version .. " " .. iif( _OPTIONS["strip-symbols"], "strip-symbols", "" ) } - end +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" } + + if os.istarget("windows") then + osfiles = "src/efsw/platform/win/*.cpp" + else + osfiles = "src/efsw/platform/posix/*.cpp" + end + + -- Activates verbose mode + if _OPTIONS["verbose"] then + defines { "EFSW_VERBOSE" } + end + + cppdialect "C++11" + + objdir("obj/" .. os.target() .. "/") + + filter "platforms:x86" + architecture "x86" + + filter "platforms:x86_64" + architecture "x86_64" + + filter "platforms:arm" + architecture "ARM" + + filter "platforms:arm64" + architecture "ARM64" + + project "efsw-static-lib" + kind "StaticLib" + language "C++" + targetdir("./lib") + includedirs { "include", "src" } + files { "src/efsw/*.cpp", osfiles } + conf_excludes() + + filter "configurations:debug" + defines { "DEBUG" } + symbols "On" + targetname "efsw-static-debug" + conf_warnings() + + filter "configurations:release" + defines { "NDEBUG" } + optimize "On" + targetname "efsw-static-release" + conf_warnings() + + filter "configurations:relwithdbginfo" + defines { "NDEBUG" } + symbols "On" + optimize "On" + targetname "efsw-static-reldbginfo" + conf_warnings() + + project "efsw-test" + kind "ConsoleApp" + language "C++" + links { "efsw-static-lib" } + files { "src/test/efsw-test.cpp" } + includedirs { "include", "src" } + conf_links() + + filter "configurations:debug" + defines { "DEBUG" } + symbols "On" + targetname "efsw-test-debug" + conf_warnings() + + filter "configurations:release" + defines { "NDEBUG" } + optimize "On" + targetname "efsw-test-release" + conf_warnings() + + filter "configurations:relwithdbginfo" + defines { "NDEBUG" } + symbols "On" + optimize "On" + targetname "efsw-test-reldbginfo" + conf_warnings() + + project "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() + + filter "configurations:debug" + defines { "DEBUG" } + symbols "On" + targetname "efsw-test-stdc-debug" + conf_warnings() + + filter "configurations:release" + defines { "NDEBUG" } + optimize "On" + targetname "efsw-test-stdc-release" + conf_warnings() + + filter "configurations:relwithdbginfo" + defines { "NDEBUG" } + symbols "On" + optimize "On" + 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() + + filter "configurations:debug" + defines { "DEBUG" } + symbols "On" + targetname "efsw-debug" + conf_warnings() + + filter "configurations:release" + defines { "NDEBUG" } + optimize "On" + targetname "efsw" + conf_warnings() + + filter "configurations:relwithdbginfo" + defines { "NDEBUG" } + symbols "On" + optimize "On" + targetname "efsw" + conf_warnings() + + if os.istarget("linux") or os.istarget("bsd") or os.istarget("haiku") then + targetextension ( ".so." .. efsw_version ) + postbuildcommands { "sh ../../project/build.reldbginfo.sh " .. efsw_major_version .. " " .. efsw_minor_version .. " " .. efsw_patch_version .. " " .. iif( _OPTIONS["strip-symbols"], "strip-symbols", "" ) } + end diff --git a/project/qtcreator-win/efsw.creator.user b/project/qtcreator-win/efsw.creator.user index deadd7e..ac1ad2c 100644 --- a/project/qtcreator-win/efsw.creator.user +++ b/project/qtcreator-win/efsw.creator.user @@ -1,211 +1,425 @@ - - - - - - EnvironmentId - {55fc4913-4acc-49e6-b0d5-ebf25d4d498e} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - {eb5b6178-a7a7-439e-ab01-e63b057196a1} - 0 - 0 - 0 - - C:\programming\efsw\make\windows - - - - all - - false - - - false - true - Make - - GenericProjectManager.GenericMakeStep - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - - clean - - true - - - false - true - Make - - GenericProjectManager.GenericMakeStep - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Default - Default - GenericProjectManager.GenericBuildConfiguration - - 1 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy locally - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - dwarf - - cpu-cycles - - - 250 - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - %{buildDir}\..\..\bin\efsw-test-debug.exe - Run C:\programming\efsw\bin\efsw-test-debug.exe - - ProjectExplorer.CustomExecutableRunConfiguration - - 3768 - false - true - false - false - true - %{buildDir} - - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - +<<<<<<< HEAD + + + + + + EnvironmentId + {55fc4913-4acc-49e6-b0d5-ebf25d4d498e} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {eb5b6178-a7a7-439e-ab01-e63b057196a1} + 0 + 0 + 0 + + C:\programming\efsw\make\windows + + + + all + + false + + + false + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + + + false + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Default + Default + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + %{buildDir}\..\..\bin\efsw-test-debug.exe + Run C:\programming\efsw\bin\efsw-test-debug.exe + + ProjectExplorer.CustomExecutableRunConfiguration + + 3768 + false + true + false + false + true + %{buildDir} + + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + +======= + + + + + + EnvironmentId + {55fc4913-4acc-49e6-b0d5-ebf25d4d498e} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {eb5b6178-a7a7-439e-ab01-e63b057196a1} + 0 + 0 + 0 + + C:\programming\efsw\make\windows + + + + all + + false + + + false + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + + + false + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Default + Default + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + %{buildDir}\..\..\bin\efsw-test-debug.exe + Run C:\programming\efsw\bin\efsw-test-debug.exe + + ProjectExplorer.CustomExecutableRunConfiguration + + 3768 + false + true + false + false + true + %{buildDir} + + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + +>>>>>>> 0adf96dcdb6ba38e789d409ca1bf1fc149e60808 diff --git a/project/qtcreator-win/efsw.files b/project/qtcreator-win/efsw.files index 8efe50d..d329ff5 100644 --- a/project/qtcreator-win/efsw.files +++ b/project/qtcreator-win/efsw.files @@ -1,215 +1,433 @@ -../../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 +<<<<<<< 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 diff --git a/src/efsw/FileWatcher.cpp b/src/efsw/FileWatcher.cpp index f45b243..ab3ec4b 100644 --- a/src/efsw/FileWatcher.cpp +++ b/src/efsw/FileWatcher.cpp @@ -1,120 +1,120 @@ -#include -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 -#include -#define FILEWATCHER_IMPL FileWatcherWin32 -#define BACKEND_NAME "Win32" -#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY -#include -#define FILEWATCHER_IMPL FileWatcherInotify -#define BACKEND_NAME "Inotify" -#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE -#include -#define FILEWATCHER_IMPL FileWatcherKqueue -#define BACKEND_NAME "Kqueue" -#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS -#include -#define FILEWATCHER_IMPL FileWatcherFSEvents -#define BACKEND_NAME "FSEvents" -#else -#define FILEWATCHER_IMPL FileWatcherGeneric -#define BACKEND_NAME "Generic" -#endif - -#include - -namespace efsw { - -FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { - efDEBUG( "Using backend: %s\n", BACKEND_NAME ); - - mImpl = new FILEWATCHER_IMPL( this ); - - if ( !mImpl->initOK() ) { - efSAFE_DELETE( mImpl ); - - efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); - - mImpl = new FileWatcherGeneric( this ); - } -} - -FileWatcher::FileWatcher( bool useGenericFileWatcher ) : - mFollowSymlinks( false ), mOutOfScopeLinks( false ) { - if ( useGenericFileWatcher ) { - efDEBUG( "Using backend: Generic\n" ); - - mImpl = new FileWatcherGeneric( this ); - } else { - efDEBUG( "Using backend: %s\n", BACKEND_NAME ); - - mImpl = new FILEWATCHER_IMPL( this ); - - if ( !mImpl->initOK() ) { - efSAFE_DELETE( mImpl ); - - efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); - - mImpl = new FileWatcherGeneric( this ); - } - } -} - -FileWatcher::~FileWatcher() { - efSAFE_DELETE( mImpl ); -} - -WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { - return addWatch( directory, watcher, false, {} ); -} - -WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive ) { - return addWatch( directory, watcher, recursive, {} ); -} - -WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& options ) { - if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { - return mImpl->addWatch( directory, watcher, recursive, options ); - } else { - return Errors::Log::createLastError( Errors::FileRemote, directory ); - } -} - -void FileWatcher::removeWatch( const std::string& directory ) { - mImpl->removeWatch( directory ); -} - -void FileWatcher::removeWatch( WatchID watchid ) { - mImpl->removeWatch( watchid ); -} - -void FileWatcher::watch() { - mImpl->watch(); -} - -std::vector FileWatcher::directories() { - return mImpl->directories(); -} - -void FileWatcher::followSymlinks( bool follow ) { - mFollowSymlinks = follow; -} - -const bool& FileWatcher::followSymlinks() const { - return mFollowSymlinks; -} - -void FileWatcher::allowOutOfScopeLinks( bool allow ) { - mOutOfScopeLinks = allow; -} - -const bool& FileWatcher::allowOutOfScopeLinks() const { - return mOutOfScopeLinks; -} - -} // namespace efsw +#include +#include +#include +#include + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 +#include +#define FILEWATCHER_IMPL FileWatcherWin32 +#define BACKEND_NAME "Win32" +#elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY +#include +#define FILEWATCHER_IMPL FileWatcherInotify +#define BACKEND_NAME "Inotify" +#elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE +#include +#define FILEWATCHER_IMPL FileWatcherKqueue +#define BACKEND_NAME "Kqueue" +#elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS +#include +#define FILEWATCHER_IMPL FileWatcherFSEvents +#define BACKEND_NAME "FSEvents" +#else +#define FILEWATCHER_IMPL FileWatcherGeneric +#define BACKEND_NAME "Generic" +#endif + +#include + +namespace efsw { + +FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { + efDEBUG( "Using backend: %s\n", BACKEND_NAME ); + + mImpl = new FILEWATCHER_IMPL( this ); + + if ( !mImpl->initOK() ) { + efSAFE_DELETE( mImpl ); + + efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); + + mImpl = new FileWatcherGeneric( this ); + } +} + +FileWatcher::FileWatcher( bool useGenericFileWatcher ) : + mFollowSymlinks( false ), mOutOfScopeLinks( false ) { + if ( useGenericFileWatcher ) { + efDEBUG( "Using backend: Generic\n" ); + + mImpl = new FileWatcherGeneric( this ); + } else { + efDEBUG( "Using backend: %s\n", BACKEND_NAME ); + + mImpl = new FILEWATCHER_IMPL( this ); + + if ( !mImpl->initOK() ) { + efSAFE_DELETE( mImpl ); + + efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); + + mImpl = new FileWatcherGeneric( this ); + } + } +} + +FileWatcher::~FileWatcher() { + efSAFE_DELETE( mImpl ); +} + +WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { + return addWatch( directory, watcher, false, {} ); +} + +WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive ) { + return addWatch( directory, watcher, recursive, {} ); +} + +WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive, const std::vector& options ) { + if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { + return mImpl->addWatch( directory, watcher, recursive, options ); + } else { + return Errors::Log::createLastError( Errors::FileRemote, directory ); + } +} + +void FileWatcher::removeWatch( const std::string& directory ) { + mImpl->removeWatch( directory ); +} + +void FileWatcher::removeWatch( WatchID watchid ) { + mImpl->removeWatch( watchid ); +} + +void FileWatcher::watch() { + mImpl->watch(); +} + +std::vector FileWatcher::directories() { + return mImpl->directories(); +} + +void FileWatcher::followSymlinks( bool follow ) { + mFollowSymlinks = follow; +} + +const bool& FileWatcher::followSymlinks() const { + return mFollowSymlinks; +} + +void FileWatcher::allowOutOfScopeLinks( bool allow ) { + mOutOfScopeLinks = allow; +} + +const bool& FileWatcher::allowOutOfScopeLinks() const { + return mOutOfScopeLinks; +} + +} // namespace efsw diff --git a/src/efsw/FileWatcherImpl.cpp b/src/efsw/FileWatcherImpl.cpp index bf69a45..f8313da 100644 --- a/src/efsw/FileWatcherImpl.cpp +++ b/src/efsw/FileWatcherImpl.cpp @@ -1,34 +1,34 @@ -#include -#include -#include - -namespace efsw { - -FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : - mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { - System::maxFD(); -} - -FileWatcherImpl::~FileWatcherImpl() {} - -bool FileWatcherImpl::initOK() { - return static_cast( mInitOK ); -} - -bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { - return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || - -1 != String::strStartsWith( curPath, link ); -} - -int FileWatcherImpl::getOptionValue( const std::vector& options, Option option, - int defaultValue ) { - for ( size_t i = 0; i < options.size(); i++ ) { - if ( options[i].mOption == option ) { - return options[i].mValue; - } - } - - return defaultValue; -} - -} // namespace efsw +#include +#include +#include + +namespace efsw { + +FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : + mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { + System::maxFD(); +} + +FileWatcherImpl::~FileWatcherImpl() {} + +bool FileWatcherImpl::initOK() { + return static_cast( mInitOK ); +} + +bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { + return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || + -1 != String::strStartsWith( curPath, link ); +} + +int FileWatcherImpl::getOptionValue( const std::vector& options, Option option, + int defaultValue ) { + for ( size_t i = 0; i < options.size(); i++ ) { + if ( options[i].mOption == option ) { + return options[i].mValue; + } + } + + return defaultValue; +} + +} // namespace efsw diff --git a/src/efsw/FileWatcherImpl.hpp b/src/efsw/FileWatcherImpl.hpp index a6ec472..d82209c 100644 --- a/src/efsw/FileWatcherImpl.hpp +++ b/src/efsw/FileWatcherImpl.hpp @@ -1,64 +1,64 @@ -#ifndef EFSW_FILEWATCHERIMPL_HPP -#define EFSW_FILEWATCHERIMPL_HPP - -#include -#include -#include -#include -#include -#include - -namespace efsw { - -class FileWatcherImpl { - public: - FileWatcherImpl( FileWatcher* parent ); - - virtual ~FileWatcherImpl(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector& options = {} ) = 0; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - virtual void removeWatch( const std::string& directory ) = 0; - - /// Remove a directory watch. This is a map lookup O(logn). - virtual void removeWatch( WatchID watchid ) = 0; - - /// Updates the watcher. Must be called often. - virtual void watch() = 0; - - /// Handles the action - virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) = 0; - - /// @return Returns a list of the directories that are being watched - virtual std::vector directories() = 0; - - /// @return true if the backend init successfully - virtual bool initOK(); - - /// @return If the link is allowed according to the current path and the state of out scope - /// links - virtual bool linkAllowed( const std::string& curPath, const std::string& link ); - - /// Search if a directory already exists in the watches - virtual bool pathInWatches( const std::string& path ) = 0; - - protected: - friend class FileWatcher; - friend class DirWatcherGeneric; - - FileWatcher* mFileWatcher; - Atomic mInitOK; - bool mIsGeneric; - - int getOptionValue( const std::vector& options, Option option, - int defaultValue ); -}; - -} // namespace efsw - -#endif +#ifndef EFSW_FILEWATCHERIMPL_HPP +#define EFSW_FILEWATCHERIMPL_HPP + +#include +#include +#include +#include +#include +#include + +namespace efsw { + +class FileWatcherImpl { + public: + FileWatcherImpl( FileWatcher* parent ); + + virtual ~FileWatcherImpl(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive, const std::vector& options = {} ) = 0; + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + virtual void removeWatch( const std::string& directory ) = 0; + + /// Remove a directory watch. This is a map lookup O(logn). + virtual void removeWatch( WatchID watchid ) = 0; + + /// Updates the watcher. Must be called often. + virtual void watch() = 0; + + /// Handles the action + virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, + std::string oldFilename = "" ) = 0; + + /// @return Returns a list of the directories that are being watched + virtual std::vector directories() = 0; + + /// @return true if the backend init successfully + virtual bool initOK(); + + /// @return If the link is allowed according to the current path and the state of out scope + /// links + virtual bool linkAllowed( const std::string& curPath, const std::string& link ); + + /// Search if a directory already exists in the watches + virtual bool pathInWatches( const std::string& path ) = 0; + + protected: + friend class FileWatcher; + friend class DirWatcherGeneric; + + FileWatcher* mFileWatcher; + Atomic mInitOK; + bool mIsGeneric; + + int getOptionValue( const std::vector& options, Option option, + int defaultValue ); +}; + +} // namespace efsw + +#endif diff --git a/src/efsw/FileWatcherWin32.cpp b/src/efsw/FileWatcherWin32.cpp index 05a20d6..1dd96aa 100644 --- a/src/efsw/FileWatcherWin32.cpp +++ b/src/efsw/FileWatcherWin32.cpp @@ -1,267 +1,267 @@ -#include -#include -#include -#include -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -namespace efsw { - -FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : - FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { - mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); - if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) - mInitOK = true; -} - -FileWatcherWin32::~FileWatcherWin32() { - mInitOK = false; - - if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { - PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast( this ), NULL ); - } - - efSAFE_DELETE( mThread ); - - removeAllWatches(); - - if ( mIOCP ) - CloseHandle( mIOCP ); -} - -WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, - bool recursive, const std::vector &options ) { - std::string dir( directory ); - - FileInfo fi( dir ); - - if ( !fi.isDirectory() ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } else if ( !fi.isReadable() ) { - return Errors::Log::createLastError( Errors::FileNotReadable, dir ); - } - - FileSystem::dirAddSlashAtEnd( dir ); - - Lock lock( mWatchesLock ); - - if ( pathInWatches( dir ) ) { - return Errors::Log::createLastError( Errors::FileRepeated, dir ); - } - - WatchID watchid = ++mLastWatchID; - - DWORD bufferSize = static_cast( getOptionValue(options, Option::WinBufferSize, 63 * 1024) ); - DWORD notifyFilter = static_cast( getOptionValue(options, Option::WinNotifyFilter, - FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | - FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_SIZE) ); - - WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), - recursive, bufferSize, notifyFilter, mIOCP ); - - if ( NULL == watch ) { - return Errors::Log::createLastError( Errors::FileNotFound, dir ); - } - - // Add the handle to the handles vector - watch->Watch->ID = watchid; - watch->Watch->Watch = this; - watch->Watch->Listener = watcher; - watch->Watch->DirName = new char[dir.length() + 1]; - strcpy( watch->Watch->DirName, dir.c_str() ); - - mWatches.insert( watch ); - - return watchid; -} - -void FileWatcherWin32::removeWatch( const std::string& directory ) { - Lock lock( mWatchesLock ); - - Watches::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - if ( directory == ( *iter )->Watch->DirName ) { - removeWatch( *iter ); - break; - } - } -} - -void FileWatcherWin32::removeWatch( WatchID watchid ) { - Lock lock( mWatchesLock ); - - Watches::iterator iter = mWatches.begin(); - - for ( ; iter != mWatches.end(); ++iter ) { - // Find the watch ID - if ( ( *iter )->Watch->ID == watchid ) { - removeWatch( *iter ); - return; - } - } -} - -void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { - Lock lock( mWatchesLock ); - - DestroyWatch( watch ); - mWatches.erase( watch ); -} - -void FileWatcherWin32::watch() { - if ( NULL == mThread ) { - mThread = new Thread([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( this ) ) { - break; - } else { - Lock lock( mWatchesLock ); - if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end()) - WatchCallback( numOfBytes, ov ); - } - } - } else { - System::sleep( 10 ); - } - } while ( mInitOK ); - - removeAllWatches(); -} - -void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, - unsigned long action, std::string /*oldFilename*/ ) { - Action fwAction; - - switch ( action ) { - case FILE_ACTION_RENAMED_OLD_NAME: - watch->OldFileName = filename; - return; - case FILE_ACTION_ADDED: - fwAction = Actions::Add; - break; - case FILE_ACTION_RENAMED_NEW_NAME: { - fwAction = Actions::Moved; - - std::string fpath( watch->Directory + filename ); - - // Update the directory path - if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { - // Update the new directory path - std::string opath( watch->Directory + watch->OldFileName ); - FileSystem::dirAddSlashAtEnd( opath ); - FileSystem::dirAddSlashAtEnd( fpath ); - - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( ( *it )->Watch->Directory == opath ) { - ( *it )->Watch->Directory = fpath; - - break; - } - } - } - - std::string folderPath( static_cast( watch )->DirName ); - std::string realFilename = filename; - std::size_t sepPos = filename.find_last_of( "/\\" ); - std::string oldFolderPath = - static_cast( watch )->DirName + - watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); - - if ( sepPos != std::string::npos ) { - folderPath += - filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); - realFilename = filename.substr( sepPos + 1 ); - } - - if ( folderPath == oldFolderPath ) { - watch->Listener->handleFileAction( - watch->ID, folderPath, realFilename, fwAction, - FileSystem::fileNameFromPath( watch->OldFileName ) ); - } else { - watch->Listener->handleFileAction( watch->ID, - static_cast( watch )->DirName, - filename, fwAction, watch->OldFileName ); - } - return; - } - case FILE_ACTION_REMOVED: - fwAction = Actions::Delete; - break; - case FILE_ACTION_MODIFIED: - fwAction = Actions::Modified; - break; - default: - return; - }; - - std::string folderPath( static_cast( watch )->DirName ); - std::string realFilename = filename; - std::size_t sepPos = filename.find_last_of( "/\\" ); - - if ( sepPos != std::string::npos ) { - folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); - realFilename = filename.substr( sepPos + 1 ); - } - - FileSystem::dirAddSlashAtEnd( folderPath ); - - watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); -} - -std::vector FileWatcherWin32::directories() { - std::vector dirs; - - Lock lock( mWatchesLock ); - - dirs.reserve( mWatches.size() ); - - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - dirs.push_back( std::string( ( *it )->Watch->DirName ) ); - } - - return dirs; -} - -bool FileWatcherWin32::pathInWatches( const std::string& path ) { - Lock lock( mWatchesLock ); - - for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { - if ( ( *it )->Watch->DirName == path ) { - return true; - } - } - - return false; -} - -} // namespace efsw - -#endif +#include +#include +#include +#include +#include + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +namespace efsw { + +FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : + FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { + mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); + if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) + mInitOK = true; +} + +FileWatcherWin32::~FileWatcherWin32() { + mInitOK = false; + + if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { + PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast( this ), NULL ); + } + + efSAFE_DELETE( mThread ); + + removeAllWatches(); + + if ( mIOCP ) + CloseHandle( mIOCP ); +} + +WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, + bool recursive, const std::vector &options ) { + std::string dir( directory ); + + FileInfo fi( dir ); + + if ( !fi.isDirectory() ) { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } else if ( !fi.isReadable() ) { + return Errors::Log::createLastError( Errors::FileNotReadable, dir ); + } + + FileSystem::dirAddSlashAtEnd( dir ); + + Lock lock( mWatchesLock ); + + if ( pathInWatches( dir ) ) { + return Errors::Log::createLastError( Errors::FileRepeated, dir ); + } + + WatchID watchid = ++mLastWatchID; + + DWORD bufferSize = static_cast( getOptionValue(options, Option::WinBufferSize, 63 * 1024) ); + DWORD notifyFilter = static_cast( getOptionValue(options, Option::WinNotifyFilter, + FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_SIZE) ); + + WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), + recursive, bufferSize, notifyFilter, mIOCP ); + + if ( NULL == watch ) { + return Errors::Log::createLastError( Errors::FileNotFound, dir ); + } + + // Add the handle to the handles vector + watch->Watch->ID = watchid; + watch->Watch->Watch = this; + watch->Watch->Listener = watcher; + watch->Watch->DirName = new char[dir.length() + 1]; + strcpy( watch->Watch->DirName, dir.c_str() ); + + mWatches.insert( watch ); + + return watchid; +} + +void FileWatcherWin32::removeWatch( const std::string& directory ) { + Lock lock( mWatchesLock ); + + Watches::iterator iter = mWatches.begin(); + + for ( ; iter != mWatches.end(); ++iter ) { + if ( directory == ( *iter )->Watch->DirName ) { + removeWatch( *iter ); + break; + } + } +} + +void FileWatcherWin32::removeWatch( WatchID watchid ) { + Lock lock( mWatchesLock ); + + Watches::iterator iter = mWatches.begin(); + + for ( ; iter != mWatches.end(); ++iter ) { + // Find the watch ID + if ( ( *iter )->Watch->ID == watchid ) { + removeWatch( *iter ); + return; + } + } +} + +void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { + Lock lock( mWatchesLock ); + + DestroyWatch( watch ); + mWatches.erase( watch ); +} + +void FileWatcherWin32::watch() { + if ( NULL == mThread ) { + mThread = new Thread([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( this ) ) { + break; + } else { + Lock lock( mWatchesLock ); + if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end()) + WatchCallback( numOfBytes, ov ); + } + } + } else { + System::sleep( 10 ); + } + } while ( mInitOK ); + + removeAllWatches(); +} + +void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, + unsigned long action, std::string /*oldFilename*/ ) { + Action fwAction; + + switch ( action ) { + case FILE_ACTION_RENAMED_OLD_NAME: + watch->OldFileName = filename; + return; + case FILE_ACTION_ADDED: + fwAction = Actions::Add; + break; + case FILE_ACTION_RENAMED_NEW_NAME: { + fwAction = Actions::Moved; + + std::string fpath( watch->Directory + filename ); + + // Update the directory path + if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { + // Update the new directory path + std::string opath( watch->Directory + watch->OldFileName ); + FileSystem::dirAddSlashAtEnd( opath ); + FileSystem::dirAddSlashAtEnd( fpath ); + + for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( ( *it )->Watch->Directory == opath ) { + ( *it )->Watch->Directory = fpath; + + break; + } + } + } + + std::string folderPath( static_cast( watch )->DirName ); + std::string realFilename = filename; + std::size_t sepPos = filename.find_last_of( "/\\" ); + std::string oldFolderPath = + static_cast( watch )->DirName + + watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); + + if ( sepPos != std::string::npos ) { + folderPath += + filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); + realFilename = filename.substr( sepPos + 1 ); + } + + if ( folderPath == oldFolderPath ) { + watch->Listener->handleFileAction( + watch->ID, folderPath, realFilename, fwAction, + FileSystem::fileNameFromPath( watch->OldFileName ) ); + } else { + watch->Listener->handleFileAction( watch->ID, + static_cast( watch )->DirName, + filename, fwAction, watch->OldFileName ); + } + return; + } + case FILE_ACTION_REMOVED: + fwAction = Actions::Delete; + break; + case FILE_ACTION_MODIFIED: + fwAction = Actions::Modified; + break; + default: + return; + }; + + std::string folderPath( static_cast( watch )->DirName ); + std::string realFilename = filename; + std::size_t sepPos = filename.find_last_of( "/\\" ); + + if ( sepPos != std::string::npos ) { + folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); + realFilename = filename.substr( sepPos + 1 ); + } + + FileSystem::dirAddSlashAtEnd( folderPath ); + + watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); +} + +std::vector FileWatcherWin32::directories() { + std::vector dirs; + + Lock lock( mWatchesLock ); + + dirs.reserve( mWatches.size() ); + + for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + dirs.push_back( std::string( ( *it )->Watch->DirName ) ); + } + + return dirs; +} + +bool FileWatcherWin32::pathInWatches( const std::string& path ) { + Lock lock( mWatchesLock ); + + for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { + if ( ( *it )->Watch->DirName == path ) { + return true; + } + } + + return false; +} + +} // namespace efsw + +#endif diff --git a/src/efsw/FileWatcherWin32.hpp b/src/efsw/FileWatcherWin32.hpp index 3016aac..3f6f419 100644 --- a/src/efsw/FileWatcherWin32.hpp +++ b/src/efsw/FileWatcherWin32.hpp @@ -1,71 +1,71 @@ -#ifndef EFSW_FILEWATCHERWIN32_HPP -#define EFSW_FILEWATCHERWIN32_HPP - -#include - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 - -#include -#include -#include -#include - -namespace efsw { - -/// Implementation for Win32 based on ReadDirectoryChangesW. -/// @class FileWatcherWin32 -class FileWatcherWin32 : public FileWatcherImpl { - public: - /// type for a map from WatchID to WatcherWin32 pointer - typedef std::unordered_set Watches; - - FileWatcherWin32( FileWatcher* parent ); - - virtual ~FileWatcherWin32(); - - /// Add a directory watch - /// On error returns WatchID with Error type. - WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, - const std::vector &options ) override; - - /// Remove a directory watch. This is a brute force lazy search O(nlogn). - void removeWatch( const std::string& directory ) override; - - /// Remove a directory watch. This is a map lookup O(logn). - void removeWatch( WatchID watchid ) override; - - /// Updates the watcher. Must be called often. - void watch() override; - - /// Handles the action - void handleAction( Watcher* watch, const std::string& filename, unsigned long action, - std::string oldFilename = "" ) override; - - /// @return Returns a list of the directories that are being watched - std::vector directories() override; - - protected: - HANDLE mIOCP; - Watches mWatches; - - /// The last watchid - WatchID mLastWatchID; - Thread* mThread; - Mutex mWatchesLock; - - bool pathInWatches( const std::string& path ) override; - - /// Remove all directory watches. - void removeAllWatches(); - - void removeWatch( WatcherStructWin32* watch ); - - private: - void run(); -}; - -} // namespace efsw - -#endif - -#endif +#ifndef EFSW_FILEWATCHERWIN32_HPP +#define EFSW_FILEWATCHERWIN32_HPP + +#include + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 + +#include +#include +#include +#include + +namespace efsw { + +/// Implementation for Win32 based on ReadDirectoryChangesW. +/// @class FileWatcherWin32 +class FileWatcherWin32 : public FileWatcherImpl { + public: + /// type for a map from WatchID to WatcherWin32 pointer + typedef std::unordered_set Watches; + + FileWatcherWin32( FileWatcher* parent ); + + virtual ~FileWatcherWin32(); + + /// Add a directory watch + /// On error returns WatchID with Error type. + WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, + const std::vector &options ) override; + + /// Remove a directory watch. This is a brute force lazy search O(nlogn). + void removeWatch( const std::string& directory ) override; + + /// Remove a directory watch. This is a map lookup O(logn). + void removeWatch( WatchID watchid ) override; + + /// Updates the watcher. Must be called often. + void watch() override; + + /// Handles the action + void handleAction( Watcher* watch, const std::string& filename, unsigned long action, + std::string oldFilename = "" ) override; + + /// @return Returns a list of the directories that are being watched + std::vector directories() override; + + protected: + HANDLE mIOCP; + Watches mWatches; + + /// The last watchid + WatchID mLastWatchID; + Thread* mThread; + Mutex mWatchesLock; + + bool pathInWatches( const std::string& path ) override; + + /// Remove all directory watches. + void removeAllWatches(); + + void removeWatch( WatcherStructWin32* watch ); + + private: + void run(); +}; + +} // namespace efsw + +#endif + +#endif diff --git a/src/efsw/Utf.hpp b/src/efsw/Utf.hpp index 1b042cd..6e9ea71 100644 --- a/src/efsw/Utf.hpp +++ b/src/efsw/Utf.hpp @@ -1,721 +1,721 @@ -/** NOTE: - * This code is based on the Utf implementation from SFML2. License zlib/png ( - *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not - *the original implementation from SFML2. - * */ - -#ifndef EFSW_UTF_HPP -#define EFSW_UTF_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include -#include -#include - -namespace efsw { - -template class Utf; - -//////////////////////////////////////////////////////////// -/// \brief Specialization of the Utf template for UTF-8 -/// -//////////////////////////////////////////////////////////// -template <> class Utf<8> { - public: - //////////////////////////////////////////////////////////// - /// \brief Decode a single UTF-8 character - /// - /// Decoding a character means finding its unique 32-bits - /// code (called the codepoint) in the Unicode standard. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Codepoint of the decoded UTF-8 character - /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template - static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-8 character - /// - /// Encoding a character means converting a unique 32-bits - /// code (called the codepoint) in the target encoding, UTF-8. - /// - /// \param input Codepoint to encode as UTF-8 - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Advance to the next UTF-8 character - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static In Next( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Count the number of characters of a UTF-8 sequence - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element, thus the - /// total size can be different from (begin - end). - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static std::size_t Count( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an ANSI characters range to UTF-8 - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a wide characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromWide( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromLatin1( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-8 characters range to ANSI characters - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToAnsi( In begin, In end, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-8 characters range to wide characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); -#endif - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-8 characters range to UTF-8 - /// - /// This functions does nothing more than a direct copy; - /// it is defined only to provide the same interface as other - /// specializations of the efsw::Utf<> template, and allow - /// generic code to be written on top of it. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out toUtf8( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-8 characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf16( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-8 characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf32( In begin, In end, Out output ); -}; - -//////////////////////////////////////////////////////////// -/// \brief Specialization of the Utf template for UTF-16 -/// -//////////////////////////////////////////////////////////// -template <> class Utf<16> { - public: - //////////////////////////////////////////////////////////// - /// \brief Decode a single UTF-16 character - /// - /// Decoding a character means finding its unique 32-bits - /// code (called the codepoint) in the Unicode standard. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Codepoint of the decoded UTF-16 character - /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template - static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-16 character - /// - /// Encoding a character means converting a unique 32-bits - /// code (called the codepoint) in the target encoding, UTF-16. - /// - /// \param input Codepoint to encode as UTF-16 - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Advance to the next UTF-16 character - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static In Next( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Count the number of characters of a UTF-16 sequence - /// - /// This function is necessary for multi-elements encodings, as - /// a single character may use more than 1 storage element, thus the - /// total size can be different from (begin - end). - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static std::size_t Count( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an ANSI characters range to UTF-16 - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a wide characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromWide( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromLatin1( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to ANSI characters - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToAnsi( In begin, In end, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to wide characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); -#endif - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-16 characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out toUtf8( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-16 characters range to UTF-16 - /// - /// This functions does nothing more than a direct copy; - /// it is defined only to provide the same interface as other - /// specializations of the efsw::Utf<> template, and allow - /// generic code to be written on top of it. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf16( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-16 characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf32( In begin, In end, Out output ); -}; - -//////////////////////////////////////////////////////////// -/// \brief Specialization of the Utf template for UTF-32 -/// -//////////////////////////////////////////////////////////// -template <> class Utf<32> { - public: - //////////////////////////////////////////////////////////// - /// \brief Decode a single UTF-32 character - /// - /// Decoding a character means finding its unique 32-bits - /// code (called the codepoint) in the Unicode standard. - /// For UTF-32, the character value is the same as the codepoint. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Codepoint of the decoded UTF-32 character - /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template - static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-32 character - /// - /// Encoding a character means converting a unique 32-bits - /// code (called the codepoint) in the target encoding, UTF-32. - /// For UTF-32, the codepoint is the same as the character value. - /// - /// \param input Codepoint to encode as UTF-32 - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Advance to the next UTF-32 character - /// - /// This function is trivial for UTF-32, which can store - /// every character in a single storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static In Next( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Count the number of characters of a UTF-32 sequence - /// - /// This function is trivial for UTF-32, which can store - /// every character in a single storage element. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// - /// \return Iterator pointing to one past the last read element of the input sequence - /// - //////////////////////////////////////////////////////////// - template static std::size_t Count( In begin, In end ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an ANSI characters range to UTF-32 - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a wide characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromWide( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out FromLatin1( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-32 characters range to ANSI characters - /// - /// The current global locale will be used by default, unless you - /// pass a custom one in the \a locale parameter. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) - /// \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToAnsi( In begin, In end, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-32 characters range to wide characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); -#endif - - //////////////////////////////////////////////////////////// - /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-32 characters range to UTF-8 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out toUtf8( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-32 characters range to UTF-16 - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf16( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Convert a UTF-32 characters range to UTF-32 - /// - /// This functions does nothing more than a direct copy; - /// it is defined only to provide the same interface as other - /// specializations of the efsw::Utf<> template, and allow - /// generic code to be written on top of it. - /// - /// \param begin Iterator pointing to the beginning of the input sequence - /// \param end Iterator pointing to the end of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template static Out ToUtf32( In begin, In end, Out output ); - - //////////////////////////////////////////////////////////// - /// \brief Decode a single ANSI character to UTF-32 - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param input Input ANSI character - /// \param locale Locale to use for conversion - /// - /// \return Converted character - /// - //////////////////////////////////////////////////////////// - template - static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); - - //////////////////////////////////////////////////////////// - /// \brief Decode a single wide character to UTF-32 - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param input Input wide character - /// - /// \return Converted character - /// - //////////////////////////////////////////////////////////// - template static Uint32 DecodeWide( In input ); - - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-32 character to ANSI - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param codepoint Iterator pointing to the beginning of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to - /// skip it) \param locale Locale to use for conversion - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, - const std::locale& locale = std::locale() ); - -#ifndef EFSW_NO_WIDECHAR - //////////////////////////////////////////////////////////// - /// \brief Encode a single UTF-32 character to wide - /// - /// This function does not exist in other specializations - /// of efsw::Utf<>, it is defined for convenience (it is used by - /// several other conversion functions). - /// - /// \param codepoint Iterator pointing to the beginning of the input sequence - /// \param output Iterator pointing to the beginning of the output sequence - /// \param replacement Replacement if the input character is not convertible to wide (use 0 to - /// skip it) - /// - /// \return Iterator to the end of the output sequence which has been written - /// - //////////////////////////////////////////////////////////// - template - static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); -#endif -}; - -#include "Utf.inl" - -// Make typedefs to get rid of the template syntax -typedef Utf<8> Utf8; -typedef Utf<16> Utf16; -typedef Utf<32> Utf32; - -} // namespace efsw -#endif - -//////////////////////////////////////////////////////////// -/// \class efsw::Utf -/// \ingroup system -/// -/// Utility class providing generic functions for UTF conversions. -/// -/// efsw::Utf is a low-level, generic interface for counting, iterating, -/// encoding and decoding Unicode characters and strings. It is able -/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. -/// -/// efsw::Utf functions are all static, these classes are not meant to -/// be instanciated. All the functions are template, so that you -/// can use any character / string type for a given encoding. -/// -/// It has 3 specializations: -/// \li efsw::Utf<8> (typedef'd to efsw::Utf8) -/// \li efsw::Utf<16> (typedef'd to efsw::Utf16) -/// \li efsw::Utf<32> (typedef'd to efsw::Utf32) -/// -//////////////////////////////////////////////////////////// +/** NOTE: + * This code is based on the Utf implementation from SFML2. License zlib/png ( + *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not + *the original implementation from SFML2. + * */ + +#ifndef EFSW_UTF_HPP +#define EFSW_UTF_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + +namespace efsw { + +template class Utf; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-8 +/// +//////////////////////////////////////////////////////////// +template <> class Utf<8> { + public: + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-8 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-8 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-8 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-8. + /// + /// \param input Codepoint to encode as UTF-8 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-8 character + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template static In Next( In begin, In end ); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-8 sequence + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element, thus the + /// total size can be different from (begin - end). + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template static std::size_t Count( In begin, In end ); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-8 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out FromWide( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out FromLatin1( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToAnsi( In begin, In end, Out output, char replacement = 0, + const std::locale& locale = std::locale() ); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); +#endif + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-8 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the efsw::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out toUtf8( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out ToUtf16( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-8 characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out ToUtf32( In begin, In end, Out output ); +}; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-16 +/// +//////////////////////////////////////////////////////////// +template <> class Utf<16> { + public: + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-16 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-16 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-16 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-16. + /// + /// \param input Codepoint to encode as UTF-16 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-16 character + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template static In Next( In begin, In end ); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-16 sequence + /// + /// This function is necessary for multi-elements encodings, as + /// a single character may use more than 1 storage element, thus the + /// total size can be different from (begin - end). + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template static std::size_t Count( In begin, In end ); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-16 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out FromWide( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out FromLatin1( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToAnsi( In begin, In end, Out output, char replacement = 0, + const std::locale& locale = std::locale() ); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); +#endif + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out toUtf8( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-16 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the efsw::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out ToUtf16( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-16 characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out ToUtf32( In begin, In end, Out output ); +}; + +//////////////////////////////////////////////////////////// +/// \brief Specialization of the Utf template for UTF-32 +/// +//////////////////////////////////////////////////////////// +template <> class Utf<32> { + public: + //////////////////////////////////////////////////////////// + /// \brief Decode a single UTF-32 character + /// + /// Decoding a character means finding its unique 32-bits + /// code (called the codepoint) in the Unicode standard. + /// For UTF-32, the character value is the same as the codepoint. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Codepoint of the decoded UTF-32 character + /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template + static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character + /// + /// Encoding a character means converting a unique 32-bits + /// code (called the codepoint) in the target encoding, UTF-32. + /// For UTF-32, the codepoint is the same as the character value. + /// + /// \param input Codepoint to encode as UTF-32 + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Advance to the next UTF-32 character + /// + /// This function is trivial for UTF-32, which can store + /// every character in a single storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template static In Next( In begin, In end ); + + //////////////////////////////////////////////////////////// + /// \brief Count the number of characters of a UTF-32 sequence + /// + /// This function is trivial for UTF-32, which can store + /// every character in a single storage element. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// + /// \return Iterator pointing to one past the last read element of the input sequence + /// + //////////////////////////////////////////////////////////// + template static std::size_t Count( In begin, In end ); + + //////////////////////////////////////////////////////////// + /// \brief Convert an ANSI characters range to UTF-32 + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a wide characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out FromWide( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out FromLatin1( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-32 characters range to ANSI characters + /// + /// The current global locale will be used by default, unless you + /// pass a custom one in the \a locale parameter. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) + /// \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToAnsi( In begin, In end, Out output, char replacement = 0, + const std::locale& locale = std::locale() ); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-32 characters range to wide characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); +#endif + + //////////////////////////////////////////////////////////// + /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-8 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out toUtf8( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-16 + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out ToUtf16( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Convert a UTF-32 characters range to UTF-32 + /// + /// This functions does nothing more than a direct copy; + /// it is defined only to provide the same interface as other + /// specializations of the efsw::Utf<> template, and allow + /// generic code to be written on top of it. + /// + /// \param begin Iterator pointing to the beginning of the input sequence + /// \param end Iterator pointing to the end of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template static Out ToUtf32( In begin, In end, Out output ); + + //////////////////////////////////////////////////////////// + /// \brief Decode a single ANSI character to UTF-32 + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param input Input ANSI character + /// \param locale Locale to use for conversion + /// + /// \return Converted character + /// + //////////////////////////////////////////////////////////// + template + static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); + + //////////////////////////////////////////////////////////// + /// \brief Decode a single wide character to UTF-32 + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param input Input wide character + /// + /// \return Converted character + /// + //////////////////////////////////////////////////////////// + template static Uint32 DecodeWide( In input ); + + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character to ANSI + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param codepoint Iterator pointing to the beginning of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to + /// skip it) \param locale Locale to use for conversion + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, + const std::locale& locale = std::locale() ); + +#ifndef EFSW_NO_WIDECHAR + //////////////////////////////////////////////////////////// + /// \brief Encode a single UTF-32 character to wide + /// + /// This function does not exist in other specializations + /// of efsw::Utf<>, it is defined for convenience (it is used by + /// several other conversion functions). + /// + /// \param codepoint Iterator pointing to the beginning of the input sequence + /// \param output Iterator pointing to the beginning of the output sequence + /// \param replacement Replacement if the input character is not convertible to wide (use 0 to + /// skip it) + /// + /// \return Iterator to the end of the output sequence which has been written + /// + //////////////////////////////////////////////////////////// + template + static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); +#endif +}; + +#include "Utf.inl" + +// Make typedefs to get rid of the template syntax +typedef Utf<8> Utf8; +typedef Utf<16> Utf16; +typedef Utf<32> Utf32; + +} // namespace efsw +#endif + +//////////////////////////////////////////////////////////// +/// \class efsw::Utf +/// \ingroup system +/// +/// Utility class providing generic functions for UTF conversions. +/// +/// efsw::Utf is a low-level, generic interface for counting, iterating, +/// encoding and decoding Unicode characters and strings. It is able +/// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. +/// +/// efsw::Utf functions are all static, these classes are not meant to +/// be instanciated. All the functions are template, so that you +/// can use any character / string type for a given encoding. +/// +/// It has 3 specializations: +/// \li efsw::Utf<8> (typedef'd to efsw::Utf8) +/// \li efsw::Utf<16> (typedef'd to efsw::Utf16) +/// \li efsw::Utf<32> (typedef'd to efsw::Utf32) +/// +//////////////////////////////////////////////////////////// diff --git a/src/efsw/Utf.inl b/src/efsw/Utf.inl index ef71bc8..7e3e9d6 100644 --- a/src/efsw/Utf.inl +++ b/src/efsw/Utf.inl @@ -1,576 +1,576 @@ -// References : -// http://www.unicode.org/ -// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c -// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h -// http://people.w3.org/rishida/scripts/uniview/conversion -//////////////////////////////////////////////////////////// - -template In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { - // Some useful precomputed data - static const int trailing[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; - static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, - 0x03C82080, 0xFA082080, 0x82082080 }; - - // Decode the character - int trailingBytes = trailing[static_cast( *begin )]; - if ( begin + trailingBytes < end ) { - output = 0; - switch ( trailingBytes ) { - case 5: - output += static_cast( *begin++ ); - output <<= 6; - case 4: - output += static_cast( *begin++ ); - output <<= 6; - case 3: - output += static_cast( *begin++ ); - output <<= 6; - case 2: - output += static_cast( *begin++ ); - output <<= 6; - case 1: - output += static_cast( *begin++ ); - output <<= 6; - case 0: - output += static_cast( *begin++ ); - } - output -= offsets[trailingBytes]; - } else { - // Incomplete character - begin = end; - output = replacement; - } - - return begin; -} - -template Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { - // Some useful precomputed data - static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - // Encode the character - if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { - // Invalid character - if ( replacement ) - *output++ = replacement; - } else { - // Valid character - - // Get the number of bytes to write - int bytesToWrite = 1; - if ( input < 0x80 ) - bytesToWrite = 1; - else if ( input < 0x800 ) - bytesToWrite = 2; - else if ( input < 0x10000 ) - bytesToWrite = 3; - else if ( input <= 0x0010FFFF ) - bytesToWrite = 4; - - // Extract the bytes to write - Uint8 bytes[4]; - switch ( bytesToWrite ) { - case 4: - bytes[3] = static_cast( ( input | 0x80 ) & 0xBF ); - input >>= 6; - case 3: - bytes[2] = static_cast( ( input | 0x80 ) & 0xBF ); - input >>= 6; - case 2: - bytes[1] = static_cast( ( input | 0x80 ) & 0xBF ); - input >>= 6; - case 1: - bytes[0] = static_cast( input | firstBytes[bytesToWrite] ); - } - - // Add them to the output - const Uint8* currentByte = bytes; - switch ( bytesToWrite ) { - case 4: - *output++ = *currentByte++; - case 3: - *output++ = *currentByte++; - case 2: - *output++ = *currentByte++; - case 1: - *output++ = *currentByte++; - } - } - - return output; -} - -template In Utf<8>::Next( In begin, In end ) { - Uint32 codepoint; - return Decode( begin, end, codepoint ); -} - -template std::size_t Utf<8>::Count( In begin, In end ) { - std::size_t length = 0; - while ( begin < end ) { - begin = Next( begin, end ); - ++length; - } - - return length; -} - -template -Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<8>::FromWide( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<8>::FromLatin1( In begin, In end, Out output ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) - output = Encode( *begin++, output ); - - return output; -} - -template -Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); - } - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeWide( codepoint, output, replacement ); - } - - return output; -} -#endif - -template -Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - *output++ = codepoint < 256 ? static_cast( codepoint ) : replacement; - } - - return output; -} - -template Out Utf<8>::toUtf8( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template Out Utf<8>::ToUtf16( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<16>::Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<8>::ToUtf32( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - *output++ = codepoint; - } - - return output; -} - -template In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { - Uint16 first = *begin++; - - // If it's a surrogate pair, first convert to a single UTF-32 character - if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { - if ( begin < end ) { - Uint32 second = *begin++; - if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { - // The second element is valid: convert the two elements to a UTF-32 character - output = static_cast( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + - 0x0010000 ); - } else { - // Invalid character - output = replacement; - } - } else { - // Invalid character - begin = end; - output = replacement; - } - } else { - // We can make a direct copy - output = first; - } - - return begin; -} - -template Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { - if ( input < 0xFFFF ) { - // The character can be copied directly, we just need to check if it's in the valid range - if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { - // Invalid character (this range is reserved) - if ( replacement ) - *output++ = replacement; - } else { - // Valid character directly convertible to a single UTF-16 character - *output++ = static_cast( input ); - } - } else if ( input > 0x0010FFFF ) { - // Invalid character (greater than the maximum unicode value) - if ( replacement ) - *output++ = replacement; - } else { - // The input character will be converted to two UTF-16 elements - input -= 0x0010000; - *output++ = static_cast( ( input >> 10 ) + 0xD800 ); - *output++ = static_cast( ( input & 0x3FFUL ) + 0xDC00 ); - } - - return output; -} - -template In Utf<16>::Next( In begin, In end ) { - Uint32 codepoint; - return Decode( begin, end, codepoint ); -} - -template std::size_t Utf<16>::Count( In begin, In end ) { - std::size_t length = 0; - while ( begin < end ) { - begin = Next( begin, end ); - ++length; - } - - return length; -} - -template -Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<16>::FromWide( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); - output = Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<16>::FromLatin1( In begin, In end, Out output ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template -Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); - } - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<32>::EncodeWide( codepoint, output, replacement ); - } - - return output; -} -#endif - -template -Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) { - *output++ = *begin < 256 ? static_cast( *begin ) : replacement; - begin++; - } - - return output; -} - -template Out Utf<16>::toUtf8( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - output = Utf<8>::Encode( codepoint, output ); - } - - return output; -} - -template Out Utf<16>::ToUtf16( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template Out Utf<16>::ToUtf32( In begin, In end, Out output ) { - while ( begin < end ) { - Uint32 codepoint; - begin = Decode( begin, end, codepoint ); - *output++ = codepoint; - } - - return output; -} - -template In Utf<32>::Decode( In begin, In end, Uint32& output, Uint32 ) { - output = *begin++; - return begin; -} - -template Out Utf<32>::Encode( Uint32 input, Out output, Uint32 replacement ) { - *output++ = input; - return output; -} - -template In Utf<32>::Next( In begin, In end ) { - return ++begin; -} - -template std::size_t Utf<32>::Count( In begin, In end ) { - return begin - end; -} - -template -Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { - while ( begin < end ) - *output++ = DecodeAnsi( *begin++, locale ); - - return output; -} - -template Out Utf<32>::FromWide( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = DecodeWide( *begin++ ); - - return output; -} - -template Out Utf<32>::FromLatin1( In begin, In end, Out output ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template -Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { - while ( begin < end ) - output = EncodeAnsi( *begin++, output, replacement, locale ); - - return output; -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { - while ( begin < end ) - output = EncodeWide( *begin++, output, replacement ); - - return output; -} -#endif - -template -Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { - // Latin-1 is directly compatible with Unicode encodings, - // and can thus be treated as (a sub-range of) UTF-32 - while ( begin < end ) { - *output++ = *begin < 256 ? static_cast( *begin ) : replacement; - begin++; - } - - return output; -} - -template Out Utf<32>::toUtf8( In begin, In end, Out output ) { - while ( begin < end ) - output = Utf<8>::Encode( *begin++, output ); - - return output; -} - -template Out Utf<32>::ToUtf16( In begin, In end, Out output ) { - while ( begin < end ) - output = Utf<16>::Encode( *begin++, output ); - - return output; -} - -template Out Utf<32>::ToUtf32( In begin, In end, Out output ) { - while ( begin < end ) - *output++ = *begin++; - - return output; -} - -template Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { - // On Windows, gcc's standard library (glibc++) has almost - // no support for Unicode stuff. As a consequence, in this - // context we can only use the default locale and ignore - // the one passed as parameter. - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ - ( defined( __GLIBCPP__ ) || \ - defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ - !( defined( __SGI_STL_PORT ) || \ - defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ - - wchar_t character = 0; - mbtowc( &character, &input, 1 ); - return static_cast( character ); - -#else -// Get the facet of the locale which deals with character conversion -#ifndef EFSW_NO_WIDECHAR - const std::ctype& facet = std::use_facet>( locale ); -#else - const std::ctype& facet = std::use_facet>( locale ); -#endif - - // Use the facet to convert each character of the input string - return static_cast( facet.widen( input ) ); - -#endif -} - -template Uint32 Utf<32>::DecodeWide( In input ) { - // The encoding of wide characters is not well defined and is left to the system; - // however we can safely assume that it is UCS-2 on Windows and - // UCS-4 on Unix systems. - // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, - // and UCS-4 *is* UTF-32). - - return input; -} - -template -Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, - const std::locale& locale ) { - // On Windows, gcc's standard library (glibc++) has almost - // no support for Unicode stuff. As a consequence, in this - // context we can only use the default locale and ignore - // the one passed as parameter. - -#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ - ( defined( __GLIBCPP__ ) || \ - defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ - !( defined( __SGI_STL_PORT ) || \ - defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ - - char character = 0; - if ( wctomb( &character, static_cast( codepoint ) ) >= 0 ) - *output++ = character; - else if ( replacement ) - *output++ = replacement; - - return output; - -#else -// Get the facet of the locale which deals with character conversion -#ifndef EFSW_NO_WIDECHAR - const std::ctype& facet = std::use_facet>( locale ); -#else - const std::ctype& facet = std::use_facet>( locale ); -#endif - - // Use the facet to convert each character of the input string - *output++ = facet.narrow( static_cast( codepoint ), replacement ); - - return output; - -#endif -} - -#ifndef EFSW_NO_WIDECHAR -template -Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { - // The encoding of wide characters is not well defined and is left to the system; - // however we can safely assume that it is UCS-2 on Windows and - // UCS-4 on Unix systems. - // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). - // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). - - switch ( sizeof( wchar_t ) ) { - case 4: { - *output++ = static_cast( codepoint ); - break; - } - - default: { - if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { - *output++ = static_cast( codepoint ); - } else if ( replacement ) { - *output++ = replacement; - } - break; - } - } - - return output; -} -#endif +// References : +// http://www.unicode.org/ +// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c +// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h +// http://people.w3.org/rishida/scripts/uniview/conversion +//////////////////////////////////////////////////////////// + +template In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { + // Some useful precomputed data + static const int trailing[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; + static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, + 0x03C82080, 0xFA082080, 0x82082080 }; + + // Decode the character + int trailingBytes = trailing[static_cast( *begin )]; + if ( begin + trailingBytes < end ) { + output = 0; + switch ( trailingBytes ) { + case 5: + output += static_cast( *begin++ ); + output <<= 6; + case 4: + output += static_cast( *begin++ ); + output <<= 6; + case 3: + output += static_cast( *begin++ ); + output <<= 6; + case 2: + output += static_cast( *begin++ ); + output <<= 6; + case 1: + output += static_cast( *begin++ ); + output <<= 6; + case 0: + output += static_cast( *begin++ ); + } + output -= offsets[trailingBytes]; + } else { + // Incomplete character + begin = end; + output = replacement; + } + + return begin; +} + +template Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { + // Some useful precomputed data + static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + // Encode the character + if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { + // Invalid character + if ( replacement ) + *output++ = replacement; + } else { + // Valid character + + // Get the number of bytes to write + int bytesToWrite = 1; + if ( input < 0x80 ) + bytesToWrite = 1; + else if ( input < 0x800 ) + bytesToWrite = 2; + else if ( input < 0x10000 ) + bytesToWrite = 3; + else if ( input <= 0x0010FFFF ) + bytesToWrite = 4; + + // Extract the bytes to write + Uint8 bytes[4]; + switch ( bytesToWrite ) { + case 4: + bytes[3] = static_cast( ( input | 0x80 ) & 0xBF ); + input >>= 6; + case 3: + bytes[2] = static_cast( ( input | 0x80 ) & 0xBF ); + input >>= 6; + case 2: + bytes[1] = static_cast( ( input | 0x80 ) & 0xBF ); + input >>= 6; + case 1: + bytes[0] = static_cast( input | firstBytes[bytesToWrite] ); + } + + // Add them to the output + const Uint8* currentByte = bytes; + switch ( bytesToWrite ) { + case 4: + *output++ = *currentByte++; + case 3: + *output++ = *currentByte++; + case 2: + *output++ = *currentByte++; + case 1: + *output++ = *currentByte++; + } + } + + return output; +} + +template In Utf<8>::Next( In begin, In end ) { + Uint32 codepoint; + return Decode( begin, end, codepoint ); +} + +template std::size_t Utf<8>::Count( In begin, In end ) { + std::size_t length = 0; + while ( begin < end ) { + begin = Next( begin, end ); + ++length; + } + + return length; +} + +template +Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { + while ( begin < end ) { + Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); + output = Encode( codepoint, output ); + } + + return output; +} + +template Out Utf<8>::FromWide( In begin, In end, Out output ) { + while ( begin < end ) { + Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); + output = Encode( codepoint, output ); + } + + return output; +} + +template Out Utf<8>::FromLatin1( In begin, In end, Out output ) { + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while ( begin < end ) + output = Encode( *begin++, output ); + + return output; +} + +template +Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); + } + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +template +Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + output = Utf<32>::EncodeWide( codepoint, output, replacement ); + } + + return output; +} +#endif + +template +Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + *output++ = codepoint < 256 ? static_cast( codepoint ) : replacement; + } + + return output; +} + +template Out Utf<8>::toUtf8( In begin, In end, Out output ) { + while ( begin < end ) + *output++ = *begin++; + + return output; +} + +template Out Utf<8>::ToUtf16( In begin, In end, Out output ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + output = Utf<16>::Encode( codepoint, output ); + } + + return output; +} + +template Out Utf<8>::ToUtf32( In begin, In end, Out output ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + *output++ = codepoint; + } + + return output; +} + +template In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { + Uint16 first = *begin++; + + // If it's a surrogate pair, first convert to a single UTF-32 character + if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { + if ( begin < end ) { + Uint32 second = *begin++; + if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { + // The second element is valid: convert the two elements to a UTF-32 character + output = static_cast( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + + 0x0010000 ); + } else { + // Invalid character + output = replacement; + } + } else { + // Invalid character + begin = end; + output = replacement; + } + } else { + // We can make a direct copy + output = first; + } + + return begin; +} + +template Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { + if ( input < 0xFFFF ) { + // The character can be copied directly, we just need to check if it's in the valid range + if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { + // Invalid character (this range is reserved) + if ( replacement ) + *output++ = replacement; + } else { + // Valid character directly convertible to a single UTF-16 character + *output++ = static_cast( input ); + } + } else if ( input > 0x0010FFFF ) { + // Invalid character (greater than the maximum unicode value) + if ( replacement ) + *output++ = replacement; + } else { + // The input character will be converted to two UTF-16 elements + input -= 0x0010000; + *output++ = static_cast( ( input >> 10 ) + 0xD800 ); + *output++ = static_cast( ( input & 0x3FFUL ) + 0xDC00 ); + } + + return output; +} + +template In Utf<16>::Next( In begin, In end ) { + Uint32 codepoint; + return Decode( begin, end, codepoint ); +} + +template std::size_t Utf<16>::Count( In begin, In end ) { + std::size_t length = 0; + while ( begin < end ) { + begin = Next( begin, end ); + ++length; + } + + return length; +} + +template +Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { + while ( begin < end ) { + Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); + output = Encode( codepoint, output ); + } + + return output; +} + +template Out Utf<16>::FromWide( In begin, In end, Out output ) { + while ( begin < end ) { + Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); + output = Encode( codepoint, output ); + } + + return output; +} + +template Out Utf<16>::FromLatin1( In begin, In end, Out output ) { + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while ( begin < end ) + *output++ = *begin++; + + return output; +} + +template +Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); + } + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +template +Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + output = Utf<32>::EncodeWide( codepoint, output, replacement ); + } + + return output; +} +#endif + +template +Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while ( begin < end ) { + *output++ = *begin < 256 ? static_cast( *begin ) : replacement; + begin++; + } + + return output; +} + +template Out Utf<16>::toUtf8( In begin, In end, Out output ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + output = Utf<8>::Encode( codepoint, output ); + } + + return output; +} + +template Out Utf<16>::ToUtf16( In begin, In end, Out output ) { + while ( begin < end ) + *output++ = *begin++; + + return output; +} + +template Out Utf<16>::ToUtf32( In begin, In end, Out output ) { + while ( begin < end ) { + Uint32 codepoint; + begin = Decode( begin, end, codepoint ); + *output++ = codepoint; + } + + return output; +} + +template In Utf<32>::Decode( In begin, In end, Uint32& output, Uint32 ) { + output = *begin++; + return begin; +} + +template Out Utf<32>::Encode( Uint32 input, Out output, Uint32 replacement ) { + *output++ = input; + return output; +} + +template In Utf<32>::Next( In begin, In end ) { + return ++begin; +} + +template std::size_t Utf<32>::Count( In begin, In end ) { + return begin - end; +} + +template +Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { + while ( begin < end ) + *output++ = DecodeAnsi( *begin++, locale ); + + return output; +} + +template Out Utf<32>::FromWide( In begin, In end, Out output ) { + while ( begin < end ) + *output++ = DecodeWide( *begin++ ); + + return output; +} + +template Out Utf<32>::FromLatin1( In begin, In end, Out output ) { + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while ( begin < end ) + *output++ = *begin++; + + return output; +} + +template +Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { + while ( begin < end ) + output = EncodeAnsi( *begin++, output, replacement, locale ); + + return output; +} + +#ifndef EFSW_NO_WIDECHAR +template +Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { + while ( begin < end ) + output = EncodeWide( *begin++, output, replacement ); + + return output; +} +#endif + +template +Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { + // Latin-1 is directly compatible with Unicode encodings, + // and can thus be treated as (a sub-range of) UTF-32 + while ( begin < end ) { + *output++ = *begin < 256 ? static_cast( *begin ) : replacement; + begin++; + } + + return output; +} + +template Out Utf<32>::toUtf8( In begin, In end, Out output ) { + while ( begin < end ) + output = Utf<8>::Encode( *begin++, output ); + + return output; +} + +template Out Utf<32>::ToUtf16( In begin, In end, Out output ) { + while ( begin < end ) + output = Utf<16>::Encode( *begin++, output ); + + return output; +} + +template Out Utf<32>::ToUtf32( In begin, In end, Out output ) { + while ( begin < end ) + *output++ = *begin++; + + return output; +} + +template Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { + // On Windows, gcc's standard library (glibc++) has almost + // no support for Unicode stuff. As a consequence, in this + // context we can only use the default locale and ignore + // the one passed as parameter. + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ + ( defined( __GLIBCPP__ ) || \ + defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ + !( defined( __SGI_STL_PORT ) || \ + defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ + + wchar_t character = 0; + mbtowc( &character, &input, 1 ); + return static_cast( character ); + +#else +// Get the facet of the locale which deals with character conversion +#ifndef EFSW_NO_WIDECHAR + const std::ctype& facet = std::use_facet>( locale ); +#else + const std::ctype& facet = std::use_facet>( locale ); +#endif + + // Use the facet to convert each character of the input string + return static_cast( facet.widen( input ) ); + +#endif +} + +template Uint32 Utf<32>::DecodeWide( In input ) { + // The encoding of wide characters is not well defined and is left to the system; + // however we can safely assume that it is UCS-2 on Windows and + // UCS-4 on Unix systems. + // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, + // and UCS-4 *is* UTF-32). + + return input; +} + +template +Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, + const std::locale& locale ) { + // On Windows, gcc's standard library (glibc++) has almost + // no support for Unicode stuff. As a consequence, in this + // context we can only use the default locale and ignore + // the one passed as parameter. + +#if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ + ( defined( __GLIBCPP__ ) || \ + defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ + !( defined( __SGI_STL_PORT ) || \ + defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ + + char character = 0; + if ( wctomb( &character, static_cast( codepoint ) ) >= 0 ) + *output++ = character; + else if ( replacement ) + *output++ = replacement; + + return output; + +#else +// Get the facet of the locale which deals with character conversion +#ifndef EFSW_NO_WIDECHAR + const std::ctype& facet = std::use_facet>( locale ); +#else + const std::ctype& facet = std::use_facet>( locale ); +#endif + + // Use the facet to convert each character of the input string + *output++ = facet.narrow( static_cast( codepoint ), replacement ); + + return output; + +#endif +} + +#ifndef EFSW_NO_WIDECHAR +template +Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { + // The encoding of wide characters is not well defined and is left to the system; + // however we can safely assume that it is UCS-2 on Windows and + // UCS-4 on Unix systems. + // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). + // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). + + switch ( sizeof( wchar_t ) ) { + case 4: { + *output++ = static_cast( codepoint ); + break; + } + + default: { + if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { + *output++ = static_cast( codepoint ); + } else if ( replacement ) { + *output++ = replacement; + } + break; + } + } + + return output; +} +#endif diff --git a/src/efsw/sophist.h b/src/efsw/sophist.h index 82e5c36..3a64504 100644 --- a/src/efsw/sophist.h +++ b/src/efsw/sophist.h @@ -1,147 +1,147 @@ -/* 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__ */ +/* sophist.h - 0.3 - public domain - Sean Barrett 2010 +** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net +** Sophist provides portable types; you typedef/#define them to your own names +** +** defines: +** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian +** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined +** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit +** +** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer +** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 +** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 +** - SOPHIST_int64_constant(number) - macros for creating 64-bit +** - SOPHIST_uint64_constant(number) integer constants +** - SOPHIST_printf_format64 - string for printf format for int64 +*/ + +#ifndef __INCLUDE_SOPHIST_H__ +#define __INCLUDE_SOPHIST_H__ + +#define SOPHIST_compiletime_assert(name,val) \ + typedef int SOPHIST__assert##name[(val) ? 1 : -1] + +/* define a couple synthetic rules to make code more readable */ +#if (defined(__sparc__) || defined(__sparc)) && \ + (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) + #define SOPHIST_sparc64 +#endif + +#if (defined(linux) || defined(__linux__)) && \ + (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) + #define SOPHIST_linux64 +#endif + +/* basic types */ +typedef signed char SOPHIST_int8; +typedef unsigned char SOPHIST_uint8; + +typedef signed short SOPHIST_int16; +typedef unsigned short SOPHIST_uint16; + +#ifdef __palmos__ + typedef signed long SOPHIST_int32; + typedef unsigned long SOPHIST_uint32; +#else + typedef signed int SOPHIST_int32; + typedef unsigned int SOPHIST_uint32; +#endif + +#ifndef SOPHIST_NO_64 + #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ + || (defined(__alpha) && defined(__DECC)) + + typedef signed __int64 SOPHIST_int64; + typedef unsigned __int64 SOPHIST_uint64; + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) (x##i64) + #define SOPHIST_uint64_constant(x) (x##ui64) + #define SOPHIST_printf_format64 "I64" + + #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) + + typedef signed long SOPHIST_int64; + typedef unsigned long SOPHIST_uint64; + + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) + #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) + #define SOPHIST_printf_format64 "l" + + #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ + || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ + || defined(sgi) || defined (__sgi) || defined(__sgi__) \ + || defined(_CRAYC) + + typedef signed long long SOPHIST_int64; + typedef unsigned long long SOPHIST_uint64; + + #define SOPHIST_has_64 1 + #define SOPHIST_int64_constant(x) (x##LL) + #define SOPHIST_uint64_constant(x) (x##ULL) + #define SOPHIST_printf_format64 "ll" + #endif +#endif + +#ifndef SOPHIST_has_64 +#define SOPHIST_has_64 0 +#endif + +SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); +SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); +SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); +SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); + +#if SOPHIST_has_64 + SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); + SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); +#endif + +/* determine whether pointers are 64-bit */ + +#if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ + || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ + || defined(__64BIT__) \ + || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ + || defined(_ADDR64) || defined(_CRAYC) \ + + #define SOPHIST_pointer64 1 + + SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); + + typedef SOPHIST_int64 SOPHIST_intptr; + typedef SOPHIST_uint64 SOPHIST_uintptr; +#else + + #define SOPHIST_pointer64 0 + + SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); + + /* do we care about pointers that are only 16-bit? */ + typedef SOPHIST_int32 SOPHIST_intptr; + typedef SOPHIST_uint32 SOPHIST_uintptr; + +#endif + +SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); + +/* enumerate known little endian cases; fallback to big-endian */ + +#define SOPHIST_little_endian 1 +#define SOPHIST_big_endian 2 + +#if defined(__386__) || defined(i386) || defined(__i386__) \ + || defined(__X86) || defined(_M_IX86) \ + || defined(_M_X64) || defined(__x86_64__) \ + || defined(alpha) || defined(__alpha) || defined(__alpha__) \ + || defined(_M_ALPHA) \ + || defined(ARM) || defined(_ARM) || defined(__arm__) \ + || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ + || defined(_WIN32_WCE) || defined(__NT__) \ + || defined(__MIPSEL__) + #define SOPHIST_endian SOPHIST_little_endian +#else + #define SOPHIST_endian SOPHIST_big_endian +#endif + +#endif /* __INCLUDE_SOPHIST_H__ */ diff --git a/src/joomer-efsw-file-monitoring.cpp b/src/joomer-efsw-file-monitoring.cpp index 88a58ca..d724563 100644 --- a/src/joomer-efsw-file-monitoring.cpp +++ b/src/joomer-efsw-file-monitoring.cpp @@ -156,18 +156,7 @@ int main( int argc, char** argv ) { /// add a watch to the system handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) ); - - /// adds another watch after started watching... - /*efsw::System::sleep( 100 ); - - efsw::WatchID watchID = - handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) ); - - /// delete the watch - if ( watchID > 0 ) { - efsw::System::sleep( 1000 ); - fileWatcher.removeWatch( watchID ); - }*/ + } else { if ( fileWatcher.addWatch( path, ul, true ) > 0 ) { fileWatcher.watch(); diff --git a/src/test/joomer-efsw-file-monitoring.cpp b/src/test/joomer-efsw-file-monitoring.cpp new file mode 100644 index 0000000..bf1fc64 --- /dev/null +++ b/src/test/joomer-efsw-file-monitoring.cpp @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include + +bool STOP = false; + +void sigend( int ) { + std::cout << std::endl << "Bye bye" << std::endl; + STOP = true; +} + +/// Processes a file action +class UpdateListener : public efsw::FileWatchListener { + public: + UpdateListener() {} + + std::string getActionName( efsw::Action action ) { + switch ( action ) { + case efsw::Actions::Add: + return "Add"; + case efsw::Actions::Modified: + return "Modified"; + case efsw::Actions::Delete: + return "Delete"; + case efsw::Actions::Moved: + return "Moved"; + default: + return "Bad Action"; + } + } + + void handleFileAction( efsw::WatchID watchid, const std::string& dir, + const std::string& filename, efsw::Action action, + std::string oldFilename = "" ) override { + std::cout << "Watch ID " << watchid << " DIR (" + << dir + ") FILE (" + + ( oldFilename.empty() ? "" : "from file " + oldFilename + " to " ) + + filename + ") has event " + << getActionName( action ) << std::endl; + } +}; + +efsw::WatchID handleWatchID( efsw::WatchID watchid ) { + switch ( watchid ) { + case efsw::Errors::FileNotFound: + case efsw::Errors::FileRepeated: + case efsw::Errors::FileOutOfScope: + case efsw::Errors::FileRemote: + case efsw::Errors::WatcherFailed: + case efsw::Errors::Unspecified: { + std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; + break; + } + default: { + std::cout << "Added WatchID: " << watchid << std::endl; + } + } + + return watchid; +} + +int main( int argc, char** argv ) { + signal( SIGABRT, sigend ); + signal( SIGINT, sigend ); + signal( SIGTERM, sigend ); + + std::cout << "Press ^C to exit demo" << std::endl; + + bool commonTest = true; + bool useGeneric = false; + std::string path; + + if ( argc >= 2 ) { + path = std::string( argv[1] ); + + if ( efsw::FileSystem::isDirectory( path ) ) { + commonTest = false; + } + + if ( argc >= 3 ) { + if ( std::string( argv[2] ) == "true" ) { + useGeneric = true; + } + } + } + + UpdateListener* ul = new UpdateListener(); + + /// create the file watcher object + efsw::FileWatcher fileWatcher( useGeneric ); + + fileWatcher.followSymlinks( false ); + fileWatcher.allowOutOfScopeLinks( false ); + + if ( commonTest ) { + std::string CurPath( efsw::System::getProcessPath() ); + + std::cout << "CurPath: " << CurPath.c_str() << std::endl; + + /// starts watching + fileWatcher.watch(); + + /// add a watch to the system + handleWatchID( fileWatcher.addWatch( CurPath + "test", ul, true ) ); + + /// adds another watch after started watching... + efsw::System::sleep( 100 ); + + efsw::WatchID watchID = + handleWatchID( fileWatcher.addWatch( CurPath + "test2", ul, true ) ); + + /// delete the watch + if ( watchID > 0 ) { + efsw::System::sleep( 1000 ); + fileWatcher.removeWatch( watchID ); + } + } else { + if ( fileWatcher.addWatch( path, ul, true ) > 0 ) { + fileWatcher.watch(); + + std::cout << "Watching directory: " << path.c_str() << std::endl; + + if ( useGeneric ) { + std::cout << "Using generic backend watcher" << std::endl; + } + } else { + std::cout << "Error trying to watch directory: " << path.c_str() << std::endl; + std::cout << efsw::Errors::Log::getLastErrorLog().c_str() << std::endl; + } + } + + while ( !STOP ) { + efsw::System::sleep( 100 ); + } + + return 0; +}