]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-108765: Python.h no longer includes <ctype.h> (#108831)
authorVictor Stinner <vstinner@python.org>
Sun, 3 Sep 2023 16:54:27 +0000 (18:54 +0200)
committerGitHub <noreply@github.com>
Sun, 3 Sep 2023 16:54:27 +0000 (18:54 +0200)
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 b5047fd01948ab108edcc1b3c2c901d915814cfd
  in 2004 for MacOSX and FreeBSD.
* Test removed by commit 52ddaefb6bab1a74ecffe8519c02735794ebfbe1
  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 fb1f68ed7cc1536482d1debd70a53c5442135fe2 (in 2001).

22 files changed:
Doc/whatsnew/3.13.rst
Include/Python.h
Include/pyport.h
Misc/NEWS.d/next/C API/2023-09-02-22-35-55.gh-issue-108765.4TOdBT.rst [new file with mode: 0644]
Modules/_localemodule.c
Modules/_sre/sre.c
Modules/_struct.c
Modules/_tkinter.c
Modules/_zoneinfo.c
Modules/pyexpat.c
Modules/timemodule.c
Objects/abstract.c
Objects/floatobject.c
Objects/longobject.c
Objects/typeobject.c
Python/bltinmodule.c
Python/ceval.c
Python/codecs.c
Python/dynload_win.c
Python/errors.c
Python/getargs.c
Python/mystrtoul.c

index 1c91a1dadb899f0e1452c3fa0a6c69b1c47b88fb..5d8ecbb193f157471ff1c50e9d9addd85c6dc62b 100644 (file)
@@ -942,6 +942,13 @@ Porting to Python 3.13
   and ``setitimer()`` functions.
   (Contributed by Victor Stinner in :gh:`108765`.)
 
+* ``Python.h`` no longer includes the ``<ctype.h>`` standard header file. If
+  needed, it should now be included explicitly. For example, it provides
+  ``isalpha()`` and ``tolower()`` functions which are locale dependent. Python
+  provides locale independent functions, like :c:func:`!Py_ISALPHA` and
+  :c:func:`!Py_TOLOWER`.
+  (Contributed by Victor Stinner in :gh:`108765`.)
+
 Deprecated
 ----------
 
index 4cc72bb23ce7a3d80e4e38d88a23626e5390d2c6..8b28200000ab560f5320106350413c259f14dfa8 100644 (file)
@@ -17,7 +17,6 @@
 
 // Include standard header files
 #include <assert.h>               // assert()
-#include <ctype.h>                // tolower()
 #include <inttypes.h>             // uintptr_t
 #include <limits.h>               // INT_MAX
 #include <math.h>                 // HUGE_VAL
index c4168d10f5815133e2df3e79e52671674c407d0a..4d9b9c026b31d46fb56944b03eeb1912e463b068 100644 (file)
@@ -392,44 +392,6 @@ extern "C" {
 #  define Py_NO_INLINE
 #endif
 
-/* On 4.4BSD-descendants, ctype functions serves the whole range of
- * wchar_t character set rather than single byte code points only.
- * This characteristic can break some operations of string object
- * including str.upper() and str.split() on UTF-8 locales.  This
- * workaround was provided by Tim Robbins of FreeBSD project.
- */
-
-#if defined(__APPLE__)
-#  define _PY_PORT_CTYPE_UTF8_ISSUE
-#endif
-
-#ifdef _PY_PORT_CTYPE_UTF8_ISSUE
-#ifndef __cplusplus
-   /* The workaround below is unsafe in C++ because
-    * the <locale> defines these symbols as real functions,
-    * with a slightly different signature.
-    * See issue #10910
-    */
-#include <ctype.h>
-#include <wctype.h>
-#undef isalnum
-#define isalnum(c) iswalnum(btowc(c))
-#undef isalpha
-#define isalpha(c) iswalpha(btowc(c))
-#undef islower
-#define islower(c) iswlower(btowc(c))
-#undef isspace
-#define isspace(c) iswspace(btowc(c))
-#undef isupper
-#define isupper(c) iswupper(btowc(c))
-#undef tolower
-#define tolower(c) towlower(btowc(c))
-#undef toupper
-#define toupper(c) towupper(btowc(c))
-#endif
-#endif
-
-
 /* Declarations for symbol visibility.
 
   PyAPI_FUNC(type): Declares a public Python API function and return type
diff --git a/Misc/NEWS.d/next/C API/2023-09-02-22-35-55.gh-issue-108765.4TOdBT.rst b/Misc/NEWS.d/next/C API/2023-09-02-22-35-55.gh-issue-108765.4TOdBT.rst
new file mode 100644 (file)
index 0000000..c13b6d9
--- /dev/null
@@ -0,0 +1,5 @@
+``Python.h`` no longer includes the ``<ctype.h>`` standard header file. If
+needed, it should now be included explicitly. For example, it provides
+``isalpha()`` and ``tolower()`` functions which are locale dependent. Python
+provides locale independent functions, like :c:func:`!Py_ISALPHA` and
+:c:func:`!Py_TOLOWER`. Patch by Victor Stinner.
index 1847a4811e8ee930edf4cfd4d152959b95ec4236..fe8e4c5e30035b369d195cd37356a95c52bc46b5 100644 (file)
@@ -10,35 +10,25 @@ This software comes with no warranty. Use at your own risk.
 ******************************************************************/
 
 #include "Python.h"
-#include "pycore_fileutils.h"
-#include "pycore_pymem.h"  // _PyMem_Strdup
-
-#include <stdio.h>
-#include <locale.h>
-#include <string.h>
-#include <ctype.h>
+#include "pycore_fileutils.h"     // _Py_GetLocaleconvNumeric()
+#include "pycore_pymem.h"         // _PyMem_Strdup()
 
+#include <locale.h>               // setlocale()
+#include <string.h>               // strlen()
 #ifdef HAVE_ERRNO_H
-#include <errno.h>
+#  include <errno.h>              // errno
 #endif
-
 #ifdef HAVE_LANGINFO_H
-#include <langinfo.h>
+#  include <langinfo.h>           // nl_langinfo()
 #endif
-
 #ifdef HAVE_LIBINTL_H
-#include <libintl.h>
-#endif
-
-#ifdef HAVE_WCHAR_H
-#include <wchar.h>
+#  include <libintl.h>
 #endif
-
-#if defined(MS_WINDOWS)
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-#include <windows.h>
+#ifdef MS_WINDOWS
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include <windows.h>
 #endif
 
 PyDoc_STRVAR(locale__doc__, "Support for POSIX locales.");
index 3872c3663c7294c51f2a3622ba105a442696d3d7..07da5da13f70d3981ce81c19772dd39a50e401d2 100644 (file)
@@ -43,12 +43,40 @@ static const char copyright[] =
 #include "pycore_long.h"          // _PyLong_GetZero()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
 
+#include "sre.h"                  // SRE_CODE
 
-#include "sre.h"
+#include <ctype.h>                // tolower(), toupper(), isalnum()
 
 #define SRE_CODE_BITS (8 * sizeof(SRE_CODE))
 
-#include <ctype.h>
+// On macOS, use the wide character ctype API using btowc()
+#if defined(__APPLE__)
+#  define USE_CTYPE_WINT_T
+#endif
+
+static int sre_isalnum(unsigned int ch) {
+#ifdef USE_CTYPE_WINT_T
+    return (unsigned int)iswalnum(btowc((int)ch));
+#else
+    return (unsigned int)isalnum((int)ch);
+#endif
+}
+
+static unsigned int sre_tolower(unsigned int ch) {
+#ifdef USE_CTYPE_WINT_T
+    return (unsigned int)towlower(btowc((int)ch));
+#else
+    return (unsigned int)tolower((int)ch);
+#endif
+}
+
+static unsigned int sre_toupper(unsigned int ch) {
+#ifdef USE_CTYPE_WINT_T
+    return (unsigned int)towupper(btowc((int)ch));
+#else
+    return (unsigned int)toupper((int)ch);
+#endif
+}
 
 /* Defining this one controls tracing:
  * 0 -- disabled
@@ -114,17 +142,17 @@ static unsigned int sre_lower_ascii(unsigned int ch)
 /* locale-specific character predicates */
 /* !(c & ~N) == (c < N+1) for any unsigned c, this avoids
  * warnings when c's type supports only numbers < N+1 */
-#define SRE_LOC_IS_ALNUM(ch) (!((ch) & ~255) ? isalnum((ch)) : 0)
+#define SRE_LOC_IS_ALNUM(ch) (!((ch) & ~255) ? sre_isalnum((ch)) : 0)
 #define SRE_LOC_IS_WORD(ch) (SRE_LOC_IS_ALNUM((ch)) || (ch) == '_')
 
 static unsigned int sre_lower_locale(unsigned int ch)
 {
-    return ((ch) < 256 ? (unsigned int)tolower((ch)) : ch);
+    return ((ch) < 256 ? (unsigned int)sre_tolower((ch)) : ch);
 }
 
 static unsigned int sre_upper_locale(unsigned int ch)
 {
-    return ((ch) < 256 ? (unsigned int)toupper((ch)) : ch);
+    return ((ch) < 256 ? (unsigned int)sre_toupper((ch)) : ch);
 }
 
 /* unicode-specific character predicates */
index be4c23af384bb980effd76ef5810078fb069390b..1f8f9c44dd69aa2a9ab3780dc8ceacb4134dcfb6 100644 (file)
@@ -12,7 +12,6 @@
 #include "pycore_long.h"          // _PyLong_AsByteArray()
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
 
-#include <ctype.h>
 #include <stddef.h>               // offsetof()
 
 /*[clinic input]
index 663b4117683629528030ba3c29cd9fbaa6c6e03e..f9a18644945c653479e24d54dab63fe45f321462 100644 (file)
@@ -26,15 +26,14 @@ Copyright (C) 1994 Steen Lumholt.
 #endif
 
 #include "Python.h"
-#include <ctype.h>
 #ifdef MS_WINDOWS
 #  include "pycore_fileutils.h"   // _Py_stat()
 #endif
 
-#include "pycore_long.h"
+#include "pycore_long.h"          // _PyLong_IsNegative()
 
 #ifdef MS_WINDOWS
-#include <windows.h>
+#  include <windows.h>
 #endif
 
 #define CHECK_SIZE(size, elemsize) \
@@ -46,11 +45,11 @@ Copyright (C) 1994 Steen Lumholt.
 #define TCL_THREADS
 
 #ifdef TK_FRAMEWORK
-#include <Tcl/tcl.h>
-#include <Tk/tk.h>
+#  include <Tcl/tcl.h>
+#  include <Tk/tk.h>
 #else
-#include <tcl.h>
-#include <tk.h>
+#  include <tcl.h>
+#  include <tk.h>
 #endif
 
 #include "tkinter.h"
index 3f7b2851c5b7942a6dab2704762d49cdff5d0d20..eb4e522465181fed78f5f60bd9f1f60cb7654b4a 100644 (file)
@@ -6,11 +6,10 @@
 #include "pycore_long.h"          // _PyLong_GetOne()
 #include "pycore_pyerrors.h"      // _PyErr_ChainExceptions1()
 
-#include <ctype.h>
-#include <stddef.h>
-#include <stdint.h>
+#include "datetime.h"             // PyDateTime_TZInfo
 
-#include "datetime.h"
+#include <stddef.h>               // offsetof()
+#include <stdint.h>
 
 #include "clinic/_zoneinfo.c.h"
 /*[clinic input]
index 52dd06cd3c818190772e1b622c796c85ec62dd8c..bd24523eac830b39716d9670472f660d616e8dbe 100644 (file)
@@ -7,7 +7,6 @@
 #include "pycore_pyhash.h"        // _Py_HashSecret
 #include "pycore_traceback.h"     // _PyTraceback_Add()
 
-#include <ctype.h>
 #include <stddef.h>               // offsetof()
 #include "expat.h"
 #include "pyexpat.h"
index 4e55da71b117caf04c39183bbb8ca045bc004604..a2b66520ee885d3b9a5f840cee6c2d2dae1f3b01 100644 (file)
@@ -6,22 +6,21 @@
 #include "pycore_namespace.h"     // _PyNamespace_New()
 #include "pycore_runtime.h"       // _Py_ID()
 
-#include <ctype.h>
 #include <time.h>                 // clock()
 #ifdef HAVE_SYS_TIMES_H
-#  include <sys/times.h>
+#  include <sys/times.h>          // times()
 #endif
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
 #if defined(HAVE_SYS_RESOURCE_H)
-#  include <sys/resource.h>
+#  include <sys/resource.h>       // getrusage(RUSAGE_SELF)
 #endif
 #ifdef QUICKWIN
 # include <io.h>
 #endif
 #if defined(HAVE_PTHREAD_H)
-#  include <pthread.h>
+#  include <pthread.h>            // pthread_getcpuclockid()
 #endif
 #if defined(_AIX)
 #   include <sys/thread.h>
index c113364a88a26a264da6995e4e691371246d7934..6713926b86d218eb76fd73d99719d5eda0488fd2 100644 (file)
@@ -9,9 +9,8 @@
 #include "pycore_pyerrors.h"      // _PyErr_Occurred()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
 #include "pycore_unionobject.h"   // _PyUnion_Check()
-#include <ctype.h>
-#include <stddef.h>               // offsetof()
 
+#include <stddef.h>               // offsetof()
 
 
 /* Shorthands to return certain errors */
index 1c5078bdda687194925272f179aa12d6158f1f89..776c7092edd057b6b5e6aeed60b3115b752aaedd 100644 (file)
@@ -16,8 +16,7 @@
 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
 #include "pycore_structseq.h"     // _PyStructSequence_FiniBuiltin()
 
-#include <ctype.h>
-#include <float.h>
+#include <float.h>                // DBL_MAX
 #include <stdlib.h>               // strtol()
 
 /*[clinic input]
index d20ef412367bb75b73b0fc2e250a4db389584c05..e73de742229005684ea26e75e1d02560c0aa9102 100644 (file)
 #include "pycore_runtime.h"       // _PY_NSMALLPOSINTS
 #include "pycore_structseq.h"     // _PyStructSequence_FiniBuiltin()
 
-#include <ctype.h>
-#include <float.h>
-#include <stddef.h>
-#include <stdlib.h>               // abs()
+#include <float.h>                // DBL_MANT_DIG
+#include <stddef.h>               // offsetof
 
 #include "clinic/longobject.c.h"
 /*[clinic input]
index 67e059c3f74b776836d542a385b86977f2f619a7..84c50507691cbe497e9a489a92a20a52b4c3184f 100644 (file)
@@ -19,8 +19,6 @@
 #include "pycore_weakref.h"       // _PyWeakref_GET_REF()
 #include "opcode.h"               // MAKE_CELL
 
-
-#include <ctype.h>
 #include <stddef.h>               // ptrdiff_t
 
 /*[clinic input]
index 971067e2d4fcc1aef57f75391ec4a8d327687a4d..8e234e085f16c91b636965dd7008ad2e54739113 100644 (file)
@@ -1,7 +1,6 @@
 /* Built-in functions */
 
 #include "Python.h"
-#include <ctype.h>
 #include "pycore_ast.h"           // _PyAST_Validate()
 #include "pycore_call.h"          // _PyObject_CallNoArgs()
 #include "pycore_ceval.h"         // _PyEval_Vector()
index a22852ec13ea99bdfb10c9efe11f59014fe1bbfc..6f90d8e6fd064b4550e152c72182340c425210ca 100644 (file)
@@ -35,9 +35,7 @@
 #include "pydtrace.h"
 #include "setobject.h"
 
-
-#include <ctype.h>
-#include <stdbool.h>
+#include <stdbool.h>              // bool
 
 #ifdef Py_DEBUG
    /* For debugging the interpreter: */
index 87ae896b8e771842d4da7c6ef9ebccf9137b3cf3..b79bf555f2f22aaa412086373bae5b0ccd18a9e5 100644 (file)
@@ -14,7 +14,6 @@ Copyright (c) Corporation for National Research Initiatives.
 #include "pycore_pyerrors.h"      // _PyErr_FormatNote()
 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
 #include "pycore_ucnhash.h"       // _PyUnicode_Name_CAPI
-#include <ctype.h>
 
 const char *Py_hexdigits = "0123456789abcdef";
 
index acab05e2c6def3a64eed0e677bc71b072d3af7aa..f69995b8f9e3a12fcddcff5d7b522efa2018a327 100644 (file)
@@ -5,13 +5,8 @@
 #include "pycore_fileutils.h"     // _Py_add_relfile()
 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
 
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#endif
-#include <ctype.h>
-
-#include "importdl.h"
-#include "patchlevel.h"
+#include "importdl.h"             // dl_funcptr
+#include "patchlevel.h"           // PY_MAJOR_VERSION
 #include <windows.h>
 
 #ifdef _DEBUG
index fb5b3ff2c7ba517aaaae98dc26b75a6d717da949..f670b78c1f14efdee292b1b281eac9b68bce8c22 100644 (file)
@@ -10,7 +10,6 @@
 #include "pycore_sysmodule.h"     // _PySys_Audit()
 #include "pycore_traceback.h"     // _PyTraceBack_FromFrame()
 
-#include <ctype.h>
 #ifdef MS_WINDOWS
 #  include <windows.h>
 #  include <winbase.h>
index fdc144488c9627cabfd4a26cb9dabb48f17e3467..cbfe561111176cc915a2c4053066d0021bdd4b71 100644 (file)
@@ -7,10 +7,6 @@
 #include "pycore_pylifecycle.h"   // _PyArg_Fini
 #include "pycore_tuple.h"         // _PyTuple_ITEMS()
 
-#include <ctype.h>
-#include <float.h>
-
-
 #ifdef __cplusplus
 extern "C" {
 #endif
index e6fe154eed611ac93bfb8a5c40667c82397b5c14..fcd3e27f17f4e926fb0b3df457ffab5dd16cc9e9 100644 (file)
@@ -1,16 +1,22 @@
+// strtol() and strtoul(), renamed to avoid conflicts.
+//
+// API:
+//
+// - PyOS_strtol(): convert string to C long integer.
+// - PyOS_strtoul(): convert string to C unsigned long integer.
+
 #include "Python.h"
 #include "pycore_long.h"          // _PyLong_DigitValue
 
 #if defined(__sgi) && !defined(_SGI_MP_SOURCE)
-#define _SGI_MP_SOURCE
+#  define _SGI_MP_SOURCE
 #endif
 
 /* strtol and strtoul, renamed to avoid conflicts */
 
 
-#include <ctype.h>
 #ifdef HAVE_ERRNO_H
-#include <errno.h>
+#  include <errno.h>              // errno
 #endif
 
 /* Static overflow check values for bases 2 through 36.
@@ -75,7 +81,7 @@ static const int digitlimit[] = {
     14,  14, 14, 14, 13, 13, 13, 13, 13, 13,  /* 20 - 29 */
     13,  12, 12, 12, 12, 12, 12};             /* 30 - 36 */
 #else
-#error "Need table for SIZEOF_LONG"
+#  error "Need table for SIZEOF_LONG"
 #endif
 
 /*