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>
This commit is contained in:
parent
0081e4e6b2
commit
e8ae254970
1 changed files with 33 additions and 1 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue