@@ -470,15 +470,37 @@ decode_ascii(const char *arg, wchar_t **wstr, size_t *wlen,
470470/* Fall back to mbstowcs()/wcstombs(). */
471471# define _Py_ICONV_FALLBACK (-9)
472472
473+ /* Return non-zero if wchar_t is not Unicode in the current locale, i.e. if
474+ the locale encoding is neither UTF-8 nor ASCII. The result is memoized:
475+ this is called before every conversion, and in the common case (a UTF-8
476+ locale) it is the only overhead. */
477+ int
478+ _Py_LocaleNeedsWcharConversion (void )
479+ {
480+ const char * codeset = nl_langinfo (CODESET );
481+ if (codeset == NULL ) {
482+ return 0 ;
483+ }
484+ struct _Py_wchar_conversion_state * state = & _PyRuntime .fileutils .wchar ;
485+ if (strcmp (codeset , state -> codeset ) == 0 ) {
486+ return state -> needed ;
487+ }
488+ int needed = (* codeset != '\0'
489+ && strcmp (codeset , "UTF-8" ) != 0
490+ && strcmp (codeset , "US-ASCII" ) != 0
491+ && strcmp (codeset , "646" ) != 0 );
492+ if (strlen (codeset ) < sizeof (state -> codeset )) {
493+ memcpy (state -> codeset , codeset , strlen (codeset ) + 1 );
494+ state -> needed = needed ;
495+ }
496+ return needed ;
497+ }
498+
473499static iconv_t
474500locale_iconv_open (int decode )
475501{
476502 const char * codeset = nl_langinfo (CODESET );
477- if (!codeset || !* codeset
478- || strcmp (codeset , "UTF-8" ) == 0
479- || strcmp (codeset , "US-ASCII" ) == 0
480- || strcmp (codeset , "646" ) == 0 )
481- {
503+ if (!_Py_LocaleNeedsWcharConversion ()) {
482504 /* mbstowcs() and wcstombs() are correct for these encodings */
483505 return (iconv_t )- 1 ;
484506 }
@@ -490,6 +512,10 @@ static int
490512decode_locale_iconv (const char * arg , wchar_t * * wstr , size_t * wlen ,
491513 const char * * reason , _Py_error_handler errors )
492514{
515+ if (!_Py_LocaleNeedsWcharConversion ()) {
516+ return _Py_ICONV_FALLBACK ;
517+ }
518+
493519 int surrogateescape ;
494520 if (get_surrogateescape (errors , & surrogateescape ) < 0 ) {
495521 return -3 ;
@@ -569,6 +595,10 @@ encode_locale_iconv(const wchar_t *text, char **str,
569595 size_t * error_pos , const char * * reason ,
570596 int raw_malloc , _Py_error_handler errors )
571597{
598+ if (!_Py_LocaleNeedsWcharConversion ()) {
599+ return _Py_ICONV_FALLBACK ;
600+ }
601+
572602 int surrogateescape ;
573603 if (get_surrogateescape (errors , & surrogateescape ) < 0 ) {
574604 return -3 ;
@@ -687,6 +717,10 @@ encode_locale_iconv(const wchar_t *text, char **str,
687717int
688718_Py_UnicodeToLocaleWchar_InPlace (wchar_t * str , Py_ssize_t size )
689719{
720+ if (!_Py_LocaleNeedsWcharConversion ()) {
721+ return 0 ;
722+ }
723+
690724 iconv_t cd = (iconv_t )- 1 ;
691725 int res = 0 ;
692726 for (Py_ssize_t i = 0 ; i < size ; i ++ ) {
@@ -763,6 +797,10 @@ _Py_UnicodeToLocaleWchar_InPlace(wchar_t *str, Py_ssize_t size)
763797void
764798_Py_LocaleWcharToUnicode_InPlace (wchar_t * str , Py_ssize_t size )
765799{
800+ if (!_Py_LocaleNeedsWcharConversion ()) {
801+ return ;
802+ }
803+
766804 iconv_t cd = (iconv_t )- 1 ;
767805 for (Py_ssize_t i = 0 ; i < size ; i ++ ) {
768806 wchar_t wc = str [i ];
0 commit comments