From 6a3b85b9b1ce4953eff4402b4b0fe2d47fa5bc2e Mon Sep 17 00:00:00 2001 From: p620 Date: Wed, 31 Mar 2021 14:02:38 +0300 Subject: [PATCH] Contribute a failing to compile part of a CLI support implementation. --- CMakeLists.txt | 2 +- cmake/GenerateRevision.cmake | 2 +- src/noggit/Cli.cpp | 157 +++++++++++++++++++++++++++++++++++ src/noggit/Cli.hpp | 111 +++++++++++++++++++++++++ src/noggit/Cli.inl | 37 +++++++++ src/noggit/MakeshiftMt.cpp | 3 +- src/noggit/application.cpp | 8 +- 7 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 src/noggit/Cli.cpp create mode 100644 src/noggit/Cli.hpp create mode 100644 src/noggit/Cli.inl diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b18dd21..0e9d88c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,7 +244,7 @@ COLLECT_FILES(false imguipiemenu_sources src/external/imguipiemenu ".c;.cpp;") set ( util_sources src/util/exception_to_string.cpp ) -COLLECT_FILES(false noggit_root_headers src/noggit ".h;.hpp") +COLLECT_FILES(false noggit_root_headers src/noggit ".h;.hpp;.inl") COLLECT_FILES(true noggit_ui_headers src/noggit/ui ".h;.hpp") COLLECT_FILES(false math_headers src/math ".h;.hpp") COLLECT_FILES(false opengl_headers src/opengl ".h;.hpp") diff --git a/cmake/GenerateRevision.cmake b/cmake/GenerateRevision.cmake index 8f561f7e..74771dca 100644 --- a/cmake/GenerateRevision.cmake +++ b/cmake/GenerateRevision.cmake @@ -33,7 +33,7 @@ file (READ "${_noggit_revision_template_file}" _template_blob) file (READ "${CMAKE_CURRENT_LIST_FILE}" _self_blob) string (SHA256 _state_hash "${_dirty_marker}${_revision}${_template_blob}${_self_blob}") -if (EXISTS ${_noggit_revision_output_file}) +if (EXISTS ${_noggit_revision_state_file}) file (READ "${_noggit_revision_state_file}" _old_state_hash) if (_state_hash STREQUAL _old_state_hash) return() diff --git a/src/noggit/Cli.cpp b/src/noggit/Cli.cpp new file mode 100644 index 00000000..c99d4e18 --- /dev/null +++ b/src/noggit/Cli.cpp @@ -0,0 +1,157 @@ +#include +#include +#include "Cli.inl" + +using namespace noggit; + +template < typename Ty > +concept CharOrCStr = std::is_same_v +|| std::is_same_v; + +template < CharOrCStr Str > +struct ControllerException +{ + explicit constexpr + ControllerException ( Str arg ) + : arg{arg} + { } + + Str arg; +}; + +Cli::Cli +( + std::size_t argC, + char const* const* argV +) +: _args(_countArgs(argC, argV)) +{ + try + { + std::size_t counter{}; + auto const findHandlerOrThrow{ + [ this ] + < CharOrCStr Str > + ( Str str ) + -> ControllerHandler + { + auto const result{CliAssister::_findControllerInfo(str, _argMapping)}; + return result ? throw ControllerException{str} : result->second; + }}; + + for(std::size_t i{}; i < argC; ++i) + { + if(argV[i][0] == '-') + { + if(argV[i][1] == '\0') + throw "-"; + + if(argV[i][1] == '-') + { + if(argV[i][2] == '\0') + throw "--"; + else + { + _args[i] = findHandlerOrThrow(&argV[i][2]); + ++counter; + continue; + } + + for(std::size_t j{1}; argV[i][j]; ++j, ++counter) + _args[counter] = findHandlerOrThrow(argV[i][j]); + } + } + + _args[counter] = (argV[i]); + ++counter; + } + } + catch ( ControllerException e ) + { + std::cerr << "\nE: Unknown control flag: '" << e.arg << '\''; + throw; + } + catch ( ControllerException e ) + { + std::cerr << "\nE: Unknown control statement: '" << e.arg << '\''; + throw; + } + catch ( char const* str ) + { + std::cerr << "\nE: Unknown parameter: '" << str << '\''; + throw; + } + catch ( ... ) + { + std::exit(EXIT_FAILURE); + } +} + +struct ControllerNotSatisfied +{ + std::string_view name; +}; + +auto Cli::exec ( ) +-> void +{ + StateMachine state{}; + + try + { + for(auto arg{_args.cbegin()}; arg != _args.cend(); ) + { + if(ControllerHandler const* handler{std::get_if(&*arg)} + ; handler) + { + if(state.curHandler) + throw ControllerNotSatisfied{*CliAssister::_findControllerInfo + (state.curHandler, _nameMapping)}; + + (*handler)({}) || (state.curHandler = *handler); + ++arg; + continue; + } + + + } + } + catch ( ControllerNotSatisfied e ) + { + std::cerr << "\nE: Controller '" << e.name << "' expected an argument."; + throw; + } + catch ( ... ) + { + std::exit(EXIT_FAILURE); + } +} + +Cli::StateMachine::StateMachine ( ) +: curHandler{}, flags{Flags::doContinueExecution} +{ } + +constexpr +auto Cli::_countArgs +( + std::size_t argC, + char const* const* argV +) +-> std::size_t +{ + std::size_t result{}; + + for(std::size_t i{}; i < argC; ++i) + { + if(argV[i][0] == '-' && argV[i][1] != '-' && argV[i][1] != '\0') + { + for(std::size_t j{1}; argV[i][j]; ++j, ++result); + + continue; + } + + ++result; + } + + return result; +} diff --git a/src/noggit/Cli.hpp b/src/noggit/Cli.hpp new file mode 100644 index 00000000..53237473 --- /dev/null +++ b/src/noggit/Cli.hpp @@ -0,0 +1,111 @@ +#ifndef NOGGIT_SRC_NOGGIT_CLI_HPP +#define NOGGIT_SRC_NOGGIT_CLI_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace noggit +{ + using namespace std::literals; + + class Cli + { + public: + explicit + Cli + ( + std::size_t argC, + char const* const* argV + ); + auto exec ( ) + -> void; + private: + static constexpr + auto _countArgs + ( + std::size_t argC, + char const* const* argV + ) + -> std::size_t; + + typedef std::vector> ArgContainer; + + struct ParamInfo + { + typedef auto(HandlerSignature) + ( + ArgContainer::const_iterator begin, + ArgContainer::const_iterator end + ) + -> bool; + + explicit constexpr + ParamInfo + ( + std::initializer_list aliases, + std::string_view name, + HandlerSignature* handler + ); + + std::vector aliases; + std::string_view name; + HandlerSignature* handler; + }; + + struct StateMachine + { + struct Flags + { + enum : std::size_t + { + IsControllerSatisfied = 0x1, + doContinueExecution = 0x2 + }; + }; + + StateMachine ( ); + + std::size_t curParamIdx; + std::size_t flags; + }; + + static constexpr + std::array paramInfos + { + ParamInfo{{"r", "recovery"}, "Recovery", nullptr} + }; + ArgContainer _args; + }; + + template < typename Ty > + concept ControllerInfo = std::is_same_v + || std::is_same_v; + + class CliAssister + { + private: + friend class Cli; + + template + < + ControllerInfo Key, + ControllerInfo Value, + std::size_t n + > + requires ( !std::is_same_v ) + static constexpr + auto _findControllerInfo + ( + Key key, + std::array, n> const& info + ) + -> std::optional; + }; +} + +#endif //NOGGIT_SRC_NOGGIT_CLI_HPP diff --git a/src/noggit/Cli.inl b/src/noggit/Cli.inl new file mode 100644 index 00000000..55a17fc3 --- /dev/null +++ b/src/noggit/Cli.inl @@ -0,0 +1,37 @@ +#ifndef NOGGIT_SRC_NOGGIT_CLI_INL +#define NOGGIT_SRC_NOGGIT_CLI_INL + +#include +#include "Cli.hpp" + +namespace noggit +{ + template + < + ControllerInfo Key, + ControllerInfo Value, + std::size_t n + > + requires ( !std::is_same_v ) + constexpr + auto CliAssister::_findControllerInfo + ( + Key key, + std::array, n> const& info + ) + -> std::optional + { + auto const result{std::find_if(info.cbegin(), info.cend(), + [ key ] + ( std::pair const& pair ) + -> bool + { + return pair.first == key; + })}; + + return result == info.cend() ? std::nullopt + : std::optional{result->second}; + } +} + +#endif //NOGGIT_SRC_NOGGIT_CLI_INL diff --git a/src/noggit/MakeshiftMt.cpp b/src/noggit/MakeshiftMt.cpp index 4a89e8bd..97b82b67 100644 --- a/src/noggit/MakeshiftMt.cpp +++ b/src/noggit/MakeshiftMt.cpp @@ -1,4 +1,4 @@ -#include "MapHeaders.h" +/*#include "MapHeaders.h" #include "MPQ.h" #include "MakeshiftMt.hpp" @@ -145,3 +145,4 @@ MakeshiftMt::~MakeshiftMt( void ) { } +*/ diff --git a/src/noggit/application.cpp b/src/noggit/application.cpp index 90e1a7f8..c45862be 100644 --- a/src/noggit/application.cpp +++ b/src/noggit/application.cpp @@ -41,7 +41,7 @@ #include #include "revision.h" - +#include "Cli.hpp" class Noggit { @@ -341,6 +341,12 @@ namespace int main(int argc, char *argv[]) { + /* command-line mode */ + if(argc > 1) + { + noggit::Cli{static_cast(argc), argv}.exec(); + } + noggit::RegisterErrorHandlers(); std::set_terminate (noggit_terminate_handler);