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
----------
// 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
# 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
--- /dev/null
+``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.
******************************************************************/
#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.");
#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
/* 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 */
#include "pycore_long.h" // _PyLong_AsByteArray()
#include "pycore_moduleobject.h" // _PyModule_GetState()
-#include <ctype.h>
#include <stddef.h> // offsetof()
/*[clinic input]
#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) \
#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"
#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]
#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"
#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>
#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 */
#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]
#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]
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
#include "opcode.h" // MAKE_CELL
-
-#include <ctype.h>
#include <stddef.h> // ptrdiff_t
/*[clinic input]
/* 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()
#include "pydtrace.h"
#include "setobject.h"
-
-#include <ctype.h>
-#include <stdbool.h>
+#include <stdbool.h> // bool
#ifdef Py_DEBUG
/* For debugging the interpreter: */
#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";
#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
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_traceback.h" // _PyTraceBack_FromFrame()
-#include <ctype.h>
#ifdef MS_WINDOWS
# include <windows.h>
# include <winbase.h>
#include "pycore_pylifecycle.h" // _PyArg_Fini
#include "pycore_tuple.h" // _PyTuple_ITEMS()
-#include <ctype.h>
-#include <float.h>
-
-
#ifdef __cplusplus
extern "C" {
#endif
+// 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.
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
/*