Skip to content

Commit

Permalink
locale.c: Inline only remaining use of querylocale_l()
Browse files Browse the repository at this point in the history
Future commits would make this macro need to be a function anyway, and
since there is only one use of it, just inline it.  The assertion it
defines is no longer needed, as we know that the one place it is now
placed is valid.

This also adds explanatory comments
  • Loading branch information
khwilliamson committed May 6, 2023
1 parent d1c7a6c commit 05054ac
Showing 1 changed file with 68 additions and 37 deletions.
105 changes: 68 additions & 37 deletions locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@ S_stdize_locale(pTHX_ const int category,
# define void_setlocale_r_with_caller(cat, locale, file, line) \
STMT_START { \
if (! bool_setlocale_r(cat, locale)) \
setlocale_failure_panic_via_i(get_category_index(cat, locale), \
setlocale_failure_panic_via_i(get_category_index(cat), \
NULL, locale, __LINE__, 0, \
file, line); \
} STMT_END
Expand Down Expand Up @@ -1249,26 +1249,6 @@ S_less_dicey_bool_setlocale_r(pTHX_ const int cat, const char * locale)
# define querylocale_i(i) querylocale_2008_i(i)
# define querylocale_c(cat) querylocale_i(cat##_INDEX_)
# define querylocale_r(cat) querylocale_i(get_category_index(cat))

# ifdef USE_QUERYLOCALE
# define isSINGLE_BIT_SET(mask) isPOWER_OF_2(mask)

/* This code used to think querylocale() was valid on LC_ALL. Make sure
* all instances of that have been removed */
# define QUERYLOCALE_ASSERT(index) \
__ASSERT_(isSINGLE_BIT_SET(category_masks[index]))
# if ! defined(HAS_QUERYLOCALE) && ( defined(_NL_LOCALE_NAME) \
&& defined(HAS_NL_LANGINFO_L))
# define querylocale_l(index, locale_obj) \
(QUERYLOCALE_ASSERT(index) \
mortalized_pv_copy(nl_langinfo_l( \
_NL_LOCALE_NAME(categories[index]), locale_obj)))
# else
# define querylocale_l(index, locale_obj) \
(QUERYLOCALE_ASSERT(index) \
mortalized_pv_copy(querylocale(category_masks[index], locale_obj)))
# endif
# endif
# if defined(__GLIBC__) && defined(USE_LOCALE_MESSAGES)
# define HAS_GLIBC_LC_MESSAGES_BUG
# include <libintl.h>
Expand All @@ -1281,19 +1261,46 @@ S_querylocale_2008_i(pTHX_ const unsigned int index)
assert(index <= LC_ALL_INDEX_);

/* This function returns the name of the locale category given by the input
* index into our parallel tables of them.
* 'index' into our parallel tables of them.
*
* POSIX 2008, for some sick reason, chose not to provide a method to find
* the category name of a locale, discarding a basic linguistic tenet that
* for any object, people will create a name for it. Some vendors have
* created a querylocale() function to do just that. This function is a
* lot simpler to implement on systems that have this. Otherwise, we have
* to keep track of what the locale has been set to, so that we can return
* its name so as to emulate setlocale(). It's also possible for C code in
* some library to change the locale without us knowing it, though as of
* September 2017, there are no occurrences in CPAN of uselocale(). Some
* libraries do use setlocale(), but that changes the global locale, and
* threads using per-thread locales will just ignore those changes. */
* the category name of a locale, disregarding a basic linguistic tenet
* that for any object, people will create a name for it. (The next
* version of the POSIX standard is proposed to fix this.) Some vendors
* have created a querylocale() function to do this in the meantime. On
* systems without querylocale(), we have to keep track of what the locale
* has been set to, so that we can return its name so as to emulate
* setlocale(). There are potential problems with this:
*
* 1) We don't know what calling newlocale() with the locale argument ""
* actually does. It gets its values from the program's environment.
* find_locale_from_environment() is used to work around this. But it
* isn't fool-proof. See the comments for that function for details.
* 2) It's possible for C code in some library to change the locale
* without us knowing it, and thus our records become wrong;
* querylocale() would catch this. But as of September 2017, there
* are no occurrences in CPAN of uselocale(). Some libraries do use
* setlocale(), but that changes the global locale, and threads using
* per-thread locales will just ignore those changes.
* 3) Many systems have multiple names for the same locale. Generally,
* there is an underlying base name, with aliases that evaluate to it.
* On some systems, if you set the locale to an alias, and then
* retrieve the name, you get the alias as expected; but on others you
* get the base name, not the alias you used. And sometimes the
* charade is incomplete. See
* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=269375.
*
* The code is structured so that the returned locale name when the
* locale is changed is whatever the result of querylocale() on the
* new locale is. This effectively gives the result the system
* expects. Without querylocale, the name returned is always the
* input name. Theoretically this could cause problems, but khw knows
* of none so far, but mentions it here in case you are trying to
* debug something. (This could be worked around by messing with the
* global locale temporarily, using setlocale() to get the base name;
* but that could cause a race. The comments for
* find_locale_from_environment() give details on the potential race.)
*/

const locale_t cur_obj = uselocale((locale_t) 0);
const char * retval;
Expand Down Expand Up @@ -1336,11 +1343,35 @@ S_querylocale_2008_i(pTHX_ const unsigned int index)

# else /* No PL_CURLOCALES means must have some form of querylocale */

/* We don't currently keep records when there is querylocale(), so have
* to get it anew each time */
retval = (index == LC_ALL_INDEX_)
? calculate_LC_ALL_string(NULL)
: querylocale_l(index, cur_obj);
/* We don't keep records when there is querylocale(), so as to avoid the
* pitfalls mentioned at the beginning of this function.
*
* That means LC_ALL has to be calculated from all its constituent
* categories each time, since the querylocale() forms only work on
* individual categories */
if (index == LC_ALL_INDEX_) {
retval = calculate_LC_ALL_string(NULL);
}
else {

# if defined(USE_QUERYLOCALE) && defined(_NL_LOCALE_NAME)

/* glibc has this querylocale() equivalent, which experience so far
* shows is thread-safe, along with its nl_langinfo_l() */
retval = mortalized_pv_copy(
nl_langinfo_l(_NL_LOCALE_NAME(categories[index]),
cur_obj));
# else
retval = mortalized_pv_copy(querylocale(category_masks[index],
cur_obj));
QUERYLOCALE_UNLOCK;

# undef QUERYLOCALE_LOCK
# undef QUERYLOCALE_UNLOCK
# endif

}

# endif

}
Expand Down

0 comments on commit 05054ac

Please sign in to comment.