Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 737ea82

Browse files
committed
Patch #774665: Make Python LC_NUMERIC agnostic.
1 parent 6ccc9a9 commit 737ea82

14 files changed

Lines changed: 317 additions & 103 deletions

File tree

Doc/lib/liblocale.tex

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -456,25 +456,6 @@ \subsection{For extension writers and programs that embed Python
456456
only be used portably to restore it, that is not very useful (except
457457
perhaps to find out whether or not the locale is \samp{C}).
458458

459-
When Python is embedded in an application, if the application sets the
460-
locale to something specific before initializing Python, that is
461-
generally okay, and Python will use whatever locale is set,
462-
\emph{except} that the \constant{LC_NUMERIC} locale should always be
463-
\samp{C}.
464-
465-
The \function{setlocale()} function in the \module{locale} module
466-
gives the Python programmer the impression that you can manipulate the
467-
\constant{LC_NUMERIC} locale setting, but this not the case at the C
468-
level: C code will always find that the \constant{LC_NUMERIC} locale
469-
setting is \samp{C}. This is because too much would break when the
470-
decimal point character is set to something else than a period
471-
(e.g. the Python parser would break). Caveat: threads that run
472-
without holding Python's global interpreter lock may occasionally find
473-
that the numeric locale setting differs; this is because the only
474-
portable way to implement this feature is to set the numeric locale
475-
settings to what the user requests, extract the relevant
476-
characteristics, and then restore the \samp{C} numeric locale.
477-
478459
When Python code uses the \module{locale} module to change the locale,
479460
this also affects the embedding application. If the embedding
480461
application doesn't want this to happen, it should remove the

Include/Python.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@
119119
#include "compile.h"
120120
#include "eval.h"
121121

122+
#include "pystrtod.h"
123+
122124
/* _Py_Mangle is defined in compile.c */
123125
PyAPI_FUNC(int) _Py_Mangle(char *p, char *name, \
124126
char *buffer, size_t maxlen);

Include/pystrtod.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef Py_STRTOD_H
2+
#define Py_STRTOD_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
9+
double PyOS_ascii_strtod(const char *str, char **ptr);
10+
double PyOS_ascii_atof(const char *str);
11+
char * PyOS_ascii_formatd(char *buffer, int buf_len, const char *format, double d);
12+
13+
14+
#ifdef __cplusplus
15+
}
16+
#endif
17+
18+
#endif /* !Py_STRTOD_H */

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ PYTHON_OBJS= \
247247
Python/sysmodule.o \
248248
Python/traceback.o \
249249
Python/getopt.o \
250+
Python/pystrtod.o \
250251
Python/$(DYNLOADFILE) \
251252
$(MACHDEP_OBJS) \
252253
$(THREADOBJ)

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1?
1212
Core and builtins
1313
-----------------
1414

15+
- Python no longer relies on the LC_NUMERIC locale setting to be
16+
the "C" locale; as a result, it no longer tries to prevent changing
17+
the LC_NUMERIC category.
18+
1519
- Bug #952807: Unpickling pickled instances of subclasses of
1620
datetime.date, datetime.datetime and datetime.time could yield insane
1721
objects. Thanks to Jiwon Seo for a fix.

Modules/_localemodule.c

Lines changed: 7 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,6 @@ static PyObject *Error;
5151
PyDoc_STRVAR(setlocale__doc__,
5252
"(integer,string=None) -> string. Activates/queries locale processing.");
5353

54-
/* to record the LC_NUMERIC settings */
55-
static PyObject* grouping = NULL;
56-
static PyObject* thousands_sep = NULL;
57-
static PyObject* decimal_point = NULL;
58-
/* if non-null, indicates that LC_NUMERIC is different from "C" */
59-
static char* saved_numeric = NULL;
60-
6154
/* the grouping is terminated by either 0 or CHAR_MAX */
6255
static PyObject*
6356
copy_grouping(char* s)
@@ -167,7 +160,6 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
167160
int category;
168161
char *locale = NULL, *result;
169162
PyObject *result_object;
170-
struct lconv *lc;
171163

172164
if (!PyArg_ParseTuple(args, "i|z:setlocale", &category, &locale))
173165
return NULL;
@@ -183,48 +175,19 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
183175
result_object = PyString_FromString(result);
184176
if (!result_object)
185177
return NULL;
186-
/* record changes to LC_NUMERIC */
187-
if (category == LC_NUMERIC || category == LC_ALL) {
188-
if (strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0) {
189-
/* user just asked for default numeric locale */
190-
if (saved_numeric)
191-
free(saved_numeric);
192-
saved_numeric = NULL;
193-
} else {
194-
/* remember values */
195-
lc = localeconv();
196-
Py_XDECREF(grouping);
197-
grouping = copy_grouping(lc->grouping);
198-
Py_XDECREF(thousands_sep);
199-
thousands_sep = PyString_FromString(lc->thousands_sep);
200-
Py_XDECREF(decimal_point);
201-
decimal_point = PyString_FromString(lc->decimal_point);
202-
if (saved_numeric)
203-
free(saved_numeric);
204-
saved_numeric = strdup(locale);
205-
/* restore to "C" */
206-
setlocale(LC_NUMERIC, "C");
207-
}
208-
}
209178
/* record changes to LC_CTYPE */
210179
if (category == LC_CTYPE || category == LC_ALL)
211180
fixup_ulcase();
212181
/* things that got wrong up to here are ignored */
213182
PyErr_Clear();
214183
} else {
215184
/* get locale */
216-
/* restore LC_NUMERIC first, if appropriate */
217-
if (saved_numeric)
218-
setlocale(LC_NUMERIC, saved_numeric);
219185
result = setlocale(category, NULL);
220186
if (!result) {
221187
PyErr_SetString(Error, "locale query failed");
222188
return NULL;
223189
}
224190
result_object = PyString_FromString(result);
225-
/* restore back to "C" */
226-
if (saved_numeric)
227-
setlocale(LC_NUMERIC, "C");
228191
}
229192
return result_object;
230193
}
@@ -262,20 +225,13 @@ PyLocale_localeconv(PyObject* self)
262225
Py_XDECREF(x)
263226

264227
/* Numeric information */
265-
if (saved_numeric){
266-
/* cannot use localeconv results */
267-
PyDict_SetItemString(result, "decimal_point", decimal_point);
268-
PyDict_SetItemString(result, "grouping", grouping);
269-
PyDict_SetItemString(result, "thousands_sep", thousands_sep);
270-
} else {
271-
RESULT_STRING(decimal_point);
272-
RESULT_STRING(thousands_sep);
273-
x = copy_grouping(l->grouping);
274-
if (!x)
275-
goto failed;
276-
PyDict_SetItemString(result, "grouping", x);
277-
Py_XDECREF(x);
278-
}
228+
RESULT_STRING(decimal_point);
229+
RESULT_STRING(thousands_sep);
230+
x = copy_grouping(l->grouping);
231+
if (!x)
232+
goto failed;
233+
PyDict_SetItemString(result, "grouping", x);
234+
Py_XDECREF(x);
279235

280236
/* Monetary information */
281237
RESULT_STRING(int_curr_symbol);
@@ -579,18 +535,6 @@ PyLocale_nl_langinfo(PyObject* self, PyObject* args)
579535
/* Check whether this is a supported constant. GNU libc sometimes
580536
returns numeric values in the char* return value, which would
581537
crash PyString_FromString. */
582-
#ifdef RADIXCHAR
583-
if (saved_numeric) {
584-
if(item == RADIXCHAR) {
585-
Py_INCREF(decimal_point);
586-
return decimal_point;
587-
}
588-
if(item == THOUSEP) {
589-
Py_INCREF(thousands_sep);
590-
return thousands_sep;
591-
}
592-
}
593-
#endif
594538
for (i = 0; langinfo_constants[i].name; i++)
595539
if (langinfo_constants[i].value == item) {
596540
/* Check NULL as a workaround for GNU libc's returning NULL

Modules/cPickle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3319,7 +3319,7 @@ load_float(Unpicklerobject *self)
33193319
if (!( s=pystrndup(s,len))) return -1;
33203320

33213321
errno = 0;
3322-
d = strtod(s, &endptr);
3322+
d = PyOS_ascii_strtod(s, &endptr);
33233323

33243324
if (errno || (endptr[0] != '\n') || (endptr[1] != '\0')) {
33253325
PyErr_SetString(PyExc_ValueError,

Modules/stropmodule.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,6 @@ PyDoc_STRVAR(atof__doc__,
838838
static PyObject *
839839
strop_atof(PyObject *self, PyObject *args)
840840
{
841-
extern double strtod(const char *, char **);
842841
char *s, *end;
843842
double x;
844843
char buffer[256]; /* For errors */
@@ -854,7 +853,7 @@ strop_atof(PyObject *self, PyObject *args)
854853
}
855854
errno = 0;
856855
PyFPE_START_PROTECT("strop_atof", return 0)
857-
x = strtod(s, &end);
856+
x = PyOS_ascii_strtod(s, &end);
858857
PyFPE_END_PROTECT(x)
859858
while (*end && isspace(Py_CHARMASK(*end)))
860859
end++;

Objects/complexobject.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,19 @@ complex_dealloc(PyObject *op)
272272
static void
273273
complex_to_buf(char *buf, int bufsz, PyComplexObject *v, int precision)
274274
{
275-
if (v->cval.real == 0.)
276-
PyOS_snprintf(buf, bufsz, "%.*gj",
277-
precision, v->cval.imag);
278-
else
279-
PyOS_snprintf(buf, bufsz, "(%.*g%+.*gj)",
280-
precision, v->cval.real,
281-
precision, v->cval.imag);
275+
char format[32];
276+
if (v->cval.real == 0.) {
277+
PyOS_snprintf(format, 32, "%%.%ig", precision);
278+
PyOS_ascii_formatd(buf, bufsz, format, v->cval.imag);
279+
strncat(buf, "j", bufsz);
280+
} else {
281+
char re[64], im[64];
282+
283+
PyOS_snprintf(format, 32, "%%.%ig", precision);
284+
PyOS_ascii_formatd(re, 64, format, v->cval.real);
285+
PyOS_ascii_formatd(im, 64, format, v->cval.imag);
286+
PyOS_snprintf(buf, bufsz, "(%s+%sj)", re, im);
287+
}
282288
}
283289

284290
static int
@@ -662,7 +668,6 @@ static PyMemberDef complex_members[] = {
662668
static PyObject *
663669
complex_subtype_from_string(PyTypeObject *type, PyObject *v)
664670
{
665-
extern double strtod(const char *, char **);
666671
const char *s, *start;
667672
char *end;
668673
double x=0.0, y=0.0, z;
@@ -774,7 +779,7 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v)
774779
}
775780
errno = 0;
776781
PyFPE_START_PROTECT("strtod", return 0)
777-
z = strtod(s, &end) ;
782+
z = PyOS_ascii_strtod(s, &end) ;
778783
PyFPE_END_PROTECT(z)
779784
if (errno != 0) {
780785
PyOS_snprintf(buffer, sizeof(buffer),

Objects/floatobject.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ PyFloat_FromString(PyObject *v, char **pend)
132132
* key off errno.
133133
*/
134134
PyFPE_START_PROTECT("strtod", return NULL)
135-
x = strtod(s, (char **)&end);
135+
x = PyOS_ascii_strtod(s, (char **)&end);
136136
PyFPE_END_PROTECT(x)
137137
errno = 0;
138138
/* Believe it or not, Solaris 2.6 can move end *beyond* the null
@@ -164,7 +164,7 @@ PyFloat_FromString(PyObject *v, char **pend)
164164
/* See above -- may have been strtod being anal
165165
about denorms. */
166166
PyFPE_START_PROTECT("atof", return NULL)
167-
x = atof(s);
167+
x = PyOS_ascii_atof(s);
168168
PyFPE_END_PROTECT(x)
169169
errno = 0; /* whether atof ever set errno is undefined */
170170
}
@@ -223,14 +223,16 @@ static void
223223
format_float(char *buf, size_t buflen, PyFloatObject *v, int precision)
224224
{
225225
register char *cp;
226+
char format[32];
226227
/* Subroutine for float_repr and float_print.
227228
We want float numbers to be recognizable as such,
228229
i.e., they should contain a decimal point or an exponent.
229230
However, %g may print the number as an integer;
230231
in such cases, we append ".0" to the string. */
231232

232233
assert(PyFloat_Check(v));
233-
PyOS_snprintf(buf, buflen, "%.*g", precision, v->ob_fval);
234+
PyOS_snprintf(format, 32, "%%.%ig", precision);
235+
PyOS_ascii_formatd(buf, buflen, format, v->ob_fval);
234236
cp = buf;
235237
if (*cp == '-')
236238
cp++;

0 commit comments

Comments
 (0)