summaryrefslogtreecommitdiff
path: root/vutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'vutil.c')
-rw-r--r--vutil.c65
1 files changed, 64 insertions, 1 deletions
diff --git a/vutil.c b/vutil.c
index af5f263be7..a66d6ef2f4 100644
--- a/vutil.c
+++ b/vutil.c
@@ -625,7 +625,11 @@ VER_NV:
* locales without letting perl know, therefore we have to find it
* from first principals. See [perl #121930]. */
- /* if it isn't C, set it to C. */
+ /* In windows, or not threaded, or not thread-safe, if it isn't C,
+ * set it to C. */
+
+# ifndef USE_POSIX_2008_LOCALE
+
const char * locale_name_on_entry;
LC_NUMERIC_LOCK(0); /* Start critical section */
@@ -641,6 +645,48 @@ VER_NV:
locale_name_on_entry = NULL;
}
+# else
+
+ const locale_t locale_obj_on_entry = uselocale((locale_t) 0);
+ const char * locale_name_on_entry = NULL;
+ DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
+
+ if (locale_obj_on_entry == LC_GLOBAL_LOCALE) {
+
+ /* in the global locale, we can call system setlocale and if it
+ * isn't C, set it to C. */
+ LC_NUMERIC_LOCK(0);
+
+ locale_name_on_entry = setlocale(LC_NUMERIC, NULL);
+ if ( strNE(locale_name_on_entry, "C")
+ && strNE(locale_name_on_entry, "POSIX"))
+ {
+ setlocale(LC_NUMERIC, "C");
+ }
+ else { /* This value indicates to the restore code that we
+ didn't change the locale */
+ locale_name_on_entry = NULL;
+ }
+ }
+ else if (locale_obj_on_entry == PL_underlying_numeric_obj) {
+ /* Here, the locale appears to have been changed to use the
+ * program's underlying locale. Just use our mechanisms to
+ * switch back to C. It might be possible for this pointer to
+ * actually refer to something else if it got released and
+ * reused somehow. But it doesn't matter, our mechanisms will
+ * work even so */
+ STORE_LC_NUMERIC_SET_STANDARD();
+ }
+ else if (locale_obj_on_entry != PL_C_locale_obj) {
+ /* The C object should be unchanged during a program's
+ * execution, so it should be safe to assume it means what it
+ * says, so if we are in it, no locale change is required.
+ * Otherwise, simply use the thread-safe operation. */
+ uselocale(PL_C_locale_obj);
+ }
+
+# endif
+
/* Prevent recursed calls from trying to change back */
LOCK_LC_NUMERIC_STANDARD();
@@ -660,12 +706,29 @@ VER_NV:
UNLOCK_LC_NUMERIC_STANDARD();
+# ifndef USE_POSIX_2008_LOCALE
+
if (locale_name_on_entry) {
setlocale(LC_NUMERIC, locale_name_on_entry);
}
LC_NUMERIC_UNLOCK; /* End critical section */
+# else
+
+ if (locale_name_on_entry) {
+ setlocale(LC_NUMERIC, locale_name_on_entry);
+ LC_NUMERIC_UNLOCK;
+ }
+ else if (locale_obj_on_entry == PL_underlying_numeric_obj) {
+ RESTORE_LC_NUMERIC();
+ }
+ else if (locale_obj_on_entry != PL_C_locale_obj) {
+ uselocale(locale_obj_on_entry);
+ }
+
+# endif
+
}
#endif /* USE_LOCALE_NUMERIC */