init
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
|
||||
# define CXX interface library
|
||||
|
||||
# define target & alias (for other projects consuming the "source-tree")
|
||||
add_library(iue-po_po INTERFACE)
|
||||
|
||||
# define sources of target
|
||||
target_sources(iue-po_po
|
||||
INTERFACE FILE_SET public_headers TYPE HEADERS BASE_DIRS ${PROJECT_SOURCE_DIR} FILES po.hpp)
|
||||
|
||||
# define installation step
|
||||
install(TARGETS iue-po_po EXPORT iue-po-export
|
||||
FILE_SET public_headers DESTINATION "./")
|
||||
|
||||
# define test
|
||||
|
||||
if(BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
|
||||
add_executable(iue-po_po.test po.test.cpp)
|
||||
target_link_libraries(iue-po_po.test iue-po_po)
|
||||
add_test(NAME iue-po_po.test COMMAND iue-po_po.test --option1 100 -option2 o2)
|
||||
endif()
|
||||
|
||||
# define C interface library
|
||||
|
||||
# define target & alias (for other projects consuming the "source-tree")
|
||||
add_library(iue-po_cpo INTERFACE)
|
||||
|
||||
# define sources of target
|
||||
target_sources(iue-po_cpo
|
||||
INTERFACE FILE_SET public_headers TYPE HEADERS BASE_DIRS ${PROJECT_SOURCE_DIR} FILES cpo.h)
|
||||
|
||||
# define installation step
|
||||
install(TARGETS iue-po_cpo EXPORT iue-po-export
|
||||
FILE_SET public_headers DESTINATION "./")
|
||||
|
||||
# define test
|
||||
|
||||
if(BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
|
||||
add_executable(iue-po_cpo.test cpo.test.c)
|
||||
target_link_libraries(iue-po_cpo.test iue-po_cpo)
|
||||
add_test(NAME iue-po_cpo.test COMMAND iue-po_cpo.test --option1 100 -option2 o2)
|
||||
endif()
|
||||
|
||||
# export targets for consuming cmake projects
|
||||
|
||||
# generate and install a .cmake file to allow dependend projects consuming the "install-tree" to import all targets
|
||||
install(EXPORT iue-po-export DESTINATION "iue-po" )
|
||||
|
||||
# allow dependend projects consuming the "build-tree" to use all targets
|
||||
export(EXPORT iue-po-export)
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h> // bool
|
||||
#include <stdio.h> // snprintf|stderr
|
||||
#include <stdlib.h> // EXIT_FAILURE|EXIT_SUCCESS
|
||||
#include <string.h> // strncmp|strlen
|
||||
|
||||
/// @brief internal function
|
||||
static bool iuepo_find_option(const char* option, const char* arg) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer) / sizeof(char), "%s%s", "-", option);
|
||||
if (strncmp(buffer, arg, strlen(buffer)) == 0)
|
||||
return true;
|
||||
snprintf(buffer, sizeof(buffer) / sizeof(char), "%s%s", "--", option);
|
||||
if (strncmp(buffer, arg, strlen(buffer)) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief internal function
|
||||
static int iuepo_count_if(const char* option, char** begin, char** end) {
|
||||
int res = 0;
|
||||
for (char** iter = begin; iter != end; ++iter) {
|
||||
if (iuepo_find_option(option, *iter))
|
||||
++res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @brief internal function
|
||||
static char** iuepo_find_if(const char* option, char** begin, char** end) {
|
||||
int res = 0;
|
||||
for (char** iter = begin; iter != end; ++iter) {
|
||||
if (iuepo_find_option(option, *iter))
|
||||
return iter;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
/// @todo Improve documentation of this enum
|
||||
enum iuepo_option { IUEPO_REQUIRED = 0, IUEPO_OPTIONAL };
|
||||
|
||||
/// @todo Improve documentation of this function
|
||||
/// @brief Optain a string option from command line arguments
|
||||
static int iuepo_get_string(int argc, char* argv[], const char* option, char* default_value, int N,
|
||||
enum iuepo_option op) {
|
||||
|
||||
int count = iuepo_count_if(option, argv + 1, argv + argc);
|
||||
|
||||
if (count == 0) {
|
||||
if (op == IUEPO_REQUIRED) {
|
||||
fprintf(stderr, "required option not provided: -/-- %s\n", option);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
fprintf(stderr, "option not unique: -/-- %s (count = %i )\n", option, count);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char** iter = iuepo_find_if(option, argv + 1, argv + argc);
|
||||
|
||||
++iter;
|
||||
|
||||
if (iter == argv + argc) {
|
||||
fprintf(stderr, "option not followed by value: -/-- %s\n", option);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (strncmp("-", *iter, 1) == 0) {
|
||||
fprintf(stderr, "option -/-- %s not followed by value but another option -/-- %s\n", option, *iter);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (snprintf(default_value, N, "%s", *iter) >= N) {
|
||||
fprintf(stderr, "provided buffer size %i for option -/-- %s not sufficient\n", N, option);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/// @todo Improve documentation of this function
|
||||
/// @brief Wrapping iuepo_get_string with a subsequent conversion
|
||||
static int iuepo_get_int(int argc, char* argv[], const char* option, int* default_value, enum iuepo_option op) {
|
||||
|
||||
char default_value_string[256] = "\0";
|
||||
snprintf(default_value_string, sizeof(default_value_string), "%i", *default_value);
|
||||
|
||||
if (iuepo_get_string(argc, argv, option, default_value_string, sizeof(default_value_string), op) == EXIT_FAILURE) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int res = sscanf(default_value_string, "%i", default_value);
|
||||
|
||||
if (res != 1) {
|
||||
fprintf(stderr, "value for option -/-- %s could not be converted\n", option);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
#include "iue-po/cpo.h"
|
||||
|
||||
#include <assert.h> // assert
|
||||
#include <stdio.h> // printf
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // strcmp
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
int value1 = 1;
|
||||
if (iuepo_get_int(argc, argv, "option1", &value1, IUEPO_REQUIRED) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
char value2[256] = "default2";
|
||||
if (iuepo_get_string(argc, argv, "option2", value2, sizeof(value2), IUEPO_REQUIRED) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
char value3[256] = "default3";
|
||||
if (iuepo_get_string(argc, argv, "option3", value3, sizeof(value3), IUEPO_OPTIONAL) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
printf("'%i'\n", value1);
|
||||
printf("'%s'\n", value2);
|
||||
printf("'%s'\n", value3);
|
||||
|
||||
assert(value1 == 100);
|
||||
assert(strcmp(value2, "o2") == 0);
|
||||
assert(strcmp(value3, "default3") == 0);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace iue::po {
|
||||
|
||||
inline std::vector<std::string> init(int argc, char* argv[]) {
|
||||
return {argv + 1, argv + argc};
|
||||
}
|
||||
|
||||
enum struct option { optional, required };
|
||||
|
||||
template <typename T>
|
||||
inline T get(std::vector<std::string> args, std::string option, T default_value, enum option op = option::optional) {
|
||||
auto find_option = [&option](const std::string& arg) -> bool {
|
||||
return arg.starts_with("-" + option) || arg.starts_with("--" + option);
|
||||
};
|
||||
const auto count = std::ranges::count_if(args, find_option);
|
||||
|
||||
if (count == 0) {
|
||||
if (op == option::required) {
|
||||
throw std::runtime_error("required option not provided: -/--" + option);
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
throw std::runtime_error("option not unique: -/--" + option + " (count = " + std::to_string(count) + ")");
|
||||
}
|
||||
|
||||
auto it = std::ranges::find_if(args, find_option);
|
||||
auto value = std::next(it);
|
||||
|
||||
if (value == args.end()) {
|
||||
throw std::runtime_error("option not followed by value: -/--" + option);
|
||||
}
|
||||
|
||||
if (value->starts_with('-')) {
|
||||
throw std::runtime_error("option -/--" + option + " not followed by value but another option -/--" + *value);
|
||||
}
|
||||
|
||||
std::istringstream ss(*value);
|
||||
ss.exceptions(std::ios::failbit);
|
||||
|
||||
T num;
|
||||
|
||||
try {
|
||||
ss >> num;
|
||||
} catch (std::exception& e) {
|
||||
throw std::runtime_error("value for option -/--" + option + " could not be converted");
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
} // namespace iue::po
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#include "iue-po/po.hpp"
|
||||
|
||||
#include <cassert> // assert
|
||||
#include <iostream> // std::cout|endl
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
auto args = iue::po::init(argc, argv);
|
||||
auto value1 = iue::po::get(args, "option1", 1, iue::po::option::required);
|
||||
auto value2 = iue::po::get(args, "option2", std::string("default2"), iue::po::option::required);
|
||||
auto value3 = iue::po::get(args, "option3", std::string("default3"));
|
||||
|
||||
std::cout << value1 << std::endl;
|
||||
std::cout << value2 << std::endl;
|
||||
std::cout << value3 << std::endl;
|
||||
|
||||
assert(value1 == 100);
|
||||
assert(value2 == "o2");
|
||||
assert(value3 == "default3");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user