Coder Social home page Coder Social logo

kamchatka-volcano / cmdlime Goto Github PK

View Code? Open in Web Editor NEW
85.0 3.0 3.0 709 KB

Possibly the least verbose command line parsing library for C++

License: Microsoft Public License

C++ 99.27% CMake 0.57% C 0.16%
cpp17 header-only command-line-parser cli argument-parser

cmdlime's Issues

Error in string_utils.h

std::string_view has no constructor from iterator and size.

Error in line 158 of string_utils.h

Fix: return std::string_view{ str.data(), res };

Error in line 166 of string_utils.h

Fix return std::string_view{ str.data() + static_cast(res + val.size()), str.size() - (res + val.size()) };

Still no support for MSVC

image

When trying to register a simple configuration like this:

struct IConfiguration
{
    virtual ~IConfiguration() noexcept = default;
};

struct ProgramConfig : public cmdlime::Config, public IConfiguration
{
    CMDLIME_PARAM(...);
};

WithoutShortName{} only works with FLAGs, not with PARAMs

If you modify ex05.cpp, line 8 to be

PARAM(name, std::string) << cmdlime::WithoutShortName{};
You get this error with Clang:

$› clang++ -I ../include/ -std=c++17 ex05.cpp 
In file included from ex05.cpp:1:
In file included from ../include/cmdlime/config.h:2:
In file included from ../include/cmdlime/gnuconfig.h:3:
In file included from ../include/cmdlime/configreader.h:5:
In file included from ../include/cmdlime/detail/configmacro.h:2:
../include/cmdlime/detail/param.h:126:39: error: 'format' is a private member of 'cmdlime::detail::Config<cmdlime::detail::FormatType::GNU>'
        static_assert(Format<TConfig::format>::shortNamesEnabled, "Current command line format doesn't support short names");
                                      ^
ex05.cpp:8:37: note: in instantiation of member function 'cmdlime::detail::ParamCreator<std::__1::basic_string<char>, Cfg>::operator<<'
      requested here
        PARAM(name, std::string)    << cmdlime::WithoutShortName{};
                                    ^
../include/cmdlime/detail/config.h:142:33: note: declared private here
    constexpr static FormatType format = formatType;
                                ^
1 error generated.

$>

Changing the format static member in include/cmdlime/detail/config.h:142:33 from private to public fixes the issue.

Add cmdlime::Format::GNUWindows

This is the GNU format with the ability to register alternative names starting with a forward slash.

All names are in kebab-case.
Parameters and flags prefix: --
Short names are supported. Short names prefix: -
Parameters usage: --parameter value--parameter=value-p value or -pvalue. /parameter:value and /parameter value are also supported, they have to be enabled with << WithSlashForm{} modifier or <<WithShortNameSlashForm to add /p:value or /p value, or << SlashName{"custom-name"} and << SlashShortName{"c"} to override an automatic name generation.
Flags usage: --flag-f. /flag or /f are also supported. They have to be enabled with << WithSlashForm{} or <<WithShortNameSlashForm modifiers, or << SlashName{"custom-name"} and << SlashShortName{"c"} to override an automatic name generation.
Flags in short form (except those that start with a slash) can be "glued" together: -abc or with one parameter: -fp value.
Default help flag: -h--help-?, or /?.

Add unregistered options handler

Unknown parameters, flags and arguments errors should be emitted with a default unregistered options handler. The user should be able to override it by adding a custom handler to ignore or filter unregistered data. It should be possible to register a handler globally or for a specified Config type.

Build fails with Clang flags (-Werror and -Wshorten-64-to-32)

Thank you for the great CLI parser! When I include cmdlime in my project, the build fails. The flags that I have added for my project are:

  • -Wall
  • -Wcast-align
  • -Wconversion
  • -Wpedantic
  • -Wextra
  • -Werror
  • -Wnon-virtual-dtor
  • -Woverloaded-virtual
  • -Wsign-conversion

The error is:

In file included from main.cpp:2:
In file included from _deps/cmdlime-src/include/cmdlime/config.h:2:
In file included from _deps/cmdlime-src/include/cmdlime/gnuconfig.h:3:
In file included from _deps/cmdlime-src/include/cmdlime/configreader.h:4:
In file included from _deps/cmdlime-src/include/cmdlime/detail/config.h:3:
_deps/cmdlime-src/include/cmdlime/detail/usageinfocreator.h:321:16: error: implicit conversion loses integer precision: 'unsigned long' to 'int' [-Werror,-Wshorten-64-to-32]
        return size;
        ~~~~~~ ^~~~
_deps/cmdlime-src/include/cmdlime/detail/usageinfocreator.h:101:26: note: in instantiation of member function 'cmdlime::detail::UsageInfoCreator<cmdlime::detail::FormatType::GNU>::maxOptionNameSize' requested here
    , maxOptionNameSize_(maxOptionNameSize() + outputSettings.columnsSpacing)
                         ^
_deps/cmdlime-src/include/cmdlime/detail/config.h:69:16: note: in instantiation of member function 'cmdlime::detail::UsageInfoCreator<cmdlime::detail::FormatType::GNU>::UsageInfoCreator' requested here
        return UsageInfoCreator<formatType>{name, UsageInfoFormat{}, params, paramLists, flags, args, argList_.get()}.create();
               ^
main.cpp:18:22: note: in instantiation of member function 'cmdlime::detail::Config<cmdlime::detail::FormatType::GNU>::usageInfo' requested here
    std::cout << cfg.usageInfo("project");

Here's my main.cpp for reference:

#include <project/version.h>
#include <cmdlime/config.h>

#include <iostream>

auto main(int argc, char** argv) -> int {
  struct Cfg : public cmdlime::Config {
    PARAM(t1, std::string);
    PARAM(t2, int);
    EXITFLAG(help);
    EXITFLAG(version);
  } cfg;

  try {
    cfg.readCommandLine(argc, argv);
  } catch (const cmdlime::Error& e) {
    std::cerr << e.what();
    std::cout << cfg.usageInfo("project");
    return -1;
  }

  if (cfg.help) {
    std::cout << cfg.usageInfoDetailed("project");
    return 0;
  }

  if (cfg.version) {
    std::cout << PROJECT_VERSION;
    return 0;
  }

  return 0;
}

This was tested on macOS 11.3 (Intel architecture) with AppleClang 12.0.5 and cmake 3.20.2.

release version

Hi,

would it be possible to create release version or tag. I use this lib, but I would like to link my app to a specific release.

Thanks

Building examples/ex01 fails

I tried to build the examples, but I got stuck at the first one.

The current build script does not build them, but I added the following to CMakeLists.txt:

add_executable(ex01 examples/ex01.cpp)
target_link_libraries(ex01 PRIVATE cmdlime)

Trying to build with g++ 9.3.0 on Ubuntu 20.04.2 LTS gives the following errors:

In file included from /src/cmdlime/include/cmdlime/configreader.h:5,
                 from /src/cmdlime/include/cmdlime/gnuconfig.h:3,
                 from /src/cmdlime/include/cmdlime/config.h:2,
                 from /src/cmdlime/examples/ex01.cpp:1:
/src/cmdlime/examples/ex01.cpp: In function ‘int main(int, char**)’:
/src/cmdlime/include/cmdlime/detail/configmacro.h:12:105: error: invalid use of ‘this’ in non-member function
   12 | #define ARG(name, type) type name = cmdlime::detail::ArgCreator<type, std::remove_reference_t<decltype(*this)>>{*this, #name, #type, [this]()->type&{return name;}}
      |                                                                                                         ^~~~
/src/cmdlime/examples/ex01.cpp:7:9: note: in expansion of macro ‘ARG’
    7 |         ARG(zipCode, int);
      |         ^~~
/src/cmdlime/include/cmdlime/detail/configmacro.h:12:95: error: template argument 1 is invalid
   12 | #define ARG(name, type) type name = cmdlime::detail::ArgCreator<type, std::remove_reference_t<decltype(*this)>>{*this, #name, #type, [this]()->type&{return name;}}
      |                                                                                               ^~~~~~~~
/src/cmdlime/examples/ex01.cpp:7:9: note: in expansion of macro ‘ARG’
    7 |         ARG(zipCode, int);
      |         ^~~
In file included from /src/cmdlime/include/cmdlime/configreader.h:5,
                 from /src/cmdlime/include/cmdlime/gnuconfig.h:3,
                 from /src/cmdlime/include/cmdlime/config.h:2,
                 from /src/cmdlime/examples/ex01.cpp:1:
/src/cmdlime/include/cmdlime/detail/configmacro.h:8:109: error: invalid use of ‘this’ in non-member function
    8 | #define PARAM(name, type) type name = cmdlime::detail::ParamCreator<type, std::remove_reference_t<decltype(*this)>>{*this, #name, #type, [this]()->type&{return name;}}
      |                                                                                                             ^~~~
/src/cmdlime/examples/ex01.cpp:8:9: note: in expansion of macro ‘PARAM’
    8 |         PARAM(name, std::string);
      |         ^~~~~
/src/cmdlime/include/cmdlime/detail/configmacro.h:8:99: error: template argument 1 is invalid
    8 | #define PARAM(name, type) type name = cmdlime::detail::ParamCreator<type, std::remove_reference_t<decltype(*this)>>{*this, #name, #type, [this]()->type&{return name;}}
      |                                                                                                   ^~~~~~~~
/src/cmdlime/examples/ex01.cpp:8:9: note: in expansion of macro ‘PARAM’
    8 |         PARAM(name, std::string);
      |         ^~~~~
In file included from /src/cmdlime/include/cmdlime/configreader.h:5,
                 from /src/cmdlime/include/cmdlime/gnuconfig.h:3,
                 from /src/cmdlime/include/cmdlime/config.h:2,
                 from /src/cmdlime/examples/ex01.cpp:1:
/src/cmdlime/include/cmdlime/detail/configmacro.h:12:110: error: template argument 2 is invalid
   12 | #define ARG(name, type) type name = cmdlime::detail::ArgCreator<type, std::remove_reference_t<decltype(*this)>>{*this, #name, #type, [this]()->type&{return name;}}
      |                                                                                                              ^~
/src/cmdlime/examples/ex01.cpp:7:9: note: in expansion of macro ‘ARG’
    7 |         ARG(zipCode, int);
      |         ^~~
In file included from /src/cmdlime/include/cmdlime/configreader.h:5,
                 from /src/cmdlime/include/cmdlime/gnuconfig.h:3,
                 from /src/cmdlime/include/cmdlime/config.h:2,
                 from /src/cmdlime/examples/ex01.cpp:1:
/src/cmdlime/include/cmdlime/detail/configmacro.h:8:114: error: template argument 2 is invalid
    8 | #define PARAM(name, type) type name = cmdlime::detail::ParamCreator<type, std::remove_reference_t<decltype(*this)>>{*this, #name, #type, [this]()->type&{return name;}}
      |                                                                                                                  ^~
/src/cmdlime/examples/ex01.cpp:8:9: note: in expansion of macro ‘PARAM’
    8 |         PARAM(name, std::string);
      |         ^~~~~
In file included from /src/cmdlime/include/cmdlime/detail/gnuformat.h:2,
                 from /src/cmdlime/include/cmdlime/gnuconfig.h:6,
                 from /src/cmdlime/include/cmdlime/config.h:2,
                 from /src/cmdlime/examples/ex01.cpp:1:
/src/cmdlime/include/cmdlime/detail/parser.h: In lambda function:
/src/cmdlime/include/cmdlime/detail/parser.h:68:13: warning: control reaches end of non-void function [-Wreturn-type]
   68 |             [&](auto param){
      |             ^~~~~~~~~~~~~~~~
   69 |                 switch(mode){
      |                 ~~~~~~~~~~~~~
   70 |                 case FindMode::Name:
      |                 ~~~~~~~~~~~~~~~~~~~~
   71 |                     return param->info().name() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   72 |                 case FindMode::ShortName:
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~
   73 |                     return param->info().shortName() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   74 |                 case FindMode::All:
      |                 ~~~~~~~~~~~~~~~~~~~
   75 |                     return param->info().name() == name || param->info().shortName() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   76 |                 }
      |                 ~
   77 |             });
      |             ~
/src/cmdlime/include/cmdlime/detail/parser.h: In lambda function:
/src/cmdlime/include/cmdlime/detail/parser.h:86:13: warning: control reaches end of non-void function [-Wreturn-type]
   86 |             [&](auto paramList){
      |             ^~~~~~~~~~~~~~~~~~~~
   87 |                 switch(mode){
      |                 ~~~~~~~~~~~~~
   88 |                 case FindMode::Name:
      |                 ~~~~~~~~~~~~~~~~~~~~
   89 |                     return paramList->info().name() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   90 |                 case FindMode::ShortName:
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~
   91 |                     return paramList->info().shortName() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   92 |                 case FindMode::All:
      |                 ~~~~~~~~~~~~~~~~~~~
   93 |                     return paramList->info().name() == name || paramList->info().shortName() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   94 |                 }
      |                 ~
   95 |             });
      |             ~
In file included from /src/cmdlime/include/cmdlime/detail/gnuformat.h:2,
                 from /src/cmdlime/include/cmdlime/gnuconfig.h:6,
                 from /src/cmdlime/include/cmdlime/config.h:2,
                 from /src/cmdlime/examples/ex01.cpp:1:
/src/cmdlime/include/cmdlime/detail/parser.h: In lambda function:
/src/cmdlime/include/cmdlime/detail/parser.h:123:13: warning: control reaches end of non-void function [-Wreturn-type]
  123 |             [&](auto flag){
      |             ^~~~~~~~~~~~~~~
  124 |             switch(mode){
      |             ~~~~~~~~~~~~~
  125 |                 case FindMode::Name:
      |                 ~~~~~~~~~~~~~~~~~~~~
  126 |                     return flag->info().name() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  127 |                 case FindMode::ShortName:
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~
  128 |                     return flag->info().shortName() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  129 |                 case FindMode::All:
      |                 ~~~~~~~~~~~~~~~~~~~
  130 |                     return flag->info().name() == name || flag->info().shortName() == name;
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  131 |                 }
      |                 ~
  132 |             });
      |             ~

Building with clang++ 10 on the same system seems to work. Building with MSVC (Visual Studio 2019) on Windows gives just a few warnings, so maybe I'm missing something in the g++ case:

c:\src\cmdlime\include\cmdlime\detail\parser.h(77) : warning C4715: '<lambda_d6bf33724169dfe5569812608f3db3ac>::operator()<gsl::not_null<cmdlime::detail::IParam *> >': not all control paths return a value
c:\src\cmdlime\include\cmdlime\detail\parser.h(132) : warning C4715: '<lambda_027da08a6184456737a8fd32a83f0ee3>::operator()<gsl::not_null<cmdlime::detail::IFlag *> >': not all control paths return a value
c:\src\cmdlime\include\cmdlime\detail\parser.h(95) : warning C4715: '<lambda_1cce2af26feeeaaa5a7e6c0694b00dac>::operator()<gsl::not_null<cmdlime::detail::IParamList *> >': not all control paths return a value

I haven't tried the other examples yet.

Feature Request: Load configuration parameters from config file

A common use case with command line parsing libraries is to load startup configuration parameters that were not passed on the command line from a ".env" file (simple key- value pair file) or similar.

So my feature request would be to provide support for reading parameters that were not given as command line input from a .env file and if that also fails (file not found, cant be read or key doesn't exist in the file) then fall back to the default argument / behavior registered for the argument.

Example of .env file based on Readme parameters:

zipCode=684007
name=John
verbose=true

I like the library a lot and it perfectly embraces the DRY rule for command line parsing. However in my projects I always end up having to repeat myself anyway because I need to read my environment file for every single parameter that I registered.

Add cmdlime::Format::PowerShell

All names are in PascalCase
Parameters and flags prefix: -
Short names aren't supported
Parameters usage: -Parameter value or -Parameter:value
Flags usage: -Flag
Flags can't be glued together like in POSIX format.
Default help flag: -?.

Reference

Improve validation of optional parameters

Validators for optional values should take the contained value as an argument and they shouldn't be invoked for empty values as there's nothing to validate in that case.

2do: add support for subcommands

Possible interface:

struct CommandCfg: public cmdlime::Config{
    //FLAG, PARAM, ARG, etc
};

struct Cfg : public cmdlime::Config {
    //FLAG, PARAM, ARG, etc
    COMMAND(commandName, CommandCfg); //creates std::optional<CommandCfg> commandName;
};

Add cmdlime::Format::Windows

All names are in lowercase, by default short names are used, long name can be enabled with << UseLongName{} modifier.
Parameters and flags prefix: /
Parameters usage: /parameter value or /parameter:value
Flags usage: /flag
Flags can't be glued together like in POSIX format.
Default help flag: /?.

Reference

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.