Page MenuHomec4science

parser.cpp
No OneTemporary

File Metadata

Created
Sun, Jun 23, 22:43

parser.cpp

/* =============================================================================
Copyright (c) 2014 - 2016
F. Georget <fabieng@princeton.edu> Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
============================================================================= */
#include "parser.hpp"
#include "specmicp_common/compat.hpp"
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>
namespace specmicp {
namespace cli {
template <ValueType T>
struct ValueTypeStr{};
template <>
struct ValueTypeStr<ValueType::boolean>
{
constexpr static const char* str = "boolean";
};
template <>
struct ValueTypeStr<ValueType::integer>
{
constexpr static const char* str = "integer";
};
template <>
struct ValueTypeStr<ValueType::floating>
{
constexpr static const char* str = "double";
};
template <>
struct ValueTypeStr<ValueType::string>
{
constexpr static const char* str = "string";
};
//! \brief Runtime value conversion
std::string value_type_str(ValueType val_type)
{
if (val_type == ValueType::boolean) {
return "boolean";
} else if (val_type == ValueType::integer) {
return "integer";
} else if (val_type == ValueType::floating) {
return "double";
} else if (val_type == ValueType::string) {
return "string";
} else {
throw std::runtime_error("Invalid type !");
}
}
struct SPECMICP_DLL_LOCAL OptionValue
{
union numerical {
bool boolean;
int integer;
double floating;
};
numerical num;
std::string str;
// getter
template <typename T>
T get() const {}
template <ValueType T>
auto get() const -> typename ValueTypeConversion<T>::type
{
return get<typename ValueTypeConversion<T>::type>();
}
// setter
template <typename T>
void set(T value) {}
template <ValueType T>
void set(typename ValueTypeConversion<T>::type value) {
set(value);
}
void set_from_string(const std::string& value, ValueType value_type) {
switch (value_type) {
case ValueType::boolean:
if (value == "True" or
value == "true" or
value == "ON" or
value == "on")
num.boolean = true;
else
num.boolean = false;
break;
case ValueType::integer:
num.integer = std::stoi(value);
break;
case ValueType::floating:
num.floating = std::stod(value);
break;
case ValueType::string:
str = value;
break;
}
}
};
#ifndef SPC_DOXYGEN_SHOULD_SKIP_THIS
template <>
bool OptionValue::get<bool>() const {
return num.boolean;
}
template <>
int OptionValue::get<int>() const {
return num.integer;
}
template <>
double OptionValue::get<double>() const {
return num.floating;
}
template <>
std::string OptionValue::get<std::string>() const {
return str;
}
template <>
void OptionValue::set<bool>(bool value) {
num.boolean = value;
}
template <>
void OptionValue::set<int>(int value) {
num.integer = value;
}
template<>
void OptionValue::set<double>(double value) {
num.floating = value;
}
template<>
void OptionValue::set<std::string>(std::string value) {
str = value;
}
#endif // SPC_DOXYGEN_SHOULD_SKIP_THIS
//! \internal
//! \brief The different types that a value can solve
//!
//! To allow a straigthforward use of the union, only a pointer
//! to the string is stored, the actual string must be stored elsewhere
//union SPECMICP_DLL_LOCAL OptionValue
//{
// bool boolean;
// int integer;
// double floating_number;
// std::string* str;
// OptionValue():
// str(nullptr)
// {}
//};
//! \internal
//! \brief Base class for an option
struct SPECMICP_DLL_LOCAL BaseOption
{
BaseOption(
ValueType type_value,
const std::string& help):
is_required(true),
value_type(type_value),
help_message(help)
{}
BaseOption(
ValueType type_value,
const std::string& help,
OptionValue default_value
):
is_required(false),
value_type(type_value),
help_message(help),
value(default_value)
{}
template <ValueType T>
auto get() -> typename ValueTypeConversion<T>::type
{
if (T != value_type) {
throw std::runtime_error("Wrong type, got " +
value_type_str(value_type) +
" expected " +
ValueTypeStr<T>::str);
}
return value.get<T>();
}
bool is_required;
bool is_set {false};
ValueType value_type;
std::string help_message;
OptionValue value;
};
//! \internal
//! \brief A positional argument
struct SPECMICP_DLL_LOCAL PositionalArgument: public BaseOption
{
PositionalArgument(const std::string& arg_name,
ValueType type_value,
const std::string& help
):
BaseOption(type_value, help),
name(arg_name)
{}
std::string name;
};
//! \internal
//! \brief An option
//!
//! An option value is precedented by a flag (starting with '--' pr '-')
//! In case of a boolean, only the flag is necessary, the value is implicetely
//! true
//!
struct SPECMICP_DLL_LOCAL SwitchArgument: public BaseOption
{
SwitchArgument(char the_short_flag,
const std::string& the_long_flag,
ValueType value_type,
OptionValue default_value,
const std::string& help_message
):
BaseOption(value_type, help_message, default_value),
short_flag(the_short_flag),
long_flag(the_long_flag)
{}
SwitchArgument(char the_short_flag,
const std::string& the_long_flag,
ValueType value_type,
const std::string& help_message
):
BaseOption(value_type, help_message),
short_flag(the_short_flag),
long_flag(the_long_flag)
{}
char short_flag;
std::string long_flag;
};
//! \internal
//! \brief Implementation details for the Command line parser
struct SPECMICP_DLL_LOCAL CommandLineParser::CommandLineParserImpl
{
//! \brief Option : <flag,value>
using str_option = std::pair<std::string, std::string>;
//! \brief Type of the list of options
using list_switch_option = std::vector<SwitchArgument>;
//! \brief Type of the list of positional argument
using list_pos_argument = std::vector<PositionalArgument>;
//! \brief Type of the index in a list of argument
using size_type = list_pos_argument::size_type;
//! \brief Type of a list of unparsed options
using raw_list_option = std::vector<std::string>;
CommandLineParserImpl() {
}
//! \brief Set the values of the options
void set_list_str_option(const raw_list_option& options);
//! \brief Check the values of the options/arguments
bool check_values();
//! \brief Check the values of the positional arguments
bool check_pos_arguments();
//! \brief Check the values of the options
bool check_options();
//! \brief Return the index of a short option
//!
//! Return -1 if the option does not exist
int get_short_option_index(char flag) noexcept;
//! \brief Return the index of a long option
//!
//! Return -1 if the option does not exist
int get_long_option_index(const std::string& flag) noexcept;
//! \brief Return the index of a long option
//!
//! \throw runtime_error if the option does not exist
size_t get_safe_long_option_index(const std::string& flag);
//! \brief Return the index of a positional argument
//!
//! \throw runtime error if the option does not exist
size_t get_safe_pos_argument_index(const std::string& name);
//! \brief Parse a boolean option activated by its short flag
size_t analyse_boolean_short_option(size_t ind, char opts);
//! \brief Parse an option activated by its short flag
size_t analyse_short_option(size_t ind, const raw_list_option& options, char opts);
//! \brief Parse an option activated by its long flag
size_t analyse_long_option(size_t ind, const raw_list_option& options, const std::string& opts);
//! \brief Parse a positional argument
size_t analyse_pos_argument(size_t ind, const std::string& arg_value);
//! \brief Return the index of the next free positional argument
//!
//! Return -1 if no such argument exists
int next_free_pos_arg() noexcept;
//! \brief Return a value that can be stored inside an option
//!
//! \tparam T true C++ type of the type
//! \param value the value to set
//! \param value_type the type of the option
OptionValue set_value(bool val, ValueType value_type) {
OptionValue value;
if (value_type != ValueType::boolean) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(value_type) +
" got boolean");
}
value.set<bool>(val);
return value;
}
OptionValue set_value(int val, ValueType value_type) {
OptionValue value;
if (value_type != ValueType::integer) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(value_type) +
" got integer");
}
value.set<int>(val);
return value;
}
OptionValue set_value(double val, ValueType value_type) {
OptionValue value;
if (value_type != ValueType::floating) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(value_type) +
" got integer");
}
value.set<double>(val);
return value;
}
OptionValue set_value(const std::string& val, ValueType value_type) {
OptionValue value;
if (value_type != ValueType::string) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(value_type) +
" got string");
}
value.set<std::string>(val);
return value;
}
//! \brief Set the value of the option
void set_option(BaseOption& arg, const std::string& value) {
arg.value.set_from_string(value, arg.value_type);
arg.is_set = true;
}
//! \brief Set the value of the option
void set_option(BaseOption& arg, bool value) {
if (arg.value_type != ValueType::boolean) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(arg.value_type) +
" got boolean");
}
arg.value.set<bool>(value);
arg.is_set = true;
}
//! \brief Set the value of the option
void set_option(BaseOption& arg, int value) {
if (arg.value_type != ValueType::integer) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(arg.value_type) +
" got integer");
}
arg.value.set<int>(value);
arg.is_set = true;
}
//! \brief Set the value of the option
void set_option(BaseOption& arg, double value) {
if (arg.value_type != ValueType::floating) {
throw std::runtime_error("Wrong type : expected "
+ value_type_str(arg.value_type) +
" got double");
}
arg.value.set<double>(value);
arg.is_set = true;
}
template <ValueType T>
auto get_option(
const std::string& long_flag
) -> typename ValueTypeConversion<T>::type
{
const size_t ind = get_safe_long_option_index(long_flag);
return m_list_opt[ind].get<T>();
}
template <ValueType T>
auto get_pos_argument(
const std::string& name
) -> typename ValueTypeConversion<T>::type
{
const size_t ind = get_safe_pos_argument_index(name);
return m_list_args[ind].get<T>();
}
//! \print the help message
void print_help_message();
std::string m_name {"<program name>"}; //!< Name of the program
std::string m_help_msg {"<no help message defined>"}; //! Global help message
list_switch_option m_list_opt; //!< List of options
list_pos_argument m_list_args; //!< List of positional argument
};
//! \name simple_predicator
//! \brief simple functions to chech the type of a string in argv
//!
//! \internal
//! @{
inline bool is_non_null(const std::string& option) {
return (option.length() > 0);
}
inline bool is_flag(const std::string& option) {
return (is_non_null(option) && option[0] == '-');
}
inline bool is_value(const std::string& option) {
return (is_non_null(option) && option[0] != '-');
}
inline bool is_short_flag(const std::string& option) {
return (is_flag(option) && option.length() >= 2 and option[1] != '-');
}
inline bool is_unique_short_flag(const std::string& option) {
return (is_flag(option) && option.length() == 2 and option[1] != '-');
}
inline bool is_same_short_flag(const std::string& option, char flag) {
return (is_unique_short_flag(option) and option['1'] == flag);
}
inline bool is_multiple_short_flags(const std::string& option) {
return (is_short_flag(option) and option.length() > 2);
}
inline bool is_long_flag(const std::string& option) {
return (is_flag(option) and option.length() > 2 and option[1] == '-');
}
inline bool is_same_long_flag(const std::string& option,
const std::string& flag) {
return (is_long_flag(option) and
(option.length()-2) == flag.length() and
option.substr(2, option.length()-2) == flag
);
}
//! @}
//! \brief A pair of <key,value> for an option
using option_value_t = std::pair<std::string, std::string>;
//! \brief Split a long option in a pair<option,value> (if = sign in it)
option_value_t SPECMICP_DLL_LOCAL split_long_option(const std::string& opts);
//! \brief Split a short option
std::vector<char> SPECMICP_DLL_LOCAL split_short_options(const std::string& opts);
// Definition of main functions
CommandLineParser::CommandLineParser():
m_impl(make_unique<CommandLineParserImpl>())
{
}
CommandLineParser::~CommandLineParser()
{}
// Getter / Setter
// ==============
// /!\ templated code : needs to be in that order to
// avoid instanciation of a specialization before we define it
// CommandLineParser::get_option
// -----------------------------
#ifndef SPC_DOXYGEN_SHOULD_SKIP_THIS
template <>
auto CommandLineParser::get_option<ValueType::boolean>(
const std::string& long_flag
) -> typename ValueTypeConversion<ValueType::boolean>::type
{
return m_impl->get_option<ValueType::boolean>(long_flag);
}
template <>
auto CommandLineParser::get_option<ValueType::integer>(
const std::string& long_flag
) -> typename ValueTypeConversion<ValueType::integer>::type
{
return m_impl->get_option<ValueType::integer>(long_flag);
}
template <>
auto CommandLineParser::get_option<ValueType::floating>(
const std::string& long_flag
) -> typename ValueTypeConversion<ValueType::floating>::type
{
return m_impl->get_option<ValueType::floating>(long_flag);
}
template <>
auto CommandLineParser::get_option<ValueType::string>(
const std::string& long_flag
) -> typename ValueTypeConversion<ValueType::string>::type
{
return m_impl->get_option<ValueType::string>(long_flag);
}
// CommandLineParser.get_pos_argument
// -----------------------------------
template <>
auto CommandLineParser::get_pos_argument<ValueType::boolean>(
const std::string& name
) -> typename ValueTypeConversion<ValueType::boolean>::type
{
return m_impl->get_pos_argument<ValueType::boolean>(name);
}
template <>
auto CommandLineParser::get_pos_argument<ValueType::integer>(
const std::string& name
) -> typename ValueTypeConversion<ValueType::integer>::type
{
return m_impl->get_pos_argument<ValueType::integer>(name);
}
template <>
auto CommandLineParser::get_pos_argument<ValueType::floating>(
const std::string& name
) -> typename ValueTypeConversion<ValueType::floating>::type
{
return m_impl->get_pos_argument<ValueType::floating>(name);
}
template <>
auto CommandLineParser::get_pos_argument<ValueType::string>(
const std::string& name
) -> typename ValueTypeConversion<ValueType::string>::type
{
return m_impl->get_pos_argument<ValueType::string>(name);
}
#endif // SPC_DOXYGEN_SHOULD_SKIP_THIS
//! \brief Obtain the value from an option
template <typename T>
T
get_value(const OptionValue& u_value, ValueType value_type)
{
T value;
switch (value_type) {
case ValueType::boolean:
value = u_value.get<ValueType::boolean>();
break;
case ValueType::integer:
value = u_value.get<ValueType::integer>();
break;
case ValueType::floating:
value = u_value.get<ValueType::floating>();
break;
case ValueType::string:
value = u_value.get<ValueType::string>();
break;
}
return value;
}
// Add options and positional arguments
// ====================================
void CommandLineParser::add_option(
char short_flag,
const std::string& long_flag,
ValueType value_type,
const std::string& help_message
)
{
m_impl->m_list_opt.emplace_back(
short_flag, long_flag, value_type, help_message);
}
void CommandLineParser::add_option(
char short_flag,
const std::string& long_flag,
int default_value,
const std::string& help_message
)
{
m_impl->m_list_opt.emplace_back(
short_flag, long_flag,
ValueType::integer,
m_impl->set_value(default_value, ValueType::integer),
help_message);
}
void CommandLineParser::add_option(
char short_flag,
const std::string& long_flag,
double default_value,
const std::string& help_message
)
{
m_impl->m_list_opt.emplace_back(
short_flag, long_flag,
ValueType::floating,
m_impl->set_value(default_value, ValueType::floating),
help_message
);
}
void CommandLineParser::add_option(
char short_flag,
const std::string& long_flag,
bool default_value,
const std::string& help_message
)
{
m_impl->m_list_opt.emplace_back(
short_flag, long_flag,
ValueType::boolean,
m_impl->set_value(default_value, ValueType::boolean),
help_message
);
}
void CommandLineParser::add_option(
char short_flag,
const std::string& long_flag,
const std::string& default_value,
const std::string& help_message
)
{
m_impl->m_list_opt.emplace_back(
short_flag, long_flag,
ValueType::string,
m_impl->set_value(default_value, ValueType::string),
help_message
);
}
void CommandLineParser::add_pos_argument(
const std::string& name,
ValueType value_type,
const std::string& help_message
)
{
m_impl->m_list_args.emplace_back(name, value_type, help_message);
}
// Parsing
// =======
int CommandLineParser::parse(const std::vector<std::string>& opts)
{
add_option('h', "help", false, "Print the help message");
m_impl->set_list_str_option(opts);
if (get_option<ValueType::boolean>("help"))
{ // if help we bypass
m_impl->print_help_message();
return 1;
}
else {
m_impl->check_values();
return 0;
}
}
int CommandLineParser::parse(int argc, char* argv[])
{
// register program name
register_program_name(std::string(argv[0]));
// first build the list of options
std::vector<std::string> opts;
opts.reserve(argc);
for (int i=1; i<argc; ++i) opts.emplace_back(std::string(argv[i]));
// then parse them
return parse(opts);
}
// Usage
// =====
void CommandLineParser::register_program_name(std::string&& name)
{
m_impl->m_name = name;
}
void CommandLineParser::set_help_message(std::string&& help_msg)
{
m_impl->m_help_msg = help_msg;
}
void CommandLineParser::CommandLineParserImpl::print_help_message()
{
std::stringstream msg;
msg << "Usage : " << m_name << " [Options]";
for (auto& arg: m_list_args) {
msg << " <" + arg.name + ">";
}
msg << "\n\n" << m_help_msg;
msg << "\n\n Positional arguments :\n-----------------------\n";
for (auto& arg: m_list_args) {
msg << "\t" << arg.name << " : " << arg.help_message << "\n";
}
msg << "\n Options :\n----------\n";
for (auto& opt: m_list_opt) {
if (opt.value_type == ValueType::boolean) {
msg << "\t -" << opt.short_flag << ", --" << opt.long_flag
<< " : " << opt.help_message << "\n";
}
else {
msg << "\t -" << opt.short_flag << " <value>"
<< ", --" << opt.long_flag << "=<value>"
<< " : " << opt.help_message << "\n";
}
}
std::cout << msg.str();
}
// Check values and options
// ========================
bool CommandLineParser::CommandLineParserImpl::check_values()
{
bool retcode = check_pos_arguments();
retcode = retcode and check_options();
return retcode;
}
bool CommandLineParser::CommandLineParserImpl::check_pos_arguments()
{
size_t expected = m_list_args.size();
size_t provided = 0;
for (auto& arg: m_list_args)
{
if (arg.is_set) ++provided;
}
if (provided != expected) {
throw std::runtime_error("Missing (a) positional argument(s) :"
"expected : " + std::to_string(expected) +
" , provided : " + std::to_string(provided) +
"."
);
}
return true;
}
bool CommandLineParser::CommandLineParserImpl::check_options()
{
for (auto& opt: m_list_opt)
{
if ((opt.is_required) and (not opt.is_set)) {
throw std::runtime_error("Missing required option : '"
+ opt.long_flag + "'.");
}
}
return true;
}
// Parse the list of argument
// ==========================
void CommandLineParser::CommandLineParserImpl::set_list_str_option(
const std::vector<std::string>& options
)
{
if (options.size() < 1) return;
m_list_opt.reserve(options.size());
for (size_type ind=0; ind<options.size();) {
// empty argument
std::string opt = options[ind];
if (opt[0] == '\0') {++ind; continue;}
// positional argument
if (opt[0] != '-') {
ind = analyse_pos_argument(ind, opt);
continue;
}
if (opt[1] != '-') {
// short option
auto sopts = split_short_options(opt);
if (sopts.size() == 1)
{
// only one option
ind = analyse_short_option(ind, options, sopts[0]);
}
else
{
// several options
for (auto it: sopts)
{
analyse_boolean_short_option(ind, it);
}
++ind;
}
continue;
}
else
{
// long option
ind = analyse_long_option(ind, options, opt);
continue;
}
}
}
size_t CommandLineParser::CommandLineParserImpl::analyse_pos_argument(
size_t ind,
const std::string& arg_value
)
{
int inda = next_free_pos_arg();
if (inda < 0) {
throw std::runtime_error("Too many positional arguments, expected : "
+ std::to_string(m_list_args.size())
+ ".");
}
auto& the_option = m_list_args[static_cast<size_type>(inda)];
set_option(the_option, arg_value);
return ++ind;
}
size_t CommandLineParser::CommandLineParserImpl::analyse_short_option(
size_t ind, const raw_list_option& options, char opt)
{
int option_index = get_short_option_index(opt);
if (option_index < 0) {
std::string msg = "Error : unknown option '";
msg.push_back(opt);
msg += "'.";
throw std::runtime_error(msg);
}
SwitchArgument& the_option = m_list_opt[option_index];
ValueType vtype = the_option.value_type;
if (vtype == ValueType::boolean) {
set_option(the_option, true);
++ind;
}
else {
if (ind > 0 and ind >= options.size()-1) {
throw std::runtime_error(
"Missing an argument for option : "
+ the_option.long_flag
);
}
std::string next_value = std::string(options[ind+1]);
if (not is_value(next_value)) {
throw std::runtime_error
("Missing an argument for option : "
+ the_option.long_flag
);
}
ind += 2;
set_option(the_option, next_value);
}
return ind;
}
size_t CommandLineParser::CommandLineParserImpl::analyse_long_option(
size_t ind, const raw_list_option& option, const std::string& opt)
{
option_value_t pair = split_long_option(opt);
int option_index = get_long_option_index(pair.first);
SwitchArgument& the_option = m_list_opt[option_index];
ValueType vtype = the_option.value_type;
if (pair.second.size() > 0)
{
set_option(the_option, pair.second);
++ind;
return ind;
}
if (vtype == ValueType::boolean) {
if (pair.second.size() > 0)
set_option(the_option, pair.second);
else
set_option(the_option, true);
++ind;
}
else {
if (ind >= option.size()) {
throw std::runtime_error(
"Missing an argument for option : "
+ the_option.long_flag
);
}
std::string next_value = std::string(option[ind+1]);
if (not is_value(next_value)) {
throw std::runtime_error(
"Missing an argument for option : "
+ the_option.long_flag
);
}
set_option(the_option, next_value);
ind = ind+2;
}
return ind;
}
size_t CommandLineParser::CommandLineParserImpl::analyse_boolean_short_option(
size_t ind, char option)
{
int option_index = get_short_option_index(option);
if (option_index < 0) {
std::string msg = "Error : unknown option '";
msg.push_back(option);
msg += "'.";
throw std::runtime_error(msg);
}
SwitchArgument& the_option = m_list_opt[option_index];
ValueType vtype = the_option.value_type;
if (vtype != ValueType::boolean) {
throw std::runtime_error(
"Error, expected boolean for option "
+ the_option.long_flag
);
}
set_option(the_option, true);
return ind;
}
// Indexes of options
// ==================
int
CommandLineParser::CommandLineParserImpl::get_short_option_index(char flag)
noexcept
{
int ind = -1;
for (auto it=m_list_opt.begin();it!=m_list_opt.end();++it)
{
if (it->short_flag == flag)
{
ind = it - m_list_opt.begin();
break;
}
}
return ind;
}
int
CommandLineParser::CommandLineParserImpl::get_long_option_index(
const std::string& flag)
noexcept
{
int ind = -1;
for (auto it=m_list_opt.begin();it!=m_list_opt.end();++it)
{
if (it->long_flag == flag)
{
ind = it - m_list_opt.begin();
break;
}
}
return ind;
}
size_t CommandLineParser::CommandLineParserImpl::get_safe_long_option_index(
const std::string& long_flag)
{
int ind = get_long_option_index(long_flag);
if (ind == -1) {
throw std::runtime_error("No such option : " + long_flag);
}
return static_cast<size_type>(ind);
}
int CommandLineParser::CommandLineParserImpl::next_free_pos_arg()
noexcept
{
int ind = -1;
for (auto it=m_list_args.begin(); it!=m_list_args.end(); ++it)
{
if (! (*it).is_set) {
ind = it - m_list_args.begin();
break;
}
}
return ind;
}
size_t CommandLineParser::CommandLineParserImpl::get_safe_pos_argument_index(
const std::string& name
)
{
int ind = -1;
for (auto it=m_list_args.begin(); it!=m_list_args.end(); ++it) {
if (name == (*it).name) {
ind = it - m_list_args.begin();
break;
}
}
if (ind < 0) {
throw std::runtime_error("Unknow positional argument : " + name);
}
return static_cast<size_t>(ind);
}
// Split options
// =============
// remove '-' for short and '--' for long options
// also split long options if they are in the form 'opt=value'
option_value_t split_long_option(const std::string& opts)
{
option_value_t val;
auto it = std::find(opts.begin(), opts.end(), '=');
// no equal sign
if (it == opts.end()) {
val.first = opts.substr(2, std::string::npos);
}
// equal sign
else {
std::string::size_type len_before = it - opts.begin();
val.first = opts.substr(2, len_before-2);
if (opts.size() > len_before) { // if there is something after
val.second = opts.substr(len_before+1, std::string::npos);
}
}
return val;
}
std::vector<char> split_short_options(const std::string& opts)
{
std::vector<char> shortopts;
shortopts.reserve(opts.size()-1);
for (size_t i=1; i<opts.size(); ++i)
{
shortopts.emplace_back(opts[i]);
}
return shortopts;
}
} //end namespace cli
} //end namespace specmicp

Event Timeline