mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 06:04:46 +01:00
- use symbol export helper - move all declarations from common.zig into c.zig - correct documentation - delete dead code
299 lines
12 KiB
Zig
299 lines
12 KiB
Zig
const builtin = @import("builtin");
|
|
const std = @import("std");
|
|
const symbol = @import("../c.zig").symbol;
|
|
|
|
comptime {
|
|
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
|
|
symbol(&memchr, "memchr");
|
|
symbol(&strcpy, "strcpy");
|
|
symbol(&strncpy, "strncpy");
|
|
symbol(&strcat, "strcat");
|
|
symbol(&strncat, "strncat");
|
|
symbol(&strcmp, "strcmp");
|
|
symbol(&strncmp, "strncmp");
|
|
symbol(&strcoll, "strcoll");
|
|
symbol(&strxfrm, "strxfrm");
|
|
symbol(&strchr, "strchr");
|
|
symbol(&strrchr, "strrchr");
|
|
symbol(&strcspn, "strcspn");
|
|
symbol(&strspn, "strspn");
|
|
symbol(&strpbrk, "strpbrk");
|
|
symbol(&strstr, "strstr");
|
|
symbol(&strtok, "strtok");
|
|
// strlen is in compiler_rt
|
|
|
|
symbol(&strtok_r, "strtok_r");
|
|
symbol(&stpcpy, "stpcpy");
|
|
symbol(&stpncpy, "stpncpy");
|
|
symbol(&strnlen, "strnlen");
|
|
symbol(&memmem, "memmem");
|
|
|
|
symbol(&memccpy, "memccpy");
|
|
|
|
symbol(&strsep, "strsep");
|
|
symbol(&strlcat, "strlcat");
|
|
symbol(&strlcpy, "strlcpy");
|
|
symbol(&explicit_bzero, "explicit_bzero");
|
|
|
|
symbol(&strchrnul, "strchrnul");
|
|
symbol(&strcasestr, "strcasestr");
|
|
symbol(&memrchr, "memrchr");
|
|
symbol(&mempcpy, "mempcpy");
|
|
|
|
symbol(&__strcoll_l, "__strcoll_l");
|
|
symbol(&__strxfrm_l, "__strxfrm_l");
|
|
symbol(&__strcoll_l, "strcoll_l");
|
|
symbol(&__strxfrm_l, "strxfrm_l");
|
|
|
|
// These symbols are not in the public ABI of musl/wasi. However they depend on these exports internally.
|
|
symbol(&stpcpy, "__stpcpy");
|
|
symbol(&stpncpy, "__stpncpy");
|
|
symbol(&strchrnul, "__strchrnul");
|
|
symbol(&memrchr, "__memrchr");
|
|
}
|
|
|
|
if (builtin.target.isMinGW()) {
|
|
symbol(&strnlen, "strnlen");
|
|
symbol(&mempcpy, "mempcpy");
|
|
symbol(&strtok_r, "strtok_r");
|
|
}
|
|
}
|
|
|
|
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 strcoll(a: [*:0]const c_char, b: [*:0]const c_char) callconv(.c) c_int {
|
|
return strcmp(a, b);
|
|
}
|
|
|
|
fn __strcoll_l(a: [*:0]const c_char, b: [*:0]const c_char, locale: *anyopaque) callconv(.c) c_int {
|
|
_ = locale;
|
|
return strcoll(a, b);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
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 str[tok_start..];
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 {
|
|
try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
|
|
try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
|
|
try std.testing.expect(strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
|
|
try std.testing.expect(strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
|
|
}
|