diff options
author | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2022-12-21 11:15:55 +0000 |
---|---|---|
committer | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2023-01-03 13:09:52 +0000 |
commit | e8ae254970cfdeb1b5aba307a95a3189b09c9784 (patch) | |
tree | 43398bdc5c3054040e88a7fafa9c0545408a4e29 | |
parent | 0081e4e6b2941ea47fdf3959696d8edc2629477c (diff) |
libcamera: yaml_parser: Use C locale
When parsing configuration files on systems with differing locales, the
use of strtod can produce different results, or in the worst case - fail
to parse expected values.
Fix this by using strtod_l() instead. To avoid constructing and
destructing a locale_t instance for every use of strtod_l(), create an
RAII class that wraps the locale_t and use it to provide a global "C"
locale.
Bug: https://bugs.libcamera.org/show_bug.cgi?id=174
Bug: https://github.com/raspberrypi/libcamera/issues/29
Reported-by: https://github.com/kralo
Reported-by: Hannes Winkler <hanneswinkler2000@web.de>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r-- | src/libcamera/yaml_parser.cpp | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp index d8a7c2f9..2806c591 100644 --- a/src/libcamera/yaml_parser.cpp +++ b/src/libcamera/yaml_parser.cpp @@ -31,6 +31,38 @@ namespace { /* Empty static YamlObject as a safe result for invalid operations */ static const YamlObject empty; +/* + * Construct a global RAII locale for use by all YAML parser instances to + * ensure consistency when parsing configuration files and types regardless of + * the system locale configuration. + * + * For more information see: + * - https://bugs.libcamera.org/show_bug.cgi?id=174 + */ +class Locale +{ +public: + Locale(const char *locale) + { + locale_ = newlocale(LC_ALL_MASK, locale, static_cast<locale_t>(0)); + if (locale_ == static_cast<locale_t>(0)) + LOG(YamlParser, Fatal) + << "Failed to construct a locale"; + } + + ~Locale() + { + freelocale(locale_); + } + + locale_t locale() { return locale_; } + +private: + locale_t locale_; +}; + +Locale yamlLocale("C"); + } /* namespace */ /** @@ -283,7 +315,7 @@ std::optional<double> YamlObject::get() const char *end; errno = 0; - double value = std::strtod(value_.c_str(), &end); + double value = strtod_l(value_.c_str(), &end, yamlLocale.locale()); if ('\0' != *end || errno == ERANGE) return std::nullopt; |