1const builtin = @import("builtin");
2
3const std = @import("std");
4const wint_t = std.c.wint_t;
5const wchar_t = std.c.wchar_t;
6
7const symbol = @import("../c.zig").symbol;
8const c = std.c;
9
10comptime {
11 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
12 symbol(&wmemchr, "wmemchr");
13 symbol(&wmemcmp, "wmemcmp");
14 symbol(&wmemcpy, "wmemcpy");
15 symbol(&wmemmove, "wmemmove");
16 symbol(&wmemset, "wmemset");
17 symbol(&wcslen, "wcslen");
18 symbol(&wcsnlen, "wcsnlen");
19 symbol(&wcscmp, "wcscmp");
20 symbol(&wcsncmp, "wcsncmp");
21 symbol(&wcpcpy, "wcpcpy");
22 symbol(&wcpncpy, "wcpncpy");
23 symbol(&wcscpy, "wcscpy");
24 symbol(&wcsncpy, "wcsncpy");
25 symbol(&wcscat, "wcscat");
26 symbol(&wcsncat, "wcsncat");
27 symbol(&wcschr, "wcschr");
28 symbol(&wcsrchr, "wcsrchr");
29 symbol(&wcsspn, "wcsspn");
30 symbol(&wcscspn, "wcscspn");
31 symbol(&wcspbrk, "wcspbrk");
32 symbol(&wcstok, "wcstok");
33 symbol(&wcsstr, "wcsstr");
34 symbol(&wcsdup, "wcsdup");
35 symbol(&wcswcs, "wcswcs");
36 }
37
38 if (builtin.target.isMinGW()) {
39 symbol(&wmemchr, "wmemchr");
40 symbol(&wmemcmp, "wmemcmp");
41 symbol(&wmemcpy, "wmemcpy");
42 symbol(&wmempcpy, "wmempcpy");
43 symbol(&wmemmove, "wmemmove");
44 symbol(&wmemset, "wmemset");
45 symbol(&wcsnlen, "wcsnlen");
46 }
47}
48
49fn wmemchr(ptr: [*]const wchar_t, value: wchar_t, len: usize) callconv(.c) ?[*]wchar_t {
50 return @constCast(ptr[std.mem.findScalar(wchar_t, ptr[0..len], value) orelse return null ..]);
51}
52
53fn wmemcmp(a: [*]const wchar_t, b: [*]const wchar_t, len: usize) callconv(.c) c_int {
54 return switch (std.mem.order(wchar_t, a[0..len], b[0..len])) {
55 .eq => 0,
56 .gt => 1,
57 .lt => -1,
58 };
59}
60
61fn wmemcpy(noalias dest: [*]wchar_t, noalias src: [*]const wchar_t, len: usize) callconv(.c) [*]wchar_t {
62 @memcpy(dest[0..len], src[0..len]);
63 return dest;
64}
65
66fn wmempcpy(noalias dest: [*]wchar_t, noalias src: [*]const wchar_t, len: usize) callconv(.c) [*]wchar_t {
67 @memcpy(dest[0..len], src[0..len]);
68 return dest + len;
69}
70
71fn wmemmove(dest: [*]wchar_t, src: [*]const wchar_t, len: usize) callconv(.c) [*]wchar_t {
72 @memmove(dest[0..len], src[0..len]);
73 return dest;
74}
75
76fn wmemset(dest: [*]wchar_t, elem: wchar_t, len: usize) callconv(.c) [*]wchar_t {
77 @memset(dest[0..len], elem);
78 return dest;
79}
80
81fn wcslen(str: [*:0]const wchar_t) callconv(.c) usize {
82 return wcsnlen(str, std.math.maxInt(usize));
83}
84
85fn wcsnlen(str: [*:0]const wchar_t, max: usize) callconv(.c) usize {
86 return std.mem.findScalar(wchar_t, str[0..max], 0) orelse max;
87}
88
89fn wcscmp(a: [*:0]const wchar_t, b: [*:0]const wchar_t) callconv(.c) c_int {
90 return wcsncmp(a, b, std.math.maxInt(usize));
91}
92
93fn wcsncmp(a: [*:0]const wchar_t, b: [*:0]const wchar_t, max: usize) callconv(.c) c_int {
94 return switch (std.mem.boundedOrderZ(wchar_t, a, b, max)) {
95 .eq => 0,
96 .gt => 1,
97 .lt => -1,
98 };
99}
100
101fn wcpcpy(noalias dst: [*]wchar_t, noalias src: [*:0]const wchar_t) callconv(.c) [*]wchar_t {
102 const src_len = std.mem.len(src);
103 @memcpy(dst[0 .. src_len + 1], src[0 .. src_len + 1]);
104 return dst + src_len;
105}
106
107fn wcpncpy(noalias dst: [*]wchar_t, noalias src: [*:0]const wchar_t, max: usize) callconv(.c) [*]wchar_t {
108 const src_len = wcsnlen(src, max);
109 const copying_len = @min(max, src_len);
110 @memcpy(dst[0..copying_len], src[0..copying_len]);
111 @memset(dst[copying_len..][0 .. max - copying_len], 0x00);
112 return dst + copying_len;
113}
114
115fn wcscpy(noalias dst: [*]wchar_t, noalias src: [*:0]const wchar_t) callconv(.c) [*]wchar_t {
116 _ = wcpcpy(dst, src);
117 return dst;
118}
119
120fn wcsncpy(noalias dst: [*]wchar_t, noalias src: [*:0]const wchar_t, max: usize) callconv(.c) [*]wchar_t {
121 _ = wcpncpy(dst, src, max);
122 return dst;
123}
124
125fn wcscat(noalias dst: [*:0]wchar_t, noalias src: [*:0]const wchar_t) callconv(.c) [*:0]wchar_t {
126 return wcsncat(dst, src, std.math.maxInt(usize));
127}
128
129fn wcsncat(noalias dst: [*:0]wchar_t, noalias src: [*:0]const wchar_t, max: usize) callconv(.c) [*:0]wchar_t {
130 const dst_len = std.mem.len(dst);
131 const src_len = std.mem.len(src);
132 const copying_len = @min(max, src_len);
133
134 @memcpy(dst[dst_len..][0..copying_len], src[0..copying_len]);
135 dst[dst_len + copying_len] = 0;
136 return dst[0..(dst_len + copying_len) :0].ptr;
137}
138
139fn wcschr(str: [*:0]const wchar_t, value: wchar_t) callconv(.c) ?[*:0]wchar_t {
140 const len = std.mem.len(str);
141
142 if (value == 0) return @constCast(str + len);
143 return @constCast(str[std.mem.findScalar(wchar_t, str[0..len], value) orelse return null ..]);
144}
145
146fn wcsrchr(str: [*:0]const wchar_t, value: wchar_t) callconv(.c) ?[*:0]wchar_t {
147 // std.mem.len(str) + 1 to not special case '\0'
148 return @constCast(str[std.mem.findScalarLast(wchar_t, str[0..(std.mem.len(str) + 1)], value) orelse return null ..]);
149}
150
151fn wcsspn(dst: [*:0]const wchar_t, values: [*:0]const wchar_t) callconv(.c) usize {
152 const dst_slice = std.mem.span(dst);
153 return std.mem.findNone(wchar_t, dst_slice, std.mem.span(values)) orelse dst_slice.len;
154}
155
156fn wcscspn(dst: [*:0]const wchar_t, values: [*:0]const wchar_t) callconv(.c) usize {
157 const dst_slice = std.mem.span(dst);
158 return std.mem.findAny(wchar_t, dst_slice, std.mem.span(values)) orelse dst_slice.len;
159}
160
161fn wcspbrk(haystack: [*:0]const wchar_t, needle: [*:0]const wchar_t) callconv(.c) ?[*:0]wchar_t {
162 return @constCast(haystack[std.mem.findAny(wchar_t, std.mem.span(haystack), std.mem.span(needle)) orelse return null ..]);
163}
164
165fn wcstok(noalias maybe_str: ?[*:0]wchar_t, noalias values: [*:0]const wchar_t, noalias state: *?[*:0]wchar_t) callconv(.c) ?[*:0]wchar_t {
166 const str = if (maybe_str) |str|
167 str
168 else if (state.*) |state_str|
169 state_str
170 else
171 return null;
172
173 const str_chars = std.mem.span(str);
174 const values_chars = std.mem.span(values);
175 const tok_start = std.mem.findNone(wchar_t, str_chars, values_chars) orelse return null;
176
177 if (std.mem.findAnyPos(wchar_t, str_chars, tok_start, values_chars)) |tok_end| {
178 str[tok_end] = 0;
179 state.* = str[tok_end + 1 ..];
180 } else {
181 state.* = str[str_chars.len..];
182 }
183
184 return str[tok_start..];
185}
186
187fn wcsstr(noalias haystack: [*:0]const wchar_t, noalias needle: [*:0]const wchar_t) callconv(.c) ?[*:0]wchar_t {
188 return @constCast(haystack[std.mem.find(wchar_t, std.mem.span(haystack), std.mem.span(needle)) orelse return null ..]);
189}
190
191fn wcswcs(noalias haystack: [*:0]const wchar_t, noalias needle: [*:0]const wchar_t) callconv(.c) ?[*:0]wchar_t {
192 return wcsstr(haystack, needle);
193}
194
195fn wcsdup(str: [*:0]const wchar_t) callconv(.c) ?[*:0]wchar_t {
196 const len = wcslen(str);
197 const size = (len + 1) * @sizeOf(wchar_t);
198 const d_opaque = c.malloc(size) orelse return null;
199 const d: [*]wchar_t = @ptrCast(@alignCast(d_opaque));
200 return @ptrCast(wmemcpy(d, str, len + 1));
201}