Show a patch.

GET /api/1.1/patches/466/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 466,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/466/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/466/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20190131234721.22606-7-laurent.pinchart@ideasonboard.com>",
    "date": "2019-01-31T23:47:19",
    "name": "[libcamera-devel,v2,6/8] cam: options: Add option type handling to options parser",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "5360409a6256c559c1b55e20e7801aeac2e5194d",
    "submitter": {
        "id": 2,
        "url": "https://patchwork.libcamera.org/api/1.1/people/2/?format=api",
        "name": "Laurent Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/466/mbox/",
    "series": [
        {
            "id": 158,
            "url": "https://patchwork.libcamera.org/api/1.1/series/158/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=158",
            "date": "2019-01-31T23:47:13",
            "name": "cam: add --format option to configure a stream",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/158/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/466/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/466/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<laurent.pinchart@ideasonboard.com>",
        "Received": [
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7C61260DB4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  1 Feb 2019 00:47:43 +0100 (CET)",
            "from pendragon.ideasonboard.com (85-76-34-136-nat.elisa-mobile.fi\n\t[85.76.34.136])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 36D1241;\n\tFri,  1 Feb 2019 00:47:42 +0100 (CET)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1548978463;\n\tbh=vXZzvIz+Axn3txmhex/kTxdYxpSLb3ePcyuwFyMtAJo=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=RHn3dwiL0LNjKRmjHSlC3DJ0VMZCFvrsZH8g/9wtz96fGZF5iFTowYwCx/vJMzmKh\n\t175V/e67cPyYLyBPKLnRDLbt6JT5Op53Z/k4S+WstHUSo3TqySPWiEY6sV+nwNcsL5\n\t/OWAG4hlX99nR7mQkoQPsQlh5E9c5/Y8Y7kOUxIY=",
        "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri,  1 Feb 2019 01:47:19 +0200",
        "Message-Id": "<20190131234721.22606-7-laurent.pinchart@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.19.2",
        "In-Reply-To": "<20190131234721.22606-1-laurent.pinchart@ideasonboard.com>",
        "References": "<20190131234721.22606-1-laurent.pinchart@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v2 6/8] cam: options: Add option type\n\thandling to options parser",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.23",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "X-List-Received-Date": "Thu, 31 Jan 2019 23:47:43 -0000"
    },
    "content": "Extend the options parser with support for option types. All options\nmust now specify the type of their argument, and the parser\nautomatically parses the argument and handles errors internally.\nAvailable types are none, integer or string.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/cam/main.cpp    |  10 ++--\n src/cam/options.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++--\n src/cam/options.h   |  41 +++++++++++++-\n 3 files changed, 172 insertions(+), 12 deletions(-)",
    "diff": "diff --git a/src/cam/main.cpp b/src/cam/main.cpp\nindex bde47a8f1798..7934d0bf4132 100644\n--- a/src/cam/main.cpp\n+++ b/src/cam/main.cpp\n@@ -37,10 +37,12 @@ static int parseOptions(int argc, char *argv[])\n {\n \tOptionsParser parser;\n \n-\tparser.addOption(OptCamera, \"Specify which camera to operate on\",\n-\t\t\t \"camera\", ArgumentRequired, \"camera\");\n-\tparser.addOption(OptHelp, \"Display this help message\", \"help\");\n-\tparser.addOption(OptList, \"List all cameras\", \"list\");\n+\tparser.addOption(OptCamera, OptionString,\n+\t\t\t \"Specify which camera to operate on\", \"camera\",\n+\t\t\t ArgumentRequired, \"camera\");\n+\tparser.addOption(OptHelp, OptionNone, \"Display this help message\",\n+\t\t\t \"help\");\n+\tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n \n \toptions = parser.parse(argc, argv);\n \tif (!options.valid())\ndiff --git a/src/cam/options.cpp b/src/cam/options.cpp\nindex c13022ce1b84..204081f3cd8e 100644\n--- a/src/cam/options.cpp\n+++ b/src/cam/options.cpp\n@@ -12,6 +12,30 @@\n \n #include \"options.h\"\n \n+/* -----------------------------------------------------------------------------\n+ * Option\n+ */\n+\n+const char *Option::typeName() const\n+{\n+\tswitch (type) {\n+\tcase OptionNone:\n+\t\treturn \"none\";\n+\n+\tcase OptionInteger:\n+\t\treturn \"integer\";\n+\n+\tcase OptionString:\n+\t\treturn \"string\";\n+\t}\n+\n+\treturn \"unknown\";\n+}\n+\n+/* -----------------------------------------------------------------------------\n+ * OptionBase<T>\n+ */\n+\n template <typename T>\n bool OptionsBase<T>::valid() const\n {\n@@ -25,11 +49,45 @@ bool OptionsBase<T>::isSet(const T &opt) const\n }\n \n template <typename T>\n-const std::string &OptionsBase<T>::operator[](const T &opt) const\n+const OptionValue &OptionsBase<T>::operator[](const T &opt) const\n {\n \treturn values_.find(opt)->second;\n }\n \n+template <typename T>\n+bool OptionsBase<T>::parseValue(const T &opt, const Option &option,\n+\t\t\t\tconst char *optarg)\n+{\n+\tOptionValue value;\n+\n+\tswitch (option.type) {\n+\tcase OptionNone:\n+\t\tbreak;\n+\n+\tcase OptionInteger:\n+\t\tunsigned int integer;\n+\n+\t\tif (optarg) {\n+\t\t\tchar *endptr;\n+\t\t\tinteger = strtoul(optarg, &endptr, 10);\n+\t\t\tif (*endptr != '\\0')\n+\t\t\t\treturn false;\n+\t\t} else {\n+\t\t\tinteger = 0;\n+\t\t}\n+\n+\t\tvalue = OptionValue(integer);\n+\t\tbreak;\n+\n+\tcase OptionString:\n+\t\tvalue = OptionValue(optarg ? optarg : \"\");\n+\t\tbreak;\n+\t}\n+\n+\tvalues_[opt] = value;\n+\treturn true;\n+}\n+\n template <typename T>\n void OptionsBase<T>::clear()\n {\n@@ -38,8 +96,53 @@ void OptionsBase<T>::clear()\n \n template class OptionsBase<int>;\n \n-bool OptionsParser::addOption(int opt, const char *help, const char *name,\n-\t\t\t      OptionArgument argument, const char *argumentName)\n+/* -----------------------------------------------------------------------------\n+ * OptionValue\n+ */\n+\n+OptionValue::OptionValue()\n+\t: type_(OptionNone)\n+{\n+}\n+\n+OptionValue::OptionValue(int value)\n+\t: type_(OptionInteger), integer_(value)\n+{\n+}\n+\n+OptionValue::OptionValue(const char *value)\n+\t: type_(OptionString), string_(value)\n+{\n+}\n+\n+OptionValue::OptionValue(const std::string &value)\n+\t: type_(OptionString), string_(value)\n+{\n+}\n+\n+OptionValue::operator int() const\n+{\n+\tif (type_ != OptionInteger)\n+\t\treturn 0;\n+\n+\treturn integer_;\n+}\n+\n+OptionValue::operator std::string() const\n+{\n+\tif (type_ != OptionString)\n+\t\treturn std::string();\n+\n+\treturn string_;\n+}\n+\n+/* -----------------------------------------------------------------------------\n+ * OptionsParser\n+ */\n+\n+bool OptionsParser::addOption(int opt, OptionType type, const char *help,\n+\t\t\t      const char *name, OptionArgument argument,\n+\t\t\t      const char *argumentName)\n {\n \t/*\n \t * Options must have at least a short or long name, and a text message.\n@@ -56,7 +159,8 @@ bool OptionsParser::addOption(int opt, const char *help, const char *name,\n \tif (optionsMap_.find(opt) != optionsMap_.end())\n \t\treturn false;\n \n-\toptions_.push_back(Option({ opt, name, argument, argumentName, help }));\n+\toptions_.push_back(Option({ opt, type, name, argument, argumentName,\n+\t\t\t\t    help }));\n \toptionsMap_[opt] = &options_.back();\n \treturn true;\n }\n@@ -126,7 +230,13 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)\n \t\t\tbreak;\n \t\t}\n \n-\t\toptions.values_[c] = optarg ? optarg : \"\";\n+\t\tconst Option &option = *optionsMap_[c];\n+\t\tif (!options.parseValue(c, option, optarg)) {\n+\t\t\tparseValueError(option);\n+\t\t\tusage();\n+\t\t\toptions.clear();\n+\t\t\tbreak;\n+\t\t}\n \t}\n \n \treturn options;\n@@ -193,3 +303,16 @@ void OptionsParser::usage()\n \t\t}\n \t}\n }\n+\n+void OptionsParser::parseValueError(const Option &option)\n+{\n+\tstd::string optionName;\n+\n+\tif (option.name)\n+\t\toptionName = \"--\" + std::string(option.name);\n+\telse\n+\t\toptionName = \"-\" + static_cast<char>(option.opt);\n+\n+\tstd::cerr << \"Can't parse \" << option.typeName()\n+\t\t  << \" argument for option \" << optionName << std::endl;\n+}\ndiff --git a/src/cam/options.h b/src/cam/options.h\nindex b9b7bd258c03..8b611d374fd5 100644\n--- a/src/cam/options.h\n+++ b/src/cam/options.h\n@@ -17,8 +17,15 @@ enum OptionArgument {\n \tArgumentOptional,\n };\n \n+enum OptionType {\n+\tOptionNone,\n+\tOptionInteger,\n+\tOptionString,\n+};\n+\n struct Option {\n \tint opt;\n+\tOptionType type;\n \tconst char *name;\n \tOptionArgument argument;\n \tconst char *argumentName;\n@@ -26,20 +33,45 @@ struct Option {\n \n \tbool hasShortOption() const { return isalnum(opt); }\n \tbool hasLongOption() const { return name != nullptr; }\n+\tconst char *typeName() const;\n };\n \n+class OptionValue;\n+\n template <typename T>\n class OptionsBase\n {\n public:\n \tbool valid() const;\n \tbool isSet(const T &opt) const;\n-\tconst std::string &operator[](const T &opt) const;\n+\tconst OptionValue &operator[](const T &opt) const;\n \n private:\n \tfriend class OptionsParser;\n-\tstd::map<T, std::string> values_;\n+\n+\tbool parseValue(const T &opt, const Option &option, const char *value);\n \tvoid clear();\n+\n+\tstd::map<T, OptionValue> values_;\n+};\n+\n+class OptionValue\n+{\n+public:\n+\tOptionValue();\n+\tOptionValue(int value);\n+\tOptionValue(const char *value);\n+\tOptionValue(const std::string &value);\n+\n+\tOptionType type() const { return type_; }\n+\n+\toperator int() const;\n+\toperator std::string() const;\n+\n+private:\n+\tOptionType type_;\n+\tint integer_;\n+\tstd::string string_;\n };\n \n class OptionsParser\n@@ -49,7 +81,8 @@ public:\n \t{\n \t};\n \n-\tbool addOption(int opt, const char *help, const char *name = nullptr,\n+\tbool addOption(int opt, OptionType type, const char *help,\n+\t\t       const char *name = nullptr,\n \t\t       OptionArgument argument = ArgumentNone,\n \t\t       const char *argumentName = nullptr);\n \n@@ -57,6 +90,8 @@ public:\n \tvoid usage();\n \n private:\n+\tvoid parseValueError(const Option &option);\n+\n \tstd::list<Option> options_;\n \tstd::map<unsigned int, Option *> optionsMap_;\n };\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "6/8"
    ]
}