[{"id":26195,"web_url":"https://patchwork.libcamera.org/comment/26195/","msgid":"<167321996016.3175711.1425216582437653337@Monstersaurus>","date":"2023-01-08T23:19:20","subject":"Re: [libcamera-devel] [PATCH v1 1/2] base: utils: Add and use\n\tstrtod() helper","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart via libcamera-devel (2023-01-08 21:43:56)\n> The strtod() function is locale-dependent, and thus ill-suited to parse\n> numbers coming from, for instance, YAML files. The YamlObject class uses\n> strtod_l() to fix that issue, but that function is not available with\n> all libc implementations. Correctly handling this problem is becoming\n> out of scope for the YamlObject class.\n> \n> As a first step, add a strtod() helper function in the utils namespace\n> that copies the implementation from YamlObject, and use it in\n> YamlObject. The core issue will then be fixed in utils::strtod().\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/base/utils.h |  2 ++\n>  src/libcamera/base/utils.cpp   | 46 ++++++++++++++++++++++++++++++++++\n>  src/libcamera/yaml_parser.cpp  | 34 +------------------------\n>  3 files changed, 49 insertions(+), 33 deletions(-)\n> \n> diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h\n> index eb7bcdf4c173..37d9af609ec7 100644\n> --- a/include/libcamera/base/utils.h\n> +++ b/include/libcamera/base/utils.h\n> @@ -367,6 +367,8 @@ decltype(auto) abs_diff(const T &a, const T &b)\n>                 return a - b;\n>  }\n>  \n> +double strtod(const char *__restrict nptr, char **__restrict endptr);\n> +\n>  } /* namespace utils */\n>  \n>  #ifndef __DOXYGEN__\n> diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp\n> index 6a307940448e..4a239427a4d9 100644\n> --- a/src/libcamera/base/utils.cpp\n> +++ b/src/libcamera/base/utils.cpp\n> @@ -8,6 +8,7 @@\n>  #include <libcamera/base/utils.h>\n>  \n>  #include <iomanip>\n> +#include <locale.h>\n>  #include <sstream>\n>  #include <stdlib.h>\n>  #include <string.h>\n> @@ -463,6 +464,51 @@ std::string toAscii(const std::string &str)\n>   * \\a b\n>   */\n>  \n> +namespace {\n> +\n> +/*\n> + * RAII wrapper around locale_t instances, to support global locale instances\n> + * without leaking memory.\n> + */\n> +class Locale\n> +{\n> +public:\n> +       Locale(const char *locale)\n> +       {\n> +               locale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));\n> +       }\n> +\n> +       ~Locale()\n> +       {\n> +               freelocale(locale_);\n> +       }\n> +\n> +       locale_t locale() { return locale_; }\n> +\n> +private:\n> +       locale_t locale_;\n> +};\n> +\n> +Locale cLocale(\"C\");\n> +\n> +} /* namespace */\n> +\n> +/**\n> + * \\brief Convert a string to a double independently of the current locale\n> + * \\param[in] nptr The string to convert\n> + * \\param[out] endptr Pointer to trailing portion of the string after conversion\n> + *\n> + * This function is a locale-independent version of the std::strtod() function.\n> + * It behaves as the standard function, but uses the \"C\" locale instead of the\n> + * current locale.\n> + *\n> + * \\return The converted value, if any, or 0.0 if the conversion failed.\n> + */\n\nSounds good.\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> +double strtod(const char *__restrict nptr, char **__restrict endptr)\n> +{\n> +       return strtod_l(nptr, endptr, cLocale.locale());\n> +}\n> +\n>  } /* namespace utils */\n>  \n>  #ifndef __DOXYGEN__\n> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> index 2806c591f75d..153a6d53c3f9 100644\n> --- a/src/libcamera/yaml_parser.cpp\n> +++ b/src/libcamera/yaml_parser.cpp\n> @@ -31,38 +31,6 @@ namespace {\n>  /* Empty static YamlObject as a safe result for invalid operations */\n>  static const YamlObject empty;\n>  \n> -/*\n> - * Construct a global RAII locale for use by all YAML parser instances to\n> - * ensure consistency when parsing configuration files and types regardless of\n> - * the system locale configuration.\n> - *\n> - * For more information see:\n> - * - https://bugs.libcamera.org/show_bug.cgi?id=174\n> - */\n> -class Locale\n> -{\n> -public:\n> -       Locale(const char *locale)\n> -       {\n> -               locale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));\n> -               if (locale_ == static_cast<locale_t>(0))\n> -                       LOG(YamlParser, Fatal)\n> -                               << \"Failed to construct a locale\";\n> -       }\n> -\n> -       ~Locale()\n> -       {\n> -               freelocale(locale_);\n> -       }\n> -\n> -       locale_t locale() { return locale_; }\n> -\n> -private:\n> -       locale_t locale_;\n> -};\n> -\n> -Locale yamlLocale(\"C\");\n> -\n>  } /* namespace */\n>  \n>  /**\n> @@ -315,7 +283,7 @@ std::optional<double> YamlObject::get() const\n>         char *end;\n>  \n>         errno = 0;\n> -       double value = strtod_l(value_.c_str(), &end, yamlLocale.locale());\n> +       double value = utils::strtod(value_.c_str(), &end);\n>  \n>         if ('\\0' != *end || errno == ERANGE)\n>                 return std::nullopt;\n> -- \n> Regards,\n> \n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8E165C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun,  8 Jan 2023 23:19:25 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DA3C0625DE;\n\tMon,  9 Jan 2023 00:19:24 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BB84C625CC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  9 Jan 2023 00:19:22 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 46AC0492;\n\tMon,  9 Jan 2023 00:19:22 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1673219964;\n\tbh=0/cZeUabS+NX2PP4+nrDt5uhOEhrZMgNkb4YjW69C3I=;\n\th=In-Reply-To:References:To:Date:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=isfmaOJbpHjCwWWGFF7uSWVaoZ0UDziWpnxzud6ucsRyrOzhZtTCi1rGcewbKNoCO\n\tzQVPM3v1yh2gXXIiihQX/DKAelEnaoZIlc8U/fmXa1hpY4QLmLR6dsg4n3oSs61g97\n\tf7JyZ7KddY4ksIXgLTpfqpbeVkcOA1cBZMb+tRNrrSUy2kLoV8A+39smEsL12nkWMn\n\tFwVCSiXLfinTQ4tjNbCCZZznO+R8zbD4stfyRi7kbCbVSwkMxFk67MrdginkOjXKml\n\t6YUs/WPSAw1B2RVVLDNVCtxAZMht68dktXANxGQPyXlPutU/2vfHv6mh66/MDo7Qd0\n\thNb/HTqIKPsKg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1673219962;\n\tbh=0/cZeUabS+NX2PP4+nrDt5uhOEhrZMgNkb4YjW69C3I=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=rcrR1kRU9DgqUbjWc6ys3kQNXdvaD4PeigUFTCliPwYFFUwFraFovDSAPjc4xOmHU\n\tdyavwGw57hFFqhPjBOMb5C2M+0ytb0+kZczTn9qSWm881cFhYas93KmiRd1htJGJUf\n\tkS08PfNFTLvG899tlXOMfR8t4tWeL3WHtUfVkrRQ="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"rcrR1kRU\"; dkim-atps=neutral","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20230108214357.12641-2-laurent.pinchart@ideasonboard.com>","References":"<20230108214357.12641-1-laurent.pinchart@ideasonboard.com>\n\t<20230108214357.12641-2-laurent.pinchart@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Sun, 08 Jan 2023 23:19:20 +0000","Message-ID":"<167321996016.3175711.1425216582437653337@Monstersaurus>","User-Agent":"alot/0.10","Subject":"Re: [libcamera-devel] [PATCH v1 1/2] base: utils: Add and use\n\tstrtod() helper","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Kieran Bingham via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":26199,"web_url":"https://patchwork.libcamera.org/comment/26199/","msgid":"<20230110081052.7k7fkahwpymxpjsu@uno.localdomain>","date":"2023-01-10T08:10:52","subject":"Re: [libcamera-devel] [PATCH v1 1/2] base: utils: Add and use\n\tstrtod() helper","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\n  I presume set_locale()\nhttps://en.cppreference.com/w/cpp/locale/setlocale\n\ndoesn't help here, right ?\n\nOn Sun, Jan 08, 2023 at 11:43:56PM +0200, Laurent Pinchart via libcamera-devel wrote:\n> The strtod() function is locale-dependent, and thus ill-suited to parse\n> numbers coming from, for instance, YAML files. The YamlObject class uses\n> strtod_l() to fix that issue, but that function is not available with\n> all libc implementations. Correctly handling this problem is becoming\n> out of scope for the YamlObject class.\n>\n> As a first step, add a strtod() helper function in the utils namespace\n> that copies the implementation from YamlObject, and use it in\n> YamlObject. The core issue will then be fixed in utils::strtod().\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/base/utils.h |  2 ++\n>  src/libcamera/base/utils.cpp   | 46 ++++++++++++++++++++++++++++++++++\n>  src/libcamera/yaml_parser.cpp  | 34 +------------------------\n>  3 files changed, 49 insertions(+), 33 deletions(-)\n>\n> diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h\n> index eb7bcdf4c173..37d9af609ec7 100644\n> --- a/include/libcamera/base/utils.h\n> +++ b/include/libcamera/base/utils.h\n> @@ -367,6 +367,8 @@ decltype(auto) abs_diff(const T &a, const T &b)\n>  \t\treturn a - b;\n>  }\n>\n> +double strtod(const char *__restrict nptr, char **__restrict endptr);\n> +\n>  } /* namespace utils */\n>\n>  #ifndef __DOXYGEN__\n> diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp\n> index 6a307940448e..4a239427a4d9 100644\n> --- a/src/libcamera/base/utils.cpp\n> +++ b/src/libcamera/base/utils.cpp\n> @@ -8,6 +8,7 @@\n>  #include <libcamera/base/utils.h>\n>\n>  #include <iomanip>\n> +#include <locale.h>\n>  #include <sstream>\n>  #include <stdlib.h>\n>  #include <string.h>\n> @@ -463,6 +464,51 @@ std::string toAscii(const std::string &str)\n>   * \\a b\n>   */\n>\n> +namespace {\n> +\n> +/*\n> + * RAII wrapper around locale_t instances, to support global locale instances\n> + * without leaking memory.\n> + */\n> +class Locale\n> +{\n> +public:\n> +\tLocale(const char *locale)\n> +\t{\n> +\t\tlocale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));\n> +\t}\n> +\n> +\t~Locale()\n> +\t{\n> +\t\tfreelocale(locale_);\n> +\t}\n> +\n> +\tlocale_t locale() { return locale_; }\n> +\n> +private:\n> +\tlocale_t locale_;\n> +};\n> +\n> +Locale cLocale(\"C\");\n> +\n> +} /* namespace */\n> +\n> +/**\n> + * \\brief Convert a string to a double independently of the current locale\n> + * \\param[in] nptr The string to convert\n> + * \\param[out] endptr Pointer to trailing portion of the string after conversion\n> + *\n> + * This function is a locale-independent version of the std::strtod() function.\n> + * It behaves as the standard function, but uses the \"C\" locale instead of the\n> + * current locale.\n> + *\n> + * \\return The converted value, if any, or 0.0 if the conversion failed.\n> + */\n> +double strtod(const char *__restrict nptr, char **__restrict endptr)\n> +{\n> +\treturn strtod_l(nptr, endptr, cLocale.locale());\n> +}\n> +\n>  } /* namespace utils */\n>\n>  #ifndef __DOXYGEN__\n> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> index 2806c591f75d..153a6d53c3f9 100644\n> --- a/src/libcamera/yaml_parser.cpp\n> +++ b/src/libcamera/yaml_parser.cpp\n> @@ -31,38 +31,6 @@ namespace {\n>  /* Empty static YamlObject as a safe result for invalid operations */\n>  static const YamlObject empty;\n>\n> -/*\n> - * Construct a global RAII locale for use by all YAML parser instances to\n> - * ensure consistency when parsing configuration files and types regardless of\n> - * the system locale configuration.\n> - *\n> - * For more information see:\n> - * - https://bugs.libcamera.org/show_bug.cgi?id=174\n> - */\n> -class Locale\n> -{\n> -public:\n> -\tLocale(const char *locale)\n> -\t{\n> -\t\tlocale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));\n> -\t\tif (locale_ == static_cast<locale_t>(0))\n> -\t\t\tLOG(YamlParser, Fatal)\n> -\t\t\t\t<< \"Failed to construct a locale\";\n> -\t}\n> -\n> -\t~Locale()\n> -\t{\n> -\t\tfreelocale(locale_);\n> -\t}\n> -\n> -\tlocale_t locale() { return locale_; }\n> -\n> -private:\n> -\tlocale_t locale_;\n> -};\n> -\n> -Locale yamlLocale(\"C\");\n> -\n>  } /* namespace */\n>\n>  /**\n> @@ -315,7 +283,7 @@ std::optional<double> YamlObject::get() const\n>  \tchar *end;\n>\n>  \terrno = 0;\n> -\tdouble value = strtod_l(value_.c_str(), &end, yamlLocale.locale());\n> +\tdouble value = utils::strtod(value_.c_str(), &end);\n>\n>  \tif ('\\0' != *end || errno == ERANGE)\n>  \t\treturn std::nullopt;\n> --\n> Regards,\n>\n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 2B257C3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 10 Jan 2023 08:10:57 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4F29F625DE;\n\tTue, 10 Jan 2023 09:10:56 +0100 (CET)","from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net\n\t[217.70.183.199])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A319961F05\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 10 Jan 2023 09:10:54 +0100 (CET)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 27CBBFF809;\n\tTue, 10 Jan 2023 08:10:53 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1673338256;\n\tbh=TuqojPQzZ24SlhnFRkrKlEZI7qeliA+lN6j9mGLbQyM=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=yNgBdhtGNKxh4ju5QhzI2xp8P6JMZ9Fw/XCI0uCxRzwfUu7OhcdCiQlFIDY9CifJn\n\tkfi5dwzzQTUdKV7wo+oHLgHih74BjgDVMp0MsPBNvaLNKLJPFpkvm/cq0VE62+Bhyv\n\taeVVP0fex6ZKlAp0qh+MblomsVY9vTA04CYa0XBJLd1xPux6l00cP8jyWpy50byS4+\n\t4MhLh9ux4KBpadIatR6IPHe2wjGioSC7YhAVcVCfhUwTGn6/GLlFDypOQsrT08LuW8\n\tcgzjFyvcolKrEZzZRxk6LLd3yRx5ZzQ6UhYks5SLcYz2Bx5hcRlHzO0dRJ7yQ2hY0x\n\tjTKCMM3MFnEmg==","Date":"Tue, 10 Jan 2023 09:10:52 +0100","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20230110081052.7k7fkahwpymxpjsu@uno.localdomain>","References":"<20230108214357.12641-1-laurent.pinchart@ideasonboard.com>\n\t<20230108214357.12641-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20230108214357.12641-2-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v1 1/2] base: utils: Add and use\n\tstrtod() helper","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":26202,"web_url":"https://patchwork.libcamera.org/comment/26202/","msgid":"<Y70k3hIaRHideIBt@pendragon.ideasonboard.com>","date":"2023-01-10T08:42:06","subject":"Re: [libcamera-devel] [PATCH v1 1/2] base: utils: Add and use\n\tstrtod() helper","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, Jan 10, 2023 at 09:10:52AM +0100, Jacopo Mondi wrote:\n> Hi Laurent\n> \n>   I presume set_locale()\n> https://en.cppreference.com/w/cpp/locale/setlocale\n> \n> doesn't help here, right ?\n\nIt doesn't, as that changes the current locale, which we can't do as a\nlibrary.\n\n> On Sun, Jan 08, 2023 at 11:43:56PM +0200, Laurent Pinchart via libcamera-devel wrote:\n> > The strtod() function is locale-dependent, and thus ill-suited to parse\n> > numbers coming from, for instance, YAML files. The YamlObject class uses\n> > strtod_l() to fix that issue, but that function is not available with\n> > all libc implementations. Correctly handling this problem is becoming\n> > out of scope for the YamlObject class.\n> >\n> > As a first step, add a strtod() helper function in the utils namespace\n> > that copies the implementation from YamlObject, and use it in\n> > YamlObject. The core issue will then be fixed in utils::strtod().\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  include/libcamera/base/utils.h |  2 ++\n> >  src/libcamera/base/utils.cpp   | 46 ++++++++++++++++++++++++++++++++++\n> >  src/libcamera/yaml_parser.cpp  | 34 +------------------------\n> >  3 files changed, 49 insertions(+), 33 deletions(-)\n> >\n> > diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h\n> > index eb7bcdf4c173..37d9af609ec7 100644\n> > --- a/include/libcamera/base/utils.h\n> > +++ b/include/libcamera/base/utils.h\n> > @@ -367,6 +367,8 @@ decltype(auto) abs_diff(const T &a, const T &b)\n> >  \t\treturn a - b;\n> >  }\n> >\n> > +double strtod(const char *__restrict nptr, char **__restrict endptr);\n> > +\n> >  } /* namespace utils */\n> >\n> >  #ifndef __DOXYGEN__\n> > diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp\n> > index 6a307940448e..4a239427a4d9 100644\n> > --- a/src/libcamera/base/utils.cpp\n> > +++ b/src/libcamera/base/utils.cpp\n> > @@ -8,6 +8,7 @@\n> >  #include <libcamera/base/utils.h>\n> >\n> >  #include <iomanip>\n> > +#include <locale.h>\n> >  #include <sstream>\n> >  #include <stdlib.h>\n> >  #include <string.h>\n> > @@ -463,6 +464,51 @@ std::string toAscii(const std::string &str)\n> >   * \\a b\n> >   */\n> >\n> > +namespace {\n> > +\n> > +/*\n> > + * RAII wrapper around locale_t instances, to support global locale instances\n> > + * without leaking memory.\n> > + */\n> > +class Locale\n> > +{\n> > +public:\n> > +\tLocale(const char *locale)\n> > +\t{\n> > +\t\tlocale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));\n> > +\t}\n> > +\n> > +\t~Locale()\n> > +\t{\n> > +\t\tfreelocale(locale_);\n> > +\t}\n> > +\n> > +\tlocale_t locale() { return locale_; }\n> > +\n> > +private:\n> > +\tlocale_t locale_;\n> > +};\n> > +\n> > +Locale cLocale(\"C\");\n> > +\n> > +} /* namespace */\n> > +\n> > +/**\n> > + * \\brief Convert a string to a double independently of the current locale\n> > + * \\param[in] nptr The string to convert\n> > + * \\param[out] endptr Pointer to trailing portion of the string after conversion\n> > + *\n> > + * This function is a locale-independent version of the std::strtod() function.\n> > + * It behaves as the standard function, but uses the \"C\" locale instead of the\n> > + * current locale.\n> > + *\n> > + * \\return The converted value, if any, or 0.0 if the conversion failed.\n> > + */\n> > +double strtod(const char *__restrict nptr, char **__restrict endptr)\n> > +{\n> > +\treturn strtod_l(nptr, endptr, cLocale.locale());\n> > +}\n> > +\n> >  } /* namespace utils */\n> >\n> >  #ifndef __DOXYGEN__\n> > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> > index 2806c591f75d..153a6d53c3f9 100644\n> > --- a/src/libcamera/yaml_parser.cpp\n> > +++ b/src/libcamera/yaml_parser.cpp\n> > @@ -31,38 +31,6 @@ namespace {\n> >  /* Empty static YamlObject as a safe result for invalid operations */\n> >  static const YamlObject empty;\n> >\n> > -/*\n> > - * Construct a global RAII locale for use by all YAML parser instances to\n> > - * ensure consistency when parsing configuration files and types regardless of\n> > - * the system locale configuration.\n> > - *\n> > - * For more information see:\n> > - * - https://bugs.libcamera.org/show_bug.cgi?id=174\n> > - */\n> > -class Locale\n> > -{\n> > -public:\n> > -\tLocale(const char *locale)\n> > -\t{\n> > -\t\tlocale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0));\n> > -\t\tif (locale_ == static_cast<locale_t>(0))\n> > -\t\t\tLOG(YamlParser, Fatal)\n> > -\t\t\t\t<< \"Failed to construct a locale\";\n> > -\t}\n> > -\n> > -\t~Locale()\n> > -\t{\n> > -\t\tfreelocale(locale_);\n> > -\t}\n> > -\n> > -\tlocale_t locale() { return locale_; }\n> > -\n> > -private:\n> > -\tlocale_t locale_;\n> > -};\n> > -\n> > -Locale yamlLocale(\"C\");\n> > -\n> >  } /* namespace */\n> >\n> >  /**\n> > @@ -315,7 +283,7 @@ std::optional<double> YamlObject::get() const\n> >  \tchar *end;\n> >\n> >  \terrno = 0;\n> > -\tdouble value = strtod_l(value_.c_str(), &end, yamlLocale.locale());\n> > +\tdouble value = utils::strtod(value_.c_str(), &end);\n> >\n> >  \tif ('\\0' != *end || errno == ERANGE)\n> >  \t\treturn std::nullopt;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 2A96BC3237\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 10 Jan 2023 08:42:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 8CD76625CF;\n\tTue, 10 Jan 2023 09:42:12 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A394261F05\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 10 Jan 2023 09:42:10 +0100 (CET)","from pendragon.ideasonboard.com (213-243-189-158.bb.dnainternet.fi\n\t[213.243.189.158])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 037C06CF;\n\tTue, 10 Jan 2023 09:42:09 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1673340132;\n\tbh=d9z64NAVHPPYjh3XT1meN81QXJCO5UFL6xHv8rIAJR4=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=htQ/NO5UQKF6g7xhy2buEw2SA9bws7bSFI4i+HcJ8HMQKBIxDay0RwRii+UJ8RzQq\n\tVNaIuzDKtoST/d0qQiKHQ3CKZxXbtVaQPE1N2/fMNSm1KxG20tkKnD/TrQW9rhS/Ah\n\tk3i4qs0QuThvOaeNeASxs4cPTkIi9wUM387bqtzPl9QIS00tO6w7KAl9YIrUzLfKJW\n\tPihUmm8URxK5BMBR2r71gWrT2vwSbrGPxp+NfMeraf1tKtVMinSgWw6SoVxcnZoZ2n\n\tRdGjW+75XzkmoKGQ2Z1849jt1yLXi8cbbplZ06Bxx926s4iQYUZy8CSl+rTmMHHxVB\n\tzaaJ0HnlVgZ+w==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1673340130;\n\tbh=d9z64NAVHPPYjh3XT1meN81QXJCO5UFL6xHv8rIAJR4=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Fnx/G6EEXJxORXC9NBhf82jZwPlv+QIR/HZDup4wj8vJLQQ0IOA5M4FtS2vJjzDNZ\n\tJbR6PRZc/cH7Xz4dOhUgJ5uV3a5qQurr4sbvDHM0OfHYhedfVDUqge6eAfjK3JHQ0M\n\tRd+57QYxhcfwLU9H9DL6fAx6B6vD1RUIt716sDbI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"Fnx/G6EE\"; dkim-atps=neutral","Date":"Tue, 10 Jan 2023 10:42:06 +0200","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<Y70k3hIaRHideIBt@pendragon.ideasonboard.com>","References":"<20230108214357.12641-1-laurent.pinchart@ideasonboard.com>\n\t<20230108214357.12641-2-laurent.pinchart@ideasonboard.com>\n\t<20230110081052.7k7fkahwpymxpjsu@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20230110081052.7k7fkahwpymxpjsu@uno.localdomain>","Subject":"Re: [libcamera-devel] [PATCH v1 1/2] base: utils: Add and use\n\tstrtod() helper","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]