diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 0ae0e90d..7a7526af 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -12,11 +12,10 @@ env: jobs: build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest] steps: - uses: actions/checkout@v2 @@ -35,3 +34,55 @@ jobs: # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} + + build_windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + + - name: Cache vcpkg + uses: actions/cache@v2 + env: + cache-name: cache-vcpkg-d8b9ae5 + with: + path: ${{ github.workspace }}/vcpkg + key: ${{ runner.os }}-vcpkg-${{ env.cache-name }} + restore-keys: ${{ runner.os }}-vcpkg-${{ env.cache-name }} + + - name: clone and bootstrap vcpkg + run: | + IF NOT EXIST "vcpkg" ( + git clone --depth=360 https://github.com/microsoft/vcpkg + cd "vcpkg" + git reset --hard d8b9ae5 + .\bootstrap-vcpkg.bat + ) + shell: cmd + + - name: Install dependencies with vcpkg + run: | + cd "%GITHUB_WORKSPACE%\vcpkg" + IF NOT EXIST "buildtrees\pthreads" ( + .\vcpkg --version + .\vcpkg install --triplet "%RUNNER_ARCH%-%RUNNER_OS%" pthreads gettext + ) + shell: cmd + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: | + cmake -B "%GITHUB_WORKSPACE%\build" -DCMAKE_BUILD_TYPE="%BUILD_TYPE%" -DVCPKG_TARGET_TRIPLET="%RUNNER_ARCH%-%RUNNER_OS%" -DCMAKE_TOOLCHAIN_FILE="vcpkg\scripts\buildsystems\vcpkg.cmake" + shell: cmd + + - name: Build + # Build your program with the given configuration + run: cmake --build "%GITHUB_WORKSPACE%\build" --config "%BUILD_TYPE%" + shell: cmd + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C "%BUILD_TYPE%" + shell: cmd diff --git a/.gitignore b/.gitignore index 31f93245..9df993c7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ fswatch_test .libs *.lo *.o -cmake-build-debug/ +*build*/ dist/ # Documentation @@ -134,3 +134,4 @@ docker/debian-testing/Dockerfile # Output files man/fswatch.7 +*_export.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 80fd9041..29a7e60e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,13 +14,13 @@ # this program. If not, see . # cmake_minimum_required(VERSION 3.8) -project(fswatch VERSION 1.16.0 LANGUAGES C CXX) +project(fs_watch VERSION 1.17.0 LANGUAGES C CXX) #@formatter:off -set(PACKAGE "${PROJECT_NAME}") +set(PACKAGE "fswatch") set(PACKAGE_NAME "${PACKAGE}") set(PACKAGE_VERSION "${PROJECT_VERSION}-develop") -set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") +set(PACKAGE_STRING "${PACKAGE} ${PACKAGE_VERSION}") set(PACKAGE_AUTHOR "enrico.m.crisostomo@gmail.com") set(PACKAGE_BUGREPORT "${PACKAGE_AUTHOR}") set(PACKAGE_TARNAME "${PACKAGE}") @@ -29,9 +29,18 @@ set(LOCALEDIR "${CMAKE_INSTALL_PREFIX}/share/locale" CACHE FILEPATH "loc #@formatter:on set(CMAKE_CXX_STANDARD 11) +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") +endif (MSVC) + +# control where the static and shared libraries are built so that on windows +# we don't need to tinker with the path to run the executable +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") # Add option to choose between shared and static libraries -option(BUILD_SHARED_LIBS "Build shared libraries" OFF) +option(BUILD_SHARED_LIBS "Build shared libraries" ON) # include modules include(FindGettext) @@ -44,7 +53,10 @@ include(CheckCXXSymbolExists) check_include_file_cxx(getopt.h HAVE_GETOPT_H) if (HAVE_GETOPT_H) - check_cxx_symbol_exists(getopt_long getopt.h HAVE_GETOPT_LONG) + check_cxx_symbol_exists(getopt_long "getopt.h" HAVE_GETOPT_LONG) +else () + set(HAVE_GETOPT_H 1) + set(HAVE_GETOPT_LONG 1) endif (HAVE_GETOPT_H) # If both gettext and libintl are found, define the USE_NLS variable to @@ -60,17 +72,24 @@ if (USE_NLS) set(LINGUAS en en@quot en@boldquot it es) foreach (language ${LINGUAS}) - configure_file(${PROJECT_SOURCE_DIR}/po/${language}.po ${PROJECT_BINARY_DIR}/${language}.po COPYONLY) + configure_file("${PROJECT_SOURCE_DIR}/po/${language}.po" "${PROJECT_BINARY_DIR}/${language}.po" COPYONLY) endforeach () - gettext_process_pot_file(po/${PACKAGE}.pot ALL INSTALL_DESTINATION share/locale LANGUAGES ${LINGUAS}) -endif () + gettext_process_pot_file("po/${PACKAGE}.pot" ALL INSTALL_DESTINATION "${LOCALEDIR}" LANGUAGES ${LINGUAS}) +endif (USE_NLS) # checks check_cxx_symbol_exists(atexit cstdlib HAVE_ATEXIT) check_cxx_symbol_exists(setlocale clocale HAVE_SETLOCALE) check_cxx_symbol_exists(strtod cstdlib HAVE_STRTOD) -add_subdirectory(libfswatch) -add_subdirectory(fswatch/src) -add_subdirectory(test/src) +option(BUILD_FSWATCH "Build ${PROJECT_NAME}" ON) +option(BUILD_TESTS "Build ${PROJECT_NAME} tests" ON) + +add_subdirectory("libfswatch") +if (BUILD_FSWATCH) + add_subdirectory("fswatch/src") +endif (BUILD_FSWATCH) +if (BUILD_TESTS) + add_subdirectory("test/src") +endif (BUILD_TESTS) diff --git a/README.windows b/README.windows index 4877073b..c9664a42 100644 --- a/README.windows +++ b/README.windows @@ -6,8 +6,9 @@ Introduction This file describes the steps required to build fswatch on Windows. fswatch was born as a POSIX application and the Windows monitor has been developed trying to -reduce the dependencies on the Windows API at a minimum. To fulfill this goal, -a dependency to Cygwin has been introduced. +reduce the dependencies on the Windows API at a minimum. + +There are two variants to fulfill this goal: Cygwin and Microsoft Visual Studio. Windows has historically provided multiple versions of the same API for single byte and multibyte character sets. We have decided to only support the @@ -15,6 +16,37 @@ multibyte API: the Windows monitor will thus not build on Windows system supporting only the single-byte APIs. In this case, the only available monitor on the Windows OS will be the poll monitor. +Microsoft Visual Studio (MSVC) +============================== + +The MSVC variant is configured through CMake and is fully native on Windows. + +The three dependencies to get it working are: + + 0. CMake: https://cmake.org + 1. pthreads: https://sourceforge.net/projects/pthreads4w + 2. gettext: https://mlocati.github.io/articles/gettext-iconv-windows.html + +The pthreads and gettext dependencies are most easily acquirable through use +of a package manager, like Microsoft's open-source cross-platform vcpkg + + git clone --depth=1 "https://github.com/microsoft/vcpkg" + cd "vcpkg" + :: Replace "[dir]" in later command with this dir + .\bootstrap-vcpkg.bat + .\vcpkg install --triplet "x64-windows" "pthreads" "gettext" + +Then the project can be configured and compiled & built with: + + cd + cmake -B "build" \ + -DCMAKE_BUILD_TYPE="Debug" \ + -DVCPKG_TARGET_TRIPLET="x64-windows" \ + -DCMAKE_TOOLCHAIN_FILE="[dir]\vcpkg\scripts\buildsystems\vcpkg.cmake" + cmake --build "build" --config "Debug" + +[everything that follows is only applicable to Cygwin] + Cygwin ====== diff --git a/cmake/FindPthreads.cmake b/cmake/FindPthreads.cmake new file mode 100644 index 00000000..b471ded9 --- /dev/null +++ b/cmake/FindPthreads.cmake @@ -0,0 +1,99 @@ +# From: https://github.com/healpy/cfitsio/blob/d02e7ce/FindPthreads.cmake +# - Find the Pthreads library +# This module searches for the Pthreads library (including the +# pthreads-win32 port). +# +# This module defines these variables: +# +# PTHREADS_FOUND +# True if the Pthreads library was found +# PTHREADS_LIBRARY +# The location of the Pthreads library +# PTHREADS_INCLUDE_DIR +# The include path of the Pthreads library +# PTHREADS_DEFINITIONS +# Preprocessor definitions to define +# +# This module responds to the PTHREADS_EXCEPTION_SCHEME +# variable on Win32 to allow the user to control the +# library linked against. The Pthreads-win32 port +# provides the ability to link against a version of the +# library with exception handling. IT IS NOT RECOMMENDED +# THAT YOU USE THIS because most POSIX thread implementations +# do not support stack unwinding. +# +# PTHREADS_EXCEPTION_SCHEME +# C = no exceptions (default) +# (NOTE: This is the default scheme on most POSIX thread +# implementations and what you should probably be using) +# CE = C++ Exception Handling +# SE = Structure Exception Handling (MSVC only) +# + +# +# Define a default exception scheme to link against +# and validate user choice. +# +IF(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) + # Assign default if needed + SET(PTHREADS_EXCEPTION_SCHEME "C") +ELSE(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) + # Validate + IF(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + + MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed") + + ENDIF(NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "C" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "CE" AND + NOT PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + + IF(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC") + ENDIF(NOT MSVC AND PTHREADS_EXCEPTION_SCHEME STREQUAL "SE") + +ENDIF(NOT DEFINED PTHREADS_EXCEPTION_SCHEME) + +# +# Find the header file +# +FIND_PATH(PTHREADS_INCLUDE_DIR pthread.h) + +# +# Find the library +# +SET(names) +IF(MSVC) + SET(names + pthreadV${PTHREADS_EXCEPTION_SCHEME}2 + pthread + ) +ELSEIF(MINGW) + SET(names + pthreadG${PTHREADS_EXCEPTION_SCHEME}2 + pthread + ) +ELSE(MSVC) # Unix / Cygwin / Apple + SET(names pthread) +ENDIF(MSVC) + +FIND_LIBRARY(PTHREADS_LIBRARY ${names} + DOC "The Portable Threads Library") + +IF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) + SET(PTHREADS_FOUND true) + SET(PTHREADS_DEFINITIONS -DHAVE_PTHREAD_H) + SET(PTHREADS_INCLUDE_DIRS ${PTHREADS_INCLUDE_DIR}) + SET(PTHREADS_LIBRARIES ${PTHREADS_LIBRARY}) +ENDIF(PTHREADS_INCLUDE_DIR AND PTHREADS_LIBRARY) + +IF(PTHREADS_FOUND) + IF(NOT PTHREADS_FIND_QUIETLY) + MESSAGE(STATUS "Found Pthreads: ${PTHREADS_LIBRARY}") + ENDIF(NOT PTHREADS_FIND_QUIETLY) +ELSE(PTHREADS_FOUND) + IF(PTHREADS_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find the Pthreads Library") + ENDIF(PTHREADS_FIND_REQUIRED) +ENDIF(PTHREADS_FOUND) diff --git a/fswatch/src/CMakeLists.txt b/fswatch/src/CMakeLists.txt index 73550ff9..2771cf9b 100644 --- a/fswatch/src/CMakeLists.txt +++ b/fswatch/src/CMakeLists.txt @@ -13,22 +13,41 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . # -set(FSWATCH_SRC_FILES - fswatch.cpp - fswatch.hpp - gettext.h) +set(EXEC_NAME "fswatch_bin") +set(Header_Files "${PACKAGE}.hpp" "gettext.h") +source_group("${PACKAGE} Header Files" FILES "${Header_Files}") -add_executable(fswatch ${FSWATCH_SRC_FILES}) +set(Source_Files "${PACKAGE}.cpp") +source_group("${PACKAGE} Source Files" FILES "${Source_Files}") -# check for gettext and libintl -if (USE_NLS) - if (Intl_LIBRARIES) - target_link_libraries(fswatch PRIVATE ${Intl_LIBRARIES}) - endif () -endif () +add_executable("${EXEC_NAME}" "${Header_Files}" "${Source_Files}") + +set_target_properties( + "${EXEC_NAME}" + PROPERTIES + LINKER_LANGUAGE + CXX +) + +if (MSVC) + add_subdirectory("./windows") + target_link_libraries("${EXEC_NAME}" PRIVATE "getopt") +endif (MSVC) -target_include_directories(fswatch PUBLIC ../.. .) -target_include_directories(fswatch PRIVATE ${PROJECT_BINARY_DIR}) -target_link_libraries(fswatch PUBLIC libfswatch) +target_link_libraries("${EXEC_NAME}" PUBLIC "libfswatch") -install(TARGETS fswatch DESTINATION bin) +if (DEFINED VCPKG_LIBRARY_LINKAGE) + if (VCPKG_LIBRARY_LINKAGE STREQUAL "static") + set(BUILD_IS_STATIC "ON") + endif (VCPKG_LIBRARY_LINKAGE STREQUAL "static") +elseif (BUILD_SHARED_LIBS) + set(BUILD_IS_STATIC "OFF") +endif () + +if (BUILD_IS_STATIC STREQUAL "ON") + set(bin_install_dir "${CURRENT_PACKAGES_DIR}") +else () + install(FILES ${Header_Files} DESTINATION "include") + set(bin_install_dir "bin") +endif () +install(TARGETS "${EXEC_NAME}" DESTINATION "${bin_install_dir}") diff --git a/fswatch/src/fswatch.cpp b/fswatch/src/fswatch.cpp index ef962a78..3572bcc6 100644 --- a/fswatch/src/fswatch.cpp +++ b/fswatch/src/fswatch.cpp @@ -27,14 +27,14 @@ #include #include #include -#include "libfswatch/c++/path_utils.hpp" -#include "libfswatch/c++/event.hpp" -#include "libfswatch/c++/monitor.hpp" -#include "libfswatch/c++/monitor_factory.hpp" -#include "libfswatch/c/error.h" -#include "libfswatch/c/libfswatch.h" -#include "libfswatch/c/libfswatch_log.h" -#include "libfswatch/c++/libfswatch_exception.hpp" +#include "path_utils.hpp" +#include "event.hpp" +#include "monitor.hpp" +#include "monitor_factory.hpp" +#include "fsw_error.h" +#include "libfswatch.h" +#include "libfswatch_log.h" +#include "libfswatch_exception.hpp" #ifdef HAVE_GETOPT_LONG # include @@ -257,6 +257,7 @@ static bool parse_event_bitmask(const char *optarg) } catch (const std::invalid_argument& ex) { + fputs(ex.what(), stderr); return false; } } @@ -296,12 +297,20 @@ static bool validate_latency(double latency, const char *optarg) static void register_signal_handlers() { +#ifndef _MSC_VER struct sigaction action{}; action.sa_handler = close_handler; sigemptyset(&action.sa_mask); action.sa_flags = 0; +#endif - if (sigaction(SIGTERM, &action, nullptr) == 0) + if ( +#ifdef _MSC_VER + signal(SIGTERM, &close_handler) != SIG_ERR +#else + sigaction(SIGTERM, &action, nullptr) == 0 +#endif + ) { FSW_ELOG(_("SIGTERM handler registered.\n")); } @@ -310,7 +319,13 @@ static void register_signal_handlers() std::cerr << _("SIGTERM handler registration failed.") << std::endl; } - if (sigaction(SIGABRT, &action, nullptr) == 0) + if ( +#ifdef _MSC_VER + signal(SIGABRT, &close_handler) != SIG_ERR +#else + sigaction(SIGABRT, &action, nullptr) == 0 +#endif + ) { FSW_ELOG(_("SIGABRT handler registered.\n")); } @@ -319,7 +334,13 @@ static void register_signal_handlers() std::cerr << _("SIGABRT handler registration failed.") << std::endl; } - if (sigaction(SIGINT, &action, nullptr) == 0) + if ( +#ifdef _MSC_VER + signal(SIGINT, &close_handler) != SIG_ERR +#else + sigaction(SIGINT, &action, nullptr) == 0 +#endif + ) { FSW_ELOG(_("SIGINT handler registered.\n")); } @@ -339,9 +360,21 @@ static void print_event_timestamp(const event& evt) const time_t& evt_time = evt.get_time(); std::array time_format_buffer{}; - const struct tm *tm_time = uflag ? gmtime(&evt_time) : localtime(&evt_time); - std::string date = +#if defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ || defined(_MSC_VER) + struct tm* tm_time; + struct tm tm_buf; +#endif +#if defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ || defined(_MSC_VER) + if (uflag) + gmtime_s(&tm_buf, &evt_time); + else localtime_s(&tm_buf, &evt_time); + tm_time = &tm_buf; +#else + const struct tm* tm_time = (uflag? gmtime : localtime)(&evt_time); +#endif + + const std::string date = strftime(time_format_buffer.data(), time_format_buffer.size(), tformat.c_str(), diff --git a/fswatch/src/windows/CMakeLists.txt b/fswatch/src/windows/CMakeLists.txt new file mode 100644 index 00000000..9e4a367f --- /dev/null +++ b/fswatch/src/windows/CMakeLists.txt @@ -0,0 +1,42 @@ +set(LIBRARY_NAME "getopt") + +set(Header_Files "${LIBRARY_NAME}.h") +source_group("${LIBRARY_NAME} Header Files" FILES "${Header_Files}") + +set(Source_Files "${LIBRARY_NAME}.c") +source_group("${LIBRARY_NAME} Source Files" FILES "${Source_Files}") + +add_library("${LIBRARY_NAME}" STATIC "${Header_Files}" "${Source_Files}") +target_include_directories( + "${LIBRARY_NAME}" + PUBLIC + "$" + "$" + "$" + "$" +) +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + C +) + +include(GenerateExportHeader) +set(_export_file "${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}_export.h") +generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") + +# setup the version numbering +set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") +set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") + +# install rules +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif () +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES ${Header_Files} "${_export_file}" DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/libfswatch") diff --git a/fswatch/src/windows/getopt.c b/fswatch/src/windows/getopt.c new file mode 100644 index 00000000..f0ff4e66 --- /dev/null +++ b/fswatch/src/windows/getopt.c @@ -0,0 +1,579 @@ +/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ + +/* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__MSYS__) || defined(__CYGWIN__) || defined(__MINGW32__) +#include "libfswatch/libfswatch_config.h" +#include +#endif /* defined(_MSC_VER) || defined(__MSYS__) || defined(__CYGWIN__) || defined(__MINGW32__) */ + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) *__progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void +_vwarnx(const char *fmt,va_list ap) +{ + (void)fprintf(stderr,"%s: ",__progname); + if (fmt != NULL) + (void)vfprintf(stderr,fmt,ap); + (void)fprintf(stderr,"\n"); +} + +static void +warnx(const char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + _vwarnx(fmt,ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + const char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) { +#ifdef _MSC_VER + char *pValue; + size_t len; + errno_t err = _dupenv_s( &pValue, &len, "POSIXLY_CORRECT" ); + if (err) + posixly_correct = FALSE; + else { + posixly_correct = TRUE; + free(pValue); + } +#else + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); +#endif + } + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} diff --git a/fswatch/src/windows/getopt.h b/fswatch/src/windows/getopt.h new file mode 100644 index 00000000..00e2b8aa --- /dev/null +++ b/fswatch/src/windows/getopt.h @@ -0,0 +1,97 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file has no copyright assigned and is placed in the Public Domain. + * This file is a part of the w64 mingw-runtime package. + * + * The w64 mingw-runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include + +#include "getopt_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +GETOPT_EXPORT extern int optind; /* index of first non-option in argv */ +GETOPT_EXPORT extern int optopt; /* single option character, as parsed */ +GETOPT_EXPORT extern int opterr; /* flag to enable built-in diagnostics... */ + /* (user may set to zero, to suppress) */ + +GETOPT_EXPORT extern char *optarg; /* pointer to argument of current option */ + +GETOPT_EXPORT extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +GETOPT_EXPORT extern int getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx); +GETOPT_EXPORT extern int getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ diff --git a/libfswatch/CMakeLists.txt b/libfswatch/CMakeLists.txt index c21a5a02..60c4f7be 100644 --- a/libfswatch/CMakeLists.txt +++ b/libfswatch/CMakeLists.txt @@ -14,191 +14,57 @@ # this program. If not, see . # -# Define symbols to conditionally define FSEvents flags -if(APPLE) - if (${CMAKE_SYSTEM_VERSION} VERSION_GREATER_EQUAL "9.0") - set(HAVE_MACOS_GE_10_5 1) - endif() +set(LIBRARY_NAME "libfswatch") - if (${CMAKE_SYSTEM_VERSION} VERSION_GREATER_EQUAL "11.0") - set(HAVE_MACOS_GE_10_7 1) - endif() +add_library("${LIBRARY_NAME}" INTERFACE) - if (${CMAKE_SYSTEM_VERSION} VERSION_GREATER_EQUAL "13.0") - set(HAVE_MACOS_GE_10_9 1) - endif() +add_subdirectory("./src/libfswatch/gettext") +target_link_libraries("${LIBRARY_NAME}" INTERFACE "gettext") - if (${CMAKE_SYSTEM_VERSION} VERSION_GREATER_EQUAL "14.0") - set(HAVE_MACOS_GE_10_10 1) - endif() -endif() +add_subdirectory("./src/libfswatch/c") +target_link_libraries("${LIBRARY_NAME}" INTERFACE "c${PACKAGE}") -set(LIBFSWATCH_HEADER_FILES - src/libfswatch/c/cevent.h - src/libfswatch/c/cfilter.h - src/libfswatch/c/cmonitor.h - src/libfswatch/c/error.h - src/libfswatch/c/libfswatch.h - src/libfswatch/c/libfswatch_log.h - src/libfswatch/c/libfswatch_types.h - src/libfswatch/c++/event.hpp - src/libfswatch/c++/filter.hpp - src/libfswatch/c++/libfswatch_exception.hpp - src/libfswatch/c++/libfswatch_map.hpp - src/libfswatch/c++/libfswatch_set.hpp - src/libfswatch/c++/monitor.hpp - src/libfswatch/c++/monitor_factory.hpp - src/libfswatch/c++/path_utils.hpp - src/libfswatch/c++/poll_monitor.hpp - src/libfswatch/c++/string/string_utils.hpp - src/libfswatch/gettext.h - src/libfswatch/gettext_defs.h - ${CMAKE_CURRENT_BINARY_DIR}/libfswatch_config.h) +add_subdirectory("./src/libfswatch/c++") +target_link_libraries("${LIBRARY_NAME}" INTERFACE "cxx${PACKAGE}") -set(LIB_SOURCE_FILES - src/libfswatch/c/cevent.cpp - src/libfswatch/c/libfswatch.cpp - src/libfswatch/c/libfswatch_log.cpp - src/libfswatch/c++/event.cpp - src/libfswatch/c++/filter.cpp - src/libfswatch/c++/libfswatch_exception.cpp - src/libfswatch/c++/monitor.cpp - src/libfswatch/c++/monitor_factory.cpp - src/libfswatch/c++/path_utils.cpp - src/libfswatch/c++/poll_monitor.cpp - src/libfswatch/c++/string/string_utils.cpp) - -check_include_file_cxx(mutex HAVE_CXX_MUTEX) - -if (NOT HAVE_CXX_MUTEX) - message(WARNING "${PROJECT_NAME} is not thread-safe because required C++11 library classes are not available.") -endif (NOT HAVE_CXX_MUTEX) - -check_include_file_cxx(atomic HAVE_CXX_ATOMIC) - -if (NOT HAVE_CXX_ATOMIC) - message(WARNING " unavailable: some functionalities will not be built.") -endif (NOT HAVE_CXX_ATOMIC) - -check_cxx_symbol_exists(modf math.h HAVE_MODF) -check_cxx_symbol_exists(realpath cstdlib HAVE_REALPATH) -check_cxx_symbol_exists(select sys/select.h HAVE_SELECT) -check_struct_has_member("struct stat" st_mtime sys/stat.h HAVE_STRUCT_STAT_ST_MTIME) -check_struct_has_member("struct stat" st_mtimespec sys/stat.h HAVE_STRUCT_STAT_ST_MTIMESPEC) -check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP) -check_include_file_cxx(unordered_set HAVE_UNORDERED_SET) - -find_library(PTHREAD_LIBRARY pthread) -set(EXTRA_LIBS ${EXTRA_LIBS} ${PTHREAD_LIBRARY}) - -if (cxx_thread_local IN_LIST CMAKE_CXX_COMPILE_FEATURES) - set(HAVE_CXX_THREAD_LOCAL ON CACHE BOOL "Enable C++ thread_local support") -endif (cxx_thread_local IN_LIST CMAKE_CXX_COMPILE_FEATURES) - -check_cxx_symbol_exists(thread_local cstdlib HAVE_CXX_THREAD_LOCAL) - -check_include_file_cxx(sys/inotify.h HAVE_SYS_INOTIFY_H) - -if (HAVE_SYS_INOTIFY_H) - set(LIBFSWATCH_HEADER_FILES - ${LIBFSWATCH_HEADER_FILES} - src/libfswatch/c++/inotify_monitor.hpp) - set(LIB_SOURCE_FILES - ${LIB_SOURCE_FILES} - src/libfswatch/c++/inotify_monitor.cpp) -endif (HAVE_SYS_INOTIFY_H) - -check_include_file_cxx(sys/event.h HAVE_SYS_EVENT_H) - -if (HAVE_SYS_EVENT_H) - set(LIBFSWATCH_HEADER_FILES - ${LIBFSWATCH_HEADER_FILES} - src/libfswatch/c++/kqueue_monitor.hpp) - set(LIB_SOURCE_FILES - ${LIB_SOURCE_FILES} - src/libfswatch/c++/kqueue_monitor.cpp) -endif (HAVE_SYS_EVENT_H) - -check_include_file_cxx(port.h HAVE_PORT_H) - -if (HAVE_PORT_H) - set(LIBFSWATCH_HEADER_FILES - ${LIBFSWATCH_HEADER_FILES} - src/libfswatch/c++/fen_monitor.hpp) - set(LIB_SOURCE_FILES - ${LIB_SOURCE_FILES} - src/libfswatch/c++/fen_monitor.cpp) -endif (HAVE_PORT_H) - -check_cxx_symbol_exists(FindFirstChangeNotification windows.h HAVE_WINDOWS_HEADER) - -if (HAVE_WINDOWS_HEADER AND CYGWIN) - check_include_file_cxx(sys/cygwin.h HAVE_CYGWIN) - - if (HAVE_CYGWIN) - set(LIBFSWATCH_HEADER_FILES - ${LIBFSWATCH_HEADER_FILES} - src/libfswatch/c++/windows/win_directory_change_event.hpp - src/libfswatch/c++/windows/win_error_message.hpp - src/libfswatch/c++/windows/win_handle.hpp - src/libfswatch/c++/windows/win_paths.hpp - src/libfswatch/c++/windows/win_strings.hpp - src/libfswatch/c++/windows_monitor.hpp) - - set(LIB_SOURCE_FILES - ${LIB_SOURCE_FILES} - src/libfswatch/c++/windows/win_directory_change_event.cpp - src/libfswatch/c++/windows/win_error_message.cpp - src/libfswatch/c++/windows/win_handle.cpp - src/libfswatch/c++/windows/win_paths.cpp - src/libfswatch/c++/windows/win_strings.cpp - src/libfswatch/c++/windows_monitor.cpp) - set(HAVE_WINDOWS ON CACHE BOOL "Enable Windows support") - endif (HAVE_CYGWIN) -endif (HAVE_WINDOWS_HEADER AND CYGWIN) - -if (APPLE) - check_include_file_cxx(CoreServices/CoreServices.h HAVE_FSEVENTS_FILE_EVENTS) - - if (HAVE_FSEVENTS_FILE_EVENTS) - find_library(CORESERVICES_LIBRARY CoreServices) - set(EXTRA_LIBS ${EXTRA_LIBS} ${CORESERVICES_LIBRARY}) - - set(LIBFSWATCH_HEADER_FILES - ${LIBFSWATCH_HEADER_FILES} - src/libfswatch/c++/fsevents_monitor.hpp) - set(LIB_SOURCE_FILES - ${LIB_SOURCE_FILES} - src/libfswatch/c++/fsevents_monitor.cpp) - - endif (HAVE_FSEVENTS_FILE_EVENTS) -endif (APPLE) - -# Add a configuration file processed by cmake -configure_file(libfswatch_config.in libfswatch_config.h) -# TODO: consider removing it -add_definitions(-DHAVE_LIBFSWATCH_CONFIG_H) - -add_library(libfswatch ${LIB_SOURCE_FILES} ${LIBFSWATCH_HEADER_FILES}) -set_target_properties(libfswatch PROPERTIES PREFIX "") - -# check for gettext and libintl -if (USE_NLS) - if (Intl_LIBRARIES) - target_link_libraries(libfswatch PRIVATE ${Intl_LIBRARIES}) +if (NOT DEFINED TARGET_ARCH) + # See https://gitlab.kitware.com/cmake/cmake/-/issues/15170 for why `CMAKE_SYSTEM_PROCESSOR` isn't used + if (DEFINED CMAKE_C_COMPILER_ARCHITECTURE_ID) + set(TARGET_ARCH "${CMAKE_C_COMPILER_ARCHITECTURE_ID}") + elseif (DEFINED CMAKE_CXX_COMPILER_ARCHITECTURE_ID) + set(TARGET_ARCH "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}") + else () + set(TARGET_ARCH "${CMAKE_SYSTEM_PROCESSOR}") endif () -endif () - -target_include_directories(libfswatch PUBLIC src/libfswatch) -target_include_directories(libfswatch PUBLIC src) -target_include_directories(libfswatch PUBLIC ${Intl_INCLUDE_DIRS}) -target_include_directories(libfswatch PRIVATE ${PROJECT_BINARY_DIR}) -target_include_directories(libfswatch PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(libfswatch PRIVATE ${EXTRA_LIBS}) + if (TARGET_ARCH STREQUAL "x64") + set(TARGET_ARCH "AMD64") + elseif (NOT TARGET_ARCH STREQUAL "X86") + set(TARGET_ARCH "ARM") + endif () +endif (NOT DEFINED TARGET_ARCH) -install(TARGETS libfswatch LIBRARY DESTINATION lib) -install(DIRECTORY src/libfswatch - DESTINATION include - FILES_MATCHING - PATTERN "*.hpp" - PATTERN "*.h") +# Add a configuration file processed by cmake +configure_file("libfswatch_config.in" "${CMAKE_CURRENT_BINARY_DIR}/libfswatch_config.h") + +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + CXX +) + +# setup the version numbering +set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") +set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") + +# install rules +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif (TARGET "${DEPENDANT_LIBRARY}") +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libfswatch_config.h" + DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/${LIBRARY_NAME}") diff --git a/libfswatch/libfswatch_config.in b/libfswatch/libfswatch_config.in index 58228760..6b50cbfb 100644 --- a/libfswatch/libfswatch_config.in +++ b/libfswatch/libfswatch_config.in @@ -25,4 +25,8 @@ #cmakedefine HAVE_MACOS_GE_10_5 #cmakedefine HAVE_MACOS_GE_10_7 #cmakedefine HAVE_MACOS_GE_10_9 -#cmakedefine HAVE_MACOS_GE_10_10 \ No newline at end of file +#cmakedefine HAVE_MACOS_GE_10_10 + +/* Architecture (needed by MSVC) */ + +#define _@TARGET_ARCH@_ diff --git a/libfswatch/src/libfswatch/c++/CMakeLists.txt b/libfswatch/src/libfswatch/c++/CMakeLists.txt new file mode 100644 index 00000000..f73dd057 --- /dev/null +++ b/libfswatch/src/libfswatch/c++/CMakeLists.txt @@ -0,0 +1,112 @@ +set(LIBRARY_NAME "cxx${PACKAGE}") + +set(Header_Files "event.hpp" + "filter.hpp" + "libfswatch_exception.hpp" + "libfswatch_map.hpp" + "libfswatch_set.hpp" + "monitor.hpp" + "monitor_factory.hpp" + "path_utils.hpp" + "poll_monitor.hpp" + ) + +set(Source_Files "event.cpp" + "filter.cpp" + "libfswatch_exception.cpp" + "monitor.cpp" + "monitor_factory.cpp" + "path_utils.cpp" + "poll_monitor.cpp" + ) + +check_cxx_symbol_exists(thread_local cstdlib HAVE_CXX_THREAD_LOCAL) + +check_include_file_cxx("sys/inotify.h" HAVE_SYS_INOTIFY_H) + +if (HAVE_SYS_INOTIFY_H) + list(APPEND Header_Files "inotify_monitor.hpp") + list(APPEND Source_Files "inotify_monitor.cpp") +endif (HAVE_SYS_INOTIFY_H) + +check_include_file_cxx("sys/event.h" HAVE_SYS_EVENT_H) + +if (HAVE_SYS_EVENT_H) + list(APPEND Header_Files "kqueue_monitor.hpp") + list(APPEND Source_Files "kqueue_monitor.cpp") +endif (HAVE_SYS_EVENT_H) + +check_include_file_cxx("port.h" HAVE_PORT_H) + +if (HAVE_PORT_H) + list(APPEND Header_Files "fen_monitor.hpp") + list(APPEND Source_Files "fen_monitor.cpp") +endif (HAVE_PORT_H) + +check_cxx_symbol_exists(FindFirstChangeNotification "windows.h" HAVE_WINDOWS_HEADER) + +if (HAVE_WINDOWS_HEADER) + include_directories("./windows") +endif (HAVE_WINDOWS_HEADER) + +set(Extra_Libs "") + +if (APPLE) + check_include_file_cxx("CoreServices/CoreServices.h" HAVE_FSEVENTS_FILE_EVENTS) + + if (HAVE_FSEVENTS_FILE_EVENTS) + find_library(CORESERVICES_LIBRARY CoreServices) + set(Extra_Libs "${CORESERVICES_LIBRARY}") + + list(APPEND Header_Files "fsevents_monitor.hpp") + list(APPEND Source_Files "fsevents_monitor.cpp") + + endif (HAVE_FSEVENTS_FILE_EVENTS) +endif (APPLE) + +source_group("${LIBRARY_NAME} Header Files" FILES "${Header_Files}") +source_group("${LIBRARY_NAME} Source Files" FILES "${Source_Files}") + +add_library("${LIBRARY_NAME}" STATIC "${Header_Files}" "${Source_Files}") +target_include_directories( + "${LIBRARY_NAME}" + PUBLIC + "$" + "$" + "$" +) + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_subdirectory("./windows") + target_link_libraries("${LIBRARY_NAME}" PUBLIC "${PACKAGE}_cxx_windows") +endif (CMAKE_SYSTEM_NAME STREQUAL "Windows") + +add_subdirectory("./string") +target_link_libraries("${LIBRARY_NAME}" PUBLIC "${PACKAGE}_string_utils" "${Extra_Libs}") +target_link_libraries("${LIBRARY_NAME}" PRIVATE "c${PACKAGE}" "gettext") + +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + CXX +) + +include(GenerateExportHeader) +set(_export_file "${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}_export.h") +generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") + +# setup the version numbering +set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") +set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") + +# install rules +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif () +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES ${Header_Files} "${_export_file}" DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/libfswatch") diff --git a/libfswatch/src/libfswatch/c++/event.cpp b/libfswatch/src/libfswatch/c++/event.cpp index 4fbbd3ce..f0c4141c 100644 --- a/libfswatch/src/libfswatch/c++/event.cpp +++ b/libfswatch/src/libfswatch/c++/event.cpp @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "event.hpp" #include "libfswatch_exception.hpp" #include diff --git a/libfswatch/src/libfswatch/c++/event.hpp b/libfswatch/src/libfswatch/c++/event.hpp index 14825097..c14a0b83 100644 --- a/libfswatch/src/libfswatch/c++/event.hpp +++ b/libfswatch/src/libfswatch/c++/event.hpp @@ -31,6 +31,7 @@ # include # include # include "../c/cevent.h" +# include "cxxfswatch_export.h" namespace fsw { @@ -44,7 +45,7 @@ namespace fsw * - The time the event was raised. * - A vector of flags specifying the type of the event. */ - class event + class CXXFSWATCH_EXPORT event { public: /** @@ -115,7 +116,7 @@ namespace fsw * @param flag The flag to print. * @return A reference to the stream. */ - std::ostream& operator<<(std::ostream& out, const fsw_event_flag flag); + CXXFSWATCH_EXPORT std::ostream& operator<<(std::ostream& out, const fsw_event_flag flag); } #endif /* FSW_EVENT_H */ diff --git a/libfswatch/src/libfswatch/c++/fen_monitor.cpp b/libfswatch/src/libfswatch/c++/fen_monitor.cpp index 67bb0838..fb8dae7e 100644 --- a/libfswatch/src/libfswatch/c++/fen_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/fen_monitor.cpp @@ -22,16 +22,19 @@ # include # include # include -# include # include # include # include -# include "libfswatch/gettext_defs.h" +#ifndef _MSC_VER +# include +#endif /* !_MSC_VER */ + +# include "gettext_defs.h" # include "fen_monitor.hpp" # include "libfswatch_map.hpp" # include "libfswatch_set.hpp" # include "libfswatch_exception.hpp" -# include "libfswatch/c/libfswatch_log.h" +# include "libfswatch_log.h" # include "path_utils.hpp" using namespace std; @@ -285,7 +288,10 @@ namespace fsw { if (child.compare(".") == 0 || child.compare("..") == 0) continue; - scan(path + "/" + child, false); + std::string new_path = path; + new_path += PATH_SEP; + new_path += child; + scan(new_path, false); } return add_watch(path, fd_stat); diff --git a/libfswatch/src/libfswatch/c++/fen_monitor.hpp b/libfswatch/src/libfswatch/c++/fen_monitor.hpp index 08282eaf..3db84a96 100644 --- a/libfswatch/src/libfswatch/c++/fen_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/fen_monitor.hpp @@ -29,6 +29,7 @@ # include "monitor.hpp" # include # include +# include "cxxfswatch_export.h" namespace fsw { @@ -50,7 +51,7 @@ namespace fsw * This monitor is built upon the _File Events Notification_ API of the * Solaris and Illumos kernels. */ - class fen_monitor : public monitor + class CXXFSWATCH_EXPORT fen_monitor : public monitor { public: /** diff --git a/libfswatch/src/libfswatch/c++/filter.cpp b/libfswatch/src/libfswatch/c++/filter.cpp index e921a7cf..7e07cbaa 100644 --- a/libfswatch/src/libfswatch/c++/filter.cpp +++ b/libfswatch/src/libfswatch/c++/filter.cpp @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "filter.hpp" #include #include @@ -27,7 +27,7 @@ namespace fsw static inline bool parse_filter(std::string filter, monitor_filter& filter_object, void (*err_handler)(std::string)); - static inline bool is_unescaped_space(string& filter, long i); + static inline bool is_unescaped_space(string& filter, size_t i); vector monitor_filter::read_from_file(const string& path, void (*err_handler)( @@ -53,7 +53,7 @@ namespace fsw return filters; } - static bool is_unescaped_space(string& filter, long i) + static bool is_unescaped_space(string& filter, size_t i) { if (filter[i] != ' ') return false; @@ -130,7 +130,7 @@ namespace fsw // Parse the filter // Trim unescaped trailing spaces. - for (auto i = frag_filter.length() - 1; i > 0; --i) + for (size_t i = frag_filter.size() - 1; i > 0; --i) { if (is_unescaped_space(frag_filter, i)) frag_filter.erase(i, 1); else break; diff --git a/libfswatch/src/libfswatch/c++/filter.hpp b/libfswatch/src/libfswatch/c++/filter.hpp index 0190420d..a2a5745e 100644 --- a/libfswatch/src/libfswatch/c++/filter.hpp +++ b/libfswatch/src/libfswatch/c++/filter.hpp @@ -29,7 +29,7 @@ # define FSW__FILTER_H # include -# include "libfswatch/c/cfilter.h" +# include # include namespace fsw diff --git a/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp b/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp index 89b3506e..23b3dab6 100644 --- a/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp @@ -15,15 +15,17 @@ */ #include "libfswatch/libfswatch_config.h" #include -#include // isatty() #include // fileno() #include "fsevents_monitor.hpp" -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "libfswatch_exception.hpp" -#include "libfswatch/c/libfswatch_log.h" +#include "libfswatch_log.h" # ifdef HAVE_CXX_MUTEX # include # endif +#ifndef _MSC_VER +#include // isatty() +#endif /* _MSC_VER */ namespace fsw { diff --git a/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp b/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp index f4ca81ab..7ff6fa52 100644 --- a/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp @@ -28,6 +28,7 @@ # include "monitor.hpp" # include +# include "cxxfswatch_export.h" namespace fsw { @@ -36,7 +37,7 @@ namespace fsw * * This monitor is built upon the _FSEvents_ API of the Apple macOS kernel. */ - class fsevents_monitor : public monitor + class CXXFSWATCH_EXPORT fsevents_monitor : public monitor { public: diff --git a/libfswatch/src/libfswatch/c++/inotify_monitor.cpp b/libfswatch/src/libfswatch/c++/inotify_monitor.cpp index 317353a4..a8065bdf 100644 --- a/libfswatch/src/libfswatch/c++/inotify_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/inotify_monitor.cpp @@ -15,19 +15,23 @@ */ #include "libfswatch/libfswatch_config.h" -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "inotify_monitor.hpp" #include #include -#ifdef __sun +#ifndef NAME_MAX # define NAME_MAX 255 /* # chars in a file name */ -#endif -#include +#endif /* ! NAME_MAX */ #include #include #include #include #include + +#ifndef _MSC_VER +# include +#endif /* !_MSC_VER */ + #include "libfswatch_exception.hpp" #include "../c/libfswatch_log.h" #include "libfswatch_map.hpp" @@ -174,7 +178,10 @@ namespace fsw /* * Scan children but only watch directories. */ - scan(path + "/" + child, false); + std::string new_path = path; + new_path += PATH_SEP; + new_path += child; + scan(new_path, false); } } @@ -240,8 +247,7 @@ namespace fsw if (event->len > 1) { - filename_stream << "/"; - filename_stream << event->name; + filename_stream << PATH_SEP << event->name; } if (flags.size()) diff --git a/libfswatch/src/libfswatch/c++/inotify_monitor.hpp b/libfswatch/src/libfswatch/c++/inotify_monitor.hpp index 984a00e7..b75d9d04 100644 --- a/libfswatch/src/libfswatch/c++/inotify_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/inotify_monitor.hpp @@ -31,6 +31,7 @@ # include # include # include +# include "cxxfswatch_export.h" namespace fsw { @@ -46,7 +47,7 @@ namespace fsw * This monitor is built upon the _File Events Notification_ API of the * Solaris and Illumos kernels. */ - class inotify_monitor : public monitor + class CXXFSWATCH_EXPORT inotify_monitor : public monitor { public: /** diff --git a/libfswatch/src/libfswatch/c++/kqueue_monitor.cpp b/libfswatch/src/libfswatch/c++/kqueue_monitor.cpp index 4850eb2a..a3ef102c 100644 --- a/libfswatch/src/libfswatch/c++/kqueue_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/kqueue_monitor.cpp @@ -17,22 +17,24 @@ #ifdef HAVE_SYS_EVENT_H -# include "libfswatch/gettext_defs.h" +# include "gettext_defs.h" # include "kqueue_monitor.hpp" # include "libfswatch_map.hpp" # include "libfswatch_set.hpp" # include "libfswatch_exception.hpp" -# include "libfswatch//c/libfswatch_log.h" +# include "libfswatch_log.h" # include "path_utils.hpp" # include -# include # include # include # include -#include -# include +# include # include +#ifndef _MSC_VER +# include +#endif /* !_MSC_VER */ + namespace fsw { @@ -203,7 +205,10 @@ namespace fsw { if (child == "." || child == "..") continue; - scan(path + "/" + child, false); + std::string new_path = path; + new_path += PATH_SEP; + new_path += child; + scan(new_path, false); } return true; diff --git a/libfswatch/src/libfswatch/c++/kqueue_monitor.hpp b/libfswatch/src/libfswatch/c++/kqueue_monitor.hpp index aa605f94..925d17b6 100644 --- a/libfswatch/src/libfswatch/c++/kqueue_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/kqueue_monitor.hpp @@ -31,6 +31,7 @@ # include # include # include +# include "cxxfswatch_export.h" namespace fsw { @@ -45,7 +46,7 @@ namespace fsw * * This monitor is built upon the `kqueue` API of the BSD kernels. */ - class kqueue_monitor : public monitor + class CXXFSWATCH_EXPORT kqueue_monitor : public monitor { public: /** diff --git a/libfswatch/src/libfswatch/c++/libfswatch_exception.cpp b/libfswatch/src/libfswatch/c++/libfswatch_exception.cpp index 71f9076e..ace3b055 100644 --- a/libfswatch/src/libfswatch/c++/libfswatch_exception.cpp +++ b/libfswatch/src/libfswatch/c++/libfswatch_exception.cpp @@ -16,7 +16,6 @@ #include "libfswatch_exception.hpp" #include -#include "libfswatch/gettext_defs.h" using namespace std; diff --git a/libfswatch/src/libfswatch/c++/libfswatch_exception.hpp b/libfswatch/src/libfswatch/c++/libfswatch_exception.hpp index cbd2f892..f33e9b4d 100644 --- a/libfswatch/src/libfswatch/c++/libfswatch_exception.hpp +++ b/libfswatch/src/libfswatch/c++/libfswatch_exception.hpp @@ -26,9 +26,10 @@ #ifndef LIBFSW_EXCEPTION_H # define LIBFSW_EXCEPTION_H -# include "../c/error.h" +# include "../c/fsw_error.h" # include # include +# include "cxxfswatch_export.h" namespace fsw { @@ -38,7 +39,7 @@ namespace fsw * An instance of this class stores an error message and an integer error * code. */ - class libfsw_exception : public std::exception + class CXXFSWATCH_EXPORT libfsw_exception : public std::exception { public: /** diff --git a/libfswatch/src/libfswatch/c++/monitor.cpp b/libfswatch/src/libfswatch/c++/monitor.cpp index 3d57150c..8b051c62 100644 --- a/libfswatch/src/libfswatch/c++/monitor.cpp +++ b/libfswatch/src/libfswatch/c++/monitor.cpp @@ -14,18 +14,15 @@ * this program. If not, see . */ #include "libfswatch/libfswatch_config.h" -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "monitor.hpp" -#include "monitor_factory.hpp" #include "libfswatch_exception.hpp" -#include "libfswatch/c/libfswatch_log.h" +#include "libfswatch_log.h" #include "string/string_utils.hpp" -#include #include #include #include #include -#include #include #include #include @@ -138,8 +135,8 @@ namespace fsw { throw libfsw_exception( string_utils::string_from_format( - _("An error occurred during the compilation of %s"), - filter.text.c_str()), + _("An error occurred during the compilation of %s\n\t%s"), + filter.text.c_str(), error.what()), FSW_ERR_INVALID_REGEX); } } diff --git a/libfswatch/src/libfswatch/c++/monitor.hpp b/libfswatch/src/libfswatch/c++/monitor.hpp index 3870dc30..a03bdcd6 100644 --- a/libfswatch/src/libfswatch/c++/monitor.hpp +++ b/libfswatch/src/libfswatch/c++/monitor.hpp @@ -41,7 +41,8 @@ # include # include # include "event.hpp" -# include "libfswatch/c/cmonitor.h" +# include "cmonitor.h" +# include "cxxfswatch_export.h" /** * @brief Main namespace of `libfswatch`. @@ -144,7 +145,7 @@ namespace fsw * - The notify_events() method is called to filter the event types and * notify the caller. */ - class monitor + class CXXFSWATCH_EXPORT monitor { public: /** diff --git a/libfswatch/src/libfswatch/c++/monitor_factory.cpp b/libfswatch/src/libfswatch/c++/monitor_factory.cpp index 505abcdb..60dc11b5 100644 --- a/libfswatch/src/libfswatch/c++/monitor_factory.cpp +++ b/libfswatch/src/libfswatch/c++/monitor_factory.cpp @@ -15,7 +15,7 @@ */ #include #include "libfswatch/libfswatch_config.h" -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "monitor_factory.hpp" #include "libfswatch_exception.hpp" #if defined(HAVE_FSEVENTS_FILE_EVENTS) diff --git a/libfswatch/src/libfswatch/c++/monitor_factory.hpp b/libfswatch/src/libfswatch/c++/monitor_factory.hpp index 7e6f5865..106661a9 100644 --- a/libfswatch/src/libfswatch/c++/monitor_factory.hpp +++ b/libfswatch/src/libfswatch/c++/monitor_factory.hpp @@ -30,6 +30,7 @@ #include "monitor.hpp" #include "libfswatch_set.hpp" +#include "cxxfswatch_export.h" namespace fsw { @@ -53,7 +54,7 @@ namespace fsw * registration will succeed; however, the registration process of multiple * monitor implementations for the same monitor type is _not_ deterministic. */ - class monitor_factory + class CXXFSWATCH_EXPORT monitor_factory { public: /** diff --git a/libfswatch/src/libfswatch/c++/path_utils.cpp b/libfswatch/src/libfswatch/c++/path_utils.cpp index c370290a..6a321da6 100644 --- a/libfswatch/src/libfswatch/c++/path_utils.cpp +++ b/libfswatch/src/libfswatch/c++/path_utils.cpp @@ -13,15 +13,27 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -#include "libfswatch/gettext_defs.h" +#include "gettext_defs.h" #include "path_utils.hpp" -#include "libfswatch/c/libfswatch_log.h" -#include +#include "libfswatch_log.h" #include + +#ifdef _MSC_VER +#include "libfswatch/libfswatch_config.h" +#ifndef _ARM_ +#include +#endif /* !_ARM_ */ +#include +#define INVALID_HANDLE_VALUE (HANDLE)(-1) +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif /* ! PATH_MAX */ +#else +#include #include #include -#include #include +#endif /* _MSC_VER */ using namespace std; @@ -29,7 +41,18 @@ namespace fsw { vector get_directory_children(const string& path) { - vector children; + vector children; +#ifdef _MSC_VER + HANDLE hFind; + WIN32_FIND_DATA FindFileData; + + if((hFind = FindFirstFile(path.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE){ + do { + children.emplace_back(FindFileData.cFileName); + } while(FindNextFile(hFind, &FindFileData)); + FindClose(hFind); + } +#else DIR *dir = opendir(path.c_str()); if (!dir) @@ -52,6 +75,7 @@ namespace fsw } closedir(dir); +#endif /* _MSC_VER */ return children; } @@ -65,6 +89,14 @@ namespace fsw std::string fsw_realpath(const char *path, char *resolved_path) { +#ifdef _MSC_VER + char *path_buf = /* _strdup(path) */ (char*)path; + char *ret = _fullpath(path_buf, resolved_path, PATH_MAX); + if (ret == NULL) + throw std::exception("_fullpath", EXIT_FAILURE); + + return std::string(ret); +#else char *ret = realpath(path, resolved_path); if (ret == nullptr) @@ -80,6 +112,7 @@ namespace fsw if (resolved_path == nullptr) free(ret); return resolved; +#endif /* _MSC_VER */ } bool stat_path(const string& path, struct stat& fd_stat) @@ -94,9 +127,12 @@ namespace fsw bool lstat_path(const string& path, struct stat& fd_stat) { - if (lstat(path.c_str(), &fd_stat) == 0) +#ifdef _MSC_VER + return stat_path(path, fd_stat); +#else + if (lstat(path.c_str(), &fd_stat) == 0) return true; - +#endif /* _MSC_VER */ fsw_logf_perror(_("Cannot lstat %s"), path.c_str()); return false; } diff --git a/libfswatch/src/libfswatch/c++/path_utils.hpp b/libfswatch/src/libfswatch/c++/path_utils.hpp index 4954a13b..51e2926d 100644 --- a/libfswatch/src/libfswatch/c++/path_utils.hpp +++ b/libfswatch/src/libfswatch/c++/path_utils.hpp @@ -29,6 +29,14 @@ # include # include # include +# include "cxxfswatch_export.h" +# include "libfswatch/libfswatch_config.h" + +#ifdef _MSC_VER +#define PATH_SEP "\\" +#else +#define PATH_SEP "/" +#endif namespace fsw { @@ -41,7 +49,7 @@ namespace fsw * @return If there is no error, realpath() returns a string, otherwise it * throws a std::system_error. */ - std::string fsw_realpath(const char *path, char *resolved_path); + CXXFSWATCH_EXPORT std::string fsw_realpath(const char *path, char *resolved_path); /** * @brief Gets a vector of direct directory children. @@ -49,7 +57,7 @@ namespace fsw * @param path The directory whose children must be returned. * @return A vector containing the list of children of @p path. */ - std::vector get_directory_children(const std::string& path); + CXXFSWATCH_EXPORT std::vector get_directory_children(const std::string& path); /** * @brief Resolves a path name. @@ -63,7 +71,7 @@ namespace fsw * path should be copied to. * @return @c true if the function succeeds, @c false otherwise. */ - bool read_link_path(const std::string& path, std::string& link_path); + CXXFSWATCH_EXPORT bool read_link_path(const std::string& path, std::string& link_path); /** * @brief Wraps a @c lstat(path, fd_stat) call that invokes @c perror() if it @@ -73,7 +81,7 @@ namespace fsw * @param fd_stat The @c stat structure where @c lstat() writes its results. * @return @c true if the function succeeds, @c false otherwise. */ - bool lstat_path(const std::string& path, struct stat& fd_stat); + CXXFSWATCH_EXPORT bool lstat_path(const std::string& path, struct stat& fd_stat); /** * @brief Wraps a @c stat(path, fd_stat) call that invokes @c perror() if it @@ -83,6 +91,6 @@ namespace fsw * @param fd_stat The @c stat structure where @c stat() writes its results. * @return @c true if the function succeeds, @c false otherwise. */ - bool stat_path(const std::string& path, struct stat& fd_stat); + CXXFSWATCH_EXPORT bool stat_path(const std::string& path, struct stat& fd_stat); } #endif /* FSW_PATH_UTILS_H */ diff --git a/libfswatch/src/libfswatch/c++/poll_monitor.cpp b/libfswatch/src/libfswatch/c++/poll_monitor.cpp index 4c65e6b8..7988dfe9 100644 --- a/libfswatch/src/libfswatch/c++/poll_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/poll_monitor.cpp @@ -13,22 +13,42 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -#include "libfswatch/gettext_defs.h" -#include -#include -#include +#include "gettext_defs.h" #include #include + +#ifdef _MSC_VER +#include "libfswatch/libfswatch_config.h" +#ifndef _ARM_ +#include +#endif /* !_ARM_ */ +#include + +/* stolen from libcurl: */ +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* stolen from libcurl: */ +#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +#else +# include +# include +#endif /* _MSC_VER */ + #include "libfswatch/libfswatch_config.h" -#include "libfswatch/c/libfswatch_log.h" +#include "libfswatch_log.h" #include "poll_monitor.hpp" #include "path_utils.hpp" #include "libfswatch_map.hpp" -#if defined HAVE_STRUCT_STAT_ST_MTIME +#ifdef HAVE_STRUCT_STAT_ST_MTIME # define FSW_MTIME(stat) ((stat).st_mtime) # define FSW_CTIME(stat) ((stat).st_ctime) -#elif defined HAVE_STRUCT_STAT_ST_MTIMESPEC +#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC) # define FSW_MTIME(stat) (stat.st_mtimespec.tv_sec) # define FSW_CTIME(stat) (stat.st_ctimespec.tv_sec) #else @@ -121,7 +141,13 @@ namespace fsw struct stat fd_stat; if (!lstat_path(path, fd_stat)) return; - if (follow_symlinks && S_ISLNK(fd_stat.st_mode)) +#ifdef _MSC_VER +#define _ISLNK !S_ISREG +#else +#define _ISLNK S_ISLNK +#endif /* _MSC_VER */ + + if (follow_symlinks && _ISLNK(fd_stat.st_mode)) { string link_path; if (read_link_path(path, link_path)) @@ -129,6 +155,7 @@ namespace fsw return; } +#undef _ISLNK if (!accept_path(path)) return; if (!add_path(path, fd_stat, fn)) return; @@ -141,7 +168,10 @@ namespace fsw { if (child == "." || child == "..") continue; - scan(path + "/" + child, fn); + std::string new_path = path; + new_path += PATH_SEP; + new_path += child; + scan(new_path, fn); } } @@ -199,7 +229,12 @@ namespace fsw FSW_ELOG(_("Done scanning.\n")); - sleep(latency < MIN_POLL_LATENCY ? MIN_POLL_LATENCY : latency); +#ifdef _MSC_VER + Sleep( 1000L * static_cast( +#else + sleep( ( +#endif + (latency < MIN_POLL_LATENCY ? MIN_POLL_LATENCY : latency))); time(&curr_time); diff --git a/libfswatch/src/libfswatch/c++/poll_monitor.hpp b/libfswatch/src/libfswatch/c++/poll_monitor.hpp index 794aa2d9..84a508ac 100644 --- a/libfswatch/src/libfswatch/c++/poll_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/poll_monitor.hpp @@ -30,6 +30,7 @@ # include # include # include +# include "cxxfswatch_export.h" namespace fsw { @@ -39,7 +40,7 @@ namespace fsw * This monitor uses the `stat()` function to periodically check the observed * paths and detect changes. */ - class poll_monitor : public monitor + class CXXFSWATCH_EXPORT poll_monitor : public monitor { public: /** diff --git a/libfswatch/src/libfswatch/c++/string/CMakeLists.txt b/libfswatch/src/libfswatch/c++/string/CMakeLists.txt new file mode 100644 index 00000000..5441b9ee --- /dev/null +++ b/libfswatch/src/libfswatch/c++/string/CMakeLists.txt @@ -0,0 +1,41 @@ +set(LIBRARY_NAME "${PACKAGE}_string_utils") + +set(Header_Files "string_utils.hpp") +source_group("${LIBRARY_NAME} Header Files" FILES "${Header_Files}") + +set(Source_Files "string_utils.cpp") +source_group("${LIBRARY_NAME} Source Files" FILES "${Source_Files}") + +add_library("${LIBRARY_NAME}" STATIC "${Header_Files}" "${Source_Files}") +target_include_directories( + "${LIBRARY_NAME}" + PUBLIC + "$" + "$" + "$" +) +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + CXX +) + +include(GenerateExportHeader) +set(_export_file "${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}_export.h") +generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") + +# setup the version numbering +set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") +set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") + +# install rules +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif () +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES ${Header_Files} "${_export_file}" DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/libfswatch") diff --git a/libfswatch/src/libfswatch/c++/string/string_utils.hpp b/libfswatch/src/libfswatch/c++/string/string_utils.hpp index 5477f4e8..04a150d8 100644 --- a/libfswatch/src/libfswatch/c++/string/string_utils.hpp +++ b/libfswatch/src/libfswatch/c++/string/string_utils.hpp @@ -28,6 +28,7 @@ #include #include +#include "fswatch_string_utils_export.h" namespace fsw { @@ -42,7 +43,7 @@ namespace fsw * @param format The `printf()` format. * @param ... The arguments to format. */ - std::string string_from_format(const char *format, ...); + FSWATCH_STRING_UTILS_EXPORT std::string string_from_format(const char *format, ...); /** * @brief Create a `std::string` using a `printf()` format and a `va_list` @@ -51,7 +52,7 @@ namespace fsw * @param format The `printf()` format. * @param args The arguments to format. */ - std::string vstring_from_format(const char *format, va_list args); + FSWATCH_STRING_UTILS_EXPORT std::string vstring_from_format(const char *format, va_list args); } } diff --git a/libfswatch/src/libfswatch/c++/windows/CMakeLists.txt b/libfswatch/src/libfswatch/c++/windows/CMakeLists.txt new file mode 100644 index 00000000..2ae766d5 --- /dev/null +++ b/libfswatch/src/libfswatch/c++/windows/CMakeLists.txt @@ -0,0 +1,68 @@ +set(LIBRARY_NAME "${PACKAGE}_cxx_windows") + +set(Header_Files "win_directory_change_event.hpp" + "win_error_message.hpp" + "win_handle.hpp" + "win_paths.hpp" + "win_strings.hpp" + "../windows_monitor.hpp" + ) + +set(Source_Files + "win_directory_change_event.cpp" + "win_error_message.cpp" + "win_handle.cpp" + "win_paths.cpp" + "win_strings.cpp" + "../windows_monitor.cpp" + ) + +check_include_file_cxx("sys/cygwin.h" HAVE_CYGWIN) + +if (MSVC) + list(APPEND Source_Files "win_paths.cpp") +else () + list(APPEND Source_Files "cygwin_paths.cpp") +endif (MSVC) + +set(HAVE_WINDOWS ON CACHE BOOL "Enable Windows support") + +source_group("${LIBRARY_NAME} Header Files" FILES "${Header_Files}") +source_group("${LIBRARY_NAME} Source Files" FILES "${Source_Files}") + +add_library("${LIBRARY_NAME}" STATIC "${Header_Files}" "${Source_Files}") +target_include_directories( + "${LIBRARY_NAME}" + PUBLIC + "$" + "$" + "$" + "$" + "$" +) +target_link_libraries("${LIBRARY_NAME}" PRIVATE "c${PACKAGE}" "cxx${PACKAGE}" "gettext") +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + CXX +) + +include(GenerateExportHeader) +set(_export_file "${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}_export.h") +generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") + +# setup the version numbering +set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") +set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") + +# install rules +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif () +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES ${Header_Files} "${_export_file}" DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/libfswatch") diff --git a/libfswatch/src/libfswatch/c++/windows/cygwin_paths.cpp b/libfswatch/src/libfswatch/c++/windows/cygwin_paths.cpp new file mode 100644 index 00000000..7542eca2 --- /dev/null +++ b/libfswatch/src/libfswatch/c++/windows/cygwin_paths.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 Enrico M. Crisostomo + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include "win_paths.hpp" +#include +#include "../libfswatch_exception.hpp" +#include "../../gettext_defs.h" + +using namespace std; + +namespace fsw +{ + namespace win_paths + { + wstring posix_to_win_w(const string &path) + { + void * raw_path = cygwin_create_path(CCP_POSIX_TO_WIN_W, path.c_str()); + if (raw_path == nullptr) throw libfsw_exception(_("cygwin_create_path could not allocate memory to convert the path.")); + + wstring win_path(static_cast (raw_path)); + + free(raw_path); + + return win_path; + } + + string win_w_to_posix(const wstring &path) + { + void * raw_path = cygwin_create_path(CCP_WIN_W_TO_POSIX, path.c_str()); + if (raw_path == nullptr) throw libfsw_exception(_("cygwin_create_path could not allocate memory to convert the path.")); + + string posix_path(static_cast (raw_path)); + + free(raw_path); + + return posix_path; + } + } +} diff --git a/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.cpp b/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.cpp index 8dcc7fe8..7e0c1e30 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.cpp +++ b/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.cpp @@ -13,16 +13,30 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include +#include +#include + #include "libfswatch/libfswatch_config.h" +#ifdef _MSC_VER +#define NOWINBASEINTERLOCK +#ifndef _ARM_ +# include +#endif /* !_ARM_ */ +# include +# include +# include +# include + +#endif /* _MSC_VER */ + #include "win_directory_change_event.hpp" #include "win_paths.hpp" #include "win_strings.hpp" -#include "libfswatch/c++/libfswatch_exception.hpp" -#include "libfswatch/c/libfswatch_log.h" -#include "libfswatch/gettext_defs.h" -#include -#include -#include +#include "libfswatch_exception.hpp" +#include "libfswatch_log.h" +#include "gettext_defs.h" + namespace fsw { @@ -89,12 +103,15 @@ namespace fsw FSW_ELOGF(_("%p.\n"), this); - return ReadDirectoryChangesW((HANDLE) handle, + return ReadDirectoryChangesW(static_cast(handle), buffer.get(), - buffer_size, + static_cast(buffer_size), TRUE, - FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION, &bytes_returned, overlapped.get(), nullptr); diff --git a/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.hpp b/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.hpp index cfa1024c..7a692d7d 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.hpp +++ b/libfswatch/src/libfswatch/c++/windows/win_directory_change_event.hpp @@ -29,9 +29,11 @@ # include # include # include -# include +# include "libfswatch/libfswatch_config.h" +# include # include "win_handle.hpp" # include "win_error_message.hpp" +# include "fswatch_cxx_windows_export.h" # include "../event.hpp" namespace fsw @@ -41,7 +43,7 @@ namespace fsw * wrap Microsoft Windows' `ReadDirectoryChangesW` function and a common * workflow to detect file system changes. */ - class directory_change_event + class FSWATCH_CXX_WINDOWS_EXPORT directory_change_event { public: std::wstring path; @@ -52,7 +54,7 @@ namespace fsw std::unique_ptr overlapped = {static_cast (malloc(sizeof (OVERLAPPED))), free}; win_error_message read_error; - directory_change_event(size_t buffer_length = 16); + explicit directory_change_event(size_t buffer_length = 16); bool is_io_incomplete(); bool is_buffer_overflowed(); bool read_changes_async(); @@ -62,5 +64,5 @@ namespace fsw }; } -#endif /* WIN_DIRECTORY_CHANGE_EVENT_H */ +#endif /* FSW_WIN_DIRECTORY_CHANGE_EVENT_H */ diff --git a/libfswatch/src/libfswatch/c++/windows/win_error_message.cpp b/libfswatch/src/libfswatch/c++/windows/win_error_message.cpp index 1c910649..12769046 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_error_message.cpp +++ b/libfswatch/src/libfswatch/c++/windows/win_error_message.cpp @@ -13,13 +13,20 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -#include "libfswatch/libfswatch_config.h" + +# include "libfswatch/libfswatch_config.h" #ifdef HAVE_WINDOWS -# include "libfswatch/gettext_defs.h" +#define NOWINBASEINTERLOCK +#ifndef _ARM_ +# include +#endif /* !_ARM_ */ +# include +# include +# include + # include "win_error_message.hpp" -# include "libfswatch/c/libfswatch_log.h" using namespace std; diff --git a/libfswatch/src/libfswatch/c++/windows/win_error_message.hpp b/libfswatch/src/libfswatch/c++/windows/win_error_message.hpp index cbcff64d..80842c10 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_error_message.hpp +++ b/libfswatch/src/libfswatch/c++/windows/win_error_message.hpp @@ -26,7 +26,9 @@ # define FSW_WINDOWS_ERROR_MESSAGE_H # include -# include +# include "libfswatch/libfswatch_config.h" +# include +# include "fswatch_cxx_windows_export.h" namespace fsw { @@ -38,7 +40,7 @@ namespace fsw * instance containing the system-defined error message for a Microsoft * Windows' error code. */ - class win_error_message + class FSWATCH_CXX_WINDOWS_EXPORT win_error_message { public: /** diff --git a/libfswatch/src/libfswatch/c++/windows/win_handle.cpp b/libfswatch/src/libfswatch/c++/windows/win_handle.cpp index c449fe79..eede263d 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_handle.cpp +++ b/libfswatch/src/libfswatch/c++/windows/win_handle.cpp @@ -13,13 +13,19 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ + #include "libfswatch/libfswatch_config.h" #ifdef HAVE_WINDOWS -# include "libfswatch/gettext_defs.h" +#ifndef _ARM_ +# include +#endif /* !_ARM_ */ +# include + +# include "gettext_defs.h" # include "win_handle.hpp" -# include "libfswatch/c/libfswatch_log.h" +# include "libfswatch_log.h" using namespace std; diff --git a/libfswatch/src/libfswatch/c++/windows/win_handle.hpp b/libfswatch/src/libfswatch/c++/windows/win_handle.hpp index 0ceaddc8..2f46781f 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_handle.hpp +++ b/libfswatch/src/libfswatch/c++/windows/win_handle.hpp @@ -25,7 +25,13 @@ #ifndef FSW_WINDOWS_HANDLE_H # define FSW_WINDOWS_HANDLE_H -# include +# include "libfswatch/libfswatch_config.h" +#ifndef _ARM_ +# include +#endif /* !_ARM_ */ +# include +# include +# include "fswatch_cxx_windows_export.h" namespace fsw { @@ -34,7 +40,7 @@ namespace fsw * * This class is a movable, non-copyable RAII wrapper on `HANDLE`. */ - class win_handle + class FSWATCH_CXX_WINDOWS_EXPORT win_handle { public: /** diff --git a/libfswatch/src/libfswatch/c++/windows/win_paths.cpp b/libfswatch/src/libfswatch/c++/windows/win_paths.cpp index 3b15db8a..1010b132 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_paths.cpp +++ b/libfswatch/src/libfswatch/c++/windows/win_paths.cpp @@ -13,39 +13,33 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include +#include +#include +#include #include "win_paths.hpp" -#include -#include "../libfswatch_exception.hpp" -#include "../../gettext_defs.h" - -using namespace std; namespace fsw { namespace win_paths { - wstring posix_to_win_w(string path) + std::wstring posix_to_win_w(const std::string &path) { - void * raw_path = cygwin_create_path(CCP_POSIX_TO_WIN_W, path.c_str()); - if (raw_path == nullptr) throw libfsw_exception(_("cygwin_create_path could not allocate memory to convert the path.")); - - wstring win_path(static_cast (raw_path)); - - free(raw_path); - - return win_path; + std::wstring_convert> converter; + return converter.from_bytes(path.c_str()); } - string win_w_to_posix(wstring path) + std::string win_w_to_posix(const std::wstring &path) { - void * raw_path = cygwin_create_path(CCP_WIN_W_TO_POSIX, path.c_str()); - if (raw_path == nullptr) throw libfsw_exception(_("cygwin_create_path could not allocate memory to convert the path.")); - - string posix_path(static_cast (raw_path)); - - free(raw_path); - - return posix_path; + /* + std::wstring_convert> converter; + return converter.to_bytes(path); + */ + std::string str(path.length(), 0); + std::transform(path.begin(), path.end(), str.begin(), [] (wchar_t c) { + return (char)c; + }); + return str; } } } diff --git a/libfswatch/src/libfswatch/c++/windows/win_paths.hpp b/libfswatch/src/libfswatch/c++/windows/win_paths.hpp index 0ea907d8..c2a320b1 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_paths.hpp +++ b/libfswatch/src/libfswatch/c++/windows/win_paths.hpp @@ -27,6 +27,7 @@ # define FSW_WIN_PATHS_HPP # include +# include "fswatch_cxx_windows_export.h" namespace fsw { @@ -44,7 +45,7 @@ namespace fsw * @param path The POSIX path to convert to a Windows path. * @return The converted Windows path. */ - std::wstring posix_to_win_w(std::string path); + FSWATCH_CXX_WINDOWS_EXPORT std::wstring posix_to_win_w(const std::string &path); /** * @brief Converts a Windows path to POSIX. @@ -52,7 +53,7 @@ namespace fsw * @param path The Windows path to convert to POSIX. * @return The converted POSIX path. */ - std::string win_w_to_posix(std::wstring path); + FSWATCH_CXX_WINDOWS_EXPORT std::string win_w_to_posix(const std::wstring &path); } } #endif /* FSW_WIN_PATHS_HPP */ diff --git a/libfswatch/src/libfswatch/c++/windows/win_strings.cpp b/libfswatch/src/libfswatch/c++/windows/win_strings.cpp index 09637627..d7f7c3b5 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_strings.cpp +++ b/libfswatch/src/libfswatch/c++/windows/win_strings.cpp @@ -13,8 +13,14 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include "libfswatch/libfswatch_config.h" + +#ifndef _ARM_ +#include +#endif /* !_ARM_ */ +#include + #include "win_strings.hpp" -#include namespace fsw { @@ -25,10 +31,12 @@ namespace fsw string wstring_to_string(wchar_t * s) { int buf_size = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); - char buf[buf_size]; + char *buf = new char[buf_size]; WideCharToMultiByte(CP_UTF8, 0, s, -1, buf, buf_size, NULL, NULL); - return string(buf); + std::string ret = string(buf); + delete[] buf; + return ret; } string wstring_to_string(const wstring & s) diff --git a/libfswatch/src/libfswatch/c++/windows/win_strings.hpp b/libfswatch/src/libfswatch/c++/windows/win_strings.hpp index ccc8ed33..df937f5a 100644 --- a/libfswatch/src/libfswatch/c++/windows/win_strings.hpp +++ b/libfswatch/src/libfswatch/c++/windows/win_strings.hpp @@ -28,6 +28,7 @@ # include # include +# include "fswatch_cxx_windows_export.h" namespace fsw { @@ -45,7 +46,7 @@ namespace fsw * @param s The @c wchar_t array to convert. * @return The converted string. */ - std::string wstring_to_string(wchar_t *s); + FSWATCH_CXX_WINDOWS_EXPORT std::string wstring_to_string(wchar_t *s); /** * @brief Converts a wide character string into a string. @@ -53,7 +54,7 @@ namespace fsw * @param s The string to convert. * @return The converted string. */ - std::string wstring_to_string(const std::wstring& s); + FSWATCH_CXX_WINDOWS_EXPORT std::string wstring_to_string(const std::wstring& s); } } diff --git a/libfswatch/src/libfswatch/c++/windows_monitor.cpp b/libfswatch/src/libfswatch/c++/windows_monitor.cpp index 0e6572cb..c85b9f4e 100644 --- a/libfswatch/src/libfswatch/c++/windows_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/windows_monitor.cpp @@ -17,24 +17,31 @@ #ifdef HAVE_WINDOWS -# include "libfswatch/gettext_defs.h" -# include "windows_monitor.hpp" -# include "libfswatch_map.hpp" -# include "libfswatch_set.hpp" -# include "libfswatch_exception.hpp" -# include "libfswatch/c/libfswatch_log.h" # include -# include -# include -# include # include # include -# include -# include -# include + +#define NOWINBASEINTERLOCK +#ifndef _ARM_ +# include +#endif /* !_ARM_ */ +# include +# include +# include +# include +# include + +#ifndef _MSC_VER # include -# include -# include +#endif /* _MSC_VER */ + +# include "gettext_defs.h" +# include "windows_monitor.hpp" +# include "libfswatch_map.hpp" +# include "libfswatch_set.hpp" +# include "libfswatch_exception.hpp" +# include "libfswatch_log.h" + # include "./windows/win_handle.hpp" # include "./windows/win_error_message.hpp" # include "./windows/win_strings.hpp" @@ -231,7 +238,12 @@ namespace fsw run_guard.unlock(); #endif - sleep(latency); +#ifdef _MSC_VER + Sleep( 1000L * static_cast( +#else + sleep( ( +#endif + (latency))); for (const auto & path : load->win_paths) { diff --git a/libfswatch/src/libfswatch/c++/windows_monitor.hpp b/libfswatch/src/libfswatch/c++/windows_monitor.hpp index 776c48e3..671cce42 100644 --- a/libfswatch/src/libfswatch/c++/windows_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/windows_monitor.hpp @@ -29,6 +29,7 @@ # include "monitor.hpp" # include # include +# include "cxxfswatch_export.h" namespace fsw { @@ -44,7 +45,7 @@ namespace fsw * This monitor is built upon the `ReadDirectoryChanges` API of the Windows * operating systems. */ - class windows_monitor : public monitor + class CXXFSWATCH_EXPORT windows_monitor : public monitor { public: /** diff --git a/libfswatch/src/libfswatch/c/CMakeLists.txt b/libfswatch/src/libfswatch/c/CMakeLists.txt new file mode 100644 index 00000000..c3826fa0 --- /dev/null +++ b/libfswatch/src/libfswatch/c/CMakeLists.txt @@ -0,0 +1,64 @@ +set(LIBRARY_NAME "c${PACKAGE}") + +set(Header_Files + "cevent.h" + "cfilter.h" + "cmonitor.h" + "fsw_error.h" + "libfswatch.h" + "libfswatch_log.h" + "libfswatch_types.h" + ) +source_group("${LIBRARY_NAME} Header Files" FILES "${Header_Files}") + +set(Source_Files "cevent.cpp" + "libfswatch.cpp" + "libfswatch_log.cpp") + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + list(APPEND Source_Files "windows/realpath.c") +endif (CMAKE_SYSTEM_NAME STREQUAL "Windows") + +source_group("${LIBRARY_NAME} Source Files" FILES "${Source_Files}") + +add_library("${LIBRARY_NAME}" STATIC "${Header_Files}" "${Source_Files}") +if (MSVC) + set_target_properties("${LIBRARY_NAME}" PROPERTIES COMPILE_FLAGS "/EHsc") +endif (MSVC) +target_include_directories( + "${LIBRARY_NAME}" + PUBLIC + "$" + "$" + "$" + "$" + "$" +) + +target_link_libraries("${LIBRARY_NAME}" PRIVATE "cxx${PACKAGE}" "gettext") + +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + C +) + +include(GenerateExportHeader) +set(_export_file "${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}_export.h") +generate_export_header("${LIBRARY_NAME}" EXPORT_FILE_NAME "${_export_file}") + +# setup the version numbering +set_property(TARGET "${LIBRARY_NAME}" PROPERTY VERSION "1.0.0") +set_property(TARGET "${LIBRARY_NAME}" PROPERTY SOVERSION "1") + +# install rules +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif () +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES ${Header_Files} "${_export_file}" DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/libfswatch") diff --git a/libfswatch/src/libfswatch/c/cevent.cpp b/libfswatch/src/libfswatch/c/cevent.cpp index 193cd302..9b65deca 100644 --- a/libfswatch/src/libfswatch/c/cevent.cpp +++ b/libfswatch/src/libfswatch/c/cevent.cpp @@ -16,8 +16,8 @@ #include "cevent.h" #include #include -#include "libfswatch/c++/event.hpp" -#include "libfswatch/c++/libfswatch_exception.hpp" +#include "event.hpp" +#include "libfswatch_exception.hpp" using namespace std; using namespace fsw; @@ -62,7 +62,11 @@ char *fsw_get_event_flag_name(const fsw_event_flag flag) if (cstr == nullptr) return nullptr; +#if defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ || defined(_MSC_VER) + strcpy_s(cstr, name.size() + 1, name.c_str()); +#else strcpy(cstr, name.c_str()); +#endif return cstr; } diff --git a/libfswatch/src/libfswatch/c/cevent.h b/libfswatch/src/libfswatch/c/cevent.h index f5349855..6c8eb13e 100644 --- a/libfswatch/src/libfswatch/c/cevent.h +++ b/libfswatch/src/libfswatch/c/cevent.h @@ -29,6 +29,7 @@ # include # include +# include "cfswatch_export.h" # include "libfswatch_types.h" # ifdef __cplusplus @@ -79,7 +80,7 @@ extern "C" Overflow = (1 << 13) /**< The event queue has overflowed. */ }; - extern const enum fsw_event_flag FSW_ALL_EVENT_FLAGS[15]; + CFSWATCH_EXPORT extern const enum fsw_event_flag FSW_ALL_EVENT_FLAGS[15]; /** * @brief Get event flag by name. @@ -93,7 +94,8 @@ extern "C" * @return #FSW_OK if the functions succeeds, #FSW_ERR_UNKNOWN_VALUE * otherwise. */ - FSW_STATUS fsw_get_event_flag_by_name(const char *name, enum fsw_event_flag *flag); + CFSWATCH_EXPORT + FSW_STATUS fsw_get_event_flag_by_name(const char *name, enum fsw_event_flag *flag); /** * @brief Get the name of an event flag. @@ -104,7 +106,7 @@ extern "C" * @param[in] flag The event flag to look for. * @return The name of @p flag, or @c nullptr if it does not exist. */ - char *fsw_get_event_flag_name(const enum fsw_event_flag flag); + CFSWATCH_EXPORT char *fsw_get_event_flag_name(const enum fsw_event_flag flag); /** * A file change event is represented as an instance of this struct where: @@ -118,7 +120,8 @@ extern "C" char * path; time_t evt_time; enum fsw_event_flag * flags; - unsigned int flags_num; + /* std::vector::size_type flags_num */ + size_t flags_num; } fsw_cevent; /** @@ -134,11 +137,11 @@ extern "C" * a pointer to it. */ typedef void (*FSW_CEVENT_CALLBACK)(fsw_cevent const *const events, - const unsigned int event_num, + const size_t event_num, void *data); # ifdef __cplusplus } -# endif +# endif /* __cplusplus */ #endif /* FSW__CEVENT_H */ diff --git a/libfswatch/src/libfswatch/c/cfilter.h b/libfswatch/src/libfswatch/c/cfilter.h index cf7d08dd..f44669a0 100644 --- a/libfswatch/src/libfswatch/c/cfilter.h +++ b/libfswatch/src/libfswatch/c/cfilter.h @@ -30,7 +30,7 @@ # ifdef __cplusplus extern "C" { -# endif +# endif /* __cplusplus */ /** * @brief Event filter type. @@ -59,6 +59,6 @@ extern "C" # ifdef __cplusplus } -# endif +# endif /* __cplusplus */ -#endif /* FSW__CFILTER_H */ +#endif /* !FSW__CFILTER_H */ diff --git a/libfswatch/src/libfswatch/c/cmonitor.h b/libfswatch/src/libfswatch/c/cmonitor.h index 258f2975..5596d978 100644 --- a/libfswatch/src/libfswatch/c/cmonitor.h +++ b/libfswatch/src/libfswatch/c/cmonitor.h @@ -31,7 +31,7 @@ # ifdef __cplusplus extern "C" { -# endif +# endif /* __cplusplus */ /** * @brief Available monitors. @@ -53,6 +53,6 @@ extern "C" # ifdef __cplusplus } -# endif +# endif /* __cplusplus */ -#endif /* FSW__CMONITOR_H */ +#endif /* !FSW__CMONITOR_H */ diff --git a/libfswatch/src/libfswatch/c/error.h b/libfswatch/src/libfswatch/c/fsw_error.h similarity index 96% rename from libfswatch/src/libfswatch/c/error.h rename to libfswatch/src/libfswatch/c/fsw_error.h index b0d7925d..3caceb1c 100644 --- a/libfswatch/src/libfswatch/c/error.h +++ b/libfswatch/src/libfswatch/c/fsw_error.h @@ -30,7 +30,7 @@ # ifdef __cplusplus extern "C" { -# endif +# endif /* __cplusplus */ // Error codes # define FSW_OK 0 /**< The call was successful. */ @@ -52,6 +52,6 @@ extern "C" # ifdef __cplusplus } -# endif +# endif /* __cplusplus */ -#endif /* FSW__ERROR_H */ +#endif /* !FSW__ERROR_H */ diff --git a/libfswatch/src/libfswatch/c/libfswatch.cpp b/libfswatch/src/libfswatch/c/libfswatch.cpp index bc12997a..4ab5676b 100644 --- a/libfswatch/src/libfswatch/c/libfswatch.cpp +++ b/libfswatch/src/libfswatch/c/libfswatch.cpp @@ -418,8 +418,7 @@ * * - The order in the filter definition has no effect. */ -#include "libfswatch/gettext_defs.h" -#include +#include "gettext_defs.h" #include #include #include @@ -428,11 +427,10 @@ #include #include "libfswatch/libfswatch_config.h" #include "libfswatch.h" -#include "libfswatch/c++/libfswatch_map.hpp" -#include "libfswatch/c++/filter.hpp" -#include "libfswatch/c++/monitor.hpp" -#include "libfswatch/c++/monitor_factory.hpp" -#include "libfswatch/c++/libfswatch_exception.hpp" +#include "filter.hpp" +#include "monitor.hpp" +#include "monitor_factory.hpp" +#include "libfswatch_exception.hpp" using namespace std; using namespace fsw; @@ -512,7 +510,11 @@ void libfsw_cpp_callback_proxy(const std::vector& events, sizeof(char *) * (path.length() + 1))); if (!cevt->path) throw int(FSW_ERR_MEMORY); +#if defined(__STDC_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ || defined(_MSC_VER) + strncpy_s(cevt->path, strlen(cevt->path) + 1, path.c_str(), path.length()); +#else strncpy(cevt->path, path.c_str(), path.length()); +#endif cevt->path[path.length()] = '\0'; cevt->evt_time = evt.get_time(); @@ -543,7 +545,7 @@ void libfsw_cpp_callback_proxy(const std::vector& events, fsw_cevent *cevt = &cevents[i]; if (cevt->flags) free(static_cast (cevt->flags)); - free(static_cast (cevt->path)); + if (cevt->path != NULL) free(static_cast (cevt->path)); } free(static_cast (cevents)); diff --git a/libfswatch/src/libfswatch/c/libfswatch.h b/libfswatch/src/libfswatch/c/libfswatch.h index 287f3b53..7f38afb8 100644 --- a/libfswatch/src/libfswatch/c/libfswatch.h +++ b/libfswatch/src/libfswatch/c/libfswatch.h @@ -30,15 +30,16 @@ #include #include "libfswatch_types.h" +#include "cfswatch_export.h" #include "cevent.h" #include "cmonitor.h" #include "cfilter.h" -#include "error.h" +#include "fsw_error.h" # ifdef __cplusplus extern "C" { -# endif +# endif /* __cplusplus */ /** * The `libfswatch` C API let users create monitor sessions and receive file @@ -90,7 +91,7 @@ extern "C" * returns FSW_OK, otherwise the initialization routine failed and the library * should not be usable. */ - FSW_STATUS fsw_init_library(); + CFSWATCH_EXPORT FSW_STATUS fsw_init_library(); /** * This function creates a new monitor session using the specified monitor @@ -99,24 +100,24 @@ extern "C" * * @see cmonitor.h for a list of all the available monitors. */ - FSW_HANDLE fsw_init_session(const enum fsw_monitor_type type); + CFSWATCH_EXPORT FSW_HANDLE fsw_init_session(const enum fsw_monitor_type type); /** * Adds a path to watch to the specified session. At least one path must be * added to the current session in order for it to be valid. */ - FSW_STATUS fsw_add_path(const FSW_HANDLE handle, const char * path); + CFSWATCH_EXPORT FSW_STATUS fsw_add_path(const FSW_HANDLE handle, const char * path); /** * Adds the specified monitor property. */ - FSW_STATUS fsw_add_property(const FSW_HANDLE handle, const char * name, const char * value); + CFSWATCH_EXPORT FSW_STATUS fsw_add_property(const FSW_HANDLE handle, const char * name, const char * value); /** * Sets the allow overflow flag of the monitor. When this flag is set, a * monitor is allowed to overflow and report it as a change event. */ - FSW_STATUS fsw_set_allow_overflow(const FSW_HANDLE handle, const bool allow_overflow); + CFSWATCH_EXPORT FSW_STATUS fsw_set_allow_overflow(const FSW_HANDLE handle, const bool allow_overflow); /** * Sets the callback the monitor invokes when some events are received. The @@ -124,42 +125,42 @@ extern "C" * * See cevent.h for the definition of FSW_CEVENT_CALLBACK. */ - FSW_STATUS fsw_set_callback(const FSW_HANDLE handle, - const FSW_CEVENT_CALLBACK callback, - void * data); + CFSWATCH_EXPORT FSW_STATUS fsw_set_callback(const FSW_HANDLE handle, + const FSW_CEVENT_CALLBACK callback, + void * data); /** * Sets the latency of the monitor. By default, the latency is set to 1 s. */ - FSW_STATUS fsw_set_latency(const FSW_HANDLE handle, const double latency); + CFSWATCH_EXPORT FSW_STATUS fsw_set_latency(const FSW_HANDLE handle, const double latency); /** * Determines whether the monitor recursively scans each watched path or not. * Recursive scanning is an optional feature which could not be implemented * by all the monitors. By default, recursive scanning is disabled. */ - FSW_STATUS fsw_set_recursive(const FSW_HANDLE handle, const bool recursive); + CFSWATCH_EXPORT FSW_STATUS fsw_set_recursive(const FSW_HANDLE handle, const bool recursive); /** * Determines whether the monitor only watches a directory when performing a * recursive scan. By default, a monitor accepts all kinds of files. */ - FSW_STATUS fsw_set_directory_only(const FSW_HANDLE handle, const bool directory_only); + CFSWATCH_EXPORT FSW_STATUS fsw_set_directory_only(const FSW_HANDLE handle, const bool directory_only); /** * Determines whether a symbolic link is followed or not. By default, a * symbolic link are not followed. */ - FSW_STATUS fsw_set_follow_symlinks(const FSW_HANDLE handle, - const bool follow_symlinks); + CFSWATCH_EXPORT FSW_STATUS fsw_set_follow_symlinks(const FSW_HANDLE handle, + const bool follow_symlinks); /** * Adds an event type filter to the current session. * * See cfilter.h for the definition of fsw_event_type_filter. */ - FSW_STATUS fsw_add_event_type_filter(const FSW_HANDLE handle, - const fsw_event_type_filter event_type); + CFSWATCH_EXPORT FSW_STATUS fsw_add_event_type_filter(const FSW_HANDLE handle, + const fsw_event_type_filter event_type); /** * Adds a filter to the current session. A filter is a regular expression @@ -168,8 +169,8 @@ extern "C" * * See cfilter.h for the definition of fsw_cmonitor_filter. */ - FSW_STATUS fsw_add_filter(const FSW_HANDLE handle, - const fsw_cmonitor_filter filter); + CFSWATCH_EXPORT FSW_STATUS fsw_add_filter(const FSW_HANDLE handle, + const fsw_cmonitor_filter filter); /** * Starts the monitor if it is properly configured. Depending on the type of @@ -180,35 +181,35 @@ extern "C" /** * Stops a running monitor. */ - FSW_STATUS fsw_stop_monitor(const FSW_HANDLE handle); + CFSWATCH_EXPORT FSW_STATUS fsw_stop_monitor(const FSW_HANDLE handle); /** * Checks if a monitor exists and is running. */ - bool fsw_is_running(const FSW_HANDLE handle); + CFSWATCH_EXPORT bool fsw_is_running(const FSW_HANDLE handle); /** * Destroys an existing session and invalidates its handle. */ - FSW_STATUS fsw_destroy_session(const FSW_HANDLE handle); + CFSWATCH_EXPORT FSW_STATUS fsw_destroy_session(const FSW_HANDLE handle); /** * Gets the last error code. */ - FSW_STATUS fsw_last_error(); + CFSWATCH_EXPORT FSW_STATUS fsw_last_error(); /** * Check whether the verbose mode is active. */ - bool fsw_is_verbose(); + CFSWATCH_EXPORT bool fsw_is_verbose(); /** * Set the verbose mode. */ - void fsw_set_verbose(bool verbose); + CFSWATCH_EXPORT void fsw_set_verbose(bool verbose); # ifdef __cplusplus } -# endif +# endif /* __cplusplus */ -#endif /* LIBFSW_H */ +#endif /* !LIBFSW_H */ diff --git a/libfswatch/src/libfswatch/c/libfswatch_log.h b/libfswatch/src/libfswatch/c/libfswatch_log.h index f0613288..72bfbcd3 100644 --- a/libfswatch/src/libfswatch/c/libfswatch_log.h +++ b/libfswatch/src/libfswatch/c/libfswatch_log.h @@ -27,39 +27,40 @@ # define LIBFSW_LOG_H #include +#include "cfswatch_export.h" /** * Prints the specified message to standard output. */ -void fsw_log(const char * msg); +CFSWATCH_EXPORT void fsw_log(const char * msg); /** * Prints the specified message to the specified file. */ -void fsw_flog(FILE * f, const char * msg); +CFSWATCH_EXPORT void fsw_flog(FILE * f, const char * msg); /** * Formats the specified message and prints it to standard output. The message * string format conforms with printf. */ -void fsw_logf(const char * format, ...); +CFSWATCH_EXPORT void fsw_logf(const char * format, ...); /** * Formats the specified message and prints it to the specified file. The * message string format conforms with printf. */ -void fsw_flogf(FILE * f, const char * format, ...); +CFSWATCH_EXPORT void fsw_flogf(FILE * f, const char * format, ...); /** * Prints the specified message using perror. */ -void fsw_log_perror(const char * msg); +CFSWATCH_EXPORT void fsw_log_perror(const char * msg); /** * Prints the specified message using perror. The message string format * conforms with printf. */ -void fsw_logf_perror(const char * format, ...); +CFSWATCH_EXPORT void fsw_logf_perror(const char * format, ...); /** * @brief Log the specified message to the standard output prepended by the @@ -91,4 +92,4 @@ void fsw_logf_perror(const char * format, ...); */ # define FSW_FLOGF(f, msg, ...) fsw_flogf(f, "%s: ", __func__); fsw_flogf(f, msg, __VA_ARGS__) -#endif /* LIBFSW_LOG_H */ +#endif /* !LIBFSW_LOG_H */ diff --git a/libfswatch/src/libfswatch/c/libfswatch_types.h b/libfswatch/src/libfswatch/c/libfswatch_types.h index 42ca90c8..3290145c 100644 --- a/libfswatch/src/libfswatch/c/libfswatch_types.h +++ b/libfswatch/src/libfswatch/c/libfswatch_types.h @@ -33,7 +33,7 @@ #ifdef __cplusplus extern "C" { -#endif +#endif /* __cplusplus */ /** * @brief Opaque type representing a monitoring session. @@ -54,10 +54,10 @@ typedef int FSW_STATUS; # define FSW_THREAD_LOCAL thread_local #else # define FSW_THREAD_LOCAL -#endif +#endif /* defined(HAVE_CXX_THREAD_LOCAL) */ #ifdef __cplusplus } -#endif +#endif /* __cplusplus */ -#endif /* LIBFSWATCH_TYPES_H */ +#endif /* !LIBFSWATCH_TYPES_H */ diff --git a/libfswatch/src/libfswatch/c/windows/realpath.c b/libfswatch/src/libfswatch/c/windows/realpath.c index 64154d61..59596fa9 100755 --- a/libfswatch/src/libfswatch/c/windows/realpath.c +++ b/libfswatch/src/libfswatch/c/windows/realpath.c @@ -21,9 +21,9 @@ #include #include #include +#include "cfswatch_export.h" -_CRTIMP char __cdecl -*realpath( const char *__restrict__ name, char *__restrict__ resolved ) +CFSWATCH_EXPORT char *realpath( const char * name, char * resolved ) { char *retname = NULL; /* we will return this, if we fail */ @@ -38,7 +38,7 @@ _CRTIMP char __cdecl * if we are going to resolve its absolute path name. */ - else if( access( name, 4 ) == 0 ) + else if( _access( name, 4 ) == 0 ) { /* If `name' didn't point to an existing entity, * then we don't get to here; we simply fall past this block, diff --git a/libfswatch/src/libfswatch/gettext/CMakeLists.txt b/libfswatch/src/libfswatch/gettext/CMakeLists.txt new file mode 100644 index 00000000..90332715 --- /dev/null +++ b/libfswatch/src/libfswatch/gettext/CMakeLists.txt @@ -0,0 +1,102 @@ +# +# Copyright (c) 2014-2021 Enrico M. Crisostomo +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . +# + +set(LIBRARY_NAME "gettext") + +# Define symbols to conditionally define FSEvents flags +if (APPLE) + if ("${CMAKE_SYSTEM_VERSION}" VERSION_GREATER_EQUAL "9.0") + set(HAVE_MACOS_GE_10_5 1) + endif () + + if ("${CMAKE_SYSTEM_VERSION}" VERSION_GREATER_EQUAL "11.0") + set(HAVE_MACOS_GE_10_7 1) + endif () + + if ("${CMAKE_SYSTEM_VERSION}" VERSION_GREATER_EQUAL "13.0") + set(HAVE_MACOS_GE_10_9 1) + endif () + + if ("${CMAKE_SYSTEM_VERSION}" VERSION_GREATER_EQUAL "14.0") + set(HAVE_MACOS_GE_10_10 1) + endif () +endif (APPLE) + +set(Header_Files "gettext.h" "gettext_defs.h") + +check_include_file_cxx(mutex HAVE_CXX_MUTEX) + +if (NOT HAVE_CXX_MUTEX) + message(WARNING "${PROJECT_NAME} is not thread-safe because required C++11 library classes are not available.") +endif (NOT HAVE_CXX_MUTEX) + +check_include_file_cxx(atomic HAVE_CXX_ATOMIC) + +if (NOT HAVE_CXX_ATOMIC) + message(WARNING " unavailable: some functionalities will not be built.") +endif (NOT HAVE_CXX_ATOMIC) + +check_cxx_symbol_exists(modf "math.h" HAVE_MODF) +check_cxx_symbol_exists(realpath cstdlib HAVE_REALPATH) +check_cxx_symbol_exists(select "sys/select.h" HAVE_SELECT) +check_struct_has_member("struct stat" st_mtime "sys/stat.h" HAVE_STRUCT_STAT_ST_MTIME) +check_struct_has_member("struct stat" st_mtimespec "sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC) +check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP) +check_include_file_cxx(unordered_set HAVE_UNORDERED_SET) + +if (cxx_thread_local IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(HAVE_CXX_THREAD_LOCAL ON CACHE BOOL "Enable C++ thread_local support") +endif (cxx_thread_local IN_LIST CMAKE_CXX_COMPILE_FEATURES) + +source_group("${LIBRARY_NAME} Header Files" FILES "${Header_Files}") + +add_library("${LIBRARY_NAME}" INTERFACE "${Header_Files}") +set_target_properties("${LIBRARY_NAME}" PROPERTIES PREFIX "") + +# check for gettext and libintl +if (USE_NLS AND Intl_LIBRARIES) + set(intl_nls_libs "${Intl_LIBRARIES}") + if (VCPKG_TOOLCHAIN) + find_package(Iconv REQUIRED) + list(APPEND intl_nls_libs "Iconv::Charset" "Iconv::Iconv") + endif (VCPKG_TOOLCHAIN) + target_link_libraries("${LIBRARY_NAME}" INTERFACE "${intl_nls_libs}") +endif (USE_NLS AND Intl_LIBRARIES) +target_include_directories("${LIBRARY_NAME}" INTERFACE "${Intl_INCLUDE_DIRS}") + +target_include_directories( + "${LIBRARY_NAME}" + INTERFACE + "$" + "$" +) +set_target_properties( + "${LIBRARY_NAME}" + PROPERTIES + LINKER_LANGUAGE + C +) + +set(installable_libs "${LIBRARY_NAME}") +if (TARGET "${DEPENDANT_LIBRARY}") + list(APPEND installable_libs "${DEPENDANT_LIBRARY}") +endif (TARGET "${DEPENDANT_LIBRARY}") +install(TARGETS ${installable_libs} + DESTINATION "lib" + EXPORT "${LIBRARY_NAME}Targets") +install(FILES ${Header_Files} + DESTINATION "include") +install(EXPORT "${LIBRARY_NAME}Targets" DESTINATION "share/libfswatch") diff --git a/libfswatch/src/libfswatch/gettext.h b/libfswatch/src/libfswatch/gettext/gettext.h similarity index 91% rename from libfswatch/src/libfswatch/gettext.h rename to libfswatch/src/libfswatch/gettext/gettext.h index 841b072b..eb9121b5 100644 --- a/libfswatch/src/libfswatch/gettext.h +++ b/libfswatch/src/libfswatch/gettext/gettext.h @@ -34,7 +34,7 @@ # undef ngettext # define ngettext(Msgid1, Msgid2, N) \ dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) -# endif +# endif /* DEFAULT_TEXT_DOMAIN */ #else @@ -46,7 +46,7 @@ is OK. */ #if defined(__sun) # include -#endif +#endif /* defined(__sun) */ /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include @@ -55,8 +55,8 @@ # include # if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H # include -# endif -#endif +# endif /* (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H */ +#endif /* defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) */ /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings @@ -90,13 +90,13 @@ # define bind_textdomain_codeset(Domainname, Codeset) \ ((void) (Domainname), (const char *) (Codeset)) -#endif +#endif /* ENABLE_NLS */ /* Prefer gnulib's setlocale override over libintl's setlocale override. */ #ifdef GNULIB_defined_setlocale # undef setlocale # define setlocale rpl_setlocale -#endif +#endif /* GNULIB_defined_setlocale */ /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time @@ -120,7 +120,7 @@ #else # define pgettext(Msgctxt, Msgid) \ pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) -#endif +#endif /* DEFAULT_TEXT_DOMAIN */ #define dpgettext(Domainname, Msgctxt, Msgid) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ @@ -131,7 +131,7 @@ #else # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) -#endif +#endif /* DEFAULT_TEXT_DOMAIN */ #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ @@ -142,8 +142,8 @@ __inline #else #ifdef __cplusplus inline -#endif -#endif +#endif /* __cplusplus */ +#endif /* __GNUC__ */ static const char * pgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, @@ -161,8 +161,8 @@ __inline #else #ifdef __cplusplus inline -#endif -#endif +#endif /* __cplusplus */ +#endif /* __GNUC__ */ static const char * npgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, @@ -188,11 +188,11 @@ npgettext_aux (const char *domain, # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1 #else # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0 -#endif +#endif /* (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) */ #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #include -#endif +#endif /* !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS */ #define pgettext_expr(Msgctxt, Msgid) \ dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) @@ -204,8 +204,8 @@ __inline #else #ifdef __cplusplus inline -#endif -#endif +#endif /* __cplusplus */ +#endif /* __GNUC__ */ static const char * dcpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, @@ -223,7 +223,7 @@ dcpgettext_expr (const char *domain, ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) -#endif +#endif /* _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS */ { int found_translation; memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); @@ -234,7 +234,7 @@ dcpgettext_expr (const char *domain, #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); -#endif +#endif /* !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS */ if (found_translation) return translation; } @@ -251,8 +251,8 @@ __inline #else #ifdef __cplusplus inline -#endif -#endif +#endif /* __cplusplus */ +#endif /* __GNUC__ */ static const char * dcnpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, @@ -271,7 +271,7 @@ dcnpgettext_expr (const char *domain, ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) -#endif +#endif /* _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS */ { int found_translation; memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); @@ -282,11 +282,11 @@ dcnpgettext_expr (const char *domain, #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); -#endif +#endif /* !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS */ if (found_translation) return translation; } return (n == 1 ? msgid : msgid_plural); } -#endif /* _LIBGETTEXT_H */ +#endif /* !_LIBGETTEXT_H */ diff --git a/libfswatch/src/libfswatch/gettext_defs.h b/libfswatch/src/libfswatch/gettext/gettext_defs.h similarity index 90% rename from libfswatch/src/libfswatch/gettext_defs.h rename to libfswatch/src/libfswatch/gettext/gettext_defs.h index b5d127a6..eb4bedf2 100644 --- a/libfswatch/src/libfswatch/gettext_defs.h +++ b/libfswatch/src/libfswatch/gettext/gettext_defs.h @@ -22,12 +22,12 @@ # ifdef __cplusplus extern "C" { -# endif +# endif /* __cplusplus */ #define _(String) gettext(String) # ifdef __cplusplus } -# endif +# endif /* __cplusplus */ -#endif /* FSW_GETTEXT_DEFS_H */ +#endif /* !FSW_GETTEXT_DEFS_H */ diff --git a/m4/fswatch_version.m4 b/m4/fswatch_version.m4 index 6e365ad9..5b75ffdd 100644 --- a/m4/fswatch_version.m4 +++ b/m4/fswatch_version.m4 @@ -13,5 +13,5 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . # -m4_define([FSWATCH_VERSION], [1.16.0]) +m4_define([FSWATCH_VERSION], [1.17.0]) m4_define([FSWATCH_REVISION], [1]) diff --git a/m4/libfswatch_version.m4 b/m4/libfswatch_version.m4 index dde61911..af0ea4e3 100644 --- a/m4/libfswatch_version.m4 +++ b/m4/libfswatch_version.m4 @@ -37,6 +37,6 @@ # # Libtool documentation, 7.3 Updating library version information # -m4_define([LIBFSWATCH_VERSION], [1.16.0]) +m4_define([LIBFSWATCH_VERSION], [1.17.0]) m4_define([LIBFSWATCH_API_VERSION], [11:3:0]) m4_define([LIBFSWATCH_REVISION], [1]) diff --git a/po/fswatch.pot b/po/fswatch.pot index 96a6403b..ff4e13cc 100644 --- a/po/fswatch.pot +++ b/po/fswatch.pot @@ -6,7 +6,7 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: fswatch 1.16.0\n" +"Project-Id-Version: fswatch 1.17.0\n" "Report-Msgid-Bugs-To: enrico.m.crisostomo@gmail.com\n" "POT-Creation-Date: 2021-06-02 17:26+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" diff --git a/test/src/CMakeLists.txt b/test/src/CMakeLists.txt index 9628ba07..88b95d7e 100644 --- a/test/src/CMakeLists.txt +++ b/test/src/CMakeLists.txt @@ -13,13 +13,36 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . # -include_directories(../.. .) +set(EXEC_NAME "${PACKAGE}_test") -set(SOURCE_FILES - fswatch_test.c - ${PROJECT_BINARY_DIR}/libfswatch/libfswatch_config.h) +set(Header_Files "${PROJECT_BINARY_DIR}/libfswatch/libfswatch_config.h") +source_group("${EXEC_NAME} Header Files" FILES "${Header_Files}") -add_executable(fswatch_test ${SOURCE_FILES}) -target_include_directories(fswatch_test PRIVATE ${PROJECT_BINARY_DIR}) +set(Source_Files "${EXEC_NAME}.c") +source_group("${EXEC_NAME} Source Files" FILES "${Source_Files}") -target_link_libraries(fswatch_test LINK_PUBLIC libfswatch) \ No newline at end of file +add_executable("${EXEC_NAME}" "${Header_Files}" "${Source_Files}") + +if (MSVC) + find_package(pthreads QUIET) + if (PTHREADS4W_FOUND) + set(PTHREAD_LIBRARY "PThreads4W::PThreads4W") + else () + include("${CMAKE_SOURCE_DIR}/CMake/FindPthreads.cmake") + set(PTHREAD_LIBRARY ${PTHREADS_LIBRARIES}) + endif (PTHREADS4W_FOUND) + + # set(EXTRA_LIBS ${EXTRA_LIBS} "advapi32") +else () + find_library(PTHREAD_LIBRARY pthread) +endif (MSVC) +target_link_libraries("${EXEC_NAME}" PRIVATE "${PTHREAD_LIBRARY}") + +set_target_properties( + "${EXEC_NAME}" + PROPERTIES + LINKER_LANGUAGE + C +) + +target_link_libraries("${EXEC_NAME}" LINK_PUBLIC "libfswatch") diff --git a/test/src/fswatch_test.c b/test/src/fswatch_test.c index 10f01b34..e4919ca5 100644 --- a/test/src/fswatch_test.c +++ b/test/src/fswatch_test.c @@ -1,8 +1,14 @@ #include #include -#include + +#include #include -#include + +#ifdef _MSC_VER +# include +#else +# include +#endif /* _MSC_VER */ /** * $ ${CC} -I /usr/local/include -o "fswatch_test" fswatch_test.c /usr/local/lib/libfswatch.dylib @@ -18,10 +24,10 @@ * @param data */ void my_callback(fsw_cevent const *const events, - const unsigned int event_num, + const size_t event_num, void *data) { - printf("my_callback: %d\n", event_num); + printf("my_callback: %zu\n", event_num); } void *start_monitor(void *param) @@ -45,14 +51,14 @@ int main(int argc, char **argv) if (argc < 2) { printf("usage: %s [path]\n", argv[0]); - return 1; + return EXIT_FAILURE; } if (FSW_OK != fsw_init_library()) { fsw_last_error(); printf("libfswatch cannot be initialised!\n"); - return 1; + return EXIT_FAILURE; } FSW_HANDLE handle = fsw_init_session(fsevents_monitor_type); @@ -84,10 +90,15 @@ int main(int argc, char **argv) if (pthread_create(&start_thread, NULL, start_monitor, (void *) &handle)) { fprintf(stderr, "Error creating thread\n"); - return 1; + return EXIT_FAILURE; } - sleep(5); +#ifdef _MSC_VER + Sleep(1000* +#else + sleep( +#endif + 5); if (FSW_OK != fsw_stop_monitor(handle)) { @@ -95,12 +106,17 @@ int main(int argc, char **argv) return 1; } - sleep(3); +#ifdef _MSC_VER + Sleep(1000* +#else + sleep( +#endif + 3); if (FSW_OK != fsw_destroy_session(handle)) { fprintf(stderr, "Error destroying session\n"); - return 1; + return EXIT_FAILURE; } // Wait for the monitor thread to finish @@ -110,5 +126,5 @@ int main(int argc, char **argv) return 2; } - return 0; + return EXIT_SUCCESS; }