1
1
Fork 0
mirror of https://github.com/oxen-io/lokinet synced 2023-12-14 06:53:00 +01:00

Allow builds on MSVC (#518)

* Import cxxopts to replace getopts usage

* Add visual studio build things

* Fixup abseil build parts

* Replace __attribute__((unused)) with ABSL_ATTRIBUTE_UNUSED

* Fixup minor windows build issues

* Replace getopts usage

* Temporarily fixup .rc files

* More minor windows fixes

* Get a working build

* Revert .rc files

* Revert changes to nodedb
This commit is contained in:
michael-loki 2019-04-19 19:24:33 +01:00 committed by Rick V
parent 52b2b3bf44
commit 0195152e05
62 changed files with 14047 additions and 176 deletions

1
.gitignore vendored
View file

@ -35,6 +35,7 @@ testnet_tmp
*.pid
vsproject/
.vs
daemon.ini
lokinet-win32.exe

View file

@ -2,7 +2,7 @@
cmake_minimum_required(VERSION 3.6.0)
set(PROJECT_NAME lokinet)
project(${PROJECT_NAME} C CXX ASM)
project(${PROJECT_NAME} C CXX)
# Core options
option(USE_AVX2 "enable avx2 code" )
@ -28,15 +28,23 @@ if(CCACHE_PROGRAM)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
endif()
if (MSVC_VERSION)
enable_language(ASM_MASM)
list(APPEND CMAKE_ASM_MASM_SOURCE_FILE_EXTENSIONS s)
add_definitions(/D_WIN32_WINNT=0x0600 /DNOMINMAX /DSODIUM_STATIC)
else()
enable_language(ASM)
endif(MSVC_VERSION)
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
# check if we have the (saner) emulation of epoll here
# it's basically linux epoll but with a sane method of
# dealing with closed file handles that still exist in the
# epoll set
#
# Note that the zombie of Oracle Solaris 2.11.x will NOT have
# this, the header check is the only method we have to distinguish
# them. -rick the svr4 guy
# check if we have the (saner) emulation of epoll here
# it's basically linux epoll but with a sane method of
# dealing with closed file handles that still exist in the
# epoll set
#
# Note that the zombie of Oracle Solaris 2.11.x will NOT have
# this, the header check is the only method we have to distinguish
# them. -rick the svr4 guy
set(SOLARIS ON)
option(USE_POLL "Revert to using poll(2) event loop (useful if targeting Oracle Solaris)" OFF)
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lsocket -lnsl")
@ -72,6 +80,7 @@ if (WIN32 AND NOT STATIC_LINK_RUNTIME)
message("for release builds, turn on STATIC_LINK_RUNTIME in cmake options")
endif(WIN32 AND NOT STATIC_LINK_RUNTIME)
add_subdirectory(vendor/cxxopts)
add_subdirectory(vendor/nlohmann)
# still need the headers unconditionally
@ -90,11 +99,13 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wno-unknown-warning-option)
endif()
add_compile_options(-Wall -Wextra -Wno-unknown-pragmas)
# vla are evil
add_compile_options(-Wvla)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
add_compile_options(-Wno-unused-function -Wno-deprecated-declarations -Wno-unknown-pragmas)
if (NOT MSVC_VERSION)
add_compile_options(-Wall -Wextra -Wno-unknown-pragmas)
# vla are evil
add_compile_options(-Wvla)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
add_compile_options(-Wno-unused-function -Wno-deprecated-declarations -Wno-unknown-pragmas)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wthread-safety)
@ -127,15 +138,15 @@ if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
endif()
endif(WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
if(WIN32)
if(WIN32 AND NOT MSVC_VERSION)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-cast-function-type>)
# unlike unix where you get a *single* compiler ID string in .comment
# GNU ld sees fit to merge *all* the .ident sections in object files
# to .r[o]data section one after the other!
# unlike unix where you get a *single* compiler ID string in .comment
# GNU ld sees fit to merge *all* the .ident sections in object files
# to .r[o]data section one after the other!
add_compile_options(-fno-ident)
set(FS_LIB stdc++fs)
endif(WIN32)
endif()
if(DEBIAN)
add_definitions(-DDEBIAN)
@ -184,10 +195,10 @@ if(TESTNET)
add_definitions(-DTESTNET=1)
endif(TESTNET)
if(NOT DEBIAN)
if(NOT DEBIAN AND NOT MSVC_VERSION)
set(OPTIMIZE_FLAGS -O3)
set(DEBUG_FLAGS -O0 -g3)
endif(NOT DEBIAN)
endif()
if(ASAN)
set(DEBUG_FLAGS ${DEBUG_FLAGS} -fsanitize=address -fno-omit-frame-pointer)
@ -232,8 +243,9 @@ endif(NON_PC_TARGET)
add_compile_options(${OPTIMIZE_FLAGS} ${CRYPTO_FLAGS})
if(NOT GIT_VERSION)
exec_program("git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "rev-parse --short HEAD" OUTPUT_VARIABLE GIT_VERSION)
add_definitions(-DGIT_REV="${GIT_VERSION}")
exec_program("git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "rev-parse --short HEAD" OUTPUT_VARIABLE GIT_VERSION_UNSTRIP)
string(STRIP "${GIT_VERSION_UNSTRIP}" GIT_VERSION)
add_definitions("-DGIT_REV=\"${GIT_VERSION}\"")
endif(NOT GIT_VERSION)
if(RELEASE_MOTTO)
@ -320,7 +332,7 @@ if(UNIX)
elseif(WIN32)
get_filename_component(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-windows.c ABSOLUTE)
get_filename_component(EV_SRC "llarp/ev/ev_win32.cpp" ABSOLUTE)
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500)
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32 -DWINVER=0x0602 -D_WIN32_WINNT=0x0602)
else()
message(FATAL_ERROR "What operating system _are_ you building on/for?")
endif(UNIX)
@ -366,12 +378,17 @@ target_link_libraries(${ABYSS_LIB} PUBLIC ${PLATFORM_LIB})
if (NOT WIN32)
add_executable(${ABYSS_EXE} ${ABYSS}/main.cpp)
target_link_libraries(${ABYSS_EXE} PUBLIC ${ABYSS_LIB} Threads::Threads)
else()
elseif(NOT MSVC_VERSION)
add_executable(${ABYSS_EXE} ${ABYSS}/main.cpp llarp/win32/abyss.rc)
target_link_libraries(${ABYSS_EXE} PUBLIC ${ABYSS_LIB} ${STATIC_LIB} ws2_32)
else()
add_executable(${ABYSS_EXE} ${ABYSS}/main.cpp)
target_link_libraries(${ABYSS_EXE} PUBLIC ${ABYSS_LIB} ${STATIC_LIB} ws2_32)
endif(NOT WIN32)
target_include_directories(${ABYSS_LIB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${ABYSS}/include")
target_include_directories(${ABYSS_EXE} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${ABYSS}/include")
# for freebsd
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
target_include_directories(${ABYSS_LIB} PUBLIC /usr/local/include)
@ -395,8 +412,10 @@ if(SHADOW)
else()
if(NOT WIN32)
add_executable(${EXE} ${EXE_SRC})
else()
elseif(NOT MSVC_VERSION)
add_executable(${EXE} ${EXE_SRC} llarp/win32/version.rc)
else()
add_executable(${EXE} ${EXE_SRC})
endif(NOT WIN32)
add_log_tag(${EXE})
@ -424,6 +443,6 @@ endif(SHADOW)
enable_testing()
if (NOT SHADOW)
if (NOT SHADOW AND NOT MSVC_VERSION)
add_subdirectory(test)
endif()

16
CMakeSettings.json Normal file
View file

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": []
}
]
}

View file

@ -19,8 +19,7 @@
/* C++Builder defines a "random" macro */
#undef random
static const randombytes_implementation *implementation =
&randombytes_salsa20_implementation;
static const randombytes_implementation *implementation = 0;
static void
randombytes_init_if_needed(void)

View file

@ -69,8 +69,12 @@ typedef NTSTATUS(FAR PASCAL *CNGAPI_DRBG)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG,
#endif
#ifndef TLS
#ifdef _WIN32
#ifdef _WIN32
#ifdef _MSC_VER
#define TLS __declspec(thread)
#else
#define TLS __thread
#endif
#else
#define TLS
#endif

View file

@ -1,16 +1,15 @@
#include <config.hpp> // for ensure_config
#include <libgen.h>
#include <llarp.h>
#include <util/fs.hpp>
#include <util/logger.hpp>
#include <getopt.h>
#include <signal.h>
#if !defined(_WIN32) && !defined(__OpenBSD__)
#include <wordexp.h>
#endif
#include <cxxopts.hpp>
#include <string>
#include <iostream>
@ -104,43 +103,75 @@ main(int argc, char *argv[])
absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
#endif
int opt = 0;
// clang-format off
cxxopts::Options options(
"lokinet",
"Lokinet is a private, decentralized and IP based overlay network for the internet"
);
options.add_options()
("v,verbose", "Verbose", cxxopts::value<bool>())
("h,help", "help", cxxopts::value<bool>())
("g,generate", "generate config", cxxopts::value<bool>())
("c,config", "generate config", cxxopts::value<bool>())
("r,router", "run as router", cxxopts::value<bool>())
("f,force", "overwrite", cxxopts::value<bool>());
options.parse_positional({"config_file"});
// clang-format on
bool genconfigOnly = false;
bool asRouter = false;
bool overWrite = false;
while((opt = getopt(argc, argv, "hgcfrv")) != -1)
{
switch(opt)
{
case 'v':
SetLogLevel(llarp::eLogDebug);
llarp::LogDebug("debug logging activated");
break;
case 'h':
return printHelp(argv[0], 0);
case 'g':
genconfigOnly = true;
break;
case 'c':
genconfigOnly = true;
break;
case 'r':
asRouter = true;
break;
case 'f':
overWrite = true;
break;
default:
return printHelp(argv[0]);
}
}
std::string conffname; // suggestions: confFName? conf_fname?
if(optind < argc)
try
{
auto result = options.parse(argc, argv);
if(result.count("verbose") > 0)
{
SetLogLevel(llarp::eLogDebug);
llarp::LogDebug("debug logging activated");
}
if(result.count("help"))
{
return printHelp(argv[0], 0);
}
if(result.count("generate") > 0 || result.count("config") > 0)
{
genconfigOnly = true;
}
if(result.count("force") > 0)
{
overWrite = true;
}
if(result.count("router") > 0)
{
asRouter = true;
}
if(result.count("config_file") > 0)
{
auto vec = result["config_file"].as< std::vector< std::string > >();
if(!vec.empty())
{
conffname = vec[0];
}
}
}
catch (const cxxopts::option_not_exists_exception& ex)
{
std::cerr << ex.what();
return printHelp(argv[0]);
}
if(!conffname.empty())
{
// when we have an explicit filepath
fs::path fname = fs::path(argv[optind]);
fs::path fname = fs::path(conffname);
fs::path basedir = fname.parent_path();
conffname = fname.string();
conffname = resolvePath(conffname);

View file

@ -77,6 +77,7 @@
* - t_tun_in6_addr: struct in6_addr/IN6_ADDR
*/
#if defined Windows
#include <windows.h>
#include <in6addr.h>
#include <winsock2.h>
typedef HANDLE t_tun;

View file

@ -15,7 +15,7 @@ struct DemoHandler : public abyss::httpd::IRPCHandler
absl::optional< Response >
HandleJSONRPC(Method_t method,
__attribute__((unused)) const Params& params) override
ABSL_ATTRIBUTE_UNUSED const Params& params) override
{
llarp::LogInfo("method: ", method);
return Response::object();
@ -50,7 +50,7 @@ struct DemoCall : public abyss::http::IRPCClientHandler
}
void
PopulateReqHeaders(__attribute__((unused))
PopulateReqHeaders(ABSL_ATTRIBUTE_UNUSED
abyss::http::Headers_t& hdr) override
{
}
@ -102,7 +102,7 @@ struct DemoServer : public abyss::httpd::BaseReqHandler
};
int
main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[])
main(ABSL_ATTRIBUTE_UNUSED int argc, ABSL_ATTRIBUTE_UNUSED char* argv[])
{
// Ignore on Windows, we don't even get SIGPIPE (even though native *and*
// emulated UNIX pipes exist - CreatePipe(2), pipe(3))

View file

@ -78,7 +78,7 @@ namespace abyss
}
static void
OnTick(__attribute__((unused)) llarp_tcp_conn* conn)
OnTick(ABSL_ATTRIBUTE_UNUSED llarp_tcp_conn* conn)
{
}

View file

@ -38,6 +38,8 @@ typedef uint32 utp_link_t;
#pragma warning(disable : 4200)
#endif
#include <absl/base/attributes.h>
typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize);
typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b,
size_t keysize);
@ -146,12 +148,12 @@ class utpHashTable
public:
static uint
compare(const void *k1, const void *k2, __attribute__((unused)) size_t ks)
compare(const void *k1, const void *k2, ABSL_ATTRIBUTE_UNUSED size_t ks)
{
return *((K *)k1) == *((K *)k2);
}
static uint32
compute_hash(const void *k, __attribute__((unused)) size_t ks)
compute_hash(const void *k, ABSL_ATTRIBUTE_UNUSED size_t ks)
{
return ((K *)k)->compute_hash();
}

View file

@ -41,6 +41,7 @@
#include <mach/mach_time.h>
#endif
#include <absl/base/attributes.h>
#include "utp_utils.h"
#ifdef WIN32
@ -286,20 +287,20 @@ utp_default_get_udp_overhead(utp_callback_arguments *args)
}
uint64
utp_default_get_random(__attribute__((unused)) utp_callback_arguments *args)
utp_default_get_random(ABSL_ATTRIBUTE_UNUSED utp_callback_arguments *args)
{
return rand();
}
uint64
utp_default_get_milliseconds(__attribute__((unused))
utp_default_get_milliseconds(ABSL_ATTRIBUTE_UNUSED
utp_callback_arguments *args)
{
return UTP_GetMilliseconds();
}
uint64
utp_default_get_microseconds(__attribute__((unused))
utp_default_get_microseconds(ABSL_ATTRIBUTE_UNUSED
utp_callback_arguments *args)
{
return UTP_GetMicroseconds();

View file

@ -46,12 +46,12 @@ set(LIB_UTIL_SRC
add_library(${UTIL_LIB} STATIC ${LIB_UTIL_SRC})
target_include_directories(${UTIL_LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(${UTIL_LIB} PUBLIC absl::synchronization)
target_link_libraries(${UTIL_LIB} PUBLIC absl::synchronization absl::hash)
target_link_libraries(${UTIL_LIB} PUBLIC nlohmann_json::nlohmann_json)
# cut back on fluff
if (NOT WIN32)
target_link_libraries(${UTIL_LIB} PUBLIC absl::optional absl::variant absl::strings absl::hash cppbackport)
target_link_libraries(${UTIL_LIB} PUBLIC absl::optional absl::variant absl::strings cppbackport)
endif(NOT WIN32)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@ -239,7 +239,7 @@ endif()
add_library(${STATIC_LIB} STATIC ${LIB_SRC})
set(LIBS ${LIBS} libutp)
target_link_libraries(${STATIC_LIB} PUBLIC ${ABYSS_LIB} ${PLATFORM_LIB} ${UTIL_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS})
target_link_libraries(${STATIC_LIB} PUBLIC cxxopts ${ABYSS_LIB} ${PLATFORM_LIB} ${UTIL_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS})
if(WITH_SHARED)
add_library(${SHARED_LIB} SHARED ${LIB_SRC})

View file

@ -16,11 +16,9 @@
#include <util/scheduler.hpp>
#include <absl/strings/str_split.h>
#include <getopt.h>
#include <cxxopts.hpp>
#include <signal.h>
#include <sys/param.h> // for MIN
#if(__FreeBSD__) || (__OpenBSD__) || (__NetBSD__)
#include <pthread_np.h>
#endif
@ -645,50 +643,40 @@ extern "C"
const char *
handleBaseCmdLineArgs(int argc, char *argv[])
{
const char *conffname = "daemon.ini";
int c;
while(1)
// clang-format off
cxxopts::Options options(
"lokinet",
"Lokinet is a private, decentralized and IP based overlay network for the internet"
);
options.add_options()
("c,config", "Config file", cxxopts::value< std::string >()->default_value("daemon.ini"))
("o,logLevel", "logging level");
// clang-format on
auto result = options.parse(argc, argv);
std::string logLevel = result["logLevel"].as< std::string >();
if(logLevel == "debug")
{
static struct option long_options[] = {
{"config", required_argument, 0, 'c'},
{"logLevel", required_argument, 0, 'o'},
{0, 0, 0, 0}};
int option_index = 0;
c = getopt_long(argc, argv, "c:o:", long_options, &option_index);
if(c == -1)
break;
switch(c)
{
case 0:
break;
case 'c':
conffname = optarg;
break;
case 'o':
if(strncmp(optarg, "debug", std::min(strlen(optarg), size_t(5))) == 0)
{
cSetLogLevel(eLogDebug);
}
else if(strncmp(optarg, "info", std::min(strlen(optarg), size_t(4)))
== 0)
{
cSetLogLevel(eLogInfo);
}
else if(strncmp(optarg, "warn", std::min(strlen(optarg), size_t(4)))
== 0)
{
cSetLogLevel(eLogWarn);
}
else if(strncmp(optarg, "error", std::min(strlen(optarg), size_t(5)))
== 0)
{
cSetLogLevel(eLogError);
}
break;
default:
break;
}
cSetLogLevel(eLogDebug);
}
return conffname;
else if(logLevel == "info")
{
cSetLogLevel(eLogInfo);
}
else if(logLevel == "warn")
{
cSetLogLevel(eLogWarn);
}
else if(logLevel == "error")
{
cSetLogLevel(eLogError);
}
// this isn't thread safe, but reconfiguring during run is likely unsafe either way
static std::string confname = result["config"].as< std::string >();
return confname.c_str();
}
}

View file

@ -23,8 +23,7 @@ dns_iptracker_init()
// not sure we want tunGatewayIP... we'll know when we get further
bool
dns_iptracker_setup_dotLokiLookup(dotLokiLookup *dll,
__attribute__((unused))
dns_iptracker_setup_dotLokiLookup(dotLokiLookup *dll, ABSL_ATTRIBUTE_UNUSED
llarp::huint32_t tunGatewayIp)
{
dll->ip_tracker = &g_dns_iptracker;

View file

@ -7,12 +7,12 @@
#include <netdb.h> /* getaddrinfo, getnameinfo */
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> /* close */
#endif
#include <stdlib.h> /* exit */
#include <string.h> /* memset */
#include <sys/types.h>
#include <unistd.h> /* close */
#include <algorithm> // for std::find_if
#include <stdio.h> // sprintf
@ -814,7 +814,7 @@ llarp_dnsc_init(struct dnsc_context *const dnsc, llarp::Logic *const logic,
}
bool
llarp_dnsc_stop(__attribute__((unused)) struct dnsc_context *const dnsc)
llarp_dnsc_stop(ABSL_ATTRIBUTE_UNUSED struct dnsc_context *const dnsc)
{
// delete(sockaddr_in *)dnsc->server; // deallocation
return true;

View file

@ -9,9 +9,14 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#ifndef ssize_t
#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#else
#define ssize_t long
#endif
#else
#include <netinet/in.h>
#include <sys/socket.h>

View file

@ -9,13 +9,13 @@
// writev
#ifndef _WIN32
#include <sys/uio.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <deque>
#include <list>
#include <future>
#include <unistd.h>
#ifdef _WIN32
#include <win32/win32_up.h>

View file

@ -35,6 +35,12 @@ win32_tun_io::queue_write(const byte_t* buf, size_t sz)
bool
win32_tun_io::setup()
{
// Create a critical section to synchronise access to the TUN handler.
// This *probably* has the effect of making packets move in order now
// as only one IOCP thread will have access to the TUN handler at a
// time
InitializeCriticalSection(&HandlerMtx);
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
llarp::LogWarn("failed to start interface");
@ -59,12 +65,6 @@ win32_tun_io::setup()
if(tunif->tun_fd == INVALID_HANDLE_VALUE)
return false;
// Create a critical section to synchronise access to the TUN handler.
// This *probably* has the effect of making packets move in order now
// as only one IOCP thread will have access to the TUN handler at a
// time
InitializeCriticalSection(&HandlerMtx);
return true;
}

View file

@ -1,6 +1,8 @@
#include <ev/pipe.hpp>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <fcntl.h>
llarp_ev_pkt_pipe::llarp_ev_pkt_pipe(llarp_ev_loop_ptr loop)

View file

@ -38,14 +38,14 @@ namespace llarp
}
bool
DecodeKey(__attribute__((unused)) const llarp_buffer_t& key,
__attribute__((unused)) llarp_buffer_t* buf) override
DecodeKey(ABSL_ATTRIBUTE_UNUSED const llarp_buffer_t& key,
ABSL_ATTRIBUTE_UNUSED llarp_buffer_t* buf) override
{
return false;
}
bool
HandleMessage(__attribute__((unused)) AbstractRouter* router) const override
HandleMessage(ABSL_ATTRIBUTE_UNUSED AbstractRouter* router) const override
{
return true;
}

View file

@ -11,6 +11,8 @@
#include <util/logger.hpp>
#include <util/metrics.hpp>
#include <memory>
namespace llarp
{
struct InboundMessageParser::msg_holder_t
@ -21,18 +23,21 @@ namespace llarp
DHTImmediateMessage m;
LR_CommitMessage c;
DiscardMessage x;
msg_holder_t() = default;
};
InboundMessageParser::InboundMessageParser(AbstractRouter* _router)
: router(_router)
, from(nullptr)
, msg(nullptr)
, holder(std::make_unique< msg_holder_t >())
, holder(new msg_holder_t())
{
}
InboundMessageParser::~InboundMessageParser()
{
delete holder;
}
bool

View file

@ -45,7 +45,7 @@ namespace llarp
ILinkMessage* msg;
struct msg_holder_t;
std::unique_ptr< msg_holder_t > holder;
msg_holder_t *holder;
};
} // namespace llarp
#endif

View file

@ -240,7 +240,7 @@ namespace llarp
for(const std::string &val : toSend)
{
ssize_t sentLen = 0;
int sentLen = 0;
do
{

View file

@ -98,7 +98,7 @@ namespace llarp
}
static void
checksumDstIPv4TCP(byte_t *pld, __attribute__((unused)) size_t psz,
checksumDstIPv4TCP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, size_t chksumoff, nuint32_t oSrcIP,
nuint32_t oDstIP, nuint32_t nSrcIP, nuint32_t nDstIP)
{
@ -117,7 +117,7 @@ namespace llarp
}
static void
checksumDstIPv4UDP(byte_t *pld, __attribute__((unused)) size_t psz,
checksumDstIPv4UDP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, nuint32_t oSrcIP, nuint32_t oDstIP,
nuint32_t nSrcIP, nuint32_t nDstIP)
{
@ -186,7 +186,7 @@ namespace llarp
}
static void
checksumSrcIPv4TCP(byte_t *pld, __attribute__((unused)) size_t psz,
checksumSrcIPv4TCP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, size_t chksumoff, nuint32_t oSrcIP,
nuint32_t oDstIP)
{
@ -206,7 +206,7 @@ namespace llarp
}
static void
checksumSrcIPv4UDP(byte_t *pld, __attribute__((unused)) size_t psz,
checksumSrcIPv4UDP(byte_t *pld, ABSL_ATTRIBUTE_UNUSED size_t psz,
size_t fragoff, nuint32_t oSrcIP, nuint32_t oDstIP)
{
if(fragoff > 6)

View file

@ -11,6 +11,12 @@
#include <set>
#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
/**
* nodedb.hpp
*

View file

@ -15,6 +15,7 @@
#include <util/threading.hpp>
#include <util/time.hpp>
#include <algorithm>
#include <functional>
#include <list>
#include <map>

View file

@ -11,8 +11,8 @@ namespace llarp
}
bool
PoW::DecodeKey(__attribute__((unused)) const llarp_buffer_t& k,
__attribute__((unused)) llarp_buffer_t* val)
PoW::DecodeKey(ABSL_ATTRIBUTE_UNUSED const llarp_buffer_t& k,
ABSL_ATTRIBUTE_UNUSED llarp_buffer_t* val)
{
// TODO: implement me
return false;

View file

@ -73,7 +73,7 @@ namespace llarp
NetID::BEncode(llarp_buffer_t *buf) const
{
auto term = std::find(begin(), end(), '\0');
return bencode_write_bytestring(buf, begin(), std::distance(begin(), term));
return bencode_write_bytestring(buf, data(), std::distance(begin(), term));
}
bool

View file

@ -20,7 +20,7 @@ bool
llarp_buffer_t::writef(const char* fmt, ...)
{
int written;
ssize_t sz = size_left();
size_t sz = size_left();
va_list args;
va_start(args, fmt);
written = vsnprintf(reinterpret_cast< char* >(cur), sz, fmt, args);

View file

@ -128,12 +128,14 @@ struct llarp_buffer_t
#ifndef _WIN32
bool
writef(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
;
#else
#elif defined(__MINGW64__) || defined(__MINGW32__)
bool
writef(const char *fmt, ...)
__attribute__((__format__(__MINGW_PRINTF_FORMAT, 2, 3)));
;
#else
bool
writef(const char *fmt, ...);
#endif
bool

View file

@ -16,7 +16,9 @@ namespace fs = std::experimental::filesystem;
namespace fs = cpp17::filesystem;
#endif
#ifndef _MSC_VER
#include <dirent.h>
#endif
namespace llarp
{
@ -26,6 +28,15 @@ namespace llarp
using PathIter = std::function< void(const fs::path &, PathVisitor) >;
static PathIter IterDir = [](const fs::path &path, PathVisitor visit) {
#ifdef _MSC_VER
for(auto &p : fs::directory_iterator(path))
{
if(!visit(p.path()))
{
break;
}
}
#else
DIR *d = opendir(path.string().c_str());
if(d == nullptr)
return;
@ -42,6 +53,7 @@ namespace llarp
break;
} while(ent);
closedir(d);
#endif
};
} // namespace util
} // namespace llarp

View file

@ -1,6 +1,8 @@
#ifndef LLARP_UTIL_LOGGER_INTERNAL_HPP
#define LLARP_UTIL_LOGGER_INTERNAL_HPP
#include <absl/time/clock.h>
#include <absl/time/time.h>
#include <util/time.hpp>
#include <sstream>
#include <ctime>
@ -55,8 +57,7 @@ namespace llarp
(void)ts;
return out << time_now_ms();
#else
auto now = llarp::Clock_t::to_time_t(llarp::Clock_t::now());
return out << std::put_time(std::localtime(&now), ts.format);
return out << absl::FormatTime(ts.format, absl::Now(), absl::LocalTimeZone());
#endif
}
};

View file

@ -2,6 +2,8 @@
#include <util/mem.h>
#include <cstdlib>
#include <absl/base/attributes.h>
namespace llarp
{
void
@ -17,9 +19,9 @@ namespace llarp
} // namespace llarp
void
llarp_mem_slab(__attribute__((unused)) struct llarp_alloc *mem,
__attribute__((unused)) uint32_t *buf,
__attribute__((unused)) size_t sz)
llarp_mem_slab(ABSL_ATTRIBUTE_UNUSED struct llarp_alloc *mem,
ABSL_ATTRIBUTE_UNUSED uint32_t *buf,
ABSL_ATTRIBUTE_UNUSED size_t sz)
{
// not implemented
abort();

View file

@ -93,15 +93,4 @@ namespace llarp
} // namespace llarp
#if __cplusplus < 201402L
namespace std
{
template < typename T, typename... Args >
std::unique_ptr< T >
make_unique(Args &&... args)
{
return std::unique_ptr< T >(new T(std::forward< Args >(args)...));
}
} // namespace std
#endif
#endif

View file

@ -17,7 +17,7 @@ namespace llarp
/// a lock that does nothing
struct SCOPED_LOCKABLE NullLock
{
NullLock(__attribute__((unused)) const NullMutex* mtx)
NullLock(ABSL_ATTRIBUTE_UNUSED const NullMutex* mtx)
EXCLUSIVE_LOCK_FUNCTION(mtx)
{
}

View file

@ -184,7 +184,7 @@ upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;
unote_t* nvec[nev];
unote_t** nvec = calloc(nev, sizeof(unote_t *));
int i, maxfd = 0, e = 0, nfds = 0;
fd_set pollin, pollout, pollerr;
@ -240,6 +240,7 @@ upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
if(rc == SOCKET_ERROR)
{
assert(WSAGetLastError() == WSAENOTSOCK);
free(nvec);
return -WSAGetLastError();
}
@ -269,6 +270,7 @@ upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
++e;
}
}
free(nvec);
return e;
}

View file

@ -67,5 +67,5 @@ if(NOT WIN32)
target_link_libraries(${TEST_EXE} PUBLIC absl::variant)
else()
target_sources(${TEST_EXE} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/win32/test.rc")
target_link_libraries(${TEST_EXE} PUBLIC ws2_32 iphlpapi)
target_link_libraries(${TEST_EXE} PUBLIC ws2_32 iphlpapi shlwapi)
endif(NOT WIN32)

View file

@ -31,7 +31,7 @@ struct AbyssTestBase : public ::testing::Test
}
static void
CancelIt(void* u, __attribute__((unused)) uint64_t orig, uint64_t left)
CancelIt(void* u, ABSL_ATTRIBUTE_UNUSED uint64_t orig, uint64_t left)
{
if(left)
return;
@ -104,12 +104,12 @@ struct ClientHandler : public abyss::http::IRPCClientHandler
}
void
PopulateReqHeaders(__attribute__((unused)) abyss::http::Headers_t& hdr)
PopulateReqHeaders(ABSL_ATTRIBUTE_UNUSED abyss::http::Headers_t& hdr)
{
}
bool
HandleResponse(__attribute__((unused)) abyss::http::RPC_Response response)
HandleResponse(ABSL_ATTRIBUTE_UNUSED abyss::http::RPC_Response response)
{
test->AsyncStop();
return true;
@ -125,7 +125,7 @@ struct ServerHandler : public abyss::httpd::IRPCHandler
}
absl::optional< Response >
HandleJSONRPC(Method_t method, __attribute__((unused)) const Params& params)
HandleJSONRPC(Method_t method, ABSL_ATTRIBUTE_UNUSED const Params& params)
{
test->AssertMethod(method);
test->called = true;

View file

@ -69,11 +69,11 @@ endif()
list(APPEND ABSL_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
# -std=X
if (WIN32)
if (WIN32 AND NOT MSVC_VERSION)
set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS} -fno-ident")
else()
set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
endif(WIN32)
endif(WIN32 AND NOT MSVC_VERSION)
# -fexceptions
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")

View file

@ -19,6 +19,8 @@
#ifdef _WIN32
#include <shlwapi.h>
#include <windows.h>
#pragma comment(lib, "shlwapi.lib")
#else
#include <fcntl.h>
#include <pthread.h>

View file

@ -181,9 +181,9 @@ absl_cc_library(
NAME
leak_check
HDRS
"$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:leak_check.h>"
"leak_check.h"
SRCS
"$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:leak_check.cc>"
"leak_check.cc"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS

8
vendor/cxxopts/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
*.swp
build*
CMakeCache.txt
Makefile
CMakeFiles/
Testing/
CTestTestfile.cmake
cmake_install.cmake

70
vendor/cxxopts/.travis.yml vendored Normal file
View file

@ -0,0 +1,70 @@
sudo: required
dist: trusty
language: cpp
os:
- linux
matrix:
include:
- os: linux
env: COMPILER=g++-4.9
addons:
apt:
packages:
- g++-4.9
sources: &sources
- llvm-toolchain-trusty-3.8
- llvm-toolchain-trusty-5.0
- ubuntu-toolchain-r-test
- os: linux
env: COMPILER=g++-4.9 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
addons:
apt:
packages:
- g++-4.9
sources: *sources
- os: linux
env: COMPILER=g++-5
addons:
apt:
packages:
- g++-5
sources: *sources
- os: linux
env: COMPILER=g++-5 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
addons:
apt:
packages:
- g++-5
sources: *sources
- os: linux
env: COMPILER=clang++-3.8 CXXFLAGS=-stdlib=libc++
addons:
apt:
packages:
- clang-3.8
- libc++-dev
sources: *sources
- os: linux
env: COMPILER=clang++-3.8 CXXFLAGS=-stdlib=libc++ UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
addons:
apt:
packages:
- clang-3.8
- libc++-dev
sources: *sources
- os: linux
env: COMPILER=clang++-5.0 CMAKE_OPTIONS=-DCXXOPTS_CXX_STANDARD=17
addons:
apt:
packages:
- clang-5.0
- g++-5
sources: *sources
script: >
cmake -DCXXOPTS_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=$COMPILER
-DCMAKE_CXX_FLAGS=$CXXFLAGS $UNICODE_OPTIONS $CMAKE_OPTIONS .
&& make && make ARGS=--output-on-failure test
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install icu4c; fi

82
vendor/cxxopts/CHANGELOG.md vendored Normal file
View file

@ -0,0 +1,82 @@
# Changelog
This is the changelog for `cxxopts`, a C++11 library for parsing command line
options. The project adheres to semantic versioning.
## 2.2
### Changed
* Allow integers to have leading zeroes.
* Build the tests by default.
### Added
* Iterator inputs to `parse_positional`.
### Bug Fixes
* Fix a warning about possible loss of data.
* Fix version numbering in CMakeLists.txt
* Remove unused declaration of the undefined `ParseResult::get_option`.
* Throw on invalid option syntax when beginning with a `-`.
* Throw in `as` when option wasn't present.
* Fix catching exceptions by reference.
## 2.1.1
### Bug Fixes
* Revert the change adding `const` type for `argv`, because most users expect
to pass a non-const `argv` from `main`.
## 2.1
### Changed
* Options with implicit arguments now require the `--option=value` form if
they are to be specified with an option. This is to remove the ambiguity
when a positional argument could follow an option with an implicit value.
For example, `--foo value`, where `foo` has an implicit value, will be
parsed as `--foo=implicit` and a positional argument `value`.
* Boolean values are no longer special, but are just an option with a default
and implicit value.
### Added
* Added support for `std::optional` as a storage type.
* Allow the help string to be customised.
* Use `const` for the type in the `argv` parameter, since the contents of the
arguments is never modified.
### Bug Fixes
* Building against GCC 4.9 was broken due to overly strict shadow warnings.
* Fixed an ambiguous overload in the `parse_positional` function when an
`initializer_list` was directly passed.
* Fixed precedence in the Boolean value regex.
## 2.0
### Changed
* `Options::parse` returns a ParseResult rather than storing the parse
result internally.
* Options with default values now get counted as appearing once if they
were not specified by the user.
### Added
* A new `ParseResult` object that is the immutable result of parsing. It
responds to the same `count` and `operator[]` as `Options` of 1.x did.
* The function `ParseResult::arguments` returns a vector of the parsed
arguments to iterate through in the order they were provided.
* The symbol `cxxopts::version` for the version of the library.
* Booleans can be specified with various strings and explicitly set false.
## 1.x
The 1.x series was the first major version of the library, with release numbers
starting to follow semantic versioning, after 0.x being unstable. It never had
a changelog maintained for it. Releases mostly contained bug fixes, with the
occasional feature added.

104
vendor/cxxopts/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,104 @@
# Copyright (c) 2014 Jarryd Beck
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
cmake_minimum_required(VERSION 3.1)
# parse the current version from the cxxopts header
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/cxxopts.hpp" cxxopts_version_defines
REGEX "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH)")
foreach(ver ${cxxopts_version_defines})
if(ver MATCHES "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
set(CXXOPTS__VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
endif()
endforeach()
set(VERSION ${CXXOPTS__VERSION_MAJOR}.${CXXOPTS__VERSION_MINOR}.${CXXOPTS__VERSION_PATCH})
message(STATUS "cxxopts version ${VERSION}")
project(cxxopts VERSION "${VERSION}")
enable_testing()
option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON)
option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" ON)
# request c++11 without gnu extension for the whole project and enable more warnings
if (CXXOPTS_CXX_STANDARD)
set(CMAKE_CXX_STANDARD ${CXXOPTS_CXX_STANDARD})
else()
set(CMAKE_CXX_STANDARD 11)
endif()
set(CMAKE_CXX_EXTENSIONS OFF)
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow")
endif()
add_library(cxxopts INTERFACE)
# optionally, enable unicode support using the ICU library
set(CXXOPTS_USE_UNICODE_HELP FALSE CACHE BOOL "Use ICU Unicode library")
if(CXXOPTS_USE_UNICODE_HELP)
find_package(PkgConfig)
pkg_check_modules(ICU REQUIRED icu-uc)
target_link_libraries(cxxopts INTERFACE ${ICU_LDFLAGS})
target_compile_options(cxxopts INTERFACE ${ICU_CFLAGS})
target_compile_definitions(cxxopts INTERFACE CXXOPTS_USE_UNICODE)
endif()
target_include_directories(cxxopts INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
include(CMakePackageConfigHelpers)
set(CXXOPTS_CMAKE_DIR "lib/cmake/cxxopts" CACHE STRING
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
set(version_config "${PROJECT_BINARY_DIR}/cxxopts-config-version.cmake")
set(project_config "${PROJECT_BINARY_DIR}/cxxopts-config.cmake")
set(targets_export_name cxxopts-targets)
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
${version_config}
VERSION ${VERSION}
COMPATIBILITY AnyNewerVersion)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/cxxopts-config.cmake.in
${project_config}
INSTALL_DESTINATION ${CXXOPTS_CMAKE_DIR})
export(TARGETS cxxopts NAMESPACE cxxopts::
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
# Install version, config and target files.
install(
FILES ${project_config} ${version_config}
DESTINATION ${CXXOPTS_CMAKE_DIR})
install(EXPORT ${targets_export_name} DESTINATION ${CXXOPTS_CMAKE_DIR}
NAMESPACE cxxopts::)
# Install the header file and export the target
install(TARGETS cxxopts EXPORT ${targets_export_name} DESTINATION lib)
install(FILES ${PROJECT_SOURCE_DIR}/include/cxxopts.hpp DESTINATION include)
add_subdirectory(src)
add_subdirectory(test)

23
vendor/cxxopts/INSTALL vendored Normal file
View file

@ -0,0 +1,23 @@
== System installation ==
This library is header only. So you can either copy `include/cxxopts.hpp` to `/usr/include` or `/usr/local/include`, or add `include` to your search path.
== Building the examples and tests ==
It is preferable to build out of source. Make a build directory somewhere, and then
do the following, where `${CXXOPTS_DIR}` is the path that you checked out `cxxopts`
to:
cmake ${CXXOPTS_DIR}
make
You can use another build tool, such as ninja.
cmake -G Ninja ${CXXOPTS_DIR}
ninja
To run the tests, you have to configure `cxxopts` with another flag:
cmake -D CXXOPTS_BUILD_TESTS=On ${CXXOPTS_DIR}
make
make test

19
vendor/cxxopts/LICENSE vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2014 Jarryd Beck
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

136
vendor/cxxopts/README.md vendored Normal file
View file

@ -0,0 +1,136 @@
[![Build Status](https://travis-ci.org/jarro2783/cxxopts.svg?branch=master)](https://travis-ci.org/jarro2783/cxxopts)
# Release versions
Note that `master` is generally a work in progress, and you probably want to use a
tagged release version.
# Quick start
This is a lightweight C++ option parser library, supporting the standard GNU
style syntax for options.
Options can be given as:
--long
--long=argument
--long argument
-a
-ab
-abc argument
where c takes an argument, but a and b do not.
Additionally, anything after `--` will be parsed as a positional argument.
## Basics
#include <cxxopts.hpp>
Create a cxxopts::Options instance.
cxxopts::Options options("MyProgram", "One line description of MyProgram");
Then use `add_options`.
options.add_options()
("d,debug", "Enable debugging")
("f,file", "File name", cxxopts::value<std::string>())
;
Options are declared with a long and an optional short option. A description
must be provided. The third argument is the value, if omitted it is boolean.
Any type can be given as long as it can be parsed, with operator>>.
To parse the command line do:
auto result = options.parse(argc, argv);
To retrieve an option use `result.count("option")` to get the number of times
it appeared, and
result["opt"].as<type>()
to get its value. If "opt" doesn't exist, or isn't of the right type, then an
exception will be thrown.
Note that the result of `options.parse` should only be used as long as the
`options` object that created it is in scope.
## Exceptions
Exceptional situations throw C++ exceptions. There are two types of
exceptions: errors defining the options, and errors when parsing a list of
arguments. All exceptions derive from `cxxopts::OptionException`. Errors
defining options derive from `cxxopts::OptionSpecException` and errors
parsing arguments derive from `cxxopts::OptionParseException`.
All exceptions define a `what()` function to get a printable string
explaining the error.
## Help groups
Options can be placed into groups for the purposes of displaying help messages.
To place options in a group, pass the group as a string to `add_options`. Then,
when displaying the help, pass the groups that you would like displayed as a
vector to the `help` function.
## Positional Arguments
Positional arguments can be optionally parsed into one or more options.
To set up positional arguments, call
options.parse_positional({"first", "second", "last"})
where "last" should be the name of an option with a container type, and the
others should have a single value.
## Default and implicit values
An option can be declared with a default or an implicit value, or both.
A default value is the value that an option takes when it is not specified
on the command line. The following specifies a default value for an option:
cxxopts::value<std::string>()->default_value("value")
An implicit value is the value that an option takes when it is given on the
command line without an argument. The following specifies an implicit value:
cxxopts::value<std::string>()->implicit_value("implicit")
If an option had both, then not specifying it would give the value `"value"`,
writing it on the command line as `--option` would give the value `"implicit"`,
and writing `--option=another` would give it the value `"another"`.
Note that the default and implicit value is always stored as a string,
regardless of the type that you want to store it in. It will be parsed as
though it was given on the command line.
## Boolean values
Boolean options have a default implicit value of `"true"`, which can be
overridden. The effect is that writing `-o` by itself will set option `o` to
`true`. However, they can also be written with various strings using `=value`.
There is no way to disambiguate positional arguments from the value following
a boolean, so we have chosen that they will be positional arguments, and
therefore, `-o false` does not work.
## Custom help
The string after the program name on the first line of the help can be
completely replaced by calling `options.custom_help`. Note that you might
also want to override the positional help by calling `options.positional_help`.
# Linking
This is a header only library.
# Requirements
The only build requirement is a C++ compiler that supports C++11 regular
expressions. For example GCC >= 4.9 or clang with libc++.
# TODO list
* Allow unrecognised options.

View file

@ -0,0 +1,4 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
check_required_components(cxxopts)

2082
vendor/cxxopts/include/cxxopts.hpp vendored Normal file

File diff suppressed because it is too large Load diff

1
vendor/cxxopts/src/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
example

24
vendor/cxxopts/src/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,24 @@
# Copyright (c) 2014 Jarryd Beck
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
if(CXXOPTS_BUILD_EXAMPLES)
add_executable(example example.cpp)
target_link_libraries(example cxxopts)
endif()

151
vendor/cxxopts/src/example.cpp vendored Normal file
View file

@ -0,0 +1,151 @@
/*
Copyright (c) 2014 Jarryd Beck
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <iostream>
#include "cxxopts.hpp"
cxxopts::ParseResult
parse(int argc, char* argv[])
{
try
{
cxxopts::Options options(argv[0], " - example command line options");
options
.positional_help("[optional args]")
.show_positional_help();
bool apple = false;
options
.allow_unrecognised_options()
.add_options()
("a,apple", "an apple", cxxopts::value<bool>(apple))
("b,bob", "Bob")
("t,true", "True", cxxopts::value<bool>()->default_value("true"))
("f, file", "File", cxxopts::value<std::vector<std::string>>(), "FILE")
("i,input", "Input", cxxopts::value<std::string>())
("o,output", "Output file", cxxopts::value<std::string>()
->default_value("a.out")->implicit_value("b.def"), "BIN")
("positional",
"Positional arguments: these are the arguments that are entered "
"without an option", cxxopts::value<std::vector<std::string>>())
("long-description",
"thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace")
("help", "Print help")
("int", "An integer", cxxopts::value<int>(), "N")
("float", "A floating point number", cxxopts::value<float>())
("option_that_is_too_long_for_the_help", "A very long option")
#ifdef CXXOPTS_USE_UNICODE
("unicode", u8"A help option with non-ascii: à. Here the size of the"
" string should be correct")
#endif
;
options.add_options("Group")
("c,compile", "compile")
("d,drop", "drop", cxxopts::value<std::vector<std::string>>());
options.parse_positional({"input", "output", "positional"});
auto result = options.parse(argc, argv);
if (result.count("help"))
{
std::cout << options.help({"", "Group"}) << std::endl;
exit(0);
}
if (apple)
{
std::cout << "Saw option a " << result.count("a") << " times " <<
std::endl;
}
if (result.count("b"))
{
std::cout << "Saw option b" << std::endl;
}
if (result.count("f"))
{
auto& ff = result["f"].as<std::vector<std::string>>();
std::cout << "Files" << std::endl;
for (const auto& f : ff)
{
std::cout << f << std::endl;
}
}
if (result.count("input"))
{
std::cout << "Input = " << result["input"].as<std::string>()
<< std::endl;
}
if (result.count("output"))
{
std::cout << "Output = " << result["output"].as<std::string>()
<< std::endl;
}
if (result.count("positional"))
{
std::cout << "Positional = {";
auto& v = result["positional"].as<std::vector<std::string>>();
for (const auto& s : v) {
std::cout << s << ", ";
}
std::cout << "}" << std::endl;
}
if (result.count("int"))
{
std::cout << "int = " << result["int"].as<int>() << std::endl;
}
if (result.count("float"))
{
std::cout << "float = " << result["float"].as<float>() << std::endl;
}
std::cout << "Arguments remain = " << argc << std::endl;
return result;
} catch (const cxxopts::OptionException& e)
{
std::cout << "error parsing options: " << e.what() << std::endl;
exit(1);
}
}
int main(int argc, char* argv[])
{
auto result = parse(argc, argv);
auto arguments = result.arguments();
std::cout << "Saw " << arguments.size() << " arguments" << std::endl;
return 0;
}

1
vendor/cxxopts/test/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
options_test

35
vendor/cxxopts/test/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,35 @@
if (CXXOPTS_BUILD_TESTS)
add_executable(options_test main.cpp options.cpp)
target_link_libraries(options_test cxxopts)
add_test(options options_test)
# test if the targets are findable from the build directory
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
-C ${CMAKE_BUILD_TYPE}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/find-package-test"
"${CMAKE_CURRENT_BINARY_DIR}/find-package-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-Dcxxopts_DIR=${PROJECT_BINARY_DIR}"
)
# test if the targets are findable when add_subdirectory is used
add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
-C ${CMAKE_BUILD_TYPE}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test"
"${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
)
add_executable(link_test link_a.cpp link_b.cpp)
target_link_libraries(link_test cxxopts)
endif()

View file

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.1)
project(cxxopts-test)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
add_subdirectory(../.. cxxopts EXCLUDE_FROM_ALL)
add_executable(library-test "../../src/example.cpp")
target_link_libraries(library-test cxxopts)

10460
vendor/cxxopts/test/catch.hpp vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.1)
project(cxxopts-test)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(cxxopts REQUIRED)
add_executable(library-test "../../src/example.cpp")
target_link_libraries(library-test cxxopts::cxxopts)

6
vendor/cxxopts/test/link_a.cpp vendored Normal file
View file

@ -0,0 +1,6 @@
#include "cxxopts.hpp"
int main(int, char**)
{
return 0;
}

1
vendor/cxxopts/test/link_b.cpp vendored Normal file
View file

@ -0,0 +1 @@
#include <cxxopts.hpp>

2
vendor/cxxopts/test/main.cpp vendored Normal file
View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

550
vendor/cxxopts/test/options.cpp vendored Normal file
View file

@ -0,0 +1,550 @@
#include "catch.hpp"
#include <initializer_list>
#include "cxxopts.hpp"
class Argv {
public:
Argv(std::initializer_list<const char*> args)
: m_argv(new char*[args.size()])
, m_argc(args.size())
{
int i = 0;
auto iter = args.begin();
while (iter != args.end()) {
auto len = strlen(*iter) + 1;
auto ptr = std::unique_ptr<char[]>(new char[len]);
strcpy(ptr.get(), *iter);
m_args.push_back(std::move(ptr));
m_argv.get()[i] = m_args.back().get();
++iter;
++i;
}
}
char** argv() const {
return m_argv.get();
}
int argc() const {
return m_argc;
}
private:
std::vector<std::unique_ptr<char[]>> m_args;
std::unique_ptr<char*[]> m_argv;
int m_argc;
};
TEST_CASE("Basic options", "[options]")
{
cxxopts::Options options("tester", " - test basic options");
options.add_options()
("long", "a long option")
("s,short", "a short option")
("value", "an option with a value", cxxopts::value<std::string>())
("a,av", "a short option with a value", cxxopts::value<std::string>())
("6,six", "a short number option")
("p, space", "an option with space between short and long")
("nothing", "won't exist", cxxopts::value<std::string>())
;
Argv argv({
"tester",
"--long",
"-s",
"--value",
"value",
"-a",
"b",
"-6",
"-p",
"--space",
});
char** actual_argv = argv.argv();
auto argc = argv.argc();
auto result = options.parse(argc, actual_argv);
CHECK(result.count("long") == 1);
CHECK(result.count("s") == 1);
CHECK(result.count("value") == 1);
CHECK(result.count("a") == 1);
CHECK(result["value"].as<std::string>() == "value");
CHECK(result["a"].as<std::string>() == "b");
CHECK(result.count("6") == 1);
CHECK(result.count("p") == 2);
CHECK(result.count("space") == 2);
auto& arguments = result.arguments();
REQUIRE(arguments.size() == 7);
CHECK(arguments[0].key() == "long");
CHECK(arguments[0].value() == "true");
CHECK(arguments[0].as<bool>() == true);
CHECK(arguments[1].key() == "short");
CHECK(arguments[2].key() == "value");
CHECK(arguments[3].key() == "av");
CHECK_THROWS_AS(result["nothing"].as<std::string>(), std::domain_error&);
}
TEST_CASE("Short options", "[options]")
{
cxxopts::Options options("test_short", " - test short options");
options.add_options()
("a", "a short option", cxxopts::value<std::string>());
Argv argv({"test_short", "-a", "value"});
auto actual_argv = argv.argv();
auto argc = argv.argc();
auto result = options.parse(argc, actual_argv);
CHECK(result.count("a") == 1);
CHECK(result["a"].as<std::string>() == "value");
REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
cxxopts::invalid_option_format_error&);
}
TEST_CASE("No positional", "[positional]")
{
cxxopts::Options options("test_no_positional",
" - test no positional options");
Argv av({"tester", "a", "b", "def"});
char** argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
REQUIRE(argc == 4);
CHECK(strcmp(argv[1], "a") == 0);
}
TEST_CASE("All positional", "[positional]")
{
std::vector<std::string> positional;
cxxopts::Options options("test_all_positional", " - test all positional");
options.add_options()
("positional", "Positional parameters",
cxxopts::value<std::vector<std::string>>(positional))
;
Argv av({"tester", "a", "b", "c"});
auto argc = av.argc();
auto argv = av.argv();
std::vector<std::string> pos_names = {"positional"};
options.parse_positional(pos_names.begin(), pos_names.end());
auto result = options.parse(argc, argv);
REQUIRE(argc == 1);
REQUIRE(positional.size() == 3);
CHECK(positional[0] == "a");
CHECK(positional[1] == "b");
CHECK(positional[2] == "c");
}
TEST_CASE("Some positional explicit", "[positional]")
{
cxxopts::Options options("positional_explicit", " - test positional");
options.add_options()
("input", "Input file", cxxopts::value<std::string>())
("output", "Output file", cxxopts::value<std::string>())
("positional", "Positional parameters",
cxxopts::value<std::vector<std::string>>())
;
options.parse_positional({"input", "output", "positional"});
Argv av({"tester", "--output", "a", "b", "c", "d"});
char** argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
CHECK(argc == 1);
CHECK(result.count("output"));
CHECK(result["input"].as<std::string>() == "b");
CHECK(result["output"].as<std::string>() == "a");
auto& positional = result["positional"].as<std::vector<std::string>>();
REQUIRE(positional.size() == 2);
CHECK(positional[0] == "c");
CHECK(positional[1] == "d");
}
TEST_CASE("No positional with extras", "[positional]")
{
cxxopts::Options options("posargmaster", "shows incorrect handling");
options.add_options()
("dummy", "oh no", cxxopts::value<std::string>())
;
Argv av({"extras", "--", "a", "b", "c", "d"});
char** argv = av.argv();
auto argc = av.argc();
auto old_argv = argv;
auto old_argc = argc;
options.parse(argc, argv);
REQUIRE(argc == old_argc - 1);
CHECK(argv[0] == std::string("extras"));
CHECK(argv[1] == std::string("a"));
}
TEST_CASE("Empty with implicit value", "[implicit]")
{
cxxopts::Options options("empty_implicit", "doesn't handle empty");
options.add_options()
("implicit", "Has implicit", cxxopts::value<std::string>()
->implicit_value("foo"));
Argv av({"implicit", "--implicit="});
char** argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
REQUIRE(result.count("implicit") == 1);
REQUIRE(result["implicit"].as<std::string>() == "");
}
TEST_CASE("Default values", "[default]")
{
cxxopts::Options options("defaults", "has defaults");
options.add_options()
("default", "Has implicit", cxxopts::value<int>()
->default_value("42"));
SECTION("Sets defaults") {
Argv av({"implicit"});
char** argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
CHECK(result.count("default") == 0);
CHECK(result["default"].as<int>() == 42);
}
SECTION("When values provided") {
Argv av({"implicit", "--default", "5"});
char** argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
CHECK(result.count("default") == 1);
CHECK(result["default"].as<int>() == 5);
}
}
TEST_CASE("Parse into a reference", "[reference]")
{
int value = 0;
cxxopts::Options options("into_reference", "parses into a reference");
options.add_options()
("ref", "A reference", cxxopts::value(value));
Argv av({"into_reference", "--ref", "42"});
auto argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
CHECK(result.count("ref") == 1);
CHECK(value == 42);
}
TEST_CASE("Integers", "[options]")
{
cxxopts::Options options("parses_integers", "parses integers correctly");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int>>());
Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});
char** argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
auto result = options.parse(argc, argv);
REQUIRE(result.count("positional") == 7);
auto& positional = result["positional"].as<std::vector<int>>();
REQUIRE(positional.size() == 7);
CHECK(positional[0] == 5);
CHECK(positional[1] == 6);
CHECK(positional[2] == -6);
CHECK(positional[3] == 0);
CHECK(positional[4] == 0xab);
CHECK(positional[5] == 0xaf);
CHECK(positional[6] == 0x0);
}
TEST_CASE("Leading zero integers", "[options]")
{
cxxopts::Options options("parses_integers", "parses integers correctly");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int>>());
Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"});
char** argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
auto result = options.parse(argc, argv);
REQUIRE(result.count("positional") == 4);
auto& positional = result["positional"].as<std::vector<int>>();
REQUIRE(positional.size() == 4);
CHECK(positional[0] == 5);
CHECK(positional[1] == 6);
CHECK(positional[2] == 0xab);
CHECK(positional[3] == 0x1);
}
TEST_CASE("Unsigned integers", "[options]")
{
cxxopts::Options options("parses_unsigned", "detects unsigned errors");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<unsigned int>>());
Argv av({"ints", "--", "-2"});
char** argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
}
TEST_CASE("Integer bounds", "[integer]")
{
cxxopts::Options options("integer_boundaries", "check min/max integer");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
SECTION("No overflow")
{
Argv av({"ints", "--", "127", "-128", "0x7f", "-0x80", "0x7e"});
auto argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
auto result = options.parse(argc, argv);
REQUIRE(result.count("positional") == 5);
auto& positional = result["positional"].as<std::vector<int8_t>>();
CHECK(positional[0] == 127);
CHECK(positional[1] == -128);
CHECK(positional[2] == 0x7f);
CHECK(positional[3] == -0x80);
CHECK(positional[4] == 0x7e);
}
}
TEST_CASE("Overflow on boundary", "[integer]")
{
using namespace cxxopts::values;
int8_t si;
uint8_t ui;
CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::argument_incorrect_type&);
CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::argument_incorrect_type&);
CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::argument_incorrect_type&);
CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::argument_incorrect_type&);
CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::argument_incorrect_type&);
CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::argument_incorrect_type&);
}
TEST_CASE("Integer overflow", "[options]")
{
cxxopts::Options options("reject_overflow", "rejects overflowing integers");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
Argv av({"ints", "--", "128"});
auto argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
}
TEST_CASE("Floats", "[options]")
{
cxxopts::Options options("parses_floats", "parses floats correctly");
options.add_options()
("double", "Double precision", cxxopts::value<double>())
("positional", "Floats", cxxopts::value<std::vector<float>>());
Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"});
char** argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
auto result = options.parse(argc, argv);
REQUIRE(result.count("double") == 1);
REQUIRE(result.count("positional") == 4);
CHECK(result["double"].as<double>() == 0.5);
auto& positional = result["positional"].as<std::vector<float>>();
CHECK(positional[0] == 4);
CHECK(positional[1] == -4);
CHECK(positional[2] == 1.5e6);
CHECK(positional[3] == -1.5e6);
}
TEST_CASE("Invalid integers", "[integer]") {
cxxopts::Options options("invalid_integers", "rejects invalid integers");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int>>());
Argv av({"ints", "--", "Ae"});
char **argv = av.argv();
auto argc = av.argc();
options.parse_positional("positional");
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type&);
}
TEST_CASE("Booleans", "[boolean]") {
cxxopts::Options options("parses_floats", "parses floats correctly");
options.add_options()
("bool", "A Boolean", cxxopts::value<bool>())
("debug", "Debugging", cxxopts::value<bool>())
("timing", "Timing", cxxopts::value<bool>())
("noExplicitDefault", "No Explicit Default", cxxopts::value<bool>())
("defaultTrue", "Timing", cxxopts::value<bool>()->default_value("true"))
("defaultFalse", "Timing", cxxopts::value<bool>()->default_value("false"))
("others", "Other arguments", cxxopts::value<std::vector<std::string>>())
;
options.parse_positional("others");
Argv av({"booleans", "--bool=false", "--debug=true", "--timing", "extra"});
char** argv = av.argv();
auto argc = av.argc();
auto result = options.parse(argc, argv);
REQUIRE(result.count("bool") == 1);
REQUIRE(result.count("debug") == 1);
REQUIRE(result.count("timing") == 1);
REQUIRE(result.count("noExplicitDefault") == 0);
REQUIRE(result.count("defaultTrue") == 0);
REQUIRE(result.count("defaultFalse") == 0);
CHECK(result["bool"].as<bool>() == false);
CHECK(result["debug"].as<bool>() == true);
CHECK(result["timing"].as<bool>() == true);
CHECK(result["noExplicitDefault"].as<bool>() == false);
CHECK(result["defaultTrue"].as<bool>() == true);
CHECK(result["defaultFalse"].as<bool>() == false);
REQUIRE(result.count("others") == 1);
}
#ifdef CXXOPTS_HAS_OPTIONAL
TEST_CASE("std::optional", "[optional]") {
std::optional<std::string> optional;
cxxopts::Options options("optional", " - tests optional");
options.add_options()
("optional", "an optional option", cxxopts::value<std::optional<std::string>>(optional));
Argv av({"optional", "--optional", "foo"});
char** argv = av.argv();
auto argc = av.argc();
options.parse(argc, argv);
REQUIRE(optional.has_value());
CHECK(*optional == "foo");
}
#endif
TEST_CASE("Unrecognised options", "[options]") {
cxxopts::Options options("unknown_options", " - test unknown options");
options.add_options()
("long", "a long option")
("s,short", "a short option");
Argv av({
"unknown_options",
"--unknown",
"--long",
"-su",
"--another_unknown",
});
char** argv = av.argv();
auto argc = av.argc();
SECTION("Default behaviour") {
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
}
SECTION("After allowing unrecognised options") {
options.allow_unrecognised_options();
CHECK_NOTHROW(options.parse(argc, argv));
REQUIRE(argc == 3);
CHECK_THAT(argv[1], Catch::Equals("--unknown"));
}
}
TEST_CASE("Invalid option syntax", "[options]") {
cxxopts::Options options("invalid_syntax", " - test invalid syntax");
Argv av({
"invalid_syntax",
"--a",
});
char** argv = av.argv();
auto argc = av.argc();
SECTION("Default behaviour") {
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_syntax_exception&);
}
}