Patch #774665: Make Python LC_NUMERIC agnostic. · pythoncapi/cpython@737ea82 · GitHub
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

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

0 commit comments

Comments
 (0)