Scoping out ArgsParser class.
This commit is contained in:
31
CMakeLists.txt
Normal file
31
CMakeLists.txt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.18...3.28)
|
||||||
|
project(ArgsParser
|
||||||
|
VERSION 1.0
|
||||||
|
LANGUAGES CXX)
|
||||||
|
|
||||||
|
if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
||||||
|
message(FATAL_ERROR "In-source builds are not allowed!")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HEADERS "include/*.hpp")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||||
|
|
||||||
|
include_directories("include")
|
||||||
|
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
add_library(ArgsParser SHARED ${SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
add_library(ArgsParser STATIC ${SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(args_demo main.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(args_demo PUBLIC ArgsParser)
|
85
include/ArgsParser.hpp
Normal file
85
include/ArgsParser.hpp
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct FlagInfo {
|
||||||
|
std::string canonical_name;
|
||||||
|
bool expects_arg;
|
||||||
|
std::optional<std::string> arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A class that provides a convenient interface for parsing commands.
|
||||||
|
class ArgsParser {
|
||||||
|
public:
|
||||||
|
/// Constructor from traditional argc, argv
|
||||||
|
ArgsParser(int argc, char** argv, bool keep_program_name = false);
|
||||||
|
|
||||||
|
/// @return True if there is another unconsumed token in the argument list.
|
||||||
|
bool has_next() const;
|
||||||
|
|
||||||
|
/// Retrieves then next unconsumed token in the argument list.
|
||||||
|
/// @return The next token in the argument list.
|
||||||
|
std::string get_next() const;
|
||||||
|
|
||||||
|
std::string consume_next();
|
||||||
|
|
||||||
|
/// Constructor from an existing vector of strings,
|
||||||
|
explicit ArgsParser(const std::vector<std::string>& value): args(value) {}
|
||||||
|
|
||||||
|
bool has_flag(const std::string& option);
|
||||||
|
|
||||||
|
bool has_flag(const std::initializer_list<std::string>& flags);
|
||||||
|
|
||||||
|
/// Searches the arguments for all given flag tokens, and removes all occurrences of it.
|
||||||
|
/// @return true if the flag was found in the arguments.
|
||||||
|
bool consume_flag(const std::string& option);
|
||||||
|
|
||||||
|
|
||||||
|
/// Searches the arguments for all given flag tokens, and removes them.
|
||||||
|
/// @return True if the flag was found in the arguments.
|
||||||
|
bool consume_flag(const std::initializer_list<std::string>& flags);
|
||||||
|
|
||||||
|
/// Searches for a specific flag and its argument.
|
||||||
|
bool has_flag_arg(const std::string& option);
|
||||||
|
|
||||||
|
/// Retrieves the argument for the given flag.
|
||||||
|
std::optional<std::string> get_flag_arg(const std::string& option);
|
||||||
|
|
||||||
|
/// Searches for a specific flag and its argument, removes both, and returns the argument.
|
||||||
|
std::optional<std::string> consume_flag_arg(const std::string& flag);
|
||||||
|
|
||||||
|
std::tuple<bool, std::string> consume_flag_arg(const std::initializer_list<std::string>& flags);
|
||||||
|
|
||||||
|
std::vector<std::string> get_remaining_args() const;
|
||||||
|
|
||||||
|
std::vector<std::string> get_unmatched() const { return get_remaining_args(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool contains(const std::string& token) const;
|
||||||
|
bool has_flag_contains(const std::string& match);
|
||||||
|
|
||||||
|
std::optional<std::string> get_flag_contains(std::string& match) {
|
||||||
|
for (auto& token : args) {
|
||||||
|
if (token.find(match) != std::string::npos)
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_flag_starts_with(const std::string& value) const;
|
||||||
|
std::string get_flag_starts_with(const std::string& prefix) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// The list of arguments that have yet to be consumed.
|
||||||
|
std::vector<std::string> args{};
|
||||||
|
/// The full list of arguments originally passed to the instance. This vector will not be modified.
|
||||||
|
std::vector<std::string> original_args{};
|
||||||
|
private:
|
||||||
|
};
|
37
main.cpp
Normal file
37
main.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <ArgsParser.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
|
std::vector<std::string> arguments (argv, argv+argc);
|
||||||
|
|
||||||
|
|
||||||
|
for (auto& entry : arguments) {
|
||||||
|
std::cout << entry << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
ArgsParser args(argc, argv);
|
||||||
|
args.consume_next(); // Consume file-name.
|
||||||
|
|
||||||
|
if (args.has_flag("--help")) {
|
||||||
|
std::cout << "Help information displayed here!" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& entry : args.get_remaining_args()) {
|
||||||
|
std::cout << entry << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
while (args.has_next()) {
|
||||||
|
std::string token = args.consume_next();
|
||||||
|
|
||||||
|
std::cout << token << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
106
src/ArgsParser.cpp
Normal file
106
src/ArgsParser.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include <ArgsParser.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
ArgsParser::ArgsParser(int argc, char **argv, bool keep_program_name) {
|
||||||
|
args = std::vector<std::string>(argv, argv+argc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::has_next() const {
|
||||||
|
return !args.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ArgsParser::get_next() const {
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ArgsParser::consume_next() {
|
||||||
|
std::string value = args[0];
|
||||||
|
|
||||||
|
args.erase(args.begin());
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::has_flag(const std::string &option) {
|
||||||
|
return std::ranges::find(args, option) != args.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::has_flag(const std::initializer_list<std::string> &flags) {
|
||||||
|
for (auto& flag : flags)
|
||||||
|
if (has_flag(flag))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::consume_flag(const std::string &option) {
|
||||||
|
if (has_flag(option)) {
|
||||||
|
args.erase(std::remove(args.begin(), args.end(), option), args.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::consume_flag(const std::initializer_list<std::string> &flags) {
|
||||||
|
bool had_any_flag = false;
|
||||||
|
for (auto& flag : flags) {
|
||||||
|
if (has_flag(flags)) {
|
||||||
|
had_any_flag = true;
|
||||||
|
args.erase(std::remove(args.begin(), args.end(), flag), args.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return had_any_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::has_flag_arg(const std::string &option) {
|
||||||
|
if (has_flag(option)) {
|
||||||
|
auto it = std::ranges::find(args, option);
|
||||||
|
return it!=args.end() && ++it!=args.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<std::string> ArgsParser::get_flag_arg(const std::string &option) {
|
||||||
|
auto it = std::ranges::find(args, option);
|
||||||
|
++it;
|
||||||
|
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> ArgsParser::consume_flag_arg(const std::string &flag) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<bool, std::string> ArgsParser::consume_flag_arg(const std::initializer_list<std::string> &flags) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ArgsParser::get_remaining_args() const {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::has_flag_contains(const std::string &match) {
|
||||||
|
for (auto& token : args) {
|
||||||
|
if (token.find(match) != std::string::npos)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArgsParser::has_flag_starts_with(const std::string &value) const {
|
||||||
|
for (auto& token : args) {
|
||||||
|
if (token.starts_with(value))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ArgsParser::get_flag_starts_with(const std::string &prefix) const {
|
||||||
|
for (auto& token : this->args) {
|
||||||
|
if (token.starts_with(prefix))
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user