Skip to content

Commit

Permalink
Locale settings from the <stdlib/locale.h> are now applied in thread-…
Browse files Browse the repository at this point in the history
…local context
  • Loading branch information
sadko4u committed Aug 30, 2024
1 parent 5b7b5e1 commit e9395fb
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 14 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*******************************************************************************

=== 1.0.38 ===

* Locale settings from the <stdlib/locale.h> are now applied in thread-local context.

=== 1.0.37 ===
* Updated definition of atomic operations.
Expand Down
76 changes: 63 additions & 13 deletions include/lsp-plug.in/stdlib/locale.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,79 @@
#include <lsp-plug.in/common/version.h>

#include <lsp-plug.in/common/finally.h>
#include <lsp-plug.in/common/types.h>
#include <locale.h>
#include <string.h>

#define SET_LOCALE_MANGLE2(prefix, postfix) prefix ## _ ## postfix
#define SET_LOCALE_MANGLE1(prefix, postfix) SET_LOCALE_MANGLE2(prefix, postfix)
#define SET_LOCALE_MANGLE(var) SET_LOCALE_MANGLE1(var, __COUNTER__)

#define SET_LOCALE_SCOPED_VAR(tmp_var, lc, value) \
char *tmp_var = setlocale(lc, NULL); \
if (tmp_var != NULL) \
{ \
size_t ___len = strlen(tmp_var) + 1; \
char *___copy = static_cast<char *>(alloca(___len)); \
memcpy(___copy, tmp_var, ___len); \
tmp_var = ___copy; \
} \
setlocale(lc, value); \
#ifdef PLATFORM_WINDOWS
#define SET_LOCALE_SCOPED_VAR(state, old, old_len, buf, lc, value) \
int state = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); \
char *old = setlocale(lc, NULL); \
if (old != NULL) \
{ \
size_t old_len = strlen(tmp_var) + 1; \
char *buf = static_cast<char *>(alloca(old_len)); \
memcpy(buf, old, old_len); \
old = buf; \
} \
setlocale(lc, value); \
lsp_finally { \
if (old != NULL) \
::setlocale(lc, old); \
if (state >= 0) \
_configthreadlocale(state); \
}

#define SET_LOCALE_SCOPED(lc, value) SET_LOCALE_SCOPED_VAR( \
SET_LOCALE_MANGLE(__state), \
SET_LOCALE_MANGLE(__old), \
SET_LOCALE_MANGLE(__len), \
SET_LOCALE_MANGLE(__buf), \
lc, \
value)

#else

#define SET_LOCALE_SCOPED_VAR(old, new, lc, value) \
locale_t old = ::lsp::detail::INVALID_LOCALE; \
locale_t new = ::lsp::detail::create_locale(lc, value); \
if (new != ::lsp::detail::INVALID_LOCALE) \
old = uselocale(new); \
lsp_finally { \
if (tmp_var != NULL) \
::setlocale(LC_NUMERIC, tmp_var); \
if (old != ::lsp::detail::INVALID_LOCALE) \
uselocale(old); \
if (new != ::lsp::detail::INVALID_LOCALE) \
freelocale(new); \
}

#define SET_LOCALE_SCOPED(lc, value) SET_LOCALE_SCOPED_VAR(SET_LOCALE_MANGLE(tmp_var), lc, value)
#define SET_LOCALE_SCOPED(lc, value) SET_LOCALE_SCOPED_VAR( \
SET_LOCALE_MANGLE(__old), \
SET_LOCALE_MANGLE(__new), \
lc, \
value)

namespace lsp
{
namespace detail
{
constexpr locale_t INVALID_LOCALE = (locale_t)0;

/**
* Create locale object based on locale type and name
* @param type locale type
* @param name locale name
* @return created locale object
*/
LSP_COMMON_LIB_PUBLIC
locale_t create_locale(int type, const char *name);
} /* namespace detail */
} /* namespace lsp */

#endif /* PLATFORM_WINDOWS */


#endif /* LSP_PLUG_IN_STDLIB_LOCALE_H_ */
62 changes: 62 additions & 0 deletions src/main/locale.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2024 Linux Studio Plugins Project <https://lsp-plug.in/>
* (C) 2024 Vladimir Sadovnikov <[email protected]>
*
* This file is part of lsp-common-lib
* Created on: 30 авг. 2024 г.
*
* lsp-common-lib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* lsp-common-lib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with lsp-common-lib. If not, see <https://www.gnu.org/licenses/>.
*/

#include <lsp-plug.in/stdlib/locale.h>

#ifndef PLATFORM_WINDOWS

namespace lsp
{
namespace detail
{
LSP_COMMON_LIB_PUBLIC
locale_t create_locale(int type, const char *name)
{
int flags;
switch (type)
{
case LC_CTYPE: flags = LC_CTYPE_MASK; break;
case LC_NUMERIC: flags = LC_NUMERIC_MASK; break;
case LC_TIME: flags = LC_TIME_MASK; break;
case LC_COLLATE: flags = LC_COLLATE_MASK; break;
case LC_MONETARY: flags = LC_MONETARY_MASK; break;
case LC_MESSAGES: flags = LC_MESSAGES_MASK; break;
case LC_ALL: flags = LC_ALL_MASK; break;
#if defined(PLATFORM_LINUX)
case LC_PAPER: flags = LC_PAPER_MASK; break;
case LC_NAME: flags = LC_NAME_MASK; break;
case LC_ADDRESS: flags = LC_ADDRESS_MASK; break;
case LC_TELEPHONE: flags = LC_TELEPHONE_MASK; break;
case LC_MEASUREMENT: flags = LC_MEASUREMENT_MASK; break;
case LC_IDENTIFICATION: flags = LC_IDENTIFICATION_MASK; break;
#endif /* PLATFORM_LINUX */

default:
return INVALID_LOCALE;
}

return newlocale(flags, name, INVALID_LOCALE);
}

} /* namespace detail */
} /* namespace lsp */

#endif /* PLATFORM_WINDOWS */
47 changes: 47 additions & 0 deletions src/test/utest/locale.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2024 Linux Studio Plugins Project <https://lsp-plug.in/>
* (C) 2024 Vladimir Sadovnikov <[email protected]>
*
* This file is part of lsp-common-lib
* Created on: 30 авг. 2024 г.
*
* lsp-common-lib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* lsp-common-lib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with lsp-common-lib. If not, see <https://www.gnu.org/licenses/>.
*/

#include <lsp-plug.in/stdlib/locale.h>
#include <lsp-plug.in/test-fw/utest.h>

using namespace lsp;

UTEST_BEGIN("common", locale)

UTEST_MAIN
{
double value = 1234.5678;

printf("Testing locale setup");
{
SET_LOCALE_SCOPED(LC_ALL, "C");
printf(" Floating-point number using 'C' locale: %.4f\n", value);
}

printf(" Floating-point number using current locale: %.4f\n", value);
}

UTEST_END





0 comments on commit e9395fb

Please sign in to comment.