From 284460d2692e48476156ebf51ed9417d0d2fbdcb Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 22 May 2021 12:39:35 +0100 Subject: [PATCH] Introduce ScopedSafeLocale class, use it in a few places Signed-off-by: falkTX --- distrho/extra/ScopedSafeLocale.hpp | 136 +++++++++++++++++++++++++++++ distrho/extra/String.hpp | 9 +- distrho/src/DistrhoPluginVST.cpp | 32 +------ 3 files changed, 142 insertions(+), 35 deletions(-) create mode 100644 distrho/extra/ScopedSafeLocale.hpp diff --git a/distrho/extra/ScopedSafeLocale.hpp b/distrho/extra/ScopedSafeLocale.hpp new file mode 100644 index 00000000..9c6293c2 --- /dev/null +++ b/distrho/extra/ScopedSafeLocale.hpp @@ -0,0 +1,136 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED +#define DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED + +#include "../DistrhoUtils.hpp" + +#include + +#if ! (defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) +# define DISTRHO_USE_NEWLOCALE +#endif + +#if defined(DISTRHO_OS_WINDOWS) && __MINGW64_VERSION_MAJOR >= 5 +# define DISTRHO_USE_CONFIGTHREADLOCALE +#endif + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------- +// ScopedSafeLocale class definition + +/** + ScopedSafeLocale is a handy class for setting current locale to C on constructor, and revert back on destructor. + It tries to be thread-safe, but it is not always possible. + + Put it inside a scope of code where string conversions happen to ensure they are consistent across many systems. + For example: + + ``` + // stack buffer to put converted float value in + char strbuf[0xff]; + + { + // safe locale operations during this scope + const ScopedSafeLocale sl; + snprintf(strbuf, 0xff, "%f", value); + } + + // do something with `strbuf` now, locale is reverted and left just as it was before + ``` + */ +class ScopedSafeLocale { +public: + /* + * Constructor. + * Current system locale will saved, while "C" is set as the next one to use. + */ + inline ScopedSafeLocale() noexcept; + + /* + * Destructor. + * System locale will revert back to the one saved during constructor. + */ + inline ~ScopedSafeLocale() noexcept; + +private: +#ifdef DISTRHO_USE_NEWLOCALE + locale_t newloc, oldloc; +#else +# ifdef DISTRHO_USE_CONFIGTHREADLOCALE + const int oldthreadloc; +# endif + char* const oldloc; +#endif + + DISTRHO_DECLARE_NON_COPYABLE(ScopedSafeLocale) + DISTRHO_PREVENT_HEAP_ALLOCATION +}; + +// ----------------------------------------------------------------------- +// ScopedSafeLocale class implementation + +#ifdef DISTRHO_USE_NEWLOCALE +static constexpr const locale_t kNullLocale = (locale_t)nullptr; +#endif + +inline ScopedSafeLocale::ScopedSafeLocale() noexcept +#ifdef DISTRHO_USE_NEWLOCALE + : newloc(::newlocale(LC_NUMERIC_MASK, "C", kNullLocale)), + oldloc(newloc != kNullLocale ? ::uselocale(newloc) : kNullLocale) {} +#else +# ifdef DISTRHO_USE_CONFIGTHREADLOCALE + : oldthreadloc(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)), +# else + : +# endif + oldloc(strdup(::setlocale(LC_NUMERIC, nullptr))) +{ + ::setlocale(LC_NUMERIC, "C"); +} +#endif + +inline ScopedSafeLocale::~ScopedSafeLocale() noexcept +{ +#ifdef DISTRHO_USE_NEWLOCALE + if (oldloc != kNullLocale) + ::uselocale(oldloc); + if (newloc != kNullLocale) + ::freelocale(newloc); +#else // DISTRHO_USE_NEWLOCALE + if (oldloc != nullptr) + { + ::setlocale(LC_NUMERIC, oldloc); + std::free(oldloc); + } + +# ifdef DISTRHO_USE_CONFIGTHREADLOCALE + if (oldthreadloc != -1) + _configthreadlocale(oldthreadloc); +# endif +#endif // DISTRHO_USE_NEWLOCALE +} + +// ----------------------------------------------------------------------- + +#undef DISTRHO_USE_CONFIGTHREADLOCALE +#undef DISTRHO_USE_NEWLOCALE + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED diff --git a/distrho/extra/String.hpp b/distrho/extra/String.hpp index 7cf85bf4..f74c430e 100644 --- a/distrho/extra/String.hpp +++ b/distrho/extra/String.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -18,6 +18,7 @@ #define DISTRHO_STRING_HPP_INCLUDED #include "../DistrhoUtils.hpp" +#include "../extra/ScopedSafeLocale.hpp" #include @@ -187,8 +188,7 @@ public: char strBuf[0xff+1]; { - // TODO - // const ScopedLocale csl; + const ScopedSafeLocale ssl; std::snprintf(strBuf, 0xff, "%.12g", static_cast(value)); } @@ -208,8 +208,7 @@ public: char strBuf[0xff+1]; { - // TODO - // const ScopedLocale csl; + const ScopedSafeLocale ssl; std::snprintf(strBuf, 0xff, "%.24g", value); } diff --git a/distrho/src/DistrhoPluginVST.cpp b/distrho/src/DistrhoPluginVST.cpp index e5bc91c8..a2fd36ca 100644 --- a/distrho/src/DistrhoPluginVST.cpp +++ b/distrho/src/DistrhoPluginVST.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2020 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -15,6 +15,7 @@ */ #include "DistrhoPluginInternal.hpp" +#include "../extra/ScopedSafeLocale.hpp" #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI # undef DISTRHO_PLUGIN_HAS_UI @@ -104,32 +105,6 @@ void snprintf_iparam(char* const dst, const int32_t value, const size_t size) // ----------------------------------------------------------------------- -class ScopedSafeLocale { -public: - ScopedSafeLocale() noexcept - : locale(::strdup(::setlocale(LC_NUMERIC, nullptr))) - { - ::setlocale(LC_NUMERIC, "C"); - } - - ~ScopedSafeLocale() noexcept - { - if (locale != nullptr) - { - ::setlocale(LC_NUMERIC, locale); - std::free(locale); - } - } - -private: - char* const locale; - - DISTRHO_DECLARE_NON_COPY_CLASS(ScopedSafeLocale) - DISTRHO_PREVENT_HEAP_ALLOCATION -}; - -// ----------------------------------------------------------------------- - struct ParameterCheckHelper { bool* parameterChecks; @@ -778,9 +753,6 @@ public: // add another separator chunkStr += "\xff"; - // temporarily set locale to "C" while converting floats - const ScopedSafeLocale ssl; - for (uint32_t i=0; i