@@ -561,11 +561,23 @@ _locale__getdefaultlocale_impl(PyObject *module)
561561#endif
562562
563563#ifdef HAVE_LANGINFO_H
564- #define LANGINFO (X , Y ) {#X, X, Y}
564+ /* On glibc, LC_TIME text items also have a wide (_NL_W*) form, named
565+ _NL_W<narrow name>, that nl_langinfo() returns as wchar_t*. LANGINFO_NW
566+ marks the items that have no wide counterpart. */
567+ #ifdef __GLIBC__
568+ # define LANGINFO (X , Y ) {#X, X, Y, _NL_W ## X}
569+ # define LANGINFO_NW (X , Y ) {#X, X, Y, 0}
570+ #else
571+ # define LANGINFO (X , Y ) {#X, X, Y}
572+ # define LANGINFO_NW (X , Y ) {#X, X, Y}
573+ #endif
565574static struct langinfo_constant {
566575 const char * name ;
567576 int value ;
568577 int category ;
578+ #ifdef __GLIBC__
579+ nl_item wide ; /* wide _NL_W* counterpart, or 0 if none */
580+ #endif
569581} langinfo_constants [] =
570582{
571583 /* These constants should exist on any langinfo implementation */
@@ -613,16 +625,16 @@ static struct langinfo_constant{
613625
614626#ifdef RADIXCHAR
615627 /* The following are not available with glibc 2.0 */
616- LANGINFO (RADIXCHAR , LC_NUMERIC ),
617- LANGINFO (THOUSEP , LC_NUMERIC ),
628+ LANGINFO_NW (RADIXCHAR , LC_NUMERIC ),
629+ LANGINFO_NW (THOUSEP , LC_NUMERIC ),
618630 /* YESSTR and NOSTR are deprecated in glibc, since they are
619631 a special case of message translation, which should be rather
620632 done using gettext. So we don't expose it to Python in the
621633 first place.
622634 LANGINFO(YESSTR, LC_MESSAGES),
623635 LANGINFO(NOSTR, LC_MESSAGES),
624636 */
625- LANGINFO (CRNCYSTR , LC_MONETARY ),
637+ LANGINFO_NW (CRNCYSTR , LC_MONETARY ),
626638#endif
627639
628640 LANGINFO (D_T_FMT , LC_TIME ),
@@ -636,13 +648,13 @@ static struct langinfo_constant{
636648 a few of the others.
637649 Solution: ifdef-test them all. */
638650#ifdef CODESET
639- LANGINFO (CODESET , LC_CTYPE ),
651+ LANGINFO_NW (CODESET , LC_CTYPE ),
640652#endif
641653#ifdef T_FMT_AMPM
642654 LANGINFO (T_FMT_AMPM , LC_TIME ),
643655#endif
644656#ifdef ERA
645- LANGINFO (ERA , LC_TIME ),
657+ LANGINFO_NW (ERA , LC_TIME ),
646658#endif
647659#ifdef ERA_D_FMT
648660 LANGINFO (ERA_D_FMT , LC_TIME ),
@@ -657,10 +669,10 @@ static struct langinfo_constant{
657669 LANGINFO (ALT_DIGITS , LC_TIME ),
658670#endif
659671#ifdef YESEXPR
660- LANGINFO (YESEXPR , LC_MESSAGES ),
672+ LANGINFO_NW (YESEXPR , LC_MESSAGES ),
661673#endif
662674#ifdef NOEXPR
663- LANGINFO (NOEXPR , LC_MESSAGES ),
675+ LANGINFO_NW (NOEXPR , LC_MESSAGES ),
664676#endif
665677#ifdef _DATE_FMT
666678 /* This is not available in all glibc versions that have CODESET. */
@@ -709,15 +721,14 @@ restore_locale(char *oldloc)
709721}
710722
711723#ifdef __GLIBC__
712- #if defined(ALT_DIGITS ) || defined(ERA )
713724static PyObject *
714- decode_strings (const char * result , size_t max_count )
725+ decode_strings (const char * result )
715726{
716727 /* Convert a sequence of NUL-separated C strings to a Python string
717728 * containing semicolon separated items. */
718729 size_t i = 0 ;
719730 size_t count = 0 ;
720- for (; count < max_count && result [i ]; count ++ ) {
731+ for (; result [i ]; count ++ ) {
721732 i += strlen (result + i ) + 1 ;
722733 }
723734 char * buf = PyMem_Malloc (i );
@@ -737,7 +748,35 @@ decode_strings(const char *result, size_t max_count)
737748 return pyresult ;
738749}
739750#endif
740- #endif
751+
752+ #ifdef __GLIBC__
753+ static PyObject *
754+ decode_wide_strings (const wchar_t * result , size_t max_count )
755+ {
756+ /* Wide-character counterpart of decode_strings(): convert a sequence of
757+ * NUL-separated wchar_t strings to a str with semicolon-separated items. */
758+ size_t i = 0 ;
759+ size_t count = 0 ;
760+ for (; count < max_count && result [i ]; count ++ ) {
761+ i += wcslen (result + i ) + 1 ;
762+ }
763+ wchar_t * buf = PyMem_New (wchar_t , i );
764+ if (buf == NULL ) {
765+ PyErr_NoMemory ();
766+ return NULL ;
767+ }
768+ memcpy (buf , result , i * sizeof (wchar_t ));
769+ /* Replace all NULs with semicolons. */
770+ i = 0 ;
771+ while (-- count ) {
772+ i += wcslen (buf + i );
773+ buf [i ++ ] = L';' ;
774+ }
775+ PyObject * pyresult = PyUnicode_FromWideChar (buf , -1 );
776+ PyMem_Free (buf );
777+ return pyresult ;
778+ }
779+ #endif /* __GLIBC__ */
741780
742781/*[clinic input]
743782_locale.nl_langinfo
@@ -758,6 +797,22 @@ _locale_nl_langinfo_impl(PyObject *module, int item)
758797 crash PyUnicode_FromString. */
759798 for (i = 0 ; langinfo_constants [i ].name ; i ++ ) {
760799 if (langinfo_constants [i ].value == item ) {
800+ #ifdef __GLIBC__
801+ /* Prefer the wide variant: it is decoded independently of the
802+ LC_CTYPE encoding. */
803+ nl_item wide = langinfo_constants [i ].wide ;
804+ if (wide ) {
805+ const wchar_t * wresult = (const wchar_t * )nl_langinfo (wide );
806+ if (wresult == NULL ) {
807+ wresult = L"" ;
808+ }
809+ /* ALT_DIGITS is a sequence of NUL-separated strings. */
810+ if (item == ALT_DIGITS && * wresult ) {
811+ return decode_wide_strings (wresult , 100 );
812+ }
813+ return PyUnicode_FromWideChar (wresult , -1 );
814+ }
815+ #endif
761816 /* Check NULL as a workaround for GNU libc's returning NULL
762817 instead of an empty string for nl_langinfo(ERA). */
763818 const char * result = nl_langinfo (item );
@@ -766,13 +821,8 @@ _locale_nl_langinfo_impl(PyObject *module, int item)
766821 if (langinfo_constants [i ].category != LC_CTYPE
767822 && * result && (
768823#ifdef __GLIBC__
769- // gh-133740: Always change the locale for ALT_DIGITS and ERA
770- # ifdef ALT_DIGITS
771- item == ALT_DIGITS ||
772- # endif
773- # ifdef ERA
824+ // gh-133740: Always change the locale for ERA
774825 item == ERA ||
775- # endif
776826#endif
777827 !is_all_ascii (result ))
778828 && change_locale (langinfo_constants [i ].category , & oldloc ) < 0 )
@@ -784,18 +834,10 @@ _locale_nl_langinfo_impl(PyObject *module, int item)
784834 /* According to the POSIX specification the result must be
785835 * a sequence of semicolon-separated strings.
786836 * But in Glibc they are NUL-separated. */
787- #ifdef ALT_DIGITS
788- if (item == ALT_DIGITS && * result ) {
789- pyresult = decode_strings (result , 100 );
790- }
791- else
792- #endif
793- #ifdef ERA
794837 if (item == ERA && * result ) {
795- pyresult = decode_strings (result , SIZE_MAX );
838+ pyresult = decode_strings (result );
796839 }
797840 else
798- #endif
799841#endif
800842 {
801843 pyresult = PyUnicode_DecodeLocale (result , NULL );
0 commit comments