msvc support
authorMichael Wallner <mike@php.net>
Thu, 3 Dec 2020 10:53:42 +0000 (11:53 +0100)
committerMichael Wallner <mike@php.net>
Thu, 3 Dec 2020 10:54:52 +0000 (11:54 +0100)
39 files changed:
.github/workflows/cmake-build-ci.gen
.github/workflows/cmake-build-ci.yml
CMake/CheckDebug.cmake
CMake/CheckThreads.cmake
CMake/_Include.cmake
CMakeConfig.txt
README.md
contrib/bin/memaslap/CMakeLists.txt
include/libmemcached-1.0/configure.h.in
include/libmemcached-1.0/memcached.h
include/libmemcachedprotocol-0.0/binary.h
include/libmemcachedprotocol-0.0/callback.h
include/libmemcachedprotocol-0.0/handler.h
src/bin/common/CMakeLists.txt
src/bin/common/options.cpp
src/bin/common/options.hpp
src/bin/common/random.hpp
src/bin/memcapable.cc
src/bin/memcp.cc
src/libhashkit/common.h
src/libmemcached/CMakeLists.txt
src/libmemcached/byteorder.h
src/libmemcached/callback.cc
src/libmemcached/common.h
src/libmemcached/connect.cc
src/libmemcached/do.cc
src/libmemcached/error.cc
src/libmemcached/poll.cc
src/libmemcached/poll.h
src/libmemcached/socket.hpp
src/libmemcached/windows.hpp
src/libmemcachedprotocol/CMakeLists.txt
src/libmemcachedprotocol/cache.c
src/libmemcachedprotocol/cache.h
src/libmemcachedutil/CMakeLists.txt
src/libmemcachedutil/common.h
src/win32/getopt.c [new file with mode: 0644]
src/win32/getopt.h [new file with mode: 0644]
src/win32/wrappers.h

index d7f7679edcd6e405a73bccaf56ab066683a988c7..1c758836eca17c9ee28e1d5806b4974fedb1c2fb 100755 (executable)
@@ -6,8 +6,10 @@ echo "# Generated file; do not edit!\n";
 const DEF = [
   "os" => "Linux",
   "Linux" => "ubuntu-20.04",
+  "Windows" => "windows-2019",
   "macOS" => "macos-10.15",
   "ubuntu-20.04" => "gnu",
+  "windows-2019" => "msvc",
   "macos-10.15" => "clang",
   "gnu" => [
     "ver" => "cur",
@@ -19,6 +21,11 @@ const DEF = [
     "CC"  => "clang",
     "CXX"  => "clang++",
   ],
+  "msvc" => [ // dummy
+    "ver" => "cur",
+    "CC" => "msvc",
+    "CXX" => "msvc",
+  ],
 ];
 const ENV = [
   "ubuntu-20.04" => [
@@ -74,7 +81,16 @@ const MAP = [
           ]
         ]
       ]
-    ]
+    ],
+    "windows-2019" => [
+      'env.CC_VND' => [
+        "msvc" => [
+          'env.CC_VER' => [
+            "cur" => "2019",
+          ],
+        ],
+      ],
+    ],
   ]
 ];
 
@@ -294,6 +310,29 @@ jobs:
 <?php steps(false); ?>
       - uses: codecov/codecov-action@v1.0.13
 
+  # win build
+  win-msvc:
+    name: win-msvc (<?=DEF["Windows"]?>, <?=DEF[DEF["Windows"]]?>, <?=DEF[DEF[DEF["Windows"]]]["ver"]?>)
+    runs-on: <?=DEF["Windows"]?> #
+    env:
+      CMAKE_BUILD_TYPE: Release
+      BUILD_TESTING:    "OFF"
+      BISON_ROOT:       "C:/msys64/usr"
+      FLEX_ROOT:        "C:/msys64/usr"
+      OS_VND: Windows
+      OS_VER: <?=DEF["Windows"]?> #
+      CC_VND: <?=DEF[DEF["Windows"]]?> #
+      CC_VER: <?=DEF[DEF[DEF["Windows"]]]["ver"]?> #
+    continue-on-error: true
+    steps:
+      - uses: actions/checkout@v2
+      - name: Generate build tree (${{ env.CMAKE_BUILD_TYPE }})
+        run: cmake --config ${{ env.CMAKE_BUILD_TYPE }} -S . -B build
+      - name: Build all with ${{ env.CC_VND }}
+        run: cmake --build build --config ${{ env.CMAKE_BUILD_TYPE }}
+      - name: Install
+        run: cmake --install build --prefix installed --config ${{ env.CMAKE_BUILD_TYPE }}
+
   # release builds
   release:
     strategy:
index 4a52dc76b1be8bb26cf3294558f09c63e60e78e0..1b45af18a9d73400426542f5888fa8e71b910aa2 100644 (file)
@@ -6,7 +6,7 @@ on:
       - "include/**"
       - "src/**"
       - "test/**"
-      - "**CMake**"
+      - "CMake*"
       - ".github/workflows/cmake-build-ci*"
     branches-ignore:
       - gh-pages
@@ -346,6 +346,29 @@ jobs:
             --data-urlencode "message=Github [${GITHUB_REPOSITORY}](https://github.com/${GITHUB_REPOSITORY}/commits/${REF}) (${REF}) [failure](https://github.com/m6w6/libmemcached/actions/runs/${GITHUB_RUN_ID}) (${ImageOS}/${CC:-${CC_VND}-${CC_VER}})"
       - uses: codecov/codecov-action@v1.0.13
 
+  # win build
+  win-msvc:
+    name: win-msvc (windows-2019, msvc, cur)
+    runs-on: windows-2019 #
+    env:
+      CMAKE_BUILD_TYPE: Release
+      BUILD_TESTING:    "OFF"
+      BISON_ROOT:       "C:/msys64/usr"
+      FLEX_ROOT:        "C:/msys64/usr"
+      OS_VND: Windows
+      OS_VER: windows-2019 #
+      CC_VND: msvc #
+      CC_VER: cur #
+    continue-on-error: true
+    steps:
+      - uses: actions/checkout@v2
+      - name: Generate build tree (${{ env.CMAKE_BUILD_TYPE }})
+        run: cmake --config ${{ env.CMAKE_BUILD_TYPE }} -S . -B build
+      - name: Build all with ${{ env.CC_VND }}
+        run: cmake --build build --config ${{ env.CMAKE_BUILD_TYPE }}
+      - name: Install
+        run: cmake --install build --prefix installed --config ${{ env.CMAKE_BUILD_TYPE }}
+
   # release builds
   release:
     strategy:
@@ -427,6 +450,11 @@ jobs:
           echo CC="clang-6.0" >> ${GITHUB_ENV}
           echo CXX="clang++-6.0" >> ${GITHUB_ENV}
           echo CXXFLAGS="-stdlib=libc++" >> ${GITHUB_ENV}
+      - name: Prepare environment (for cur msvc on windows-2019)
+        if: (env.OS_VER=='windows-2019') && (env.CC_VND=='msvc') && (env.CC_VER=='cur')
+        run: |
+          echo CC="msvc2019" >> ${GITHUB_ENV}
+          echo CXX="msvc2019" >> ${GITHUB_ENV}
       - name: Install dependencies (Linux)
         if: runner.os == 'Linux'
         run: |
index b83406d8f2a0af065d1162e6b0c769f3a34ceeaf..fb188529afed4551c3daa189a65159e1b81405e4 100644 (file)
@@ -32,7 +32,7 @@ macro(check_sanitizer VAR NAME LIB)
     endif()
 endmacro()
 
-if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT MSVC)
     add_definitions(-DDEBUG=1)
     if(CMAKE_CXX_FLAGS MATCHES --coverage)
         message("-- Coverage build detected!")
index 785d8a6e45dde751fb184489d3d738ebee75d9ca..8c79c2dfaa85be9db89d2c473055c31d644f806c 100644 (file)
@@ -1,3 +1,4 @@
+configure_define(HAVE_PTHREAD_H)
 set(THREADS_PREFER_PTHREAD_FLAG ON)
 set(CMAKE_THREAD_PREFER_PTHREAD ON)
-find_package(Threads REQUIRED)
+find_package(Threads)
index 7c1b546d24040f331d3d3714b1b143c630b350c9..6f9a092bf641f40e67651db01c86f85e7abda741 100644 (file)
@@ -118,21 +118,21 @@ configure_set(HAVE_HSIEH_HASH ${ENABLE_HASH_HSIEH})
 check_include(alloca.h)
 check_include(arpa/inet.h)
 check_include(dlfcn.h)
+check_include(getopt.h)
+check_include(libgen.h)
 check_include(netdb.h)
 check_include(poll.h)
 check_include(strings.h)
+check_include(sys/poll.h)
 check_include(sys/socket.h)
 check_include(sys/time.h)
 check_include(sys/un.h)
 check_include(unistd.h)
 
-if(WIN32)
-    check_include(io.h)
-    check_include(winsock2.h)
-    check_include(ws2tcpip.h)
-endif()
-
 check_type(in_port_t netinet/in.h)
+check_type(pid_t sys/types.h)
+check_type(ssize_t sys/types.h)
+check_type("struct msghdr" sys/socket.h)
 
 check_cxx_symbol(abi::__cxa_demangle cxxabi.h)
 check_symbol(fcntl fcntl.h)
@@ -142,6 +142,7 @@ check_symbol(MSG_MORE sys/socket.h)
 check_symbol(MSG_NOSIGNAL sys/socket.h)
 check_symbol(SO_RCVTIMEO sys/socket.h)
 check_symbol(SO_SNDTIMEO sys/socket.h)
+check_symbol(sendmsg sys/socket.h)
 check_symbol(setenv stdlib.h)
 check_symbol(strerror_r string.h)
 check_c_source("
@@ -152,3 +153,11 @@ check_c_source("
         }"
         HAVE_STRERROR_R_CHAR_P
 )
+
+if(WIN32)
+    check_include(io.h)
+    check_include(winsock2.h)
+    check_include(ws2tcpip.h)
+
+    check_symbol(htonll winsock2.h)
+endif()
index 4d17185f4f9a7b059d40ec3f0839bdd8426bff46..b8c60a761693eefc0677b945848f089d0e372865 100644 (file)
@@ -80,10 +80,6 @@ if(BUILD_DOCS)
         CACHE STRING "append verbatim code to sphinx' conf.py")
 endif()
 
-# legacy
-
-set(HAVE_VISIBILITY 1)
-
 # modules
 
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake")
index 9a6b9d3fcff365477e0af5ef3c45f6310ddffeda..e881e057b01584572b2ddeb3181629d88aa6a4dc 100644 (file)
--- a/README.md
+++ b/README.md
@@ -48,6 +48,20 @@ set any preferred options.
     make
     sudo make install
 
+#### Requirements
+
+* CMake 3.9+
+* A C++11 compiler
+* GNU Bison 2.3+ and Flex
+
+##### Optional dependencies
+
+* A C++17 compiler (tests: required)
+* Intel's libtbb (tests: optional for GCC's stdlib parallelism support)
+* PThreads (tests, contrib/bin/memaslap, libmemcachedutil/pool)
+* libevent (contrib/bin/memaslap)
+* Cyrus' libsasl2 (libmemacached/sasl)
+
 ## Testing
 
 [![Codecov Badge]](https://codecov.io/gh/m6w6/libmemcached)
index cbc44f608512f6a2d30758fac2ec02eb6aed1c77..abd3c83d6a0e8b28dbdfaeb4819cdcf9d04ac473 100644 (file)
@@ -1,4 +1,4 @@
-if(ENABLE_MEMASLAP)
+if(ENABLE_MEMASLAP AND CMAKE_USE_PTHREADS_INIT)
     add_definitions(-D_GNU_SOURCE)
 
     include(CheckAtomics)
index 91e3f1ceba5763fe4a8da3265bee2bf0bb9852e6..fcda4200754e6a039f6a04f1e620cd5e9b5cc191 100644 (file)
 #cmakedefine01 LIBMEMCACHED_ENABLE_DEPRECATED
 #cmakedefine01 LIBMEMCACHED_WITH_SASL_SUPPORT
 
-#cmakedefine HAVE_IN_PORT_T 1
 #cmakedefine HAVE_NETDB_H 1
 
+#cmakedefine HAVE_IN_PORT_T 1
+#cmakedefine HAVE_PID_T 1
+#cmakedefine HAVE_SSIZE_T 1
+
 #define LIBMEMCACHED_VERSION_STRING "@LIBMEMCACHED_VERSION@"
 #define LIBMEMCACHED_VERSION_HEX    @LIBMEMCACHED_VERSION_HEX@
 
index f2ef064275899e1c60208c8e4252642d47cec6c7..6f87e4380ebed70e982c9f1f46060e08c400062a 100644 (file)
 
 #include <sys/types.h>
 
+#ifndef HAVE_PID_T
+typedef int pid_t;
+#endif
+#ifndef HAVE_SSIZE_T
+typedef long int ssize_t;
+#endif
+
 #include "libmemcached-1.0/visibility.h"
 #include "libmemcached-1.0/configure.h"
 #include "libmemcached-1.0/platform.h"
index 437824088535b199a5c1eaad6fd016d3ed359fa3..837f3adfbff8be90524dec6a190bf21eefbde3f3 100644 (file)
  * host order.
  */
 #ifdef __cplusplus
+# include <cstdint>
 extern "C" {
+#else
+# include <stdint.h>
 #endif
 
 /**
index ceb441bf6141d8de74c4af4a53e925a87e8815dd..646843292809ddd010a2bfa7c86a7bd3b40b1ace 100644 (file)
 
 #pragma once
 
+#ifdef __cplusplus
+# include <cstdint>
+extern "C" {
+#else
+# include <stdint.h>
+#endif
+
+#ifdef _MSC_VER
+# undef interface
+#endif
+
 /**
  * Callback to send data back from a successful GET/GETQ/GETK/GETKQ command
  *
@@ -362,3 +373,7 @@ typedef struct {
     memcached_binary_protocol_callback_v1_st v1;
   } interface;
 } memcached_binary_protocol_callback_st;
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
index 74bdee3d5bff71238537483ad2a0b566291479e8..5f0090560716f094d6b1f29c707e63be84f76bc5 100644 (file)
 #pragma once
 
 #include <sys/types.h>
-#if !defined(__cplusplus)
+#ifndef HAVE_SSIZE_T
+typedef long int ssize_t;
+#endif
+
+#ifndef __cplusplus
 #  include <stdbool.h>
+#  include <stdint.h>
+#  include <stddef.h>
+#else
+#  include <cstdint>
 #endif
 
 #include "libmemcached-1.0/visibility.h"
index c5b4faa57fb6de4937634a591ddf3be843dfa254..84443e26ca1317c5e6b7a4ebae652cff26b407e1 100644 (file)
@@ -1,4 +1,7 @@
 add_library(libclient_common STATIC options.cpp checks.hpp random.hpp time.hpp)
+if(NOT HAVE_GETOPT_H)
+        target_sources(libclient_common PRIVATE ../../win32/getopt.c)
+endif()
 add_library(client_common ALIAS libclient_common)
 set_target_properties(libclient_common PROPERTIES CXX_STANDARD ${CXX_STANDARD})
 target_link_libraries(libclient_common PUBLIC libmemcached)
index 8c520b8f152d561dfb904cd9bb33ac3863fd13c4..c62020a3b6dd1b308a86844f7532a02786e31163 100644 (file)
@@ -149,7 +149,7 @@ bool client_options::parse(int argc, char **argv, char ***argp) {
 bool client_options::apply(memcached_st *memc) {
 #ifdef _WIN32
   WSADATA wsaData;
-  if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+  if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
     std::cerr << "Socket Initialization Error.\n";
     return false;
   }
index 5682c78610ec32b0c75dfa2752297d0e0943bd1b..7d2b3e38cf6b4612fb02919c1cf349c0b512bb5d 100644 (file)
 #include <cstdint>
 #include <climits>
 #include <functional>
-#include <getopt.h>
 #include <iostream>
 #include <string>
 #include <vector>
 
+#ifdef HAVE_GETOPT_H
+#  include <getopt.h>
+#elif defined _MSC_VER
+#  include "win32/getopt.h"
+#endif
+
 #include "libmemcached/common.h"
 
 class client_options {
index eab844f1d3c449e6289cb273088d55c64d705936..35be5ad946a7f9833680151ace6c9b8d954025a7 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "time.hpp"
 #include <random>
+#undef max
 
 class random64 {
 public:
@@ -27,8 +28,8 @@ public:
   , dst{}
   {}
 
-  typ operator()(typ min = 0, typ max = std::numeric_limits<typ>::max()) {
-    return (dst(gen) % (max - min)) + min;
+  typ operator()(typ min_ = 0, typ max_ = std::numeric_limits<typ>::max()) {
+    return (dst(gen) % (max_ - min_)) + min_;
   }
 
   void fill(char *buf, size_t len,
index a3a4e3a2b559c93ab1d530aaf4711ba47a6ad2ad..1b9af02a5dc4bd596408351b8df6845255e55199 100644 (file)
 
 #include "mem_config.h"
 
-#ifdef HAVE_POLL_H
-#  include <poll.h>
-#else
-#  include "poll/poll.h"
-#endif
-
 #include <cassert>
 #include <cerrno>
 #include <cstdio>
 #include <cctype>
 #include <fcntl.h>
 #include <cinttypes>
-#include <pthread.h>
+#include <ciso646>
 #include <csignal>
 #include <sys/types.h>
 #if HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#include "libmemcached-1.0/memcached.h"
 
+#ifndef HAVE_GETOPT_H
+#  include "../../win32/getopt.h"
+#endif
+
+#include "libmemcached-1.0/memcached.h"
+#include "libmemcached/poll.h"
 #include "libmemcached/socket.hpp"
 #include "libmemcachedprotocol-0.0/binary.h"
 #include "libmemcached/byteorder.h"
@@ -176,13 +175,13 @@ static memcached_socket_t connect_server(const char *hostname, const char *port)
   return sock;
 }
 
-static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf, size_t len) {
+static ssize_t timeout_io_op(memcached_socket_t fd, short direction, const char *buf, size_t len) {
   ssize_t ret;
 
   if (direction == POLLOUT) {
     ret = send(fd, buf, len, 0);
   } else {
-    ret = recv(fd, buf, len, 0);
+    ret = recv(fd, const_cast<char *>(buf), len, 0);
   }
 
   if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) {
@@ -196,7 +195,7 @@ static ssize_t timeout_io_op(memcached_socket_t fd, short direction, void *buf,
       if (direction == POLLOUT) {
         ret = send(fd, buf, len, 0);
       } else {
-        ret = recv(fd, buf, len, 0);
+        ret = recv(fd, const_cast<char *>(buf), len, 0);
       }
     } else if (err == 0) {
       errno = ETIMEDOUT;
@@ -251,7 +250,7 @@ static enum test_return retry_write(const void *buf, size_t len) {
 
   do {
     size_t num_bytes = len - offset;
-    ssize_t nw = timeout_io_op(sock, POLLOUT, (void *) (ptr + offset), num_bytes);
+    ssize_t nw = timeout_io_op(sock, POLLOUT, (ptr + offset), num_bytes);
     if (nw == -1) {
       verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
     } else {
@@ -1882,7 +1881,14 @@ int main(int argc, char **argv) {
     return EXIT_FAILURE;
   }
 
-  //initialize_sockets();
+  #ifdef _WIN32
+  WSADATA wsaData;
+  if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
+    fprintf(stderr, "Socket Initialization Error.\n");
+    return EXIT_FAILURE;
+  }
+#endif // _WIN32
+
   sock = connect_server(hostname, port);
   if (sock == INVALID_SOCKET) {
     fprintf(stderr, "Failed to connect to <%s:%s>: %s\n", hostname, port,
@@ -1958,5 +1964,9 @@ int main(int argc, char **argv) {
     fprintf(stderr, "%d of %d tests failed\n", failed, total);
   }
 
+#ifdef _WIN32
+  WSACleanup();
+#endif
+
   return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
index eb7151e65a8680155b565cd1a8870cae48e84792..7ad8678717b315a52437dba9e9e7ae91685c0c33 100644 (file)
 #include <cerrno>
 #include <climits>
 #include <cstdlib>
-#include <libgen.h>
+#if HAVE_LIBGEN_H
+#  include <libgen.h>
+#endif
 #include <fstream>
 #include <sstream>
 
+#ifndef PATH_MAX
+#  ifdef MAX_PATH
+#    define PATH_MAX MAX_PATH
+#  else
+#    define PATH_MAX 256
+#  endif
+#endif
+
 struct memcp_file {
   enum class type {
     basename,
@@ -130,7 +140,7 @@ static bool path2key(const client_options &opt, memcp_file &file, char **path) {
   } else if (file.key == memcp_file::type::relative) {
     *path = file.path;
   } else {
-    *path = basename((file.path));
+    *path = basename(file.path);
   }
   return true;
 }
index 140d88154147a13ba11a43e504e1a76521444825..6d4835840b21c069c24832f7f218ed636bc4d7ab 100644 (file)
@@ -22,6 +22,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cmath>
+#include <ciso646>
 
 #ifndef __WORDSIZE
 #  ifdef __MINGW32__
index 35e5b0f0dc9ac91491cc8d8bacce1ddf911d3f12..159472153e288d0c3c51140ecc5498ad88d6db61 100644 (file)
@@ -12,8 +12,12 @@ bison_target(CSL_PARSER csl/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/csl/parser.cc
         COMPILE_FLAGS ${BISON_WARNINGS}
         )
 set_source_files_properties(${BISON_CSL_PARSER_OUTPUTS} PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+if(NOT HAVE_UNISTD_H)
+        set(FLEX_FLAGS --nounistd)
+endif()
 flex_target(CSL_SCANNER csl/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/csl/scanner.cc
         DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/csl/scanner.h
+        COMPILE_FLAGS "${FLEX_FLAGS}"
         )
 set_source_files_properties(${FLEX_CSL_SCANNER_OUTPUTS} PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
 add_flex_bison_dependency(CSL_SCANNER CSL_PARSER)
@@ -91,6 +95,9 @@ set_target_properties(libmemcached PROPERTIES
         SOVERSION ${LIBMEMCACHED_SO_VERSION})
 target_compile_definitions(libmemcached PRIVATE -DBUILDING_LIBMEMCACHED)
 target_link_libraries(libmemcached PUBLIC libhashkit Threads::Threads ${CMAKE_DL_LIBS})
+if(MSVC)
+    target_link_libraries(libmemcached PUBLIC wsock32 ws2_32)
+endif()
 if(HAVE_BACKTRACE)
     target_link_libraries(libmemcached PUBLIC ${BACKTRACE})
 endif()
@@ -131,6 +138,9 @@ add_library(memcachedinternal ALIAS libmemcachedinternal)
 set_target_properties(libmemcachedinternal PROPERTIES CXX_STANDARD ${CXX_STANDARD} LIBRARY_OUTPUT_NAME memcachedinternal)
 target_compile_definitions(libmemcachedinternal PRIVATE -DBUILDING_LIBMEMCACHEDINTERNAL)
 target_link_libraries(libmemcachedinternal PUBLIC libhashkit Threads::Threads ${CMAKE_DL_LIBS})
+if(MSVC)
+    target_link_libraries(libmemcached PUBLIC wsock32 ws2_32)
+endif()
 if(HAVE_LIBSASL)
     target_link_libraries(libmemcachedinternal PUBLIC ${LIBSASL})
 endif()
index ecc894670848623837dad7c91d4ac149beb0aa3f..36d3f1016ddd94b0bece382f1267ed052add5dc4 100644 (file)
 #pragma once
 
 #ifdef __cplusplus
+#  include <cstdint>
 extern "C" {
+#else
+#  include <stdint.h>
 #endif
 
-#include <stdint.h>
 
 uint64_t memcached_ntohll(uint64_t);
 
index fbbf68d7231461094080e71ac2e67d35b41028f8..e3d80bd2cf30e0921dfb7aa5e8b93ebdb98b494f 100644 (file)
 #include "libmemcached/common.h"
 #include <sys/types.h>
 
-#ifndef __INTEL_COMPILER
-#  pragma GCC diagnostic ignored "-Wstrict-aliasing"
-#endif
-
 /*
   These functions provide data and function callback support
 */
index f9b20c4e725b12b6a676282adc9959fcf71880cf..eea5319b654c800dcecd20cbe867b67d65ae3db0 100644 (file)
@@ -26,6 +26,7 @@
 #  include <cctype>
 #  include <cerrno>
 #  include <climits>
+#  include <ciso646>
 #else
 #  include <stddef.h>
 #  include <stdio.h>
@@ -34,6 +35,7 @@
 #  include <time.h>
 #  include <errno.h>
 #  include <limits.h>
+#  include <iso646.h>
 #endif
 
 #ifdef HAVE_SYS_UN_H
 #include "libmemcached/is.h"
 typedef struct memcached_st Memcached;
 
-#ifdef HAVE_POLL_H
-#  include <poll.h>
-#else
-#  include "libmemcached/poll.h"
-#endif
+#include "libmemcached/poll.h"
 
 #ifdef __cplusplus
 memcached_instance_st *memcached_instance_fetch(memcached_st *ptr, uint32_t server_key);
index 248cd7cd387955987b141e3caf291fcbb00cc5f7..ff7772ca1c39bb97f14d5b6a396160fa59db1a67 100644 (file)
@@ -59,7 +59,7 @@ static memcached_return_t connect_poll(memcached_instance_st *server, const int
   while (--loop_max) // Should only loop on cases of ERESTART or EINTR
   {
     int number_of;
-    if ((number_of = poll(fds, 1, server->root->connect_timeout)) == -1) {
+    if ((number_of = poll(fds, 1, server->root->connect_timeout)) == SOCKET_ERROR) {
       int local_errno = get_socket_errno(); // We cache in case closesocket() modifies errno
       switch (local_errno) {
 #ifdef __linux__
@@ -90,7 +90,7 @@ static memcached_return_t connect_poll(memcached_instance_st *server, const int
     }
 
     if (number_of == 0) {
-      if (connection_error == EINPROGRESS) {
+      if (connection_error != EALREADY) {
         int err;
         socklen_t len = sizeof(err);
         if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) {
@@ -138,7 +138,7 @@ static memcached_return_t connect_poll(memcached_instance_st *server, const int
     }
     assert(fds[0].revents & POLLOUT);
 
-    if (fds[0].revents & POLLOUT and connection_error == EINPROGRESS) {
+    if (fds[0].revents & POLLOUT and connection_error != EALREADY) {
       int err;
       socklen_t len = sizeof(err);
       if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) {
@@ -521,6 +521,7 @@ static memcached_return_t network_connect(memcached_instance_st *server) {
 #if EWOULDBLOCK != EAGAIN
     case EWOULDBLOCK:
 #endif
+    case EAGAIN:
     case EINPROGRESS: // nonblocking mode - first return
     case EALREADY:    // nonblocking mode - subsequent returns
     {
index eb592a6de9428dabe1a222a6be1839eef2784b85..8385a3003b3c9788ef8ab666d0e981d054f63fb4 100644 (file)
@@ -17,7 +17,7 @@
 
 static memcached_return_t _vdo_udp(memcached_instance_st *instance,
                                    libmemcached_io_vector_st vector[], const size_t count) {
-#ifndef __MINGW32__
+#if HAVE_SENDMSG && HAVE_STRUCT_MSGHDR
   if (vector[0].buffer or vector[0].length) {
     return memcached_set_error(
         *instance->root, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT,
index b8f0cc336c1b2574370715bcb6b484bcff74f3cb..cd14e06bec05a7411e6eb0041ac4d67b70886ecb 100644 (file)
@@ -191,10 +191,6 @@ memcached_return_t memcached_set_error(memcached_instance_st &self, memcached_re
   return memcached_set_error(self, rc, at, tmp);
 }
 
-#ifndef __INTEL_COMPILER
-#  pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#endif
-
 memcached_return_t memcached_set_error(Memcached &memc, memcached_return_t rc, const char *at,
                                        memcached_string_t &str) {
   assert_msg(rc != MEMCACHED_ERRNO,
index 81062caee33b658e1756f72f82c804b51be1ba48..5914aa47655236070f2e741b94d7da98e7e2121d 100644 (file)
@@ -22,7 +22,7 @@
 #  endif
 #  include <time.h>
 #  if HAVE_STRINGS_H
-#    include <strings.h>
+#    include <cstrings>
 #  endif
 
 int poll(struct pollfd fds[], nfds_t nfds, int tmo) {
@@ -49,7 +49,7 @@ int poll(struct pollfd fds[], nfds_t nfds, int tmo) {
     }
   }
 
-  struct timeval timeout = {.tv_sec = tmo / 1000, .tv_usec = (tmo % 1000) * 1000};
+  struct timeval timeout = {tmo / 1000, (tmo % 1000) * 1000};
   struct timeval *tp = &timeout;
   if (tmo == -1) {
     tp = NULL;
index fab30d1f07dcbdca93e4a43b82f724710822cbfc..8c0ad1ff25eb17af58bac306d8acc87ef712a692 100644 (file)
 
 #pragma once
 
-#if defined(_WIN32)
-
-#  include <winsock2.h>
+#if defined HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+#elif defined HAVE_POLL_H
+#  include <poll.h>
+#elif defined _WIN32
+#  include "windows.hpp"
+#  define poll WSAPoll
+typedef int nfds_t;
+#elif !defined _MSC_VER
 
 #  ifdef __cplusplus
 extern "C" {
index d1a339638a3487e76982bfafc26bb270df28e13b..ed7810f7c06deb4fa571dec48b96c59589362118 100644 (file)
@@ -24,7 +24,8 @@
  */
 #if defined(WIN32) || defined(__MINGW32__)
 #  include "win32/wrappers.h"
-#  define get_socket_errno() WSAGetLastError()
+#  include "windows.hpp"
+#  define get_socket_errno() translate_windows_error()
 #else
 #  include <unistd.h>
 #  define INVALID_SOCKET     -1
index afa0be15f35615c2dc5700a456c820611b7d6684..b867a6d4718025242f26160335acbf10de10e016 100644 (file)
 #  define WIN32_LEAN_AND_MEAN
 #endif
 
-#ifndef _WIN32_WINNT
-#  define _WIN32_WINNT 0x0501
-#endif
-
-#ifdef __MINGW32__
-#  if (_WIN32_WINNT >= 0x0501)
-#  else
-#    undef _WIN32_WINNT
-#    define _WIN32_WINNT 0x0501
-#  endif /* _WIN32_WINNT >= 0x0501 */
-#endif   /* __MINGW32__ */
-
 #if defined(HAVE_WINSOCK2_H) && HAVE_WINSOCK2_H
 #  include <winsock2.h>
 #endif
@@ -58,26 +46,56 @@ static inline int translate_windows_error() {
   int local_errno = WSAGetLastError();
 
   switch (local_errno) {
-  case WSAEINVAL: local_errno = EINPROGRESS; break;
+  case WSAEINVAL:
+    local_errno = EINPROGRESS;
+    break;
   case WSAEALREADY:
-  case WSAEWOULDBLOCK: local_errno = EAGAIN; break;
+  case WSAEWOULDBLOCK:
+    local_errno = EAGAIN;
+    break;
 
-  case WSAECONNREFUSED: local_errno = ECONNREFUSED; break;
+  case WSAECONNREFUSED:
+    local_errno = ECONNREFUSED;
+    break;
 
-  case WSAENETUNREACH: local_errno = ENETUNREACH; break;
+  case WSAENETUNREACH:
+    local_errno = ENETUNREACH;
+    break;
 
-  case WSAETIMEDOUT: local_errno = ETIMEDOUT; break;
+  case WSAETIMEDOUT:
+    local_errno = ETIMEDOUT;
+    break;
 
-  case WSAECONNRESET: local_errno = ECONNRESET; break;
+  case WSAECONNRESET:
+    local_errno = ECONNRESET;
+    break;
 
-  case WSAEADDRINUSE: local_errno = EADDRINUSE; break;
+  case WSAEADDRINUSE:
+    local_errno = EADDRINUSE;
+    break;
 
-  case WSAEOPNOTSUPP: local_errno = EOPNOTSUPP; break;
+  case WSAEOPNOTSUPP:
+    local_errno = EOPNOTSUPP;
+    break;
 
-  case WSAENOPROTOOPT: local_errno = ENOPROTOOPT; break;
+  case WSAENOPROTOOPT:
+    local_errno = ENOPROTOOPT;
+    break;
 
-  default: break;
+  default:
+    break;
   }
 
   return local_errno;
 }
+
+static inline char *basename(const char *filename) {
+  static char base[MAX_PATH * 2], ext[MAX_PATH], *ptr;
+  (void) _splitpath_s(filename, NULL, 0, NULL, 0, base, MAX_PATH, ext, MAX_PATH);
+  strcat_s(base, MAX_PATH * 2 - 1, ext);
+  return base;
+}
+
+static inline char *realpath(const char *path, char real[MAX_PATH]) {
+  return _fullpath(real, path, MAX_PATH);
+}
\ No newline at end of file
index dd66d6a89758e358617815c5f4653c15e8757f5d..61fbed1560b0e6de26aba1ad222962c629e99ff4 100644 (file)
@@ -7,6 +7,7 @@ add_library(libmemcachedprotocol SHARED
         common.h
         handler.c
         pedantic.c
+        ../libmemcached/byteorder.cc
         )
 add_library(memcachedprotocol ALIAS libmemcachedprotocol)
 set_target_properties(libmemcachedprotocol PROPERTIES
@@ -21,6 +22,9 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)
                )
 endif()
 target_link_libraries(libmemcachedprotocol PUBLIC Threads::Threads)
+if(MSVC)
+    target_link_libraries(libmemcachedprotocol PUBLIC wsock32 ws2_32)
+endif()
 target_include_directories(libmemcachedprotocol PRIVATE
         ${CMAKE_SOURCE_DIR}/src
         ${CMAKE_BINARY_DIR}/src
index 1de8b0a6cf5614280204be5e7f3801c9836ed351..39e2fc7d9ba5f02ce726e8dab6fcbe558e9387d0 100644 (file)
 
 #ifndef HAVE_UMEM_H
 
+#  ifdef _MSC_VER
+typedef SECURITY_ATTRIBUTES pthread_mutexattr_t;
+
+static inline int pthread_mutex_init(pthread_mutex_t *m, pthread_mutexattr_t *a) {
+    *m = CreateMutexA(a, FALSE, NULL);
+    return !*m;
+}
+static inline int pthread_mutex_destroy(pthread_mutex_t *m) {
+    return !CloseHandle(*m);
+}
+static inline int pthread_mutex_lock(pthread_mutex_t *m) {
+    if (WaitForSingleObject(*m, INFINITE)) {
+        return 0;
+    }
+    return GetLastError();
+}
+static inline int pthread_mutex_unlock(pthread_mutex_t *m) {
+    return !ReleaseMutex(*m);
+}
+#  endif
+
 #  ifndef NDEBUG
 #    include <signal.h>
 
index 616909f785226cc88ab19c03f6ba506ac9e96df0..7b5efa987c0b88bb88f80d6e34a8ca3b5ea296fb 100644 (file)
 
 #pragma once
 
-#include <pthread.h>
+#ifdef HAVE_PTHREAD_H
+#  include <pthread.h>
+#else
+typedef void *pthread_mutex_t;
+#endif
 
 #ifdef HAVE_UMEM_H
 #  include <umem.h>
index 594099bf983ccae6f2de17fcdc9617060416bbbc..b49d0d030a4ed28efcb68cd0124be86de515eb3d 100644 (file)
@@ -5,9 +5,11 @@ add_library(libmemcachedutil SHARED
         flush.cc
         pid.cc
         ping.cc
-        pool.cc
         version.cc
         )
+if(CMAKE_USE_PTHREADS_INIT)
+    target_sources(libmemcachedutil PRIVATE pool.cc)
+endif()
 add_library(memcachedutil ALIAS libmemcachedutil)
 set_target_properties(libmemcachedutil PROPERTIES
         CXX_STANDARD ${CXX_STANDARD}
@@ -20,6 +22,11 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)
                LINK_FLAGS "-Wl,-undefined,dynamic_lookup"
                )
 endif()
+if(MSVC)
+        set_target_properties(libmemcachedutil PROPERTIES
+                LINK_FLAGS "/FORCE:UNRESOLVED"
+                )
+endif()
 target_link_libraries(libmemcachedutil PUBLIC Threads::Threads)
 if(HAVE_LIBSASL)
     target_link_libraries(libmemcachedutil PUBLIC ${LIBSASL})
index e7095cd6f9c636e0f3072e2eb9975a1fd4189a21..680f85c023efcba5e6dda25b2f0a1e37a66171ab 100644 (file)
@@ -20,6 +20,7 @@
 #include <cstddef>
 #include <cstdlib>
 #include <cstdio>
+#include <ciso646>
 
 #include "libmemcachedutil-1.0/util.h"
 #include "libmemcached/assert.hpp"
diff --git a/src/win32/getopt.c b/src/win32/getopt.c
new file mode 100644 (file)
index 0000000..dd8cd70
--- /dev/null
@@ -0,0 +1,652 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file is part of the mingw-w64 runtime package.
+ *
+ * The mingw-w64 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.
+ */
+ /*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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.
+ */
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include <crtdefs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <windows.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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
+
+//extern int optind;           /* index of first non-option in argv      */
+//extern int optopt;           /* single option character, as parsed     */
+//extern int opterr;           /* flag to enable built-in diagnostics... */
+//                             /* (user may set to zero, to suppress)    */
+//
+//extern char *optarg;         /* pointer to argument of current option  */
+
+#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;
+               }
+       }
+}
+
+#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 */
+
+//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          */
+};
+
+/*
+ * 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)
+{
+       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)
+               posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+       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 = (char*)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);
+}
+
+/*
+ * 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));
+}
+
+//extern int getopt_long(int nargc, char * const *nargv, const char *options,
+//    const struct option *long_options, int *idx);
+//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/src/win32/getopt.h b/src/win32/getopt.h
new file mode 100644 (file)
index 0000000..8f0835b
--- /dev/null
@@ -0,0 +1,30 @@
+#pragma once
+
+extern "C" {
+
+extern int opterr;    /* if error message should be printed */
+extern int optind;    /* index into parent argv vector */
+extern char *optarg;  /* argument associated with option */
+
+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    */
+};
+
+int getopt(int nargc, char * const *nargv, const char *options);
+int getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx);
+int getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx);
+
+}
\ No newline at end of file
index 5bf325e9b31f68d431d1d30aa27370a17417acc3..a009fbdc8037dce7918829802bf97e8158f116d1 100644 (file)
 #ifndef SHUT_RDWR
 # define SHUT_RDWR SD_BOTH
 #endif
+#ifndef SHUT_WR
+# define SHUT_WR SD_SEND
+#endif
+#ifndef SHUT_RD
+# define SHUT_RD SD_RECEIVE
+#endif
 
 /* EAI_SYSTEM isn't defined anywhere... just set it to... 11? */
 #ifndef EAI_SYSTEM
 #define waitpid(a,b,c) (-1)
 #define fnmatch(a,b,c) (-1)
 #define sleep(a) Sleep(a*1000)
+
+#ifdef __cplusplus
+#  include <chrono>
+static inline int gettimeofday(struct timeval* tp, struct timezone* tzp) {
+  using clock = std::chrono::system_clock;
+  auto as_sec = [] (auto d) {
+      return std::chrono::duration_cast<std::chrono::seconds>(d);
+  };
+  auto as_usec = [] (auto d) {
+      return std::chrono::duration_cast<std::chrono::microseconds>(d);
+  };
+
+  auto now = clock::now().time_since_epoch();
+  auto sec = as_sec(now);
+  auto usec = as_usec(now - sec);
+
+  tp->tv_sec = sec.count();
+  tp->tv_usec = usec.count();
+  return 0;
+}
+#endif
\ No newline at end of file