This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Document API for XS LC_NUMERIC locale manipulation
authorKarl Williamson <khw@cpan.org>
Thu, 19 Mar 2015 20:39:06 +0000 (14:39 -0600)
committerKarl Williamson <khw@cpan.org>
Thu, 19 Mar 2015 22:18:00 +0000 (16:18 -0600)
XS writers may need to manipulate the LC_NUMERIC locale.  Some macros
are available to do this.  This documents them and the issues.

dist/ExtUtils-ParseXS/lib/perlxs.pod
perl.h
pod/perldelta.pod

index 8d762a8..d77ac1b 100644 (file)
@@ -2141,13 +2141,18 @@ this model, the less likely conflicts will occur.
 
 One area where there has been conflict is in regards to C locales.  (See
 L<perllocale>.)  perl, with one exception and unless told otherwise,
-sets up the underlying locale the program is running in to that passed
-into it from the environment.  As of v5.20, this underlying locale is
-completely hidden from pure perl code outside the lexical scope of
-C<S<use locale>>; except a couple of function calls in the POSIX
-module of necessity use it.  But the underlying locale, with that one
-exception is exposed to XS code, affecting all C library routines whose
-behavior is locale-dependent.   The exception is the
+sets up the underlying locale the program is running in to the locale
+passed
+into it from the environment.  This is an important difference from a
+generic C language program, where the underlying locale is the "C"
+locale unless the program changes it.  As of v5.20, this underlying
+locale is completely hidden from pure perl code outside the lexical
+scope of C<S<use locale>> except for a couple of function calls in the
+POSIX module which of necessity use it.  But the underlying locale, with
+that
+one exception is exposed to XS code, affecting all C library routines
+whose behavior is locale-dependent.  Your XS code better not assume that
+the underlying locale is "C".  The exception is the
 L<C<LC_NUMERIC>|perllocale/Category LC_NUMERIC: Numeric Formatting>
 locale category, and the reason it is an exception is that experience
 has shown that it can be problematic for XS code, whereas we have not
@@ -2174,16 +2179,20 @@ may call a C library function that is.  Hopefully the man page for such
 a function will indicate that dependency, but the documentation is
 imperfect.
 
-The current locale is exposed to XS code except possibly C<LC_NUMERIC>.
-There have not been reports of problems with these other categories.
+The current locale is exposed to XS code except possibly C<LC_NUMERIC>
+(explained in the next paragraph).
+There have not been reports of problems with the other categories.
+Perl initializes things on start-up so that the current locale is the
+one which is indicated by the user's environment in effect at that time.
+See L<perllocale/ENVIRONMENT>.
 
-Up through v5.20, Perl initializes things on start-up so that
-C<LC_NUMERIC> is set to the "C" locale.  But if any code anywhere
-changes it, it will stay changed.  This means that your module can't
+However, up through v5.20, Perl initialized things on start-up so that
+C<LC_NUMERIC> was set to the "C" locale.  But if any code anywhere
+changed it, it would stay changed.  This means that your module can't
 count on C<LC_NUMERIC> being something in particular, and you can't
 expect floating point numbers (including version strings) to have dots
 in them.  If you don't allow for a non-dot, your code could break if
-anyone anywhere changes the locale.  For this reason, v5.22 is changing
+anyone anywhere changed the locale.  For this reason, v5.22 changed
 the behavior so that Perl tries to keep C<LC_NUMERIC> in the "C" locale
 except around the operations internally where it should be something
 else.  Misbehaving XS code will always be able to change the locale
@@ -2201,15 +2210,13 @@ C<Gtk>.  This can cause problems for the perl core and other modules.
 Starting in v5.20.1, calling the function
 L<sync_locale()|perlapi/sync_locale> from XS should be sufficient to
 avoid most of these problems.  Prior to this, you need a pure Perl
-segment that does this:
+statement that does this:
 
  POSIX::setlocale(LC_ALL, POSIX::setlocale(LC_ALL));
 
-Macros are provided for XS code to temporarily change to use the
-underlying C<LC_NUMERIC> locale when necessary.  An API is being
-developed for this, but has not yet been nailed down, but will be during
-the course of v5.21.  Send email to L<mailto:perl5-porters@perl.org> for
-guidance.
+In the event that your XS code may need the underlying C<LC_NUMERIC>
+locale, there are macros available to access this; see
+L<perlapi/Locale-related functions and macros>.
 
 =back
 
diff --git a/perl.h b/perl.h
index d9d673b..21a5d9b 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -5867,7 +5867,98 @@ typedef struct am_table_short AMTS;
 #ifdef USE_LOCALE_NUMERIC
 
 /* These macros are for toggling between the underlying locale (UNDERLYING or
- * LOCAL) and the C locale (STANDARD). */
+ * LOCAL) and the C locale (STANDARD).
+
+=head1 Locale-related functions and macros
+
+=for apidoc Amn|void|DECLARATION_FOR_LC_NUMERIC_MANIPULATION
+
+This macro should be used as a statement.  It declares a private variable
+(whose name begins with an underscore) that is needed by the other macros in
+this section.  Failing to include this correctly should lead to a syntax error.
+For compatibility with C89 C compilers it should be placed in a block before
+any executable statements.
+
+=for apidoc Am|void|STORE_LC_NUMERIC_FORCE_TO_UNDERLYING
+
+This is used by XS code that that is C<LC_NUMERIC> locale-aware to force the
+locale for category C<LC_NUMERIC> to be what perl thinks is the current
+underlying locale.  (The perl interpreter could be wrong about what the
+underlying locale actually is if some C or XS code has called the C library
+function L<setlocale(3)> behind its back; calling L</sync_locale> before calling
+this macro will update perl's records.)
+
+A call to L</DECLARATION_FOR_LC_NUMERIC_MANIPULATION> must have been made to
+declare at compile time a private variable used by this macro.  This macro
+should be called as a single statement, not an expression, but with an empty
+argument list, like this:
+
+ {
+    DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
+     ...
+    STORE_LC_NUMERIC_FORCE_TO_UNDERLYING();
+     ...
+    RESTORE_LC_NUMERIC();
+     ...
+ }
+
+The private variable is used to save the current locale state, so
+that the requisite matching call to L</RESTORE_LC_NUMERIC> can restore it.
+
+=for apidoc Am|void|STORE_LC_NUMERIC_SET_TO_NEEDED
+
+This is used to help wrap XS or C code that that is C<LC_NUMERIC> locale-aware.
+This locale category is generally kept set to the C locale by Perl for
+backwards compatibility, and because most XS code that reads floating point
+values can cope only with the decimal radix character being a dot.
+
+This macro makes sure the current C<LC_NUMERIC> state is set properly, to be
+aware of locale if the call to the XS or C code from the Perl program is
+from within the scope of a S<C<use locale>>; or to ignore locale if the call is
+instead from outside such scope.
+
+This macro is the start of wrapping the C or XS code; the wrap ending is done
+by calling the L</RESTORE_LC_NUMERIC> macro after the operation.  Otherwise
+the state can be changed that will adversely affect other XS code.
+
+A call to L</DECLARATION_FOR_LC_NUMERIC_MANIPULATION> must have been made to
+declare at compile time a private variable used by this macro.  This macro
+should be called as a single statement, not an expression, but with an empty
+argument list, like this:
+
+ {
+    DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
+     ...
+    STORE_LC_NUMERIC_SET_TO_NEEDED();
+     ...
+    RESTORE_LC_NUMERIC();
+     ...
+ }
+
+=for apidoc Am|void|RESTORE_LC_NUMERIC
+
+This is used in conjunction with one of the macros
+L</STORE_LC_NUMERIC_SET_TO_NEEDED>
+and
+L</STORE_LC_NUMERIC_FORCE_TO_UNDERLYING>
+
+to properly restore the C<LC_NUMERIC> state.
+
+A call to L</DECLARATION_FOR_LC_NUMERIC_MANIPULATION> must have been made to
+declare at compile time a private variable used by this macro and the two
+C<STORE> ones.  This macro should be called as a single statement, not an
+expression, but with an empty argument list, like this:
+
+ {
+    DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
+     ...
+    RESTORE_LC_NUMERIC();
+     ...
+ }
+
+=cut
+
+*/
 
 #define _NOT_IN_NUMERIC_STANDARD (! PL_numeric_standard)
 
index 64fb24b..747bd2f 100644 (file)
@@ -480,7 +480,9 @@ well.
 
 =item *
 
-XXX
+Macros have been created to allow XS code to better manipulate the POSIX
+locale category C<LC_NUMERIC>.
+See L<perlapi/Locale-related functions and macros>.
 
 =back