bpo-42236: Enhance _locale._get_locale_encoding() (GH-23083) · python/cpython@82458b6

GitHub

@@ -821,43 +821,87 @@ _Py_EncodeLocaleEx(const wchar_t *text, char **str,

821821}

822822823823824-// Get the current locale encoding: locale.getpreferredencoding(False).

824+// Get the current locale encoding name:

825+//

826+// - Return "UTF-8" if _Py_FORCE_UTF8_LOCALE macro is defined (ex: on Android)

827+// - Return "UTF-8" if the UTF-8 Mode is enabled

828+// - On Windows, return the ANSI code page (ex: "cp1250")

829+// - Return "UTF-8" if nl_langinfo(CODESET) returns an empty string

830+// and if the _Py_FORCE_UTF8_FS_ENCODING macro is defined (ex: on macOS).

831+// - Otherwise, return nl_langinfo(CODESET).

832+//

833+// Return NULL and set errmsg to an error message

834+// if nl_langinfo(CODESET) fails.

835+//

836+// Return NULL and set errmsg to NULL on memory allocation failure.

837+//

825838// See also config_get_locale_encoding()

826-PyObject*

827-_Py_GetLocaleEncoding(void)

839+wchar_t*

840+_Py_GetLocaleEncoding(constchar**errmsg)

828841{

842+*errmsg=NULL;

829843#ifdef_Py_FORCE_UTF8_LOCALE

830844// On Android langinfo.h and CODESET are missing,

831845// and UTF-8 is always used in mbstowcs() and wcstombs().

832-returnPyUnicode_FromString("UTF-8");

846+return_PyMem_RawWcsdup(L"UTF-8");

833847#else

834848constPyPreConfig*preconfig=&_PyRuntime.preconfig;

835849if (preconfig->utf8_mode) {

836-returnPyUnicode_FromString("UTF-8");

850+return_PyMem_RawWcsdup(L"UTF-8");

837851 }

838852839-#if defined(MS_WINDOWS)

840-returnPyUnicode_FromFormat("cp%u", GetACP());

853+#ifdefMS_WINDOWS

854+wchar_tencoding[23];

855+unsigned intansi_codepage=GetACP();

856+swprintf(encoding, Py_ARRAY_LENGTH(encoding), L"cp%u", ansi_codepage);

857+encoding[Py_ARRAY_LENGTH(encoding) -1] =0;

858+return_PyMem_RawWcsdup(encoding);

841859#else

842860constchar*encoding=nl_langinfo(CODESET);

843861if (!encoding||encoding[0] =='\0') {

844862#ifdef_Py_FORCE_UTF8_FS_ENCODING

845863// nl_langinfo() can return an empty string when the LC_CTYPE locale is

846864// not supported. Default to UTF-8 in that case, because UTF-8 is the

847865// default charset on macOS.

848-encoding="UTF-8";

866+return_PyMem_RawWcsdup(L"UTF-8");

849867#else

850-PyErr_SetString(PyExc_ValueError,

851-"failed to get the locale encoding: "

852-"nl_langinfo(CODESET) returns an empty string");

868+*errmsg="failed to get the locale encoding: "

869+"nl_langinfo(CODESET) returns an empty string";

853870returnNULL;

854871#endif

855872 }

856-// Decode from UTF-8

857-returnPyUnicode_FromString(encoding);

858-#endif// !CODESET

859873860-#endif

874+wchar_t*wstr;

875+intres=decode_current_locale(encoding, &wstr, NULL,

876+errmsg, _Py_ERROR_SURROGATEESCAPE);

877+if (res<0) {

878+returnNULL;

879+ }

880+returnwstr;

881+#endif// !MS_WINDOWS

882+883+#endif// !_Py_FORCE_UTF8_LOCALE

884+}

885+886+887+PyObject*

888+_Py_GetLocaleEncodingObject(void)

889+{

890+constchar*errmsg;

891+wchar_t*encoding=_Py_GetLocaleEncoding(&errmsg);

892+if (encoding==NULL) {

893+if (errmsg!=NULL) {

894+PyErr_SetString(PyExc_ValueError, errmsg);

895+ }

896+else {

897+PyErr_NoMemory();

898+ }

899+returnNULL;

900+ }

901+902+PyObject*str=PyUnicode_FromWideChar(encoding, -1);

903+PyMem_RawFree(encoding);

904+returnstr;

861905}

862906863907