authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-09 22:38:06+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-09 22:38:06+01:00
log5e242f05510330896db202974570324cf2606c22
tree69cdebbc960eda35d98d502927f1cc772a8d05f5
parent721bdb6256302540bf019370ff3085596fe866e3
parent6abb1dcd35dc87f79403b5edb4c9f4e203ae6a92

Merge pull request 'libc: use common `ctype.h` implementation' (#30763) from GasInfinity/zig:libc-ascii-ctype into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30763 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

21 files changed, 214 insertions(+), 237 deletions(-)

lib/c.zig+1
...@@ -15,6 +15,7 @@ else...@@ -15,6 +15,7 @@ else
1515
16comptime {16comptime {
17 _ = @import("c/inttypes.zig");17 _ = @import("c/inttypes.zig");
18 _ = @import("c/ctype.zig");
18 _ = @import("c/stdlib.zig");19 _ = @import("c/stdlib.zig");
19 _ = @import("c/math.zig");20 _ = @import("c/math.zig");
2021
lib/c/ctype.zig created+192
...@@ -0,0 +1,192 @@
1const std = @import("std");
2const common = @import("common.zig");
3const builtin = @import("builtin");
4
5comptime {
6 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
7 // Functions specific to musl and wasi-libc.
8 @export(&isalnum, .{ .name = "isalnum", .linkage = common.linkage, .visibility = common.visibility });
9 @export(&isalpha, .{ .name = "isalpha", .linkage = common.linkage, .visibility = common.visibility });
10 @export(&isblank, .{ .name = "isblank", .linkage = common.linkage, .visibility = common.visibility });
11 @export(&iscntrl, .{ .name = "iscntrl", .linkage = common.linkage, .visibility = common.visibility });
12 @export(&isdigit, .{ .name = "isdigit", .linkage = common.linkage, .visibility = common.visibility });
13 @export(&isgraph, .{ .name = "isgraph", .linkage = common.linkage, .visibility = common.visibility });
14 @export(&islower, .{ .name = "islower", .linkage = common.linkage, .visibility = common.visibility });
15 @export(&isprint, .{ .name = "isprint", .linkage = common.linkage, .visibility = common.visibility });
16 @export(&ispunct, .{ .name = "ispunct", .linkage = common.linkage, .visibility = common.visibility });
17 @export(&isspace, .{ .name = "isspace", .linkage = common.linkage, .visibility = common.visibility });
18 @export(&isupper, .{ .name = "isupper", .linkage = common.linkage, .visibility = common.visibility });
19 @export(&isxdigit, .{ .name = "isxdigit", .linkage = common.linkage, .visibility = common.visibility });
20 @export(&tolower, .{ .name = "tolower", .linkage = common.linkage, .visibility = common.visibility });
21 @export(&toupper, .{ .name = "toupper", .linkage = common.linkage, .visibility = common.visibility });
22
23 @export(&__isalnum_l, .{ .name = "__isalnum_l", .linkage = common.linkage, .visibility = common.visibility });
24 @export(&__isalpha_l, .{ .name = "__isalpha_l", .linkage = common.linkage, .visibility = common.visibility });
25 @export(&__isblank_l, .{ .name = "__isblank_l", .linkage = common.linkage, .visibility = common.visibility });
26 @export(&__iscntrl_l, .{ .name = "__iscntrl_l", .linkage = common.linkage, .visibility = common.visibility });
27 @export(&__isdigit_l, .{ .name = "__isdigit_l", .linkage = common.linkage, .visibility = common.visibility });
28 @export(&__isgraph_l, .{ .name = "__isgraph_l", .linkage = common.linkage, .visibility = common.visibility });
29 @export(&__islower_l, .{ .name = "__islower_l", .linkage = common.linkage, .visibility = common.visibility });
30 @export(&__isprint_l, .{ .name = "__isprint_l", .linkage = common.linkage, .visibility = common.visibility });
31 @export(&__ispunct_l, .{ .name = "__ispunct_l", .linkage = common.linkage, .visibility = common.visibility });
32 @export(&__isspace_l, .{ .name = "__isspace_l", .linkage = common.linkage, .visibility = common.visibility });
33 @export(&__isupper_l, .{ .name = "__isupper_l", .linkage = common.linkage, .visibility = common.visibility });
34 @export(&__isxdigit_l, .{ .name = "__isxdigit_l", .linkage = common.linkage, .visibility = common.visibility });
35 @export(&__tolower_l, .{ .name = "__tolower_l", .linkage = common.linkage, .visibility = common.visibility });
36 @export(&__toupper_l, .{ .name = "__toupper_l", .linkage = common.linkage, .visibility = common.visibility });
37
38 @export(&__isalnum_l, .{ .name = "isalnum_l", .linkage = common.linkage, .visibility = common.visibility });
39 @export(&__isalpha_l, .{ .name = "isalpha_l", .linkage = common.linkage, .visibility = common.visibility });
40 @export(&__isblank_l, .{ .name = "isblank_l", .linkage = common.linkage, .visibility = common.visibility });
41 @export(&__iscntrl_l, .{ .name = "iscntrl_l", .linkage = common.linkage, .visibility = common.visibility });
42 @export(&__isdigit_l, .{ .name = "isdigit_l", .linkage = common.linkage, .visibility = common.visibility });
43 @export(&__isgraph_l, .{ .name = "isgraph_l", .linkage = common.linkage, .visibility = common.visibility });
44 @export(&__islower_l, .{ .name = "islower_l", .linkage = common.linkage, .visibility = common.visibility });
45 @export(&__isprint_l, .{ .name = "isprint_l", .linkage = common.linkage, .visibility = common.visibility });
46 @export(&__ispunct_l, .{ .name = "ispunct_l", .linkage = common.linkage, .visibility = common.visibility });
47 @export(&__isspace_l, .{ .name = "isspace_l", .linkage = common.linkage, .visibility = common.visibility });
48 @export(&__isupper_l, .{ .name = "isupper_l", .linkage = common.linkage, .visibility = common.visibility });
49 @export(&__isxdigit_l, .{ .name = "isxdigit_l", .linkage = common.linkage, .visibility = common.visibility });
50 @export(&__tolower_l, .{ .name = "tolower_l", .linkage = common.linkage, .visibility = common.visibility });
51 @export(&__toupper_l, .{ .name = "toupper_l", .linkage = common.linkage, .visibility = common.visibility });
52
53 @export(&isascii, .{ .name = "isascii", .linkage = common.linkage, .visibility = common.visibility });
54 @export(&toascii, .{ .name = "toascii", .linkage = common.linkage, .visibility = common.visibility });
55 }
56}
57
58// NOTE: If the input is not representable as an unsigned char or is not EOF the behaviour is undefined.
59
60fn isalnum(c: c_int) callconv(.c) c_int {
61 return @intFromBool(std.ascii.isAlphanumeric(@intCast(c)));
62}
63
64fn __isalnum_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
65 _ = locale;
66 return isalnum(c);
67}
68
69fn isalpha(c: c_int) callconv(.c) c_int {
70 return @intFromBool(std.ascii.isAlphabetic(@intCast(c)));
71}
72
73fn __isalpha_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
74 _ = locale;
75 return isalpha(c);
76}
77
78fn isblank(c: c_int) callconv(.c) c_int {
79 return @intFromBool(c == ' ' or c == '\t');
80}
81
82fn __isblank_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
83 _ = locale;
84 return isblank(c);
85}
86
87fn iscntrl(c: c_int) callconv(.c) c_int {
88 return @intFromBool(std.ascii.isControl(@intCast(c)));
89}
90
91fn __iscntrl_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
92 _ = locale;
93 return iscntrl(c);
94}
95
96fn isdigit(c: c_int) callconv(.c) c_int {
97 return @intFromBool(std.ascii.isDigit(@intCast(c)));
98}
99
100fn __isdigit_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
101 _ = locale;
102 return isdigit(c);
103}
104
105fn isgraph(c: c_int) callconv(.c) c_int {
106 return @intFromBool(std.ascii.isGraphical(@intCast(c)));
107}
108
109fn __isgraph_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
110 _ = locale;
111 return isgraph(c);
112}
113
114fn islower(c: c_int) callconv(.c) c_int {
115 return @intFromBool(std.ascii.isLower(@intCast(c)));
116}
117
118fn __islower_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
119 _ = locale;
120 return islower(c);
121}
122
123fn isprint(c: c_int) callconv(.c) c_int {
124 return @intFromBool(std.ascii.isPrint(@intCast(c)));
125}
126
127fn __isprint_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
128 _ = locale;
129 return isprint(c);
130}
131
132fn ispunct(c: c_int) callconv(.c) c_int {
133 return @intFromBool(std.ascii.isPunctuation(@intCast(c)));
134}
135
136fn __ispunct_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
137 _ = locale;
138 return ispunct(c);
139}
140
141fn isspace(c: c_int) callconv(.c) c_int {
142 return @intFromBool(std.ascii.isWhitespace(@intCast(c)));
143}
144
145fn __isspace_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
146 _ = locale;
147 return isspace(c);
148}
149
150fn isupper(c: c_int) callconv(.c) c_int {
151 return @intFromBool(std.ascii.isUpper(@intCast(c)));
152}
153
154fn __isupper_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
155 _ = locale;
156 return isupper(c);
157}
158
159fn isxdigit(c: c_int) callconv(.c) c_int {
160 return @intFromBool(std.ascii.isHex(@intCast(c)));
161}
162
163fn __isxdigit_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
164 _ = locale;
165 return isxdigit(c);
166}
167
168fn tolower(c: c_int) callconv(.c) c_int {
169 return std.ascii.toLower(@intCast(c));
170}
171
172fn __tolower_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
173 _ = locale;
174 return tolower(c);
175}
176
177fn toupper(c: c_int) callconv(.c) c_int {
178 return std.ascii.toUpper(@intCast(c));
179}
180
181fn __toupper_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
182 _ = locale;
183 return toupper(c);
184}
185
186fn isascii(c: c_int) callconv(.c) c_int {
187 return @intFromBool(std.ascii.isAscii(@intCast(c)));
188}
189
190fn toascii(c: c_int) callconv(.c) c_int {
191 return c & 0x7F;
192}
lib/libc/musl/src/ctype/isalnum.c deleted-13
...@@ -1,13 +0,0 @@
1#include <ctype.h>
2
3int isalnum(int c)
4{
5 return isalpha(c) || isdigit(c);
6}
7
8int __isalnum_l(int c, locale_t l)
9{
10 return isalnum(c);
11}
12
13weak_alias(__isalnum_l, isalnum_l);
lib/libc/musl/src/ctype/isalpha.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef isalpha
3
4int isalpha(int c)
5{
6 return ((unsigned)c|32)-'a' < 26;
7}
8
9int __isalpha_l(int c, locale_t l)
10{
11 return isalpha(c);
12}
13
14weak_alias(__isalpha_l, isalpha_l);
lib/libc/musl/src/ctype/isascii.c deleted-7
...@@ -1,7 +0,0 @@
1#include <ctype.h>
2#undef isascii
3
4int isascii(int c)
5{
6 return !(c&~0x7f);
7}
lib/libc/musl/src/ctype/isblank.c deleted-13
...@@ -1,13 +0,0 @@
1#include <ctype.h>
2
3int isblank(int c)
4{
5 return (c == ' ' || c == '\t');
6}
7
8int __isblank_l(int c, locale_t l)
9{
10 return isblank(c);
11}
12
13weak_alias(__isblank_l, isblank_l);
lib/libc/musl/src/ctype/iscntrl.c deleted-13
...@@ -1,13 +0,0 @@
1#include <ctype.h>
2
3int iscntrl(int c)
4{
5 return (unsigned)c < 0x20 || c == 0x7f;
6}
7
8int __iscntrl_l(int c, locale_t l)
9{
10 return iscntrl(c);
11}
12
13weak_alias(__iscntrl_l, iscntrl_l);
lib/libc/musl/src/ctype/isdigit.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef isdigit
3
4int isdigit(int c)
5{
6 return (unsigned)c-'0' < 10;
7}
8
9int __isdigit_l(int c, locale_t l)
10{
11 return isdigit(c);
12}
13
14weak_alias(__isdigit_l, isdigit_l);
lib/libc/musl/src/ctype/isgraph.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef isgraph
3
4int isgraph(int c)
5{
6 return (unsigned)c-0x21 < 0x5e;
7}
8
9int __isgraph_l(int c, locale_t l)
10{
11 return isgraph(c);
12}
13
14weak_alias(__isgraph_l, isgraph_l);
lib/libc/musl/src/ctype/islower.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef islower
3
4int islower(int c)
5{
6 return (unsigned)c-'a' < 26;
7}
8
9int __islower_l(int c, locale_t l)
10{
11 return islower(c);
12}
13
14weak_alias(__islower_l, islower_l);
lib/libc/musl/src/ctype/isprint.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef isprint
3
4int isprint(int c)
5{
6 return (unsigned)c-0x20 < 0x5f;
7}
8
9int __isprint_l(int c, locale_t l)
10{
11 return isprint(c);
12}
13
14weak_alias(__isprint_l, isprint_l);
lib/libc/musl/src/ctype/ispunct.c deleted-13
...@@ -1,13 +0,0 @@
1#include <ctype.h>
2
3int ispunct(int c)
4{
5 return isgraph(c) && !isalnum(c);
6}
7
8int __ispunct_l(int c, locale_t l)
9{
10 return ispunct(c);
11}
12
13weak_alias(__ispunct_l, ispunct_l);
lib/libc/musl/src/ctype/isspace.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef isspace
3
4int isspace(int c)
5{
6 return c == ' ' || (unsigned)c-'\t' < 5;
7}
8
9int __isspace_l(int c, locale_t l)
10{
11 return isspace(c);
12}
13
14weak_alias(__isspace_l, isspace_l);
lib/libc/musl/src/ctype/isupper.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2#undef isupper
3
4int isupper(int c)
5{
6 return (unsigned)c-'A' < 26;
7}
8
9int __isupper_l(int c, locale_t l)
10{
11 return isupper(c);
12}
13
14weak_alias(__isupper_l, isupper_l);
lib/libc/musl/src/ctype/isxdigit.c deleted-13
...@@ -1,13 +0,0 @@
1#include <ctype.h>
2
3int isxdigit(int c)
4{
5 return isdigit(c) || ((unsigned)c|32)-'a' < 6;
6}
7
8int __isxdigit_l(int c, locale_t l)
9{
10 return isxdigit(c);
11}
12
13weak_alias(__isxdigit_l, isxdigit_l);
lib/libc/musl/src/ctype/toascii.c deleted-7
...@@ -1,7 +0,0 @@
1#include <ctype.h>
2
3/* nonsense function that should NEVER be used! */
4int toascii(int c)
5{
6 return c & 0x7f;
7}
lib/libc/musl/src/ctype/tolower.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2
3int tolower(int c)
4{
5 if (isupper(c)) return c | 32;
6 return c;
7}
8
9int __tolower_l(int c, locale_t l)
10{
11 return tolower(c);
12}
13
14weak_alias(__tolower_l, tolower_l);
lib/libc/musl/src/ctype/toupper.c deleted-14
...@@ -1,14 +0,0 @@
1#include <ctype.h>
2
3int toupper(int c)
4{
5 if (islower(c)) return c & 0x5f;
6 return c;
7}
8
9int __toupper_l(int c, locale_t l)
10{
11 return toupper(c);
12}
13
14weak_alias(__toupper_l, toupper_l);
lib/std/ascii.zig+21
...@@ -137,6 +137,16 @@ pub fn isPrint(c: u8) bool {...@@ -137,6 +137,16 @@ pub fn isPrint(c: u8) bool {
137 return isAscii(c) and !isControl(c);137 return isAscii(c) and !isControl(c);
138}138}
139139
140/// Returns whether the character has some graphical representation,
141pub fn isGraphical(c: u8) bool {
142 return isPrint(c) and c != ' ';
143}
144
145/// Returns whether the character is a punctuation character.
146pub fn isPunctuation(c: u8) bool {
147 return isGraphical(c) and !isAlphanumeric(c);
148}
149
140/// Returns whether this character is included in `whitespace`.150/// Returns whether this character is included in `whitespace`.
141pub fn isWhitespace(c: u8) bool {151pub fn isWhitespace(c: u8) bool {
142 return switch (c) {152 return switch (c) {
...@@ -264,6 +274,17 @@ test "ASCII character classes" {...@@ -264,6 +274,17 @@ test "ASCII character classes" {
264 try testing.expect(!isPrint(control_code.esc));274 try testing.expect(!isPrint(control_code.esc));
265 try testing.expect(!isPrint(0x80));275 try testing.expect(!isPrint(0x80));
266 try testing.expect(!isPrint(0xff));276 try testing.expect(!isPrint(0xff));
277
278 try testing.expect(isGraphical('@'));
279 try testing.expect(isGraphical('!'));
280 try testing.expect(!isGraphical(' '));
281
282 try testing.expect(isPunctuation('@'));
283 try testing.expect(isPunctuation('!'));
284 try testing.expect(isPunctuation(';'));
285 try testing.expect(isPunctuation(','));
286 try testing.expect(!isPunctuation('A'));
287 try testing.expect(!isPunctuation('8'));
267}288}
268289
269/// Writes a lower case copy of `ascii_string` to `output`.290/// Writes a lower case copy of `ascii_string` to `output`.
src/libs/musl.zig-16
...@@ -535,18 +535,6 @@ const src_files = [_][]const u8{...@@ -535,18 +535,6 @@ const src_files = [_][]const u8{
535 "musl/src/ctype/__ctype_get_mb_cur_max.c",535 "musl/src/ctype/__ctype_get_mb_cur_max.c",
536 "musl/src/ctype/__ctype_tolower_loc.c",536 "musl/src/ctype/__ctype_tolower_loc.c",
537 "musl/src/ctype/__ctype_toupper_loc.c",537 "musl/src/ctype/__ctype_toupper_loc.c",
538 "musl/src/ctype/isalnum.c",
539 "musl/src/ctype/isalpha.c",
540 "musl/src/ctype/isascii.c",
541 "musl/src/ctype/isblank.c",
542 "musl/src/ctype/iscntrl.c",
543 "musl/src/ctype/isdigit.c",
544 "musl/src/ctype/isgraph.c",
545 "musl/src/ctype/islower.c",
546 "musl/src/ctype/isprint.c",
547 "musl/src/ctype/ispunct.c",
548 "musl/src/ctype/isspace.c",
549 "musl/src/ctype/isupper.c",
550 "musl/src/ctype/iswalnum.c",538 "musl/src/ctype/iswalnum.c",
551 "musl/src/ctype/iswalpha.c",539 "musl/src/ctype/iswalpha.c",
552 "musl/src/ctype/iswblank.c",540 "musl/src/ctype/iswblank.c",
...@@ -560,10 +548,6 @@ const src_files = [_][]const u8{...@@ -560,10 +548,6 @@ const src_files = [_][]const u8{
560 "musl/src/ctype/iswspace.c",548 "musl/src/ctype/iswspace.c",
561 "musl/src/ctype/iswupper.c",549 "musl/src/ctype/iswupper.c",
562 "musl/src/ctype/iswxdigit.c",550 "musl/src/ctype/iswxdigit.c",
563 "musl/src/ctype/isxdigit.c",
564 "musl/src/ctype/toascii.c",
565 "musl/src/ctype/tolower.c",
566 "musl/src/ctype/toupper.c",
567 "musl/src/ctype/towctrans.c",551 "musl/src/ctype/towctrans.c",
568 "musl/src/ctype/wcswidth.c",552 "musl/src/ctype/wcswidth.c",
569 "musl/src/ctype/wctrans.c",553 "musl/src/ctype/wctrans.c",
src/libs/wasi_libc.zig-16
...@@ -643,18 +643,6 @@ const libc_top_half_src_files = [_][]const u8{...@@ -643,18 +643,6 @@ const libc_top_half_src_files = [_][]const u8{
643 "musl/src/ctype/__ctype_get_mb_cur_max.c",643 "musl/src/ctype/__ctype_get_mb_cur_max.c",
644 "musl/src/ctype/__ctype_tolower_loc.c",644 "musl/src/ctype/__ctype_tolower_loc.c",
645 "musl/src/ctype/__ctype_toupper_loc.c",645 "musl/src/ctype/__ctype_toupper_loc.c",
646 "musl/src/ctype/isalnum.c",
647 "musl/src/ctype/isalpha.c",
648 "musl/src/ctype/isascii.c",
649 "musl/src/ctype/isblank.c",
650 "musl/src/ctype/iscntrl.c",
651 "musl/src/ctype/isdigit.c",
652 "musl/src/ctype/isgraph.c",
653 "musl/src/ctype/islower.c",
654 "musl/src/ctype/isprint.c",
655 "musl/src/ctype/ispunct.c",
656 "musl/src/ctype/isspace.c",
657 "musl/src/ctype/isupper.c",
658 "musl/src/ctype/iswalnum.c",646 "musl/src/ctype/iswalnum.c",
659 "musl/src/ctype/iswalpha.c",647 "musl/src/ctype/iswalpha.c",
660 "musl/src/ctype/iswblank.c",648 "musl/src/ctype/iswblank.c",
...@@ -668,10 +656,6 @@ const libc_top_half_src_files = [_][]const u8{...@@ -668,10 +656,6 @@ const libc_top_half_src_files = [_][]const u8{
668 "musl/src/ctype/iswspace.c",656 "musl/src/ctype/iswspace.c",
669 "musl/src/ctype/iswupper.c",657 "musl/src/ctype/iswupper.c",
670 "musl/src/ctype/iswxdigit.c",658 "musl/src/ctype/iswxdigit.c",
671 "musl/src/ctype/isxdigit.c",
672 "musl/src/ctype/toascii.c",
673 "musl/src/ctype/tolower.c",
674 "musl/src/ctype/toupper.c",
675 "musl/src/ctype/towctrans.c",659 "musl/src/ctype/towctrans.c",
676 "musl/src/ctype/wcswidth.c",660 "musl/src/ctype/wcswidth.c",
677 "musl/src/ctype/wctrans.c",661 "musl/src/ctype/wctrans.c",