Skip to content

Commit

Permalink
locale.c: Return defaults for uncomputable langinfo items
Browse files Browse the repository at this point in the history
Return the values from the C locale for nl_langinfo() items that aren't
computable on this platform.  If the platform has nl_langinfo(), then
all of them are computable, but if not, some can't be computed, and
others can be, but only if there are alternative methods available on
the platform.

As part of this commit, S_my_nl_langinfo() and S_save_to_buffer() are no
longer used when USE_LOCALE is not defined, so don't compile them.
  • Loading branch information
khwilliamson committed May 5, 2021
1 parent d86f01f commit d430dfe
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 40 deletions.
2 changes: 0 additions & 2 deletions embed.fnc
Expand Up @@ -3219,7 +3219,6 @@ ST |const char*|category_name |const int category
ST |unsigned int|get_category_index|const int category|NULLOK const char * locale
S |const char*|switch_category_locale_to_template|const int switch_category|const int template_category|NULLOK const char * template_locale
S |void |restore_switched_locale|const int category|NULLOK const char * const original_locale
# endif
# ifdef HAS_NL_LANGINFO
ST |const char*|my_nl_langinfo|const nl_item item|bool toggle
# else
Expand All @@ -3229,7 +3228,6 @@ iTR |const char *|save_to_buffer|NULLOK const char * string \
|NULLOK const char **buf \
|NN Size_t *buf_size \
|const Size_t offset
# if defined(USE_LOCALE)
:# ifndef HAS_POSIX_2008_LOCALE
S |const char*|stdize_locale|const int category \
|NULLOK const char* input_locale \
Expand Down
6 changes: 5 additions & 1 deletion embed.h
Expand Up @@ -1504,7 +1504,9 @@
# endif
# if !(defined(HAS_NL_LANGINFO))
# if defined(PERL_IN_LOCALE_C)
# if defined(USE_LOCALE)
#define my_nl_langinfo S_my_nl_langinfo
# endif
# endif
# endif
# if !(defined(PERL_DEFAULT_DO_EXEC3_IMPLEMENTATION))
Expand Down Expand Up @@ -1612,7 +1614,9 @@
# endif
# if defined(HAS_NL_LANGINFO)
# if defined(PERL_IN_LOCALE_C)
# if defined(USE_LOCALE)
#define my_nl_langinfo S_my_nl_langinfo
# endif
# endif
# endif
# if defined(HAS_PIPE)
Expand Down Expand Up @@ -1705,7 +1709,6 @@
#define unshare_hek_or_pvn(a,b,c,d) S_unshare_hek_or_pvn(aTHX_ a,b,c,d)
# endif
# if defined(PERL_IN_LOCALE_C)
#define save_to_buffer S_save_to_buffer
# if defined(USE_LOCALE)
#define category_name S_category_name
#define get_category_index S_get_category_index
Expand All @@ -1714,6 +1717,7 @@
#define new_ctype(a) S_new_ctype(aTHX_ a)
#define new_numeric(a) S_new_numeric(aTHX_ a)
#define restore_switched_locale(a,b) S_restore_switched_locale(aTHX_ a,b)
#define save_to_buffer S_save_to_buffer
#define set_numeric_radix(a) S_set_numeric_radix(aTHX_ a)
#define setlocale_failure_panic_i(a,b,c,d,e) S_setlocale_failure_panic_i(aTHX_ a,b,c,d,e)
#define stdize_locale(a,b,c,d) S_stdize_locale(aTHX_ a,b,c,d)
Expand Down
178 changes: 148 additions & 30 deletions locale.c
Expand Up @@ -2604,6 +2604,8 @@ Perl_setlocale(const int category, const char * locale)

}

#ifdef USE_LOCALE

PERL_STATIC_INLINE const char *
S_save_to_buffer(const char * string, const char **buf, Size_t *buf_size,
const Size_t offset)
Expand Down Expand Up @@ -2634,6 +2636,8 @@ S_save_to_buffer(const char * string, const char **buf, Size_t *buf_size,
return *buf;
}

#endif

int
Perl_mbtowc_(pTHX_ const wchar_t * pwc, const char * s, const Size_t len)
{
Expand Down Expand Up @@ -2805,16 +2809,157 @@ Perl_langinfo(const nl_item item)
Perl_langinfo(const int item)
#endif
{
/* If we are not paying attention to the category that controls an item,
* instead return a default value. Also return the default value if there
* is no way for us to figure out the correct value. If we have some form
* of nl_langinfo(), we can always figure it out, but lacking that, there
* may be alternative methods that can be used to recover most of the
* possible items. Some of those methods need libc functions, which may or
* may not be available. If unavailable, we can't compute the correct
* value, so must here return the default.
*
* The weird preprocessor directives will be changed in a future commit */
switch (item) {
default:
break;

#ifdef USE_LOCALE_CTYPE
#else

case CODESET:
return C_codeset;

#endif
#if defined(USE_LOCALE_MESSAGES) && defined(HAS_SOME_LANGINFO)
#else

case YESEXPR: return "^[+1yY]";
case YESSTR: return "yes";
case NOEXPR: return "^[-0nN]";
case NOSTR: return "no";

#endif
#if defined(USE_LOCALE_MONETARY) \
&& (defined(HAS_SOME_LANGINFO) || defined(HAS_SOME_LOCALECONV))
#else

case CRNCYSTR:
return "-";

#endif
#if defined(USE_LOCALE_NUMERIC) \
&& (defined(HAS_SOME_LANGINFO) || defined(HAS_SOME_LOCALECONV))
#else

case RADIXCHAR:
return C_decimal_point;

case THOUSEP:
return C_thousands_sep;

#endif
#if ! defined(USE_LOCALE_TIME) || ! defined(HAS_SOME_LANGINFO)

/* If not using LC_TIME, hard code the rest. Or, if there is no
* nl_langinfo(), we use strftime() as an alternative, and it is missing
* functionality to get every single one, so hard-code those */

case ERA: return ""; /* Unimplemented; for use with strftime() %E
modifier */

/* These formats are defined by C89, so we assume that strftime supports
* them, and so are returned unconditionally; they may not be what the
* locale actually says, but should give good enough results for someone
* using them as formats (as opposed to trying to parse them to figure
* out what the locale says). The other format items are actually tested
* to verify they work on the platform */
case D_FMT: return "%x";
case T_FMT: return "%X";
case D_T_FMT: return "%c";

# if defined(WIN32) || ! defined(USE_LOCALE_TIME)

/* strftime() on Windows doesn't have the POSIX (beyond C89) extensions
* that would allow it to recover these */
case ERA_D_FMT: return "%x";
case ERA_T_FMT: return "%X";
case ERA_D_T_FMT: return "%c";
case ALT_DIGITS: return "0";

# endif
#endif
#ifdef USE_LOCALE_TIME
#else /* Below we have no LC_TIME */

case T_FMT_AMPM: return "%r";
case ABDAY_1: return "Sun";
case ABDAY_2: return "Mon";
case ABDAY_3: return "Tue";
case ABDAY_4: return "Wed";
case ABDAY_5: return "Thu";
case ABDAY_6: return "Fri";
case ABDAY_7: return "Sat";
case AM_STR: return "am";
case PM_STR: return "pm";
case ABMON_1: return "Jan";
case ABMON_2: return "Feb";
case ABMON_3: return "Mar";
case ABMON_4: return "Apr";
case ABMON_5: return "May";
case ABMON_6: return "Jun";
case ABMON_7: return "Jul";
case ABMON_8: return "Aug";
case ABMON_9: return "Sep";
case ABMON_10: return "Oct";
case ABMON_11: return "Nov";
case ABMON_12: return "Dec";
case DAY_1: return "Sunday";
case DAY_2: return "Monday";
case DAY_3: return "Tuesday";
case DAY_4: return "Wednesday";
case DAY_5: return "Thursday";
case DAY_6: return "Friday";
case DAY_7: return "Saturday";
case MON_1: return "January";
case MON_2: return "February";
case MON_3: return "March";
case MON_4: return "April";
case MON_5: return "May";
case MON_6: return "June";
case MON_7: return "July";
case MON_8: return "August";
case MON_9: return "September";
case MON_10: return "October";
case MON_11: return "November";
case MON_12: return "December";

#endif

} /* End of switch on item */

#ifndef USE_LOCALE

Perl_croak_nocontext("panic: Unexpected nl_langinfo() item %d", item);
NOT_REACHED; /* NOTREACHED */

#else

return my_nl_langinfo(item, TRUE);

#endif

}

#ifdef USE_LOCALE

STATIC const char *
# ifdef HAS_SOME_LANGINFO
S_my_nl_langinfo(const nl_item item, bool toggle)
# else
S_my_nl_langinfo(const int item, bool toggle)
# endif
{

dTHX;
const char * retval;

Expand Down Expand Up @@ -2891,16 +3036,6 @@ S_my_nl_langinfo(const int item, bool toggle)

# endif

/* We can return 'yes' and 'no' even if we didn't get a result */
if (strEQ(retval, "")) {
if (item == YESSTR) {
return "yes";
}
if (item == NOSTR) {
return "no";
}
}

return retval;
/*--------------------------------------------------------------------------*/
# else /* Below, emulate nl_langinfo as best we can */
Expand Down Expand Up @@ -2943,19 +3078,10 @@ S_my_nl_langinfo(const int item, bool toggle)
switch (item) {
Size_t len;

/* This is unimplemented */
case ERA: /* For use with strftime() %E modifier */

default:
return "";

/* We use only an English set, since we don't know any more */
case YESEXPR: return "^[+1yY]";
case YESSTR: return "yes";
case NOEXPR: return "^[-0nN]";
case NOSTR: return "no";

# ifdef HAS_LOCALECONV
# ifdef HAS_SOME_LOCALECONV

case CRNCYSTR:

Expand Down Expand Up @@ -3161,16 +3287,6 @@ S_my_nl_langinfo(const int item, bool toggle)
# endif
# ifdef HAS_STRFTIME

/* These are defined by C89, so we assume that strftime supports
* them, and so are returned unconditionally; they may not be what
* the locale actually says, but should give good enough results
* for someone using them as formats (as opposed to trying to parse
* them to figure out what the locale says). The other format
* items are actually tested to verify they work on the platform */
case D_FMT: return "%x";
case T_FMT: return "%X";
case D_T_FMT: return "%c";

/* These formats are only available in later strfmtime's */
case ERA_D_FMT: case ERA_T_FMT: case ERA_D_T_FMT: case T_FMT_AMPM:

Expand Down Expand Up @@ -3462,6 +3578,8 @@ S_my_nl_langinfo(const int item, bool toggle)
/*--------------------------------------------------------------------------*/
}

#endif /* USE_LOCALE */

/*
* Initialize locale awareness.
*/
Expand Down
18 changes: 11 additions & 7 deletions proto.h
Expand Up @@ -4219,8 +4219,10 @@ PERL_CALLCONV const char* Perl_langinfo(const int item);
#endif
#if !(defined(HAS_NL_LANGINFO))
# if defined(PERL_IN_LOCALE_C)
# if defined(USE_LOCALE)
STATIC const char* S_my_nl_langinfo(const int item, bool toggle);
#define PERL_ARGS_ASSERT_MY_NL_LANGINFO
# endif
# endif
#endif
#if !(defined(PERL_DEFAULT_DO_EXEC3_IMPLEMENTATION))
Expand Down Expand Up @@ -4696,8 +4698,10 @@ PERL_CALLCONV I32 Perl_do_shmio(pTHX_ I32 optype, SV** mark, SV** sp);
#endif
#if defined(HAS_NL_LANGINFO)
# if defined(PERL_IN_LOCALE_C)
# if defined(USE_LOCALE)
STATIC const char* S_my_nl_langinfo(const nl_item item, bool toggle);
#define PERL_ARGS_ASSERT_MY_NL_LANGINFO
# endif
# endif
#endif
#if defined(HAS_NL_LANGINFO) && defined(PERL_LANGINFO_H)
Expand Down Expand Up @@ -5122,13 +5126,6 @@ PERL_CALLCONV SV* Perl_hfree_next_entry(pTHX_ HV *hv, STRLEN *indexp);
assert(hv); assert(indexp)
#endif
#if defined(PERL_IN_LOCALE_C)
#ifndef PERL_NO_INLINE_FUNCTIONS
PERL_STATIC_INLINE const char * S_save_to_buffer(const char * string, const char **buf, Size_t *buf_size, const Size_t offset)
__attribute__warn_unused_result__;
#define PERL_ARGS_ASSERT_SAVE_TO_BUFFER \
assert(buf_size)
#endif

# if defined(USE_LOCALE)
STATIC const char* S_category_name(const int category);
#define PERL_ARGS_ASSERT_CATEGORY_NAME
Expand All @@ -5145,6 +5142,13 @@ STATIC void S_new_numeric(pTHX_ const char* newnum);
#define PERL_ARGS_ASSERT_NEW_NUMERIC
STATIC void S_restore_switched_locale(pTHX_ const int category, const char * const original_locale);
#define PERL_ARGS_ASSERT_RESTORE_SWITCHED_LOCALE
#ifndef PERL_NO_INLINE_FUNCTIONS
PERL_STATIC_INLINE const char * S_save_to_buffer(const char * string, const char **buf, Size_t *buf_size, const Size_t offset)
__attribute__warn_unused_result__;
#define PERL_ARGS_ASSERT_SAVE_TO_BUFFER \
assert(buf_size)
#endif

STATIC void S_set_numeric_radix(pTHX_ const bool use_locale);
#define PERL_ARGS_ASSERT_SET_NUMERIC_RADIX
PERL_STATIC_NO_RET void S_setlocale_failure_panic_i(pTHX_ const unsigned int cat_index, const char * current, const char * failed, const line_t caller_0_line, const line_t caller_1_line)
Expand Down

0 comments on commit d430dfe

Please sign in to comment.