/CheckedCmd

This is a command line parser library which is typed an checked.

Primary LanguageC++Boost Software License 1.0BSL-1.0

Build Status Build status

CheckedCmd

This is a command line parser library which is typed an checked. It makes use of Clara to do all the hard work behind the scenes.

it does the following:

  • creates a tuple of the passed types or takes a tuple by value,
  • assigns the parsed values to each of the tuple members
  • calls the checks for each of them
  • and returns std::optional<std::tuple<...>>

The caller does not need to use mutable variables.

The parser needs distinct types as input.

using CmdHasHeadLine   = CheckedCmd::Flag<HasHeadLine>;                //optional  
using CmdOutputFile    = CheckedCmd::Param<std::optional<OutputFile>>; //optional
using CmdExcelRowLimit = CheckedCmd::Param<std::optional<ExcelRow>>;
using CmdTableName     = CheckedCmd::Param<TableName>;                //required
using CmdInputFile     = CheckedCmd::Arg<InputFile>;                  //required
using CmdOptArg        = CheckedCmd::Arg<std::optional<std::string>>; //optional

These types need to be default constructable and provide an overload for

std::istream& operator>>(std::istream&, type&);

This library provides a convenient way to create distinct types. Please have a look in the testing source code.

We need to provide callables for range checks for each type:

bool OutputFileValidator(OutputFile const &outputFile) {
    return outputFile.Get().size() < 6;
}

bool InputFileValidator(InputFile const &inputFile) {
    return inputFile.Get().size() < 100;
}

bool RowLimitValidator(ExcelRow const &excelRow) {
    return (excelRow.Get() > 0);
}

bool TableNameValidator(TableName const &tableName) {
    return (tableName.Get().size() < 5);
}

auto const NoChecks = [](auto const &) { return true; };

Now the input gets parsed without introducing state. ParseCmd returns a std::optional<std::tuple<...>>:

auto args = detail::CopyToArgs({"prgname", "-l 2",  "-H", "-h", "file.csv", "file1.csv", "string"});
auto argv = detail::IntoPtrs(args);
auto argc = args.size();
// The lines above are used for testing only
// please have a look in the testing source code

auto const success = ParseCmd(argc, argv
                        ,CmdHasHeadLine(ShortName("-H")
                                        ,LongName("--HasHeadLine")
                                        ,Description("lol")
                                       )
                        ,CmdOutputFile(Hint("filename")
                                       ,ShortName("-o")
                                       ,LongName("--OutPutFile")
                                       ,Description("")
                                       ,OutputFileValidator
                                      )
                        ,CmdInputFile(Hint("inputfile")
                                      ,Description("lol")
                                      ,InputFileValidator
                                     )
                        ,CmdSecondInputFile(Hint("outputfile")
                                            ,Description("lol")
                                            ,NoChecks
                                           )
                        ,CmdOptArg(Hint("CmdOptArg")
                                   ,Description("lol")
                                   ,NoChecks
                                  )
                        ,CmdExcelRowLimit(Hint("1..65535")
                                         ,ShortName("-l")
                                         ,LongName("--LineLimit")
                                         ,Description(R"(If option "-H" is set, the minimum allowed value is 2.)")
                                         ,RowLimitValidator
                                        )
                        ,CheckedCmd::Help()
);

The parsed values can be accessed by:

if (success.has_value()) {
    auto parsed_args = success.value();
    CHECK_EQ ( InputFile("file.csv"),     std::get<CmdInputFile>(parsed_args).value());
    CHECK_EQ ( SecInputFile("file1.csv"), std::get<CmdSecondInputFile>(parsed_args).value());
    CHECK_EQ ( HasHeadLine(true),         std::get<CmdHasHeadLine>(parsed_args).value());
    CHECK_EQ ( OutputFile("lol"),         std::get<CmdOutputFile>(parsed_args).value_or(OutputFile("lol")));
    CHECK_EQ ( true,                      std::get<CheckedCmd::Help>(parsed_args).value());
    CHECK_EQ ( true,                      std::get<CmdOptArg>(parsed_args).value().has_value());
}

If parsing or one of the checks fail, the returned value is std::nullopt.