[{"id":1134,"web_url":"https://patchwork.libcamera.org/comment/1134/","msgid":"<20190326105053.dh23jpczhwhwa4ep@uno.localdomain>","date":"2019-03-26T10:50:53","subject":"Re: [libcamera-devel] [PATCH 1/2] cam: Separate options valid() and\n\tempty()","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Sat, Mar 23, 2019 at 09:31:24AM +0200, Laurent Pinchart wrote:\n> An empty option list is not necessarily an error. Add a new empty()\n> function to test the option list for emptiness, and modify the valid()\n> function to only notify parsing errors. As a side effect this allows\n> accessing partially parsed options, which may be useful in the future.\n>\n\nNot an expert of this part, but this look sane to me apart from the\nfact I don't get where it is used? Do you need partial options in 2/2 ?\n\nOn the single patch:\n(Not-sure-I-got-this-but)Acked-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n  j\n\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/cam/main.cpp    |  7 +++++--\n>  src/cam/options.cpp | 34 +++++++++++++++-------------------\n>  src/cam/options.h   |  5 ++++-\n>  3 files changed, 24 insertions(+), 22 deletions(-)\n>\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index 1ca7862bf237..e7490c32f99a 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -67,9 +67,12 @@ static int parseOptions(int argc, char *argv[])\n>  \tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n>\n>  \toptions = parser.parse(argc, argv);\n> -\tif (!options.valid() || options.isSet(OptHelp)) {\n> +\tif (!options.valid())\n> +\t\treturn -EINVAL;\n> +\n> +\tif (options.empty() || options.isSet(OptHelp)) {\n>  \t\tparser.usage();\n> -\t\treturn !options.valid() ? -EINVAL : -EINTR;\n> +\t\treturn options.empty() ? -EINVAL : -EINTR;\n>  \t}\n>\n>  \treturn 0;\n> diff --git a/src/cam/options.cpp b/src/cam/options.cpp\n> index 655aa36bb9c9..f053a31d6ea1 100644\n> --- a/src/cam/options.cpp\n> +++ b/src/cam/options.cpp\n> @@ -39,10 +39,16 @@ const char *Option::typeName() const\n>   * OptionBase<T>\n>   */\n>\n> +template<typename T>\n> +bool OptionsBase<T>::empty() const\n> +{\n> +\treturn values_.empty();\n> +}\n> +\n>  template<typename T>\n>  bool OptionsBase<T>::valid() const\n>  {\n> -\treturn !values_.empty();\n> +\treturn valid_;\n>  }\n>\n>  template<typename T>\n> @@ -100,12 +106,6 @@ bool OptionsBase<T>::parseValue(const T &opt, const Option &option,\n>  \treturn true;\n>  }\n>\n> -template<typename T>\n> -void OptionsBase<T>::clear()\n> -{\n> -\tvalues_.clear();\n> -}\n> -\n>  template class OptionsBase<int>;\n>  template class OptionsBase<std::string>;\n>\n> @@ -165,21 +165,18 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)\n>\n>  \t\tif (optionsMap_.find(key) == optionsMap_.end()) {\n>  \t\t\tstd::cerr << \"Invalid option \" << key << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>\n>  \t\tOptionArgument arg = optionsMap_[key].argument;\n>  \t\tif (value.empty() && arg == ArgumentRequired) {\n>  \t\t\tstd::cerr << \"Option \" << key << \" requires an argument\"\n>  \t\t\t\t  << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t} else if (!value.empty() && arg == ArgumentNone) {\n>  \t\t\tstd::cerr << \"Option \" << key << \" takes no argument\"\n>  \t\t\t\t  << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>\n>  \t\tconst Option &option = optionsMap_[key];\n> @@ -187,11 +184,11 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)\n>  \t\t\tstd::cerr << \"Failed to parse '\" << value << \"' as \"\n>  \t\t\t\t  << option.typeName() << \" for option \" << key\n>  \t\t\t\t  << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>  \t}\n>\n> +\toptions.valid_ = true;\n>  \treturn options;\n>  }\n>\n> @@ -412,19 +409,18 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)\n>  \t\t\tstd::cerr << argv[optind - 1] << std::endl;\n>\n>  \t\t\tusage();\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>\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\treturn options;\n>  \t\t}\n>  \t}\n>\n> +\toptions.valid_ = true;\n>  \treturn options;\n>  }\n>\n> diff --git a/src/cam/options.h b/src/cam/options.h\n> index 745f4a4a3a43..0b0444c2db42 100644\n> --- a/src/cam/options.h\n> +++ b/src/cam/options.h\n> @@ -45,6 +45,9 @@ template<typename T>\n>  class OptionsBase\n>  {\n>  public:\n> +\tOptionsBase() : valid_(false) {}\n> +\n> +\tbool empty() const;\n>  \tbool valid() const;\n>  \tbool isSet(const T &opt) const;\n>  \tconst OptionValue &operator[](const T &opt) const;\n> @@ -54,9 +57,9 @@ private:\n>  \tfriend class OptionsParser;\n>\n>  \tbool parseValue(const T &opt, const Option &option, const char *value);\n> -\tvoid clear();\n>\n>  \tstd::map<T, OptionValue> values_;\n> +\tbool valid_;\n>  };\n>\n>  class KeyValueParser\n> --\n> Regards,\n>\n> Laurent Pinchart\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net\n\t[217.70.183.193])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 107086110D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 Mar 2019 11:50:13 +0100 (CET)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay1-d.mail.gandi.net (Postfix) with ESMTPSA id 57D3F24000E;\n\tTue, 26 Mar 2019 10:50:11 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Tue, 26 Mar 2019 11:50:53 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190326105053.dh23jpczhwhwa4ep@uno.localdomain>","References":"<20190323073125.25497-1-laurent.pinchart@ideasonboard.com>\n\t<20190323073125.25497-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"fwhjhyfa3tkgefyr\"","Content-Disposition":"inline","In-Reply-To":"<20190323073125.25497-2-laurent.pinchart@ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH 1/2] cam: Separate options valid() and\n\tempty()","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":"Tue, 26 Mar 2019 10:50:13 -0000"}},{"id":1140,"web_url":"https://patchwork.libcamera.org/comment/1140/","msgid":"<20190326235447.GA4842@pendragon.ideasonboard.com>","date":"2019-03-26T23:54:47","subject":"Re: [libcamera-devel] [PATCH 1/2] cam: Separate options valid() and\n\tempty()","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Tue, Mar 26, 2019 at 11:50:53AM +0100, Jacopo Mondi wrote:\n> On Sat, Mar 23, 2019 at 09:31:24AM +0200, Laurent Pinchart wrote:\n> > An empty option list is not necessarily an error. Add a new empty()\n> > function to test the option list for emptiness, and modify the valid()\n> > function to only notify parsing errors. As a side effect this allows\n> > accessing partially parsed options, which may be useful in the future.\n> >\n> \n> Not an expert of this part, but this look sane to me apart from the\n> fact I don't get where it is used? Do you need partial options in 2/2 ?\n\nThe qcam application doesn't require options, they're all optional, so I\nneed to be able to distinguish between invalid options and no option.\n\n> On the single patch:\n> (Not-sure-I-got-this-but)Acked-by: Jacopo Mondi <jacopo@jmondi.org>\n> \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  src/cam/main.cpp    |  7 +++++--\n> >  src/cam/options.cpp | 34 +++++++++++++++-------------------\n> >  src/cam/options.h   |  5 ++++-\n> >  3 files changed, 24 insertions(+), 22 deletions(-)\n> >\n> > diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> > index 1ca7862bf237..e7490c32f99a 100644\n> > --- a/src/cam/main.cpp\n> > +++ b/src/cam/main.cpp\n> > @@ -67,9 +67,12 @@ static int parseOptions(int argc, char *argv[])\n> >  \tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n> >\n> >  \toptions = parser.parse(argc, argv);\n> > -\tif (!options.valid() || options.isSet(OptHelp)) {\n> > +\tif (!options.valid())\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tif (options.empty() || options.isSet(OptHelp)) {\n> >  \t\tparser.usage();\n> > -\t\treturn !options.valid() ? -EINVAL : -EINTR;\n> > +\t\treturn options.empty() ? -EINVAL : -EINTR;\n> >  \t}\n> >\n> >  \treturn 0;\n> > diff --git a/src/cam/options.cpp b/src/cam/options.cpp\n> > index 655aa36bb9c9..f053a31d6ea1 100644\n> > --- a/src/cam/options.cpp\n> > +++ b/src/cam/options.cpp\n> > @@ -39,10 +39,16 @@ const char *Option::typeName() const\n> >   * OptionBase<T>\n> >   */\n> >\n> > +template<typename T>\n> > +bool OptionsBase<T>::empty() const\n> > +{\n> > +\treturn values_.empty();\n> > +}\n> > +\n> >  template<typename T>\n> >  bool OptionsBase<T>::valid() const\n> >  {\n> > -\treturn !values_.empty();\n> > +\treturn valid_;\n> >  }\n> >\n> >  template<typename T>\n> > @@ -100,12 +106,6 @@ bool OptionsBase<T>::parseValue(const T &opt, const Option &option,\n> >  \treturn true;\n> >  }\n> >\n> > -template<typename T>\n> > -void OptionsBase<T>::clear()\n> > -{\n> > -\tvalues_.clear();\n> > -}\n> > -\n> >  template class OptionsBase<int>;\n> >  template class OptionsBase<std::string>;\n> >\n> > @@ -165,21 +165,18 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)\n> >\n> >  \t\tif (optionsMap_.find(key) == optionsMap_.end()) {\n> >  \t\t\tstd::cerr << \"Invalid option \" << key << std::endl;\n> > -\t\t\toptions.clear();\n> > -\t\t\tbreak;\n> > +\t\t\treturn options;\n> >  \t\t}\n> >\n> >  \t\tOptionArgument arg = optionsMap_[key].argument;\n> >  \t\tif (value.empty() && arg == ArgumentRequired) {\n> >  \t\t\tstd::cerr << \"Option \" << key << \" requires an argument\"\n> >  \t\t\t\t  << std::endl;\n> > -\t\t\toptions.clear();\n> > -\t\t\tbreak;\n> > +\t\t\treturn options;\n> >  \t\t} else if (!value.empty() && arg == ArgumentNone) {\n> >  \t\t\tstd::cerr << \"Option \" << key << \" takes no argument\"\n> >  \t\t\t\t  << std::endl;\n> > -\t\t\toptions.clear();\n> > -\t\t\tbreak;\n> > +\t\t\treturn options;\n> >  \t\t}\n> >\n> >  \t\tconst Option &option = optionsMap_[key];\n> > @@ -187,11 +184,11 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)\n> >  \t\t\tstd::cerr << \"Failed to parse '\" << value << \"' as \"\n> >  \t\t\t\t  << option.typeName() << \" for option \" << key\n> >  \t\t\t\t  << std::endl;\n> > -\t\t\toptions.clear();\n> > -\t\t\tbreak;\n> > +\t\t\treturn options;\n> >  \t\t}\n> >  \t}\n> >\n> > +\toptions.valid_ = true;\n> >  \treturn options;\n> >  }\n> >\n> > @@ -412,19 +409,18 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)\n> >  \t\t\tstd::cerr << argv[optind - 1] << std::endl;\n> >\n> >  \t\t\tusage();\n> > -\t\t\toptions.clear();\n> > -\t\t\tbreak;\n> > +\t\t\treturn options;\n> >  \t\t}\n> >\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\treturn options;\n> >  \t\t}\n> >  \t}\n> >\n> > +\toptions.valid_ = true;\n> >  \treturn options;\n> >  }\n> >\n> > diff --git a/src/cam/options.h b/src/cam/options.h\n> > index 745f4a4a3a43..0b0444c2db42 100644\n> > --- a/src/cam/options.h\n> > +++ b/src/cam/options.h\n> > @@ -45,6 +45,9 @@ template<typename T>\n> >  class OptionsBase\n> >  {\n> >  public:\n> > +\tOptionsBase() : valid_(false) {}\n> > +\n> > +\tbool empty() const;\n> >  \tbool valid() const;\n> >  \tbool isSet(const T &opt) const;\n> >  \tconst OptionValue &operator[](const T &opt) const;\n> > @@ -54,9 +57,9 @@ private:\n> >  \tfriend class OptionsParser;\n> >\n> >  \tbool parseValue(const T &opt, const Option &option, const char *value);\n> > -\tvoid clear();\n> >\n> >  \tstd::map<T, OptionValue> values_;\n> > +\tbool valid_;\n> >  };\n> >\n> >  class KeyValueParser","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 903A9600F9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Mar 2019 00:55:04 +0100 (CET)","from pendragon.ideasonboard.com\n\t(p5269001-ipngn11702marunouchi.tokyo.ocn.ne.jp [114.158.195.1])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 288242E1;\n\tWed, 27 Mar 2019 00:55:01 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1553644503;\n\tbh=rwq6BblNvlAZyjpBjTRqbWO1L3ddkuA3k7WQBQ84nyo=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=GYBznXXWtJVz+C3aTHk+BykbNikLmNThacv3z90yeP+zM8Yy7cPKvCO4Hc+RlsilR\n\tl4pZDrdkrVQMZ4/KaXHYIo+OuVkxS7Jxp0Bso2WEP/HpGzO7hd5QtvvxtnwdEfxtNT\n\t+6bEocPbm9MBhKxwSuGxfSyo3UKdYh0NdsnfRUmA=","Date":"Wed, 27 Mar 2019 01:54:47 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190326235447.GA4842@pendragon.ideasonboard.com>","References":"<20190323073125.25497-1-laurent.pinchart@ideasonboard.com>\n\t<20190323073125.25497-2-laurent.pinchart@ideasonboard.com>\n\t<20190326105053.dh23jpczhwhwa4ep@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190326105053.dh23jpczhwhwa4ep@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 1/2] cam: Separate options valid() and\n\tempty()","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":"Tue, 26 Mar 2019 23:55:04 -0000"}},{"id":1143,"web_url":"https://patchwork.libcamera.org/comment/1143/","msgid":"<20190327003906.GA28018@bigcity.dyn.berto.se>","date":"2019-03-27T00:39:06","subject":"Re: [libcamera-devel] [PATCH 1/2] cam: Separate options valid() and\n\tempty()","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nThanks for your work.\n\nOn 2019-03-23 09:31:24 +0200, Laurent Pinchart wrote:\n> An empty option list is not necessarily an error. Add a new empty()\n> function to test the option list for emptiness, and modify the valid()\n> function to only notify parsing errors. As a side effect this allows\n> accessing partially parsed options, which may be useful in the future.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nNice idea,\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> ---\n>  src/cam/main.cpp    |  7 +++++--\n>  src/cam/options.cpp | 34 +++++++++++++++-------------------\n>  src/cam/options.h   |  5 ++++-\n>  3 files changed, 24 insertions(+), 22 deletions(-)\n> \n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index 1ca7862bf237..e7490c32f99a 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -67,9 +67,12 @@ static int parseOptions(int argc, char *argv[])\n>  \tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n>  \n>  \toptions = parser.parse(argc, argv);\n> -\tif (!options.valid() || options.isSet(OptHelp)) {\n> +\tif (!options.valid())\n> +\t\treturn -EINVAL;\n> +\n> +\tif (options.empty() || options.isSet(OptHelp)) {\n>  \t\tparser.usage();\n> -\t\treturn !options.valid() ? -EINVAL : -EINTR;\n> +\t\treturn options.empty() ? -EINVAL : -EINTR;\n>  \t}\n>  \n>  \treturn 0;\n> diff --git a/src/cam/options.cpp b/src/cam/options.cpp\n> index 655aa36bb9c9..f053a31d6ea1 100644\n> --- a/src/cam/options.cpp\n> +++ b/src/cam/options.cpp\n> @@ -39,10 +39,16 @@ const char *Option::typeName() const\n>   * OptionBase<T>\n>   */\n>  \n> +template<typename T>\n> +bool OptionsBase<T>::empty() const\n> +{\n> +\treturn values_.empty();\n> +}\n> +\n>  template<typename T>\n>  bool OptionsBase<T>::valid() const\n>  {\n> -\treturn !values_.empty();\n> +\treturn valid_;\n>  }\n>  \n>  template<typename T>\n> @@ -100,12 +106,6 @@ bool OptionsBase<T>::parseValue(const T &opt, const Option &option,\n>  \treturn true;\n>  }\n>  \n> -template<typename T>\n> -void OptionsBase<T>::clear()\n> -{\n> -\tvalues_.clear();\n> -}\n> -\n>  template class OptionsBase<int>;\n>  template class OptionsBase<std::string>;\n>  \n> @@ -165,21 +165,18 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)\n>  \n>  \t\tif (optionsMap_.find(key) == optionsMap_.end()) {\n>  \t\t\tstd::cerr << \"Invalid option \" << key << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>  \n>  \t\tOptionArgument arg = optionsMap_[key].argument;\n>  \t\tif (value.empty() && arg == ArgumentRequired) {\n>  \t\t\tstd::cerr << \"Option \" << key << \" requires an argument\"\n>  \t\t\t\t  << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t} else if (!value.empty() && arg == ArgumentNone) {\n>  \t\t\tstd::cerr << \"Option \" << key << \" takes no argument\"\n>  \t\t\t\t  << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>  \n>  \t\tconst Option &option = optionsMap_[key];\n> @@ -187,11 +184,11 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)\n>  \t\t\tstd::cerr << \"Failed to parse '\" << value << \"' as \"\n>  \t\t\t\t  << option.typeName() << \" for option \" << key\n>  \t\t\t\t  << std::endl;\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>  \t}\n>  \n> +\toptions.valid_ = true;\n>  \treturn options;\n>  }\n>  \n> @@ -412,19 +409,18 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)\n>  \t\t\tstd::cerr << argv[optind - 1] << std::endl;\n>  \n>  \t\t\tusage();\n> -\t\t\toptions.clear();\n> -\t\t\tbreak;\n> +\t\t\treturn options;\n>  \t\t}\n>  \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\treturn options;\n>  \t\t}\n>  \t}\n>  \n> +\toptions.valid_ = true;\n>  \treturn options;\n>  }\n>  \n> diff --git a/src/cam/options.h b/src/cam/options.h\n> index 745f4a4a3a43..0b0444c2db42 100644\n> --- a/src/cam/options.h\n> +++ b/src/cam/options.h\n> @@ -45,6 +45,9 @@ template<typename T>\n>  class OptionsBase\n>  {\n>  public:\n> +\tOptionsBase() : valid_(false) {}\n> +\n> +\tbool empty() const;\n>  \tbool valid() const;\n>  \tbool isSet(const T &opt) const;\n>  \tconst OptionValue &operator[](const T &opt) const;\n> @@ -54,9 +57,9 @@ private:\n>  \tfriend class OptionsParser;\n>  \n>  \tbool parseValue(const T &opt, const Option &option, const char *value);\n> -\tvoid clear();\n>  \n>  \tstd::map<T, OptionValue> values_;\n> +\tbool valid_;\n>  };\n>  \n>  class KeyValueParser\n> -- \n> Regards,\n> \n> Laurent Pinchart\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lj1-x241.google.com (mail-lj1-x241.google.com\n\t[IPv6:2a00:1450:4864:20::241])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3B0D9600FD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Mar 2019 01:39:09 +0100 (CET)","by mail-lj1-x241.google.com with SMTP id j89so12828241ljb.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 26 Mar 2019 17:39:09 -0700 (PDT)","from localhost (89-233-230-99.cust.bredband2.com. [89.233.230.99])\n\tby smtp.gmail.com with ESMTPSA id\n\tc2sm4670148ljj.45.2019.03.26.17.39.07\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tTue, 26 Mar 2019 17:39:07 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=ECzZ04tw43obtJu0UQ5ZmcXdFS8dU0p0lADKehQ+Iz0=;\n\tb=w3R9Isv8ffw91LNdsEENskXDEDy1KNV8SGUQLJXt5xLGoTW+LExC6J7l+g2NjfagMi\n\tu3DbCrrejZldD/rp9hYAyje1noIAto05/xhiK6bqk2Rs8UEuoF9QicmFbkeHFjQIOLQs\n\tA2WOGrv2IP6Yyvb93lFu7/zCqXrULSR8uwYfJ92cRJkC55Hh9gRddfs4u3I6WbYGMr0E\n\t+JvPGy2TOM4nQorNPsUnbMVD+GZygLcmuycdBSiEaFHhbQkagF8ikbsFnoeGAz6Kl074\n\tIqGoKm85m33h8ja9HVz+fAhko4cHWCwPKJHpEEaENK4OU9Vi3c+ZFP5hb9dwzi8KcxUR\n\tJeMg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=ECzZ04tw43obtJu0UQ5ZmcXdFS8dU0p0lADKehQ+Iz0=;\n\tb=L9coTJduU8ahHl2TkPtfj1gHbechaCDDOS9bYn6FKxKWHAf5K6CcAkF5yYab0rraU9\n\ttgy+OQreeIXQEIrKifA1d3Q/wS3tSLyBlGnRmGLHogDPOHlo1vsD8w1DZXP+JbecaaJ7\n\tCh1kSBJbXf+tqPXd9PWJ8pKBAgL2t0lD0TtcMQrz0lUoNCtddL9dVVowUjI4QCkzMQUN\n\tBBizskWhAAmR3T5mtdcerisFLPzXo4bTDWH7Pp9CoPOML0Y2Sscn5RaGGjhlVkdiTDwo\n\tLapuuurYipHGZqJq1Gq/pNY6bneM/sase9csB4MdCkD7Zw9dr90zdUJ5cJF7NLHu2JaG\n\tmR4w==","X-Gm-Message-State":"APjAAAV6YG70z3KFk3ayxjVEFwoJbIaauq04O3Av5X9cs4YvS7+YrhTU\n\teSs/TEj3i7+1kP5eEB7jzk6X8A==","X-Google-Smtp-Source":"APXvYqx0ey8z8ANl9Dem7uu09SUkeXz3kWNLiCv0RV+Aqs6Vgtne9dLiVCm0JBWS6rr/5Arjce6EkQ==","X-Received":"by 2002:a2e:9010:: with SMTP id h16mr9329551ljg.16.1553647148400;\n\tTue, 26 Mar 2019 17:39:08 -0700 (PDT)","Date":"Wed, 27 Mar 2019 01:39:06 +0100","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190327003906.GA28018@bigcity.dyn.berto.se>","References":"<20190323073125.25497-1-laurent.pinchart@ideasonboard.com>\n\t<20190323073125.25497-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190323073125.25497-2-laurent.pinchart@ideasonboard.com>","User-Agent":"Mutt/1.11.3 (2019-02-01)","Subject":"Re: [libcamera-devel] [PATCH 1/2] cam: Separate options valid() and\n\tempty()","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":"Wed, 27 Mar 2019 00:39:09 -0000"}}]