feat(libzigc): add common ctype implementation

* implements all functions in the standard `ctype.h` header
* also removes their musl implementations
This commit is contained in:
GasInfinity 2026-01-09 02:46:52 +01:00
parent e558e64ca0
commit 6abb1dcd35
No known key found for this signature in database
20 changed files with 193 additions and 237 deletions

View file

@ -15,6 +15,7 @@ else
comptime {
_ = @import("c/inttypes.zig");
_ = @import("c/ctype.zig");
_ = @import("c/stdlib.zig");
_ = @import("c/math.zig");

192
lib/c/ctype.zig Normal file
View file

@ -0,0 +1,192 @@
const std = @import("std");
const common = @import("common.zig");
const builtin = @import("builtin");
comptime {
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// Functions specific to musl and wasi-libc.
@export(&isalnum, .{ .name = "isalnum", .linkage = common.linkage, .visibility = common.visibility });
@export(&isalpha, .{ .name = "isalpha", .linkage = common.linkage, .visibility = common.visibility });
@export(&isblank, .{ .name = "isblank", .linkage = common.linkage, .visibility = common.visibility });
@export(&iscntrl, .{ .name = "iscntrl", .linkage = common.linkage, .visibility = common.visibility });
@export(&isdigit, .{ .name = "isdigit", .linkage = common.linkage, .visibility = common.visibility });
@export(&isgraph, .{ .name = "isgraph", .linkage = common.linkage, .visibility = common.visibility });
@export(&islower, .{ .name = "islower", .linkage = common.linkage, .visibility = common.visibility });
@export(&isprint, .{ .name = "isprint", .linkage = common.linkage, .visibility = common.visibility });
@export(&ispunct, .{ .name = "ispunct", .linkage = common.linkage, .visibility = common.visibility });
@export(&isspace, .{ .name = "isspace", .linkage = common.linkage, .visibility = common.visibility });
@export(&isupper, .{ .name = "isupper", .linkage = common.linkage, .visibility = common.visibility });
@export(&isxdigit, .{ .name = "isxdigit", .linkage = common.linkage, .visibility = common.visibility });
@export(&tolower, .{ .name = "tolower", .linkage = common.linkage, .visibility = common.visibility });
@export(&toupper, .{ .name = "toupper", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isalnum_l, .{ .name = "__isalnum_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isalpha_l, .{ .name = "__isalpha_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isblank_l, .{ .name = "__isblank_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__iscntrl_l, .{ .name = "__iscntrl_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isdigit_l, .{ .name = "__isdigit_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isgraph_l, .{ .name = "__isgraph_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__islower_l, .{ .name = "__islower_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isprint_l, .{ .name = "__isprint_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__ispunct_l, .{ .name = "__ispunct_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isspace_l, .{ .name = "__isspace_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isupper_l, .{ .name = "__isupper_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isxdigit_l, .{ .name = "__isxdigit_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__tolower_l, .{ .name = "__tolower_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__toupper_l, .{ .name = "__toupper_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isalnum_l, .{ .name = "isalnum_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isalpha_l, .{ .name = "isalpha_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isblank_l, .{ .name = "isblank_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__iscntrl_l, .{ .name = "iscntrl_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isdigit_l, .{ .name = "isdigit_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isgraph_l, .{ .name = "isgraph_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__islower_l, .{ .name = "islower_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isprint_l, .{ .name = "isprint_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__ispunct_l, .{ .name = "ispunct_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isspace_l, .{ .name = "isspace_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isupper_l, .{ .name = "isupper_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__isxdigit_l, .{ .name = "isxdigit_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__tolower_l, .{ .name = "tolower_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__toupper_l, .{ .name = "toupper_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&isascii, .{ .name = "isascii", .linkage = common.linkage, .visibility = common.visibility });
@export(&toascii, .{ .name = "toascii", .linkage = common.linkage, .visibility = common.visibility });
}
}
// NOTE: If the input is not representable as an unsigned char or is not EOF the behaviour is undefined.
fn isalnum(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isAlphanumeric(@intCast(c)));
}
fn __isalnum_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isalnum(c);
}
fn isalpha(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isAlphabetic(@intCast(c)));
}
fn __isalpha_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isalpha(c);
}
fn isblank(c: c_int) callconv(.c) c_int {
return @intFromBool(c == ' ' or c == '\t');
}
fn __isblank_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isblank(c);
}
fn iscntrl(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isControl(@intCast(c)));
}
fn __iscntrl_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return iscntrl(c);
}
fn isdigit(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isDigit(@intCast(c)));
}
fn __isdigit_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isdigit(c);
}
fn isgraph(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isGraphical(@intCast(c)));
}
fn __isgraph_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isgraph(c);
}
fn islower(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isLower(@intCast(c)));
}
fn __islower_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return islower(c);
}
fn isprint(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isPrint(@intCast(c)));
}
fn __isprint_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isprint(c);
}
fn ispunct(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isPunctuation(@intCast(c)));
}
fn __ispunct_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return ispunct(c);
}
fn isspace(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isWhitespace(@intCast(c)));
}
fn __isspace_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isspace(c);
}
fn isupper(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isUpper(@intCast(c)));
}
fn __isupper_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isupper(c);
}
fn isxdigit(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isHex(@intCast(c)));
}
fn __isxdigit_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return isxdigit(c);
}
fn tolower(c: c_int) callconv(.c) c_int {
return std.ascii.toLower(@intCast(c));
}
fn __tolower_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return tolower(c);
}
fn toupper(c: c_int) callconv(.c) c_int {
return std.ascii.toUpper(@intCast(c));
}
fn __toupper_l(c: c_int, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return toupper(c);
}
fn isascii(c: c_int) callconv(.c) c_int {
return @intFromBool(std.ascii.isAscii(@intCast(c)));
}
fn toascii(c: c_int) callconv(.c) c_int {
return c & 0x7F;
}

View file

@ -1,13 +0,0 @@
#include <ctype.h>
int isalnum(int c)
{
return isalpha(c) || isdigit(c);
}
int __isalnum_l(int c, locale_t l)
{
return isalnum(c);
}
weak_alias(__isalnum_l, isalnum_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef isalpha
int isalpha(int c)
{
return ((unsigned)c|32)-'a' < 26;
}
int __isalpha_l(int c, locale_t l)
{
return isalpha(c);
}
weak_alias(__isalpha_l, isalpha_l);

View file

@ -1,7 +0,0 @@
#include <ctype.h>
#undef isascii
int isascii(int c)
{
return !(c&~0x7f);
}

View file

@ -1,13 +0,0 @@
#include <ctype.h>
int isblank(int c)
{
return (c == ' ' || c == '\t');
}
int __isblank_l(int c, locale_t l)
{
return isblank(c);
}
weak_alias(__isblank_l, isblank_l);

View file

@ -1,13 +0,0 @@
#include <ctype.h>
int iscntrl(int c)
{
return (unsigned)c < 0x20 || c == 0x7f;
}
int __iscntrl_l(int c, locale_t l)
{
return iscntrl(c);
}
weak_alias(__iscntrl_l, iscntrl_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef isdigit
int isdigit(int c)
{
return (unsigned)c-'0' < 10;
}
int __isdigit_l(int c, locale_t l)
{
return isdigit(c);
}
weak_alias(__isdigit_l, isdigit_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef isgraph
int isgraph(int c)
{
return (unsigned)c-0x21 < 0x5e;
}
int __isgraph_l(int c, locale_t l)
{
return isgraph(c);
}
weak_alias(__isgraph_l, isgraph_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef islower
int islower(int c)
{
return (unsigned)c-'a' < 26;
}
int __islower_l(int c, locale_t l)
{
return islower(c);
}
weak_alias(__islower_l, islower_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef isprint
int isprint(int c)
{
return (unsigned)c-0x20 < 0x5f;
}
int __isprint_l(int c, locale_t l)
{
return isprint(c);
}
weak_alias(__isprint_l, isprint_l);

View file

@ -1,13 +0,0 @@
#include <ctype.h>
int ispunct(int c)
{
return isgraph(c) && !isalnum(c);
}
int __ispunct_l(int c, locale_t l)
{
return ispunct(c);
}
weak_alias(__ispunct_l, ispunct_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef isspace
int isspace(int c)
{
return c == ' ' || (unsigned)c-'\t' < 5;
}
int __isspace_l(int c, locale_t l)
{
return isspace(c);
}
weak_alias(__isspace_l, isspace_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
#undef isupper
int isupper(int c)
{
return (unsigned)c-'A' < 26;
}
int __isupper_l(int c, locale_t l)
{
return isupper(c);
}
weak_alias(__isupper_l, isupper_l);

View file

@ -1,13 +0,0 @@
#include <ctype.h>
int isxdigit(int c)
{
return isdigit(c) || ((unsigned)c|32)-'a' < 6;
}
int __isxdigit_l(int c, locale_t l)
{
return isxdigit(c);
}
weak_alias(__isxdigit_l, isxdigit_l);

View file

@ -1,7 +0,0 @@
#include <ctype.h>
/* nonsense function that should NEVER be used! */
int toascii(int c)
{
return c & 0x7f;
}

View file

@ -1,14 +0,0 @@
#include <ctype.h>
int tolower(int c)
{
if (isupper(c)) return c | 32;
return c;
}
int __tolower_l(int c, locale_t l)
{
return tolower(c);
}
weak_alias(__tolower_l, tolower_l);

View file

@ -1,14 +0,0 @@
#include <ctype.h>
int toupper(int c)
{
if (islower(c)) return c & 0x5f;
return c;
}
int __toupper_l(int c, locale_t l)
{
return toupper(c);
}
weak_alias(__toupper_l, toupper_l);

View file

@ -535,18 +535,6 @@ const src_files = [_][]const u8{
"musl/src/ctype/__ctype_get_mb_cur_max.c",
"musl/src/ctype/__ctype_tolower_loc.c",
"musl/src/ctype/__ctype_toupper_loc.c",
"musl/src/ctype/isalnum.c",
"musl/src/ctype/isalpha.c",
"musl/src/ctype/isascii.c",
"musl/src/ctype/isblank.c",
"musl/src/ctype/iscntrl.c",
"musl/src/ctype/isdigit.c",
"musl/src/ctype/isgraph.c",
"musl/src/ctype/islower.c",
"musl/src/ctype/isprint.c",
"musl/src/ctype/ispunct.c",
"musl/src/ctype/isspace.c",
"musl/src/ctype/isupper.c",
"musl/src/ctype/iswalnum.c",
"musl/src/ctype/iswalpha.c",
"musl/src/ctype/iswblank.c",
@ -560,10 +548,6 @@ const src_files = [_][]const u8{
"musl/src/ctype/iswspace.c",
"musl/src/ctype/iswupper.c",
"musl/src/ctype/iswxdigit.c",
"musl/src/ctype/isxdigit.c",
"musl/src/ctype/toascii.c",
"musl/src/ctype/tolower.c",
"musl/src/ctype/toupper.c",
"musl/src/ctype/towctrans.c",
"musl/src/ctype/wcswidth.c",
"musl/src/ctype/wctrans.c",

View file

@ -643,18 +643,6 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/ctype/__ctype_get_mb_cur_max.c",
"musl/src/ctype/__ctype_tolower_loc.c",
"musl/src/ctype/__ctype_toupper_loc.c",
"musl/src/ctype/isalnum.c",
"musl/src/ctype/isalpha.c",
"musl/src/ctype/isascii.c",
"musl/src/ctype/isblank.c",
"musl/src/ctype/iscntrl.c",
"musl/src/ctype/isdigit.c",
"musl/src/ctype/isgraph.c",
"musl/src/ctype/islower.c",
"musl/src/ctype/isprint.c",
"musl/src/ctype/ispunct.c",
"musl/src/ctype/isspace.c",
"musl/src/ctype/isupper.c",
"musl/src/ctype/iswalnum.c",
"musl/src/ctype/iswalpha.c",
"musl/src/ctype/iswblank.c",
@ -668,10 +656,6 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/ctype/iswspace.c",
"musl/src/ctype/iswupper.c",
"musl/src/ctype/iswxdigit.c",
"musl/src/ctype/isxdigit.c",
"musl/src/ctype/toascii.c",
"musl/src/ctype/tolower.c",
"musl/src/ctype/toupper.c",
"musl/src/ctype/towctrans.c",
"musl/src/ctype/wcswidth.c",
"musl/src/ctype/wctrans.c",