summaryrefslogtreecommitdiff
path: root/src/cam/options.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cam/options.cpp')
-rw-r--r--src/cam/options.cpp537
1 files changed, 0 insertions, 537 deletions
diff --git a/src/cam/options.cpp b/src/cam/options.cpp
deleted file mode 100644
index 2c56eacf..00000000
--- a/src/cam/options.cpp
+++ /dev/null
@@ -1,537 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * options.cpp - cam - Options parsing
- */
-
-#include <assert.h>
-#include <getopt.h>
-#include <iomanip>
-#include <iostream>
-#include <string.h>
-
-#include "options.h"
-
-/* -----------------------------------------------------------------------------
- * Option
- */
-
-const char *Option::typeName() const
-{
- switch (type) {
- case OptionNone:
- return "none";
-
- case OptionInteger:
- return "integer";
-
- case OptionString:
- return "string";
-
- case OptionKeyValue:
- return "key=value";
- }
-
- return "unknown";
-}
-
-/* -----------------------------------------------------------------------------
- * OptionBase<T>
- */
-
-template<typename T>
-bool OptionsBase<T>::empty() const
-{
- return values_.empty();
-}
-
-template<typename T>
-bool OptionsBase<T>::valid() const
-{
- return valid_;
-}
-
-template<typename T>
-bool OptionsBase<T>::isSet(const T &opt) const
-{
- return values_.find(opt) != values_.end();
-}
-
-template<typename T>
-const OptionValue &OptionsBase<T>::operator[](const T &opt) const
-{
- 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, 0);
- if (*endptr != '\0')
- return false;
- } else {
- integer = 0;
- }
-
- value = OptionValue(integer);
- break;
-
- case OptionString:
- value = OptionValue(optarg ? optarg : "");
- break;
-
- case OptionKeyValue:
- KeyValueParser *kvParser = option.keyValueParser;
- KeyValueParser::Options keyValues = kvParser->parse(optarg);
- if (!keyValues.valid())
- return false;
-
- value = OptionValue(keyValues);
- break;
- }
-
- if (option.isArray)
- values_[opt].addValue(value);
- else
- values_[opt] = value;
-
- return true;
-}
-
-template class OptionsBase<int>;
-template class OptionsBase<std::string>;
-
-/* -----------------------------------------------------------------------------
- * KeyValueParser
- */
-
-bool KeyValueParser::addOption(const char *name, OptionType type,
- const char *help, OptionArgument argument)
-{
- if (!name)
- return false;
- if (!help || help[0] == '\0')
- return false;
- if (argument != ArgumentNone && type == OptionNone)
- return false;
-
- /* Reject duplicate options. */
- if (optionsMap_.find(name) != optionsMap_.end())
- return false;
-
- optionsMap_[name] = Option({ 0, type, name, argument, nullptr,
- help, nullptr, false });
- return true;
-}
-
-KeyValueParser::Options KeyValueParser::parse(const char *arguments)
-{
- Options options;
-
- for (const char *pair = arguments; *arguments != '\0'; pair = arguments) {
- const char *comma = strchrnul(arguments, ',');
- size_t len = comma - pair;
-
- /* Skip over the comma. */
- arguments = *comma == ',' ? comma + 1 : comma;
-
- /* Skip to the next pair if the pair is empty. */
- if (!len)
- continue;
-
- std::string key;
- std::string value;
-
- const char *separator = static_cast<const char *>(memchr(pair, '=', len));
- if (!separator) {
- key = std::string(pair, len);
- value = "";
- } else {
- key = std::string(pair, separator - pair);
- value = std::string(separator + 1, comma - separator - 1);
- }
-
- /* The key is mandatory, the value might be optional. */
- if (key.empty())
- continue;
-
- if (optionsMap_.find(key) == optionsMap_.end()) {
- std::cerr << "Invalid option " << key << std::endl;
- return options;
- }
-
- OptionArgument arg = optionsMap_[key].argument;
- if (value.empty() && arg == ArgumentRequired) {
- std::cerr << "Option " << key << " requires an argument"
- << std::endl;
- return options;
- } else if (!value.empty() && arg == ArgumentNone) {
- std::cerr << "Option " << key << " takes no argument"
- << std::endl;
- return options;
- }
-
- const Option &option = optionsMap_[key];
- if (!options.parseValue(key, option, value.c_str())) {
- std::cerr << "Failed to parse '" << value << "' as "
- << option.typeName() << " for option " << key
- << std::endl;
- return options;
- }
- }
-
- options.valid_ = true;
- return options;
-}
-
-void KeyValueParser::usage(int indent)
-{
- unsigned int space = 0;
-
- for (auto const &iter : optionsMap_) {
- const Option &option = iter.second;
- unsigned int length = 14;
- if (option.argument != ArgumentNone)
- length += 1 + strlen(option.typeName());
- if (option.argument == ArgumentOptional)
- length += 2;
-
- if (length > space)
- space = length;
- }
-
- space = (space + 7) / 8 * 8;
-
- for (auto const &iter : optionsMap_) {
- const Option &option = iter.second;
- std::string argument = option.name;
-
- if (option.argument != ArgumentNone) {
- if (option.argument == ArgumentOptional)
- argument += "[=";
- else
- argument += "=";
- argument += option.typeName();
- if (option.argument == ArgumentOptional)
- argument += "]";
- }
-
- std::cerr << std::setw(indent) << std::right << " "
- << std::setw(space) << std::left << argument;
-
- for (const char *help = option.help, *end = help; end;) {
- end = strchr(help, '\n');
- if (end) {
- std::cerr << std::string(help, end - help + 1);
- std::cerr << std::setw(indent + space) << " ";
- help = end + 1;
- } else {
- std::cerr << help << std::endl;
- }
- }
- }
-}
-
-/* -----------------------------------------------------------------------------
- * OptionValue
- */
-
-OptionValue::OptionValue()
- : type_(ValueNone), integer_(0)
-{
-}
-
-OptionValue::OptionValue(int value)
- : type_(ValueInteger), integer_(value)
-{
-}
-
-OptionValue::OptionValue(const char *value)
- : type_(ValueString), integer_(0), string_(value)
-{
-}
-
-OptionValue::OptionValue(const std::string &value)
- : type_(ValueString), integer_(0), string_(value)
-{
-}
-
-OptionValue::OptionValue(const KeyValueParser::Options &value)
- : type_(ValueKeyValue), integer_(0), keyValues_(value)
-{
-}
-
-void OptionValue::addValue(const OptionValue &value)
-{
- assert(type_ == ValueNone || type_ == ValueArray);
-
- type_ = ValueArray;
- array_.push_back(value);
-}
-
-OptionValue::operator int() const
-{
- return toInteger();
-}
-
-OptionValue::operator std::string() const
-{
- return toString();
-}
-
-OptionValue::operator KeyValueParser::Options() const
-{
- return toKeyValues();
-}
-
-OptionValue::operator std::vector<OptionValue>() const
-{
- return toArray();
-}
-
-int OptionValue::toInteger() const
-{
- if (type_ != ValueInteger)
- return 0;
-
- return integer_;
-}
-
-std::string OptionValue::toString() const
-{
- if (type_ != ValueString)
- return std::string();
-
- return string_;
-}
-
-KeyValueParser::Options OptionValue::toKeyValues() const
-{
- if (type_ != ValueKeyValue)
- return KeyValueParser::Options();
-
- return keyValues_;
-}
-
-std::vector<OptionValue> OptionValue::toArray() const
-{
- if (type_ != ValueArray)
- return std::vector<OptionValue>{};
-
- return array_;
-}
-
-/* -----------------------------------------------------------------------------
- * OptionsParser
- */
-
-bool OptionsParser::addOption(int opt, OptionType type, const char *help,
- const char *name, OptionArgument argument,
- const char *argumentName, bool array)
-{
- /*
- * Options must have at least a short or long name, and a text message.
- * If an argument is accepted, it must be described by argumentName.
- */
- if (!isalnum(opt) && !name)
- return false;
- if (!help || help[0] == '\0')
- return false;
- if (argument != ArgumentNone && !argumentName)
- return false;
-
- /* Reject duplicate options. */
- if (optionsMap_.find(opt) != optionsMap_.end())
- return false;
-
- options_.push_back(Option({ opt, type, name, argument, argumentName,
- help, nullptr, array }));
- optionsMap_[opt] = &options_.back();
- return true;
-}
-
-bool OptionsParser::addOption(int opt, KeyValueParser *parser, const char *help,
- const char *name, bool array)
-{
- if (!addOption(opt, OptionKeyValue, help, name, ArgumentRequired,
- "key=value[,key=value,...]", array))
- return false;
-
- options_.back().keyValueParser = parser;
- return true;
-}
-
-OptionsParser::Options OptionsParser::parse(int argc, char **argv)
-{
- OptionsParser::Options options;
-
- /*
- * Allocate short and long options arrays large enough to contain all
- * options.
- */
- char shortOptions[options_.size() * 3 + 2];
- struct option longOptions[options_.size() + 1];
- unsigned int ids = 0;
- unsigned int idl = 0;
-
- shortOptions[ids++] = ':';
-
- for (const Option &option : options_) {
- if (option.hasShortOption()) {
- shortOptions[ids++] = option.opt;
- if (option.argument != ArgumentNone)
- shortOptions[ids++] = ':';
- if (option.argument == ArgumentOptional)
- shortOptions[ids++] = ':';
- }
-
- if (option.hasLongOption()) {
- longOptions[idl].name = option.name;
-
- switch (option.argument) {
- case ArgumentNone:
- longOptions[idl].has_arg = no_argument;
- break;
- case ArgumentRequired:
- longOptions[idl].has_arg = required_argument;
- break;
- case ArgumentOptional:
- longOptions[idl].has_arg = optional_argument;
- break;
- }
-
- longOptions[idl].flag = 0;
- longOptions[idl].val = option.opt;
- idl++;
- }
- }
-
- shortOptions[ids] = '\0';
- memset(&longOptions[idl], 0, sizeof(longOptions[idl]));
-
- opterr = 0;
-
- while (true) {
- int c = getopt_long(argc, argv, shortOptions, longOptions, nullptr);
-
- if (c == -1)
- break;
-
- if (c == '?' || c == ':') {
- if (c == '?')
- std::cerr << "Invalid option ";
- else
- std::cerr << "Missing argument for option ";
- std::cerr << argv[optind - 1] << std::endl;
-
- usage();
- return options;
- }
-
- const Option &option = *optionsMap_[c];
- if (!options.parseValue(c, option, optarg)) {
- parseValueError(option);
- usage();
- return options;
- }
- }
-
- options.valid_ = true;
- return options;
-}
-
-void OptionsParser::usage()
-{
- std::cerr << "Options:" << std::endl;
-
- unsigned int indent = 0;
-
- for (const Option &option : options_) {
- unsigned int length = 14;
- if (option.hasLongOption())
- length += 2 + strlen(option.name);
- if (option.argument != ArgumentNone)
- length += 1 + strlen(option.argumentName);
- if (option.argument == ArgumentOptional)
- length += 2;
- if (option.isArray)
- length += 4;
-
- if (length > indent)
- indent = length;
- }
-
- indent = (indent + 7) / 8 * 8;
-
- for (const Option &option : options_) {
- std::string argument;
- if (option.hasShortOption())
- argument = std::string(" -")
- + static_cast<char>(option.opt);
- else
- argument = " ";
-
- if (option.hasLongOption()) {
- if (option.hasShortOption())
- argument += ", ";
- else
- argument += " ";
- argument += std::string("--") + option.name;
- }
-
- if (option.argument != ArgumentNone) {
- if (option.argument == ArgumentOptional)
- argument += "[=";
- else
- argument += " ";
- argument += option.argumentName;
- if (option.argument == ArgumentOptional)
- argument += "]";
- }
-
- if (option.isArray)
- argument += " ...";
-
- std::cerr << std::setw(indent) << std::left << argument;
-
- for (const char *help = option.help, *end = help; end; ) {
- end = strchr(help, '\n');
- if (end) {
- std::cerr << std::string(help, end - help + 1);
- std::cerr << std::setw(indent) << " ";
- help = end + 1;
- } else {
- std::cerr << help << std::endl;
- }
- }
-
- if (option.keyValueParser)
- option.keyValueParser->usage(indent);
- }
-}
-
-void OptionsParser::parseValueError(const Option &option)
-{
- std::string optionName;
-
- if (option.name)
- optionName = "--" + std::string(option.name);
- else
- optionName = "-" + std::string(1, option.opt);
-
- std::cerr << "Can't parse " << option.typeName()
- << " argument for option " << optionName << std::endl;
-}