Dusk Audio Framework
Loading...
Searching...
No Matches
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 DAF_SCOPED_SAFE_LOCALE_HPP_INCLUDED
18#define DAF_SCOPED_SAFE_LOCALE_HPP_INCLUDED
19
20#include "../DafUtils.hpp"
21
22#include <clocale>
23
24#if ! (defined(DAF_OS_HAIKU) || defined(DAF_OS_MAC) || defined(DAF_OS_WINDOWS))
25# define DAF_USE_NEWLOCALE
26#endif
27
28#if defined(DAF_OS_WINDOWS) && __MINGW64_VERSION_MAJOR >= 5
29# define DAF_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 */
57class ScopedSafeLocale {
58public:
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
71private:
72#ifdef DAF_USE_NEWLOCALE
73 locale_t newloc, oldloc;
74#else
75# ifdef DAF_USE_CONFIGTHREADLOCALE
76 const int oldthreadloc;
77# endif
78 char* const oldloc;
79#endif
80
81 DAF_DECLARE_NON_COPYABLE(ScopedSafeLocale)
82 DAF_PREVENT_HEAP_ALLOCATION
83};
84
85// -----------------------------------------------------------------------
86// ScopedSafeLocale class implementation
87
88#ifdef DAF_USE_NEWLOCALE
89static constexpr const locale_t kNullLocale = (locale_t)nullptr;
90#endif
91
92inline ScopedSafeLocale::ScopedSafeLocale() noexcept
93#ifdef DAF_USE_NEWLOCALE
94 : newloc(::newlocale(LC_NUMERIC_MASK, "C", kNullLocale)),
95 oldloc(newloc != kNullLocale ? ::uselocale(newloc) : kNullLocale) {}
96#else
97# ifdef DAF_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
108inline ScopedSafeLocale::~ScopedSafeLocale() noexcept
109{
110#ifdef DAF_USE_NEWLOCALE
111 if (oldloc != kNullLocale)
112 ::uselocale(oldloc);
113 if (newloc != kNullLocale)
114 ::freelocale(newloc);
115#else // DAF_USE_NEWLOCALE
116 if (oldloc != nullptr)
117 {
118 ::setlocale(LC_NUMERIC, oldloc);
119 std::free(oldloc);
120 }
121
122# ifdef DAF_USE_CONFIGTHREADLOCALE
123 if (oldthreadloc != -1)
124 _configthreadlocale(oldthreadloc);
125# endif
126#endif // DAF_USE_NEWLOCALE
127}
128
129// -----------------------------------------------------------------------
130
131#undef DAF_USE_CONFIGTHREADLOCALE
132#undef DAF_USE_NEWLOCALE
133
135
136#endif // DAF_SCOPED_SAFE_LOCALE_HPP_INCLUDED
#define END_NAMESPACE_DAF
Definition DafInfo.hpp:996
#define START_NAMESPACE_DAF
Definition DafInfo.hpp:990