diff --git a/embed.fnc b/embed.fnc index abb67c14cb06..51042b256a18 100644 --- a/embed.fnc +++ b/embed.fnc @@ -4399,14 +4399,6 @@ S |void |ints_to_tm |NN struct tm *my_tm \ |int yday \ |int isdst S |bool |is_locale_utf8 |NN const char *locale -S |char * |strftime8 |NN const char *fmt \ - |NN const struct tm *mytm \ - |const utf8ness_t fmt_utf8ness \ - |NN utf8ness_t *result_utf8ness \ - |const bool came_from_sv -Sf |char * |strftime_tm |NN const char *fmt \ - |NN const struct tm *mytm -# if defined(HAS_LOCALECONV) S |HV * |my_localeconv |const int item S |void |populate_hash_from_C_localeconv \ |NN HV *hv \ @@ -4414,7 +4406,13 @@ S |void |populate_hash_from_C_localeconv \ |const PERL_UINT_FAST8_T which_mask \ |NN const lconv_offset_t *strings[2] \ |NN const lconv_offset_t *integers[2] -# endif +S |char * |strftime8 |NN const char *fmt \ + |NN const struct tm *mytm \ + |const utf8ness_t fmt_utf8ness \ + |NN utf8ness_t *result_utf8ness \ + |const bool came_from_sv +Sf |char * |strftime_tm |NN const char *fmt \ + |NN const struct tm *mytm # if defined(USE_LOCALE) S |const char *|calculate_LC_ALL_string \ |NULLOK const char **category_locales_list \ diff --git a/embed.h b/embed.h index a963d296017d..054085663b79 100644 --- a/embed.h +++ b/embed.h @@ -1299,12 +1299,10 @@ # define get_locale_string_utf8ness_i(a,b,c,d) S_get_locale_string_utf8ness_i(aTHX_ a,b,c,d) # define ints_to_tm(a,b,c,d,e,f,g,h,i,j) S_ints_to_tm(aTHX_ a,b,c,d,e,f,g,h,i,j) # define is_locale_utf8(a) S_is_locale_utf8(aTHX_ a) +# define my_localeconv(a) S_my_localeconv(aTHX_ a) +# define populate_hash_from_C_localeconv(a,b,c,d,e) S_populate_hash_from_C_localeconv(aTHX_ a,b,c,d,e) # define strftime8(a,b,c,d,e) S_strftime8(aTHX_ a,b,c,d,e) # define strftime_tm(a,b) S_strftime_tm(aTHX_ a,b) -# if defined(HAS_LOCALECONV) -# define my_localeconv(a) S_my_localeconv(aTHX_ a) -# define populate_hash_from_C_localeconv(a,b,c,d,e) S_populate_hash_from_C_localeconv(aTHX_ a,b,c,d,e) -# endif # if defined(USE_LOCALE) # define calculate_LC_ALL_string(a,b,c,d) S_calculate_LC_ALL_string(aTHX_ a,b,c,d) # define get_category_index_helper(a,b,c) S_get_category_index_helper(aTHX_ a,b,c) diff --git a/locale.c b/locale.c index f21d3e294049..71c3f52f9d90 100644 --- a/locale.c +++ b/locale.c @@ -5297,24 +5297,47 @@ fields), but directly callable from XS code. =cut */ +#ifndef HAS_LOCALECONV + +/* Easier to just define this ourselves based on the C/POSIX standards in the + * unlikely event that localeconv() is not available for use */ + typedef struct { + char *decimal_point; + char *thousands_sep; + char *grouping; + + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +} lconv; + +#endif + HV * Perl_localeconv(pTHX) { - -#if ! defined(HAS_LOCALECONV) - - return newHV(); - -#else - return my_localeconv(0); - -#endif - } -#if defined(HAS_LOCALECONV) - HV * S_my_localeconv(pTHX_ const int item) { @@ -5364,23 +5387,22 @@ S_my_localeconv(pTHX_ const int item) * pointing each name to its value's offset within lconv, e.g., { "thousands_sep", STRUCT_OFFSET(struct lconv, thousands_sep) } */ -# define LCONV_ENTRY(name) \ - {STRINGIFY(name), STRUCT_OFFSET(struct lconv, name)} +#define LCONV_ENTRY(name) {STRINGIFY(name), STRUCT_OFFSET(struct lconv, name)} /* These synonyms are just for clarity, and to make it easier in case * something needs to change in the future */ -# define LCONV_NUMERIC_ENTRY(name) LCONV_ENTRY(name) -# define LCONV_MONETARY_ENTRY(name) LCONV_ENTRY(name) +#define LCONV_NUMERIC_ENTRY(name) LCONV_ENTRY(name) +#define LCONV_MONETARY_ENTRY(name) LCONV_ENTRY(name) /* There are just a few fields for NUMERIC strings */ const lconv_offset_t lconv_numeric_strings[] = { -# ifndef NO_LOCALECONV_GROUPING +#ifndef NO_LOCALECONV_GROUPING LCONV_NUMERIC_ENTRY(grouping), -# endif +# endif LCONV_NUMERIC_ENTRY(thousands_sep), -# define THOUSANDS_SEP_LITERAL "thousands_sep" +# define THOUSANDS_SEP_LITERAL "thousands_sep" LCONV_NUMERIC_ENTRY(decimal_point), -# define DECIMAL_POINT_LITERAL "decimal_point" +# define DECIMAL_POINT_LITERAL "decimal_point" {NULL, 0} }; @@ -5393,28 +5415,28 @@ S_my_localeconv(pTHX_ const int item) * By placing the decimal_point field last in the full structure, we can * use just the tail for this bit of it, saving space. This macro yields * the address of the sub structure. */ -# define DECIMAL_POINT_ADDRESS \ +#define DECIMAL_POINT_ADDRESS \ &lconv_numeric_strings[(C_ARRAY_LENGTH(lconv_numeric_strings) - 2)] /* And the MONETARY string fields */ const lconv_offset_t lconv_monetary_strings[] = { LCONV_MONETARY_ENTRY(int_curr_symbol), LCONV_MONETARY_ENTRY(mon_decimal_point), -# ifndef NO_LOCALECONV_MON_THOUSANDS_SEP +#ifndef NO_LOCALECONV_MON_THOUSANDS_SEP LCONV_MONETARY_ENTRY(mon_thousands_sep), -# endif -# ifndef NO_LOCALECONV_MON_GROUPING +#endif +#ifndef NO_LOCALECONV_MON_GROUPING LCONV_MONETARY_ENTRY(mon_grouping), -# endif +#endif LCONV_MONETARY_ENTRY(positive_sign), LCONV_MONETARY_ENTRY(negative_sign), LCONV_MONETARY_ENTRY(currency_symbol), -# define CURRENCY_SYMBOL_LITERAL "currency_symbol" +#define CURRENCY_SYMBOL_LITERAL "currency_symbol" {NULL, 0} }; /* Like above, this field being last can be used as a sub structure */ -# define CURRENCY_SYMBOL_ADDRESS \ +#define CURRENCY_SYMBOL_ADDRESS \ &lconv_monetary_strings[(C_ARRAY_LENGTH(lconv_monetary_strings) - 2)] /* Finally there are integer fields, all are for monetary purposes */ @@ -5426,21 +5448,21 @@ S_my_localeconv(pTHX_ const int item) LCONV_ENTRY(n_sep_by_space), LCONV_ENTRY(p_sign_posn), LCONV_ENTRY(n_sign_posn), -# ifdef HAS_LC_MONETARY_2008 +#ifdef HAS_LC_MONETARY_2008 LCONV_ENTRY(int_p_cs_precedes), LCONV_ENTRY(int_p_sep_by_space), LCONV_ENTRY(int_n_cs_precedes), LCONV_ENTRY(int_n_sep_by_space), LCONV_ENTRY(int_p_sign_posn), LCONV_ENTRY(int_n_sign_posn), -# endif -# define P_CS_PRECEDES_LITERAL "p_cs_precedes" +#endif +# define P_CS_PRECEDES_LITERAL "p_cs_precedes" LCONV_ENTRY(p_cs_precedes), {NULL, 0} }; /* Like above, this field being last can be used as a sub structure */ -# define P_CS_PRECEDES_ADDRESS \ +#define P_CS_PRECEDES_ADDRESS \ &lconv_integers[(C_ARRAY_LENGTH(lconv_integers) - 2)] /* The actual populating of the hash is done by two sub functions that get @@ -5464,7 +5486,7 @@ S_my_localeconv(pTHX_ const int item) * choose which (or both) to populate from */ PERL_UINT_FAST8_T index_bits = 0; -# if ! defined(USE_LOCALE_NUMERIC) && ! defined(USE_LOCALE_MONETARY) +#if ! defined(USE_LOCALE_NUMERIC) && ! defined(USE_LOCALE_MONETARY) /* If both NUMERIC and MONETARY must be the "C" locale, simply populate the * hash using the function that works on just that locale. */ @@ -5482,7 +5504,7 @@ S_my_localeconv(pTHX_ const int item) return hv; -# else +#else /* From here to the end of this function, at least one of NUMERIC or * MONETARY can be non-C @@ -5516,12 +5538,12 @@ S_my_localeconv(pTHX_ const int item) * parameter is ignored. */ PERL_UNUSED_ARG(item); -# else +# else /* This only gets compiled for the use-case of using localeconv() to * emulate an nl_langinfo() missing from the platform. */ -# ifdef USE_LOCALE_NUMERIC +# ifdef USE_LOCALE_NUMERIC /* We need this substructure to only return this field for the THOUSEP * item. The other items also need substructures, but they were handled @@ -5534,7 +5556,7 @@ S_my_localeconv(pTHX_ const int item) {NULL, 0} }; -# endif +# endif /* End of all the initialization of data structures. Now for actual code. * @@ -5556,7 +5578,7 @@ S_my_localeconv(pTHX_ const int item) "Unexpected item passed to my_localeconv: %d", item)); break; -# ifdef USE_LOCALE_NUMERIC +# ifdef USE_LOCALE_NUMERIC case RADIXCHAR: if (isNAME_C_OR_POSIX(PL_numeric_name)) { @@ -5580,8 +5602,8 @@ S_my_localeconv(pTHX_ const int item) locale = PL_numeric_name; break; -# endif -# ifdef USE_LOCALE_MONETARY +# endif +# ifdef USE_LOCALE_MONETARY case CRNCYSTR: /* This item needs the values for both the currency symbol, and another one used to construct the @@ -5600,7 +5622,7 @@ S_my_localeconv(pTHX_ const int item) locale = querylocale_c(LC_MONETARY); break; -# endif +# endif } /* End of switch() */ @@ -5612,7 +5634,7 @@ S_my_localeconv(pTHX_ const int item) } else /* End of for just one item to emulate nl_langinfo() */ -# endif +# endif { /* 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 @@ -5620,7 +5642,7 @@ S_my_localeconv(pTHX_ const int item) index_bits = OFFSET_TO_BIT(MONETARY_OFFSET); -# ifdef USE_LOCALE_MONETARY +# ifdef USE_LOCALE_MONETARY locales[MONETARY_OFFSET] = querylocale_c(LC_MONETARY); populate[MONETARY_OFFSET] = @@ -5628,13 +5650,13 @@ S_my_localeconv(pTHX_ const int item) ? S_populate_hash_from_C_localeconv : S_populate_hash_from_localeconv; -# else +# else locales[MONETARY_OFFSET] = "C"; populate[MONETARY_OFFSET] = S_populate_hash_from_C_localeconv; -# endif -# ifdef USE_LOCALE_NUMERIC +# endif +# ifdef USE_LOCALE_NUMERIC /* And if the locales for the two categories are the same, we can also * do the NUMERIC values in the same call */ @@ -5651,7 +5673,7 @@ S_my_localeconv(pTHX_ const int item) : S_populate_hash_from_localeconv; } -# else +# else /* When LC_NUMERIC is confined to "C", the two locales are the same iff LC_MONETARY in this case is also "C". We set up the function @@ -5666,7 +5688,7 @@ S_my_localeconv(pTHX_ const int item) populate[NUMERIC_OFFSET] = S_populate_hash_from_C_localeconv; } -# endif +# endif } /* End of call is for localeconv() */ @@ -5677,7 +5699,7 @@ S_my_localeconv(pTHX_ const int item) hv, locales[MONETARY_OFFSET], index_bits, strings, integers); -# ifndef HAS_SOME_LANGINFO /* Could be using this function to emulate +# ifndef HAS_SOME_LANGINFO /* Could be using this function to emulate nl_langinfo() */ /* We are done when called with an individual item. There are no integer @@ -5689,7 +5711,7 @@ S_my_localeconv(pTHX_ const int item) return hv; } -# endif +# endif /* The above call may have done all the hash fields, but not always, as * already explained. If we need a second call it is always for the @@ -5741,11 +5763,11 @@ S_my_localeconv(pTHX_ const int item) } } -# endif /* MULTIPLICITY */ +# endif /* MULTIPLICITY */ return hv; -# endif /* End of must have one or both USE_MONETARY, USE_NUMERIC */ +#endif /* End of must have one or both USE_MONETARY, USE_NUMERIC */ } @@ -5785,11 +5807,11 @@ S_populate_hash_from_C_localeconv(pTHX_ HV * hv, /* This category's string fields */ const lconv_offset_t * category_strings = strings[i]; -# ifndef HAS_SOME_LANGINFO /* This doesn't work properly if called on single - items, which could only happen when there isn't - nl_langinfo on the platform */ +#ifndef HAS_SOME_LANGINFO /* This doesn't work properly if called on single + items, which could only happen when there isn't + nl_langinfo on the platform */ assert(category_strings[1].name != NULL); -# endif +#endif /* All string fields are empty except for one NUMERIC one. That one * has been initialized to be the final one in the NUMERIC strings, so @@ -5829,7 +5851,7 @@ S_populate_hash_from_C_localeconv(pTHX_ HV * hv, } } -# if defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) +#if defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) STATIC void S_populate_hash_from_localeconv(pTHX_ HV * hv, @@ -5872,8 +5894,8 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, 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 */ @@ -5881,7 +5903,7 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, if (which_mask & OFFSET_TO_BIT(NUMERIC_OFFSET)) { 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 @@ -5892,17 +5914,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 */ @@ -5912,14 +5934,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 @@ -5958,7 +5980,7 @@ 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 */ /* Finally, do the actual localeconv */ const char *lcbuf_as_string = (const char *) localeconv(); @@ -6028,7 +6050,7 @@ 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(TS_W32_BROKEN_LOCALECONV) && defined(USE_THREAD_SAFE_LOCALE) /* Restore the global locale's prior state */ void_setlocale_c(LC_ALL, save_global); @@ -6043,18 +6065,18 @@ 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 & OFFSET_TO_BIT(NUMERIC_OFFSET)) { @@ -6067,12 +6089,11 @@ S_populate_hash_from_localeconv(pTHX_ HV * hv, restore_toggled_locale_c(LC_CTYPE, orig_CTYPE_locale); LC_CTYPE_UNLOCK; -# endif +# endif } -# endif /* defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) */ -#endif /* defined(HAS_LOCALECONV) */ +#endif /* defined(USE_LOCALE_NUMERIC) || defined(USE_LOCALE_MONETARY) */ #ifndef HAS_SOME_LANGINFO typedef int nl_item; /* Substitute 'int' for emulated nl_langinfo() */ diff --git a/proto.h b/proto.h index 37bdd18c6686..aeb40e6f66d6 100644 --- a/proto.h +++ b/proto.h @@ -7006,6 +7006,15 @@ S_is_locale_utf8(pTHX_ const char *locale); # define PERL_ARGS_ASSERT_IS_LOCALE_UTF8 \ assert(locale) +STATIC HV * +S_my_localeconv(pTHX_ const int item); +# define PERL_ARGS_ASSERT_MY_LOCALECONV + +STATIC void +S_populate_hash_from_C_localeconv(pTHX_ HV *hv, const char *locale, const PERL_UINT_FAST8_T which_mask, const lconv_offset_t *strings[2], const lconv_offset_t *integers[2]); +# define PERL_ARGS_ASSERT_POPULATE_HASH_FROM_C_LOCALECONV \ + assert(hv); assert(locale); assert(strings); assert(integers) + STATIC char * S_strftime8(pTHX_ const char *fmt, const struct tm *mytm, const utf8ness_t fmt_utf8ness, utf8ness_t *result_utf8ness, const bool came_from_sv); # define PERL_ARGS_ASSERT_STRFTIME8 \ @@ -7017,17 +7026,6 @@ S_strftime_tm(pTHX_ const char *fmt, const struct tm *mytm) # define PERL_ARGS_ASSERT_STRFTIME_TM \ assert(fmt); assert(mytm) -# if defined(HAS_LOCALECONV) -STATIC HV * -S_my_localeconv(pTHX_ const int item); -# define PERL_ARGS_ASSERT_MY_LOCALECONV - -STATIC void -S_populate_hash_from_C_localeconv(pTHX_ HV *hv, const char *locale, const PERL_UINT_FAST8_T which_mask, const lconv_offset_t *strings[2], const lconv_offset_t *integers[2]); -# define PERL_ARGS_ASSERT_POPULATE_HASH_FROM_C_LOCALECONV \ - assert(hv); assert(locale); assert(strings); assert(integers) - -# endif /* defined(HAS_LOCALECONV) */ # if defined(USE_LOCALE) STATIC const char * S_calculate_LC_ALL_string(pTHX_ const char **category_locales_list, const calc_LC_ALL_format format, const calc_LC_ALL_return returning, const line_t caller_line);