diff --git a/locale.c b/locale.c index a69d26cf7811..3525dc98844c 100644 --- a/locale.c +++ b/locale.c @@ -2,6 +2,7 @@ * 123456789112345678921234567893123456789412345678951234567896123456789712345678981 * strptime + * NO_USE_LOCALE_foo is not the same as no LC_foo * what deltas for stdize changes? subroutines in this file, so as to reorder them * a bunch of copies aren't needed on nonthreaded @@ -5298,6 +5299,11 @@ Perl_localeconv(pTHX) { #if ! defined(HAS_LOCALECONV) + /* XXX We could define our own 'struct lconv' if localeconv is not to be + * used and that typedef isn't present, and then fix up localeconv to + * return its canned strings in this situation, then this function could + * always be defined and would return the C localeconv values. But + * localeconv() is C89, so very likely to be present */ return newHV(); @@ -5310,6 +5316,11 @@ Perl_localeconv(pTHX) } #if defined(HAS_LOCALECONV) +# if ! defined(USE_LOCALE_NUMERIC) || ! defined(USE_LOCALE_MONETARY) + +struct lconv C_lconv; + +# endif HV * S_my_localeconv(pTHX_ const int item) @@ -5419,28 +5430,6 @@ S_my_localeconv(pTHX_ const int item) # define P_CS_PRECEDES_ADDRESS \ &lconv_integers[(C_ARRAY_LENGTH(lconv_integers) - 2)] - /* If we aren't paying attention to a given category, use LC_CTYPE instead; - * If not paying attention to that either, the code below should end up not - * using this. Make sure that things blow up if that avoidance gets lost, - * by setting the category to an out-of-bounds value */ - locale_category_index numeric_index; - locale_category_index monetary_index; - -# ifdef USE_LOCALE_NUMERIC - numeric_index = LC_NUMERIC_INDEX_; -# elif defined(USE_LOCALE_CTYPE) - numeric_index = LC_CTYPE_INDEX_; -# else - numeric_index = LC_ALL_INDEX_; /* Out-of-bounds */ -# endif -# ifdef USE_LOCALE_MONETARY - monetary_index = LC_MONETARY_INDEX_; -# elif defined(USE_LOCALE_CTYPE) - monetary_index = LC_CTYPE_INDEX_; -# else - monetary_index = LC_ALL_INDEX_; /* Out-of-bounds */ -# endif - /* Some platforms, for correct non-mojibake results, require LC_CTYPE's * locale to match LC_NUMERIC's for the numeric fields, and LC_MONETARY's * for the monetary ones. What happens if LC_NUMERIC and LC_MONETARY @@ -5469,13 +5458,8 @@ S_my_localeconv(pTHX_ const int item) # define INDEX_TO_BIT(i) (1 << ((i) - LC_NUMERIC_INDEX_)) STATIC_ASSERT_STMT(LC_MONETARY_INDEX_ == LC_NUMERIC_INDEX_ + 1); - /* The two categories can have disparate locales. Initialize them to C and - * override later whichever one(s) we pay attention to */ - const char * numeric_locale = "C"; - const char * monetary_locale = "C"; - - /* This will be either 'numeric_locale' or 'monetary_locale' depending on - * what we are working on at the moment */ + /* This will be either the NUMERIC or MONETARY depending on what we are + * working on at the moment */ const char * locale; /* The LC_MONETARY category also has some integer-valued fields, whose @@ -5517,7 +5501,9 @@ S_my_localeconv(pTHX_ const int item) * * For each, set up the appropriate parameters for the call below to * S_populate_hash_from_localeconv() */ - if (item != 0) switch (item) { + if (item != 0) { + switch (item) { + // XXX indent default: locale_panic_(Perl_form(aTHX_ "Unexpected item passed to my_localeconv: %d", item)); @@ -5525,8 +5511,9 @@ S_my_localeconv(pTHX_ const int item) # ifdef USE_LOCALE_NUMERIC + // XXX Consider reording these, the numeric can be mostly comb ined case RADIXCHAR: - locale = numeric_locale = PL_numeric_name; + locale = PL_numeric_name; index_bits = INDEX_TO_BIT(LC_NUMERIC_INDEX_); strings[NUMERIC_STRING_OFFSET] = DECIMAL_POINT_ADDRESS; integers = NULL; @@ -5534,7 +5521,7 @@ S_my_localeconv(pTHX_ const int item) case THOUSEP: index_bits = INDEX_TO_BIT(LC_NUMERIC_INDEX_); - locale = numeric_locale = PL_numeric_name; + locale = PL_numeric_name; strings[NUMERIC_STRING_OFFSET] = thousands_sep_string; integers = NULL; break; @@ -5544,7 +5531,7 @@ S_my_localeconv(pTHX_ const int item) case CRNCYSTR: index_bits = INDEX_TO_BIT(LC_MONETARY_INDEX_); - locale = monetary_locale = querylocale_i(LC_MONETARY_INDEX_); + locale = querylocale_i(LC_MONETARY_INDEX_); /* This item needs the values for both the currency symbol, and another * one used to construct the nl_langino()-compatible return */ @@ -5556,32 +5543,38 @@ S_my_localeconv(pTHX_ const int item) } /* End of switch() */ - else /* End of for just one item to emulate nl_langinfo() */ + HV * hv = newHV(); /* The returned hash, initially empty */ + sv_2mortal((SV*)hv); + + /* Call localeconv() and copy its results into the hash. All the + * parameters have been initialized above */ + populate_hash_from_localeconv(hv, + locale, + index_bits, + strings, + integers + ); + return hv; + } # endif - { /* Here, the call is for all of localeconv(). It has a bunch of + // XXX outdent + + /* Here, the call is for all of localeconv(). It has a bunch of * items. As in the individual item case, set up the parameters for * S_populate_hash_from_localeconv(); */ -# ifdef USE_LOCALE_NUMERIC - numeric_locale = PL_numeric_name; -# elif defined(USE_LOCALE_CTYPE) - numeric_locale = querylocale_i(numeric_index); -# endif -# if defined(USE_LOCALE_MONETARY) || defined(USE_LOCALE_CTYPE) - monetary_locale = querylocale_i(monetary_index); -# endif - /* The first call to S_populate_hash_from_localeconv() will be for the * MONETARY values */ - index_bits = INDEX_TO_BIT(monetary_index); - locale = monetary_locale; + index_bits = INDEX_TO_BIT(LC_MONETARY_INDEX_); + locale = querylocale_c(LC_MONETARY); /* And if the locales for the two categories are the same, we can also * do the NUMERIC values in the same call */ - if (strEQ(numeric_locale, monetary_locale)) { - index_bits |= INDEX_TO_BIT(numeric_index); + // XXX reorder condit + if (strEQ(PL_numeric_name, locale)) { + index_bits |= INDEX_TO_BIT(LC_NUMERIC_INDEX_); } else { requires_2nd_localeconv = true; @@ -5596,12 +5589,6 @@ S_my_localeconv(pTHX_ const int item) * say to use them or not */ integers = lconv_integers; - } /* End of call is for localeconv() */ - - /* The code above has determined the parameters to - S_populate_hash_from_localeconv() for both cases of an individual item - and for the entire structure. Below is code common to both */ - HV * hv = newHV(); /* The returned hash, initially empty */ sv_2mortal((SV*)hv); @@ -5619,8 +5606,8 @@ S_my_localeconv(pTHX_ const int item) * NUMERIC fields */ if (requires_2nd_localeconv) { populate_hash_from_localeconv(hv, - numeric_locale, - INDEX_TO_BIT(numeric_index), + PL_numeric_name, + INDEX_TO_BIT(LC_NUMERIC_INDEX_), strings, NULL /* There are no NUMERIC integer fields */ @@ -5647,20 +5634,7 @@ S_my_localeconv(pTHX_ const int item) * cost which khw doesn't think is worth it */ -# ifndef HAS_SOME_LANGINFO - - /* We are done when called with an individual item. There are no integer - * items to adjust, and it's best for the caller to determine if this - * string item is UTF-8 or not. This is because the locale's UTF-8ness is - * calculated below, and in some Configurations, that can lead to a - * recursive call to here, which could recurse infinitely. */ - - if (item != 0) { - return hv; - } - -# endif - + // XXX could skip the C only strings for (unsigned int i = 0; i < 2; i++) { /* Try both types of strings */ if (! strings[i]) { /* Skip if no strings of this type */ continue; @@ -5744,15 +5718,16 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, * global static buffer. Some locks might be no-ops on this platform, but * not others. We need to lock if any one isn't a no-op. */ -# ifdef USE_LOCALE_CTYPE +# if defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) +# ifdef USE_LOCALE_CTYPE /* Some platforms require LC_CTYPE to be congruent with the category we are * looking for */ const char * orig_CTYPE_locale = toggle_locale_c(LC_CTYPE, locale); LC_CTYPE_LOCK; -# endif -# ifdef USE_LOCALE_NUMERIC +# endif +# ifdef USE_LOCALE_NUMERIC /* We need to toggle to the underlying NUMERIC locale if we are getting * NUMERIC strings */ @@ -5760,7 +5735,7 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, if (which_mask & INDEX_TO_BIT(LC_NUMERIC_INDEX_)) { LC_NUMERIC_LOCK(0); -# if defined(WIN32) +# if defined(WIN32) /* There is a bug in Windows in which setting LC_CTYPE after the others * doesn't actually take effect for localeconv(). See commit @@ -5775,17 +5750,17 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, orig_NUMERIC_locale = toggle_locale_i(LC_NUMERIC_INDEX_, "C"); toggle_locale_i(LC_NUMERIC_INDEX_, locale); -# else +# else /* No need for the extra toggle when not on Windows */ orig_NUMERIC_locale = toggle_locale_i(LC_NUMERIC_INDEX_, locale); -# endif +# endif } -# endif -# if defined(USE_LOCALE_MONETARY) && defined(WIN32) +# endif +# if defined(USE_LOCALE_MONETARY) && defined(WIN32) /* Same Windows bug as described just above for NUMERIC. Otherwise, no * need to toggle LC_MONETARY, as it is kept in the underlying locale */ @@ -5795,14 +5770,14 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, toggle_locale_i(LC_MONETARY_INDEX_, locale); } -# endif +# endif /* Finally ready to do the actual localeconv(). Lock to prevent other * accesses until we have made a copy of its returned static buffer */ LC_MONETARY_LOCK; gwLOCALE_LOCK; -# if defined(TS_W32_BROKEN_LOCALECONV) && defined(USE_THREAD_SAFE_LOCALE) +# if defined(TS_W32_BROKEN_LOCALECONV) && defined(USE_THREAD_SAFE_LOCALE) /* This is a workaround for another bug in Windows. localeconv() was * broken with thread-safe locales prior to VS 15. It looks at the global @@ -5841,17 +5816,55 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, const char * save_global = querylocale_c(LC_ALL); void_setlocale_c(LC_ALL, save_thread); -# endif /* TS_W32_BROKEN_LOCALECONV */ +# endif /* TS_W32_BROKEN_LOCALECONV */ +# endif /* USE_LOCALE_NUMERIC || USE_LOCALE_MONETARY */ /* Finally, do the actual localeconv */ + +# if defined(USE_LOCALE_NUMERIC) && defined(USE_LOCALE_MONETARY) + + /* Both categories change; use the same return throughout */ const char *lcbuf_as_string = (const char *) localeconv(); +# elif ! defined(USE_LOCALE_NUMERIC) && ! defined(USE_LOCALE_MONETARY) + + /* Neither category changeable; use the C results throughout */ + const char *lcbuf_as_string = (const char *) &C_lconv; + +# endif + /* Fill in the string fields of the HV* */ PERL_UINT_FAST8_T working_mask = which_mask; while (working_mask) { const PERL_UINT_FAST8_T i = lsbit_pos(working_mask); working_mask &= ~ (1 << i); +# if ! defined(USE_LOCALE_NUMERIC) || ! defined(USE_LOCALE_MONETARY) +# if defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) + + /* Exactly one category changeable from C */ + const char * lcbuf_as_string; + + /* If changeable, use localeconv(); otherwise use the C values */ +# ifdef USE_LOCALE_NUMERIC + + if (i == NUMERIC_STRING_OFFSET) { + +# else + + if (i == MONETARY_STRING_OFFSET) { + +# endif + + lcbuf_as_string= (const char *) localeconv(); + } + else { + lcbuf_as_string = (const char *) &C_lconv; + } + +# endif +# endif + /* For each field for the given category ... */ const lconv_offset_t * category_strings = strings[i]; while (category_strings->name) { @@ -5886,7 +5899,8 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, /* Done with copying to the hash. Can unwind the critical section locks */ -# if defined(TS_W32_BROKEN_LOCALECONV) && defined(USE_THREAD_SAFE_LOCALE) +# if defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) +# if defined(TS_W32_BROKEN_LOCALECONV) && defined(USE_THREAD_SAFE_LOCALE) /* Restore the global locale's prior state */ void_setlocale_c(LC_ALL, save_global); @@ -5901,31 +5915,32 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, /* Restore the per-thread locale state */ void_setlocale_c(LC_ALL, save_thread); -# endif /* TS_W32_BROKEN_LOCALECONV */ +# endif /* TS_W32_BROKEN_LOCALECONV */ gwLOCALE_UNLOCK; /* Finished with the critical section of a globally-accessible buffer */ LC_MONETARY_UNLOCK; -# if defined(USE_LOCALE_MONETARY) && defined(WIN32) +# if defined(USE_LOCALE_MONETARY) && defined(WIN32) restore_toggled_locale_i(LC_MONETARY_INDEX_, orig_MONETARY_locale); -# endif -# ifdef USE_LOCALE_NUMERIC +# endif +# ifdef USE_LOCALE_NUMERIC restore_toggled_locale_i(LC_NUMERIC_INDEX_, orig_NUMERIC_locale); if (which_mask & INDEX_TO_BIT(LC_NUMERIC_INDEX_)) { LC_NUMERIC_UNLOCK; } -# endif -# ifdef USE_LOCALE_CTYPE +# endif +# ifdef USE_LOCALE_CTYPE restore_toggled_locale_c(LC_CTYPE, orig_CTYPE_locale); LC_CTYPE_UNLOCK; -# endif +# endif +# endif /* USE_LOCALE_NUMERIC || USE_LOCALE_MONETARY */ } @@ -6527,14 +6542,14 @@ S_my_langinfo_i(pTHX_ /* The modification is to prefix the localeconv() return with a * single byte, calculated as follows: */ - char prefix = (LIKELY(SvIV(precedes) != -1)) + char prefix = (LIKELY(SvIV(precedes) != CHAR_MAX)) ? ((precedes != 0) ? '-' : '+') /* khw couldn't find any documentation that - * CHAR_MAX (which we modify to -1) is the signal, - * but cygwin uses it thusly, and it makes sense - * given that CHAR_MAX indicates the value isn't - * used, so it neither precedes nor succeeds */ + * CHAR_MAX is the signal, but cygwin uses it + * thusly, and it makes sense given that CHAR_MAX + * indicates the value isn't used, so it neither + * precedes nor succeeds */ : '.'; /* Now get CRNCYSTR */ @@ -7800,6 +7815,12 @@ Perl_init_i18nl10n(pTHX_ int printwarn) PL_underlying_radix_sv = newSV(1); Newxz(PL_numeric_name, 1, char); /* Single NUL character */ +# else + + PL_numeric_radix_sv = newSVpv(C_decimal_point, 0); + PL_underlying_radix_sv = newSVpv(C_decimal_point, 0); + NewCopy("C", PL_numeric_name, 2, char); + # endif # ifdef USE_LOCALE_COLLATE @@ -7810,6 +7831,49 @@ Perl_init_i18nl10n(pTHX_ int printwarn) Newxz(PL_ctype_name, 1, char); +# endif +# if defined(HAS_LOCALECONV) && ( ! defined(USE_LOCALE_NUMERIC) \ + || ! defined(USE_LOCALE_MONETARY)) + + if (C_lconv.decimal_point == NULL) { + C_lconv.thousands_sep = (char *) ""; + +# ifndef NO_LOCALECONV_GROUPING + C_lconv.grouping = (char *) ""; +# endif + + C_lconv.currency_symbol = (char *) ""; + C_lconv.decimal_point = (char *) C_decimal_point; + C_lconv.frac_digits = CHAR_MAX; + C_lconv.int_curr_symbol = (char *) ""; + C_lconv.int_frac_digits = CHAR_MAX; + C_lconv.mon_decimal_point = (char *) ""; + C_lconv.n_cs_precedes = CHAR_MAX; + C_lconv.negative_sign = (char *) ""; + C_lconv.n_sep_by_space = CHAR_MAX; + C_lconv.n_sign_posn = CHAR_MAX; + C_lconv.p_cs_precedes = CHAR_MAX; + C_lconv.positive_sign = (char *) ""; + C_lconv.p_sep_by_space = CHAR_MAX; + C_lconv.p_sign_posn = CHAR_MAX; + +# ifndef NO_LOCALECONV_MON_THOUSANDS_SEP + C_lconv.mon_thousands_sep = (char *) ""; +# endif +# ifndef NO_LOCALECONV_MON_GROUPING + C_lconv.mon_grouping = (char *) ""; +# endif +# ifdef HAS_LC_MONETARY_2008 + C_lconv.int_p_cs_precedes = CHAR_MAX; + C_lconv.int_p_sep_by_space = CHAR_MAX; + C_lconv.int_n_cs_precedes = CHAR_MAX; + C_lconv.int_n_sep_by_space = CHAR_MAX; + C_lconv.int_p_sign_posn = CHAR_MAX; + C_lconv.int_n_sign_posn = CHAR_MAX; +# endif + + } + # endif new_LC_ALL("C", true /* Don't shortcut */); diff --git a/locale_table.h b/locale_table.h index e9100c593d2a..b2545e6055fe 100644 --- a/locale_table.h +++ b/locale_table.h @@ -15,7 +15,8 @@ * given here. That order is mostly arbitrary. LC_CTYPE is first because when * we are setting multiple categories, CTYPE often needs to match the other(s), * and the way the code is constructed, if we set the other category first, we - * might otherwise have to set CTYPE twice. + * might otherwise have to set CTYPE twice. LC_MONETARY directly follows + * LC_NUMERIC for faster computation with localeconv(). * * Each entry takes the token giving the category name, and either the name of * a function to call that does specialized set up for this category when it is diff --git a/perl.c b/perl.c index 298350d1c5bb..5e540dde55c5 100644 --- a/perl.c +++ b/perl.c @@ -1165,14 +1165,12 @@ perl_destruct(pTHXx) PL_scratch_locale_obj = NULL; } #endif -#ifdef USE_LOCALE_NUMERIC Safefree(PL_numeric_name); PL_numeric_name = NULL; SvREFCNT_dec(PL_numeric_radix_sv); PL_numeric_radix_sv = NULL; SvREFCNT_dec(PL_underlying_radix_sv); PL_underlying_radix_sv = NULL; -#endif #ifdef USE_LOCALE_CTYPE Safefree(PL_ctype_name); PL_ctype_name = NULL; diff --git a/sv.c b/sv.c index e1556f4dbbf2..494b0e132647 100644 --- a/sv.c +++ b/sv.c @@ -16093,10 +16093,11 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, PL_locale_mutex_depth = 0; #endif -#ifdef USE_LOCALE_NUMERIC + // SAVEPV? PL_numeric_name = SAVEPV("C"); PL_numeric_radix_sv = newSVpvs("."); PL_underlying_radix_sv = newSVpvs("."); +#ifdef USE_LOCALE_NUMERIC PL_numeric_standard = true; PL_numeric_underlying = true; PL_numeric_underlying_is_standard = true; diff --git a/win32/GNUmakefile b/win32/GNUmakefile index 8c9c67768f98..40b92bc214fd 100644 --- a/win32/GNUmakefile +++ b/win32/GNUmakefile @@ -489,6 +489,7 @@ GCCVER := $(shell $(GCCBIN) -dumpversion) GCCVER1 := $(shell for /f "delims=. tokens=1,2,3" %%i in ('$(GCCBIN) -dumpversion') do echo %%i) GCCVER2 := $(shell for /f "delims=. tokens=1,2,3" %%i in ('$(GCCBIN) -dumpversion') do echo %%j) GCCVER3 := $(shell for /f "delims=. tokens=1,2,3" %%i in ('$(GCCBIN) -dumpversion') do echo %%k) +GCCVER_STRING := $(shell $(GCCBIN) --version) endif # Set the install location of the compiler headers/libraries. @@ -1484,7 +1485,7 @@ perllibst.h : $(HAVEMINIPERL) $(CONFIGPM) create_perllibst_h.pl perldll.def : $(HAVEMINIPERL) $(CONFIGPM) ..\embed.fnc ..\makedef.pl $(MINIPERL) -I..\lib -w ..\makedef.pl PLATFORM=win32 CONFIG_H=$(CONFIG_H) $(OPTIMIZE) $(DEFINES) \ - $(BUILDOPT) CCTYPE=$(CCTYPE) TARG_DIR=..\ > perldll.def + $(BUILDOPT) CCTYPE=$(CCTYPE) CRT=$(CRT) TARG_DIR=..\ > perldll.def $(PERLEXPLIB) : $(PERLIMPLIB)