authorgravatar for me@gasinfinity.devGasInfinity <me@gasinfinity.dev> 2026-01-17 20:21:42+01:00
committergravatar for me@gasinfinity.devGasInfinity <me@gasinfinity.dev> 2026-01-17 21:42:40+01:00
log06d05decaecb1dc5ad070b01c358f76e33095f71
treec8417bd03100bb00955cf1827e146a6db8d18f8c
parent3d8b0e33241809cbca05d762458eec73b6b336ae
signaturebadge-check Signed by SSH key SHA256:p3IHbr0lyK2ekfDC1Zi7dOEV/9T6lGghNawhl5sBnM4

feat(libzigc): add `wcstok` and reuse more `std.mem` code

* also makes `wcpncpy`/`wcsncpy` pad the buffer with zeroes as required by the standard

1 files changed, 31 insertions(+), 26 deletions(-)

lib/c/wchar.zig+31-26
......@@ -26,6 +26,7 @@ comptime {
2626 @export(&wcsspn, .{ .name = "wcsspn", .linkage = common.linkage, .visibility = common.visibility });
2727 @export(&wcscspn, .{ .name = "wcscspn", .linkage = common.linkage, .visibility = common.visibility });
2828 @export(&wcspbrk, .{ .name = "wcspbrk", .linkage = common.linkage, .visibility = common.visibility });
29 @export(&wcstok, .{ .name = "wcstok", .linkage = common.linkage, .visibility = common.visibility });
2930 @export(&wcsstr, .{ .name = "wcsstr", .linkage = common.linkage, .visibility = common.visibility });
3031 @export(&wcswcs, .{ .name = "wcswcs", .linkage = common.linkage, .visibility = common.visibility });
3132 }
......@@ -46,10 +47,8 @@ fn wmemchr(ptr: [*]const wchar_t, value: wchar_t, len: usize) callconv(.c) ?[*]w
4647}
4748
4849fn wmemcmp(a: [*]const wchar_t, b: [*]const wchar_t, len: usize) callconv(.c) c_int {
49 const idx = std.mem.findDiff(wchar_t, a[0..len], b[0..len]) orelse return 0;
50
51 return switch (std.math.order(a[idx], b[idx])) {
52 .eq => unreachable,
50 return switch (std.mem.order(wchar_t, a[0..len], b[0..len])) {
51 .eq => 0,
5352 .gt => 1,
5453 .lt => -1,
5554 };
......@@ -88,40 +87,24 @@ fn wcscmp(a: [*:0]const wchar_t, b: [*:0]const wchar_t) callconv(.c) c_int {
8887}
8988
9089fn wcsncmp(a: [*:0]const wchar_t, b: [*:0]const wchar_t, max: usize) callconv(.c) c_int {
91 const a_slice = a[0..wcsnlen(a, max)];
92 const b_slice = b[0..wcsnlen(b, max)];
93
94 return switch (std.math.order(a_slice.len, b_slice.len)) {
95 .eq => blk: {
96 const idx = std.mem.findDiff(wchar_t, a_slice, b_slice) orelse break :blk 0;
97
98 break :blk switch (std.math.order(a[idx], b[idx])) {
99 .eq => unreachable,
100 .gt => 1,
101 .lt => -1,
102 };
103 },
90 return switch (std.mem.boundedOrderZ(wchar_t, a, b, max)) {
91 .eq => 0,
10492 .gt => 1,
10593 .lt => -1,
10694 };
10795}
10896
10997fn wcpcpy(noalias dst: [*]wchar_t, noalias src: [*:0]const wchar_t) callconv(.c) [*]wchar_t {
110 const src_slice = std.mem.span(src);
111 @memcpy(dst[0..src_slice.len], src_slice);
112 dst[src_slice.len] = 0;
113 return dst + src_slice.len;
114 // XXX: LLVM bug?
115 // return wcpncpy(dst, src, std.math.maxInt(usize));
98 const src_len = std.mem.len(src);
99 @memcpy(dst[0 .. src_len + 1], src[0 .. src_len + 1]);
100 return dst + src_len;
116101}
117102
118103fn wcpncpy(noalias dst: [*]wchar_t, noalias src: [*:0]const wchar_t, max: usize) callconv(.c) [*]wchar_t {
119104 const src_len = wcsnlen(src, max);
120105 const copying_len = @min(max, src_len);
121
122106 @memcpy(dst[0..copying_len], src[0..copying_len]);
123
124 if (copying_len < max) dst[copying_len] = 0;
107 @memset(dst[copying_len..][0 .. max - copying_len], 0x00);
125108 return dst + copying_len;
126109}
127110
......@@ -175,6 +158,28 @@ fn wcspbrk(haystack: [*:0]const wchar_t, needle: [*:0]const wchar_t) callconv(.c
175158 return @constCast(haystack[std.mem.findAny(wchar_t, std.mem.span(haystack), std.mem.span(needle)) orelse return null ..]);
176159}
177160
161fn wcstok(noalias maybe_str: ?[*:0]wchar_t, noalias values: [*:0]const wchar_t, noalias state: *?[*:0]wchar_t) callconv(.c) ?[*:0]wchar_t {
162 const str = if (maybe_str) |str|
163 str
164 else if (state.*) |state_str|
165 state_str
166 else
167 return null;
168
169 const str_chars = std.mem.span(str);
170 const values_chars = std.mem.span(values);
171 const tok_start = std.mem.findNone(wchar_t, str_chars, values_chars) orelse return null;
172
173 if (std.mem.findAnyPos(wchar_t, str_chars, tok_start, values_chars)) |tok_end| {
174 str[tok_end] = 0;
175 state.* = str[tok_end + 1 ..];
176 } else {
177 state.* = str[str_chars.len..];
178 }
179
180 return str[tok_start..];
181}
182
178183fn wcsstr(noalias haystack: [*:0]const wchar_t, noalias needle: [*:0]const wchar_t) callconv(.c) ?[*:0]wchar_t {
179184 return @constCast(haystack[std.mem.find(wchar_t, std.mem.span(haystack), std.mem.span(needle)) orelse return null ..]);
180185}