diff --git a/cmake-build-reldebug-asan/.ninja_deps b/cmake-build-reldebug-asan/.ninja_deps index 14ff182..1d50419 100644 Binary files a/cmake-build-reldebug-asan/.ninja_deps and b/cmake-build-reldebug-asan/.ninja_deps differ diff --git a/cmake-build-reldebug-asan/build.ninja b/cmake-build-reldebug-asan/build.ninja index bcc57b6..a56fb89 100644 --- a/cmake-build-reldebug-asan/build.ninja +++ b/cmake-build-reldebug-asan/build.ninja @@ -119,13 +119,6 @@ build CMakeFiles/BLT.dir/src/blt/parse/argparse.cpp.o: CXX_COMPILER__BLT_unscann OBJECT_DIR = CMakeFiles/BLT.dir OBJECT_FILE_DIR = CMakeFiles/BLT.dir/src/blt/parse -build CMakeFiles/BLT.dir/src/blt/parse/argparse_2.cpp.o: CXX_COMPILER__BLT_unscanned_RelWithDebInfo /home/brett/Documents/code/c++/BLT/src/blt/parse/argparse_2.cpp || cmake_object_order_depends_target_BLT - DEP_FILE = CMakeFiles/BLT.dir/src/blt/parse/argparse_2.cpp.o.d - FLAGS = -O2 -g -DNDEBUG -std=gnu++20 -fdiagnostics-color=always -Wall -Wextra -Wpedantic - INCLUDES = -I/home/brett/Documents/code/c++/BLT/libraries/parallel-hashmap -I/home/brett/Documents/code/c++/BLT/include -I/home/brett/Documents/code/c++/BLT/cmake-build-reldebug-asan/config - OBJECT_DIR = CMakeFiles/BLT.dir - OBJECT_FILE_DIR = CMakeFiles/BLT.dir/src/blt/parse - # ============================================================================= # Link build statements for STATIC_LIBRARY target BLT @@ -134,7 +127,7 @@ build CMakeFiles/BLT.dir/src/blt/parse/argparse_2.cpp.o: CXX_COMPILER__BLT_unsca ############################################# # Link the static library libBLT.a -build libBLT.a: CXX_STATIC_LIBRARY_LINKER__BLT_RelWithDebInfo CMakeFiles/BLT.dir/src/blt/std/filesystem.cpp.o CMakeFiles/BLT.dir/src/blt/std/format.cpp.o CMakeFiles/BLT.dir/src/blt/std/loader.cpp.o CMakeFiles/BLT.dir/src/blt/std/logging.cpp.o CMakeFiles/BLT.dir/src/blt/std/string.cpp.o CMakeFiles/BLT.dir/src/blt/std/system.cpp.o CMakeFiles/BLT.dir/src/blt/profiling/profiler.cpp.o CMakeFiles/BLT.dir/src/blt/nbt/nbt.cpp.o CMakeFiles/BLT.dir/src/blt/nbt/nbt_block.cpp.o CMakeFiles/BLT.dir/src/blt/parse/argparse.cpp.o CMakeFiles/BLT.dir/src/blt/parse/argparse_2.cpp.o +build libBLT.a: CXX_STATIC_LIBRARY_LINKER__BLT_RelWithDebInfo CMakeFiles/BLT.dir/src/blt/std/filesystem.cpp.o CMakeFiles/BLT.dir/src/blt/std/format.cpp.o CMakeFiles/BLT.dir/src/blt/std/loader.cpp.o CMakeFiles/BLT.dir/src/blt/std/logging.cpp.o CMakeFiles/BLT.dir/src/blt/std/string.cpp.o CMakeFiles/BLT.dir/src/blt/std/system.cpp.o CMakeFiles/BLT.dir/src/blt/profiling/profiler.cpp.o CMakeFiles/BLT.dir/src/blt/nbt/nbt.cpp.o CMakeFiles/BLT.dir/src/blt/nbt/nbt_block.cpp.o CMakeFiles/BLT.dir/src/blt/parse/argparse.cpp.o LANGUAGE_COMPILE_FLAGS = -O2 -g -DNDEBUG OBJECT_DIR = CMakeFiles/BLT.dir POST_BUILD = : diff --git a/include/blt/parse/argparse.h b/include/blt/parse/argparse.h index 6b49797..b49ae82 100644 --- a/include/blt/parse/argparse.h +++ b/include/blt/parse/argparse.h @@ -1,5 +1,5 @@ /* - * Created by Brett on 28/07/23. + * Created by Brett on 06/08/23. * Licensed under GNU General Public License V3.0 * See LICENSE file for license detail */ @@ -7,17 +7,22 @@ #ifndef BLT_TESTS_ARGPARSE_H #define BLT_TESTS_ARGPARSE_H +#include #include #include #include #include #include #include -#include -namespace blt::parser { +namespace blt +{ + typedef std::variant arg_data_internal_t; + typedef std::vector arg_data_vec_t; + typedef std::variant arg_data_t; - enum class arg_action_t { + enum class arg_action_t + { STORE, STORE_CONST, STORE_TRUE, @@ -30,73 +35,50 @@ namespace blt::parser { EXTEND }; - enum class arg_result_t { - BOOL, - VALUE, - VECTOR - }; - - class arg_vector_t { - private: - std::vector names; - std::vector flags; - bool isFlags = false; - - void insertAndSort(const std::string& str); - public: - arg_vector_t() = default; - - arg_vector_t(const std::vector& args); - - arg_vector_t(std::initializer_list args); - - arg_vector_t(const std::string& arg); - - arg_vector_t(const char* arg); - - arg_vector_t& operator=(const std::string& arg); - - arg_vector_t& operator=(const char* arg); - - arg_vector_t& operator=(std::initializer_list& args); - - arg_vector_t& operator=(std::vector& args); - - [[nodiscard]] inline std::vector& getNames() { - return names; - } - - [[nodiscard]] inline std::vector& getFlags() { - return flags; - } - - [[nodiscard]] inline const std::vector& getNames() const { - return names; - } - - [[nodiscard]] inline const std::vector& getFlags() const { - return flags; - } - - /** - * @return true if contains flags - */ - [[nodiscard]] inline bool isFlag() const { - return isFlags; - } - - [[nodiscard]] inline bool contains(std::string_view string) const { - return std::any_of(flags.begin(), flags.end(), [&string](const auto& flag) -> bool { - return flag == string; - }) || std::any_of(names.begin(), names.end(), [&string](const auto& name) -> bool { - return name == string; - }); - } - }; - - class arg_nargs_t { - private: + class arg_vector_t + { friend class arg_parse; + + private: + std::vector flags; + std::string name; + + void validateFlags(); + + public: + arg_vector_t(std::vector flags): flags(std::move(flags)) + { + validateFlags(); + } + + arg_vector_t(std::initializer_list flags): flags(flags) + { + validateFlags(); + } + + arg_vector_t(const char* str); + arg_vector_t(const std::string& str); + + [[nodiscard]] inline bool isFlag() const + { + return !flags.empty(); + } + + [[nodiscard]] inline bool contains(const std::string& str) + { + return std::any_of( + flags.begin(), flags.end(), [&str](const std::string& flag) -> bool { + return flag == str; + } + ) || str == name; + } + }; + + class arg_nargs_t + { + friend class arg_parse; + + private: static constexpr int UNKNOWN = 0x1; static constexpr int ALL = 0x2; static constexpr int ALL_REQUIRED = 0x4; @@ -110,182 +92,239 @@ namespace blt::parser { public: arg_nargs_t() = default; - arg_nargs_t(int args): args(args) {} + arg_nargs_t(int args): args(args) + {} arg_nargs_t(char c); arg_nargs_t(std::string s); arg_nargs_t(const char* s); - - arg_nargs_t& operator=(const std::string& s); - - arg_nargs_t& operator=(const char* s); - - arg_nargs_t& operator=(char c); - - arg_nargs_t& operator=(int args); }; - struct arg_properties_t { + struct arg_properties_t + { private: public: arg_vector_t a_flags; arg_action_t a_action = arg_action_t::STORE; arg_nargs_t a_nargs = 1; std::string a_const{}; - std::string a_default{}; + arg_data_internal_t a_default{}; std::string a_dest{}; std::string a_help{}; std::string a_version{}; std::string a_metavar{}; - bool a_required = false; + bool a_required = true; }; - class arg_builder { + class arg_builder + { arg_properties_t properties; public: - arg_builder(const arg_vector_t& flags): properties(flags) {} + arg_builder(const arg_vector_t& flags): properties(flags) + {} - inline arg_properties_t build() { + inline arg_properties_t build() + { return properties; } - inline arg_builder& setAction(arg_action_t action){ + inline arg_builder& setAction(arg_action_t action) + { properties.a_action = action; return *this; } - inline arg_builder& setNArgs(const arg_nargs_t& nargs){ + inline arg_builder& setNArgs(const arg_nargs_t& nargs) + { properties.a_nargs = nargs; return *this; } - inline arg_builder& setConst(const std::string& a_const){ + inline arg_builder& setConst(const std::string& a_const) + { properties.a_const = a_const; return *this; } - inline arg_builder& setDefault(const std::string& def){ + inline arg_builder& setDefault(const arg_data_internal_t& def) + { properties.a_default = def; return *this; } - inline arg_builder& setDest(const std::string& dest){ + inline arg_builder& setDest(const std::string& dest) + { properties.a_dest = dest; return *this; } - inline arg_builder& setHelp(const std::string& help){ + inline arg_builder& setHelp(const std::string& help) + { properties.a_help = help; return *this; } - inline arg_builder& setVersion(const std::string& version){ + inline arg_builder& setVersion(const std::string& version) + { properties.a_version = version; return *this; } - inline arg_builder& setMetavar(const std::string& metavar){ + inline arg_builder& setMetavar(const std::string& metavar) + { properties.a_metavar = metavar; return *this; } - inline arg_builder& setRequired(){ + inline arg_builder& setRequired() + { properties.a_required = true; return *this; } - - }; - - class arg_tokenizer_t { - private: - static constexpr char FLAG = '-'; - std::vector args; - size_t nextIndex = 0; - - inline const std::string& get(size_t i) { - return args[i]; - } - - inline bool hasNext(size_t i) { - return (size_t) i < args.size(); - } + }; + + class arg_tokenizer + { + private: + std::vector args; + size_t currentIndex = 0; public: - arg_tokenizer_t() = default; + arg_tokenizer(std::vector args): args(std::move(args)) + {} - arg_tokenizer_t(size_t argc, const char** argv); - - inline void forward() { - nextIndex++; + // returns the current arg + inline const std::string& get() + { + return args[currentIndex]; } - inline const std::string& get() { - return get(nextIndex); + // returns if we have next arg to process + inline bool hasNext() + { + return currentIndex + 1 < args.size(); } - inline const std::string& next() { - return get(nextIndex++); + inline bool hasCurrent() + { + return currentIndex < args.size(); } - inline bool hasNext() { - return hasNext(nextIndex); + // returns true if the current arg is a flag + inline bool isFlag() + { + return args[currentIndex].starts_with('-'); } - inline bool isFlag(size_t i) { - return get(i).starts_with(FLAG); + // returns true if we have next and the next arg is a flag + inline bool isNextFlag() + { + return hasNext() && args[currentIndex + 1].starts_with('-'); } - inline bool isFlag() { - return isFlag(nextIndex); + // advances to the next flag + inline size_t advance() + { + return currentIndex++; } }; - class arg_parse { - public: - typedef std::variant> arg_data_t; + class arg_parse + { private: - struct { + struct + { friend arg_parse; private: - std::vector arg_storage; + std::vector arg_properties_storage; public: - std::vector> name_associations; + std::vector name_associations; HASHMAP flag_associations; - HASHSET required_vars; } user_args; - struct arg_results { + struct arg_results + { friend arg_parse; private: - HASHSET found_required; + // stores dest value not the flag/name! + HASHSET found_args; std::vector unrecognized_args; public: std::string program_name; - HASHMAP positional_args; - HASHMAP flag_args; + HASHMAP data; + + inline arg_data_t& operator[](const std::string& key) + { + return data[key]; + } + + inline auto begin() + { + return data.begin(); + } + + inline auto end() + { + return data.end(); + } + + inline bool contains(const std::string& key) + { + return data.find(key) != data.end(); + } } loaded_args; + private: static std::string filename(const std::string& path); - static bool validateArgument(const arg_properties_t& args); - static bool consumeArguments(arg_tokenizer_t& arg_tokenizer, const arg_properties_t& properties, std::vector& v_out); - void handlePositionalArgument(arg_tokenizer_t& arg_tokenizer, size_t& last_pos); - void handleFlagArgument(arg_tokenizer_t& arg_tokenizer); - void processFlag(arg_tokenizer_t& arg_tokenizer, const std::string& flag); + + // expects that the current flag has already been consumed (advanced past), leaves tokenizer in a state where the next element is 'current' + static bool consumeArguments(arg_tokenizer& tokenizer, const arg_properties_t& properties, std::vector& v_out); + + void handlePositionalArgument(arg_tokenizer& tokenizer, size_t& last_pos); + + void handleFlagArgument(arg_tokenizer& tokenizer); + + void processFlag(arg_tokenizer& tokenizer, const std::string& flag); + + template + static inline bool holds_alternative(const arg_data_t& v){ + if constexpr (std::is_same_v) + return std::holds_alternative(v); + else + return std::holds_alternative(v) && std::holds_alternative(std::get(v)); + } + template + static inline T& get(arg_data_t& v){ + if constexpr (std::is_same_v) + return std::get(v); + else + return std::get(std::get(v)); + } public: - arg_parse() { - //addArgument(arg_builder({"--help", "-h"}).setAction(arg_action_t::HELP).setHelp("Show this help menu").build()); + arg_parse() + { + addArgument(arg_builder({"--help", "-h"}).setAction(arg_action_t::HELP).setHelp("Show this help menu").build()); }; void addArgument(const arg_properties_t& args); - const arg_results& parse_args(int argc, const char** argv); + arg_results parse_args(int argc, const char** argv); + + arg_results parse_args(const std::vector& args); void printHelp(); + + ~arg_parse() + { + for (auto* p : user_args.arg_properties_storage) + delete p; + } }; - std::string to_string(const blt::parser::arg_parse::arg_data_t& v); + std::string to_string(const blt::arg_data_t& v); + std::string to_string(const blt::arg_data_internal_t& v); } diff --git a/include/blt/parse/argparse_2.h b/include/blt/parse/argparse_2.h deleted file mode 100644 index c469bb6..0000000 --- a/include/blt/parse/argparse_2.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Created by Brett on 06/08/23. - * Licensed under GNU General Public License V3.0 - * See LICENSE file for license detail - */ - -#ifndef BLT_TESTS_ARGPARSE_2_H -#define BLT_TESTS_ARGPARSE_2_H - -#include -#include -#include -#include -#include -#include -#include - -namespace blt -{ - typedef std::variant arg_data_internal_t; - typedef std::vector arg_data_vec_t; - typedef std::variant arg_data_t; - - enum class arg_action_t - { - STORE, - STORE_CONST, - STORE_TRUE, - STORE_FALSE, - APPEND, - APPEND_CONST, - COUNT, - HELP, - VERSION, - EXTEND - }; - - class arg_vector_t - { - friend class arg_parse; - - private: - std::vector flags; - std::string name; - - void validateFlags(); - - public: - arg_vector_t(std::vector flags): flags(std::move(flags)) - { - validateFlags(); - } - - arg_vector_t(std::initializer_list flags): flags(flags) - { - validateFlags(); - } - - arg_vector_t(const char* str); - arg_vector_t(const std::string& str); - - [[nodiscard]] inline bool isFlag() const - { - return !flags.empty(); - } - - [[nodiscard]] inline bool contains(const std::string& str) - { - return std::any_of( - flags.begin(), flags.end(), [&str](const std::string& flag) -> bool { - return flag == str; - } - ) || str == name; - } - }; - - class arg_nargs_t - { - friend class arg_parse; - - private: - static constexpr int UNKNOWN = 0x1; - static constexpr int ALL = 0x2; - static constexpr int ALL_REQUIRED = 0x4; - // 0 means ignore - int args = 1; - // 0 indicates args is used - int flags = 0; - - void decode(char c); - - public: - arg_nargs_t() = default; - - arg_nargs_t(int args): args(args) - {} - - arg_nargs_t(char c); - - arg_nargs_t(std::string s); - - arg_nargs_t(const char* s); - }; - - struct arg_properties_t - { - private: - public: - arg_vector_t a_flags; - arg_action_t a_action = arg_action_t::STORE; - arg_nargs_t a_nargs = 1; - std::string a_const{}; - arg_data_internal_t a_default{}; - std::string a_dest{}; - std::string a_help{}; - std::string a_version{}; - std::string a_metavar{}; - bool a_required = true; - }; - - class arg_builder - { - arg_properties_t properties; - public: - arg_builder(const arg_vector_t& flags): properties(flags) - {} - - inline arg_properties_t build() - { - return properties; - } - - inline arg_builder& setAction(arg_action_t action) - { - properties.a_action = action; - return *this; - } - - inline arg_builder& setNArgs(const arg_nargs_t& nargs) - { - properties.a_nargs = nargs; - return *this; - } - - inline arg_builder& setConst(const std::string& a_const) - { - properties.a_const = a_const; - return *this; - } - - inline arg_builder& setDefault(const arg_data_internal_t& def) - { - properties.a_default = def; - return *this; - } - - inline arg_builder& setDest(const std::string& dest) - { - properties.a_dest = dest; - return *this; - } - - inline arg_builder& setHelp(const std::string& help) - { - properties.a_help = help; - return *this; - } - - inline arg_builder& setVersion(const std::string& version) - { - properties.a_version = version; - return *this; - } - - inline arg_builder& setMetavar(const std::string& metavar) - { - properties.a_metavar = metavar; - return *this; - } - - inline arg_builder& setRequired() - { - properties.a_required = true; - return *this; - } - - }; - - class arg_tokenizer - { - private: - std::vector args; - size_t currentIndex = 0; - public: - arg_tokenizer(std::vector args): args(std::move(args)) - {} - - // returns the current arg - inline const std::string& get() - { - return args[currentIndex]; - } - - // returns if we have next arg to process - inline bool hasNext() - { - return currentIndex + 1 < args.size(); - } - - inline bool hasCurrent() - { - return currentIndex < args.size(); - } - - // returns true if the current arg is a flag - inline bool isFlag() - { - return args[currentIndex].starts_with('-'); - } - - // returns true if we have next and the next arg is a flag - inline bool isNextFlag() - { - return hasNext() && args[currentIndex + 1].starts_with('-'); - } - - // advances to the next flag - inline size_t advance() - { - return currentIndex++; - } - }; - - class arg_parse - { - private: - struct - { - friend arg_parse; - private: - std::vector arg_properties_storage; - public: - std::vector name_associations; - HASHMAP flag_associations; - } user_args; - - struct arg_results - { - friend arg_parse; - private: - HASHSET found_args; - std::vector unrecognized_args; - public: - std::string program_name; - HASHMAP data; - - inline arg_data_t& operator[](const std::string& key) - { - return data[key]; - } - - inline auto begin() - { - return data.begin(); - } - - inline auto end() - { - return data.end(); - } - - inline bool contains(const std::string& key) - { - return data.find(key) != data.end(); - } - } loaded_args; - - private: - static std::string filename(const std::string& path); - - // expects that the current flag has already been consumed (advanced past), leaves tokenizer in a state where the next element is 'current' - static bool consumeArguments(arg_tokenizer& tokenizer, const arg_properties_t& properties, std::vector& v_out); - - void handlePositionalArgument(arg_tokenizer& tokenizer, size_t& last_pos); - - void handleFlagArgument(arg_tokenizer& tokenizer); - - void processFlag(arg_tokenizer& tokenizer, const std::string& flag); - - template - static inline bool holds_alternative(const arg_data_t& v){ - if constexpr (std::is_same_v) - return std::holds_alternative(v); - else - { - if (std::holds_alternative(v)) - { - arg_data_internal_t data = std::get(v); - return std::holds_alternative(data); - } else - return false; - } - } - template - static inline T& get(arg_data_t& v){ - if constexpr (std::is_same_v) - return std::get(v); - else - return std::get(std::get(v)); - } - public: - arg_parse() - { - addArgument(arg_builder({"--help", "-h"}).setAction(arg_action_t::HELP).setHelp("Show this help menu").build()); - }; - - void addArgument(const arg_properties_t& args); - - arg_results parse_args(int argc, const char** argv); - - arg_results parse_args(const std::vector& args); - - void printHelp(); - - ~arg_parse() - { - for (auto* p : user_args.arg_properties_storage) - delete p; - } - }; - - std::string to_string(const blt::arg_data_t& v); - std::string to_string(const blt::arg_data_internal_t& v); - -} - -#endif //BLT_TESTS_ARGPARSE_2_H diff --git a/src/blt/parse/argparse.cpp b/src/blt/parse/argparse.cpp index 7407088..c1a7ca6 100644 --- a/src/blt/parse/argparse.cpp +++ b/src/blt/parse/argparse.cpp @@ -1,351 +1,404 @@ /* - * Created by Brett on 28/07/23. + * Created by Brett on 06/08/23. * Licensed under GNU General Public License V3.0 * See LICENSE file for license detail */ -#include "blt/std/logging.h" - +#include +#include #include -//namespace blt::parser { -// -// arg_vector_t::arg_vector_t(const std::vector& args) { -// for (auto& arg : args) -// insertAndSort(arg); -// } -// -// arg_vector_t::arg_vector_t(std::initializer_list args) { -// for (auto& arg : args) -// insertAndSort(arg); -// } -// -// arg_vector_t::arg_vector_t(const std::string& arg) { -// insertAndSort(arg); -// } -// -// arg_vector_t::arg_vector_t(const char* arg) { -// insertAndSort(arg); -// } -// -// arg_vector_t& arg_vector_t::operator=(const std::string& arg) { -// insertAndSort(arg); -// return *this; -// } -// -// arg_vector_t& arg_vector_t::operator=(const char* arg) { -// insertAndSort(arg); -// return *this; -// } -// -// arg_vector_t& arg_vector_t::operator=(std::initializer_list& args) { -// for (auto& arg : args) -// insertAndSort(arg); -// return *this; -// } -// -// arg_vector_t& arg_vector_t::operator=(std::vector& args) { -// for (auto& arg : args) -// insertAndSort(arg); -// return *this; -// } -// -// void arg_vector_t::insertAndSort(const std::string& str) { -// if (str.starts_with('-')) { -// flags.push_back(str); -// isFlags = true; -// } else { -// names.push_back(str); -// isFlags = false; -// } -// if (!flags.empty() && !names.empty()) -// BLT_WARN("Flags provided alongside named positional args. This is not supported!"); -// } -// -// arg_nargs_t::arg_nargs_t(char c) { -// decode(c); -// } -// -// arg_nargs_t::arg_nargs_t(std::string s) { -// decode(s[0]); -// } -// -// arg_nargs_t::arg_nargs_t(const char* s) { -// decode(*s); -// } -// -// arg_nargs_t& arg_nargs_t::operator=(const std::string& s) { -// decode(s[0]); -// return *this; -// } -// -// arg_nargs_t& arg_nargs_t::operator=(char c) { -// decode(c); -// return *this; -// } -// -// arg_nargs_t& arg_nargs_t::operator=(int a) { -// args = a; -// return *this; -// } -// -// arg_nargs_t& arg_nargs_t::operator=(const char* s) { -// decode(*s); -// return *this; -// } -// -// void arg_nargs_t::decode(char c) { -// if (c == '?') -// flags = UNKNOWN; -// else if (c == '+') -// flags = ALL_REQUIRED; -// else if (c == '*') -// flags = ALL; -// else -// flags = 0; -// } -// -// arg_tokenizer_t::arg_tokenizer_t(size_t argc, const char** argv) { -// for (size_t i = 0; i < argc; i++) -// args.emplace_back(argv[i]); -// } -// -// bool arg_parse::validateArgument(const arg_properties_t& args) { -// return !(args.a_flags.getFlags().empty() ^ args.a_flags.getNames().empty()); -// } -// -// void arg_parse::addArgument(const arg_properties_t& args) { -// if (validateArgument(args)) { -// BLT_WARN("Argument contains both flags and positional names, this is not allowed!"); -// return; -// } -// // store one copy of the properties (arg properties could in theory be very large!) -// auto pos = user_args.arg_storage.size(); -// user_args.arg_storage.push_back(args); -// auto& arg = user_args.arg_storage[pos]; -// if (arg.a_dest.empty()) { -// // update dest with first full flag (same as python's behaviour) -// if (arg.a_flags.isFlag()) { -// for (const auto& flag : arg.a_flags.getFlags()) { -// if (flag.starts_with("--")) { -// arg.a_dest = flag; -// break; -// } -// } -// } else { -// for (const auto& name : arg.a_flags.getNames()) { -// arg.a_dest = name; -// break; -// } -// } -// } -// BLT_TRACE("Flag %s: %p", arg.a_dest.c_str(), &arg); -// // associate the arg properties per name and flag to allow for quick access when parsing -// auto& names = arg.a_flags.getNames(); -// for (const auto& name : names) { -// user_args.name_associations.emplace_back(name, &arg); -// user_args.required_vars.insert(name); -// } -// -// auto& flags = arg.a_flags.getFlags(); -// for (const auto& flag : flags) -// user_args.flag_associations[flag] = &arg; -// -// if (arg.a_required) -// user_args.required_vars.insert(arg.a_dest); -// -// if (arg.a_nargs.flags == arg_nargs_t::UNKNOWN) { -// if (arg.a_flags.getNames().empty()) { -// for (const auto& flag : arg.a_flags.getFlags()) -// loaded_args.flag_args[flag] = arg.a_default; -// } else { -// for (const auto& name : arg.a_flags.getNames()) -// loaded_args.positional_args[name] = arg.a_default; -// } -// } -// -// BLT_DEBUG("PRINTING: %d, %d", user_args.arg_storage[pos].a_flags.getFlags().size(), user_args.arg_storage[pos].a_flags.getNames().size()); -// -// } -// -// const arg_parse::arg_results& arg_parse::parse_args(int argc, const char** argv) { -// loaded_args = {}; -// arg_tokenizer_t arg_tokenizer(argc, argv); -// loaded_args.program_name = arg_tokenizer.next(); -// -// size_t last_positional = 0; -// while (arg_tokenizer.hasNext()) { -// // a token isn't a flag it must be a positional arg as flags will consume nargs -// if (!arg_tokenizer.isFlag()){ -// handlePositionalArgument(arg_tokenizer, last_positional); -// continue; -// } -// handleFlagArgument(arg_tokenizer); -// } -// -// if (loaded_args.unrecognized_args.empty()) -// return loaded_args; -// -// std::string unrec; -// for (const auto& r : loaded_args.unrecognized_args) { -// unrec += '\''; -// unrec += r; -// unrec += '\''; -// unrec += ' '; -// } -// unrec = unrec.substr(0, unrec.size()-1); -// BLT_WARN("Unrecognized args: %s", unrec.c_str()); -// printHelp(); -// -// return loaded_args; -// } -// -// void arg_parse::printHelp() { -// -// } -// -// void arg_parse::handlePositionalArgument(arg_tokenizer_t& arg_tokenizer, size_t& last_pos) { -// // TODO: -// auto index = last_pos++; -// if (index >= user_args.name_associations.size()) -// loaded_args.unrecognized_args.push_back(arg_tokenizer.next()); -// else -// loaded_args.positional_args[user_args.name_associations[index].first] = arg_tokenizer.next(); -// } -// -// void arg_parse::handleFlagArgument(arg_tokenizer_t& arg_tokenizer) { -// // token is a flag, find out special information about it -// auto flag = arg_tokenizer.next(); -// -// if (flag.starts_with("--")) -// processFlag(arg_tokenizer, flag); -// else { -// // handle special args like -vvv -// if (!flag.starts_with('-')) -// BLT_TRACE("Flag processed but does not start with '-'!"); -// // size without - -// auto len = flag.size()-1; -// // get flag type -// std::string str = "- "; -// str[1] = flag[1]; -// for (size_t i = 0; i < len; i++) -// processFlag(arg_tokenizer, str); -// } -// } -// -// void arg_parse::processFlag(arg_tokenizer_t& arg_tokenizer, const std::string& flag) { -// auto loc = user_args.flag_associations.find(flag); -// if (loc == user_args.flag_associations.end()){ -// BLT_WARN("Flag '%s' not an option!", flag.c_str()); -// printHelp(); -// return; -// } -// -// auto* flag_properties = loc->second; -// if (flag_properties->a_dest.empty()) { -// BLT_ERROR("Flag dest empty! %s : %d, %p", flag.c_str(), flag_properties->a_flags.getFlags().size(), flag_properties); -// return; -// } -// auto dest = flag_properties->a_dest; -// -// arg_data_t& data = loaded_args.flag_args[dest]; -// switch(flag_properties->a_action){ -// case arg_action_t::HELP: -// printHelp(); -// break; -// case arg_action_t::STORE: { -// std::vector v; -// if (!consumeArguments(arg_tokenizer, *flag_properties, v)) { -// printHelp(); -// return; -// } -// if (v.size() == 1) -// data = v[0]; -// else -// data = v; -// break; -// } -// case arg_action_t::STORE_CONST: -// data = flag_properties->a_const; -// break; -// case arg_action_t::STORE_FALSE: -// data = false; -// break; -// case arg_action_t::STORE_TRUE: -// data = true; -// break; -// case arg_action_t::COUNT: { -// if (!std::holds_alternative(data)) -// data = 0; -// data = std::get(data) + 1; -// break; -// } -// case arg_action_t::EXTEND: { -// -// break; -// } -// case arg_action_t::VERSION: { -// auto file = filename(loaded_args.program_name); -// BLT_INFO("%s, %s", file.c_str(), flag_properties->a_version.c_str()); -// break; -// } -// case arg_action_t::APPEND_CONST: { -// if (!holds_alternative>(data)) { -// data = std::vector(); -// } -// auto& l = get>(data); -// l.emplace_back(flag_properties->a_const); -// break; -// } -// case arg_action_t::APPEND: { -// if (!holds_alternative>(data)) -// data = std::vector(); -// auto& l = get>(data); -// consumeArguments(arg_tokenizer, *flag_properties, l); -// break; -// } -// } -// } -// -// bool arg_parse::consumeArguments(arg_tokenizer_t& arg_tokenizer, const arg_properties_t& properties, std::vector& v_out) { -// switch (properties.a_nargs.flags) { -// case 0: -// for (int i = 0; i < properties.a_nargs.args; i++) { -// if (!arg_tokenizer.hasNext()){ -// BLT_WARN("Expected %d arguments got %d instead!", properties.a_nargs.args, i); -// return false; -// } -// if (arg_tokenizer.isFlag()) { -// BLT_WARN("Expected %d arguments, found flag instead!", properties.a_nargs.args); -// return false; -// } -// v_out.emplace_back(arg_tokenizer.next()); -// } -// return true; -// case arg_nargs_t::UNKNOWN: -// // no arg next -// if (!arg_tokenizer.hasNext() || arg_tokenizer.isFlag()) { -// if (!properties.a_const.empty()) -// v_out.emplace_back(properties.a_const); -// else -// v_out.emplace_back(properties.a_default); -// return true; -// } -// v_out.emplace_back(arg_tokenizer.next()); -// return true; -// case arg_nargs_t::ALL: -// while (arg_tokenizer.hasNext() && !arg_tokenizer.isFlag()) -// v_out.emplace_back(arg_tokenizer.next()); -// return true; -// case arg_nargs_t::ALL_REQUIRED: -// if (arg_tokenizer.isFlag()) { -// BLT_WARN("At least one argument is required!"); -// return false; -// } -// while (arg_tokenizer.hasNext() && !arg_tokenizer.isFlag()) -// v_out.emplace_back(arg_tokenizer.next()); -// return true; -// } -// return false; -// } -// -//} \ No newline at end of file +namespace blt +{ + + void arg_nargs_t::decode(char c) + { + if (c == '?') + flags = UNKNOWN; + else if (c == '+') + flags = ALL_REQUIRED; + else if (c == '*') + flags = ALL; + else + flags = 0; + } + + arg_nargs_t::arg_nargs_t(char c) + { + decode(c); + } + + arg_nargs_t::arg_nargs_t(std::string s) + { + decode(s[0]); + } + + arg_nargs_t::arg_nargs_t(const char* s) + { + decode(*s); + } + + class invalid_argument_exception : public std::runtime_error + { + public: + invalid_argument_exception(const std::string& str): std::runtime_error(str) + {} + }; + + void arg_vector_t::validateFlags() + { + for (const auto& flag : flags) + if (!flag.starts_with('-')) + throw invalid_argument_exception("Flag '" + flag + "' must start with - or --"); + } + + arg_vector_t::arg_vector_t(const char* str) { + std::string as_string(str); + if (as_string.starts_with('-')) + flags.emplace_back(as_string); + else + name = as_string; + } + arg_vector_t::arg_vector_t(const std::string& str) { + if (str.starts_with('-')) + flags.emplace_back(str); + else + name = str; + } + + std::string to_string(const arg_data_t& v) + { + if (holds_alternative(v)) + return to_string(std::get(v)); + else if (std::holds_alternative(v)) + { + const auto& vec = std::get(v); + if (vec.size() == 1) + return to_string(vec[0]); + if (vec.empty()) + return "Empty Vector"; + std::string str; + for (const auto& r : vec) + { + str += to_string(r); + str += ' '; + } + return "Vector of contents: " + str; + } + return "Empty"; + } + + std::string to_string(const arg_data_internal_t& v) + { + if (std::holds_alternative(v)){ + return std::get(v); + } else if (std::holds_alternative(v)) { + return std::get(v) ? "True" : "False"; + } + return std::to_string(std::get(v)); + } + + std::string arg_parse::filename(const std::string& path) + { + auto paths = blt::string::split(path, "/"); + auto final = paths[paths.size() - 1]; + if (final == "/") + return paths[paths.size() - 2]; + return final; + } + + void arg_parse::addArgument(const arg_properties_t& args) + { + auto properties = new arg_properties_t(args); + + // determine where to store the arg when parsing + if (properties->a_dest.empty()) + { + if (properties->a_flags.isFlag()) + { + // take first arg so a_dest exists, could be - or -- + properties->a_dest = properties->a_flags.flags[0]; + // look for a -- arg (python's behaviour) + for (const auto& flag : properties->a_flags.flags) + { + if (flag.starts_with("--")) + { + properties->a_dest = flag; + break; + } + } + } else + properties->a_dest = properties->a_flags.name; + } + + if (properties->a_dest.starts_with("--")) + properties->a_dest = properties->a_dest.substr(2); + else if (properties->a_dest.starts_with('-')) + properties->a_dest = properties->a_dest.substr(1); + + // associate flags with their properties + for (const auto& flag : properties->a_flags.flags) + user_args.flag_associations[flag] = properties; + + // positional args uses index (vector) to store the properties + if (!properties->a_flags.isFlag()) + user_args.name_associations.push_back(properties); + + user_args.arg_properties_storage.push_back(properties); + } + + bool arg_parse::consumeArguments(arg_tokenizer& tokenizer, const arg_properties_t& properties, std::vector& v_out) + { + switch (properties.a_nargs.flags) + { + case 0: + for (int i = 0; i < properties.a_nargs.args; i++) + { + // if we don't have another arg to consume we have a problem! + if (!tokenizer.hasCurrent()) + { + BLT_WARN("Expected %d arguments got %d instead!", properties.a_nargs.args, i); + return false; + } + // if we do have one, but it is a flag then we also have a problem! + if (tokenizer.isFlag()) + { + BLT_WARN("Expected %d arguments, found flag instead!", properties.a_nargs.args); + return false; + } + // get the value and advance + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + } + return true; + case arg_nargs_t::UNKNOWN: + // no arg next + if (!tokenizer.hasCurrent() || tokenizer.isFlag()) + { + // python's default is to store const if around otherwise store default + if (!properties.a_const.empty()) + v_out.emplace_back(properties.a_const); + else // this should no longer be required with the changes to how defaults are handled + v_out.emplace_back(properties.a_default); + return true; + } + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + return true; + case arg_nargs_t::ALL: + while (tokenizer.hasCurrent() && !tokenizer.isFlag()) + { + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + } + return true; + case arg_nargs_t::ALL_REQUIRED: + if (tokenizer.hasCurrent() && tokenizer.isFlag()) + { + BLT_WARN("At least one argument is required!"); + return false; + } + while (tokenizer.hasCurrent() && !tokenizer.isFlag()) + { + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + } + return true; + } + return false; + } + + void arg_parse::handlePositionalArgument(arg_tokenizer& tokenizer, size_t& last_pos) + { + auto index = last_pos++; + if (index >= user_args.name_associations.size()) + loaded_args.unrecognized_args.push_back(tokenizer.get()); + else + { + loaded_args.data[user_args.name_associations[index]->a_dest] = tokenizer.get(); + loaded_args.found_args.insert(user_args.name_associations[index]->a_dest); + } + tokenizer.advance(); + } + + void arg_parse::handleFlagArgument(arg_tokenizer& tokenizer) + { + auto flag = tokenizer.get(); + tokenizer.advance(); + + // token is a flag, figure out how to handle it + if (flag.starts_with("--")) + processFlag(tokenizer, flag); + else + { + // handle special args like -vvv + if (!flag.starts_with('-')) + BLT_ERROR("Flag processed but does not start with '-'"); + // make sure the flag only contains the same character + auto type = flag[1]; + for (char c : flag.substr(1)) + { + if (c != type) + { + BLT_ERROR("Processed flag '%s' expected %c found %c", flag.c_str(), type, c); + return; + } + } + // size without - + auto len = flag.size() - 1; + // get flag type + std::string str = "- "; + str[1] = flag[1]; + for (size_t i = 0; i < len; i++) + processFlag(tokenizer, str); + } + } + + void arg_parse::processFlag(arg_tokenizer& tokenizer, const std::string& flag) + { + auto flag_itr = user_args.flag_associations.find(flag); + if (flag_itr == user_args.flag_associations.end()) + { + loaded_args.unrecognized_args.push_back(flag); + return; + } + + const auto* const properties = user_args.flag_associations.at(flag); + + if (properties->a_dest.empty()) + { + loaded_args.unrecognized_args.push_back(flag); + return; + } + auto dest = properties->a_dest; + + loaded_args.found_args.insert(dest); + + switch (properties->a_action) + { + case arg_action_t::HELP: + printHelp(); + break; + case arg_action_t::STORE: + { + arg_data_t& data = loaded_args.data[dest]; + arg_data_vec_t v; + if (!consumeArguments(tokenizer, *properties, v)) + { + printHelp(); + return; + } + if (v.size() == 1) + data = v[0]; + else + data = v; + break; + } + case arg_action_t::STORE_CONST: + loaded_args.data[dest] = properties->a_const; + break; + case arg_action_t::STORE_FALSE: + loaded_args.data[dest] = false; + break; + case arg_action_t::STORE_TRUE: + loaded_args.data[dest] = true; + break; + case arg_action_t::COUNT: + { + auto& data = loaded_args.data[dest]; + if (!holds_alternative(data)) + data = 0; + data = get(data) + 1; + break; + } + case arg_action_t::EXTEND: + { + + break; + } + case arg_action_t::VERSION: + { + auto file = filename(loaded_args.program_name); + BLT_INFO("%s, %s", file.c_str(), properties->a_version.c_str()); + break; + } + case arg_action_t::APPEND_CONST: + { + auto& data = loaded_args.data[dest]; + if (!std::holds_alternative(data)) + { + data = arg_data_vec_t(); + } + auto& l = get(data); + l.emplace_back(properties->a_const); + break; + } + case arg_action_t::APPEND: + { + auto& data = loaded_args.data[dest]; + if (!holds_alternative(data)) + data = arg_data_vec_t(); + auto& l = get(data); + consumeArguments(tokenizer, *properties, l); + break; + } + } + } + + arg_parse::arg_results arg_parse::parse_args(int argc, const char** argv) + { + std::vector args; + args.reserve(argc); + for (int i = 0; i < argc; i++) + args.emplace_back(argv[i]); + return parse_args(args); + } + + arg_parse::arg_results arg_parse::parse_args(const std::vector& args) + { + arg_tokenizer tokenizer(args); + loaded_args.program_name = tokenizer.get(); + tokenizer.advance(); + + size_t last_positional = 0; + while (tokenizer.hasCurrent()) + { + if (tokenizer.isFlag()) + handleFlagArgument(tokenizer); + else + handlePositionalArgument(tokenizer, last_positional); + } + + // load defaults for args which were not found + for (const auto* arg : user_args.arg_properties_storage) { + if (!to_string(arg->a_default).empty() && !loaded_args.contains(arg->a_dest)) + loaded_args.data[arg->a_dest] = arg->a_default; + } + + // if there was no problems processing then return the loaded args + if (loaded_args.unrecognized_args.empty()) + return loaded_args; + + // otherwise construct a string detailing the unrecognized args + std::string unrec; + for (const auto& r : loaded_args.unrecognized_args) + { + unrec += '\''; + unrec += r; + unrec += '\''; + unrec += ' '; + } + // remove the last space caused by the for loop + unrec = unrec.substr(0, unrec.size() - 1); + // TODO: use exceptions? + BLT_WARN("Unrecognized args: %s", unrec.c_str()); + printHelp(); + + return loaded_args; + } + + void arg_parse::printHelp() + { + BLT_TRACE("I am helpful!"); + std::exit(0); + } +} \ No newline at end of file diff --git a/src/blt/parse/argparse_2.cpp b/src/blt/parse/argparse_2.cpp deleted file mode 100644 index a3dc1bf..0000000 --- a/src/blt/parse/argparse_2.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Created by Brett on 06/08/23. - * Licensed under GNU General Public License V3.0 - * See LICENSE file for license detail - */ -#include -#include -#include - -namespace blt -{ - - void arg_nargs_t::decode(char c) - { - if (c == '?') - flags = UNKNOWN; - else if (c == '+') - flags = ALL_REQUIRED; - else if (c == '*') - flags = ALL; - else - flags = 0; - } - - arg_nargs_t::arg_nargs_t(char c) - { - decode(c); - } - - arg_nargs_t::arg_nargs_t(std::string s) - { - decode(s[0]); - } - - arg_nargs_t::arg_nargs_t(const char* s) - { - decode(*s); - } - - class invalid_argument_exception : public std::runtime_error - { - public: - invalid_argument_exception(const std::string& str): std::runtime_error(str) - {} - }; - - void arg_vector_t::validateFlags() - { - for (const auto& flag : flags) - if (!flag.starts_with('-')) - throw invalid_argument_exception("Flag '" + flag + "' must start with - or --"); - } - - arg_vector_t::arg_vector_t(const char* str) { - std::string as_string(str); - if (as_string.starts_with('-')) - flags.emplace_back(as_string); - else - name = as_string; - } - arg_vector_t::arg_vector_t(const std::string& str) { - if (str.starts_with('-')) - flags.emplace_back(str); - else - name = str; - } - - std::string to_string(const arg_data_t& v) - { - if (holds_alternative(v)) - return to_string(std::get(v)); - else if (std::holds_alternative(v)) - { - const auto& vec = std::get(v); - if (vec.size() == 1) - return to_string(vec[0]); - if (vec.empty()) - return "Empty Vector"; - std::string str; - for (const auto& r : vec) - { - str += to_string(r); - str += ' '; - } - return "Vector of contents: " + str; - } - return "Empty"; - } - - std::string to_string(const arg_data_internal_t& v) - { - if (std::holds_alternative(v)){ - return std::get(v); - } else if (std::holds_alternative(v)) { - return std::get(v) ? "True" : "False"; - } - return std::to_string(std::get(v)); - } - - std::string arg_parse::filename(const std::string& path) - { - auto paths = blt::string::split(path, "/"); - auto final = paths[paths.size() - 1]; - if (final == "/") - return paths[paths.size() - 2]; - return final; - } - - void arg_parse::addArgument(const arg_properties_t& args) - { - auto properties = new arg_properties_t(args); - - // determine where to store the arg when parsing - if (properties->a_dest.empty()) - { - if (properties->a_flags.isFlag()) - { - // take first arg so a_dest exists, could be - or -- - properties->a_dest = properties->a_flags.flags[0]; - // look for a -- arg (python's behaviour) - for (const auto& flag : properties->a_flags.flags) - { - if (flag.starts_with("--")) - { - properties->a_dest = flag; - break; - } - } - } else - properties->a_dest = properties->a_flags.name; - } - - // associate flags with their properties - for (const auto& flag : properties->a_flags.flags) - user_args.flag_associations[flag] = properties; - - // positional args uses index (vector) to store the properties - if (!properties->a_flags.isFlag()) - user_args.name_associations.push_back(properties); - - user_args.arg_properties_storage.push_back(properties); - } - - bool arg_parse::consumeArguments(arg_tokenizer& tokenizer, const arg_properties_t& properties, std::vector& v_out) - { - switch (properties.a_nargs.flags) - { - case 0: - for (int i = 0; i < properties.a_nargs.args; i++) - { - // if we don't have another arg to consume we have a problem! - if (!tokenizer.hasCurrent()) - { - BLT_WARN("Expected %d arguments got %d instead!", properties.a_nargs.args, i); - return false; - } - // if we do have one, but it is a flag then we also have a problem! - if (tokenizer.isFlag()) - { - BLT_WARN("Expected %d arguments, found flag instead!", properties.a_nargs.args); - return false; - } - // get the value and advance - v_out.emplace_back(tokenizer.get()); - tokenizer.advance(); - } - return true; - case arg_nargs_t::UNKNOWN: - // no arg next - if (!tokenizer.hasCurrent() || tokenizer.isFlag()) - { - // python's default is to store const if around otherwise store default - if (!properties.a_const.empty()) - v_out.emplace_back(properties.a_const); - else // this should no longer be required with the changes to how defaults are handled - v_out.emplace_back(properties.a_default); - return true; - } - v_out.emplace_back(tokenizer.get()); - tokenizer.advance(); - return true; - case arg_nargs_t::ALL: - while (tokenizer.hasCurrent() && !tokenizer.isFlag()) - { - v_out.emplace_back(tokenizer.get()); - tokenizer.advance(); - } - return true; - case arg_nargs_t::ALL_REQUIRED: - if (tokenizer.hasCurrent() && tokenizer.isFlag()) - { - BLT_WARN("At least one argument is required!"); - return false; - } - while (tokenizer.hasCurrent() && !tokenizer.isFlag()) - { - v_out.emplace_back(tokenizer.get()); - tokenizer.advance(); - } - return true; - } - return false; - } - - void arg_parse::handlePositionalArgument(arg_tokenizer& tokenizer, size_t& last_pos) - { - auto index = last_pos++; - if (index >= user_args.name_associations.size()) - loaded_args.unrecognized_args.push_back(tokenizer.get()); - else - loaded_args.data[user_args.name_associations[index]->a_dest] = tokenizer.get(); - tokenizer.advance(); - } - - void arg_parse::handleFlagArgument(arg_tokenizer& tokenizer) - { - auto flag = tokenizer.get(); - tokenizer.advance(); - - // token is a flag, figure out how to handle it - if (flag.starts_with("--")) - processFlag(tokenizer, flag); - else - { - // handle special args like -vvv - if (!flag.starts_with('-')) - BLT_ERROR("Flag processed but does not start with '-'"); - // make sure the flag only contains the same character - auto type = flag[1]; - for (char c : flag.substr(1)) - { - if (c != type) - { - BLT_ERROR("Processed flag '%s' expected %c found %c", flag.c_str(), type, c); - return; - } - } - // size without - - auto len = flag.size() - 1; - // get flag type - std::string str = "- "; - str[1] = flag[1]; - for (size_t i = 0; i < len; i++) - processFlag(tokenizer, str); - } - } - - void arg_parse::processFlag(arg_tokenizer& tokenizer, const std::string& flag) - { - auto flag_itr = user_args.flag_associations.find(flag); - if (flag_itr == user_args.flag_associations.end()) - { - loaded_args.unrecognized_args.push_back(flag); - return; - } - - const auto* const properties = user_args.flag_associations.at(flag); - - - if (properties->a_dest.empty()) - { - loaded_args.unrecognized_args.push_back(flag); - return; - } - auto dest = properties->a_dest; - if (dest.starts_with("--")) - dest = dest.substr(2); - else if (dest.starts_with('-')) - dest = dest.substr(1); - - switch (properties->a_action) - { - case arg_action_t::HELP: - printHelp(); - break; - case arg_action_t::STORE: - { - arg_data_t& data = loaded_args.data[dest]; - arg_data_vec_t v; - if (!consumeArguments(tokenizer, *properties, v)) - { - printHelp(); - return; - } - if (v.size() == 1) - data = v[0]; - else - data = v; - break; - } - case arg_action_t::STORE_CONST: - loaded_args.data[dest] = properties->a_const; - break; - case arg_action_t::STORE_FALSE: - loaded_args.data[dest] = false; - break; - case arg_action_t::STORE_TRUE: - loaded_args.data[dest] = true; - break; - case arg_action_t::COUNT: - { - auto& data = loaded_args.data[dest]; - if (!holds_alternative(data)) - data = 0; - data = get(data) + 1; - break; - } - case arg_action_t::EXTEND: - { - - break; - } - case arg_action_t::VERSION: - { - auto file = filename(loaded_args.program_name); - BLT_INFO("%s, %s", file.c_str(), properties->a_version.c_str()); - break; - } - case arg_action_t::APPEND_CONST: - { - auto& data = loaded_args.data[dest]; - if (!std::holds_alternative(data)) - { - data = arg_data_vec_t(); - } - auto& l = get(data); - l.emplace_back(properties->a_const); - break; - } - case arg_action_t::APPEND: - { - auto& data = loaded_args.data[dest]; - if (!holds_alternative(data)) - data = arg_data_vec_t(); - auto& l = get(data); - consumeArguments(tokenizer, *properties, l); - break; - } - } - } - - arg_parse::arg_results arg_parse::parse_args(int argc, const char** argv) - { - std::vector args; - args.reserve(argc); - for (int i = 0; i < argc; i++) - args.emplace_back(argv[i]); - return parse_args(args); - } - - arg_parse::arg_results arg_parse::parse_args(const std::vector& args) - { - arg_tokenizer tokenizer(args); - loaded_args.program_name = tokenizer.get(); - tokenizer.advance(); - - size_t last_positional = 0; - while (tokenizer.hasCurrent()) - { - if (tokenizer.isFlag()) - handleFlagArgument(tokenizer); - else - handlePositionalArgument(tokenizer, last_positional); - } - - // if there was no problems processing then return the loaded args - if (loaded_args.unrecognized_args.empty()) - return loaded_args; - - // otherwise construct a string detailing the unrecognized args - std::string unrec; - for (const auto& r : loaded_args.unrecognized_args) - { - unrec += '\''; - unrec += r; - unrec += '\''; - unrec += ' '; - } - // remove the last space caused by the for loop - unrec = unrec.substr(0, unrec.size() - 1); - // TODO: use exceptions? - BLT_WARN("Unrecognized args: %s", unrec.c_str()); - printHelp(); - - return loaded_args; - } - - void arg_parse::printHelp() - { - BLT_TRACE("I am helpful!"); - std::exit(0); - } -} \ No newline at end of file diff --git a/src/tests/main.cpp b/src/tests/main.cpp index cc96081..822b91e 100755 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -4,7 +4,7 @@ //#include "logging.h" #include "profiling_tests.h" #include "nbt_tests.h" -#include "blt/parse/argparse_2.h" +#include "blt/parse/argparse.h" //#include "queue_tests.h" //#include "blt/math/vectors.h" //#include "blt/math/matrix.h" @@ -79,7 +79,8 @@ int main(int argc, const char** argv) { std::vector superArgs { "BLT_TESTS", "Sexy", - "--poo", "I have poop", + "-p", "I have poop", + "-f" }; auto args2 = parser.parse_args(superArgs);