Skip to content

Commit 03c4080

Browse files
authored
gh-108765: Python.h no longer includes <ctype.h> (#108831)
Remove <ctype.h> in C files which don't use it; only sre.c and _decimal.c still use it. Remove _PY_PORT_CTYPE_UTF8_ISSUE code from pyport.h: * Code added by commit b5047fd in 2004 for MacOSX and FreeBSD. * Test removed by commit 52ddaef in 2007, since Python str type now uses locale independent functions like Py_ISALPHA() and Py_TOLOWER() and the Unicode database. Modules/_sre/sre.c replaces _PY_PORT_CTYPE_UTF8_ISSUE with new functions: sre_isalnum(), sre_tolower(), sre_toupper(). Remove unused includes: * _localemodule.c: remove <stdio.h>. * getargs.c: remove <float.h>. * dynload_win.c: remove <direct.h>, it no longer calls _getcwd() since commit fb1f68e (in 2001).
1 parent 1796c19 commit 03c4080

22 files changed

+86
-114
lines changed

Doc/whatsnew/3.13.rst

+7
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,13 @@ Porting to Python 3.13
942942
and ``setitimer()`` functions.
943943
(Contributed by Victor Stinner in :gh:`108765`.)
944944

945+
* ``Python.h`` no longer includes the ``<ctype.h>`` standard header file. If
946+
needed, it should now be included explicitly. For example, it provides
947+
``isalpha()`` and ``tolower()`` functions which are locale dependent. Python
948+
provides locale independent functions, like :c:func:`!Py_ISALPHA` and
949+
:c:func:`!Py_TOLOWER`.
950+
(Contributed by Victor Stinner in :gh:`108765`.)
951+
945952
Deprecated
946953
----------
947954

Include/Python.h

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
// Include standard header files
1919
#include <assert.h> // assert()
20-
#include <ctype.h> // tolower()
2120
#include <inttypes.h> // uintptr_t
2221
#include <limits.h> // INT_MAX
2322
#include <math.h> // HUGE_VAL

Include/pyport.h

-38
Original file line numberDiff line numberDiff line change
@@ -392,44 +392,6 @@ extern "C" {
392392
# define Py_NO_INLINE
393393
#endif
394394

395-
/* On 4.4BSD-descendants, ctype functions serves the whole range of
396-
* wchar_t character set rather than single byte code points only.
397-
* This characteristic can break some operations of string object
398-
* including str.upper() and str.split() on UTF-8 locales. This
399-
* workaround was provided by Tim Robbins of FreeBSD project.
400-
*/
401-
402-
#if defined(__APPLE__)
403-
# define _PY_PORT_CTYPE_UTF8_ISSUE
404-
#endif
405-
406-
#ifdef _PY_PORT_CTYPE_UTF8_ISSUE
407-
#ifndef __cplusplus
408-
/* The workaround below is unsafe in C++ because
409-
* the <locale> defines these symbols as real functions,
410-
* with a slightly different signature.
411-
* See issue #10910
412-
*/
413-
#include <ctype.h>
414-
#include <wctype.h>
415-
#undef isalnum
416-
#define isalnum(c) iswalnum(btowc(c))
417-
#undef isalpha
418-
#define isalpha(c) iswalpha(btowc(c))
419-
#undef islower
420-
#define islower(c) iswlower(btowc(c))
421-
#undef isspace
422-
#define isspace(c) iswspace(btowc(c))
423-
#undef isupper
424-
#define isupper(c) iswupper(btowc(c))
425-
#undef tolower
426-
#define tolower(c) towlower(btowc(c))
427-
#undef toupper
428-
#define toupper(c) towupper(btowc(c))
429-
#endif
430-
#endif
431-
432-
433395
/* Declarations for symbol visibility.
434396
435397
PyAPI_FUNC(type): Declares a public Python API function and return type
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
``Python.h`` no longer includes the ``<ctype.h>`` standard header file. If
2+
needed, it should now be included explicitly. For example, it provides
3+
``isalpha()`` and ``tolower()`` functions which are locale dependent. Python
4+
provides locale independent functions, like :c:func:`!Py_ISALPHA` and
5+
:c:func:`!Py_TOLOWER`. Patch by Victor Stinner.

Modules/_localemodule.c

+12-22
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,25 @@ This software comes with no warranty. Use at your own risk.
1010
******************************************************************/
1111

1212
#include "Python.h"
13-
#include "pycore_fileutils.h"
14-
#include "pycore_pymem.h" // _PyMem_Strdup
15-
16-
#include <stdio.h>
17-
#include <locale.h>
18-
#include <string.h>
19-
#include <ctype.h>
13+
#include "pycore_fileutils.h" // _Py_GetLocaleconvNumeric()
14+
#include "pycore_pymem.h" // _PyMem_Strdup()
2015

16+
#include <locale.h> // setlocale()
17+
#include <string.h> // strlen()
2118
#ifdef HAVE_ERRNO_H
22-
#include <errno.h>
19+
# include <errno.h> // errno
2320
#endif
24-
2521
#ifdef HAVE_LANGINFO_H
26-
#include <langinfo.h>
22+
# include <langinfo.h> // nl_langinfo()
2723
#endif
28-
2924
#ifdef HAVE_LIBINTL_H
30-
#include <libintl.h>
31-
#endif
32-
33-
#ifdef HAVE_WCHAR_H
34-
#include <wchar.h>
25+
# include <libintl.h>
3526
#endif
36-
37-
#if defined(MS_WINDOWS)
38-
#ifndef WIN32_LEAN_AND_MEAN
39-
#define WIN32_LEAN_AND_MEAN
40-
#endif
41-
#include <windows.h>
27+
#ifdef MS_WINDOWS
28+
# ifndef WIN32_LEAN_AND_MEAN
29+
# define WIN32_LEAN_AND_MEAN
30+
# endif
31+
# include <windows.h>
4232
#endif
4333

4434
PyDoc_STRVAR(locale__doc__, "Support for POSIX locales.");

Modules/_sre/sre.c

+33-5
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,40 @@ static const char copyright[] =
4343
#include "pycore_long.h" // _PyLong_GetZero()
4444
#include "pycore_moduleobject.h" // _PyModule_GetState()
4545

46+
#include "sre.h" // SRE_CODE
4647

47-
#include "sre.h"
48+
#include <ctype.h> // tolower(), toupper(), isalnum()
4849

4950
#define SRE_CODE_BITS (8 * sizeof(SRE_CODE))
5051

51-
#include <ctype.h>
52+
// On macOS, use the wide character ctype API using btowc()
53+
#if defined(__APPLE__)
54+
# define USE_CTYPE_WINT_T
55+
#endif
56+
57+
static int sre_isalnum(unsigned int ch) {
58+
#ifdef USE_CTYPE_WINT_T
59+
return (unsigned int)iswalnum(btowc((int)ch));
60+
#else
61+
return (unsigned int)isalnum((int)ch);
62+
#endif
63+
}
64+
65+
static unsigned int sre_tolower(unsigned int ch) {
66+
#ifdef USE_CTYPE_WINT_T
67+
return (unsigned int)towlower(btowc((int)ch));
68+
#else
69+
return (unsigned int)tolower((int)ch);
70+
#endif
71+
}
72+
73+
static unsigned int sre_toupper(unsigned int ch) {
74+
#ifdef USE_CTYPE_WINT_T
75+
return (unsigned int)towupper(btowc((int)ch));
76+
#else
77+
return (unsigned int)toupper((int)ch);
78+
#endif
79+
}
5280

5381
/* Defining this one controls tracing:
5482
* 0 -- disabled
@@ -114,17 +142,17 @@ static unsigned int sre_lower_ascii(unsigned int ch)
114142
/* locale-specific character predicates */
115143
/* !(c & ~N) == (c < N+1) for any unsigned c, this avoids
116144
* warnings when c's type supports only numbers < N+1 */
117-
#define SRE_LOC_IS_ALNUM(ch) (!((ch) & ~255) ? isalnum((ch)) : 0)
145+
#define SRE_LOC_IS_ALNUM(ch) (!((ch) & ~255) ? sre_isalnum((ch)) : 0)
118146
#define SRE_LOC_IS_WORD(ch) (SRE_LOC_IS_ALNUM((ch)) || (ch) == '_')
119147

120148
static unsigned int sre_lower_locale(unsigned int ch)
121149
{
122-
return ((ch) < 256 ? (unsigned int)tolower((ch)) : ch);
150+
return ((ch) < 256 ? (unsigned int)sre_tolower((ch)) : ch);
123151
}
124152

125153
static unsigned int sre_upper_locale(unsigned int ch)
126154
{
127-
return ((ch) < 256 ? (unsigned int)toupper((ch)) : ch);
155+
return ((ch) < 256 ? (unsigned int)sre_toupper((ch)) : ch);
128156
}
129157

130158
/* unicode-specific character predicates */

Modules/_struct.c

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "pycore_long.h" // _PyLong_AsByteArray()
1313
#include "pycore_moduleobject.h" // _PyModule_GetState()
1414

15-
#include <ctype.h>
1615
#include <stddef.h> // offsetof()
1716

1817
/*[clinic input]

Modules/_tkinter.c

+6-7
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,14 @@ Copyright (C) 1994 Steen Lumholt.
2626
#endif
2727

2828
#include "Python.h"
29-
#include <ctype.h>
3029
#ifdef MS_WINDOWS
3130
# include "pycore_fileutils.h" // _Py_stat()
3231
#endif
3332

34-
#include "pycore_long.h"
33+
#include "pycore_long.h" // _PyLong_IsNegative()
3534

3635
#ifdef MS_WINDOWS
37-
#include <windows.h>
36+
# include <windows.h>
3837
#endif
3938

4039
#define CHECK_SIZE(size, elemsize) \
@@ -46,11 +45,11 @@ Copyright (C) 1994 Steen Lumholt.
4645
#define TCL_THREADS
4746

4847
#ifdef TK_FRAMEWORK
49-
#include <Tcl/tcl.h>
50-
#include <Tk/tk.h>
48+
# include <Tcl/tcl.h>
49+
# include <Tk/tk.h>
5150
#else
52-
#include <tcl.h>
53-
#include <tk.h>
51+
# include <tcl.h>
52+
# include <tk.h>
5453
#endif
5554

5655
#include "tkinter.h"

Modules/_zoneinfo.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
#include "pycore_long.h" // _PyLong_GetOne()
77
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
88

9-
#include <ctype.h>
10-
#include <stddef.h>
11-
#include <stdint.h>
9+
#include "datetime.h" // PyDateTime_TZInfo
1210

13-
#include "datetime.h"
11+
#include <stddef.h> // offsetof()
12+
#include <stdint.h>
1413

1514
#include "clinic/_zoneinfo.c.h"
1615
/*[clinic input]

Modules/pyexpat.c

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include "pycore_pyhash.h" // _Py_HashSecret
88
#include "pycore_traceback.h" // _PyTraceback_Add()
99

10-
#include <ctype.h>
1110
#include <stddef.h> // offsetof()
1211
#include "expat.h"
1312
#include "pyexpat.h"

Modules/timemodule.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,21 @@
66
#include "pycore_namespace.h" // _PyNamespace_New()
77
#include "pycore_runtime.h" // _Py_ID()
88

9-
#include <ctype.h>
109
#include <time.h> // clock()
1110
#ifdef HAVE_SYS_TIMES_H
12-
# include <sys/times.h>
11+
# include <sys/times.h> // times()
1312
#endif
1413
#ifdef HAVE_SYS_TYPES_H
1514
# include <sys/types.h>
1615
#endif
1716
#if defined(HAVE_SYS_RESOURCE_H)
18-
# include <sys/resource.h>
17+
# include <sys/resource.h> // getrusage(RUSAGE_SELF)
1918
#endif
2019
#ifdef QUICKWIN
2120
# include <io.h>
2221
#endif
2322
#if defined(HAVE_PTHREAD_H)
24-
# include <pthread.h>
23+
# include <pthread.h> // pthread_getcpuclockid()
2524
#endif
2625
#if defined(_AIX)
2726
# include <sys/thread.h>

Objects/abstract.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@
99
#include "pycore_pyerrors.h" // _PyErr_Occurred()
1010
#include "pycore_pystate.h" // _PyThreadState_GET()
1111
#include "pycore_unionobject.h" // _PyUnion_Check()
12-
#include <ctype.h>
13-
#include <stddef.h> // offsetof()
1412

13+
#include <stddef.h> // offsetof()
1514

1615

1716
/* Shorthands to return certain errors */

Objects/floatobject.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1717
#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin()
1818

19-
#include <ctype.h>
20-
#include <float.h>
19+
#include <float.h> // DBL_MAX
2120
#include <stdlib.h> // strtol()
2221

2322
/*[clinic input]

Objects/longobject.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
#include "pycore_runtime.h" // _PY_NSMALLPOSINTS
1111
#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin()
1212

13-
#include <ctype.h>
14-
#include <float.h>
15-
#include <stddef.h>
16-
#include <stdlib.h> // abs()
13+
#include <float.h> // DBL_MANT_DIG
14+
#include <stddef.h> // offsetof
1715

1816
#include "clinic/longobject.c.h"
1917
/*[clinic input]

Objects/typeobject.c

-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
2020
#include "opcode.h" // MAKE_CELL
2121

22-
23-
#include <ctype.h>
2422
#include <stddef.h> // ptrdiff_t
2523

2624
/*[clinic input]

Python/bltinmodule.c

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/* Built-in functions */
22

33
#include "Python.h"
4-
#include <ctype.h>
54
#include "pycore_ast.h" // _PyAST_Validate()
65
#include "pycore_call.h" // _PyObject_CallNoArgs()
76
#include "pycore_ceval.h" // _PyEval_Vector()

Python/ceval.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@
3535
#include "pydtrace.h"
3636
#include "setobject.h"
3737

38-
39-
#include <ctype.h>
40-
#include <stdbool.h>
38+
#include <stdbool.h> // bool
4139

4240
#ifdef Py_DEBUG
4341
/* For debugging the interpreter: */

Python/codecs.c

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Copyright (c) Corporation for National Research Initiatives.
1414
#include "pycore_pyerrors.h" // _PyErr_FormatNote()
1515
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1616
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
17-
#include <ctype.h>
1817

1918
const char *Py_hexdigits = "0123456789abcdef";
2019

Python/dynload_win.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@
55
#include "pycore_fileutils.h" // _Py_add_relfile()
66
#include "pycore_pystate.h" // _PyInterpreterState_GET()
77

8-
#ifdef HAVE_DIRECT_H
9-
#include <direct.h>
10-
#endif
11-
#include <ctype.h>
12-
13-
#include "importdl.h"
14-
#include "patchlevel.h"
8+
#include "importdl.h" // dl_funcptr
9+
#include "patchlevel.h" // PY_MAJOR_VERSION
1510
#include <windows.h>
1611

1712
#ifdef _DEBUG

Python/errors.c

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "pycore_sysmodule.h" // _PySys_Audit()
1111
#include "pycore_traceback.h" // _PyTraceBack_FromFrame()
1212

13-
#include <ctype.h>
1413
#ifdef MS_WINDOWS
1514
# include <windows.h>
1615
# include <winbase.h>

Python/getargs.c

-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
#include "pycore_pylifecycle.h" // _PyArg_Fini
88
#include "pycore_tuple.h" // _PyTuple_ITEMS()
99

10-
#include <ctype.h>
11-
#include <float.h>
12-
13-
1410
#ifdef __cplusplus
1511
extern "C" {
1612
#endif

0 commit comments

Comments
 (0)