feat(libzigc): use common implementations for strings.h and string.h

* forwards all functions to their equivalent `std`
* removes their musl, wasi-libc and mingw implementations
This commit is contained in:
GasInfinity
2026-01-17 20:56:35 +01:00
parent 06d05decae
commit f0649dd978
42 changed files with 370 additions and 1164 deletions
+2 -2
View File
@@ -18,12 +18,12 @@ comptime {
_ = @import("c/ctype.zig");
_ = @import("c/stdlib.zig");
_ = @import("c/math.zig");
_ = @import("c/string.zig");
_ = @import("c/strings.zig");
_ = @import("c/wchar.zig");
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// Files specific to musl and wasi-libc.
_ = @import("c/string.zig");
_ = @import("c/strings.zig");
}
if (builtin.target.isMuslLibC()) {
+265 -70
View File
@@ -3,97 +3,292 @@ const std = @import("std");
const common = @import("common.zig");
comptime {
@export(&strcmp, .{ .name = "strcmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncmp, .{ .name = "strncmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcasecmp, .{ .name = "strcasecmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncasecmp, .{ .name = "strncasecmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcasecmp_l, .{ .name = "__strcasecmp_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strncasecmp_l, .{ .name = "__strncasecmp_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcasecmp_l, .{ .name = "strcasecmp_l", .linkage = .weak, .visibility = common.visibility });
@export(&__strncasecmp_l, .{ .name = "strncasecmp_l", .linkage = .weak, .visibility = common.visibility });
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// memcpy implemented in compiler_rt
// memmove implemented in compiler_rt
// memset implemented in compiler_rt
// memcmp implemented in compiler_rt
@export(&memchr, .{ .name = "memchr", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcpy, .{ .name = "strcpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncpy, .{ .name = "strncpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcat, .{ .name = "strcat", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncat, .{ .name = "strncat", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcmp, .{ .name = "strcmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncmp, .{ .name = "strncmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcoll, .{ .name = "strcoll", .linkage = common.linkage, .visibility = common.visibility });
@export(&strxfrm, .{ .name = "strxfrm", .linkage = common.linkage, .visibility = common.visibility });
@export(&strchr, .{ .name = "strchr", .linkage = common.linkage, .visibility = common.visibility });
@export(&strrchr, .{ .name = "strrchr", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcspn, .{ .name = "strcspn", .linkage = common.linkage, .visibility = common.visibility });
@export(&strspn, .{ .name = "strspn", .linkage = common.linkage, .visibility = common.visibility });
@export(&strpbrk, .{ .name = "strpbrk", .linkage = common.linkage, .visibility = common.visibility });
@export(&strstr, .{ .name = "strstr", .linkage = common.linkage, .visibility = common.visibility });
@export(&strtok, .{ .name = "strtok", .linkage = common.linkage, .visibility = common.visibility });
// strlen is in compiler_rt
@export(&strtok_r, .{ .name = "strtok_r", .linkage = common.linkage, .visibility = common.visibility });
@export(&stpcpy, .{ .name = "stpcpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&stpncpy, .{ .name = "stpncpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&strnlen, .{ .name = "strnlen", .linkage = common.linkage, .visibility = common.visibility });
@export(&memmem, .{ .name = "memmem", .linkage = common.linkage, .visibility = common.visibility });
@export(&memccpy, .{ .name = "memccpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&strsep, .{ .name = "strsep", .linkage = common.linkage, .visibility = common.visibility });
@export(&strlcat, .{ .name = "strlcat", .linkage = common.linkage, .visibility = common.visibility });
@export(&strlcpy, .{ .name = "strlcpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&explicit_bzero, .{ .name = "explicit_bzero", .linkage = common.linkage, .visibility = common.visibility });
@export(&strchrnul, .{ .name = "strchrnul", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcasestr, .{ .name = "strcasestr", .linkage = common.linkage, .visibility = common.visibility });
@export(&memrchr, .{ .name = "memrchr", .linkage = common.linkage, .visibility = common.visibility });
@export(&mempcpy, .{ .name = "mempcpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcoll_l, .{ .name = "__strcoll_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strxfrm_l, .{ .name = "__strxfrm_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcoll_l, .{ .name = "strcoll_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strxfrm_l, .{ .name = "strxfrm_l", .linkage = common.linkage, .visibility = common.visibility });
// These symbols are not in the public ABI of musl/wasi. However they depend on these exports internally.
@export(&stpcpy, .{ .name = "__stpcpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&stpncpy, .{ .name = "__stpncpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&strchrnul, .{ .name = "__strchrnul", .linkage = common.linkage, .visibility = common.visibility });
@export(&memrchr, .{ .name = "__memrchr", .linkage = common.linkage, .visibility = common.visibility });
}
if (builtin.target.isMinGW()) {
@export(&strnlen, .{ .name = "strnlen", .linkage = common.linkage, .visibility = common.visibility });
@export(&mempcpy, .{ .name = "mempcpy", .linkage = common.linkage, .visibility = common.visibility });
@export(&strtok_r, .{ .name = "strtok_r", .linkage = common.linkage, .visibility = common.visibility });
}
}
fn strcmp(s1: [*:0]const c_char, s2: [*:0]const c_char) callconv(.c) c_int {
// We need to perform unsigned comparisons.
return switch (std.mem.orderZ(u8, @ptrCast(s1), @ptrCast(s2))) {
.lt => -1,
fn memchr(ptr: *const anyopaque, value: c_int, len: usize) callconv(.c) ?*anyopaque {
const bytes: [*]const u8 = @ptrCast(ptr);
return @constCast(bytes[std.mem.findScalar(u8, bytes[0..len], @truncate(@as(c_uint, @bitCast(value)))) orelse return null ..]);
}
fn strcpy(noalias dst: [*]c_char, noalias src: [*:0]const c_char) callconv(.c) [*]c_char {
_ = stpcpy(dst, src);
return dst;
}
fn strncpy(noalias dst: [*]c_char, noalias src: [*:0]const c_char, max: usize) callconv(.c) [*]c_char {
_ = stpncpy(dst, src, max);
return dst;
}
fn strcat(noalias dst: [*:0]c_char, noalias src: [*:0]const c_char) callconv(.c) [*:0]c_char {
return strncat(dst, src, std.math.maxInt(usize));
}
fn strncat(noalias dst: [*:0]c_char, noalias src: [*:0]const c_char, max: usize) callconv(.c) [*:0]c_char {
const dst_len = std.mem.len(@as([*:0]u8, @ptrCast(dst)));
const src_len = strnlen(src, max);
@memcpy(dst[dst_len..][0..src_len], src[0..src_len]);
dst[dst_len + src_len] = 0;
return dst[0..(dst_len + src_len) :0].ptr;
}
fn strcmp(a: [*:0]const c_char, b: [*:0]const c_char) callconv(.c) c_int {
return strncmp(a, b, std.math.maxInt(usize));
}
fn strncmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) callconv(.c) c_int {
return switch (std.mem.boundedOrderZ(u8, @ptrCast(a), @ptrCast(b), max)) {
.eq => 0,
.gt => 1,
.lt => -1,
};
}
fn strncmp(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize) callconv(.c) c_int {
if (n == 0) return 0;
var l: [*:0]const u8 = @ptrCast(s1);
var r: [*:0]const u8 = @ptrCast(s2);
var i = n - 1;
while (l[0] != 0 and r[0] != 0 and i != 0 and l[0] == r[0]) {
l += 1;
r += 1;
i -= 1;
}
return @as(c_int, l[0]) - @as(c_int, r[0]);
fn strcoll(a: [*:0]const c_char, b: [*:0]const c_char) callconv(.c) c_int {
return strcmp(a, b);
}
fn strcasecmp(s1: [*:0]const c_char, s2: [*:0]const c_char) callconv(.c) c_int {
const toLower = std.ascii.toLower;
var l: [*:0]const u8 = @ptrCast(s1);
var r: [*:0]const u8 = @ptrCast(s2);
while (l[0] != 0 and r[0] != 0 and (l[0] == r[0] or toLower(l[0]) == toLower(r[0]))) {
l += 1;
r += 1;
}
return @as(c_int, toLower(l[0])) - @as(c_int, toLower(r[0]));
}
fn __strcasecmp_l(s1: [*:0]const c_char, s2: [*:0]const c_char, locale: *anyopaque) callconv(.c) c_int {
fn __strcoll_l(a: [*:0]const c_char, b: [*:0]const c_char, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return strcasecmp(s1, s2);
return strcoll(a, b);
}
fn strncasecmp(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize) callconv(.c) c_int {
const toLower = std.ascii.toLower;
var l: [*:0]const u8 = @ptrCast(s1);
var r: [*:0]const u8 = @ptrCast(s2);
var i = n - 1;
// NOTE: If 'max' is 0, 'dst' is allowed to be a null pointer
fn strxfrm(noalias dst: ?[*]c_char, noalias src: [*:0]const c_char, max: usize) callconv(.c) usize {
const src_len = std.mem.len(@as([*:0]const u8, @ptrCast(src)));
if (src_len < max) @memcpy(dst.?[0 .. src_len + 1], src[0 .. src_len + 1]);
return src_len;
}
while (l[0] != 0 and r[0] != 0 and i != 0 and (l[0] == r[0] or toLower(l[0]) == toLower(r[0]))) {
l += 1;
r += 1;
i -= 1;
fn __strxfrm_l(noalias dst: ?[*]c_char, noalias src: [*:0]const c_char, max: usize, locale: *anyopaque) callconv(.c) usize {
_ = locale;
return strxfrm(dst, src, max);
}
fn strchr(str: [*:0]const c_char, value: c_int) callconv(.c) ?[*:0]c_char {
const str_u8: [*:0]const u8 = @ptrCast(str);
const len = std.mem.len(str_u8);
if (value == 0) return @constCast(str + len);
return @constCast(str[std.mem.findScalar(u8, str_u8[0..len], @truncate(@as(c_uint, @bitCast(value)))) orelse return null ..]);
}
fn strrchr(str: [*:0]const c_char, value: c_int) callconv(.c) ?[*:0]c_char {
const str_u8: [*:0]const u8 = @ptrCast(str);
// std.mem.len(str) + 1 to not special case '\0'
return @constCast(str[std.mem.findScalarLast(u8, str_u8[0 .. std.mem.len(str_u8) + 1], @truncate(@as(c_uint, @bitCast(value)))) orelse return null ..]);
}
fn strcspn(dst: [*:0]const c_char, values: [*:0]const c_char) callconv(.c) usize {
const dst_slice = std.mem.span(@as([*:0]const u8, @ptrCast(dst)));
return std.mem.findAny(u8, dst_slice, std.mem.span(@as([*:0]const u8, @ptrCast(values)))) orelse dst_slice.len;
}
fn strspn(dst: [*:0]const c_char, values: [*:0]const c_char) callconv(.c) usize {
const dst_slice = std.mem.span(@as([*:0]const u8, @ptrCast(dst)));
return std.mem.findNone(u8, dst_slice, std.mem.span(@as([*:0]const u8, @ptrCast(values)))) orelse dst_slice.len;
}
fn strpbrk(haystack: [*:0]const c_char, needle: [*:0]const c_char) callconv(.c) ?[*:0]c_char {
return @constCast(haystack[std.mem.findAny(u8, std.mem.span(@as([*:0]const u8, @ptrCast(haystack))), std.mem.span(@as([*:0]const u8, @ptrCast(needle)))) orelse return null ..]);
}
fn strstr(haystack: [*:0]const c_char, needle: [*:0]const c_char) callconv(.c) ?[*:0]c_char {
return @constCast(haystack[std.mem.find(u8, std.mem.span(@as([*:0]const u8, @ptrCast(haystack))), std.mem.span(@as([*:0]const u8, @ptrCast(needle)))) orelse return null ..]);
}
fn strtok(noalias maybe_str: ?[*:0]c_char, noalias values: [*:0]const c_char) callconv(.c) ?[*:0]c_char {
const state = struct {
var str: ?[*:0]c_char = null;
};
return strtok_r(maybe_str, values, &state.str);
}
// strlen is in compiler_rt
fn strtok_r(noalias maybe_str: ?[*:0]c_char, noalias values: [*:0]const c_char, noalias state: *?[*:0]c_char) callconv(.c) ?[*:0]c_char {
const str = if (maybe_str) |str|
str
else if (state.*) |state_str|
state_str
else
return null;
const str_bytes = std.mem.span(@as([*:0]u8, @ptrCast(str)));
const values_bytes = std.mem.span(@as([*:0]const u8, @ptrCast(values)));
const tok_start = std.mem.findNone(u8, str_bytes, values_bytes) orelse return null;
if (std.mem.findAnyPos(u8, str_bytes, tok_start, values_bytes)) |tok_end| {
str[tok_end] = 0;
state.* = str[tok_end + 1 ..];
} else {
state.* = str[str_bytes.len..];
}
return @as(c_int, toLower(l[0])) - @as(c_int, toLower(r[0]));
return str[tok_start..];
}
fn __strncasecmp_l(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return strncasecmp(s1, s2, n);
fn stpcpy(noalias dst: [*]c_char, noalias src: [*:0]const c_char) callconv(.c) [*]c_char {
const src_len = std.mem.len(@as([*:0]const u8, @ptrCast(src)));
@memcpy(dst[0 .. src_len + 1], src[0 .. src_len + 1]);
return dst + src_len;
}
test strcasecmp {
try std.testing.expect(strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
try std.testing.expect(strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
try std.testing.expect(strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
fn stpncpy(noalias dst: [*]c_char, noalias src: [*:0]const c_char, max: usize) callconv(.c) [*]c_char {
const src_len = strnlen(src, max);
const copying_len = @min(max, src_len);
@memcpy(dst[0..copying_len], src[0..copying_len]);
@memset(dst[copying_len..][0 .. max - copying_len], 0x00);
return dst + copying_len;
}
test strncasecmp {
try std.testing.expect(strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
try std.testing.expect(strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
try std.testing.expect(strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
fn strnlen(str: [*:0]const c_char, max: usize) callconv(.c) usize {
return std.mem.findScalar(u8, @ptrCast(str[0..max]), 0) orelse max;
}
fn memmem(haystack: *const anyopaque, haystack_len: usize, needle: *const anyopaque, needle_len: usize) callconv(.c) ?*anyopaque {
const haystack_bytes: [*:0]const u8 = @ptrCast(haystack);
const needle_bytes: [*:0]const u8 = @ptrCast(needle);
return @constCast(haystack_bytes[std.mem.find(u8, haystack_bytes[0..haystack_len], needle_bytes[0..needle_len]) orelse return null ..]);
}
fn strsep(maybe_str: *?[*:0]c_char, values: [*:0]const c_char) callconv(.c) ?[*]c_char {
if (maybe_str.*) |str| {
const values_bytes = std.mem.span(@as([*:0]const u8, @ptrCast(values)));
const str_bytes = std.mem.span(@as([*:0]u8, @ptrCast(str)));
const found = std.mem.findAny(u8, str_bytes, values_bytes) orelse {
maybe_str.* = null;
return str;
};
str[found] = 0;
maybe_str.* = str[found + 1 ..];
return str;
}
return null;
}
fn strlcat(dst: [*:0]c_char, src: [*:0]const c_char, dst_total_len: usize) callconv(.c) usize {
const dst_len = strnlen(dst, dst_total_len);
const src_bytes = std.mem.span(@as([*:0]const u8, @ptrCast(src)));
if (dst_total_len == dst_len) return dst_len + src_bytes.len;
const copying_len = @min(dst_total_len - (dst_len + 1), src_bytes.len);
@memcpy(dst[dst_len..][0..copying_len], src[0..copying_len]);
dst[dst_len + copying_len] = 0;
return dst_len + src_bytes.len;
}
fn strlcpy(dst: [*]c_char, src: [*:0]const c_char, dst_total_len: usize) callconv(.c) usize {
const src_bytes = std.mem.span(@as([*:0]const u8, @ptrCast(src)));
if (dst_total_len != 0) {
const copying_len = @min(src_bytes.len, dst_total_len - 1);
@memcpy(dst[0..copying_len], src[0..copying_len]);
dst[copying_len] = 0;
}
return src_bytes.len;
}
fn memccpy(noalias dst: *anyopaque, noalias src: *const anyopaque, value: c_int, len: usize) callconv(.c) *anyopaque {
const dst_bytes: [*]u8 = @ptrCast(dst);
const src_bytes: [*]const u8 = @ptrCast(src);
const value_u8: u8 = @truncate(@as(c_uint, @bitCast(value)));
const copying_len = std.mem.findScalar(u8, src_bytes[0..len], value_u8) orelse len;
@memcpy(dst_bytes[0..copying_len], src_bytes[0..copying_len]);
return dst_bytes + copying_len;
}
fn explicit_bzero(ptr: *anyopaque, len: usize) callconv(.c) void {
const bytes: [*]u8 = @ptrCast(ptr);
std.crypto.secureZero(u8, bytes[0..len]);
}
fn strchrnul(str: [*:0]const c_char, value: c_int) callconv(.c) [*:0]c_char {
const str_u8: [*:0]const u8 = @ptrCast(str);
const len = std.mem.len(str_u8);
if (value == 0) return @constCast(str + len);
return @constCast(str[std.mem.findScalar(u8, str_u8[0..len], @truncate(@as(c_uint, @bitCast(value)))) orelse len ..]);
}
fn strcasestr(haystack: [*:0]const c_char, needle: [*:0]const c_char) callconv(.c) ?[*:0]c_char {
return @constCast(haystack[std.ascii.findIgnoreCase(std.mem.span(@as([*:0]const u8, @ptrCast(haystack))), std.mem.span(@as([*:0]const u8, @ptrCast(needle)))) orelse return null ..]);
}
fn memrchr(ptr: *const anyopaque, value: c_int, len: usize) callconv(.c) ?*anyopaque {
const bytes: [*]const u8 = @ptrCast(ptr);
return @constCast(bytes[std.mem.findScalarLast(u8, bytes[0..len], @truncate(@as(c_uint, @bitCast(value)))) orelse return null ..]);
}
fn mempcpy(noalias dst: *anyopaque, noalias src: *const anyopaque, len: usize) callconv(.c) *anyopaque {
const dst_bytes: [*]u8 = @ptrCast(dst);
const src_bytes: [*]const u8 = @ptrCast(src);
@memcpy(dst_bytes[0..len], src_bytes[0..len]);
return dst_bytes + len;
}
test strncmp {
+103 -1
View File
@@ -1,8 +1,34 @@
const std = @import("std");
const common = @import("common.zig");
const builtin = @import("builtin");
comptime {
@export(&bzero, .{ .name = "bzero", .linkage = common.linkage, .visibility = common.visibility });
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
// bcmp is implemented in compiler_rt
@export(&bcopy, .{ .name = "bcopy", .linkage = common.linkage, .visibility = common.visibility });
@export(&bzero, .{ .name = "bzero", .linkage = common.linkage, .visibility = common.visibility });
@export(&index, .{ .name = "index", .linkage = common.linkage, .visibility = common.visibility });
@export(&rindex, .{ .name = "rindex", .linkage = common.linkage, .visibility = common.visibility });
@export(&ffs, .{ .name = "ffs", .linkage = common.linkage, .visibility = common.visibility });
@export(&ffsl, .{ .name = "ffsl", .linkage = common.linkage, .visibility = common.visibility });
@export(&ffsll, .{ .name = "ffsll", .linkage = common.linkage, .visibility = common.visibility });
@export(&strcasecmp, .{ .name = "strcasecmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&strncasecmp, .{ .name = "strncasecmp", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcasecmp_l, .{ .name = "__strcasecmp_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strncasecmp_l, .{ .name = "__strncasecmp_l", .linkage = common.linkage, .visibility = common.visibility });
@export(&__strcasecmp_l, .{ .name = "strcasecmp_l", .linkage = .weak, .visibility = common.visibility });
@export(&__strncasecmp_l, .{ .name = "strncasecmp_l", .linkage = .weak, .visibility = common.visibility });
}
}
fn bcopy(src: *const anyopaque, dst: *anyopaque, len: usize) callconv(.c) void {
const src_bytes: [*]const u8 = @ptrCast(src);
const dst_bytes: [*]u8 = @ptrCast(dst);
@memmove(dst_bytes[0..len], src_bytes[0..len]);
}
fn bzero(s: *anyopaque, n: usize) callconv(.c) void {
@@ -10,6 +36,52 @@ fn bzero(s: *anyopaque, n: usize) callconv(.c) void {
@memset(s_cast[0..n], 0);
}
fn index(str: [*:0]const c_char, value: c_int) callconv(.c) ?[*:0]c_char {
return @constCast(str[std.mem.findScalar(u8, std.mem.span(@as([*:0]const u8, @ptrCast(str))), @truncate(@as(c_uint, @bitCast(value)))) orelse return null ..]);
}
fn rindex(str: [*:0]const c_char, value: c_int) callconv(.c) ?[*:0]c_char {
return @constCast(str[std.mem.findScalarLast(u8, std.mem.span(@as([*:0]const u8, @ptrCast(str))), @truncate(@as(c_uint, @bitCast(value)))) orelse return null ..]);
}
fn firstBitSet(comptime T: type, value: T) T {
return @bitSizeOf(T) - @clz(value);
}
fn ffs(i: c_int) callconv(.c) c_int {
return firstBitSet(c_int, i);
}
fn ffsl(i: c_long) callconv(.c) c_long {
return firstBitSet(c_long, i);
}
fn ffsll(i: c_longlong) callconv(.c) c_longlong {
return firstBitSet(c_longlong, i);
}
fn strcasecmp(a: [*:0]const c_char, b: [*:0]const c_char) callconv(.c) c_int {
return strncasecmp(a, b, std.math.maxInt(usize));
}
fn __strcasecmp_l(a: [*:0]const c_char, b: [*:0]const c_char, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return strcasecmp(a, b);
}
fn strncasecmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) callconv(.c) c_int {
return switch (std.ascii.boundedOrderIgnoreCaseZ(@ptrCast(a), @ptrCast(b), max)) {
.eq => 0,
.gt => 1,
.lt => -1,
};
}
fn __strncasecmp_l(a: [*:0]const c_char, b: [*:0]const c_char, n: usize, locale: *anyopaque) callconv(.c) c_int {
_ = locale;
return strncasecmp(a, b, n);
}
test bzero {
var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
var a = std.mem.zeroes([array.len]u8);
@@ -17,3 +89,33 @@ test bzero {
bzero(&array[0], 9);
try std.testing.expect(std.mem.eql(u8, &array, &a));
}
test firstBitSet {
try std.testing.expectEqual(0, firstBitSet(usize, 0));
for (0..@bitSizeOf(usize)) |i| {
const bit = @as(usize, 1) << @intCast(i);
try std.testing.expectEqual(i + 1, firstBitSet(usize, bit));
}
}
test strcasecmp {
try std.testing.expect(strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0);
try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0);
try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0);
try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0);
try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0);
try std.testing.expect(strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0);
try std.testing.expect(strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0);
}
test strncasecmp {
try std.testing.expect(strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0);
try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0);
try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0);
try std.testing.expect(strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0);
try std.testing.expect(strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0);
}
-12
View File
@@ -1,12 +0,0 @@
#define __CRT__NO_INLINE
#include <string.h>
void * __cdecl
mempcpy (void *d, const void *s, size_t len)
{
char *r = ((char *) d) + len;
if (len != 0)
memcpy (d, s, len);
return r;
}
-11
View File
@@ -1,11 +0,0 @@
#define __CRT__NO_INLINE
#include <string.h>
size_t __cdecl strnlen (const char *s, size_t maxlen)
{
const char *s2 = s;
while ((size_t) (s2 - s) < maxlen && *s2)
++s2;
return s2 - s;
}
-98
View File
@@ -1,98 +0,0 @@
/*-
* Copyright (c) 1998 Softweyr LLC. All rights reserved.
*
* strtok_r, from Berkeley strtok
* Oct 13, 1998 by Wes Peters <wes@softweyr.com>
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notices, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notices, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
* REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _POSIX_SOURCE 1
#include <string.h>
/*
* strtok_r documentation:
* http://pubs.opengroup.org/onlinepubs/009695399/functions/strtok.html
*
* Implementation:
* http://svnweb.freebsd.org/base/head/lib/libc/string/strtok.c?view=co
*
* strtok_r cannot completely be implemented by strtok because of the internal state.
* It breaks when used on 2 strings where they are scanned A, B then A, B.
* Thread-safety is not the issue.
*
* Sample strtok implemenatation, note the internal state:
* char *strtok(char *s, const char *d) { static char *t; return strtok_r(s,d,t); }
*
*/
char *
strtok_r(char * __restrict s, const char * __restrict delim, char ** __restrict last)
{
char *spanp, *tok;
int c, sc;
if (s == NULL && (s = *last) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
*last = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = '\0';
*last = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
-8
View File
@@ -1,8 +0,0 @@
#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
void bcopy(const void *s1, void *s2, size_t n)
{
memmove(s2, s1, n);
}
-8
View File
@@ -1,8 +0,0 @@
#define _BSD_SOURCE
#include <string.h>
void explicit_bzero(void *d, size_t n)
{
d = memset(d, 0, n);
__asm__ __volatile__ ("" : : "r"(d) : "memory");
}
-8
View File
@@ -1,8 +0,0 @@
#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
char *index(const char *s, int c)
{
return strchr(s, c);
}
-34
View File
@@ -1,34 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;
c = (unsigned char)c;
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
word *wd;
const word *ws;
if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
for (; ((uintptr_t)s & ALIGN) && n && (*d=*s)!=c; n--, s++, d++);
if ((uintptr_t)s & ALIGN) goto tail;
size_t k = ONES * c;
wd=(void *)d; ws=(const void *)s;
for (; n>=sizeof(size_t) && !HASZERO(*ws^k);
n-=sizeof(size_t), ws++, wd++) *wd = *ws;
d=(void *)wd; s=(const void *)ws;
}
#endif
for (; n && (*d=*s)!=c; n--, s++, d++);
tail:
if (n) return d+1;
return 0;
}
-27
View File
@@ -1,27 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define SS (sizeof(size_t))
#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
void *memchr(const void *src, int c, size_t n)
{
const unsigned char *s = src;
c = (unsigned char)c;
#ifdef __GNUC__
for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--);
if (n && *s != c) {
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
size_t k = ONES * c;
for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS);
s = (const void *)w;
}
#endif
for (; n && *s != c; s++, n--);
return n ? (void *)s : 0;
}
-149
View File
@@ -1,149 +0,0 @@
#define _GNU_SOURCE
#include <string.h>
#include <stdint.h>
static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
for (h+=2, k-=2; k; k--, hw = hw<<8 | *h++)
if (hw == nw) return (char *)h-2;
return hw == nw ? (char *)h-2 : 0;
}
static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8;
uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8;
for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8)
if (hw == nw) return (char *)h-3;
return hw == nw ? (char *)h-3 : 0;
}
static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
for (h+=4, k-=4; k; k--, hw = hw<<8 | *h++)
if (hw == nw) return (char *)h-4;
return hw == nw ? (char *)h-4 : 0;
}
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
static char *twoway_memmem(const unsigned char *h, const unsigned char *z, const unsigned char *n, size_t l)
{
size_t i, ip, jp, k, p, ms, p0, mem, mem0;
size_t byteset[32 / sizeof(size_t)] = { 0 };
size_t shift[256];
/* Computing length of needle and fill shift table */
for (i=0; i<l; i++)
BITOP(byteset, n[i], |=), shift[n[i]] = i+1;
/* Compute maximal suffix */
ip = -1; jp = 0; k = p = 1;
while (jp+k<l) {
if (n[ip+k] == n[jp+k]) {
if (k == p) {
jp += p;
k = 1;
} else k++;
} else if (n[ip+k] > n[jp+k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
ms = ip;
p0 = p;
/* And with the opposite comparison */
ip = -1; jp = 0; k = p = 1;
while (jp+k<l) {
if (n[ip+k] == n[jp+k]) {
if (k == p) {
jp += p;
k = 1;
} else k++;
} else if (n[ip+k] < n[jp+k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
if (ip+1 > ms+1) ms = ip;
else p = p0;
/* Periodic needle? */
if (memcmp(n, n+p, ms+1)) {
mem0 = 0;
p = MAX(ms, l-ms-1) + 1;
} else mem0 = l-p;
mem = 0;
/* Search loop */
for (;;) {
/* If remainder of haystack is shorter than needle, done */
if (z-h < l) return 0;
/* Check last byte first; advance by shift on mismatch */
if (BITOP(byteset, h[l-1], &)) {
k = l-shift[h[l-1]];
if (k) {
if (k < mem) k = mem;
h += k;
mem = 0;
continue;
}
} else {
h += l;
mem = 0;
continue;
}
/* Compare right half */
for (k=MAX(ms+1,mem); k<l && n[k] == h[k]; k++);
if (k < l) {
h += k-ms;
mem = 0;
continue;
}
/* Compare left half */
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
if (k <= mem) return (char *)h;
h += p;
mem = mem0;
}
}
void *memmem(const void *h0, size_t k, const void *n0, size_t l)
{
const unsigned char *h = h0, *n = n0;
/* Return immediately on empty needle */
if (!l) return (void *)h;
/* Return immediately when needle is longer than haystack */
if (k<l) return 0;
/* Use faster algorithms for short needles */
h = memchr(h0, *n, k);
if (!h || l==1) return (void *)h;
k -= h - (const unsigned char *)h0;
if (k<l) return 0;
if (l==2) return twobyte_memmem(h, k, n);
if (l==3) return threebyte_memmem(h, k, n);
if (l==4) return fourbyte_memmem(h, k, n);
return twoway_memmem(h, h+k, n, l);
}
-7
View File
@@ -1,7 +0,0 @@
#define _GNU_SOURCE
#include <string.h>
void *mempcpy(void *dest, const void *src, size_t n)
{
return (char *)memcpy(dest, src, n) + n;
}
-11
View File
@@ -1,11 +0,0 @@
#include <string.h>
void *__memrchr(const void *m, int c, size_t n)
{
const unsigned char *s = m;
c = (unsigned char)c;
while (n--) if (s[n]==c) return (void *)(s+n);
return 0;
}
weak_alias(__memrchr, memrchr);
-8
View File
@@ -1,8 +0,0 @@
#define _BSD_SOURCE
#include <string.h>
#include <strings.h>
char *rindex(const char *s, int c)
{
return strrchr(s, c);
}
-29
View File
@@ -1,29 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define ALIGN (sizeof(size_t))
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
char *__stpcpy(char *restrict d, const char *restrict s)
{
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
word *wd;
const word *ws;
if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) {
for (; (uintptr_t)s % ALIGN; s++, d++)
if (!(*d=*s)) return d;
wd=(void *)d; ws=(const void *)s;
for (; !HASZERO(*ws); *wd++ = *ws++);
d=(void *)wd; s=(const void *)ws;
}
#endif
for (; (*d=*s); s++, d++);
return d;
}
weak_alias(__stpcpy, stpcpy);
-32
View File
@@ -1,32 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
char *__stpncpy(char *restrict d, const char *restrict s, size_t n)
{
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
word *wd;
const word *ws;
if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++);
if (!n || !*s) goto tail;
wd=(void *)d; ws=(const void *)s;
for (; n>=sizeof(size_t) && !HASZERO(*ws);
n-=sizeof(size_t), ws++, wd++) *wd = *ws;
d=(void *)wd; s=(const void *)ws;
}
#endif
for (; n && (*d=*s); n--, s++, d++);
tail:
memset(d, 0, n);
return d;
}
weak_alias(__stpncpy, stpncpy);
-9
View File
@@ -1,9 +0,0 @@
#define _GNU_SOURCE
#include <string.h>
char *strcasestr(const char *h, const char *n)
{
size_t l = strlen(n);
for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h;
return 0;
}
-7
View File
@@ -1,7 +0,0 @@
#include <string.h>
char *strcat(char *restrict dest, const char *restrict src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
-7
View File
@@ -1,7 +0,0 @@
#include <string.h>
char *strchr(const char *s, int c)
{
char *r = __strchrnul(s, c);
return *(unsigned char *)r == (unsigned char)c ? r : 0;
}
-28
View File
@@ -1,28 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define ALIGN (sizeof(size_t))
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
char *__strchrnul(const char *s, int c)
{
c = (unsigned char)c;
if (!c) return (char *)s + strlen(s);
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
for (; (uintptr_t)s % ALIGN; s++)
if (!*s || *(unsigned char *)s == c) return (char *)s;
size_t k = ONES * c;
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
s = (void *)w;
#endif
for (; *s && *(unsigned char *)s != c; s++);
return (char *)s;
}
weak_alias(__strchrnul, strchrnul);
-7
View File
@@ -1,7 +0,0 @@
#include <string.h>
char *strcpy(char *restrict dest, const char *restrict src)
{
__stpcpy(dest, src);
return dest;
}
-17
View File
@@ -1,17 +0,0 @@
#include <string.h>
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
size_t strcspn(const char *s, const char *c)
{
const char *a = s;
size_t byteset[32/sizeof(size_t)];
if (!c[0] || !c[1]) return __strchrnul(s, *c)-a;
memset(byteset, 0, sizeof byteset);
for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++);
for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++);
return s-a;
}
-9
View File
@@ -1,9 +0,0 @@
#define _BSD_SOURCE
#include <string.h>
size_t strlcat(char *d, const char *s, size_t n)
{
size_t l = strnlen(d, n);
if (l == n) return l + strlen(s);
return l + strlcpy(d+l, s, n-l);
}
-34
View File
@@ -1,34 +0,0 @@
#define _BSD_SOURCE
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
size_t strlcpy(char *d, const char *s, size_t n)
{
char *d0 = d;
size_t *wd;
if (!n--) goto finish;
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *ws;
if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++);
if (n && *s) {
wd=(void *)d; ws=(const void *)s;
for (; n>=sizeof(size_t) && !HASZERO(*ws);
n-=sizeof(size_t), ws++, wd++) *wd = *ws;
d=(void *)wd; s=(const void *)ws;
}
}
#endif
for (; n && (*d=*s); n--, s++, d++);
*d = 0;
finish:
return d-d0 + strlen(s);
}
-10
View File
@@ -1,10 +0,0 @@
#include <string.h>
char *strncat(char *restrict d, const char *restrict s, size_t n)
{
char *a = d;
d += strlen(d);
while (n && *s) n--, *d++ = *s++;
*d++ = 0;
return a;
}
-7
View File
@@ -1,7 +0,0 @@
#include <string.h>
char *strncpy(char *restrict d, const char *restrict s, size_t n)
{
__stpncpy(d, s, n);
return d;
}
-7
View File
@@ -1,7 +0,0 @@
#include <string.h>
size_t strnlen(const char *s, size_t n)
{
const char *p = memchr(s, 0, n);
return p ? p-s : n;
}
-7
View File
@@ -1,7 +0,0 @@
#include <string.h>
char *strpbrk(const char *s, const char *b)
{
s += strcspn(s, b);
return *s ? (char *)s : 0;
}
-6
View File
@@ -1,6 +0,0 @@
#include <string.h>
char *strrchr(const char *s, int c)
{
return __memrchr(s, c, strlen(s) + 1);
}
-13
View File
@@ -1,13 +0,0 @@
#define _GNU_SOURCE
#include <string.h>
char *strsep(char **str, const char *sep)
{
char *s = *str, *end;
if (!s) return NULL;
end = s + strcspn(s, sep);
if (*end) *end++ = 0;
else end = 0;
*str = end;
return s;
}
-20
View File
@@ -1,20 +0,0 @@
#include <string.h>
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
size_t strspn(const char *s, const char *c)
{
const char *a = s;
size_t byteset[32/sizeof(size_t)] = { 0 };
if (!c[0]) return 0;
if (!c[1]) {
for (; *s == *c; s++);
return s-a;
}
for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++);
for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++);
return s-a;
}
-154
View File
@@ -1,154 +0,0 @@
#include <string.h>
#include <stdint.h>
static char *twobyte_strstr(const unsigned char *h, const unsigned char *n)
{
uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
for (h++; *h && hw != nw; hw = hw<<8 | *++h);
return *h ? (char *)h-1 : 0;
}
static char *threebyte_strstr(const unsigned char *h, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8;
uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8;
for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8);
return *h ? (char *)h-2 : 0;
}
static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
for (h+=3; *h && hw != nw; hw = hw<<8 | *++h);
return *h ? (char *)h-3 : 0;
}
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
{
const unsigned char *z;
size_t l, ip, jp, k, p, ms, p0, mem, mem0;
size_t byteset[32 / sizeof(size_t)] = { 0 };
size_t shift[256];
/* Computing length of needle and fill shift table */
for (l=0; n[l] && h[l]; l++)
BITOP(byteset, n[l], |=), shift[n[l]] = l+1;
if (n[l]) return 0; /* hit the end of h */
/* Compute maximal suffix */
ip = -1; jp = 0; k = p = 1;
while (jp+k<l) {
if (n[ip+k] == n[jp+k]) {
if (k == p) {
jp += p;
k = 1;
} else k++;
} else if (n[ip+k] > n[jp+k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
ms = ip;
p0 = p;
/* And with the opposite comparison */
ip = -1; jp = 0; k = p = 1;
while (jp+k<l) {
if (n[ip+k] == n[jp+k]) {
if (k == p) {
jp += p;
k = 1;
} else k++;
} else if (n[ip+k] < n[jp+k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
if (ip+1 > ms+1) ms = ip;
else p = p0;
/* Periodic needle? */
if (memcmp(n, n+p, ms+1)) {
mem0 = 0;
p = MAX(ms, l-ms-1) + 1;
} else mem0 = l-p;
mem = 0;
/* Initialize incremental end-of-haystack pointer */
z = h;
/* Search loop */
for (;;) {
/* Update incremental end-of-haystack pointer */
if (z-h < l) {
/* Fast estimate for MAX(l,63) */
size_t grow = l | 63;
const unsigned char *z2 = memchr(z, 0, grow);
if (z2) {
z = z2;
if (z-h < l) return 0;
} else z += grow;
}
/* Check last byte first; advance by shift on mismatch */
if (BITOP(byteset, h[l-1], &)) {
k = l-shift[h[l-1]];
if (k) {
if (k < mem) k = mem;
h += k;
mem = 0;
continue;
}
} else {
h += l;
mem = 0;
continue;
}
/* Compare right half */
for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
if (n[k]) {
h += k-ms;
mem = 0;
continue;
}
/* Compare left half */
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
if (k <= mem) return (char *)h;
h += p;
mem = mem0;
}
}
char *strstr(const char *h, const char *n)
{
/* Return immediately on empty needle */
if (!n[0]) return (char *)h;
/* Use faster algorithms for short needles */
h = strchr(h, *n);
if (!h || !n[1]) return (char *)h;
if (!h[1]) return 0;
if (!n[2]) return twobyte_strstr((void *)h, (void *)n);
if (!h[2]) return 0;
if (!n[3]) return threebyte_strstr((void *)h, (void *)n);
if (!h[3]) return 0;
if (!n[4]) return fourbyte_strstr((void *)h, (void *)n);
return twoway_strstr((void *)h, (void *)n);
}
-13
View File
@@ -1,13 +0,0 @@
#include <string.h>
char *strtok(char *restrict s, const char *restrict sep)
{
static char *p;
if (!s && !(s = p)) return NULL;
s += strspn(s, sep);
if (!*s) return p = 0;
p = s + strcspn(s, sep);
if (*p) *p++ = 0;
else p = 0;
return s;
}
-12
View File
@@ -1,12 +0,0 @@
#include <string.h>
char *strtok_r(char *restrict s, const char *restrict sep, char **restrict p)
{
if (!s && !(s = *p)) return NULL;
s += strspn(s, sep);
if (!*s) return *p = 0;
*p = s + strcspn(s, sep);
if (**p) *(*p)++ = 0;
else *p = 0;
return s;
}
-12
View File
@@ -1,12 +0,0 @@
#include <wchar.h>
wchar_t *wcstok(wchar_t *restrict s, const wchar_t *restrict sep, wchar_t **restrict p)
{
if (!s && !(s = *p)) return NULL;
s += wcsspn(s, sep);
if (!*s) return *p = 0;
*p = s + wcscspn(s, sep);
if (**p) *(*p)++ = 0;
else *p = 0;
return s;
}
-89
View File
@@ -1,89 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#ifdef __wasm_simd128__
#include <wasm_simd128.h>
#endif
#define SS (sizeof(size_t))
#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
void *memchr(const void *src, int c, size_t n)
{
#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string)
// Skip Clang 19 and Clang 20 which have a bug (llvm/llvm-project#146574)
// which results in an ICE when inline assembly is used with a vector result.
#if __clang_major__ != 19 && __clang_major__ != 20
// When n is zero, a function that locates a character finds no occurrence.
// Otherwise, decrement n to ensure sub_overflow overflows
// when n would go equal-to-or-below zero.
if (!n--) {
return NULL;
}
// Note that reading before/after the allocation of a pointer is UB in
// C, so inline assembly is used to generate the exact machine
// instruction we want with opaque semantics to the compiler to avoid
// the UB.
uintptr_t align = (uintptr_t)src % sizeof(v128_t);
uintptr_t addr = (uintptr_t)src - align;
v128_t vc = wasm_i8x16_splat(c);
for (;;) {
v128_t v;
__asm__ (
"local.get %1\n"
"v128.load 0\n"
"local.set %0\n"
: "=r"(v)
: "r"(addr)
: "memory");
v128_t cmp = wasm_i8x16_eq(v, vc);
// Bitmask is slow on AArch64, any_true is much faster.
if (wasm_v128_any_true(cmp)) {
// Clear the bits corresponding to align (little-endian)
// so we can count trailing zeros.
int mask = wasm_i8x16_bitmask(cmp) >> align << align;
// At least one bit will be set, unless align cleared them.
// Knowing this helps the compiler if it unrolls the loop.
__builtin_assume(mask || align);
// If the mask became zero because of align,
// it's as if we didn't find anything.
if (mask) {
// Find the offset of the first one bit (little-endian).
// That's a match, unless it is beyond the end of the object.
// Recall that we decremented n, so less-than-or-equal-to is correct.
size_t ctz = __builtin_ctz(mask);
return ctz - align <= n ? (char *)src + (addr + ctz - (uintptr_t)src)
: NULL;
}
}
// Decrement n; if it overflows we're done.
if (__builtin_sub_overflow(n, sizeof(v128_t) - align, &n)) {
return NULL;
}
align = 0;
addr += sizeof(v128_t);
}
#endif
#endif
const unsigned char *s = src;
c = (unsigned char)c;
#ifdef __GNUC__
for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--);
if (n && *s != c) {
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
size_t k = ONES * c;
for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS);
s = (const void *)w;
}
#endif
for (; n && *s != c; s++, n--);
return n ? (void *)s : 0;
}
-33
View File
@@ -1,33 +0,0 @@
#include <string.h>
#ifdef __wasm_simd128__
#include <wasm_simd128.h>
#endif
void *__memrchr(const void *m, int c, size_t n)
{
#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string)
// memrchr is allowed to read up to n bytes from the object.
// Search backward for the last matching character.
const v128_t *v = (v128_t *)((char *)m + n);
const v128_t vc = wasm_i8x16_splat(c);
for (; n >= sizeof(v128_t); n -= sizeof(v128_t)) {
const v128_t cmp = wasm_i8x16_eq(wasm_v128_load(--v), vc);
// Bitmask is slow on AArch64, any_true is much faster.
if (wasm_v128_any_true(cmp)) {
// Find the offset of the last one bit (little-endian).
// The leading 16 bits of the bitmask are always zero,
// and to be ignored.
size_t clz = __builtin_clz(wasm_i8x16_bitmask(cmp)) - 16;
return (char *)(v + 1) - (clz + 1);
}
}
#endif
const unsigned char *s = m;
c = (unsigned char)c;
while (n--) if (s[n]==c) return (void *)(s+n);
return 0;
}
weak_alias(__memrchr, memrchr);
-75
View File
@@ -1,75 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <limits.h>
#ifdef __wasm_simd128__
#include <wasm_simd128.h>
#endif
#define ALIGN (sizeof(size_t))
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
char *__strchrnul(const char *s, int c)
{
c = (unsigned char)c;
if (!c) return (char *)s + strlen(s);
#if defined(__wasm_simd128__) && defined(__wasilibc_simd_string)
// Skip Clang 19 and Clang 20 which have a bug (llvm/llvm-project#146574)
// which results in an ICE when inline assembly is used with a vector result.
#if __clang_major__ != 19 && __clang_major__ != 20
// Note that reading before/after the allocation of a pointer is UB in
// C, so inline assembly is used to generate the exact machine
// instruction we want with opaque semantics to the compiler to avoid
// the UB.
uintptr_t align = (uintptr_t)s % sizeof(v128_t);
uintptr_t addr = (uintptr_t)s - align;
v128_t vc = wasm_i8x16_splat(c);
for (;;) {
v128_t v;
__asm__ (
"local.get %1\n"
"v128.load 0\n"
"local.set %0\n"
: "=r"(v)
: "r"(addr)
: "memory");
const v128_t cmp = wasm_i8x16_eq(v, (v128_t){}) | wasm_i8x16_eq(v, vc);
// Bitmask is slow on AArch64, any_true is much faster.
if (wasm_v128_any_true(cmp)) {
// Clear the bits corresponding to align (little-endian)
// so we can count trailing zeros.
int mask = wasm_i8x16_bitmask(cmp) >> align << align;
// At least one bit will be set, unless align cleared them.
// Knowing this helps the compiler if it unrolls the loop.
__builtin_assume(mask || align);
// If the mask became zero because of align,
// it's as if we didn't find anything.
if (mask) {
// Find the offset of the first one bit (little-endian).
return (char *)s + (addr - (uintptr_t)s + __builtin_ctz(mask));
}
}
align = 0;
addr += sizeof(v128_t);
}
#endif
#endif
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
for (; (uintptr_t)s % ALIGN; s++)
if (!*s || *(unsigned char *)s == c) return (char *)s;
size_t k = ONES * c;
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++);
s = (void *)w;
#endif
for (; *s && *(unsigned char *)s != c; s++);
return (char *)s;
}
weak_alias(__strchrnul, strchrnul);
-3
View File
@@ -661,7 +661,6 @@ const mingw32_generic_src = [_][]const u8{
"misc" ++ path.sep_str ++ "getlogin.c",
"misc" ++ path.sep_str ++ "getopt.c",
"misc" ++ path.sep_str ++ "gettimeofday.c",
"misc" ++ path.sep_str ++ "mempcpy.c",
"misc" ++ path.sep_str ++ "mingw-access.c",
"misc" ++ path.sep_str ++ "mingw-aligned-malloc.c",
"misc" ++ path.sep_str ++ "mingw_getsp.S",
@@ -674,7 +673,6 @@ const mingw32_generic_src = [_][]const u8{
"misc" ++ path.sep_str ++ "mingw_wcstold.c",
"misc" ++ path.sep_str ++ "mkstemp.c",
"misc" ++ path.sep_str ++ "sleep.c",
"misc" ++ path.sep_str ++ "strnlen.c",
"misc" ++ path.sep_str ++ "strsafe.c",
"misc" ++ path.sep_str ++ "tdelete.c",
"misc" ++ path.sep_str ++ "tdestroy.c",
@@ -744,7 +742,6 @@ const mingw32_generic_src = [_][]const u8{
"stdio" ++ path.sep_str ++ "mingw_vswscanf.c",
"stdio" ++ path.sep_str ++ "snprintf.c",
"stdio" ++ path.sep_str ++ "snwprintf.c",
"stdio" ++ path.sep_str ++ "strtok_r.c",
"stdio" ++ path.sep_str ++ "truncate.c",
"stdio" ++ path.sep_str ++ "ulltoa.c",
"stdio" ++ path.sep_str ++ "ulltow.c",
-35
View File
@@ -784,10 +784,8 @@ const src_files = [_][]const u8{
"musl/src/locale/newlocale.c",
"musl/src/locale/pleval.c",
"musl/src/locale/setlocale.c",
"musl/src/locale/strcoll.c",
"musl/src/locale/strfmon.c",
"musl/src/locale/strtod_l.c",
"musl/src/locale/strxfrm.c",
"musl/src/locale/textdomain.c",
"musl/src/locale/uselocale.c",
"musl/src/locale/wcscoll.c",
@@ -1129,9 +1127,6 @@ const src_files = [_][]const u8{
"musl/src/misc/a64l.c",
"musl/src/misc/basename.c",
"musl/src/misc/dirname.c",
"musl/src/misc/ffs.c",
"musl/src/misc/ffsl.c",
"musl/src/misc/ffsll.c",
"musl/src/misc/fmtmsg.c",
"musl/src/misc/forkpty.c",
"musl/src/misc/getauxval.c",
@@ -1616,39 +1611,10 @@ const src_files = [_][]const u8{
"musl/src/stdlib/strtod.c",
"musl/src/stdlib/wcstod.c",
"musl/src/stdlib/wcstol.c",
"musl/src/string/bcopy.c",
"musl/src/string/explicit_bzero.c",
"musl/src/string/index.c",
"musl/src/string/memccpy.c",
"musl/src/string/memchr.c",
"musl/src/string/memmem.c",
"musl/src/string/mempcpy.c",
"musl/src/string/memrchr.c",
"musl/src/string/rindex.c",
"musl/src/string/stpcpy.c",
"musl/src/string/stpncpy.c",
"musl/src/string/strcasestr.c",
"musl/src/string/strcat.c",
"musl/src/string/strchr.c",
"musl/src/string/strchrnul.c",
"musl/src/string/strcpy.c",
"musl/src/string/strcspn.c",
"musl/src/string/strdup.c",
"musl/src/string/strerror_r.c",
"musl/src/string/strlcat.c",
"musl/src/string/strlcpy.c",
"musl/src/string/strncat.c",
"musl/src/string/strncpy.c",
"musl/src/string/strndup.c",
"musl/src/string/strnlen.c",
"musl/src/string/strpbrk.c",
"musl/src/string/strrchr.c",
"musl/src/string/strsep.c",
"musl/src/string/strsignal.c",
"musl/src/string/strspn.c",
"musl/src/string/strstr.c",
"musl/src/string/strtok.c",
"musl/src/string/strtok_r.c",
"musl/src/string/strverscmp.c",
"musl/src/string/swab.c",
"musl/src/string/wcscasecmp.c",
@@ -1656,7 +1622,6 @@ const src_files = [_][]const u8{
"musl/src/string/wcsdup.c",
"musl/src/string/wcsncasecmp.c",
"musl/src/string/wcsncasecmp_l.c",
"musl/src/string/wcstok.c",
"musl/src/temp/mkdtemp.c",
"musl/src/temp/mkostemp.c",
"musl/src/temp/mkostemps.c",
-35
View File
@@ -680,10 +680,8 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/locale/__mo_lookup.c",
"musl/src/locale/pleval.c",
"musl/src/locale/setlocale.c",
"musl/src/locale/strcoll.c",
"musl/src/locale/strfmon.c",
"musl/src/locale/strtod_l.c",
"musl/src/locale/strxfrm.c",
"musl/src/locale/wcscoll.c",
"musl/src/locale/wcsxfrm.c",
"musl/src/math/acos.c",
@@ -847,9 +845,6 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/misc/a64l.c",
"musl/src/misc/basename.c",
"musl/src/misc/dirname.c",
"musl/src/misc/ffs.c",
"musl/src/misc/ffsl.c",
"musl/src/misc/ffsll.c",
"musl/src/misc/getdomainname.c",
"musl/src/misc/gethostid.c",
"musl/src/misc/getopt.c",
@@ -968,35 +963,9 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/stdlib/ecvt.c",
"musl/src/stdlib/fcvt.c",
"musl/src/stdlib/gcvt.c",
"musl/src/string/bcopy.c",
"musl/src/string/explicit_bzero.c",
"musl/src/string/index.c",
"musl/src/string/memccpy.c",
"musl/src/string/memmem.c",
"musl/src/string/mempcpy.c",
"musl/src/string/rindex.c",
"musl/src/string/stpcpy.c",
"musl/src/string/stpncpy.c",
"musl/src/string/strcasestr.c",
"musl/src/string/strcat.c",
"musl/src/string/strchr.c",
"musl/src/string/strcpy.c",
"musl/src/string/strcspn.c",
"musl/src/string/strdup.c",
"musl/src/string/strerror_r.c",
"musl/src/string/strlcat.c",
"musl/src/string/strlcpy.c",
"musl/src/string/strncat.c",
"musl/src/string/strncpy.c",
"musl/src/string/strndup.c",
"musl/src/string/strnlen.c",
"musl/src/string/strpbrk.c",
"musl/src/string/strrchr.c",
"musl/src/string/strsep.c",
"musl/src/string/strspn.c",
"musl/src/string/strstr.c",
"musl/src/string/strtok.c",
"musl/src/string/strtok_r.c",
"musl/src/string/strverscmp.c",
"musl/src/string/swab.c",
"musl/src/string/wcscasecmp.c",
@@ -1004,7 +973,6 @@ const libc_top_half_src_files = [_][]const u8{
"musl/src/string/wcsdup.c",
"musl/src/string/wcsncasecmp.c",
"musl/src/string/wcsncasecmp_l.c",
"musl/src/string/wcstok.c",
"musl/src/thread/default_attr.c",
"musl/src/thread/pthread_attr_destroy.c",
"musl/src/thread/pthread_attr_init.c",
@@ -1132,9 +1100,6 @@ const libc_top_half_src_files = [_][]const u8{
"wasi/libc-top-half/musl/src/stdlib/strtod.c",
"wasi/libc-top-half/musl/src/stdlib/wcstod.c",
"wasi/libc-top-half/musl/src/stdlib/wcstol.c",
"wasi/libc-top-half/musl/src/string/memchr.c",
"wasi/libc-top-half/musl/src/string/memrchr.c",
"wasi/libc-top-half/musl/src/string/strchrnul.c",
"wasi/libc-top-half/musl/src/thread/pthread_attr_get.c",
"wasi/libc-top-half/musl/src/thread/pthread_attr_setguardsize.c",
"wasi/libc-top-half/musl/src/thread/pthread_attr_setschedparam.c",