diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-01-22 05:03:54 +0200 |
---|---|---|
committer | Niklas Söderlund <niklas.soderlund@ragnatech.se> | 2019-01-22 14:04:09 +0100 |
commit | f5e48ebf447ec15ba653fa3524e9b9de8e5eb736 (patch) | |
tree | 8b0b926612198fffa218e77a6d557f539aafc44f /src/cam | |
parent | fba3d0460750fb4123d66f55315dbd9b34cc3d90 (diff) |
cam: Extract option parser to separate file
And turn it into an OptionsParser object.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Diffstat (limited to 'src/cam')
-rw-r--r-- | src/cam/cam.cpp | 144 | ||||
-rw-r--r-- | src/cam/main.cpp | 85 | ||||
-rw-r--r-- | src/cam/meson.build | 3 | ||||
-rw-r--r-- | src/cam/options.cpp | 192 | ||||
-rw-r--r-- | src/cam/options.h | 62 |
5 files changed, 341 insertions, 145 deletions
diff --git a/src/cam/cam.cpp b/src/cam/cam.cpp deleted file mode 100644 index 0f795be7..00000000 --- a/src/cam/cam.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * main.cpp - cam-ctl a tool to interact with the library - */ - -#include <getopt.h> -#include <iomanip> -#include <iostream> -#include <map> -#include <string.h> - -#include <libcamera/libcamera.h> - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -using namespace std; -using namespace libcamera; - -enum Option { - OptCamera = 'c', - OptHelp = 'h', - OptList = 'l', - OptLast = 0, -}; - -struct OptionInfo { - Option id; - const char *name; - const char *arguments; - const char *description; -}; - -static struct OptionInfo option_info[] = { - { OptCamera, "camera", "<camera>", "Specify which camera to operate on" }, - { OptHelp, "help", nullptr, "Display this help message" }, - { OptList, "list", nullptr, "List all cameras" }, - { OptLast, nullptr, nullptr, nullptr }, -}; - -std::map<Option, std::string> options; - -void usage() -{ - struct OptionInfo *info; - - cout << "Options:" << endl; - for (info = option_info; info->id != OptLast; info++) { - string arg(info->name); - - if (info->arguments) - arg += string(" ") + info->arguments; - - cout << " -" << static_cast<char>(info->id) << " --" << - setw(20) << left << arg << " - " << - info->description << endl; - } -} - -int parseOptions(int argc, char **argv) -{ - char short_options[ARRAY_SIZE(option_info) * 2 + 1]; - struct option long_options[ARRAY_SIZE(option_info)]; - struct OptionInfo *info; - unsigned ids = 0, idl = 0; - - memset(short_options, 0, sizeof(short_options)); - memset(long_options, 0, sizeof(long_options)); - - for (info = option_info; info->id != OptLast; info++) { - short_options[ids++] = info->id; - if (info->arguments) - short_options[ids++] = ':'; - - long_options[idl].name = info->name; - long_options[idl].has_arg = - info->arguments ? required_argument : no_argument; - long_options[idl].flag = 0; - long_options[idl].val = info->id; - idl++; - } - - while (true) { - int c = getopt_long(argc, argv, short_options, long_options, nullptr); - - if (c == -1) - break; - - if (!isalpha(c)) - return EXIT_FAILURE; - - options[static_cast<Option>(c)] = optarg ? string(optarg) : ""; - } - - return 0; -} - -bool optSet(Option opt) -{ - return options.count(opt) != 0; -} - -int main(int argc, char **argv) -{ - int ret; - - ret = parseOptions(argc, argv); - if (ret == EXIT_FAILURE) - return ret; - - if (argc == 1 || optSet(OptHelp)) { - usage(); - return 0; - } - - CameraManager *cm = CameraManager::instance(); - - ret = cm->start(); - if (ret) { - cout << "Failed to start camera manager: " << strerror(-ret) << endl; - return EXIT_FAILURE; - } - - if (optSet(OptList)) { - cout << "Available cameras:" << endl; - for (const std::shared_ptr<Camera> &camera : cm->cameras()) - cout << "- " << camera->name() << endl; - } - - if (optSet(OptCamera)) { - std::shared_ptr<Camera> cam = cm->get(options[OptCamera]); - - if (cam) { - cout << "Using camera " << cam->name() << endl; - } else { - cout << "Camera " << options[OptCamera] << " not found" << endl; - } - } - - cm->stop(); - - return 0; -} diff --git a/src/cam/main.cpp b/src/cam/main.cpp new file mode 100644 index 00000000..22211670 --- /dev/null +++ b/src/cam/main.cpp @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * main.cpp - cam - The libcamera swiss army knife + */ + +#include <iostream> +#include <map> +#include <string.h> + +#include <libcamera/libcamera.h> + +#include "options.h" + +using namespace libcamera; + +OptionsParser::Options options; + +enum { + OptCamera = 'c', + OptHelp = 'h', + OptList = 'l', +}; + +static int parseOptions(int argc, char *argv[]) +{ + OptionsParser parser; + + parser.addOption(OptCamera, "Specify which camera to operate on", + "camera", OptionsParser::ArgumentRequired, + "camera"); + parser.addOption(OptHelp, "Display this help message", "help"); + parser.addOption(OptList, "List all cameras", "list"); + + options = std::move(parser.parse(argc, argv)); + if (!options.valid()) + return -EINVAL; + + if (argc == 1 || options.isSet(OptHelp)) { + parser.usage(); + return 1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int ret; + + ret = parseOptions(argc, argv); + if (ret < 0) + return EXIT_FAILURE; + + CameraManager *cm = CameraManager::instance(); + + ret = cm->start(); + if (ret) { + std::cout << "Failed to start camera manager: " + << strerror(-ret) << std::endl; + return EXIT_FAILURE; + } + + if (options.isSet(OptList)) { + std::cout << "Available cameras:" << std::endl; + for (const std::shared_ptr<Camera> &camera : cm->cameras()) + std::cout << "- " << camera->name() << std::endl; + } + + if (options.isSet(OptCamera)) { + std::shared_ptr<Camera> cam = cm->get(options[OptCamera]); + + if (cam) { + std::cout << "Using camera " << cam->name() << std::endl; + } else { + std::cout << "Camera " << options[OptCamera] + << " not found" << std::endl; + } + } + + cm->stop(); + + return 0; +} diff --git a/src/cam/meson.build b/src/cam/meson.build index 809a40e0..e45e5391 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -1,5 +1,6 @@ cam_sources = files([ - 'cam.cpp', + 'main.cpp', + 'options.cpp', ]) cam = executable('cam', cam_sources, diff --git a/src/cam/options.cpp b/src/cam/options.cpp new file mode 100644 index 00000000..d391a0e5 --- /dev/null +++ b/src/cam/options.cpp @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * options.cpp - cam - Options parsing + */ + +#include <getopt.h> +#include <iomanip> +#include <iostream> +#include <string.h> + +#include "options.h" + +void OptionsParser::addOption(int opt, 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. + * If an argument is accepted, it must be described by argumentName. + */ + if (!isalnum(opt) && !name) + return; + if (!help || help[0] == '\0') + return; + if (argument != ArgumentNone && !argumentName) + return; + + /* Reject duplicate options. */ + if (optionsMap_.find(opt) != optionsMap_.end()) + return; + + options_.push_back(Option({ opt, name, argument, argumentName, help })); + optionsMap_[opt] = &options_.back(); +} + +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++; + } + } + + 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(); + options.clear(); + break; + } + + options.values_[c] = optarg ? optarg : ""; + } + + return std::move(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 (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) { + argument += std::string(" "); + if (option.argument == ArgumentOptional) + argument += "["; + argument += option.argumentName; + if (option.argument == ArgumentOptional) + argument += "]"; + } + + std::cerr << std::setw(indent) << std::left << argument; + std::cerr << option.help << std::endl; + } +} + +OptionsParser::Options::Options() +{ +} + +OptionsParser::Options::Options(Options &&other) + : values_(std::move(other.values_)) +{ +} + +OptionsParser::Options &OptionsParser::Options::operator=(Options &&other) +{ + values_ = other.values_; + return *this; +} + +bool OptionsParser::Options::valid() const +{ + return !values_.empty(); +} + +bool OptionsParser::Options::isSet(int opt) const +{ + return values_.find(opt) != values_.end(); +} + +const std::string &OptionsParser::Options::operator[](int opt) const +{ + return values_.find(opt)->second; +} + +void OptionsParser::Options::clear() +{ + values_.clear(); +} diff --git a/src/cam/options.h b/src/cam/options.h new file mode 100644 index 00000000..88336dfe --- /dev/null +++ b/src/cam/options.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * options.h - cam - Options parsing + */ +#ifndef __CAM_OPTIONS_H__ +#define __CAM_OPTIONS_H__ + +#include <ctype.h> +#include <map> +#include <vector> + +class OptionsParser +{ +public: + enum OptionArgument { + ArgumentNone, + ArgumentRequired, + ArgumentOptional, + }; + + class Options { + public: + Options(); + Options(Options &&other); + Options &operator=(Options &&other); + + bool valid() const; + bool isSet(int opt) const; + const std::string &operator[](int opt) const; + + private: + friend class OptionsParser; + std::map<int, std::string> values_; + void clear(); + }; + + void addOption(int opt, const char *help, const char *name = nullptr, + OptionArgument argument = ArgumentNone, + const char *argumentName = nullptr); + + Options parse(int argc, char *argv[]); + void usage(); + +private: + struct Option { + int opt; + const char *name; + OptionArgument argument; + const char *argumentName; + const char *help; + + bool hasShortOption() const { return isalnum(opt); } + bool hasLongOption() const { return name != nullptr; } + }; + + std::vector<Option> options_; + std::map<unsigned int, Option *> optionsMap_; +}; + +#endif /* __CAM_OPTIONS_H__ */ |