mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
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:
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Vendored
-12
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
-11
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
-98
@@ -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 */
|
||||
}
|
||||
Vendored
-8
@@ -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
@@ -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");
|
||||
}
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
#define _BSD_SOURCE
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
char *index(const char *s, int c)
|
||||
{
|
||||
return strchr(s, c);
|
||||
}
|
||||
Vendored
-34
@@ -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;
|
||||
}
|
||||
Vendored
-27
@@ -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;
|
||||
}
|
||||
Vendored
-149
@@ -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);
|
||||
}
|
||||
Vendored
-7
@@ -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;
|
||||
}
|
||||
Vendored
-11
@@ -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);
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
#define _BSD_SOURCE
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
char *rindex(const char *s, int c)
|
||||
{
|
||||
return strrchr(s, c);
|
||||
}
|
||||
Vendored
-29
@@ -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);
|
||||
Vendored
-32
@@ -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
@@ -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;
|
||||
}
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strcat(char *restrict dest, const char *restrict src)
|
||||
{
|
||||
strcpy(dest + strlen(dest), src);
|
||||
return dest;
|
||||
}
|
||||
Vendored
-7
@@ -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;
|
||||
}
|
||||
Vendored
-28
@@ -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);
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strcpy(char *restrict dest, const char *restrict src)
|
||||
{
|
||||
__stpcpy(dest, src);
|
||||
return dest;
|
||||
}
|
||||
Vendored
-17
@@ -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;
|
||||
}
|
||||
Vendored
-9
@@ -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);
|
||||
}
|
||||
Vendored
-34
@@ -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);
|
||||
}
|
||||
Vendored
-10
@@ -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;
|
||||
}
|
||||
Vendored
-7
@@ -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;
|
||||
}
|
||||
Vendored
-7
@@ -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;
|
||||
}
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strpbrk(const char *s, const char *b)
|
||||
{
|
||||
s += strcspn(s, b);
|
||||
return *s ? (char *)s : 0;
|
||||
}
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strrchr(const char *s, int c)
|
||||
{
|
||||
return __memrchr(s, c, strlen(s) + 1);
|
||||
}
|
||||
Vendored
-13
@@ -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;
|
||||
}
|
||||
Vendored
-20
@@ -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;
|
||||
}
|
||||
Vendored
-154
@@ -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);
|
||||
}
|
||||
Vendored
-13
@@ -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;
|
||||
}
|
||||
Vendored
-12
@@ -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;
|
||||
}
|
||||
Vendored
-12
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user