mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-13 15:29:45 +03:00
cam: options: Add option type handling to options parser
Extend the options parser with support for option types. All options must now specify the type of their argument, and the parser automatically parses the argument and handles errors internally. Available types are none, integer or string. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
6f3503981a
commit
c8c546fe99
3 changed files with 172 additions and 12 deletions
|
@ -37,10 +37,12 @@ static int parseOptions(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
OptionsParser parser;
|
OptionsParser parser;
|
||||||
|
|
||||||
parser.addOption(OptCamera, "Specify which camera to operate on",
|
parser.addOption(OptCamera, OptionString,
|
||||||
"camera", ArgumentRequired, "camera");
|
"Specify which camera to operate on", "camera",
|
||||||
parser.addOption(OptHelp, "Display this help message", "help");
|
ArgumentRequired, "camera");
|
||||||
parser.addOption(OptList, "List all cameras", "list");
|
parser.addOption(OptHelp, OptionNone, "Display this help message",
|
||||||
|
"help");
|
||||||
|
parser.addOption(OptList, OptionNone, "List all cameras", "list");
|
||||||
|
|
||||||
options = parser.parse(argc, argv);
|
options = parser.parse(argc, argv);
|
||||||
if (!options.valid())
|
if (!options.valid())
|
||||||
|
|
|
@ -12,6 +12,30 @@
|
||||||
|
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* Option
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *Option::typeName() const
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case OptionNone:
|
||||||
|
return "none";
|
||||||
|
|
||||||
|
case OptionInteger:
|
||||||
|
return "integer";
|
||||||
|
|
||||||
|
case OptionString:
|
||||||
|
return "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* OptionBase<T>
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool OptionsBase<T>::valid() const
|
bool OptionsBase<T>::valid() const
|
||||||
{
|
{
|
||||||
|
@ -25,11 +49,45 @@ bool OptionsBase<T>::isSet(const T &opt) const
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const std::string &OptionsBase<T>::operator[](const T &opt) const
|
const OptionValue &OptionsBase<T>::operator[](const T &opt) const
|
||||||
{
|
{
|
||||||
return values_.find(opt)->second;
|
return values_.find(opt)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool OptionsBase<T>::parseValue(const T &opt, const Option &option,
|
||||||
|
const char *optarg)
|
||||||
|
{
|
||||||
|
OptionValue value;
|
||||||
|
|
||||||
|
switch (option.type) {
|
||||||
|
case OptionNone:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OptionInteger:
|
||||||
|
unsigned int integer;
|
||||||
|
|
||||||
|
if (optarg) {
|
||||||
|
char *endptr;
|
||||||
|
integer = strtoul(optarg, &endptr, 10);
|
||||||
|
if (*endptr != '\0')
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
integer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = OptionValue(integer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OptionString:
|
||||||
|
value = OptionValue(optarg ? optarg : "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
values_[opt] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void OptionsBase<T>::clear()
|
void OptionsBase<T>::clear()
|
||||||
{
|
{
|
||||||
|
@ -38,8 +96,53 @@ void OptionsBase<T>::clear()
|
||||||
|
|
||||||
template class OptionsBase<int>;
|
template class OptionsBase<int>;
|
||||||
|
|
||||||
bool OptionsParser::addOption(int opt, const char *help, const char *name,
|
/* -----------------------------------------------------------------------------
|
||||||
OptionArgument argument, const char *argumentName)
|
* OptionValue
|
||||||
|
*/
|
||||||
|
|
||||||
|
OptionValue::OptionValue()
|
||||||
|
: type_(OptionNone)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionValue::OptionValue(int value)
|
||||||
|
: type_(OptionInteger), integer_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionValue::OptionValue(const char *value)
|
||||||
|
: type_(OptionString), string_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionValue::OptionValue(const std::string &value)
|
||||||
|
: type_(OptionString), string_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionValue::operator int() const
|
||||||
|
{
|
||||||
|
if (type_ != OptionInteger)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return integer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionValue::operator std::string() const
|
||||||
|
{
|
||||||
|
if (type_ != OptionString)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
return string_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* OptionsParser
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool OptionsParser::addOption(int opt, OptionType type, const char *help,
|
||||||
|
const char *name, OptionArgument argument,
|
||||||
|
const char *argumentName)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Options must have at least a short or long name, and a text message.
|
* Options must have at least a short or long name, and a text message.
|
||||||
|
@ -56,7 +159,8 @@ bool OptionsParser::addOption(int opt, const char *help, const char *name,
|
||||||
if (optionsMap_.find(opt) != optionsMap_.end())
|
if (optionsMap_.find(opt) != optionsMap_.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
options_.push_back(Option({ opt, name, argument, argumentName, help }));
|
options_.push_back(Option({ opt, type, name, argument, argumentName,
|
||||||
|
help }));
|
||||||
optionsMap_[opt] = &options_.back();
|
optionsMap_[opt] = &options_.back();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +230,13 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.values_[c] = optarg ? optarg : "";
|
const Option &option = *optionsMap_[c];
|
||||||
|
if (!options.parseValue(c, option, optarg)) {
|
||||||
|
parseValueError(option);
|
||||||
|
usage();
|
||||||
|
options.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
|
@ -193,3 +303,16 @@ void OptionsParser::usage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OptionsParser::parseValueError(const Option &option)
|
||||||
|
{
|
||||||
|
std::string optionName;
|
||||||
|
|
||||||
|
if (option.name)
|
||||||
|
optionName = "--" + std::string(option.name);
|
||||||
|
else
|
||||||
|
optionName = "-" + static_cast<char>(option.opt);
|
||||||
|
|
||||||
|
std::cerr << "Can't parse " << option.typeName()
|
||||||
|
<< " argument for option " << optionName << std::endl;
|
||||||
|
}
|
||||||
|
|
|
@ -17,8 +17,15 @@ enum OptionArgument {
|
||||||
ArgumentOptional,
|
ArgumentOptional,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum OptionType {
|
||||||
|
OptionNone,
|
||||||
|
OptionInteger,
|
||||||
|
OptionString,
|
||||||
|
};
|
||||||
|
|
||||||
struct Option {
|
struct Option {
|
||||||
int opt;
|
int opt;
|
||||||
|
OptionType type;
|
||||||
const char *name;
|
const char *name;
|
||||||
OptionArgument argument;
|
OptionArgument argument;
|
||||||
const char *argumentName;
|
const char *argumentName;
|
||||||
|
@ -26,20 +33,45 @@ struct Option {
|
||||||
|
|
||||||
bool hasShortOption() const { return isalnum(opt); }
|
bool hasShortOption() const { return isalnum(opt); }
|
||||||
bool hasLongOption() const { return name != nullptr; }
|
bool hasLongOption() const { return name != nullptr; }
|
||||||
|
const char *typeName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OptionValue;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class OptionsBase
|
class OptionsBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
bool isSet(const T &opt) const;
|
bool isSet(const T &opt) const;
|
||||||
const std::string &operator[](const T &opt) const;
|
const OptionValue &operator[](const T &opt) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class OptionsParser;
|
friend class OptionsParser;
|
||||||
std::map<T, std::string> values_;
|
|
||||||
|
bool parseValue(const T &opt, const Option &option, const char *value);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
std::map<T, OptionValue> values_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OptionValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OptionValue();
|
||||||
|
OptionValue(int value);
|
||||||
|
OptionValue(const char *value);
|
||||||
|
OptionValue(const std::string &value);
|
||||||
|
|
||||||
|
OptionType type() const { return type_; }
|
||||||
|
|
||||||
|
operator int() const;
|
||||||
|
operator std::string() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OptionType type_;
|
||||||
|
int integer_;
|
||||||
|
std::string string_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OptionsParser
|
class OptionsParser
|
||||||
|
@ -49,7 +81,8 @@ public:
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
bool addOption(int opt, const char *help, const char *name = nullptr,
|
bool addOption(int opt, OptionType type, const char *help,
|
||||||
|
const char *name = nullptr,
|
||||||
OptionArgument argument = ArgumentNone,
|
OptionArgument argument = ArgumentNone,
|
||||||
const char *argumentName = nullptr);
|
const char *argumentName = nullptr);
|
||||||
|
|
||||||
|
@ -57,6 +90,8 @@ public:
|
||||||
void usage();
|
void usage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void parseValueError(const Option &option);
|
||||||
|
|
||||||
std::list<Option> options_;
|
std::list<Option> options_;
|
||||||
std::map<unsigned int, Option *> optionsMap_;
|
std::map<unsigned int, Option *> optionsMap_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue