Skip to content

Commit 578ebc5

Browse files
authored
gh-108767: Replace ctype.h functions with pyctype.h functions (#108772)
Replace <ctype.h> locale dependent functions with Python "pyctype.h" locale independent functions: * Replace isalpha() with Py_ISALPHA(). * Replace isdigit() with Py_ISDIGIT(). * Replace isxdigit() with Py_ISXDIGIT(). * Replace tolower() with Py_TOLOWER(). Leave Modules/_sre/sre.c unchanged, it uses locale dependent functions on purpose. Include explicitly <ctype.h> in _decimal.c to get isascii().
1 parent 03c5a68 commit 578ebc5

File tree

6 files changed

+36
-36
lines changed

6 files changed

+36
-36
lines changed

Modules/_decimal/_decimal.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "complexobject.h"
3636
#include "mpdecimal.h"
3737

38+
#include <ctype.h> // isascii()
3839
#include <stdlib.h>
3940

4041
#include "docstrings.h"

Modules/_zoneinfo.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,7 +1701,7 @@ parse_tz_str(zoneinfo_state *state, PyObject *tz_str_obj, _tzrule *out)
17011701
static int
17021702
parse_uint(const char *const p, uint8_t *value)
17031703
{
1704-
if (!isdigit(*p)) {
1704+
if (!Py_ISDIGIT(*p)) {
17051705
return -1;
17061706
}
17071707

@@ -1732,7 +1732,7 @@ parse_abbr(const char *const p, PyObject **abbr)
17321732
// '+' ) character, or the minus-sign ( '-' ) character. The std
17331733
// and dst fields in this case shall not include the quoting
17341734
// characters.
1735-
if (!isalpha(buff) && !isdigit(buff) && buff != '+' &&
1735+
if (!Py_ISALPHA(buff) && !Py_ISDIGIT(buff) && buff != '+' &&
17361736
buff != '-') {
17371737
return -1;
17381738
}
@@ -1748,7 +1748,7 @@ parse_abbr(const char *const p, PyObject **abbr)
17481748
// In the unquoted form, all characters in these fields shall be
17491749
// alphabetic characters from the portable character set in the
17501750
// current locale.
1751-
while (isalpha(*ptr)) {
1751+
while (Py_ISALPHA(*ptr)) {
17521752
ptr++;
17531753
}
17541754
str_end = ptr;
@@ -1802,7 +1802,7 @@ parse_tz_delta(const char *const p, long *total_seconds)
18021802
// The hour can be 1 or 2 numeric characters
18031803
for (size_t i = 0; i < 2; ++i) {
18041804
buff = *ptr;
1805-
if (!isdigit(buff)) {
1805+
if (!Py_ISDIGIT(buff)) {
18061806
if (i == 0) {
18071807
return -1;
18081808
}
@@ -1830,7 +1830,7 @@ parse_tz_delta(const char *const p, long *total_seconds)
18301830

18311831
for (size_t j = 0; j < 2; ++j) {
18321832
buff = *ptr;
1833-
if (!isdigit(buff)) {
1833+
if (!Py_ISDIGIT(buff)) {
18341834
return -1;
18351835
}
18361836
*(outputs[i]) *= 10;
@@ -1932,7 +1932,7 @@ parse_transition_rule(const char *const p, TransitionRuleType **out)
19321932
}
19331933

19341934
for (size_t i = 0; i < 3; ++i) {
1935-
if (!isdigit(*ptr)) {
1935+
if (!Py_ISDIGIT(*ptr)) {
19361936
if (i == 0) {
19371937
return -1;
19381938
}
@@ -2007,7 +2007,7 @@ parse_transition_time(const char *const p, int8_t *hour, int8_t *minute,
20072007

20082008
uint8_t buff = 0;
20092009
for (size_t j = 0; j < 2; j++) {
2010-
if (!isdigit(*ptr)) {
2010+
if (!Py_ISDIGIT(*ptr)) {
20112011
if (i == 0 && j > 0) {
20122012
break;
20132013
}

Modules/getaddrinfo.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
#include <string.h>
5252
#include <stdlib.h>
5353
#include <stddef.h>
54-
#include <ctype.h>
5554
#include <unistd.h>
5655

5756
#include "addrinfo.h"
@@ -228,8 +227,9 @@ str_isnumber(const char *p)
228227
{
229228
unsigned char *q = (unsigned char *)p;
230229
while (*q) {
231-
if (! isdigit(*q))
230+
if (!Py_ISDIGIT(*q)) {
232231
return NO;
232+
}
233233
q++;
234234
}
235235
return YES;

Objects/bytesobject.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -722,11 +722,11 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
722722
if (--fmtcnt >= 0)
723723
c = *fmt++;
724724
}
725-
else if (c >= 0 && isdigit(c)) {
725+
else if (c >= 0 && Py_ISDIGIT(c)) {
726726
width = c - '0';
727727
while (--fmtcnt >= 0) {
728728
c = Py_CHARMASK(*fmt++);
729-
if (!isdigit(c))
729+
if (!Py_ISDIGIT(c))
730730
break;
731731
if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) {
732732
PyErr_SetString(
@@ -761,11 +761,11 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
761761
if (--fmtcnt >= 0)
762762
c = *fmt++;
763763
}
764-
else if (c >= 0 && isdigit(c)) {
764+
else if (c >= 0 && Py_ISDIGIT(c)) {
765765
prec = c - '0';
766766
while (--fmtcnt >= 0) {
767767
c = Py_CHARMASK(*fmt++);
768-
if (!isdigit(c))
768+
if (!Py_ISDIGIT(c))
769769
break;
770770
if (prec > (INT_MAX - ((int)c - '0')) / 10) {
771771
PyErr_SetString(

Parser/tokenizer.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include "Python.h"
55
#include "pycore_call.h" // _PyObject_CallNoArgs()
66

7-
#include <ctype.h>
87
#include <assert.h>
98

109
#include "tokenizer.h"
@@ -158,7 +157,7 @@ get_normal_name(const char *s) /* for utf-8 and latin-1 */
158157
else if (c == '_')
159158
buf[i] = '-';
160159
else
161-
buf[i] = tolower(c);
160+
buf[i] = Py_TOLOWER(c);
162161
}
163162
buf[i] = '\0';
164163
if (strcmp(buf, "utf-8") == 0 ||
@@ -1715,12 +1714,12 @@ tok_decimal_tail(struct tok_state *tok)
17151714
while (1) {
17161715
do {
17171716
c = tok_nextc(tok);
1718-
} while (isdigit(c));
1717+
} while (Py_ISDIGIT(c));
17191718
if (c != '_') {
17201719
break;
17211720
}
17221721
c = tok_nextc(tok);
1723-
if (!isdigit(c)) {
1722+
if (!Py_ISDIGIT(c)) {
17241723
tok_backup(tok, c);
17251724
syntaxerror(tok, "invalid decimal literal");
17261725
return 0;
@@ -2108,7 +2107,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
21082107
/* Period or number starting with period? */
21092108
if (c == '.') {
21102109
c = tok_nextc(tok);
2111-
if (isdigit(c)) {
2110+
if (Py_ISDIGIT(c)) {
21122111
goto fraction;
21132112
} else if (c == '.') {
21142113
c = tok_nextc(tok);
@@ -2131,7 +2130,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
21312130
}
21322131

21332132
/* Number */
2134-
if (isdigit(c)) {
2133+
if (Py_ISDIGIT(c)) {
21352134
if (c == '0') {
21362135
/* Hex, octal or binary -- maybe. */
21372136
c = tok_nextc(tok);
@@ -2142,13 +2141,13 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
21422141
if (c == '_') {
21432142
c = tok_nextc(tok);
21442143
}
2145-
if (!isxdigit(c)) {
2144+
if (!Py_ISXDIGIT(c)) {
21462145
tok_backup(tok, c);
21472146
return MAKE_TOKEN(syntaxerror(tok, "invalid hexadecimal literal"));
21482147
}
21492148
do {
21502149
c = tok_nextc(tok);
2151-
} while (isxdigit(c));
2150+
} while (Py_ISXDIGIT(c));
21522151
} while (c == '_');
21532152
if (!verify_end_of_number(tok, c, "hexadecimal")) {
21542153
return MAKE_TOKEN(ERRORTOKEN);
@@ -2162,7 +2161,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
21622161
c = tok_nextc(tok);
21632162
}
21642163
if (c < '0' || c >= '8') {
2165-
if (isdigit(c)) {
2164+
if (Py_ISDIGIT(c)) {
21662165
return MAKE_TOKEN(syntaxerror(tok,
21672166
"invalid digit '%c' in octal literal", c));
21682167
}
@@ -2175,7 +2174,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
21752174
c = tok_nextc(tok);
21762175
} while ('0' <= c && c < '8');
21772176
} while (c == '_');
2178-
if (isdigit(c)) {
2177+
if (Py_ISDIGIT(c)) {
21792178
return MAKE_TOKEN(syntaxerror(tok,
21802179
"invalid digit '%c' in octal literal", c));
21812180
}
@@ -2191,7 +2190,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
21912190
c = tok_nextc(tok);
21922191
}
21932192
if (c != '0' && c != '1') {
2194-
if (isdigit(c)) {
2193+
if (Py_ISDIGIT(c)) {
21952194
return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c));
21962195
}
21972196
else {
@@ -2203,7 +2202,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
22032202
c = tok_nextc(tok);
22042203
} while (c == '0' || c == '1');
22052204
} while (c == '_');
2206-
if (isdigit(c)) {
2205+
if (Py_ISDIGIT(c)) {
22072206
return MAKE_TOKEN(syntaxerror(tok, "invalid digit '%c' in binary literal", c));
22082207
}
22092208
if (!verify_end_of_number(tok, c, "binary")) {
@@ -2217,7 +2216,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
22172216
while (1) {
22182217
if (c == '_') {
22192218
c = tok_nextc(tok);
2220-
if (!isdigit(c)) {
2219+
if (!Py_ISDIGIT(c)) {
22212220
tok_backup(tok, c);
22222221
return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal"));
22232222
}
@@ -2228,7 +2227,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
22282227
c = tok_nextc(tok);
22292228
}
22302229
char* zeros_end = tok->cur;
2231-
if (isdigit(c)) {
2230+
if (Py_ISDIGIT(c)) {
22322231
nonzero = 1;
22332232
c = tok_decimal_tail(tok);
22342233
if (c == 0) {
@@ -2272,7 +2271,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
22722271
c = tok_nextc(tok);
22732272
fraction:
22742273
/* Fraction */
2275-
if (isdigit(c)) {
2274+
if (Py_ISDIGIT(c)) {
22762275
c = tok_decimal_tail(tok);
22772276
if (c == 0) {
22782277
return MAKE_TOKEN(ERRORTOKEN);
@@ -2287,11 +2286,11 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
22872286
c = tok_nextc(tok);
22882287
if (c == '+' || c == '-') {
22892288
c = tok_nextc(tok);
2290-
if (!isdigit(c)) {
2289+
if (!Py_ISDIGIT(c)) {
22912290
tok_backup(tok, c);
22922291
return MAKE_TOKEN(syntaxerror(tok, "invalid decimal literal"));
22932292
}
2294-
} else if (!isdigit(c)) {
2293+
} else if (!Py_ISDIGIT(c)) {
22952294
tok_backup(tok, c);
22962295
if (!verify_end_of_number(tok, e, "decimal")) {
22972296
return MAKE_TOKEN(ERRORTOKEN);
@@ -2326,7 +2325,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
23262325
}
23272326

23282327
f_string_quote:
2329-
if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r') && (c == '\'' || c == '"'))) {
2328+
if (((Py_TOLOWER(*tok->start) == 'f' || Py_TOLOWER(*tok->start) == 'r') && (c == '\'' || c == '"'))) {
23302329
int quote = c;
23312330
int quote_size = 1; /* 1 or 3 */
23322331

@@ -2377,7 +2376,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t
23772376
switch (*tok->start) {
23782377
case 'F':
23792378
case 'f':
2380-
the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r';
2379+
the_current_tok->f_string_raw = Py_TOLOWER(*(tok->start + 1)) == 'r';
23812380
break;
23822381
case 'R':
23832382
case 'r':

Python/pystrcmp.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ PyOS_mystrnicmp(const char *s1, const char *s2, Py_ssize_t size)
1111
return 0;
1212
p1 = (const unsigned char *)s1;
1313
p2 = (const unsigned char *)s2;
14-
for (; (--size > 0) && *p1 && *p2 && (tolower(*p1) == tolower(*p2));
14+
for (; (--size > 0) && *p1 && *p2 && (Py_TOLOWER(*p1) == Py_TOLOWER(*p2));
1515
p1++, p2++) {
1616
;
1717
}
18-
return tolower(*p1) - tolower(*p2);
18+
return Py_TOLOWER(*p1) - Py_TOLOWER(*p2);
1919
}
2020

2121
int
2222
PyOS_mystricmp(const char *s1, const char *s2)
2323
{
2424
const unsigned char *p1 = (const unsigned char *)s1;
2525
const unsigned char *p2 = (const unsigned char *)s2;
26-
for (; *p1 && *p2 && (tolower(*p1) == tolower(*p2)); p1++, p2++) {
26+
for (; *p1 && *p2 && (Py_TOLOWER(*p1) == Py_TOLOWER(*p2)); p1++, p2++) {
2727
;
2828
}
29-
return (tolower(*p1) - tolower(*p2));
29+
return (Py_TOLOWER(*p1) - Py_TOLOWER(*p2));
3030
}

0 commit comments

Comments
 (0)