From 5241f9783b41e74f719dc4a472c6b0803b0eff8c Mon Sep 17 00:00:00 2001
From: a1xd <68629610+a1xd@users.noreply.github.com>
Date: Fri, 31 Jul 2020 20:04:19 -0400
Subject: add read
add function that makes an ioctl call to return the driver's active mouse_modifier
---
common/common.vcxitems | 1 +
common/external/tagged-union-single.h | 2 +-
common/rawaccel-io.hpp | 46 +++++++++++++++++++++++++
driver/driver.cpp | 63 +++++++++++++++++++++++------------
4 files changed, 89 insertions(+), 23 deletions(-)
create mode 100644 common/rawaccel-io.hpp
diff --git a/common/common.vcxitems b/common/common.vcxitems
index d1e8db0..aeeaa95 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -23,6 +23,7 @@
+
diff --git a/common/external/tagged-union-single.h b/common/external/tagged-union-single.h
index 3353325..f0de097 100644
--- a/common/external/tagged-union-single.h
+++ b/common/external/tagged-union-single.h
@@ -137,7 +137,7 @@ struct tagged_union {
int tag = 0;
struct storage_t {
- alignas(max_align_of) char bytes[max_size_of] = "";
+ alignas(max_align_of) char bytes[max_size_of] = {};
template
inline constexpr T& as() {
diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp
new file mode 100644
index 0000000..5d6fad6
--- /dev/null
+++ b/common/rawaccel-io.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include
+
+#define NOMINMAX
+#include
+
+#include "rawaccel.hpp"
+
+#define RA_IOCTL CTL_CODE(0x8888, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+namespace rawaccel {
+
+ mouse_modifier read() {
+ HANDLE ra_handle = INVALID_HANDLE_VALUE;
+
+ ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0);
+
+ if (ra_handle == INVALID_HANDLE_VALUE) {
+ throw std::system_error(GetLastError(), std::system_category(), "CreateFile failed");
+ }
+
+ mouse_modifier mod;
+ DWORD dummy;
+
+ BOOL success = DeviceIoControl(
+ ra_handle,
+ RA_IOCTL,
+ NULL, // input buffer
+ 0, // input buffer size
+ &mod, // output buffer
+ sizeof(mouse_modifier), // output buffer size
+ &dummy, // bytes returned
+ NULL // overlapped structure
+ );
+
+ CloseHandle(ra_handle);
+
+ if (!success) {
+ throw std::system_error(GetLastError(), std::system_category(), "DeviceIoControl failed");
+ }
+
+ return mod;
+ }
+
+}
diff --git a/driver/driver.cpp b/driver/driver.cpp
index 1f9cebd..c893b8b 100644
--- a/driver/driver.cpp
+++ b/driver/driver.cpp
@@ -143,41 +143,60 @@ Return Value:
--*/
{
NTSTATUS status;
- void* input_buffer;
- size_t input_size;
+ void* buffer;
+ size_t size;
UNREFERENCED_PARAMETER(Queue);
- UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(IoControlCode);
PAGED_CODE();
DebugPrint(("Ioctl received into filter control object.\n"));
- if (InputBufferLength != sizeof(ra::mouse_modifier)) {
- DebugPrint(("Received unknown request of %u bytes\n", InputBufferLength));
- // status maps to win32 error code 1784: ERROR_INVALID_USER_BUFFER
- WdfRequestComplete(Request, STATUS_INVALID_BUFFER_SIZE);
- return;
- }
+ if (InputBufferLength == sizeof(ra::mouse_modifier)) {
+ status = WdfRequestRetrieveInputBuffer(
+ Request,
+ sizeof(ra::mouse_modifier),
+ &buffer,
+ &size
+ );
- status = WdfRequestRetrieveInputBuffer(
- Request,
- sizeof(ra::mouse_modifier),
- &input_buffer,
- &input_size
- );
+ if (!NT_SUCCESS(status)) {
+ DebugPrint(("RetrieveInputBuffer failed: 0x%x\n", status));
+ // status maps to win32 error code 1359: ERROR_INTERNAL_ERROR
+ WdfRequestComplete(Request, STATUS_MESSAGE_LOST);
+ return;
+ }
- if (!NT_SUCCESS(status)) {
- DebugPrint(("RetrieveInputBuffer failed: 0x%x\n", status));
- // status maps to win32 error code 1359: ERROR_INTERNAL_ERROR
- WdfRequestComplete(Request, STATUS_MESSAGE_LOST);
- return;
+ global.modifier = *reinterpret_cast(buffer);
+
+ WdfRequestComplete(Request, STATUS_SUCCESS);
}
+ else if (OutputBufferLength == sizeof(ra::mouse_modifier)) {
+ status = WdfRequestRetrieveOutputBuffer(
+ Request,
+ sizeof(ra::mouse_modifier),
+ &buffer,
+ &size
+ );
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint(("RetrieveOutputBuffer failed: 0x%x\n", status));
+ // status maps to win32 error code 1359: ERROR_INTERNAL_ERROR
+ WdfRequestComplete(Request, STATUS_MESSAGE_LOST);
+ return;
+ }
+
+ *reinterpret_cast(buffer) = global.modifier;
- global.modifier = *reinterpret_cast(input_buffer);
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+ }
+ else {
+ DebugPrint(("Received unknown request: in %uB, out %uB\n", InputBufferLength, OutputBufferLength));
+ // status maps to win32 error code 1784: ERROR_INVALID_USER_BUFFER
+ WdfRequestComplete(Request, STATUS_INVALID_BUFFER_SIZE);
+ }
- WdfRequestComplete(Request, STATUS_SUCCESS);
}
#pragma warning(pop) // enable 28118 again
--
cgit v1.2.3
From 66a4043a9ecb1990878bea230f213708c7fdd3da Mon Sep 17 00:00:00 2001
From: a1xd <68629610+a1xd@users.noreply.github.com>
Date: Fri, 31 Jul 2020 20:19:24 -0400
Subject: move write function into common io header
---
common/rawaccel-io.hpp | 29 +++++++++++++++++++++++++++++
console/console.cpp | 9 ++++-----
console/console.vcxproj | 2 --
console/console_write.cpp | 32 --------------------------------
console/console_write.hpp | 14 --------------
rawaccel.sln | 3 +--
wrapper/wrapper.cpp | 1 +
wrapper/wrapper.hpp | 14 ++++++--------
wrapper/wrapper.vcxproj | 1 +
wrapper/wrapper_writer.cpp | 4 ++--
wrapper/wrapper_writer.hpp | 2 +-
11 files changed, 45 insertions(+), 66 deletions(-)
delete mode 100644 console/console_write.cpp
delete mode 100644 console/console_write.hpp
diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp
index 5d6fad6..7a4c59c 100644
--- a/common/rawaccel-io.hpp
+++ b/common/rawaccel-io.hpp
@@ -43,4 +43,33 @@ namespace rawaccel {
return mod;
}
+ void write(mouse_modifier mod) {
+ HANDLE ra_handle = INVALID_HANDLE_VALUE;
+
+ ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0);
+
+ if (ra_handle == INVALID_HANDLE_VALUE) {
+ throw std::system_error(GetLastError(), std::system_category(), "CreateFile failed");
+ }
+
+ DWORD dummy;
+
+ BOOL success = DeviceIoControl(
+ ra_handle,
+ RA_IOCTL,
+ &mod, // input buffer
+ sizeof(mouse_modifier), // input buffer size
+ NULL, // output buffer
+ 0, // output buffer size
+ &dummy, // bytes returned
+ NULL // overlapped structure
+ );
+
+ CloseHandle(ra_handle);
+
+ if (!success) {
+ throw std::system_error(GetLastError(), std::system_category(), "DeviceIoControl failed");
+ }
+ }
+
}
diff --git a/console/console.cpp b/console/console.cpp
index 549cb68..00dc481 100644
--- a/console/console.cpp
+++ b/console/console.cpp
@@ -1,14 +1,13 @@
#include
-#define NOMINMAX
-#include
-
#include
-#include "console_write.hpp"
+#include
+
+namespace ra = rawaccel;
int main(int argc, char** argv) {
try {
- write(ra::parse(argc, argv));
+ ra::write(ra::parse(argc, argv));
}
catch (std::domain_error e) {
std::cerr << e.what() << '\n';
diff --git a/console/console.vcxproj b/console/console.vcxproj
index 05780cd..d0ad292 100644
--- a/console/console.vcxproj
+++ b/console/console.vcxproj
@@ -90,8 +90,6 @@
-
-
diff --git a/console/console_write.cpp b/console/console_write.cpp
deleted file mode 100644
index 3240ea5..0000000
--- a/console/console_write.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include "console_write.hpp"
-
-void write(ra::mouse_modifier vars) {
- HANDLE ra_handle = INVALID_HANDLE_VALUE;
-
- ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0);
-
- if (ra_handle == INVALID_HANDLE_VALUE) {
- throw std::system_error(GetLastError(), std::system_category(), "CreateFile failed");
- }
-
- DWORD dummy;
-
- BOOL success = DeviceIoControl(
- ra_handle,
- RA_WRITE,
- &vars,
- sizeof(ra::mouse_modifier),
- NULL, // output buffer
- 0, // output buffer size
- &dummy, // bytes returned
- NULL // overlapped structure
- );
-
- CloseHandle(ra_handle);
-
- if (!success) {
- throw std::system_error(GetLastError(), std::system_category(), "DeviceIoControl failed");
- }
-}
diff --git a/console/console_write.hpp b/console/console_write.hpp
deleted file mode 100644
index 31eb575..0000000
--- a/console/console_write.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#include
-
-#define NOMINMAX
-#include
-
-#include "..\common\rawaccel.hpp"
-
-#define RA_WRITE CTL_CODE(0x8888, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-namespace ra = rawaccel;
-
-void write(ra::mouse_modifier vars);
\ No newline at end of file
diff --git a/rawaccel.sln b/rawaccel.sln
index 2235818..0db5ecb 100644
--- a/rawaccel.sln
+++ b/rawaccel.sln
@@ -23,10 +23,9 @@ Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
common-install\common-install.vcxitems*{058d66c6-d88b-4fdb-b0e4-0a6fe7483b95}*SharedItemsImports = 9
common\common.vcxitems*{24b4226f-1461-408f-a1a4-1371c97153ea}*SharedItemsImports = 9
- common\common.vcxitems*{60d6c942-ac20-4c05-a2be-54b5c966534d}*SharedItemsImports = 4
+ common\common.vcxitems*{28a3656f-a1de-405c-b547-191c32ec555f}*SharedItemsImports = 4
common-install\common-install.vcxitems*{896950d1-520a-420a-b6b1-73014b92a68c}*SharedItemsImports = 4
common-install\common-install.vcxitems*{a4097ff6-a6f0-44e8-b8d0-538d0fb75936}*SharedItemsImports = 4
- common\common.vcxitems*{ab7b3759-b85f-4067-8935-fb4539b41869}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp
index ceee1a1..bd0574f 100644
--- a/wrapper/wrapper.cpp
+++ b/wrapper/wrapper.cpp
@@ -1,6 +1,7 @@
#pragma once
#include "wrapper.hpp"
+
using namespace rawaccel;
using namespace System;
diff --git a/wrapper/wrapper.hpp b/wrapper/wrapper.hpp
index 870aca7..e8f100d 100644
--- a/wrapper/wrapper.hpp
+++ b/wrapper/wrapper.hpp
@@ -1,16 +1,14 @@
#pragma once
-#include "wrapper_writer.hpp"
-#include "..\common\rawaccel.hpp";
-#include "..\common\accel-error.hpp";
#include
-using namespace rawaccel;
-using namespace System;
+#include
+#include
-public value struct ArgsWrapper {
- int a;
-};
+#include "wrapper_writer.hpp"
+
+using namespace rawaccel;
+using namespace System;
public ref class ManagedAccel
{
diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj
index 28acbe7..bffbf8b 100644
--- a/wrapper/wrapper.vcxproj
+++ b/wrapper/wrapper.vcxproj
@@ -59,6 +59,7 @@
+
diff --git a/wrapper/wrapper_writer.cpp b/wrapper/wrapper_writer.cpp
index 0a74105..da7c9bf 100644
--- a/wrapper/wrapper_writer.cpp
+++ b/wrapper/wrapper_writer.cpp
@@ -1,9 +1,9 @@
#pragma once
-#include "..\console\console_write.cpp"
+#include
#include "wrapper_writer.hpp"
void writer::writeToDriver(rawaccel::mouse_modifier* modifier)
{
- write(*modifier);
+ rawaccel::write(*modifier);
}
diff --git a/wrapper/wrapper_writer.hpp b/wrapper/wrapper_writer.hpp
index 591f62f..dcbef10 100644
--- a/wrapper/wrapper_writer.hpp
+++ b/wrapper/wrapper_writer.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include "..\common\rawaccel.hpp"
+#include
struct writer {
void writeToDriver(rawaccel::mouse_modifier* modifier);
--
cgit v1.2.3
From b49a91627faa6411023f7823250337cc1a71af82 Mon Sep 17 00:00:00 2001
From: a1xd <68629610+a1xd@users.noreply.github.com>
Date: Fri, 31 Jul 2020 20:36:17 -0400
Subject: move clipp/parse logic into console project
---
common/common.vcxitems | 2 +-
common/external/clipp.h | 7027 ---------------------------------
common/external/nillable.h | 30 -
common/external/tagged-union-single.h | 202 -
common/rawaccel-io.hpp | 6 +
common/rawaccel-userspace.hpp | 128 -
common/rawaccel.hpp | 2 +-
common/tagged-union-single.h | 202 +
console/console.cpp | 3 +-
console/console.vcxproj | 3 +
console/external/clipp.h | 7027 +++++++++++++++++++++++++++++++++
console/parse.hpp | 128 +
rawaccel.sln | 2 +-
13 files changed, 7371 insertions(+), 7391 deletions(-)
delete mode 100644 common/external/clipp.h
delete mode 100644 common/external/nillable.h
delete mode 100644 common/external/tagged-union-single.h
delete mode 100644 common/rawaccel-userspace.hpp
create mode 100644 common/tagged-union-single.h
create mode 100644 console/external/clipp.h
create mode 100644 console/parse.hpp
diff --git a/common/common.vcxitems b/common/common.vcxitems
index aeeaa95..7102164 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -24,8 +24,8 @@
-
+
diff --git a/common/external/clipp.h b/common/external/clipp.h
deleted file mode 100644
index cca1554..0000000
--- a/common/external/clipp.h
+++ /dev/null
@@ -1,7027 +0,0 @@
-/*****************************************************************************
- * ___ _ _ ___ ___
- * | _|| | | | | _ \ _ \ CLIPP - command line interfaces for modern C++
- * | |_ | |_ | | | _/ _/ version 1.2.3
- * |___||___||_| |_| |_| https://github.com/muellan/clipp
- *
- * Licensed under the MIT License .
- * Copyright (c) 2017-2018 André Müller
- *
- * ---------------------------------------------------------------------------
- * 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.
- *
- *****************************************************************************/
-
-#ifndef AM_CLIPP_H__
-#define AM_CLIPP_H__
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-/*************************************************************************//**
- *
- * @brief primary namespace
- *
- *****************************************************************************/
-namespace clipp {
-
-
-
-/*****************************************************************************
- *
- * basic constants and datatype definitions
- *
- *****************************************************************************/
-using arg_index = int;
-
-using arg_string = std::string;
-using doc_string = std::string;
-
-using arg_list = std::vector;
-
-
-
-/*************************************************************************//**
- *
- * @brief tristate
- *
- *****************************************************************************/
-enum class tri : char { no, yes, either };
-
-inline constexpr bool operator == (tri t, bool b) noexcept {
- return b ? t != tri::no : t != tri::yes;
-}
-inline constexpr bool operator == (bool b, tri t) noexcept { return (t == b); }
-inline constexpr bool operator != (tri t, bool b) noexcept { return !(t == b); }
-inline constexpr bool operator != (bool b, tri t) noexcept { return !(t == b); }
-
-
-
-/*************************************************************************//**
- *
- * @brief (start,size) index range
- *
- *****************************************************************************/
-class subrange {
-public:
- using size_type = arg_string::size_type;
-
- /** @brief default: no match */
- explicit constexpr
- subrange() noexcept :
- at_{arg_string::npos}, length_{0}
- {}
-
- /** @brief match length & position within subject string */
- explicit constexpr
- subrange(size_type pos, size_type len) noexcept :
- at_{pos}, length_{len}
- {}
-
- /** @brief position of the match within the subject string */
- constexpr size_type at() const noexcept { return at_; }
- /** @brief length of the matching subsequence */
- constexpr size_type length() const noexcept { return length_; }
-
- /** @brief returns true, if query string is a prefix of the subject string */
- constexpr bool prefix() const noexcept {
- return at_ == 0;
- }
-
- /** @brief returns true, if query is a substring of the query string */
- constexpr explicit operator bool () const noexcept {
- return at_ != arg_string::npos;
- }
-
-private:
- size_type at_;
- size_type length_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief match predicates
- *
- *****************************************************************************/
-using match_predicate = std::function;
-using match_function = std::function;
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief type traits (NOT FOR DIRECT USE IN CLIENT CODE!)
- * no interface guarantees; might be changed or removed in the future
- *
- *****************************************************************************/
-namespace traits {
-
-/*************************************************************************//**
- *
- * @brief function (class) signature type trait
- *
- *****************************************************************************/
-template
-constexpr auto
-check_is_callable(int) -> decltype(
- std::declval()(std::declval()...),
- std::integral_constant>::value>{} );
-
-template
-constexpr auto
-check_is_callable(long) -> std::false_type;
-
-template
-constexpr auto
-check_is_callable_without_arg(int) -> decltype(
- std::declval()(),
- std::integral_constant>::value>{} );
-
-template
-constexpr auto
-check_is_callable_without_arg(long) -> std::false_type;
-
-
-
-template
-constexpr auto
-check_is_void_callable(int) -> decltype(
- std::declval()(std::declval()...), std::true_type{});
-
-template
-constexpr auto
-check_is_void_callable(long) -> std::false_type;
-
-template
-constexpr auto
-check_is_void_callable_without_arg(int) -> decltype(
- std::declval()(), std::true_type{});
-
-template
-constexpr auto
-check_is_void_callable_without_arg(long) -> std::false_type;
-
-
-
-template
-struct is_callable;
-
-
-template
-struct is_callable :
- decltype(check_is_callable(0))
-{};
-
-template
-struct is_callable :
- decltype(check_is_callable_without_arg(0))
-{};
-
-
-template
-struct is_callable :
- decltype(check_is_void_callable(0))
-{};
-
-template
-struct is_callable :
- decltype(check_is_void_callable_without_arg(0))
-{};
-
-
-
-/*************************************************************************//**
- *
- * @brief input range type trait
- *
- *****************************************************************************/
-template
-constexpr auto
-check_is_input_range(int) -> decltype(
- begin(std::declval()), end(std::declval()),
- std::true_type{});
-
-template
-constexpr auto
-check_is_input_range(char) -> decltype(
- std::begin(std::declval()), std::end(std::declval()),
- std::true_type{});
-
-template
-constexpr auto
-check_is_input_range(long) -> std::false_type;
-
-template
-struct is_input_range :
- decltype(check_is_input_range(0))
-{};
-
-
-
-/*************************************************************************//**
- *
- * @brief size() member type trait
- *
- *****************************************************************************/
-template
-constexpr auto
-check_has_size_getter(int) ->
- decltype(std::declval().size(), std::true_type{});
-
-template
-constexpr auto
-check_has_size_getter(long) -> std::false_type;
-
-template
-struct has_size_getter :
- decltype(check_has_size_getter(0))
-{};
-
-} // namespace traits
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!)
- * no interface guarantees; might be changed or removed in the future
- *
- *****************************************************************************/
-namespace detail {
-
-
-/*************************************************************************//**
- * @brief forwards string to first non-whitespace char;
- * std string -> unsigned conv yields max value, but we want 0;
- * also checks for nullptr
- *****************************************************************************/
-inline bool
-fwd_to_unsigned_int(const char*& s)
-{
- if(!s) return false;
- for(; std::isspace(*s); ++s);
- if(!s[0] || s[0] == '-') return false;
- if(s[0] == '-') return false;
- return true;
-}
-
-
-/*************************************************************************//**
- *
- * @brief value limits clamping
- *
- *****************************************************************************/
-template sizeof(T))>
-struct limits_clamped {
- static T from(const V& v) {
- if(v >= V(std::numeric_limits::max())) {
- return std::numeric_limits::max();
- }
- if(v <= V(std::numeric_limits::lowest())) {
- return std::numeric_limits::lowest();
- }
- return T(v);
- }
-};
-
-template
-struct limits_clamped {
- static T from(const V& v) { return T(v); }
-};
-
-
-/*************************************************************************//**
- *
- * @brief returns value of v as a T, clamped at T's maximum
- *
- *****************************************************************************/
-template
-inline T clamped_on_limits(const V& v) {
- return limits_clamped::from(v);
-}
-
-
-
-
-/*************************************************************************//**
- *
- * @brief type conversion helpers
- *
- *****************************************************************************/
-template
-struct make {
- static inline T from(const char* s) {
- if(!s) return false;
- //a conversion from const char* to / must exist
- return static_cast(s);
- }
-};
-
-template<>
-struct make {
- static inline bool from(const char* s) {
- if(!s) return false;
- return static_cast(s);
- }
-};
-
-template<>
-struct make {
- static inline unsigned char from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline unsigned short int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline unsigned int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline unsigned long int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline unsigned long long int from(const char* s) {
- if(!fwd_to_unsigned_int(s)) return (0);
- return clamped_on_limits(std::strtoull(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline char from(const char* s) {
- //parse as single character?
- const auto n = std::strlen(s);
- if(n == 1) return s[0];
- //parse as integer
- return clamped_on_limits(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline short int from(const char* s) {
- return clamped_on_limits(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline int from(const char* s) {
- return clamped_on_limits(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline long int from(const char* s) {
- return clamped_on_limits(std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline long long int from(const char* s) {
- return (std::strtoll(s,nullptr,10));
- }
-};
-
-template<>
-struct make {
- static inline float from(const char* s) {
- return (std::strtof(s,nullptr));
- }
-};
-
-template<>
-struct make {
- static inline double from(const char* s) {
- return (std::strtod(s,nullptr));
- }
-};
-
-template<>
-struct make {
- static inline long double from(const char* s) {
- return (std::strtold(s,nullptr));
- }
-};
-
-template<>
-struct make {
- static inline std::string from(const char* s) {
- return std::string(s);
- }
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief assigns boolean constant to one or multiple target objects
- *
- *****************************************************************************/
-template
-class assign_value
-{
-public:
- template
- explicit constexpr
- assign_value(T& target, X&& value) noexcept :
- t_{std::addressof(target)}, v_{std::forward(value)}
- {}
-
- void operator () () const {
- if(t_) *t_ = v_;
- }
-
-private:
- T* t_;
- V v_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief flips bools
- *
- *****************************************************************************/
-class flip_bool
-{
-public:
- explicit constexpr
- flip_bool(bool& target) noexcept :
- b_{&target}
- {}
-
- void operator () () const {
- if(b_) *b_ = !*b_;
- }
-
-private:
- bool* b_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief increments using operator ++
- *
- *****************************************************************************/
-template
-class increment
-{
-public:
- explicit constexpr
- increment(T& target) noexcept : t_{std::addressof(target)} {}
-
- void operator () () const {
- if(t_) ++(*t_);
- }
-
-private:
- T* t_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief decrements using operator --
- *
- *****************************************************************************/
-template
-class decrement
-{
-public:
- explicit constexpr
- decrement(T& target) noexcept : t_{std::addressof(target)} {}
-
- void operator () () const {
- if(t_) --(*t_);
- }
-
-private:
- T* t_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief increments by a fixed amount using operator +=
- *
- *****************************************************************************/
-template
-class increment_by
-{
-public:
- explicit constexpr
- increment_by(T& target, T by) noexcept :
- t_{std::addressof(target)}, by_{std::move(by)}
- {}
-
- void operator () () const {
- if(t_) (*t_) += by_;
- }
-
-private:
- T* t_;
- T by_;
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes a value from a string and assigns it to an object
- *
- *****************************************************************************/
-template
-class map_arg_to
-{
-public:
- explicit constexpr
- map_arg_to(T& target) noexcept : t_{std::addressof(target)} {}
-
- void operator () (const char* s) const {
- if(t_ && s) *t_ = detail::make::from(s);
- }
-
-private:
- T* t_;
-};
-
-
-//-------------------------------------------------------------------
-/**
- * @brief specialization for vectors: append element
- */
-template
-class map_arg_to>
-{
-public:
- map_arg_to(std::vector& target): t_{std::addressof(target)} {}
-
- void operator () (const char* s) const {
- if(t_ && s) t_->push_back(detail::make::from(s));
- }
-
-private:
- std::vector* t_;
-};
-
-
-//-------------------------------------------------------------------
-/**
- * @brief specialization for bools:
- * set to true regardless of string content
- */
-template<>
-class map_arg_to
-{
-public:
- map_arg_to(bool& target): t_{&target} {}
-
- void operator () (const char* s) const {
- if(t_ && s) *t_ = true;
- }
-
-private:
- bool* t_;
-};
-
-
-} // namespace detail
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief string matching and processing tools
- *
- *****************************************************************************/
-
-namespace str {
-
-
-/*************************************************************************//**
- *
- * @brief converts string to value of target type 'T'
- *
- *****************************************************************************/
-template
-T make(const arg_string& s)
-{
- return detail::make::from(s);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief removes trailing whitespace from string
- *
- *****************************************************************************/
-template
-inline void
-trimr(std::basic_string& s)
-{
- if(s.empty()) return;
-
- s.erase(
- std::find_if_not(s.rbegin(), s.rend(),
- [](char c) { return std::isspace(c);} ).base(),
- s.end() );
-}
-
-
-/*************************************************************************//**
- *
- * @brief removes leading whitespace from string
- *
- *****************************************************************************/
-template
-inline void
-triml(std::basic_string& s)
-{
- if(s.empty()) return;
-
- s.erase(
- s.begin(),
- std::find_if_not(s.begin(), s.end(),
- [](char c) { return std::isspace(c);})
- );
-}
-
-
-/*************************************************************************//**
- *
- * @brief removes leading and trailing whitespace from string
- *
- *****************************************************************************/
-template
-inline void
-trim(std::basic_string& s)
-{
- triml(s);
- trimr(s);
-}
-
-
-/*************************************************************************//**
- *
- * @brief removes all whitespaces from string
- *
- *****************************************************************************/
-template
-inline void
-remove_ws(std::basic_string& s)
-{
- if(s.empty()) return;
-
- s.erase(std::remove_if(s.begin(), s.end(),
- [](char c) { return std::isspace(c); }),
- s.end() );
-}
-
-
-/*************************************************************************//**
- *
- * @brief returns true, if the 'prefix' argument
- * is a prefix of the 'subject' argument
- *
- *****************************************************************************/
-template
-inline bool
-has_prefix(const std::basic_string& subject,
- const std::basic_string& prefix)
-{
- if(prefix.size() > subject.size()) return false;
- return subject.find(prefix) == 0;
-}
-
-
-/*************************************************************************//**
- *
- * @brief returns true, if the 'postfix' argument
- * is a postfix of the 'subject' argument
- *
- *****************************************************************************/
-template
-inline bool
-has_postfix(const std::basic_string& subject,
- const std::basic_string& postfix)
-{
- if(postfix.size() > subject.size()) return false;
- return (subject.size() - postfix.size()) == subject.find(postfix);
-}
-
-
-
-/*************************************************************************//**
-*
-* @brief returns longest common prefix of several
-* sequential random access containers
-*
-* @details InputRange require begin and end (member functions or overloads)
-* the elements of InputRange require a size() member
-*
-*****************************************************************************/
-template
-auto
-longest_common_prefix(const InputRange& strs)
- -> typename std::decay::type
-{
- static_assert(traits::is_input_range(),
- "parameter must satisfy the InputRange concept");
-
- static_assert(traits::has_size_getter<
- typename std::decay::type>(),
- "elements of input range must have a ::size() member function");
-
- using std::begin;
- using std::end;
-
- using item_t = typename std::decay::type;
- using str_size_t = typename std::decaysize())>::type;
-
- const auto n = size_t(distance(begin(strs), end(strs)));
- if(n < 1) return item_t("");
- if(n == 1) return *begin(strs);
-
- //length of shortest string
- auto m = std::min_element(begin(strs), end(strs),
- [](const item_t& a, const item_t& b) {
- return a.size() < b.size(); })->size();
-
- //check each character until we find a mismatch
- for(str_size_t i = 0; i < m; ++i) {
- for(str_size_t j = 1; j < n; ++j) {
- if(strs[j][i] != strs[j-1][i])
- return strs[0].substr(0, i);
- }
- }
- return strs[0].substr(0, m);
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns longest substring range that could be found in 'arg'
- *
- * @param arg string to be searched in
- * @param substrings range of candidate substrings
- *
- *****************************************************************************/
-template
-subrange
-longest_substring_match(const std::basic_string& arg,
- const InputRange& substrings)
-{
- using string_t = std::basic_string;
-
- static_assert(traits::is_input_range(),
- "parameter must satisfy the InputRange concept");
-
- static_assert(std::is_same::type>(),
- "substrings must have same type as 'arg'");
-
- auto i = string_t::npos;
- auto n = string_t::size_type(0);
- for(const auto& s : substrings) {
- auto j = arg.find(s);
- if(j != string_t::npos && s.size() > n) {
- i = j;
- n = s.size();
- }
- }
- return subrange{i,n};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns longest prefix range that could be found in 'arg'
- *
- * @param arg string to be searched in
- * @param prefixes range of candidate prefix strings
- *
- *****************************************************************************/
-template
-subrange
-longest_prefix_match(const std::basic_string& arg,
- const InputRange& prefixes)
-{
- using string_t = std::basic_string;
- using s_size_t = typename string_t::size_type;
-
- static_assert(traits::is_input_range(),
- "parameter must satisfy the InputRange concept");
-
- static_assert(std::is_same::type>(),
- "prefixes must have same type as 'arg'");
-
- auto i = string_t::npos;
- auto n = s_size_t(0);
- for(const auto& s : prefixes) {
- auto j = arg.find(s);
- if(j == 0 && s.size() > n) {
- i = 0;
- n = s.size();
- }
- }
- return subrange{i,n};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns the first occurrence of 'query' within 'subject'
- *
- *****************************************************************************/
-template
-inline subrange
-substring_match(const std::basic_string& subject,
- const std::basic_string& query)
-{
- if(subject.empty() && query.empty()) return subrange(0,0);
- if(subject.empty() || query.empty()) return subrange{};
- auto i = subject.find(query);
- if(i == std::basic_string::npos) return subrange{};
- return subrange{i,query.size()};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns first substring match (pos,len) within the input string
- * that represents a number
- * (with at maximum one decimal point and digit separators)
- *
- *****************************************************************************/
-template
-subrange
-first_number_match(std::basic_string s,
- C digitSeparator = C(','),
- C decimalPoint = C('.'),
- C exponential = C('e'))
-{
- using string_t = std::basic_string;
- str::trim(s);
- if(s.empty()) return subrange{};
-
- //auto i = s.find_first_of("0123456789+-");
- //if(i == string_t::npos) {
- // i = s.find(decimalPoint);
- // if(i == string_t::npos) return subrange{};
- //}
- //bool point = false;
-
- // overwritten to match numbers without leading 0,
- // also commented out call to sanitize_args in parse
- auto i = s.find_first_of("0123456789+-.");
- if (i == string_t::npos) return subrange{};
- bool point = s[i] == decimalPoint;
-
- bool sep = false;
- auto exp = string_t::npos;
- auto j = i + 1;
- for(; j < s.size(); ++j) {
- if(s[j] == digitSeparator) {
- if(!sep) sep = true; else break;
- }
- else {
- sep = false;
- if(s[j] == decimalPoint) {
- //only one decimal point before exponent allowed
- if(!point && exp == string_t::npos) point = true; else break;
- }
- else if(std::tolower(s[j]) == std::tolower(exponential)) {
- //only one exponent separator allowed
- if(exp == string_t::npos) exp = j; else break;
- }
- else if(exp != string_t::npos && (exp+1) == j) {
- //only sign or digit after exponent separator
- if(s[j] != '+' && s[j] != '-' && !std::isdigit(s[j])) break;
- }
- else if(!std::isdigit(s[j])) {
- break;
- }
- }
- }
-
- //if length == 1 then must be a digit
- if(j-i == 1 && !std::isdigit(s[i])) return subrange{};
-
- return subrange{i,j-i};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns first substring match (pos,len)
- * that represents an integer (with optional digit separators)
- *
- *****************************************************************************/
-template
-subrange
-first_integer_match(std::basic_string s,
- C digitSeparator = C(','))
-{
- using string_t = std::basic_string;
- str::trim(s);
- if(s.empty()) return subrange{};
-
- auto i = s.find_first_of("0123456789+-");
- if(i == string_t::npos) return subrange{};
-
- bool sep = false;
- auto j = i + 1;
- for(; j < s.size(); ++j) {
- if(s[j] == digitSeparator) {
- if(!sep) sep = true; else break;
- }
- else {
- sep = false;
- if(!std::isdigit(s[j])) break;
- }
- }
-
- //if length == 1 then must be a digit
- if(j-i == 1 && !std::isdigit(s[i])) return subrange{};
-
- return subrange{i,j-i};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns true if candidate string represents a number
- *
- *****************************************************************************/
-template
-bool represents_number(const std::basic_string& candidate,
- C digitSeparator = C(','),
- C decimalPoint = C('.'),
- C exponential = C('e'))
-{
- const auto match = str::first_number_match(candidate, digitSeparator,
- decimalPoint, exponential);
-
- return (match && match.length() == candidate.size());
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief returns true if candidate string represents an integer
- *
- *****************************************************************************/
-template
-bool represents_integer(const std::basic_string& candidate,
- C digitSeparator = C(','))
-{
- const auto match = str::first_integer_match(candidate, digitSeparator);
- return (match && match.length() == candidate.size());
-}
-
-} // namespace str
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes function object with a const char* parameter
- * that assigns a value to a ref-captured object
- *
- *****************************************************************************/
-template
-inline detail::assign_value
-set(T& target, V value) {
- return detail::assign_value{target, std::move(value)};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes parameter-less function object
- * that assigns value(s) to a ref-captured object;
- * value(s) are obtained by converting the const char* argument to
- * the captured object types;
- * bools are always set to true if the argument is not nullptr
- *
- *****************************************************************************/
-template
-inline detail::map_arg_to
-set(T& target) {
- return detail::map_arg_to{target};
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief makes function object that sets a bool to true
- *
- *****************************************************************************/
-inline detail::assign_value
-set(bool& target) {
- return detail::assign_value{target,true};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that sets a bool to false
- *
- *****************************************************************************/
-inline detail::assign_value
-unset(bool& target) {
- return detail::assign_value{target,false};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that flips the value of a ref-captured bool
- *
- *****************************************************************************/
-inline detail::flip_bool
-flip(bool& b) {
- return detail::flip_bool(b);
-}
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief makes function object that increments using operator ++
- *
- *****************************************************************************/
-template
-inline detail::increment
-increment(T& target) {
- return detail::increment{target};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that decrements using operator --
- *
- *****************************************************************************/
-template
-inline detail::increment_by
-increment(T& target, T by) {
- return detail::increment_by{target, std::move(by)};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that increments by a fixed amount using operator +=
- *
- *****************************************************************************/
-template
-inline detail::decrement
-decrement(T& target) {
- return detail::decrement{target};
-}
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!)
- *
- *****************************************************************************/
-namespace detail {
-
-
-/*************************************************************************//**
- *
- * @brief mixin that provides action definition and execution
- *
- *****************************************************************************/
-template
-class action_provider
-{
-private:
- //---------------------------------------------------------------
- using simple_action = std::function;
- using arg_action = std::function;
- using index_action = std::function;
-
- //-----------------------------------------------------
- class simple_action_adapter {
- public:
- simple_action_adapter() = default;
- simple_action_adapter(const simple_action& a): action_(a) {}
- simple_action_adapter(simple_action&& a): action_(std::move(a)) {}
- void operator() (const char*) const { action_(); }
- void operator() (int) const { action_(); }
- private:
- simple_action action_;
- };
-
-
-public:
- //---------------------------------------------------------------
- /** @brief adds an action that has an operator() that is callable
- * with a 'const char*' argument */
- Derived&
- call(arg_action a) {
- argActions_.push_back(std::move(a));
- return *static_cast(this);
- }
-
- /** @brief adds an action that has an operator()() */
- Derived&
- call(simple_action a) {
- argActions_.push_back(simple_action_adapter(std::move(a)));
- return *static_cast(this);
- }
-
- /** @brief adds an action that has an operator() that is callable
- * with a 'const char*' argument */
- Derived& operator () (arg_action a) { return call(std::move(a)); }
-
- /** @brief adds an action that has an operator()() */
- Derived& operator () (simple_action a) { return call(std::move(a)); }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will set the value of 't' from
- * a 'const char*' arg */
- template
- Derived&
- set(Target& t) {
- static_assert(!std::is_pointer::value,
- "parameter target type must not be a pointer");
-
- return call(clipp::set(t));
- }
-
- /** @brief adds an action that will set the value of 't' to 'v' */
- template
- Derived&
- set(Target& t, Value&& v) {
- return call(clipp::set(t, std::forward(v)));
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a parameter
- * matches an argument for the 2nd, 3rd, 4th, ... time
- */
- Derived&
- if_repeated(simple_action a) {
- repeatActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast(this);
- }
- /** @brief adds an action that will be called with the argument's
- * index if a parameter matches an argument for
- * the 2nd, 3rd, 4th, ... time
- */
- Derived&
- if_repeated(index_action a) {
- repeatActions_.push_back(std::move(a));
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a required parameter
- * is missing
- */
- Derived&
- if_missing(simple_action a) {
- missingActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast(this);
- }
- /** @brief adds an action that will be called if a required parameter
- * is missing; the action will get called with the index of
- * the command line argument where the missing event occurred first
- */
- Derived&
- if_missing(index_action a) {
- missingActions_.push_back(std::move(a));
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a parameter
- * was matched, but was unreachable in the current scope
- */
- Derived&
- if_blocked(simple_action a) {
- blockedActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast(this);
- }
- /** @brief adds an action that will be called if a parameter
- * was matched, but was unreachable in the current scope;
- * the action will be called with the index of
- * the command line argument where the problem occurred
- */
- Derived&
- if_blocked(index_action a) {
- blockedActions_.push_back(std::move(a));
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds an action that will be called if a parameter match
- * was in conflict with a different alternative parameter
- */
- Derived&
- if_conflicted(simple_action a) {
- conflictActions_.push_back(simple_action_adapter{std::move(a)});
- return *static_cast(this);
- }
- /** @brief adds an action that will be called if a parameter match
- * was in conflict with a different alternative parameter;
- * the action will be called with the index of
- * the command line argument where the problem occurred
- */
- Derived&
- if_conflicted(index_action a) {
- conflictActions_.push_back(std::move(a));
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds targets = either objects whose values should be
- * set by command line arguments or actions that should
- * be called in case of a match */
- template
- Derived&
- target(T&& t, Ts&&... ts) {
- target(std::forward(t));
- target(std::forward(ts)...);
- return *static_cast(this);
- }
-
- /** @brief adds action that should be called in case of a match */
- template::type>() &&
- (traits::is_callable() ||
- traits::is_callable() )
- >::type>
- Derived&
- target(T&& t) {
- call(std::forward(t));
- return *static_cast(this);
- }
-
- /** @brief adds object whose value should be set by command line arguments
- */
- template::type>() ||
- (!traits::is_callable() &&
- !traits::is_callable() )
- >::type>
- Derived&
- target(T& t) {
- set(t);
- return *static_cast(this);
- }
-
- //TODO remove ugly empty param list overload
- Derived&
- target() {
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief adds target, see member function 'target' */
- template
- inline friend Derived&
- operator << (Target&& t, Derived& p) {
- p.target(std::forward(t));
- return p;
- }
- /** @brief adds target, see member function 'target' */
- template
- inline friend Derived&&
- operator << (Target&& t, Derived&& p) {
- p.target(std::forward(t));
- return std::move(p);
- }
-
- //-----------------------------------------------------
- /** @brief adds target, see member function 'target' */
- template
- inline friend Derived&
- operator >> (Derived& p, Target&& t) {
- p.target(std::forward(t));
- return p;
- }
- /** @brief adds target, see member function 'target' */
- template
- inline friend Derived&&
- operator >> (Derived&& p, Target&& t) {
- p.target(std::forward(t));
- return std::move(p);
- }
-
-
- //---------------------------------------------------------------
- /** @brief executes all argument actions */
- void execute_actions(const arg_string& arg) const {
- int i = 0;
- for(const auto& a : argActions_) {
- ++i;
- a(arg.c_str());
- }
- }
-
- /** @brief executes repeat actions */
- void notify_repeated(arg_index idx) const {
- for(const auto& a : repeatActions_) a(idx);
- }
- /** @brief executes missing error actions */
- void notify_missing(arg_index idx) const {
- for(const auto& a : missingActions_) a(idx);
- }
- /** @brief executes blocked error actions */
- void notify_blocked(arg_index idx) const {
- for(const auto& a : blockedActions_) a(idx);
- }
- /** @brief executes conflict error actions */
- void notify_conflict(arg_index idx) const {
- for(const auto& a : conflictActions_) a(idx);
- }
-
-private:
- //---------------------------------------------------------------
- std::vector argActions_;
- std::vector repeatActions_;
- std::vector missingActions_;
- std::vector blockedActions_;
- std::vector conflictActions_;
-};
-
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief mixin that provides basic common settings of parameters and groups
- *
- *****************************************************************************/
-template
-class token
-{
-public:
- //---------------------------------------------------------------
- using doc_string = clipp::doc_string;
-
-
- //---------------------------------------------------------------
- /** @brief returns documentation string */
- const doc_string& doc() const noexcept {
- return doc_;
- }
-
- /** @brief sets documentations string */
- Derived& doc(const doc_string& txt) {
- doc_ = txt;
- return *static_cast(this);
- }
-
- /** @brief sets documentations string */
- Derived& doc(doc_string&& txt) {
- doc_ = std::move(txt);
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if a group/parameter is repeatable */
- bool repeatable() const noexcept {
- return repeatable_;
- }
-
- /** @brief sets repeatability of group/parameter */
- Derived& repeatable(bool yes) noexcept {
- repeatable_ = yes;
- return *static_cast(this);
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if a group/parameter is blocking/positional */
- bool blocking() const noexcept {
- return blocking_;
- }
-
- /** @brief determines, if a group/parameter is blocking/positional */
- Derived& blocking(bool yes) noexcept {
- blocking_ = yes;
- return *static_cast(this);
- }
-
-
-private:
- //---------------------------------------------------------------
- doc_string doc_;
- bool repeatable_ = false;
- bool blocking_ = false;
-};
-
-
-
-
-/*************************************************************************//**
- *
- * @brief sets documentation strings on a token
- *
- *****************************************************************************/
-template
-inline T&
-operator % (doc_string docstr, token& p)
-{
- return p.doc(std::move(docstr));
-}
-//---------------------------------------------------------
-template
-inline T&&
-operator % (doc_string docstr, token&& p)
-{
- return std::move(p.doc(std::move(docstr)));
-}
-
-//---------------------------------------------------------
-template