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 +++++++++++++++++++++++++++++++++++
3 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 common/rawaccel-io.hpp
(limited to 'common')
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;
+ }
+
+}
--
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 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
(limited to 'common')
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");
+ }
+ }
+
}
--
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 +
8 files changed, 210 insertions(+), 7389 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
(limited to 'common')
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
-inline T&
-operator % (token& p, doc_string docstr)
-{
- return p.doc(std::move(docstr));
-}
-//---------------------------------------------------------
-template
-inline T&&
-operator % (token&& p, doc_string docstr)
-{
- return std::move(p.doc(std::move(docstr)));
-}
-
-
-
-
-/*************************************************************************//**
- *
- * @brief sets documentation strings on a token
- *
- *****************************************************************************/
-template
-inline T&
-doc(doc_string docstr, token& p)
-{
- return p.doc(std::move(docstr));
-}
-//---------------------------------------------------------
-template
-inline T&&
-doc(doc_string docstr, token&& p)
-{
- return std::move(p.doc(std::move(docstr)));
-}
-
-
-
-} // namespace detail
-
-
-
-/*************************************************************************//**
- *
- * @brief contains parameter matching functions and function classes
- *
- *****************************************************************************/
-namespace match {
-
-
-/*************************************************************************//**
- *
- * @brief predicate that is always true
- *
- *****************************************************************************/
-inline bool
-any(const arg_string&) { return true; }
-
-/*************************************************************************//**
- *
- * @brief predicate that is always false
- *
- *****************************************************************************/
-inline bool
-none(const arg_string&) { return false; }
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the argument string is non-empty string
- *
- *****************************************************************************/
-inline bool
-nonempty(const arg_string& s) {
- return !s.empty();
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the argument is a non-empty
- * string that consists only of alphanumeric characters
- *
- *****************************************************************************/
-inline bool
-alphanumeric(const arg_string& s) {
- if(s.empty()) return false;
- return std::all_of(s.begin(), s.end(), [](char c) {return std::isalnum(c); });
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the argument is a non-empty
- * string that consists only of alphabetic characters
- *
- *****************************************************************************/
-inline bool
-alphabetic(const arg_string& s) {
- return std::all_of(s.begin(), s.end(), [](char c) {return std::isalpha(c); });
-}
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns false if the argument string is
- * equal to any string from the exclusion list
- *
- *****************************************************************************/
-class none_of
-{
-public:
- none_of(arg_list strs):
- excluded_{std::move(strs)}
- {}
-
- template
- none_of(arg_string str, Strings&&... strs):
- excluded_{std::move(str), std::forward(strs)...}
- {}
-
- template
- none_of(const char* str, Strings&&... strs):
- excluded_{arg_string(str), std::forward(strs)...}
- {}
-
- bool operator () (const arg_string& arg) const {
- return (std::find(begin(excluded_), end(excluded_), arg)
- == end(excluded_));
- }
-
-private:
- arg_list excluded_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns the first substring match within the input
- * string that rmeepresents a number
- * (with at maximum one decimal point and digit separators)
- *
- *****************************************************************************/
-class numbers
-{
-public:
- explicit
- numbers(char decimalPoint = '.',
- char digitSeparator = ' ',
- char exponentSeparator = 'e')
- :
- decpoint_{decimalPoint}, separator_{digitSeparator},
- exp_{exponentSeparator}
- {}
-
- subrange operator () (const arg_string& s) const {
- return str::first_number_match(s, separator_, decpoint_, exp_);
- }
-
-private:
- char decpoint_;
- char separator_;
- char exp_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string represents an integer
- * (with optional digit separators)
- *
- *****************************************************************************/
-class integers {
-public:
- explicit
- integers(char digitSeparator = ' '): separator_{digitSeparator} {}
-
- subrange operator () (const arg_string& s) const {
- return str::first_integer_match(s, separator_);
- }
-
-private:
- char separator_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string represents
- * a non-negative integer (with optional digit separators)
- *
- *****************************************************************************/
-class positive_integers {
-public:
- explicit
- positive_integers(char digitSeparator = ' ') : separator_{ digitSeparator } {}
- subrange operator () (const arg_string& s) const {
- auto match = str::first_integer_match(s, separator_);
- if(!match) return subrange{};
- if(s[match.at()] == '-') return subrange{};
- return match;
- }
-
-private:
- char separator_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string
- * contains a given substring
- *
- *****************************************************************************/
-class substring
-{
-public:
- explicit
- substring(arg_string str): str_{std::move(str)} {}
-
- subrange operator () (const arg_string& s) const {
- return str::substring_match(s, str_);
- }
-
-private:
- arg_string str_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string starts
- * with a given prefix
- *
- *****************************************************************************/
-class prefix {
-public:
- explicit
- prefix(arg_string p): prefix_{std::move(p)} {}
-
- bool operator () (const arg_string& s) const {
- return s.find(prefix_) == 0;
- }
-
-private:
- arg_string prefix_;
-};
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the input string does not start
- * with a given prefix
- *
- *****************************************************************************/
-class prefix_not {
-public:
- explicit
- prefix_not(arg_string p): prefix_{std::move(p)} {}
-
- bool operator () (const arg_string& s) const {
- return s.find(prefix_) != 0;
- }
-
-private:
- arg_string prefix_;
-};
-
-
-/** @brief alias for prefix_not */
-using noprefix = prefix_not;
-
-
-
-/*************************************************************************//**
- *
- * @brief predicate that returns true if the length of the input string
- * is wihtin a given interval
- *
- *****************************************************************************/
-class length {
-public:
- explicit
- length(std::size_t exact):
- min_{exact}, max_{exact}
- {}
-
- explicit
- length(std::size_t min, std::size_t max):
- min_{min}, max_{max}
- {}
-
- bool operator () (const arg_string& s) const {
- return s.size() >= min_ && s.size() <= max_;
- }
-
-private:
- std::size_t min_;
- std::size_t max_;
-};
-
-
-/*************************************************************************//**
- *
- * @brief makes function object that returns true if the input string has a
- * given minimum length
- *
- *****************************************************************************/
-inline length min_length(std::size_t min)
-{
- return length{min, arg_string::npos-1};
-}
-
-/*************************************************************************//**
- *
- * @brief makes function object that returns true if the input string is
- * not longer than a given maximum length
- *
- *****************************************************************************/
-inline length max_length(std::size_t max)
-{
- return length{0, max};
-}
-
-
-} // namespace match
-
-
-
-
-
-/*************************************************************************//**
- *
- * @brief command line parameter that can match one or many arguments.
- *
- *****************************************************************************/
-class parameter :
- public detail::token,
- public detail::action_provider
-{
- /** @brief adapts a 'match_predicate' to the 'match_function' interface */
- class predicate_adapter {
- public:
- explicit
- predicate_adapter(match_predicate pred): match_{std::move(pred)} {}
-
- subrange operator () (const arg_string& arg) const {
- return match_(arg) ? subrange{0,arg.size()} : subrange{};
- }
-
- private:
- match_predicate match_;
- };
-
-public:
- //---------------------------------------------------------------
- /** @brief makes default parameter, that will match nothing */
- parameter():
- flags_{},
- matcher_{predicate_adapter{match::none}},
- label_{}, required_{false}, greedy_{false}
- {}
-
- /** @brief makes "flag" parameter */
- template
- explicit
- parameter(arg_string str, Strings&&... strs):
- flags_{},
- matcher_{predicate_adapter{match::none}},
- label_{}, required_{false}, greedy_{false}
- {
- add_flags(std::move(str), std::forward(strs)...);
- }
-
- /** @brief makes "flag" parameter from range of strings */
- explicit
- parameter(const arg_list& flaglist):
- flags_{},
- matcher_{predicate_adapter{match::none}},
- label_{}, required_{false}, greedy_{false}
- {
- add_flags(flaglist);
- }
-
- //-----------------------------------------------------
- /** @brief makes "value" parameter with custom match predicate
- * (= yes/no matcher)
- */
- explicit
- parameter(match_predicate filter):
- flags_{},
- matcher_{predicate_adapter{std::move(filter)}},
- label_{}, required_{false}, greedy_{false}
- {}
-
- /** @brief makes "value" parameter with custom match function
- * (= partial matcher)
- */
- explicit
- parameter(match_function filter):
- flags_{},
- matcher_{std::move(filter)},
- label_{}, required_{false}, greedy_{false}
- {}
-
-
- //---------------------------------------------------------------
- /** @brief returns if a parameter is required */
- bool
- required() const noexcept {
- return required_;
- }
-
- /** @brief determines if a parameter is required */
- parameter&
- required(bool yes) noexcept {
- required_ = yes;
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns if a parameter should match greedily */
- bool
- greedy() const noexcept {
- return greedy_;
- }
-
- /** @brief determines if a parameter should match greedily */
- parameter&
- greedy(bool yes) noexcept {
- greedy_ = yes;
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns parameter label;
- * will be used for documentation, if flags are empty
- */
- const doc_string&
- label() const {
- return label_;
- }
-
- /** @brief sets parameter label;
- * will be used for documentation, if flags are empty
- */
- parameter&
- label(const doc_string& lbl) {
- label_ = lbl;
- return *this;
- }
-
- /** @brief sets parameter label;
- * will be used for documentation, if flags are empty
- */
- parameter&
- label(doc_string&& lbl) {
- label_ = lbl;
- return *this;
- }
-
-
- //---------------------------------------------------------------
- /** @brief returns either longest matching prefix of 'arg' in any
- * of the flags or the result of the custom match operation
- */
- subrange
- match(const arg_string& arg) const
- {
- if(flags_.empty()) {
- return matcher_(arg);
- }
- else {
- //empty flags are not allowed
- if(arg.empty()) return subrange{};
-
- if(std::find(flags_.begin(), flags_.end(), arg) != flags_.end()) {
- return subrange{0,arg.size()};
- }
- return str::longest_prefix_match(arg, flags_);
- }
- }
-
-
- //---------------------------------------------------------------
- /** @brief access range of flag strings */
- const arg_list&
- flags() const noexcept {
- return flags_;
- }
-
- /** @brief access custom match operation */
- const match_function&
- matcher() const noexcept {
- return matcher_;
- }
-
-
- //---------------------------------------------------------------
- /** @brief prepend prefix to each flag */
- inline friend parameter&
- with_prefix(const arg_string& prefix, parameter& p)
- {
- if(prefix.empty() || p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.find(prefix) != 0) f.insert(0, prefix);
- }
- return p;
- }
-
-
- /** @brief prepend prefix to each flag
- */
- inline friend parameter&
- with_prefixes_short_long(
- const arg_string& shortpfx, const arg_string& longpfx,
- parameter& p)
- {
- if(shortpfx.empty() && longpfx.empty()) return p;
- if(p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.size() == 1) {
- if(f.find(shortpfx) != 0) f.insert(0, shortpfx);
- } else {
- if(f.find(longpfx) != 0) f.insert(0, longpfx);
- }
- }
- return p;
- }
-
-
- //---------------------------------------------------------------
- /** @brief prepend suffix to each flag */
- inline friend parameter&
- with_suffix(const arg_string& suffix, parameter& p)
- {
- if(suffix.empty() || p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.find(suffix) + suffix.size() != f.size()) {
- f.insert(f.end(), suffix.begin(), suffix.end());
- }
- }
- return p;
- }
-
-
- /** @brief prepend suffix to each flag
- */
- inline friend parameter&
- with_suffixes_short_long(
- const arg_string& shortsfx, const arg_string& longsfx,
- parameter& p)
- {
- if(shortsfx.empty() && longsfx.empty()) return p;
- if(p.flags().empty()) return p;
-
- for(auto& f : p.flags_) {
- if(f.size() == 1) {
- if(f.find(shortsfx) + shortsfx.size() != f.size()) {
- f.insert(f.end(), shortsfx.begin(), shortsfx.end());
- }
- } else {
- if(f.find(longsfx) + longsfx.size() != f.size()) {
- f.insert(f.end(), longsfx.begin(), longsfx.end());
- }
- }
- }
- return p;
- }
-
-private:
- //---------------------------------------------------------------
- void add_flags(arg_string str) {
- //empty flags are not allowed
- str::remove_ws(str);
- if(!str.empty()) flags_.push_back(std::move(str));
- }
-
- //---------------------------------------------------------------
- void add_flags(const arg_list& strs) {
- if(strs.empty()) return;
- flags_.reserve(flags_.size() + strs.size());
- for(const auto& s : strs) add_flags(s);
- }
-
- template