DISTRHO Plugin Framework
ScopedSafeLocale.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED
18 #define DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED
19 
20 #include "../DistrhoUtils.hpp"
21 
22 #include <clocale>
23 
24 #if ! (defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS))
25 # define DISTRHO_USE_NEWLOCALE
26 #endif
27 
28 #if defined(DISTRHO_OS_WINDOWS) && __MINGW64_VERSION_MAJOR >= 5
29 # define DISTRHO_USE_CONFIGTHREADLOCALE
30 #endif
31 
33 
34 // -----------------------------------------------------------------------
35 // ScopedSafeLocale class definition
36 
37 /**
38  ScopedSafeLocale is a handy class for setting current locale to C on constructor, and revert back on destructor.
39  It tries to be thread-safe, but it is not always possible.
40 
41  Put it inside a scope of code where string conversions happen to ensure they are consistent across many systems.
42  For example:
43 
44  ```
45  // stack buffer to put converted float value in
46  char strbuf[0xff];
47 
48  {
49  // safe locale operations during this scope
50  const ScopedSafeLocale sl;
51  snprintf(strbuf, 0xff, "%f", value);
52  }
53 
54  // do something with `strbuf` now, locale is reverted and left just as it was before
55  ```
56  */
58 public:
59  /*
60  * Constructor.
61  * Current system locale will saved, while "C" is set as the next one to use.
62  */
63  inline ScopedSafeLocale() noexcept;
64 
65  /*
66  * Destructor.
67  * System locale will revert back to the one saved during constructor.
68  */
69  inline ~ScopedSafeLocale() noexcept;
70 
71 private:
72 #ifdef DISTRHO_USE_NEWLOCALE
73  locale_t newloc, oldloc;
74 #else
75 # ifdef DISTRHO_USE_CONFIGTHREADLOCALE
76  const int oldthreadloc;
77 # endif
78  char* const oldloc;
79 #endif
80 
81  DISTRHO_DECLARE_NON_COPYABLE(ScopedSafeLocale)
82  DISTRHO_PREVENT_HEAP_ALLOCATION
83 };
84 
85 // -----------------------------------------------------------------------
86 // ScopedSafeLocale class implementation
87 
88 #ifdef DISTRHO_USE_NEWLOCALE
89 static constexpr const locale_t kNullLocale = (locale_t)nullptr;
90 #endif
91 
92 inline ScopedSafeLocale::ScopedSafeLocale() noexcept
93 #ifdef DISTRHO_USE_NEWLOCALE
94  : newloc(::newlocale(LC_NUMERIC_MASK, "C", kNullLocale)),
95  oldloc(newloc != kNullLocale ? ::uselocale(newloc) : kNullLocale) {}
96 #else
97 # ifdef DISTRHO_USE_CONFIGTHREADLOCALE
98  : oldthreadloc(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)),
99 # else
100  :
101 # endif
102  oldloc(strdup(::setlocale(LC_NUMERIC, nullptr)))
103 {
104  ::setlocale(LC_NUMERIC, "C");
105 }
106 #endif
107 
108 inline ScopedSafeLocale::~ScopedSafeLocale() noexcept
109 {
110 #ifdef DISTRHO_USE_NEWLOCALE
111  if (oldloc != kNullLocale)
112  ::uselocale(oldloc);
113  if (newloc != kNullLocale)
114  ::freelocale(newloc);
115 #else // DISTRHO_USE_NEWLOCALE
116  if (oldloc != nullptr)
117  {
118  ::setlocale(LC_NUMERIC, oldloc);
119  std::free(oldloc);
120  }
121 
122 # ifdef DISTRHO_USE_CONFIGTHREADLOCALE
123  if (oldthreadloc != -1)
124  _configthreadlocale(oldthreadloc);
125 # endif
126 #endif // DISTRHO_USE_NEWLOCALE
127 }
128 
129 // -----------------------------------------------------------------------
130 
131 #undef DISTRHO_USE_CONFIGTHREADLOCALE
132 #undef DISTRHO_USE_NEWLOCALE
133 
135 
136 #endif // DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED
Definition: ScopedSafeLocale.hpp:57
#define END_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:949
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:943