Skip to content

gianluisdiana/InputParser

Repository files navigation

Input parser (for C++)

Highlights

  • Requires C++23
  • MIT License

Parser

In order to create a parser we must include the folder <parser.hpp>. To start parsing arguments create Parser object:

#include <input_parser/parser.hpp>

auto parser = input_parser::Parser();

To add new options, simply call addOption. This method receives a function that doesn't receives parameter and returns an BaseOption child (see Option Types).

parser.addOption([] {
  return input_parser::FlagOption();
});

To parse the arguments, call the method parse with the amount of arguments and the array of string. This method will throw a ParsingError if the arguments provided at the command line don't correspond to the ones described previously. A basic how to use information can be displayed calling displayUsage.

try {
  parser.parse(argc, argv);
} catch (input_parser::ParsingError& error) {
  std::cerr << error.what() << "\n";
  parser.displayUsage();
  return 1;
}

Options

This parser supports three option types: flag, single and compound.

Flags

A flag option is an option that must be placed alone. Represents a boolean value. For example:

auto flag_option = input_parser::FlagOption("-v", "--verbose")
  .addDescription("Whether if the program will display the output or not")
  .addDefaultValue(false);
auto parser = input_parser::Parser()
  .addOption([flag_option] {
    return flag_option;
  });

try {
  parser.parse(argc, argv);
} catch (input_parser::ParsingError& error) {
  std::cerr << error.what() << "\n";
  parser.displayUsage();
  return 1;
}

const bool verbose = parser.getValue<bool>("-v");
if (verbose) std::cout << "Hello World!\n";

And we can execute the code:

$ ./a.out

$ ./a.out -v
Hello World!

$ ./a.out --verbose
Hello World!
  • Default value

    The option manage default values different from the others two: if an option has a default value but the program is called with the flag activated, the value to be assigned will the opposite of the default. Look at this example:

    auto parser = input_parser::Parser()
      .addOption([] {
        return input_parser::FlagOption("-v", "--verbose")
          .addDescription("Whether if the program will display information or not")
          .addDefaultValue(true);
      });
    parser.parse(argc, argv);
    if (parser.getValue<bool>("-v")) std::cout << "Really important information!\n";

    We can call the program like this:

    $ ./a.out
    Really important information!
    
    $ ./a.out -v
    
  • Transformation

    Using a flag option allows you to create a different type value from a boolean. For example:

    auto parser = input_parser::Parser()
      .addOption([] {
        return input_parser::FlagOption("-g", "--greeting")
          .addDescription("Whether if the program will say hi or bye")
          .addDefaultValue(false)
          .to<std::string>([](const bool& value) -> std::string {
            return value ? "Hi!" : "Bye!";
          });
      });
    parser.parse(argc, argv);
    std::cout << parser.getValue<std::string>("-g") << '\n';

    When executing the code, the string displayed will depend:

    $ ./a.out
    Bye!
    
    $ ./a.out -g
    Hi!
    
    $ ./a.out --greeting
    Hi!

Singles

A single option is an option that must be placed with an extra argument. Originally is stored as a std::string. For example:

auto parser = input_parser::Parser()
  .addOption([] {
    return input_parser::SingleOption("-n")
      .addDescription("The name of the person using this program");
  });

parser.parse(argc, argv);
std::cout << parser.getValue<std::string>("-n") << " is using this program!\n";

And we can execute the code:

$ ./a.out
terminate called after throwing an instance of 'input_parser::ParsingError'
  what():  Missing option -n
Aborted

$ ./a.out -n
terminate called after throwing an instance of 'input_parser::ParsingError'
  what():  After the -n option should be an extra argument!
Aborted

$ ./a.out -n Luke
Luke is using this program!

Compounds

A compound option is an option that must be placed with at least one extra argument. It stores its values on a std::vectorstd::string. Here's an example:

auto parser = input_parser::Parser()
  .addOption([] {
    return input_parser::CompoundOption("-n", "--numbers")
      .addDescription("The numbers to be added together")
      .toDouble();
  });

parser.parse(argc, argv);

double result = 0;
for (auto& number : parser.getValue<std::vector<double>>("-n")) {
  result += number;
}
std::cout << "The sum of the number is: " << result << '\n';

And when executed, we get the following output:

$ ./a.out
terminate called after throwing an instance of 'input_parser::ParsingError'
  what():  Missing option -n
Aborted

$ ./a.out -n
terminate called after throwing an instance of 'input_parser::ParsingError'
  what():  After the -n option should be at least an extra argument!
Aborted

$ ./a.out -n 1 2
The sum of the number is: 3

$ ./a.out -n 1 2.201 3.4 -4
The sum of the number is: 2.601
  • Transformation (each element)

    This options allows the user to provide a callback function that will be applied to each of the elements stored using the elementsTo method. The callback provided must have one std::string parameter and return variable with the type desired.

    auto parser = input_parser::Parser()
      .addOption([] {
        return input_parser::CompoundOption("--approves")
          .addDescription("A group of y's and n's that will be counted")
          .elementsTo<bool>([](const std::string& element) {
            return element == "y" || element == "Y";
          });
      });
    
    parser.parse(argc, argv);
    
    int amount = 0;
    for (const auto approve : parser.getValue<std::vector<bool>>("--approves")) {
      amount += (approve ? 1 : 0);
    }
    std::cout << "There are " << amount << " people that approves\n";

    We can execute the code and get the following results:

    $ ./a.out --approves y n y y n n Y
    There are 4 people that approves
  • Transformation (all vector)

    It also brings the possibility of transforming all the set calling the to method.

    struct Coordinate {
      int x;
      int y;
    };
    
    auto parser = input_parser::Parser()
      .addOption([] {
        return input_parser::CompoundOption("-c", "--coordinate")
          .addDescription("The coordinate of a point (x, y)")
          .to<Coordinate>([](const std::vector<std::string>& value) {
            return Coordinate{
              std::stoi(value[0]), std::stoi(value[1])
            };
          });
      });
    
    parser.parse(argc, argv);
    auto [x, y] = parser.getValue<Coordinate>("-c");
    std::cout << "The coordinates are (" << x << ", " << y << ")\n";

    And as we can see, the Coordinate struct is created:

    $ ./my_project -c 1.3 3
    The coordinate are (1, 3)
    
    $ ./my_project -c -213 123
    The coordinate are (-213, 123)

CMake Integration

Just clone the repository and add these lines to your CMakeLists.txt file.

cmake_minimum_required(VERSION 3.22)

PROJECT(my_project)
add_executable(my_project src/main.cpp)

target_link_libraries(${PROJECT_NAME} input_parser)
add_subdirectory(InputParser)

Fetching the repository

Another way to integrate this library is by using the FetchContent module. Just add these lines to your CMakeLists.txt file.

cmake_minimum_required(VERSION 3.22)

PROJECT(my_project)

include(FetchContent)

FetchContent_Declare(
  input_parser
  URL https://github.com/gianluisdiana/InputParser/releases/download/0.4.1/InputParser.zip)
FetchContent_MakeAvailable(input_parser)

add_executable(my_project src/main.cpp)

target_link_libraries(${PROJECT_NAME} input_parser)

About

C++ command line parser

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors