This is an (almost) drop-in replacement for the system setlocale(3), taking the same parameters, and returning the same information, except that it returns the correct underlying LC_NUMERIC locale. Regular setlocale will instead return C if the underlying locale has a non-dot decimal point character, or a non-empty thousands separator for displaying floating point numbers. This is because perl keeps that locale category such that it has a dot and empty separator, changing the locale briefly during the operations where the underlying one is required. Perl_setlocale knows about this, and compensates; regular setlocale doesn't.
Another reason it isn't completely a drop-in replacement is that it is declared to return const char *, whereas the system setlocale omits the const (presumably because its API was specified long ago, and can't be updated; it is illegal to change the information setlocale returns; doing so leads to segfaults.)
Finally, Perl_setlocale works under all circumstances, whereas plain setlocale can be completely ineffective on some platforms under some configurations.
Changing the locale is not a good idea when more than one thread is running, except on systems where the predefined variable ${^SAFE_LOCALES} is non-zero. This is because on such systems the locale is global to the whole process and not local to just the thread calling the function. So changing it in one thread instantaneously changes it in all. On some such systems, the system setlocale() is ineffective, returning the wrong information, and failing to actually change the locale. z/OS refuses to try to change the locale once a second thread is created. Perl_setlocale, should give you accurate results of what actually happened on these problematic platforms, returning NULL if the system forbade the locale change.
The return points to a per-thread static buffer, which is overwritten the next time Perl_setlocale is called from the same thread.
This is a thread-safe version of the libc localeconv(3). It is the same as POSIX::localeconv (returning a hash of the localeconv() fields), but directly callable from XS code. The hash is mortalized, so must be dealt with immediately.
These perform the equivalent functionality as the system nl_langinfo(3), taking the same item parameter values, but are preferred over calling that directly because they are portable to platforms lacking that function, are thread-safe, and can automatically handle UTF-8 strings.
The simplest to use is sv_langinfo. It returns an SV containing the correct PV and UTF8ness, requiring no extra muss or fuss from you. New code should use this form.
Perl_langinfo and Perl_langinfo8 are retained for backwards compatibility. Perl_langinfo is an (almost) drop-in replacement for the system nl_langinfo(3), but exists on systems that lack a native nl_langinfo.
Perl_langinfo8 is identical to Perl_langinfo except for an additional parameter, a pointer to a variable declared as "utf8ness_t", into which it returns to you how you should treat the returned string with regards to it being encoded in UTF-8 or not.
Perl_langinfo and Perl_langinfo8 share private per-thread memory that will be changed the next time either one of them is called with any input, but not before.
Concerning the differences between these functions and plain nl_langinfo():
- a.
-
Perl_langinfo8has an extra parameter, described above. Besides this, the other reason they aren't quite a drop-in replacement is actually an advantage. Theconstness of the return allows the compiler to catch attempts to write into the returned buffer, which is illegal and could cause run-time crashes. - b.
-
They deliver the correct results for the
RADIXCHARandTHOUSEPitems, without you having to write extra code. The reason for the extra code would be because these are from theLC_NUMERIClocale category, which is normally kept set by Perl so that the radix is a dot, and the separator is the empty string, no matter what the underlying locale is supposed to be, and so to get the expected results, you have to temporarily toggle into the underlying locale, and later toggle back. (You could use plainnl_langinfoand"STORE_LC_NUMERIC_FORCE_TO_UNDERLYING"for this but then you wouldn't get the other advantages ofPerl_langinfo(); not keepingLC_NUMERICin the C (or equivalent) locale would break a lot of CPAN, which is expecting the radix (decimal point) character to be a dot.) - c.
-
The system function they replace can have its static return buffer trashed, not only by a subsequent call to that function, but by a
freelocale,setlocale, or other locale change.sv_langinfosidesteps this problem entirely; the returned buffer of the other two is not changed until the next call to one or the other, so the buffer is never in a trashed state. - d.
-
The return buffer of
Perl_langinfoandPerl_langinfo8is per-thread so it also is never overwritten by a call to these functions from another thread; unlike the function they replace. - e.
-
But most importantly, they work on systems that don't have
nl_langinfo, such as Windows, hence making your code more portable. Of the fifty-some possible items specified by the POSIX 2008 standard, https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/langinfo.h.html, only one is completely unimplemented, though on non-Windows platforms, another significant one is not fully implemented). They use various techniques to recover the other items, including callinglocaleconv(3), andstrftime(3), both of which are specified in C89, so should be always be available. Laterstrftime()versions have additional capabilities. If an item is not available on your system, this returns either the value associated with the C locale, or simply"", whichever is more appropriate.It is important to note that, when called with an item that is recovered by using
localeconv, the buffer from any previous explicit call tolocaleconv(3)will be overwritten. But you shouldn't be usinglocaleconvanyway because it is is very much not thread-safe, and suffers from the same problems outlined in item 'b.' above for the fields it returns that are controlled by the LC_NUMERIC locale category. Instead, avoid all of those problems by calling "Perl_localeconv", which is thread-safe; or by using the methods given in perlcall to callPOSIX::localeconv(), which is also thread-safe.
The details for those items which may deviate from what this emulation returns and what a native nl_langinfo() would return are specified in I18N::Langinfo.
These implement the libc strftime().
On failure, they return NULL, and set errno to EINVAL.
sv_strftime_tm and sv_strftime_ints are preferred, as they transparently handle the UTF-8ness of the current locale, the input fmt, and the returned result. Only if the current LC_TIME locale is a UTF-8 one (and use bytes is not in effect) will the result be marked as UTF-8.
my_strftime is kept for backwards compatibility. Knowing if its result should be considered UTF-8 or not requires significant extra logic.
Note that all three functions are always executed in the underlying LC_TIME locale of the program, giving results based on that locale.
The functions differ as follows:
sv_strftime_tm takes a pointer to a filled-in struct tm parameter. It ignores the values of the wday and yday fields in it. The other fields give enough information to accurately calculate these values, and are used for that purpose.
The caller assumes ownership of the returned SV with a reference count of 1.
sv_strftime_ints takes a bunch of integer parameters that together completely define a given time. It calculates the struct tm to pass to libc strftime(), and calls that function.
The value of isdst is used as follows:
- 0
-
No daylight savings time is in effect
- >0
-
Check if daylight savings time is in effect, and adjust the results accordingly.
- <0
-
This value is reserved for internal use by the POSIX module for backwards compatibility purposes.
The caller assumes ownership of the returned SV with a reference count of 1.
my_strftime is like sv_strftime_ints except that:
- The
fmtparameter and the return arechar *instead ofSV *. -
This means the UTF-8ness of the result is unspecified. The result MUST be arranged to be FREED BY THE CALLER).
- The
is_dstparameter is ignored. -
Daylight savings time is never considered to be in effect.
- It has extra parameters
ydayandwdaythat are ignored. -
These exist only for historical reasons; the values for the corresponding fields in
struct tmare calculated from the other arguments.
Note that all three functions are always executed in the underlying LC_TIME locale of the program, giving results based on that locale.
This function copies the locale state of the calling thread into the program's global locale, and converts the thread to use that global locale.
It is intended so that Perl can safely be used with C libraries that access the global locale and which can't be converted to not access it. Effectively, this means libraries that call setlocale(3) on non-Windows systems. (For portability, it is a good idea to use it on Windows as well.)
A downside of using it is that it disables the services that Perl provides to hide locale gotchas from your code. The service you most likely will miss regards the radix character (decimal point) in floating point numbers. Code executed after this function is called can no longer just assume that this character is correct for the current circumstances.
To return to Perl control, and restart the gotcha prevention services, call "sync_locale". Behavior is undefined for any pure Perl code that executes while the switch is in effect.
The global locale and the per-thread locales are independent. As long as just one thread converts to the global locale, everything works smoothly. But if more than one does, they can easily interfere with each other, and races are likely. On Windows systems prior to Visual Studio 15 (at which point Microsoft fixed a bug), races can occur (even if only one thread has been converted to the global locale), but only if you use the following operations:
- POSIX::localeconv
- I18N::Langinfo, items
CRNCYSTRandTHOUSEP - "sv_langinfo" in perlapi, items
CRNCYSTRandTHOUSEP
The first item is not fixable (except by upgrading to a later Visual Studio release), but it would be possible to work around the latter two items by having Perl change its algorithm for calculating these to use Windows API functions (likely GetNumberFormat and GetCurrencyFormat); patches welcome.
XS code should never call plain setlocale, but should instead be converted to either call Perl_setlocale (which is a drop-in for the system setlocale) or use the methods given in perlcall to call POSIX::setlocale. Either one will transparently properly handle all cases of single- vs multi-thread, POSIX 2008-supported or not.
This function copies the state of the program global locale into the calling thread, and converts that thread to using per-thread locales, if it wasn't already, and the platform supports them. The LC_NUMERIC locale is toggled into the standard state (using the C locale's conventions), if not within the lexical scope of use locale.
Perl will now consider itself to have control of the locale.
Since unthreaded perls have only a global locale, this function is a no-op without threads.
This function is intended for use with C libraries that do locale manipulation. It allows Perl to accommodate the use of them. Call this function before transferring back to Perl space so that it knows what state the C code has left things in.
XS code should not manipulate the locale on its own. Instead, Perl_setlocale can be used at any time to query or change the locale (though changing the locale is antisocial and dangerous on multi-threaded systems that don't have multi-thread safe locale operations. (See "Multi-threaded operation" in perllocale).
Using the libc setlocale(3) function should be avoided. Nevertheless, certain non-Perl libraries called from XS, do call it, and their behavior may not be able to be changed. This function, along with "switch_to_global_locale", can be used to get seamless behavior in these circumstances, as long as only one thread is involved.
If the library has an option to turn off its locale manipulation, doing that is preferable to using this mechanism. Gtk is such a library.
The return value is a boolean: TRUE if the global locale at the time of call was in effect for the caller; and FALSE if a per-thread locale was in effect.