From: Michael Wallner Date: Thu, 3 Dec 2020 13:24:40 +0000 (+0100) Subject: p9y X-Git-Tag: 1.1.0-beta1~75 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=2f289c64f625962d945ec3bee80f36bc5c61ee35;p=m6w6%2Flibmemcached p9y --- diff --git a/CMake/_Include.cmake b/CMake/_Include.cmake index 6f9a092b..a419d8df 100644 --- a/CMake/_Include.cmake +++ b/CMake/_Include.cmake @@ -136,12 +136,17 @@ check_type("struct msghdr" sys/socket.h) check_cxx_symbol(abi::__cxa_demangle cxxabi.h) check_symbol(fcntl fcntl.h) +check_symbol(gettimeofday sys/time.h) check_symbol(htonll arpa/inet.h) +check_symbol(index strings.h) check_symbol(MSG_DONTWAIT sys/socket.h) 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(rand stdlib.h) +check_symbol(random stdlib.h) +check_symbol(realpath stdlib.h) check_symbol(sendmsg sys/socket.h) check_symbol(setenv stdlib.h) check_symbol(strerror_r string.h) diff --git a/include/libmemcached-1.0/configure.h.in b/include/libmemcached-1.0/configure.h.in index fcda4200..dfa55eba 100644 --- a/include/libmemcached-1.0/configure.h.in +++ b/include/libmemcached-1.0/configure.h.in @@ -18,6 +18,8 @@ #cmakedefine01 LIBMEMCACHED_ENABLE_DEPRECATED #cmakedefine01 LIBMEMCACHED_WITH_SASL_SUPPORT +#cmakedefine HAVE_VISIBILITY 1 + #cmakedefine HAVE_NETDB_H 1 #cmakedefine HAVE_IN_PORT_T 1 diff --git a/include/libmemcached-1.0/memcached.h b/include/libmemcached-1.0/memcached.h index 6f87e438..e3eac4e2 100644 --- a/include/libmemcached-1.0/memcached.h +++ b/include/libmemcached-1.0/memcached.h @@ -15,34 +15,8 @@ #pragma once -/* This seems to be required for older compilers @note - * http://stackoverflow.com/questions/8132399/how-to-printf-uint64-t */ -#ifndef __STDC_FORMAT_MACROS -# define __STDC_FORMAT_MACROS -#endif - -#ifdef __cplusplus -# include -# include -# include -#else -# include -# include -# include -# include -#endif - -#include - -#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/visibility.h" #include "libmemcached-1.0/platform.h" #include "libmemcached-1.0/limits.h" diff --git a/include/libmemcached-1.0/platform.h b/include/libmemcached-1.0/platform.h index a3ccd3d7..1ab1bc07 100644 --- a/include/libmemcached-1.0/platform.h +++ b/include/libmemcached-1.0/platform.h @@ -17,25 +17,45 @@ #include "libmemcached-1.0/configure.h" -#if defined(_WIN32) -# include -# include +/* This seems to be required for older compilers @note + * http://stackoverflow.com/questions/8132399/how-to-printf-uint64-t */ +#ifndef __STDC_FORMAT_MACROS +# define __STDC_FORMAT_MACROS +#endif + +#ifdef __cplusplus +# include +# include +# include +#else +# include +# include +# include +# include +#endif + +#include -# ifndef HAVE_IN_PORT_T +#if defined HAVE_NETDB_H +# include +#endif + +#if !defined HAVE_IN_PORT_T typedef int in_port_t; -# define HAVE_IN_PORT_T 1 -# endif +#endif -typedef SOCKET memcached_socket_t; +#if !defined HAVE_PID_T +typedef int pid_t; +#endif -#else -# include -# include -# include -# include -# include -# include +#ifndef HAVE_SSIZE_T +typedef long int ssize_t; +#endif +#if defined _WIN32 +# include +# include +typedef SOCKET memcached_socket_t; +#else typedef int memcached_socket_t; - -#endif /* _WIN32 */ +#endif // _WIN32 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3eaa0219..87176a23 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(p9y) add_subdirectory(bin) add_subdirectory(libhashkit) diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt index 187b9cef..7b4c3498 100644 --- a/src/bin/CMakeLists.txt +++ b/src/bin/CMakeLists.txt @@ -19,6 +19,5 @@ target_sources(memcapable PRIVATE ../libmemcached/byteorder.cc) # extra libs -target_link_libraries(memcapable PRIVATE Threads::Threads) target_link_libraries(memping PRIVATE libmemcachedutil) target_link_libraries(memslap PRIVATE Threads::Threads) diff --git a/src/bin/common/CMakeLists.txt b/src/bin/common/CMakeLists.txt index 84443e26..0c77c392 100644 --- a/src/bin/common/CMakeLists.txt +++ b/src/bin/common/CMakeLists.txt @@ -1,9 +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 PRIVATE p9y) target_link_libraries(libclient_common PUBLIC libmemcached) target_include_directories(libclient_common PUBLIC . diff --git a/src/bin/common/options.hpp b/src/bin/common/options.hpp index 980ca38d..65018eff 100644 --- a/src/bin/common/options.hpp +++ b/src/bin/common/options.hpp @@ -24,12 +24,7 @@ #include #include "libmemcached/common.h" - -#ifdef HAVE_GETOPT_H -# include -#elif defined _MSC_VER -# include "win32/getopt.h" -#endif +#include "p9y/getopt.hpp" class client_options { public: diff --git a/src/bin/memcapable.cc b/src/bin/memcapable.cc index 1b9af02a..54e9c224 100644 --- a/src/bin/memcapable.cc +++ b/src/bin/memcapable.cc @@ -32,13 +32,11 @@ # include #endif -#ifndef HAVE_GETOPT_H -# include "../../win32/getopt.h" -#endif +#include "p9y/getopt.hpp" +#include "p9y/socket.hpp" +#include "p9y/poll.hpp" #include "libmemcached-1.0/memcached.h" -#include "libmemcached/poll.h" -#include "libmemcached/socket.hpp" #include "libmemcachedprotocol-0.0/binary.h" #include "libmemcached/byteorder.h" @@ -132,14 +130,14 @@ static memcached_socket_t set_noblock(void) { int flags = fcntl(sock, F_GETFL, 0); if (flags == -1) { perror("Failed to get socket flags"); - memcached_close_socket(sock); + closesocket(sock); return INVALID_SOCKET; } if ((flags & O_NONBLOCK) != O_NONBLOCK) { if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { perror("Failed to set socket to nonblocking mode"); - memcached_close_socket(sock); + closesocket(sock); return INVALID_SOCKET; } } @@ -183,8 +181,8 @@ static ssize_t timeout_io_op(memcached_socket_t fd, short direction, const char } else { ret = recv(fd, const_cast(buf), len, 0); } - - if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) { + int local_errno = get_socket_errno(); + if (ret == SOCKET_ERROR && local_errno == EWOULDBLOCK || (EAGAIN != EWOULDBLOCK && local_errno == EAGAIN)) { struct pollfd fds; memset(&fds, 0, sizeof(struct pollfd)); fds.events = direction; diff --git a/src/bin/memcp.cc b/src/bin/memcp.cc index 7ad86787..7396057e 100644 --- a/src/bin/memcp.cc +++ b/src/bin/memcp.cc @@ -21,13 +21,12 @@ #include "common/options.hpp" #include "common/checks.hpp" +#include "p9y/libgen.hpp" +#include "p9y/realpath.hpp" #include #include #include -#if HAVE_LIBGEN_H -# include -#endif #include #include diff --git a/src/libmemcached/CMakeLists.txt b/src/libmemcached/CMakeLists.txt index 15947215..0287fcc9 100644 --- a/src/libmemcached/CMakeLists.txt +++ b/src/libmemcached/CMakeLists.txt @@ -57,7 +57,6 @@ set(LIBMEMCACHED_SOURCES namespace.cc options.cc parse.cc - poll.cc purge.cc quit.cc response.cc @@ -95,6 +94,7 @@ 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}) +target_link_libraries(libmemcached PRIVATE p9y) if(MSVC) target_link_libraries(libmemcached PUBLIC wsock32 ws2_32) endif() @@ -138,6 +138,7 @@ 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}) +target_link_libraries(libmemcachedinternal PRIVATE p9y) if(MSVC) target_link_libraries(libmemcached PUBLIC wsock32 ws2_32) endif() diff --git a/src/libmemcached/behavior.cc b/src/libmemcached/behavior.cc index 576ec883..d0d6c6f2 100644 --- a/src/libmemcached/behavior.cc +++ b/src/libmemcached/behavior.cc @@ -16,6 +16,8 @@ #include "libmemcached/common.h" #include "libmemcached/options.hpp" #include "libmemcached/virtual_bucket.h" +#include "p9y/random.hpp" +#include "p9y/socket.hpp" #include #include diff --git a/src/libmemcached/common.h b/src/libmemcached/common.h index eea5319b..defb3b0d 100644 --- a/src/libmemcached/common.h +++ b/src/libmemcached/common.h @@ -65,17 +65,11 @@ # include #endif -#if defined(_WIN32) -# include "libmemcached/windows.hpp" -#endif - #include "libmemcached-1.0/memcached.h" #include "libmemcached/watchpoint.h" #include "libmemcached/is.h" typedef struct memcached_st Memcached; -#include "libmemcached/poll.h" - #ifdef __cplusplus memcached_instance_st *memcached_instance_fetch(memcached_st *ptr, uint32_t server_key); #endif @@ -90,7 +84,6 @@ memcached_instance_st *memcached_instance_fetch(memcached_st *ptr, uint32_t serv # include "libmemcached/io.hpp" # include "libmemcached/udp.hpp" # include "libmemcached/do.hpp" -# include "libmemcached/socket.hpp" # include "libmemcached/connect.hpp" # include "libmemcached/allocators.hpp" # include "libmemcached/hash.hpp" @@ -151,6 +144,7 @@ extern "C" { memcached_return_t run_distribution(memcached_st *ptr); #ifdef __cplusplus +# include "p9y/poll.hpp" static inline void memcached_server_response_increment(memcached_instance_st *instance) { instance->events(POLLIN); instance->cursor_active_++; diff --git a/src/libmemcached/connect.cc b/src/libmemcached/connect.cc index ff7772ca..913e48be 100644 --- a/src/libmemcached/connect.cc +++ b/src/libmemcached/connect.cc @@ -14,32 +14,11 @@ */ #include "libmemcached/common.h" +#include "p9y/socket.hpp" +#include "p9y/poll.hpp" #include -#ifndef SOCK_CLOEXEC -# define SOCK_CLOEXEC 0 -#endif - -#ifndef SOCK_NONBLOCK -# define SOCK_NONBLOCK 0 -#endif - -#ifndef FD_CLOEXEC -# define FD_CLOEXEC 0 -#endif - -#ifndef SO_NOSIGPIPE -# define SO_NOSIGPIPE 0 -#endif - -#ifndef TCP_NODELAY -# define TCP_NODELAY 0 -#endif - -#ifndef TCP_KEEPIDLE -# define TCP_KEEPIDLE 0 -#endif static memcached_return_t connect_poll(memcached_instance_st *server, const int connection_error) { struct pollfd fds[1]; diff --git a/src/libmemcached/flush_buffers.cc b/src/libmemcached/flush_buffers.cc index 512fa2b7..6c58e69c 100644 --- a/src/libmemcached/flush_buffers.cc +++ b/src/libmemcached/flush_buffers.cc @@ -14,6 +14,7 @@ */ #include "libmemcached/common.h" +#include "p9y/socket.hpp" memcached_return_t memcached_flush_buffers(memcached_st *shell) { Memcached *memc = memcached2Memcached(shell); diff --git a/src/libmemcached/get.cc b/src/libmemcached/get.cc index 4dd88061..d625adce 100644 --- a/src/libmemcached/get.cc +++ b/src/libmemcached/get.cc @@ -14,6 +14,7 @@ */ #include "libmemcached/common.h" +#include "p9y/random.hpp" char *memcached_get(memcached_st *ptr, const char *key, size_t key_length, size_t *value_length, uint32_t *flags, memcached_return_t *error) { diff --git a/src/libmemcached/hash.cc b/src/libmemcached/hash.cc index cb1ca464..3e147f87 100644 --- a/src/libmemcached/hash.cc +++ b/src/libmemcached/hash.cc @@ -14,13 +14,9 @@ */ #include "libmemcached/common.h" - -#if HAVE_SYS_TIME_H -# include -#endif -#include - #include "libmemcached/virtual_bucket.h" +#include "p9y/gettimeofday.hpp" +#include "p9y/random.hpp" uint32_t memcached_generate_hash_value(const char *key, size_t key_length, memcached_hash_t hash_algorithm) { diff --git a/src/libmemcached/hosts.cc b/src/libmemcached/hosts.cc index 39247287..8f121502 100644 --- a/src/libmemcached/hosts.cc +++ b/src/libmemcached/hosts.cc @@ -15,12 +15,10 @@ #include "libmemcached/common.h" #include "libmemcached/assert.hpp" +#include "p9y/gettimeofday.hpp" +#include "p9y/random.hpp" #include -#if HAVE_SYS_TIME_H -# include -#endif -#include /* Protoypes (static) */ static memcached_return_t update_continuum(Memcached *ptr); diff --git a/src/libmemcached/instance.cc b/src/libmemcached/instance.cc index 266eccc7..972f6b6f 100644 --- a/src/libmemcached/instance.cc +++ b/src/libmemcached/instance.cc @@ -14,6 +14,7 @@ */ #include "libmemcached/common.h" +#include "p9y/socket.hpp" static inline void _server_init(memcached_instance_st *self, Memcached *root, const memcached_string_t &hostname, in_port_t port, uint32_t weight, diff --git a/src/libmemcached/io.cc b/src/libmemcached/io.cc index 27b5ecbd..94aca617 100644 --- a/src/libmemcached/io.cc +++ b/src/libmemcached/io.cc @@ -15,9 +15,8 @@ #include "libmemcached/common.h" -#ifdef HAVE_SYS_SOCKET_H -# include -#endif +#include "p9y/socket.hpp" +#include "p9y/poll.hpp" void initialize_binary_request(memcached_instance_st *server, protocol_binary_request_header &header) { diff --git a/src/libmemcached/parse.cc b/src/libmemcached/parse.cc index 7130cf46..12431222 100644 --- a/src/libmemcached/parse.cc +++ b/src/libmemcached/parse.cc @@ -26,8 +26,8 @@ memcached_server_list_st memcached_servers_parse(const char *server_strings) { end_ptr = server_strings + strlen(server_strings); - for (begin_ptr = server_strings, string = (char *) index(server_strings, ','); - begin_ptr != end_ptr; string = (char *) index(begin_ptr, ',')) + for (begin_ptr = server_strings, string = (char *) strchr(server_strings, ','); + begin_ptr != end_ptr; string = (char *) strchr(begin_ptr, ',')) { char buffer[HUGE_STRING_LEN]; char *ptr, *ptr2; @@ -44,7 +44,7 @@ memcached_server_list_st memcached_servers_parse(const char *server_strings) { begin_ptr = end_ptr; } - ptr = index(buffer, ':'); + ptr = strchr(buffer, ':'); in_port_t port = 0; if (ptr) { @@ -59,9 +59,9 @@ memcached_server_list_st memcached_servers_parse(const char *server_strings) { return NULL; } - ptr2 = index(ptr, ' '); + ptr2 = strchr(ptr, ' '); if (!ptr2) - ptr2 = index(ptr, ':'); + ptr2 = strchr(ptr, ':'); if (ptr2) { ptr2++; diff --git a/src/libmemcached/poll.cc b/src/libmemcached/poll.cc deleted file mode 100644 index 5914aa47..00000000 --- a/src/libmemcached/poll.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | libmemcached - C/C++ Client Library for memcached | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted under the terms of the BSD license. | - | You should have received a copy of the license in a bundled file | - | named LICENSE; in case you did not receive a copy you can review | - | the terms online at: https://opensource.org/licenses/BSD-3-Clause | - +--------------------------------------------------------------------+ - | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ | - | Copyright (c) 2020 Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#include "libmemcached/common.h" - -#if defined(_WIN32) -# include "libmemcached/poll.h" -# if HAVE_SYS_TIME_H -# include -# endif -# include -# if HAVE_STRINGS_H -# include -# endif - -int poll(struct pollfd fds[], nfds_t nfds, int tmo) { - fd_set readfds, writefds, errorfds; - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&errorfds); - - int maxfd = 0; - - for (nfds_t x = 0; x < nfds; ++x) { - if (fds[x].events & (POLLIN | POLLOUT)) { -# ifndef _WIN32 - if (fds[x].fd > maxfd) { - maxfd = fds[x].fd; - } -# endif - if (fds[x].events & POLLIN) { - FD_SET(fds[x].fd, &readfds); - } - if (fds[x].events & POLLOUT) { - FD_SET(fds[x].fd, &writefds); - } - } - } - - struct timeval timeout = {tmo / 1000, (tmo % 1000) * 1000}; - struct timeval *tp = &timeout; - if (tmo == -1) { - tp = NULL; - } - int ret = select(maxfd + 1, &readfds, &writefds, &errorfds, tp); - if (ret <= 0) { - return ret; - } - - /* Iterate through all of them because I need to clear the revent map */ - for (nfds_t x = 0; x < nfds; ++x) { - fds[x].revents = 0; - if (FD_ISSET(fds[x].fd, &readfds)) { - fds[x].revents |= POLLIN; - } - if (FD_ISSET(fds[x].fd, &writefds)) { - fds[x].revents |= POLLOUT; - } - if (FD_ISSET(fds[x].fd, &errorfds)) { - fds[x].revents |= POLLERR; - } - } - - return ret; -} - -#endif // defined(_WIN32) diff --git a/src/libmemcached/poll.h b/src/libmemcached/poll.h deleted file mode 100644 index 8c0ad1ff..00000000 --- a/src/libmemcached/poll.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | libmemcached - C/C++ Client Library for memcached | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted under the terms of the BSD license. | - | You should have received a copy of the license in a bundled file | - | named LICENSE; in case you did not receive a copy you can review | - | the terms online at: https://opensource.org/licenses/BSD-3-Clause | - +--------------------------------------------------------------------+ - | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ | - | Copyright (c) 2020 Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#pragma once - -#if defined HAVE_SYS_POLL_H -# include -#elif defined HAVE_POLL_H -# include -#elif defined _WIN32 -# include "windows.hpp" -# define poll WSAPoll -typedef int nfds_t; -#elif !defined _MSC_VER - -# ifdef __cplusplus -extern "C" { -# endif - -typedef struct pollfd { -# if defined(_WIN32) - SOCKET fd; -# else - int fd; -# endif - short events; - short revents; -} pollfd_t; - -typedef int nfds_t; - -# define POLLIN 0x0001 -# define POLLOUT 0x0004 -# define POLLERR 0x0008 -# define POLLHUP 0x010 /* Hung up. */ -# define POLLNVAL 0x020 /* Invalid polling request. */ - -int poll(struct pollfd fds[], nfds_t nfds, int tmo); - -# ifdef __cplusplus -} -# endif - -#endif // defined(_WIN32) diff --git a/src/libmemcached/purge.cc b/src/libmemcached/purge.cc index 4437d761..d4b3146d 100644 --- a/src/libmemcached/purge.cc +++ b/src/libmemcached/purge.cc @@ -14,6 +14,7 @@ */ #include "libmemcached/common.h" +#include "p9y/socket.hpp" #define memcached_set_purging(__object, __value) ((__object)->state.is_purging = (__value)) diff --git a/src/libmemcached/response.cc b/src/libmemcached/response.cc index 5f0f0204..13ffefeb 100644 --- a/src/libmemcached/response.cc +++ b/src/libmemcached/response.cc @@ -197,7 +197,7 @@ static memcached_return_t textual_read_one_response(memcached_instance_st *insta and buffer[5] == 'O' and buffer[6] == 'N') /* VERSION */ { /* Find the space, and then move one past it to copy version */ - char *response_ptr = index(buffer, ' '); + char *response_ptr = strchr(buffer, ' '); char *endptr; errno = 0; diff --git a/src/libmemcached/sasl.cc b/src/libmemcached/sasl.cc index 9c8ad52f..4fa981d2 100644 --- a/src/libmemcached/sasl.cc +++ b/src/libmemcached/sasl.cc @@ -14,6 +14,8 @@ */ #include "libmemcached/common.h" +#include "p9y/socket.hpp" + #include #include diff --git a/src/libmemcached/server.cc b/src/libmemcached/server.cc index e038196a..28d063ec 100644 --- a/src/libmemcached/server.cc +++ b/src/libmemcached/server.cc @@ -14,6 +14,7 @@ */ #include "libmemcached/common.h" +#include "p9y/socket.hpp" static inline void _server_init(memcached_server_st *self, Memcached *root, const memcached_string_t &hostname, in_port_t port, uint32_t weight, diff --git a/src/libmemcached/server.hpp b/src/libmemcached/server.hpp index 017242bd..86f6ffb9 100644 --- a/src/libmemcached/server.hpp +++ b/src/libmemcached/server.hpp @@ -15,9 +15,7 @@ #pragma once -#ifdef HAVE_SYS_TIME_H -# include -#endif +#include "p9y/gettimeofday.hpp" #include diff --git a/src/libmemcached/socket.hpp b/src/libmemcached/socket.hpp deleted file mode 100644 index ed7810f7..00000000 --- a/src/libmemcached/socket.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | libmemcached - C/C++ Client Library for memcached | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted under the terms of the BSD license. | - | You should have received a copy of the license in a bundled file | - | named LICENSE; in case you did not receive a copy you can review | - | the terms online at: https://opensource.org/licenses/BSD-3-Clause | - +--------------------------------------------------------------------+ - | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ | - | Copyright (c) 2020 Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#pragma once - -/* To hide the platform differences between MS Windows and Unix, I am - * going to use the Microsoft way and #define the Microsoft-specific - * functions to the unix way. Microsoft use a separate subsystem for sockets, - * but Unix normally just use a filedescriptor on the same functions. It is - * a lot easier to map back to the unix way with macros than going the other - * way without side effect ;-) - */ -#if defined(WIN32) || defined(__MINGW32__) -# include "win32/wrappers.h" -# include "windows.hpp" -# define get_socket_errno() translate_windows_error() -#else -# include -# define INVALID_SOCKET -1 -# define SOCKET_ERROR -1 -# define closesocket(a) close(a) -# define get_socket_errno() errno -#endif - -#ifdef __cplusplus -static inline void memcached_close_socket(memcached_socket_t &socket_fd) { - closesocket(socket_fd); - socket_fd = INVALID_SOCKET; -} -#endif - -#ifndef HAVE_MSG_NOSIGNAL -# define MSG_NOSIGNAL 0 -#endif - -#ifndef HAVE_MSG_DONTWAIT -# define MSG_DONTWAIT 0 -#endif - -#ifndef HAVE_MSG_MORE -# define MSG_MORE 0 -#endif diff --git a/src/libmemcached/windows.hpp b/src/libmemcached/windows.hpp deleted file mode 100644 index b867a6d4..00000000 --- a/src/libmemcached/windows.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - +--------------------------------------------------------------------+ - | libmemcached - C/C++ Client Library for memcached | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted under the terms of the BSD license. | - | You should have received a copy of the license in a bundled file | - | named LICENSE; in case you did not receive a copy you can review | - | the terms online at: https://opensource.org/licenses/BSD-3-Clause | - +--------------------------------------------------------------------+ - | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ | - | Copyright (c) 2020 Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#pragma once - -#ifdef __cplusplus -# include -#else -# include -#endif - -#ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#if defined(HAVE_WINSOCK2_H) && HAVE_WINSOCK2_H -# include -#endif - -#if defined(HAVE_WS2TCPIP_H) && HAVE_WS2TCPIP_H -# include -#endif - -#if defined(HAVE_IO_H) && HAVE_IO_H -# include -#endif - -struct sockaddr_un { - short int sun_family; - char sun_path[108]; -}; - -static inline int translate_windows_error() { - int local_errno = WSAGetLastError(); - - switch (local_errno) { - case WSAEINVAL: - local_errno = EINPROGRESS; - break; - case WSAEALREADY: - case WSAEWOULDBLOCK: - local_errno = EAGAIN; - break; - - case WSAECONNREFUSED: - local_errno = ECONNREFUSED; - break; - - case WSAENETUNREACH: - local_errno = ENETUNREACH; - break; - - case WSAETIMEDOUT: - local_errno = ETIMEDOUT; - break; - - case WSAECONNRESET: - local_errno = ECONNRESET; - break; - - case WSAEADDRINUSE: - local_errno = EADDRINUSE; - break; - - case WSAEOPNOTSUPP: - local_errno = EOPNOTSUPP; - break; - - case WSAENOPROTOOPT: - local_errno = ENOPROTOOPT; - 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 diff --git a/src/libmemcachedprotocol/CMakeLists.txt b/src/libmemcachedprotocol/CMakeLists.txt index 61fbed15..43d59de1 100644 --- a/src/libmemcachedprotocol/CMakeLists.txt +++ b/src/libmemcachedprotocol/CMakeLists.txt @@ -21,6 +21,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang) LINK_FLAGS "-Wl,-undefined,dynamic_lookup" ) endif() +target_link_libraries(libmemcachedprotocol PRIVATE p9y) target_link_libraries(libmemcachedprotocol PUBLIC Threads::Threads) if(MSVC) target_link_libraries(libmemcachedprotocol PUBLIC wsock32 ws2_32) diff --git a/src/libmemcachedprotocol/binary_handler.c b/src/libmemcachedprotocol/binary_handler.c index ada4c425..a1b072d0 100644 --- a/src/libmemcachedprotocol/binary_handler.c +++ b/src/libmemcachedprotocol/binary_handler.c @@ -14,6 +14,7 @@ */ #include "libmemcachedprotocol/common.h" +#include "p9y/socket.hpp" #include #include diff --git a/src/libmemcachedprotocol/common.h b/src/libmemcachedprotocol/common.h index ee27ab4a..39f0464e 100644 --- a/src/libmemcachedprotocol/common.h +++ b/src/libmemcachedprotocol/common.h @@ -21,7 +21,6 @@ #include "libmemcachedprotocol-0.0/handler.h" #include "libmemcachedprotocol/cache.h" #include "libmemcached/byteorder.h" -#include "libmemcached/socket.hpp" /* * I don't really need the following two functions as function pointers diff --git a/src/libmemcachedprotocol/handler.c b/src/libmemcachedprotocol/handler.c index b8484072..535795ca 100644 --- a/src/libmemcachedprotocol/handler.c +++ b/src/libmemcachedprotocol/handler.c @@ -26,10 +26,7 @@ #include #include -#include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif +#include "p9y/socket.hpp" /* ** ********************************************************************** diff --git a/src/p9y/CMakeLists.txt b/src/p9y/CMakeLists.txt new file mode 100644 index 00000000..1734f0b7 --- /dev/null +++ b/src/p9y/CMakeLists.txt @@ -0,0 +1,36 @@ +add_library(p9y STATIC + getopt.hpp + libgen.hpp + realpath.hpp + socket.hpp + poll.hpp + random.hpp + index.hpp + p9y.cpp + ) + +target_include_directories(p9y PRIVATE + . + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}/include + ) + +if(NOT HAVE_GETOPT_H) + target_sources(p9y PRIVATE getopt.c) +endif() +if(NOT HAVE_LIBGEN_H) + target_sources(p9y PRIVATE libgen.c) +endif() +if(NOT HAVE_REALPATH) + target_sources(p9y PRIVATE realpath.c) +endif() +if(WIN32) + target_sources(p9y PRIVATE socket.c) +endif() +if(NOT HAVE_POLL_H AND NOT HAVE_SYS_POLL_H AND NOT WIN32) + target_sources(p9y PRIVATE poll.c) +endif() +if(NOT HAVE_GETTIMEOFDAY) + target_sources(p9y PRIVATE gettimeofday.cpp) +endif() diff --git a/src/p9y/getopt.c b/src/p9y/getopt.c new file mode 100644 index 00000000..40434941 --- /dev/null +++ b/src/p9y/getopt.c @@ -0,0 +1,659 @@ +#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 + * + * 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__ + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef _WIN32 +# include +# include +#endif + +#include +#include +#include +#include +#include +#include + + +#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/p9y/getopt.hpp b/src/p9y/getopt.hpp new file mode 100644 index 00000000..f449d601 --- /dev/null +++ b/src/p9y/getopt.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "mem_config.h" + +#ifdef HAVE_GETOPT_H +# include +#else + +# ifdef __cplusplus +extern "C" { +# endif + +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); + +# ifdef __cplusplus +} +# endif + +#endif // HAVE_GETOPT_H diff --git a/src/p9y/gettimeofday.cpp b/src/p9y/gettimeofday.cpp new file mode 100644 index 00000000..7d002ca8 --- /dev/null +++ b/src/p9y/gettimeofday.cpp @@ -0,0 +1,23 @@ +#include "gettimeofday.hpp" + +#include + +#if !defined HAVE_GETTIMEOFDAY +int gettimeofday(struct timeval* tp, struct timezone*) { + using clock = std::chrono::system_clock; + auto as_sec = [] (auto d) { + return std::chrono::duration_cast(d); + }; + auto as_usec = [] (auto d) { + return std::chrono::duration_cast(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 diff --git a/src/p9y/gettimeofday.hpp b/src/p9y/gettimeofday.hpp new file mode 100644 index 00000000..02b8d6d9 --- /dev/null +++ b/src/p9y/gettimeofday.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "libmemcached-1.0/platform.h" + +#include +#if defined HAVE_SYS_TIME_H +# include +#endif + +#if !defined HAVE_GETTIMEOFDAY +int gettimeofday(struct timeval* tp, struct timezone* tzp); +#endif diff --git a/src/p9y/index.hpp b/src/p9y/index.hpp new file mode 100644 index 00000000..d193bf67 --- /dev/null +++ b/src/p9y/index.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "mem_config.h" + +#if defined HAVE_STRINGS_H +# include +#elif defined __cplusplus +# include +#else +# include +#endif + +#if !defined HAVE_INDEX +# define index strchr +#endif diff --git a/src/p9y/libgen.c b/src/p9y/libgen.c new file mode 100644 index 00000000..70696eb7 --- /dev/null +++ b/src/p9y/libgen.c @@ -0,0 +1,10 @@ +#include "libgen.hpp" + +#if defined _WIN32 +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; +} +#endif diff --git a/src/p9y/libgen.hpp b/src/p9y/libgen.hpp new file mode 100644 index 00000000..82976d7e --- /dev/null +++ b/src/p9y/libgen.hpp @@ -0,0 +1,20 @@ + +#include "mem_config.h" + +#if defined __cplusplus +# include +#else +# include +#endif + +#if defined HAVE_LIBGEN_H +# include +#elif defined _WIN32 +# if defined __cplusplus +extern "C" { +# endif +char *basename(const char *filename); +# if defined __cplusplus +} +# endif +#endif // HAVE_LIBGEN_H diff --git a/src/p9y/p9y.cpp b/src/p9y/p9y.cpp new file mode 100644 index 00000000..35ee8f01 --- /dev/null +++ b/src/p9y/p9y.cpp @@ -0,0 +1 @@ +// empty stub diff --git a/src/p9y/poll.c b/src/p9y/poll.c new file mode 100644 index 00000000..b745c8be --- /dev/null +++ b/src/p9y/poll.c @@ -0,0 +1,56 @@ +#include "poll.hpp" + +#if defined P9Y_NEED_POLL + +int poll(struct pollfd fds[], nfds_t nfds, int tmo) { + fd_set readfds, writefds, errorfds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&errorfds); + + int maxfd = 0; + + for (nfds_t x = 0; x < nfds; ++x) { + if (fds[x].events & (POLLIN | POLLOUT)) { +# ifndef _WIN32 + if (fds[x].fd > maxfd) { + maxfd = fds[x].fd; + } +# endif + if (fds[x].events & POLLIN) { + FD_SET(fds[x].fd, &readfds); + } + if (fds[x].events & POLLOUT) { + FD_SET(fds[x].fd, &writefds); + } + } + } + + struct timeval timeout = {tmo / 1000, (tmo % 1000) * 1000}; + struct timeval *tp = &timeout; + if (tmo == -1) { + tp = NULL; + } + int ret = select(maxfd + 1, &readfds, &writefds, &errorfds, tp); + if (ret <= 0) { + return ret; + } + + /* Iterate through all of them because I need to clear the revent map */ + for (nfds_t x = 0; x < nfds; ++x) { + fds[x].revents = 0; + if (FD_ISSET(fds[x].fd, &readfds)) { + fds[x].revents |= POLLIN; + } + if (FD_ISSET(fds[x].fd, &writefds)) { + fds[x].revents |= POLLOUT; + } + if (FD_ISSET(fds[x].fd, &errorfds)) { + fds[x].revents |= POLLERR; + } + } + + return ret; +} + +#endif // P9Y_NEED_POLL diff --git a/src/p9y/poll.hpp b/src/p9y/poll.hpp new file mode 100644 index 00000000..6a242618 --- /dev/null +++ b/src/p9y/poll.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "libmemcached-1.0/platform.h" + +#if defined HAVE_SYS_POLL_H +# include +#elif defined HAVE_POLL_H +# include +#elif defined _WIN32 +# define poll WSAPoll +typedef int nfds_t; +#else + +# define P9Y_NEED_POLL + +# ifdef __cplusplus +extern "C" { +# endif + +typedef struct pollfd { +# if defined(_WIN32) + SOCKET fd; +# else + int fd; +# endif + short events; + short revents; +} pollfd_t; + +typedef int nfds_t; + +# define POLLIN 0x0001 +# define POLLOUT 0x0004 +# define POLLERR 0x0008 +# define POLLHUP 0x010 /* Hung up. */ +# define POLLNVAL 0x020 /* Invalid polling request. */ + +int poll(struct pollfd fds[], nfds_t nfds, int tmo); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/p9y/random.hpp b/src/p9y/random.hpp new file mode 100644 index 00000000..213d2adb --- /dev/null +++ b/src/p9y/random.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "mem_config.h" + +#if defined __cplusplus +# include +#else +# include +#endif + +#if !defined HAVE_RANDOM +# if defined HAVE_RAND +# define random rand +# define srandom srand +# endif +#endif diff --git a/src/p9y/realpath.c b/src/p9y/realpath.c new file mode 100644 index 00000000..cf6430a2 --- /dev/null +++ b/src/p9y/realpath.c @@ -0,0 +1,7 @@ +#include "realpath.hpp" + +#if defined _WIN32 +char *realpath(const char *path, char real[_MAX_PATH]) { + return _fullpath(real, path, _MAX_PATH); +} +#endif diff --git a/src/p9y/realpath.hpp b/src/p9y/realpath.hpp new file mode 100644 index 00000000..ed63cfac --- /dev/null +++ b/src/p9y/realpath.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "mem_config.h" + +#if defined __cplusplus +# include +#else +# include +#endif + +#if !defined HAVE_REALPATH +# if defined _WIN32 +# if defined __cplusplus +extern "C" { +# endif +char *realpath(const char *path, char real[_MAX_PATH]); +# if defined __cplusplus +} +# endif +# endif // _WIN32 +#endif // HAVE_REALPATH diff --git a/src/p9y/socket.c b/src/p9y/socket.c new file mode 100644 index 00000000..1398e1d8 --- /dev/null +++ b/src/p9y/socket.c @@ -0,0 +1,50 @@ +#include "socket.hpp" + +#if defined _WIN32 +int get_socket_errno() { + int local_errno = WSAGetLastError(); + + switch (local_errno) { + case WSAEINVAL: + local_errno = EINPROGRESS; + break; + case WSAEALREADY: + case WSAEWOULDBLOCK: + local_errno = EAGAIN; + break; + + case WSAECONNREFUSED: + local_errno = ECONNREFUSED; + break; + + case WSAENETUNREACH: + local_errno = ENETUNREACH; + break; + + case WSAETIMEDOUT: + local_errno = ETIMEDOUT; + break; + + case WSAECONNRESET: + local_errno = ECONNRESET; + break; + + case WSAEADDRINUSE: + local_errno = EADDRINUSE; + break; + + case WSAEOPNOTSUPP: + local_errno = EOPNOTSUPP; + break; + + case WSAENOPROTOOPT: + local_errno = ENOPROTOOPT; + break; + + default: + break; + } + + return local_errno; +} +#endif // _WIN32 diff --git a/src/p9y/socket.hpp b/src/p9y/socket.hpp new file mode 100644 index 00000000..339b5995 --- /dev/null +++ b/src/p9y/socket.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "libmemcached-1.0/platform.h" + +#if defined __cplusplus +# include +#else +# include +#endif + +#if defined HAVE_ARPA_INET_H +# include +#endif + +#if defined HAVE_SYS_SOCKET_H +# include +#endif + +#if defined HAVE_SYS_UN_H +# include +#endif + +#if defined HAVE_UNISTD_H +# include +#endif + +#if defined __cplusplus +extern "C" { +#endif + +# if defined _WIN32 +int get_socket_errno(); +# define SHUT_WR SD_SEND +# define SHUT_RD SD_RECEIVE +# define SHUT_RDWR SD_BOTH +# else +# define closesocket close +# define get_socket_errno() errno +# define INVALID_SOCKET (-1) +# define SOCKET_ERROR (-1) +# endif + +#if defined __cplusplus +} +#endif + +#if !defined SOCK_CLOEXEC +# define SOCK_CLOEXEC 0 +#endif + +#if !defined SOCK_NONBLOCK +# define SOCK_NONBLOCK 0 +#endif + +#if !defined FD_CLOEXEC +# define FD_CLOEXEC 0 +#endif + +#if !defined SO_NOSIGPIPE +# define SO_NOSIGPIPE 0 +#endif + +#if !defined TCP_NODELAY +# define TCP_NODELAY 0 +#endif + +#if !defined TCP_KEEPIDLE +# define TCP_KEEPIDLE 0 +#endif + +#if !defined EAI_SYSTEM +# define EAI_SYSTEM (-1) +#endif + +#if !defined HAVE_MSG_NOSIGNAL +# define MSG_NOSIGNAL 0 +#endif + +#if !defined HAVE_MSG_MORE +# define MSG_MORE 0 +#endif diff --git a/src/win32/getopt.c b/src/win32/getopt.c deleted file mode 100644 index dd8cd704..00000000 --- a/src/win32/getopt.c +++ /dev/null @@ -1,652 +0,0 @@ -#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 - * - * 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 -#include -#include -#include -#include -#include -#include - - -#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 deleted file mode 100644 index 8f0835b7..00000000 --- a/src/win32/getopt.h +++ /dev/null @@ -1,30 +0,0 @@ -#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 diff --git a/test/lib/common.hpp b/test/lib/common.hpp index e522f9cc..083efe0d 100644 --- a/test/lib/common.hpp +++ b/test/lib/common.hpp @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include #include