diff options
| author | Denis Evsyukov <[email protected]> | 2020-03-07 18:46:45 +0300 |
|---|---|---|
| committer | Denis Evsyukov <[email protected]> | 2020-03-07 18:46:45 +0300 |
| commit | 101d877bf713df10c58968b80b0712477fad7bf3 (patch) | |
| tree | 620ac5e4114f84264cd78947387a4c9c20338ef5 | |
| parent | [+] added important note (diff) | |
| download | t-101d877bf713df10c58968b80b0712477fad7bf3.tar.xz t-101d877bf713df10c58968b80b0712477fad7bf3.zip | |
[+] getopts
| -rw-r--r-- | .gitignore | 5 | ||||
| -rw-r--r-- | CMakeLists.txt | 6 | ||||
| -rw-r--r-- | Cargo.lock | 23 | ||||
| -rw-r--r-- | Cargo.toml | 10 | ||||
| -rw-r--r-- | src/functions.hpp | 35 | ||||
| -rw-r--r-- | src/main.cpp | 248 | ||||
| -rw-r--r-- | src/main.rs | 43 | ||||
| -rw-r--r-- | src/opts/cxxopts.hpp | 2072 | ||||
| -rw-r--r-- | src/sha256/picosha2.h | 376 |
9 files changed, 77 insertions, 2741 deletions
@@ -1,4 +1 @@ -cmake-build-release -cmake-build-debug -.ccls-cache -build
\ No newline at end of file +/target diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 655db6f..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -cmake_minimum_required(VERSION 3.15) -project(t) - -set(CMAKE_CXX_STANDARD 17) - -add_executable(t src/main.cpp src/opts/cxxopts.hpp src/functions.hpp)
\ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..2d96995 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "t" +version = "0.1.0" +dependencies = [ + "getopts", +] + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..18f248d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "t" +version = "0.1.0" +authors = ["Denis Evsyukov <[email protected]>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +getopts = "0.2"
\ No newline at end of file diff --git a/src/functions.hpp b/src/functions.hpp deleted file mode 100644 index 6b86197..0000000 --- a/src/functions.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Created by d.evsyukov on 09.01.2020. -// - -#ifndef T_FUNCTIONS_HPP -#define T_FUNCTIONS_HPP - -#include "sha256/picosha2.h" -#include <string> - -std::string <rim(std::string &str, const std::string &chars = "\t\n\v\f\r ") { - str.erase(0, str.find_first_not_of(chars)); - return str; -} - -std::string &rtrim(std::string &str, const std::string &chars = "\t\n\v\f\r ") { - str.erase(str.find_last_not_of(chars) + 1); - return str; -} - -std::string &trim(std::string &str, const std::string &chars = "\t\n\v\f\r ") { - return ltrim(rtrim(str, chars), chars); -} - -std::vector<std::string> split(const std::string &s, char delimiter) { - std::vector<std::string> tokens; - std::string token; - std::istringstream tokenStream(s); - while (std::getline(tokenStream, token, delimiter)) { - tokens.push_back(token); - } - return tokens; -} - -#endif // T_FUNCTIONS_HPP diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 010f3d3..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include <filesystem> -#include <unordered_map> - -#include "functions.hpp" -#include "opts/cxxopts.hpp" - -namespace fs = std::filesystem; - -std::unordered_map<std::string, std::string> tasks = {}; -std::unordered_map<std::string, std::string> tasksDone = {}; -std::unordered_map<std::string, std::string> prefixes = {}; - -fs::path taskpath, donepath; -std::string taskdir; -std::string taskfile; -bool deleteIfEmpthy; - -std::string sha256_hash(std::string text) { - std::vector<unsigned char> hash(picosha2::k_digest_size); - picosha2::hash256(text.begin(), text.end(), hash.begin(), hash.end()); - - std::string hex_str = picosha2::bytes_to_hex_string(hash.begin(), hash.end()); - return hex_str; -} - -std::string prefix(std::string hash) { - std::string prefix; - for (size_t i = 1; i <= hash.length(); i++) { - prefix = hash.substr(0, i); - if (prefixes.find(prefix) == prefixes.end()) - return prefix; - } - return hash; -} - -std::string getPrefixByHash(const std::string& hash) { - for (const auto &n : prefixes) { - if (n.second == hash) - return n.first; - } - return ""; -} - -void readFiles() { - // read task file - std::ifstream intaskfile(taskpath); - - std::string line; - while (std::getline(intaskfile, line)) { - std::istringstream iss(line); - tasks[sha256_hash(line)] = line; - } - intaskfile.close(); - - // read done file - std::ifstream indonefile(donepath); - - while (std::getline(indonefile, line)) { - std::istringstream iss(line); - tasksDone[sha256_hash(line)] = line; - } - indonefile.close(); - - for (const auto &n : tasks) { - prefixes[prefix(n.first)] = n.first; - } -} - -void writeFiles() { - if (deleteIfEmpthy && (tasks.empty())) { - remove(taskpath); - remove(donepath); - } else { - std::ofstream outtaskfile(taskpath); - if (outtaskfile.is_open()) { - for (const auto &n : tasks) { - outtaskfile << n.second << std::endl; - } - } - outtaskfile.close(); - std::ofstream outdonefile(donepath); - if (outdonefile.is_open()) { - for (const auto &n : tasksDone) { - outdonefile << n.second << std::endl; - } - } - outdonefile.close(); - } -} - -int main(int argc, char *argv[]) { - cxxopts::Options options( - "t", "t is for people that want do things, not organize their tasks."); - options.allow_unrecognised_options().add_options()( - "positional", - "Positional arguments: these are the arguments that are entered " - "without an option", - cxxopts::value<std::vector<std::string>>())( - "e,edit", "edit TASK to contain TEXT", cxxopts::value<std::string>())( - "f,finish", "mark TASK as finished", cxxopts::value<std::string>())( - "r,remove", "Remove TASK from list", cxxopts::value<std::string>())( - "l,list", "work on LIST", - cxxopts::value<std::string>()->default_value("tasks"))( - "t,taskdir", "work on the lists in DIR", cxxopts::value<std::string>())( - "d,delete-if-empty", "delete the task file if it becomes empty", - cxxopts::value<bool>()->default_value("false"))( - "g,grep", "print only tasks that contain WORD", - cxxopts::value<std::string>())( - "v,verbose", "print more detailed output (full task ids, etc)", - cxxopts::value<bool>()->default_value("false"))( - "q,quiet", "print less detailed output (no task ids, etc)", - cxxopts::value<bool>()->default_value("false"))( - "done", "list done tasks instead of unfinished ones", - cxxopts::value<bool>()->default_value("false"))("h,help", "HELP"); - options.parse_positional({"positional"}); - auto result = options.parse(argc, argv); - const auto &arguments = result.arguments(); - - if (result.count("help")) { - std::cout << options.help() << std::endl; - exit(0); - } - - if (result.count("taskdir")) { - taskdir = result["taskdir"].as<std::string>(); - } else { - namespace fs = std::filesystem; - taskdir = fs::current_path(); - } - - if (result.count("list")) { - taskfile = result["list"].as<std::string>(); - } else { - taskfile = "tasks"; - } - - taskpath = fs::path(taskdir) / fs::path(taskfile); - donepath = fs::path(taskdir) / fs::path("." + taskfile + ".done"); - - if (!fs::exists(fs::path(taskdir))) { - std::cout << "Path is not exist: " << fs::path(taskdir) << std::endl; - exit(1); - } - - if (result.count("delete-if-empty")) { - deleteIfEmpthy = true; - } - - readFiles(); - - // edit task - if (result.count("edit")) { - auto task_prefix = result["edit"].as<std::string>(); - auto task_hash = prefixes[task_prefix]; - if (tasks.find(task_hash) != tasks.end()) { - std::string str; - auto &v = result["positional"].as<std::vector<std::string>>(); - for (const auto &s : v) { - str += s + " "; - } - auto src_str = trim(str); - if (src_str.length() > 0) { - tasks[sha256_hash(src_str)] = src_str; - tasks.erase(task_hash); - writeFiles(); - } - } else { - std::cout << "Task not found: " << task_prefix << std::endl; - } - exit(0); - } - - // finish task - if (result.count("finish")) { - auto task_prefix = result["finish"].as<std::string>(); - for (const auto &el : split(task_prefix, ',')) { - auto task_hash = prefixes[el]; - if (tasks.find(task_hash) != tasks.end()) { - tasksDone[task_hash] = tasks[task_hash]; - tasks.erase(task_hash); - } else { - std::cout << "Task not found: " << el << std::endl; - } - } - writeFiles(); - exit(0); - } - - // remove task - if (result.count("remove")) { - auto task_prefix = result["remove"].as<std::string>(); - for (const auto &el : split(task_prefix, ',')) { - auto task_hash = prefixes[el]; - if (tasks.find(task_hash) != tasks.end()) { - tasks.erase(task_hash); - } else { - std::cout << "Task not found: " << el << std::endl; - } - } - writeFiles(); - exit(0); - } - - // add new task - if (result.count("positional")) { - std::string str; - auto &v = result["positional"].as<std::vector<std::string>>(); - for (const auto &s : v) { - str += s + " "; - } - auto src_str = trim(str); - tasks[sha256_hash(src_str)] = src_str; - std::string hash = sha256_hash(src_str); - std::string p = prefix(hash); - - writeFiles(); - exit(0); - } - - // print tasks - if (result.count("done")) { - for (const auto &n : tasksDone) { - std::cout << n.second << std::endl; - } - exit(0); - } - - std::string word; - if (result.count("grep")) { - word = result["grep"].as<std::string>(); - } else { - word = ""; - } - - for (const auto &n : tasks) { - if (n.second.find(word) != std::string::npos) { - if (result.count("quiet")) { - std::cout << n.second << std::endl; - } else if (result.count("verbose")) { - std::cout << n.first << " - " << n.second << std::endl; - } else { - std::cout << getPrefixByHash(n.first) << " - " << n.second << std::endl; - } - } - } - - return 0; -}
\ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..88027c7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,43 @@ +extern crate getopts; + +use getopts::*; +use std::env; + +fn main() { + let args: Vec<String> = env::args().collect(); + let mut opts = Options::new(); + opts.optflag("h", "help", "Show this help screen"); + opts.optflag("", "done", "list done tasks instead of unfinished ones"); + opts.optopt("e", "edit", "edit TASK to contain TEXT", "TASK"); + opts.optopt("f", "finish", "mark TASK as finished", "TASK"); + opts.optopt("r", "remove", "Remove TASK from list", "TASK"); + opts.optopt("l", "list", "work on LIST", "LIST"); + opts.optopt("t", "taskdir", "work on the lists in DIR", "DIR"); + opts.optflag( + "d", + "delete-if-empty", + "delete the task file if it becomes empty", + ); + opts.optopt("g", "grep", "print only tasks that contain WORD", "WORD"); + opts.optflag( + "v", + "verbose", + "print more detailed output (full task ids, etc)", + ); + opts.optflag( + "q", + "quiet", + "print less detailed output (no task ids, etc)", + ); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => panic!(f.to_string()), + }; + + if matches.opt_present("h") { + let brief = "t is for people that want do things, not organize their tasks"; + opts.usage(&brief); + return; + } +} diff --git a/src/opts/cxxopts.hpp b/src/opts/cxxopts.hpp deleted file mode 100644 index 99e0aab..0000000 --- a/src/opts/cxxopts.hpp +++ /dev/null @@ -1,2072 +0,0 @@ -/* - -Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*/ - -#ifndef CXXOPTS_HPP_INCLUDED -#define CXXOPTS_HPP_INCLUDED - -#include <cstring> -#include <cctype> -#include <exception> -#include <iostream> -#include <limits> -#include <map> -#include <memory> -#include <regex> -#include <sstream> -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <vector> - -#ifdef __cpp_lib_optional -#include <optional> -#define CXXOPTS_HAS_OPTIONAL -#endif - -#ifndef CXXOPTS_VECTOR_DELIMITER -#define CXXOPTS_VECTOR_DELIMITER ',' -#endif - -#define CXXOPTS__VERSION_MAJOR 2 -#define CXXOPTS__VERSION_MINOR 2 -#define CXXOPTS__VERSION_PATCH 0 - -namespace cxxopts -{ -static constexpr struct -{ - uint8_t major, minor, patch; -} version = { - CXXOPTS__VERSION_MAJOR, - CXXOPTS__VERSION_MINOR, - CXXOPTS__VERSION_PATCH}; -} // namespace cxxopts - -//when we ask cxxopts to use Unicode, help strings are processed using ICU, -//which results in the correct lengths being computed for strings when they -//are formatted for the help output -//it is necessary to make sure that <unicode/unistr.h> can be found by the -//compiler, and that icu-uc is linked in to the binary. - -#ifdef CXXOPTS_USE_UNICODE -#include <unicode/unistr.h> - -namespace cxxopts -{ -typedef icu::UnicodeString String; - -inline String -toLocalString(std::string s) -{ - return icu::UnicodeString::fromUTF8(std::move(s)); -} - -class UnicodeStringIterator : public std::iterator<std::forward_iterator_tag, int32_t> -{ -public: - UnicodeStringIterator(const icu::UnicodeString *string, int32_t pos) - : s(string), i(pos) - { - } - - value_type - operator*() const - { - return s->char32At(i); - } - - bool - operator==(const UnicodeStringIterator &rhs) const - { - return s == rhs.s && i == rhs.i; - } - - bool - operator!=(const UnicodeStringIterator &rhs) const - { - return !(*this == rhs); - } - - UnicodeStringIterator & - operator++() - { - ++i; - return *this; - } - - UnicodeStringIterator - operator+(int32_t v) - { - return UnicodeStringIterator(s, i + v); - } - -private: - const icu::UnicodeString *s; - int32_t i; -}; - -inline String & -stringAppend(String &s, String a) -{ - return s.append(std::move(a)); -} - -inline String & -stringAppend(String &s, int n, UChar32 c) -{ - for (int i = 0; i != n; ++i) - { - s.append(c); - } - - return s; -} - -template <typename Iterator> -String & -stringAppend(String &s, Iterator begin, Iterator end) -{ - while (begin != end) - { - s.append(*begin); - ++begin; - } - - return s; -} - -inline size_t -stringLength(const String &s) -{ - return s.length(); -} - -inline std::string -toUTF8String(const String &s) -{ - std::string result; - s.toUTF8String(result); - - return result; -} - -inline bool -empty(const String &s) -{ - return s.isEmpty(); -} -} // namespace cxxopts - -namespace std -{ -inline cxxopts::UnicodeStringIterator -begin(const icu::UnicodeString &s) -{ - return cxxopts::UnicodeStringIterator(&s, 0); -} - -inline cxxopts::UnicodeStringIterator -end(const icu::UnicodeString &s) -{ - return cxxopts::UnicodeStringIterator(&s, s.length()); -} -} // namespace std - -//ifdef CXXOPTS_USE_UNICODE -#else - -namespace cxxopts -{ -typedef std::string String; - -template <typename T> -T toLocalString(T &&t) -{ - return std::forward<T>(t); -} - -inline size_t -stringLength(const String &s) -{ - return s.length(); -} - -inline String & -stringAppend(String &s, String a) -{ - return s.append(std::move(a)); -} - -inline String & -stringAppend(String &s, size_t n, char c) -{ - return s.append(n, c); -} - -template <typename Iterator> -String & -stringAppend(String &s, Iterator begin, Iterator end) -{ - return s.append(begin, end); -} - -template <typename T> -std::string -toUTF8String(T &&t) -{ - return std::forward<T>(t); -} - -inline bool -empty(const std::string &s) -{ - return s.empty(); -} -} // namespace cxxopts - -//ifdef CXXOPTS_USE_UNICODE -#endif - -namespace cxxopts -{ -namespace -{ -#ifdef _WIN32 -const std::string LQUOTE("\'"); -const std::string RQUOTE("\'"); -#else -const std::string LQUOTE("‘"); -const std::string RQUOTE("’"); -#endif -} // namespace - -class Value : public std::enable_shared_from_this<Value> -{ -public: - virtual ~Value() = default; - - virtual std::shared_ptr<Value> - clone() const = 0; - - virtual void - parse(const std::string &text) const = 0; - - virtual void - parse() const = 0; - - virtual bool - has_default() const = 0; - - virtual bool - is_container() const = 0; - - virtual bool - has_implicit() const = 0; - - virtual std::string - get_default_value() const = 0; - - virtual std::string - get_implicit_value() const = 0; - - virtual std::shared_ptr<Value> - default_value(const std::string &value) = 0; - - virtual std::shared_ptr<Value> - implicit_value(const std::string &value) = 0; - - virtual std::shared_ptr<Value> - no_implicit_value() = 0; - - virtual bool - is_boolean() const = 0; -}; - -class OptionException : public std::exception -{ -public: - OptionException(const std::string &message) - : m_message(message) - { - } - - virtual const char * - what() const noexcept - { - return m_message.c_str(); - } - -private: - std::string m_message; -}; - -class OptionSpecException : public OptionException -{ -public: - OptionSpecException(const std::string &message) - : OptionException(message) - { - } -}; - -class OptionParseException : public OptionException -{ -public: - OptionParseException(const std::string &message) - : OptionException(message) - { - } -}; - -class option_exists_error : public OptionSpecException -{ -public: - option_exists_error(const std::string &option) - : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") - { - } -}; - -class invalid_option_format_error : public OptionSpecException -{ -public: - invalid_option_format_error(const std::string &format) - : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) - { - } -}; - -class option_syntax_exception : public OptionParseException -{ -public: - option_syntax_exception(const std::string &text) - : OptionParseException("Argument " + LQUOTE + text + RQUOTE + - " starts with a - but has incorrect syntax") - { - } -}; - -class option_not_exists_exception : public OptionParseException -{ -public: - option_not_exists_exception(const std::string &option) - : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") - { - } -}; - -class missing_argument_exception : public OptionParseException -{ -public: - missing_argument_exception(const std::string &option) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + " is missing an argument") - { - } -}; - -class option_requires_argument_exception : public OptionParseException -{ -public: - option_requires_argument_exception(const std::string &option) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + " requires an argument") - { - } -}; - -class option_not_has_argument_exception : public OptionParseException -{ -public: - option_not_has_argument_exception( - const std::string &option, - const std::string &arg) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + - " does not take an argument, but argument " + - LQUOTE + arg + RQUOTE + " given") - { - } -}; - -class option_not_present_exception : public OptionParseException -{ -public: - option_not_present_exception(const std::string &option) - : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") - { - } -}; - -class argument_incorrect_type : public OptionParseException -{ -public: - argument_incorrect_type( - const std::string &arg) - : OptionParseException( - "Argument " + LQUOTE + arg + RQUOTE + " failed to parse") - { - } -}; - -class option_required_exception : public OptionParseException -{ -public: - option_required_exception(const std::string &option) - : OptionParseException( - "Option " + LQUOTE + option + RQUOTE + " is required but not present") - { - } -}; - -template <typename T> -void throw_or_mimic(const std::string &text) -{ - static_assert(std::is_base_of<std::exception, T>::value, - "throw_or_mimic only works on std::exception and " - "deriving classes"); - -#ifndef CXXOPTS_NO_EXCEPTIONS - // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw - throw T{text}; -#else - // Otherwise manually instantiate the exception, print what() to stderr, - // and abort - T exception{text}; - std::cerr << exception.what() << std::endl; - std::cerr << "Aborting (exceptions disabled)..." << std::endl; - std::abort(); -#endif -} - -namespace values -{ -namespace -{ -std::basic_regex<char> integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); -std::basic_regex<char> truthy_pattern("(t|T)(rue)?|1"); -std::basic_regex<char> falsy_pattern("(f|F)(alse)?|0"); -} // namespace - -namespace detail -{ -template <typename T, bool B> -struct SignedCheck; - -template <typename T> -struct SignedCheck<T, true> -{ - template <typename U> - void - operator()(bool negative, U u, const std::string &text) - { - if (negative) - { - if (u > static_cast<U>((std::numeric_limits<T>::min)())) - { - throw_or_mimic<argument_incorrect_type>(text); - } - } - else - { - if (u > static_cast<U>((std::numeric_limits<T>::max)())) - { - throw_or_mimic<argument_incorrect_type>(text); - } - } - } -}; - -template <typename T> -struct SignedCheck<T, false> -{ - template <typename U> - void - operator()(bool, U, const std::string &) {} -}; - -template <typename T, typename U> -void check_signed_range(bool negative, U value, const std::string &text) -{ - SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text); -} -} // namespace detail - -template <typename R, typename T> -R checked_negate(T &&t, const std::string &, std::true_type) -{ - // if we got to here, then `t` is a positive number that fits into - // `R`. So to avoid MSVC C4146, we first cast it to `R`. - // See https://github.com/jarro2783/cxxopts/issues/62 for more details. - return static_cast<R>(-static_cast<R>(t - 1) - 1); -} - -template <typename R, typename T> -T checked_negate(T &&t, const std::string &text, std::false_type) -{ - throw_or_mimic<argument_incorrect_type>(text); - return t; -} - -template <typename T> -void integer_parser(const std::string &text, T &value) -{ - std::smatch match; - std::regex_match(text, match, integer_pattern); - - if (match.length() == 0) - { - throw_or_mimic<argument_incorrect_type>(text); - } - - if (match.length(4) > 0) - { - value = 0; - return; - } - - using US = typename std::make_unsigned<T>::type; - - constexpr bool is_signed = std::numeric_limits<T>::is_signed; - const bool negative = match.length(1) > 0; - const uint8_t base = match.length(2) > 0 ? 16 : 10; - - auto value_match = match[3]; - - US result = 0; - - for (auto iter = value_match.first; iter != value_match.second; ++iter) - { - US digit = 0; - - if (*iter >= '0' && *iter <= '9') - { - digit = static_cast<US>(*iter - '0'); - } - else if (base == 16 && *iter >= 'a' && *iter <= 'f') - { - digit = static_cast<US>(*iter - 'a' + 10); - } - else if (base == 16 && *iter >= 'A' && *iter <= 'F') - { - digit = static_cast<US>(*iter - 'A' + 10); - } - else - { - throw_or_mimic<argument_incorrect_type>(text); - } - - const US next = static_cast<US>(result * base + digit); - if (result > next) - { - throw_or_mimic<argument_incorrect_type>(text); - } - - result = next; - } - - detail::check_signed_range<T>(negative, result, text); - - if (negative) - { - value = checked_negate<T>(result, - text, - std::integral_constant<bool, is_signed>()); - } - else - { - value = static_cast<T>(result); - } -} - -template <typename T> -void stringstream_parser(const std::string &text, T &value) -{ - std::stringstream in(text); - in >> value; - if (!in) - { - throw_or_mimic<argument_incorrect_type>(text); - } -} - -inline void -parse_value(const std::string &text, uint8_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, int8_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, uint16_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, int16_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, uint32_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, int32_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, uint64_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, int64_t &value) -{ - integer_parser(text, value); -} - -inline void -parse_value(const std::string &text, bool &value) -{ - std::smatch result; - std::regex_match(text, result, truthy_pattern); - - if (!result.empty()) - { - value = true; - return; - } - - std::regex_match(text, result, falsy_pattern); - if (!result.empty()) - { - value = false; - return; - } - - throw_or_mimic<argument_incorrect_type>(text); -} - -inline void -parse_value(const std::string &text, std::string &value) -{ - value = text; -} - -// The fallback parser. It uses the stringstream parser to parse all types -// that have not been overloaded explicitly. It has to be placed in the -// source code before all other more specialized templates. -template <typename T> -void parse_value(const std::string &text, T &value) -{ - stringstream_parser(text, value); -} - -template <typename T> -void parse_value(const std::string &text, std::vector<T> &value) -{ - std::stringstream in(text); - std::string token; - while (in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) - { - T v; - parse_value(token, v); - value.emplace_back(std::move(v)); - } -} - -#ifdef CXXOPTS_HAS_OPTIONAL -template <typename T> -void parse_value(const std::string &text, std::optional<T> &value) -{ - T result; - parse_value(text, result); - value = std::move(result); -} -#endif - -inline void parse_value(const std::string &text, char &c) -{ - if (text.length() != 1) - { - throw_or_mimic<argument_incorrect_type>(text); - } - - c = text[0]; -} - -template <typename T> -struct type_is_container -{ - static constexpr bool value = false; -}; - -template <typename T> -struct type_is_container<std::vector<T>> -{ - static constexpr bool value = true; -}; - -template <typename T> -class abstract_value : public Value -{ - using Self = abstract_value<T>; - -public: - abstract_value() - : m_result(std::make_shared<T>()), m_store(m_result.get()) - { - } - - abstract_value(T *t) - : m_store(t) - { - } - - virtual ~abstract_value() = default; - - abstract_value(const abstract_value &rhs) - { - if (rhs.m_result) - { - m_result = std::make_shared<T>(); - m_store = m_result.get(); - } - else - { - m_store = rhs.m_store; - } - - m_default = rhs.m_default; - m_implicit = rhs.m_implicit; - m_default_value = rhs.m_default_value; - m_implicit_value = rhs.m_implicit_value; - } - - void - parse(const std::string &text) const - { - parse_value(text, *m_store); - } - - bool - is_container() const - { - return type_is_container<T>::value; - } - - void - parse() const - { - parse_value(m_default_value, *m_store); - } - - bool - has_default() const - { - return m_default; - } - - bool - has_implicit() const - { - return m_implicit; - } - - std::shared_ptr<Value> - default_value(const std::string &value) - { - m_default = true; - m_default_value = value; - return shared_from_this(); - } - - std::shared_ptr<Value> - implicit_value(const std::string &value) - { - m_implicit = true; - m_implicit_value = value; - return shared_from_this(); - } - - std::shared_ptr<Value> - no_implicit_value() - { - m_implicit = false; - return shared_from_this(); - } - - std::string - get_default_value() const - { - return m_default_value; - } - - std::string - get_implicit_value() const - { - return m_implicit_value; - } - - bool - is_boolean() const - { - return std::is_same<T, bool>::value; - } - - const T & - get() const - { - if (m_store == nullptr) - { - return *m_result; - } - else - { - return *m_store; - } - } - -protected: - std::shared_ptr<T> m_result; - T *m_store; - - bool m_default = false; - bool m_implicit = false; - - std::string m_default_value; - std::string m_implicit_value; -}; - -template <typename T> -class standard_value : public abstract_value<T> -{ -public: - using abstract_value<T>::abstract_value; - - std::shared_ptr<Value> - clone() const - { - return std::make_shared<standard_value<T>>(*this); - } -}; - -template <> -class standard_value<bool> : public abstract_value<bool> -{ -public: - ~standard_value() = default; - - standard_value() - { - set_default_and_implicit(); - } - - standard_value(bool *b) - : abstract_value(b) - { - set_default_and_implicit(); - } - - std::shared_ptr<Value> - clone() const - { - return std::make_shared<standard_value<bool>>(*this); - } - -private: - void - set_default_and_implicit() - { - m_default = true; - m_default_value = "false"; - m_implicit = true; - m_implicit_value = "true"; - } -}; -} // namespace values - -template <typename T> -std::shared_ptr<Value> -value() -{ - return std::make_shared<values::standard_value<T>>(); -} - -template <typename T> -std::shared_ptr<Value> -value(T &t) -{ - return std::make_shared<values::standard_value<T>>(&t); -} - -class OptionAdder; - -class OptionDetails -{ -public: - OptionDetails( - const std::string &short_, - const std::string &long_, - const String &desc, - std::shared_ptr<const Value> val) - : m_short(short_), m_long(long_), m_desc(desc), m_value(val), m_count(0) - { - } - - OptionDetails(const OptionDetails &rhs) - : m_desc(rhs.m_desc), m_count(rhs.m_count) - { - m_value = rhs.m_value->clone(); - } - - OptionDetails(OptionDetails &&rhs) = default; - - const String & - description() const - { - return m_desc; - } - - const Value &value() const - { - return *m_value; - } - - std::shared_ptr<Value> - make_storage() const - { - return m_value->clone(); - } - - const std::string & - short_name() const - { - return m_short; - } - - const std::string & - long_name() const - { - return m_long; - } - -private: - std::string m_short; - std::string m_long; - String m_desc; - std::shared_ptr<const Value> m_value; - int m_count; -}; - -struct HelpOptionDetails -{ - std::string s; - std::string l; - String desc; - bool has_default; - std::string default_value; - bool has_implicit; - std::string implicit_value; - std::string arg_help; - bool is_container; - bool is_boolean; -}; - -struct HelpGroupDetails -{ - std::string name; - std::string description; - std::vector<HelpOptionDetails> options; -}; - -class OptionValue -{ -public: - void - parse( - std::shared_ptr<const OptionDetails> details, - const std::string &text) - { - ensure_value(details); - ++m_count; - m_value->parse(text); - } - - void - parse_default(std::shared_ptr<const OptionDetails> details) - { - ensure_value(details); - m_default = true; - m_value->parse(); - } - - size_t - count() const noexcept - { - return m_count; - } - - // TODO: maybe default options should count towards the number of arguments - bool - has_default() const noexcept - { - return m_default; - } - - template <typename T> - const T & - as() const - { - if (m_value == nullptr) - { - throw_or_mimic<std::domain_error>("No value"); - } - -#ifdef CXXOPTS_NO_RTTI - return static_cast<const values::standard_value<T> &>(*m_value).get(); -#else - return dynamic_cast<const values::standard_value<T> &>(*m_value).get(); -#endif - } - -private: - void - ensure_value(std::shared_ptr<const OptionDetails> details) - { - if (m_value == nullptr) - { - m_value = details->make_storage(); - } - } - - std::shared_ptr<Value> m_value; - size_t m_count = 0; - bool m_default = false; -}; - -class KeyValue -{ -public: - KeyValue(std::string key_, std::string value_) - : m_key(std::move(key_)), m_value(std::move(value_)) - { - } - - const std::string & - key() const - { - return m_key; - } - - const std::string & - value() const - { - return m_value; - } - - template <typename T> - T as() const - { - T result; - values::parse_value(m_value, result); - return result; - } - -private: - std::string m_key; - std::string m_value; -}; - -class ParseResult -{ -public: - ParseResult( - const std::shared_ptr< - std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>, - std::vector<std::string>, - bool allow_unrecognised, - int &, char **&); - - size_t - count(const std::string &o) const - { - auto iter = m_options->find(o); - if (iter == m_options->end()) - { - return 0; - } - - auto riter = m_results.find(iter->second); - - return riter->second.count(); - } - - const OptionValue & - operator[](const std::string &option) const - { - auto iter = m_options->find(option); - - if (iter == m_options->end()) - { - throw_or_mimic<option_not_present_exception>(option); - } - - auto riter = m_results.find(iter->second); - - return riter->second; - } - - const std::vector<KeyValue> & - arguments() const - { - return m_sequential; - } - -private: - void - parse(int &argc, char **&argv); - - void - add_to_option(const std::string &option, const std::string &arg); - - bool - consume_positional(std::string a); - - void - parse_option( - std::shared_ptr<OptionDetails> value, - const std::string &name, - const std::string &arg = ""); - - void - parse_default(std::shared_ptr<OptionDetails> details); - - void - checked_parse_arg( - int argc, - char *argv[], - int ¤t, - std::shared_ptr<OptionDetails> value, - const std::string &name); - - const std::shared_ptr< - std::unordered_map<std::string, std::shared_ptr<OptionDetails>>> - m_options; - std::vector<std::string> m_positional; - std::vector<std::string>::iterator m_next_positional; - std::unordered_set<std::string> m_positional_set; - std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results; - - bool m_allow_unrecognised; - - std::vector<KeyValue> m_sequential; -}; - -struct Option -{ - Option( - const std::string &opts, - const std::string &desc, - const std::shared_ptr<const Value> &value = ::cxxopts::value<bool>(), - const std::string &arg_help = "") - : opts_(opts), desc_(desc), value_(value), arg_help_(arg_help) - { - } - - std::string opts_; - std::string desc_; - std::shared_ptr<const Value> value_; - std::string arg_help_; -}; - -class Options -{ - typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>> - OptionMap; - -public: - Options(std::string program, std::string help_string = "") - : m_program(std::move(program)), m_help_string(toLocalString(std::move(help_string))), m_custom_help("[OPTION...]"), m_positional_help("positional parameters"), m_show_positional(false), m_allow_unrecognised(false), m_options(std::make_shared<OptionMap>()), m_next_positional(m_positional.end()) - { - } - - Options & - positional_help(std::string help_text) - { - m_positional_help = std::move(help_text); - return *this; - } - - Options & - custom_help(std::string help_text) - { - m_custom_help = std::move(help_text); - return *this; - } - - Options & - show_positional_help() - { - m_show_positional = true; - return *this; - } - - Options & - allow_unrecognised_options() - { - m_allow_unrecognised = true; - return *this; - } - - ParseResult - parse(int &argc, char **&argv); - - OptionAdder - add_options(std::string group = ""); - - void - add_options( - const std::string &group, - std::initializer_list<Option> options); - - void - add_option( - const std::string &group, - const Option &option); - - void - add_option( - const std::string &group, - const std::string &s, - const std::string &l, - std::string desc, - std::shared_ptr<const Value> value, - std::string arg_help); - - //parse positional arguments into the given option - void - parse_positional(std::string option); - - void - parse_positional(std::vector<std::string> options); - - void - parse_positional(std::initializer_list<std::string> options); - - template <typename Iterator> - void - parse_positional(Iterator begin, Iterator end) - { - parse_positional(std::vector<std::string>{begin, end}); - } - - std::string - help(const std::vector<std::string> &groups = {}) const; - - const std::vector<std::string> - groups() const; - - const HelpGroupDetails & - group_help(const std::string &group) const; - -private: - void - add_one_option( - const std::string &option, - std::shared_ptr<OptionDetails> details); - - String - help_one_group(const std::string &group) const; - - void - generate_group_help( - String &result, - const std::vector<std::string> &groups) const; - - void - generate_all_groups_help(String &result) const; - - std::string m_program; - String m_help_string; - std::string m_custom_help; - std::string m_positional_help; - bool m_show_positional; - bool m_allow_unrecognised; - - std::shared_ptr<OptionMap> m_options; - std::vector<std::string> m_positional; - std::vector<std::string>::iterator m_next_positional; - std::unordered_set<std::string> m_positional_set; - - //mapping from groups to help options - std::map<std::string, HelpGroupDetails> m_help; -}; - -class OptionAdder -{ -public: - OptionAdder(Options &options, std::string group) - : m_options(options), m_group(std::move(group)) - { - } - - OptionAdder & - operator()( - const std::string &opts, - const std::string &desc, - std::shared_ptr<const Value> value = ::cxxopts::value<bool>(), - std::string arg_help = ""); - -private: - Options &m_options; - std::string m_group; -}; - -namespace -{ -constexpr int OPTION_LONGEST = 30; -constexpr int OPTION_DESC_GAP = 2; - -std::basic_regex<char> option_matcher("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); - -std::basic_regex<char> option_specifier("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); - -String -format_option( - const HelpOptionDetails &o) -{ - auto &s = o.s; - auto &l = o.l; - - String result = " "; - - if (s.size() > 0) - { - result += "-" + toLocalString(s) + ","; - } - else - { - result += " "; - } - - if (l.size() > 0) - { - result += " --" + toLocalString(l); - } - - auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg"; - - if (!o.is_boolean) - { - if (o.has_implicit) - { - result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]"; - } - else - { - result += " " + arg; - } - } - - return result; -} - -String -format_description( - const HelpOptionDetails &o, - size_t start, - size_t width) -{ - auto desc = o.desc; - - if (o.has_default && (!o.is_boolean || o.default_value != "false")) - { - if (o.default_value != "") - { - desc += toLocalString(" (default: " + o.default_value + ")"); - } - else - { - desc += toLocalString(" (default: \"\")"); - } - } - - String result; - - auto current = std::begin(desc); - auto startLine = current; - auto lastSpace = current; - - auto size = size_t{}; - - while (current != std::end(desc)) - { - if (*current == ' ') - { - lastSpace = current; - } - - if (*current == '\n') - { - startLine = current + 1; - lastSpace = startLine; - } - else if (size > width) - { - if (lastSpace == startLine) - { - stringAppend(result, startLine, current + 1); - stringAppend(result, "\n"); - stringAppend(result, start, ' '); - startLine = current + 1; - lastSpace = startLine; - } - else - { - stringAppend(result, startLine, lastSpace); - stringAppend(result, "\n"); - stringAppend(result, start, ' '); - startLine = lastSpace + 1; - lastSpace = startLine; - } - size = 0; - } - else - { - ++size; - } - - ++current; - } - - //append whatever is left - stringAppend(result, startLine, current); - - return result; -} -} // namespace - -inline ParseResult::ParseResult( - const std::shared_ptr< - std::unordered_map<std::string, std::shared_ptr<OptionDetails>>> - options, - std::vector<std::string> positional, - bool allow_unrecognised, - int &argc, char **&argv) - : m_options(options), m_positional(std::move(positional)), m_next_positional(m_positional.begin()), m_allow_unrecognised(allow_unrecognised) -{ - parse(argc, argv); -} - -inline void -Options::add_options( - const std::string &group, - std::initializer_list<Option> options) -{ - OptionAdder option_adder(*this, group); - for (const auto &option : options) - { - option_adder(option.opts_, option.desc_, option.value_, option.arg_help_); - } -} - -inline OptionAdder -Options::add_options(std::string group) -{ - return OptionAdder(*this, std::move(group)); -} - -inline OptionAdder & -OptionAdder::operator()( - const std::string &opts, - const std::string &desc, - std::shared_ptr<const Value> value, - std::string arg_help) -{ - std::match_results<const char *> result; - std::regex_match(opts.c_str(), result, option_specifier); - - if (result.empty()) - { - throw_or_mimic<invalid_option_format_error>(opts); - } - - const auto &short_match = result[2]; - const auto &long_match = result[3]; - - if (!short_match.length() && !long_match.length()) - { - throw_or_mimic<invalid_option_format_error>(opts); - } - else if (long_match.length() == 1 && short_match.length()) - { - throw_or_mimic<invalid_option_format_error>(opts); - } - - auto option_names = []( - const std::sub_match<const char *> &short_, - const std::sub_match<const char *> &long_) { - if (long_.length() == 1) - { - return std::make_tuple(long_.str(), short_.str()); - } - else - { - return std::make_tuple(short_.str(), long_.str()); - } - }(short_match, long_match); - - m_options.add_option( - m_group, - std::get<0>(option_names), - std::get<1>(option_names), - desc, - value, - std::move(arg_help)); - - return *this; -} - -inline void -ParseResult::parse_default(std::shared_ptr<OptionDetails> details) -{ - m_results[details].parse_default(details); -} - -inline void -ParseResult::parse_option( - std::shared_ptr<OptionDetails> value, - const std::string & /*name*/, - const std::string &arg) -{ - auto &result = m_results[value]; - result.parse(value, arg); - - m_sequential.emplace_back(value->long_name(), arg); -} - -inline void -ParseResult::checked_parse_arg( - int argc, - char *argv[], - int ¤t, - std::shared_ptr<OptionDetails> value, - const std::string &name) -{ - if (current + 1 >= argc) - { - if (value->value().has_implicit()) - { - parse_option(value, name, value->value().get_implicit_value()); - } - else - { - throw_or_mimic<missing_argument_exception>(name); - } - } - else - { - if (value->value().has_implicit()) - { - parse_option(value, name, value->value().get_implicit_value()); - } - else - { - parse_option(value, name, argv[current + 1]); - ++current; - } - } -} - -inline void -ParseResult::add_to_option(const std::string &option, const std::string &arg) -{ - auto iter = m_options->find(option); - - if (iter == m_options->end()) - { - throw_or_mimic<option_not_exists_exception>(option); - } - - parse_option(iter->second, option, arg); -} - -inline bool -ParseResult::consume_positional(std::string a) -{ - while (m_next_positional != m_positional.end()) - { - auto iter = m_options->find(*m_next_positional); - if (iter != m_options->end()) - { - auto &result = m_results[iter->second]; - if (!iter->second->value().is_container()) - { - if (result.count() == 0) - { - add_to_option(*m_next_positional, a); - ++m_next_positional; - return true; - } - else - { - ++m_next_positional; - continue; - } - } - else - { - add_to_option(*m_next_positional, a); - return true; - } - } - else - { - throw_or_mimic<option_not_exists_exception>(*m_next_positional); - } - } - - return false; -} - -inline void -Options::parse_positional(std::string option) -{ - parse_positional(std::vector<std::string>{std::move(option)}); -} - -inline void -Options::parse_positional(std::vector<std::string> options) -{ - m_positional = std::move(options); - m_next_positional = m_positional.begin(); - - m_positional_set.insert(m_positional.begin(), m_positional.end()); -} - -inline void -Options::parse_positional(std::initializer_list<std::string> options) -{ - parse_positional(std::vector<std::string>(std::move(options))); -} - -inline ParseResult -Options::parse(int &argc, char **&argv) -{ - ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); - return result; -} - -inline void -ParseResult::parse(int &argc, char **&argv) -{ - int current = 1; - - int nextKeep = 1; - - bool consume_remaining = false; - - while (current != argc) - { - if (strcmp(argv[current], "--") == 0) - { - consume_remaining = true; - ++current; - break; - } - - std::match_results<const char *> result; - std::regex_match(argv[current], result, option_matcher); - - if (result.empty()) - { - //not a flag - - // but if it starts with a `-`, then it's an error - if (argv[current][0] == '-' && argv[current][1] != '\0') - { - if (!m_allow_unrecognised) - { - throw_or_mimic<option_syntax_exception>(argv[current]); - } - } - - //if true is returned here then it was consumed, otherwise it is - //ignored - if (consume_positional(argv[current])) - { - } - else - { - argv[nextKeep] = argv[current]; - ++nextKeep; - } - //if we return from here then it was parsed successfully, so continue - } - else - { - //short or long option? - if (result[4].length() != 0) - { - const std::string &s = result[4]; - - for (std::size_t i = 0; i != s.size(); ++i) - { - std::string name(1, s[i]); - auto iter = m_options->find(name); - - if (iter == m_options->end()) - { - if (m_allow_unrecognised) - { - continue; - } - else - { - //error - throw_or_mimic<option_not_exists_exception>(name); - } - } - - auto value = iter->second; - - if (i + 1 == s.size()) - { - //it must be the last argument - checked_parse_arg(argc, argv, current, value, name); - } - else if (value->value().has_implicit()) - { - parse_option(value, name, value->value().get_implicit_value()); - } - else - { - //error - throw_or_mimic<option_requires_argument_exception>(name); - } - } - } - else if (result[1].length() != 0) - { - const std::string &name = result[1]; - - auto iter = m_options->find(name); - - if (iter == m_options->end()) - { - if (m_allow_unrecognised) - { - // keep unrecognised options in argument list, skip to next argument - argv[nextKeep] = argv[current]; - ++nextKeep; - ++current; - continue; - } - else - { - //error - throw_or_mimic<option_not_exists_exception>(name); - } - } - - auto opt = iter->second; - - //equals provided for long option? - if (result[2].length() != 0) - { - //parse the option given - - parse_option(opt, name, result[3]); - } - else - { - //parse the next argument - checked_parse_arg(argc, argv, current, opt, name); - } - } - } - - ++current; - } - - for (auto &opt : *m_options) - { - auto &detail = opt.second; - auto &value = detail->value(); - - auto &store = m_results[detail]; - - if (value.has_default() && !store.count() && !store.has_default()) - { - parse_default(detail); - } - } - - if (consume_remaining) - { - while (current < argc) - { - if (!consume_positional(argv[current])) - { - break; - } - ++current; - } - - //adjust argv for any that couldn't be swallowed - while (current != argc) - { - argv[nextKeep] = argv[current]; - ++nextKeep; - ++current; - } - } - - argc = nextKeep; -} - -inline void -Options::add_option( - const std::string &group, - const Option &option) -{ - add_options(group, {option}); -} - -inline void -Options::add_option( - const std::string &group, - const std::string &s, - const std::string &l, - std::string desc, - std::shared_ptr<const Value> value, - std::string arg_help) -{ - auto stringDesc = toLocalString(std::move(desc)); - auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value); - - if (s.size() > 0) - { - add_one_option(s, option); - } - - if (l.size() > 0) - { - add_one_option(l, option); - } - - //add the help details - auto &options = m_help[group]; - - options.options.emplace_back(HelpOptionDetails{s, l, stringDesc, - value->has_default(), value->get_default_value(), - value->has_implicit(), value->get_implicit_value(), - std::move(arg_help), - value->is_container(), - value->is_boolean()}); -} - -inline void -Options::add_one_option( - const std::string &option, - std::shared_ptr<OptionDetails> details) -{ - auto in = m_options->emplace(option, details); - - if (!in.second) - { - throw_or_mimic<option_exists_error>(option); - } -} - -inline String -Options::help_one_group(const std::string &g) const -{ - typedef std::vector<std::pair<String, String>> OptionHelp; - - auto group = m_help.find(g); - if (group == m_help.end()) - { - return ""; - } - - OptionHelp format; - - size_t longest = 0; - - String result; - - if (!g.empty()) - { - result += toLocalString(" " + g + " options:\n"); - } - - for (const auto &o : group->second.options) - { - if (m_positional_set.find(o.l) != m_positional_set.end() && - !m_show_positional) - { - continue; - } - - auto s = format_option(o); - longest = (std::max)(longest, stringLength(s)); - format.push_back(std::make_pair(s, String())); - } - - longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST)); - - //widest allowed description - auto allowed = size_t{76} - longest - OPTION_DESC_GAP; - - auto fiter = format.begin(); - for (const auto &o : group->second.options) - { - if (m_positional_set.find(o.l) != m_positional_set.end() && - !m_show_positional) - { - continue; - } - - auto d = format_description(o, longest + OPTION_DESC_GAP, allowed); - - result += fiter->first; - if (stringLength(fiter->first) > longest) - { - result += '\n'; - result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' ')); - } - else - { - result += toLocalString(std::string(longest + OPTION_DESC_GAP - - stringLength(fiter->first), - ' ')); - } - result += d; - result += '\n'; - - ++fiter; - } - - return result; -} - -inline void -Options::generate_group_help( - String &result, - const std::vector<std::string> &print_groups) const -{ - for (size_t i = 0; i != print_groups.size(); ++i) - { - const String &group_help_text = help_one_group(print_groups[i]); - if (empty(group_help_text)) - { - continue; - } - result += group_help_text; - if (i < print_groups.size() - 1) - { - result += '\n'; - } - } -} - -inline void -Options::generate_all_groups_help(String &result) const -{ - std::vector<std::string> all_groups; - all_groups.reserve(m_help.size()); - - for (auto &group : m_help) - { - all_groups.push_back(group.first); - } - - generate_group_help(result, all_groups); -} - -inline std::string -Options::help(const std::vector<std::string> &help_groups) const -{ - String result = m_help_string + "\nUsage:\n " + - toLocalString(m_program) + " " + toLocalString(m_custom_help); - - if (m_positional.size() > 0 && m_positional_help.size() > 0) - { - result += " " + toLocalString(m_positional_help); - } - - result += "\n\n"; - - if (help_groups.size() == 0) - { - generate_all_groups_help(result); - } - else - { - generate_group_help(result, help_groups); - } - - return toUTF8String(result); -} - -inline const std::vector<std::string> -Options::groups() const -{ - std::vector<std::string> g; - - std::transform( - m_help.begin(), - m_help.end(), - std::back_inserter(g), - [](const std::map<std::string, HelpGroupDetails>::value_type &pair) { - return pair.first; - }); - - return g; -} - -inline const HelpGroupDetails & -Options::group_help(const std::string &group) const -{ - return m_help.at(group); -} - -} // namespace cxxopts - -#endif //CXXOPTS_HPP_INCLUDED
\ No newline at end of file diff --git a/src/sha256/picosha2.h b/src/sha256/picosha2.h deleted file mode 100644 index 6bfe2d0..0000000 --- a/src/sha256/picosha2.h +++ /dev/null @@ -1,376 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (C) 2017 okdshin - -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 PICOSHA2_H -#define PICOSHA2_H -// picosha2:20140213 - -#ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR -#define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \ - 1048576 //=1024*1024: default is 1MB memory -#endif - -#include <algorithm> -#include <cassert> -#include <fstream> -#include <iterator> -#include <sstream> -#include <vector> -namespace picosha2 { -typedef unsigned long word_t; -typedef unsigned char byte_t; - -static const size_t k_digest_size = 32; - -namespace detail { -inline byte_t mask_8bit(byte_t x) { return x & 0xff; } - -inline word_t mask_32bit(word_t x) { return x & 0xffffffff; } - -const word_t add_constant[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, - 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, - 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, - 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, - 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, - 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; - -const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, - 0xa54ff53a, 0x510e527f, 0x9b05688c, - 0x1f83d9ab, 0x5be0cd19}; - -inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); } - -inline word_t maj(word_t x, word_t y, word_t z) { - return (x & y) ^ (x & z) ^ (y & z); -} - -inline word_t rotr(word_t x, std::size_t n) { - assert(n < 32); - return mask_32bit((x >> n) | (x << (32 - n))); -} - -inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); } - -inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); } - -inline word_t shr(word_t x, std::size_t n) { - assert(n < 32); - return x >> n; -} - -inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); } - -inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); } - -template <typename RaIter1, typename RaIter2> -void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) { - assert(first + 64 == last); - static_cast<void>(last); // for avoiding unused-variable warning - word_t w[64]; - std::fill(w, w + 64, 0); - for (std::size_t i = 0; i < 16; ++i) { - w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) | - (static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) | - (static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) | - (static_cast<word_t>(mask_8bit(*(first + i * 4 + 3)))); - } - for (std::size_t i = 16; i < 64; ++i) { - w[i] = - mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) + w[i - 16]); - } - - word_t a = *message_digest; - word_t b = *(message_digest + 1); - word_t c = *(message_digest + 2); - word_t d = *(message_digest + 3); - word_t e = *(message_digest + 4); - word_t f = *(message_digest + 5); - word_t g = *(message_digest + 6); - word_t h = *(message_digest + 7); - - for (std::size_t i = 0; i < 64; ++i) { - word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i]; - word_t temp2 = bsig0(a) + maj(a, b, c); - h = g; - g = f; - f = e; - e = mask_32bit(d + temp1); - d = c; - c = b; - b = a; - a = mask_32bit(temp1 + temp2); - } - *message_digest += a; - *(message_digest + 1) += b; - *(message_digest + 2) += c; - *(message_digest + 3) += d; - *(message_digest + 4) += e; - *(message_digest + 5) += f; - *(message_digest + 6) += g; - *(message_digest + 7) += h; - for (std::size_t i = 0; i < 8; ++i) { - *(message_digest + i) = mask_32bit(*(message_digest + i)); - } -} - -} // namespace detail - -template <typename InIter> -void output_hex(InIter first, InIter last, std::ostream &os) { - os.setf(std::ios::hex, std::ios::basefield); - while (first != last) { - os.width(2); - os.fill('0'); - os << static_cast<unsigned int>(*first); - ++first; - } - os.setf(std::ios::dec, std::ios::basefield); -} - -template <typename InIter> -void bytes_to_hex_string(InIter first, InIter last, std::string &hex_str) { - std::ostringstream oss; - output_hex(first, last, oss); - hex_str.assign(oss.str()); -} - -template <typename InContainer> -void bytes_to_hex_string(const InContainer &bytes, std::string &hex_str) { - bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str); -} - -template <typename InIter> -std::string bytes_to_hex_string(InIter first, InIter last) { - std::string hex_str; - bytes_to_hex_string(first, last, hex_str); - return hex_str; -} - -template <typename InContainer> -std::string bytes_to_hex_string(const InContainer &bytes) { - std::string hex_str; - bytes_to_hex_string(bytes, hex_str); - return hex_str; -} - -class hash256_one_by_one { -public: - hash256_one_by_one() { init(); } - - void init() { - buffer_.clear(); - std::fill(data_length_digits_, data_length_digits_ + 4, 0); - std::copy(detail::initial_message_digest, - detail::initial_message_digest + 8, h_); - } - - template <typename RaIter> void process(RaIter first, RaIter last) { - add_to_data_length(static_cast<word_t>(std::distance(first, last))); - std::copy(first, last, std::back_inserter(buffer_)); - std::size_t i = 0; - for (; i + 64 <= buffer_.size(); i += 64) { - detail::hash256_block(h_, buffer_.begin() + i, buffer_.begin() + i + 64); - } - buffer_.erase(buffer_.begin(), buffer_.begin() + i); - } - - void finish() { - byte_t temp[64]; - std::fill(temp, temp + 64, 0); - std::size_t remains = buffer_.size(); - std::copy(buffer_.begin(), buffer_.end(), temp); - temp[remains] = 0x80; - - if (remains > 55) { - std::fill(temp + remains + 1, temp + 64, 0); - detail::hash256_block(h_, temp, temp + 64); - std::fill(temp, temp + 64 - 4, 0); - } else { - std::fill(temp + remains + 1, temp + 64 - 4, 0); - } - - write_data_bit_length(&(temp[56])); - detail::hash256_block(h_, temp, temp + 64); - } - - template <typename OutIter> - void get_hash_bytes(OutIter first, OutIter last) const { - for (const word_t *iter = h_; iter != h_ + 8; ++iter) { - for (std::size_t i = 0; i < 4 && first != last; ++i) { - *(first++) = - detail::mask_8bit(static_cast<byte_t>((*iter >> (24 - 8 * i)))); - } - } - } - -private: - void add_to_data_length(word_t n) { - word_t carry = 0; - data_length_digits_[0] += n; - for (std::size_t i = 0; i < 4; ++i) { - data_length_digits_[i] += carry; - if (data_length_digits_[i] >= 65536u) { - carry = data_length_digits_[i] >> 16; - data_length_digits_[i] &= 65535u; - } else { - break; - } - } - } - void write_data_bit_length(byte_t *begin) { - word_t data_bit_length_digits[4]; - std::copy(data_length_digits_, data_length_digits_ + 4, - data_bit_length_digits); - - // convert byte length to bit length (multiply 8 or shift 3 times left) - word_t carry = 0; - for (std::size_t i = 0; i < 4; ++i) { - word_t before_val = data_bit_length_digits[i]; - data_bit_length_digits[i] <<= 3; - data_bit_length_digits[i] |= carry; - data_bit_length_digits[i] &= 65535u; - carry = (before_val >> (16 - 3)) & 65535u; - } - - // write data_bit_length - for (int i = 3; i >= 0; --i) { - (*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8); - (*begin++) = static_cast<byte_t>(data_bit_length_digits[i]); - } - } - std::vector<byte_t> buffer_; - word_t data_length_digits_[4]; // as 64bit integer (16bit x 4 integer) - word_t h_[8]; -}; - -inline void get_hash_hex_string(const hash256_one_by_one &hasher, - std::string &hex_str) { - byte_t hash[k_digest_size]; - hasher.get_hash_bytes(hash, hash + k_digest_size); - return bytes_to_hex_string(hash, hash + k_digest_size, hex_str); -} - -inline std::string get_hash_hex_string(const hash256_one_by_one &hasher) { - std::string hex_str; - get_hash_hex_string(hasher, hex_str); - return hex_str; -} - -namespace impl { -template <typename RaIter, typename OutIter> -void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int, - std::random_access_iterator_tag) { - hash256_one_by_one hasher; - // hasher.init(); - hasher.process(first, last); - hasher.finish(); - hasher.get_hash_bytes(first2, last2); -} - -template <typename InputIter, typename OutIter> -void hash256_impl(InputIter first, InputIter last, OutIter first2, - OutIter last2, int buffer_size, std::input_iterator_tag) { - std::vector<byte_t> buffer(buffer_size); - hash256_one_by_one hasher; - // hasher.init(); - while (first != last) { - int size = buffer_size; - for (int i = 0; i != buffer_size; ++i, ++first) { - if (first == last) { - size = i; - break; - } - buffer[i] = *first; - } - hasher.process(buffer.begin(), buffer.begin() + size); - } - hasher.finish(); - hasher.get_hash_bytes(first2, last2); -} -} // namespace impl - -template <typename InIter, typename OutIter> -void hash256(InIter first, InIter last, OutIter first2, OutIter last2, - int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) { - picosha2::impl::hash256_impl( - first, last, first2, last2, buffer_size, - typename std::iterator_traits<InIter>::iterator_category()); -} - -template <typename InIter, typename OutContainer> -void hash256(InIter first, InIter last, OutContainer &dst) { - hash256(first, last, dst.begin(), dst.end()); -} - -template <typename InContainer, typename OutIter> -void hash256(const InContainer &src, OutIter first, OutIter last) { - hash256(src.begin(), src.end(), first, last); -} - -template <typename InContainer, typename OutContainer> -void hash256(const InContainer &src, OutContainer &dst) { - hash256(src.begin(), src.end(), dst.begin(), dst.end()); -} - -template <typename InIter> -void hash256_hex_string(InIter first, InIter last, std::string &hex_str) { - byte_t hashed[k_digest_size]; - hash256(first, last, hashed, hashed + k_digest_size); - std::ostringstream oss; - output_hex(hashed, hashed + k_digest_size, oss); - hex_str.assign(oss.str()); -} - -template <typename InIter> -std::string hash256_hex_string(InIter first, InIter last) { - std::string hex_str; - hash256_hex_string(first, last, hex_str); - return hex_str; -} - -inline void hash256_hex_string(const std::string &src, std::string &hex_str) { - hash256_hex_string(src.begin(), src.end(), hex_str); -} - -template <typename InContainer> -void hash256_hex_string(const InContainer &src, std::string &hex_str) { - hash256_hex_string(src.begin(), src.end(), hex_str); -} - -template <typename InContainer> -std::string hash256_hex_string(const InContainer &src) { - return hash256_hex_string(src.begin(), src.end()); -} -template <typename OutIter> -void hash256(std::ifstream &f, OutIter first, OutIter last) { - hash256(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), - first, last); -} -} // namespace picosha2 -#endif // PICOSHA2_H
\ No newline at end of file |