@@ -11,6 +11,7 @@ This software comes with no warranty. Use at your own risk.
1111
1212#define PY_SSIZE_T_CLEAN
1313#include "Python.h"
14+ #include "pycore_fileutils.h"
1415
1516#include <stdio.h>
1617#include <locale.h>
@@ -128,14 +129,90 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
128129 return result_object ;
129130}
130131
132+ static int
133+ locale_is_ascii (const char * str )
134+ {
135+ return (strlen (str ) == 1 && ((unsigned char )str [0 ]) <= 127 );
136+ }
137+
138+ static int
139+ locale_decode_monetary (PyObject * dict , struct lconv * lc )
140+ {
141+ int change_locale ;
142+ change_locale = (!locale_is_ascii (lc -> int_curr_symbol )
143+ || !locale_is_ascii (lc -> currency_symbol )
144+ || !locale_is_ascii (lc -> mon_decimal_point )
145+ || !locale_is_ascii (lc -> mon_thousands_sep ));
146+
147+ /* Keep a copy of the LC_CTYPE locale */
148+ char * oldloc = NULL , * loc = NULL ;
149+ if (change_locale ) {
150+ oldloc = setlocale (LC_CTYPE , NULL );
151+ if (!oldloc ) {
152+ PyErr_SetString (PyExc_RuntimeWarning ,
153+ "failed to get LC_CTYPE locale" );
154+ return -1 ;
155+ }
156+
157+ oldloc = _PyMem_Strdup (oldloc );
158+ if (!oldloc ) {
159+ PyErr_NoMemory ();
160+ return -1 ;
161+ }
162+
163+ loc = setlocale (LC_MONETARY , NULL );
164+ if (loc != NULL && strcmp (loc , oldloc ) == 0 ) {
165+ loc = NULL ;
166+ }
167+
168+ if (loc != NULL ) {
169+ /* Only set the locale temporarily the LC_CTYPE locale
170+ to the LC_MONETARY locale if the two locales are different and
171+ at least one string is non-ASCII. */
172+ setlocale (LC_CTYPE , loc );
173+ }
174+ }
175+
176+ int res = -1 ;
177+
178+ #define RESULT_STRING (ATTR ) \
179+ do { \
180+ PyObject *obj; \
181+ obj = PyUnicode_DecodeLocale(lc->ATTR, NULL); \
182+ if (obj == NULL) { \
183+ goto done; \
184+ } \
185+ if (PyDict_SetItemString(dict, Py_STRINGIFY(ATTR), obj) < 0) { \
186+ Py_DECREF(obj); \
187+ goto done; \
188+ } \
189+ Py_DECREF(obj); \
190+ } while (0)
191+
192+ RESULT_STRING (int_curr_symbol );
193+ RESULT_STRING (currency_symbol );
194+ RESULT_STRING (mon_decimal_point );
195+ RESULT_STRING (mon_thousands_sep );
196+ #undef RESULT_STRING
197+
198+ res = 0 ;
199+
200+ done :
201+ if (loc != NULL ) {
202+ setlocale (LC_CTYPE , oldloc );
203+ }
204+ PyMem_Free (oldloc );
205+ return res ;
206+ }
207+
131208PyDoc_STRVAR (localeconv__doc__ ,
132209"() -> dict. Returns numeric and monetary locale-specific parameters." );
133210
134211static PyObject *
135212PyLocale_localeconv (PyObject * self , PyObject * Py_UNUSED (ignored ))
136213{
137214 PyObject * result ;
138- struct lconv * l ;
215+ struct lconv * lc ;
139216 PyObject * x ;
140217
141218 result = PyDict_New ();
@@ -144,7 +221,7 @@ PyLocale_localeconv(PyObject* self, PyObject *Py_UNUSED(ignored))
144221 }
145222
146223 /* if LC_NUMERIC is different in the C library, use saved value */
147- l = localeconv ();
224+ lc = localeconv ();
148225
149226 /* hopefully, the localeconv result survives the C library calls
150227 involved herein */
@@ -162,22 +239,21 @@ PyLocale_localeconv(PyObject* self, PyObject *Py_UNUSED(ignored))
162239
163240#define RESULT_STRING (s )\
164241 do { \
165- x = PyUnicode_DecodeLocale(l ->s, NULL); \
242+ x = PyUnicode_DecodeLocale(lc ->s, NULL); \
166243 RESULT(#s, x); \
167244 } while (0)
168245
169246#define RESULT_INT (i )\
170247 do { \
171- x = PyLong_FromLong(l ->i); \
248+ x = PyLong_FromLong(lc ->i); \
172249 RESULT(#i, x); \
173250 } while (0)
174251
175- /* Monetary information */
176- RESULT_STRING (int_curr_symbol );
177- RESULT_STRING (currency_symbol );
178- RESULT_STRING (mon_decimal_point );
179- RESULT_STRING (mon_thousands_sep );
180- x = copy_grouping (l -> mon_grouping );
252+ /* Monetary information: LC_MONETARY encoding */
253+ if (locale_decode_monetary (result , lc ) < 0 ) {
254+ goto failed ;
255+ }
256+ x = copy_grouping (lc -> mon_grouping );
181257 RESULT ("mon_grouping" , x );
182258
183259 RESULT_STRING (positive_sign );
@@ -191,12 +267,9 @@ PyLocale_localeconv(PyObject* self, PyObject *Py_UNUSED(ignored))
191267 RESULT_INT (p_sign_posn );
192268 RESULT_INT (n_sign_posn );
193269
194- /* Numeric information */
270+ /* Numeric information: LC_NUMERIC encoding */
195271 PyObject * decimal_point , * thousands_sep ;
196- const char * grouping ;
197- if (_Py_GetLocaleconvNumeric (& decimal_point ,
198- & thousands_sep ,
199- & grouping ) < 0 ) {
272+ if (_Py_GetLocaleconvNumeric (lc , & decimal_point , & thousands_sep ) < 0 ) {
200273 goto failed ;
201274 }
202275
@@ -213,14 +286,18 @@ PyLocale_localeconv(PyObject* self, PyObject *Py_UNUSED(ignored))
213286 }
214287 Py_DECREF (thousands_sep );
215288
216- x = copy_grouping (grouping );
289+ x = copy_grouping (lc -> grouping );
217290 RESULT ("grouping" , x );
218291
219292 return result ;
220293
221294 failed :
222295 Py_DECREF (result );
223296 return NULL ;
297+
298+ #undef RESULT
299+ #undef RESULT_STRING
300+ #undef RESULT_INT
224301}
225302
226303#if defined(HAVE_WCSCOLL )
0 commit comments