1use core::{iter::once, mem, ptr, slice};
6
7use cbitset::BitSet256;
8
9use crate::{
10 header::{
11 errno::{ENOMEM, ERANGE, STR_ERROR, STRERROR_MAX},
12 signal,
13 },
14 iter::{NulTerminated, NulTerminatedInclusive, SrcDstPtrIter},
15 platform::{
16 self,
17 types::{c_char, c_int, c_void, size_t},
18 },
19 raw_cell::RawCell,
20};
21
22use super::{bits_locale_t::locale_t, locale::THREAD_LOCALE};
23
24#[unsafe(no_mangle)]
31pub unsafe extern "C" fn memccpy(
32 s1: *mut c_void,
33 s2: *const c_void,
34 c: c_int,
35 n: size_t,
36) -> *mut c_void {
37 let to = unsafe { memchr(s2, c, n) };
38 let dist = if to.is_null() {
39 n
40 } else {
41 ((to as usize) - (s2 as usize)) + 1
42 };
43 unsafe { memcpy(s1, s2, dist) };
44 if to.is_null() {
45 ptr::null_mut()
46 } else {
47 unsafe { s1.cast::<u8>().add(dist).cast::<c_void>() }
48 }
49}
50
51#[unsafe(no_mangle)]
53pub unsafe extern "C" fn memchr(
54 haystack: *const c_void,
55 needle: c_int,
56 len: size_t,
57) -> *mut c_void {
58 let haystack = unsafe { slice::from_raw_parts(haystack.cast::<u8>(), len) };
59
60 match memchr::memchr(needle as u8, haystack) {
61 Some(index) => haystack[index..].as_ptr() as *mut c_void,
62 None => ptr::null_mut(),
63 }
64}
65
66#[unsafe(no_mangle)]
68pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: size_t) -> c_int {
69 let (div, rem) = (n / mem::size_of::<size_t>(), n % mem::size_of::<size_t>());
70 let mut a = s1.cast::<usize>();
71 let mut b = s2.cast::<usize>();
72 for _ in 0..div {
73 if unsafe { a.read_unaligned() } != unsafe { b.read_unaligned() } {
76 for i in 0..mem::size_of::<usize>() {
77 let c = unsafe { *(a.cast::<u8>()).add(i) };
78 let d = unsafe { *(b.cast::<u8>()).add(i) };
79 if c != d {
80 return c_int::from(c) - c_int::from(d);
81 }
82 }
83 unreachable!()
84 }
85 a = unsafe { a.offset(1) };
86 b = unsafe { b.offset(1) };
87 }
88
89 let mut a = a.cast::<u8>();
90 let mut b = b.cast::<u8>();
91 for _ in 0..rem {
92 if unsafe { *a } != unsafe { *b } {
93 return c_int::from(unsafe { *a }) - c_int::from(unsafe { *b });
94 }
95 a = unsafe { a.offset(1) };
96 b = unsafe { b.offset(1) };
97 }
98 0
99}
100
101#[unsafe(no_mangle)]
110pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void {
111 for i in 0..n {
112 unsafe { *s1.cast::<u8>().add(i) = *s2.cast::<u8>().add(i) };
113 }
114 s1
115}
116
117#[unsafe(no_mangle)]
124pub unsafe extern "C" fn memmem(
125 haystack: *const c_void,
126 haystacklen: size_t,
127 needle: *const c_void,
128 needlelen: size_t,
129) -> *mut c_void {
130 match needlelen {
131 0 => haystack,
133 _ => {
134 let haystack_slice =
137 unsafe { slice::from_raw_parts(haystack.cast::<u8>(), haystacklen) };
138 let needle_slice = unsafe { slice::from_raw_parts(needle.cast::<u8>(), needlelen) };
139
140 match haystack_slice
143 .windows(needlelen)
144 .find(|&haystack_window| haystack_window == needle_slice)
145 {
146 Some(match_slice) => match_slice.as_ptr().cast(),
147 None => ptr::null(),
148 }
149 }
150 }
151 .cast_mut()
152}
153
154#[unsafe(no_mangle)]
156pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void {
157 if s2 < s1.cast_const() {
158 let mut i = n;
160 while i != 0 {
161 i -= 1;
162 unsafe { *s1.cast::<u8>().add(i) = *s2.cast::<u8>().add(i) };
163 }
164 } else {
165 let mut i = 0;
167 while i < n {
168 unsafe { *s1.cast::<u8>().add(i) = *s2.cast::<u8>().add(i) };
169 i += 1;
170 }
171 }
172 s1
173}
174
175#[unsafe(no_mangle)]
177pub unsafe extern "C" fn memrchr(
178 haystack: *const c_void,
179 needle: c_int,
180 len: size_t,
181) -> *mut c_void {
182 let haystack = unsafe { slice::from_raw_parts(haystack.cast::<u8>(), len) };
183
184 match memchr::memrchr(needle as u8, haystack) {
185 Some(index) => haystack[index..].as_ptr() as *mut c_void,
186 None => ptr::null_mut(),
187 }
188}
189
190#[unsafe(no_mangle)]
200pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_void {
201 for i in 0..n {
202 unsafe { *s.cast::<u8>().add(i) = c as u8 };
203 }
204 s
205}
206
207#[unsafe(no_mangle)]
209pub unsafe extern "C" fn stpcpy(mut s1: *mut c_char, mut s2: *const c_char) -> *mut c_char {
210 loop {
211 unsafe { *s1 = *s2 };
212
213 if unsafe { *s1 } == 0 {
214 break;
215 }
216
217 s1 = unsafe { s1.add(1) };
218 s2 = unsafe { s2.add(1) };
219 }
220
221 s1
222}
223
224#[unsafe(no_mangle)]
241pub unsafe extern "C" fn stpncpy(
242 mut s1: *mut c_char,
243 mut s2: *const c_char,
244 mut n: size_t,
245) -> *mut c_char {
246 while n > 0 {
247 unsafe { *s1 = *s2 };
248
249 if unsafe { *s1 } == 0 {
250 break;
251 }
252
253 n -= 1;
254 s1 = unsafe { s1.add(1) };
255 s2 = unsafe { s2.add(1) };
256 }
257
258 unsafe { memset(s1.cast(), 0, n) };
259
260 s1
261}
262
263#[unsafe(no_mangle)]
265pub unsafe extern "C" fn strcasestr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
266 unsafe { inner_strstr(haystack, needle, !32) }
267}
268
269#[unsafe(no_mangle)]
271pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
272 unsafe { strncat(s1, s2, usize::MAX) }
273}
274
275#[unsafe(no_mangle)]
282pub unsafe extern "C" fn strchr(s: *const c_char, c: c_int) -> *mut c_char {
283 let c_as_c_char = c as c_char;
284
285 let ptr: *const c_char =
290 match unsafe { NulTerminatedInclusive::new(s) }.find(|&&sc| sc == c_as_c_char) {
291 Some(sc_ref) => sc_ref,
292 None => ptr::null(),
293 };
294 ptr.cast_mut()
295}
296
297#[unsafe(no_mangle)]
299pub unsafe extern "C" fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char {
300 let mut s = s.cast_mut();
301 loop {
302 if unsafe { *s } == c as _ {
303 break;
304 }
305 if unsafe { *s } == 0 {
306 break;
307 }
308 s = unsafe { s.add(1) };
309 }
310 s
311}
312
313#[unsafe(no_mangle)]
315pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
316 unsafe { strncmp(s1, s2, usize::MAX) }
317}
318
319#[unsafe(no_mangle)]
321pub unsafe extern "C" fn strcoll_l(s1: *const c_char, s2: *const c_char, _loc: locale_t) -> c_int {
322 unsafe { strcmp(s1, s2) }
324}
325
326#[unsafe(no_mangle)]
328pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
329 unsafe { strcoll_l(s1, s2, THREAD_LOCALE as locale_t) }
330}
331
332#[unsafe(no_mangle)]
334pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
335 let src_iter = unsafe { NulTerminated::new(src).unwrap() };
336 let src_dest_iter = unsafe { SrcDstPtrIter::new(src_iter.chain(once(&0)), dst) };
337 for (src_item, dst_item) in src_dest_iter {
338 dst_item.write(*src_item);
339 }
340
341 dst
342}
343
344pub unsafe fn inner_strspn(s1: *const c_char, s2: *const c_char, cmp: bool) -> size_t {
345 let mut s1 = s1.cast::<u8>();
346 let mut s2 = s2.cast::<u8>();
347
348 let mut set = BitSet256::new();
354
355 while unsafe { *s2 } != 0 {
356 set.insert(unsafe { *s2 } as usize);
357 s2 = unsafe { s2.offset(1) };
358 }
359
360 let mut i = 0;
361 while unsafe { *s1 } != 0 {
362 if set.contains(unsafe { *s1 } as usize) != cmp {
363 break;
364 }
365 i += 1;
366 s1 = unsafe { s1.offset(1) };
367 }
368 i
369}
370
371#[unsafe(no_mangle)]
373pub unsafe extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> size_t {
374 unsafe { inner_strspn(s1, s2, false) }
375}
376
377#[unsafe(no_mangle)]
379pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
380 unsafe { strndup(s1, usize::MAX) }
381}
382
383#[unsafe(no_mangle)]
385pub unsafe extern "C" fn strerror_l(errnum: c_int, _loc: locale_t) -> *mut c_char {
386 use core::fmt::Write;
387
388 static STRERROR_BUF: RawCell<[c_char; STRERROR_MAX]> = RawCell::new([0; STRERROR_MAX]);
389 let strerror_ptr = unsafe { STRERROR_BUF.unsafe_mut().as_mut_ptr() };
390 let mut w = platform::StringWriter(strerror_ptr, STRERROR_MAX);
391
392 let _ = match STR_ERROR.get(errnum as usize) {
393 Some(e) => w.write_str(e),
394 None => w.write_fmt(format_args!("Unknown error {}", errnum)),
395 };
396
397 strerror_ptr
398}
399
400#[unsafe(no_mangle)]
402pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
403 unsafe { strerror_l(errnum, THREAD_LOCALE as locale_t) }
404}
405
406#[unsafe(no_mangle)]
408pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
409 let msg = unsafe { strerror(errnum) };
410 let len = unsafe { strlen(msg) };
411
412 if len >= buflen {
413 if buflen != 0 {
414 unsafe { memcpy(buf.cast::<c_void>(), msg as *const c_void, buflen - 1) };
415 unsafe { *buf.add(buflen - 1) = 0 };
416 }
417 return ERANGE as c_int;
418 }
419 unsafe { memcpy(buf.cast::<c_void>(), msg as *const c_void, len + 1) };
420
421 0
422}
423
424#[unsafe(no_mangle)]
426pub unsafe extern "C" fn strlcat(dst: *mut c_char, src: *const c_char, dstsize: size_t) -> size_t {
427 let dst_len = unsafe { strnlen(dst, dstsize) };
428 let d = unsafe { dst.add(dst_len) };
429 let src_len = unsafe { strlcpy(d, src, dstsize - dst_len) };
430 src_len + if dst_len > dstsize { dstsize } else { dst_len }
431}
432
433#[unsafe(no_mangle)]
435pub unsafe extern "C" fn strsep(str_: *mut *mut c_char, sep: *const c_char) -> *mut c_char {
436 let s = unsafe { *str_ };
437 if s.is_null() {
438 return ptr::null_mut();
439 }
440 let mut end = unsafe { s.add(strcspn(s, sep)) };
441 if unsafe { *end } != 0 {
442 unsafe { *end = 0 };
443 end = unsafe { end.add(1) };
444 } else {
445 end = ptr::null_mut();
446 }
447 unsafe { *str_ = end };
448 s
449}
450
451#[unsafe(no_mangle)]
453pub unsafe extern "C" fn strlcpy(dst: *mut c_char, src: *const c_char, dstsize: size_t) -> size_t {
454 let mut i = 0;
455
456 if dstsize != 0 {
457 while unsafe { *src.add(i) } != 0 && i < dstsize - 1 {
458 unsafe {
459 *dst.add(i) = *src.add(i);
460 }
461 i += 1;
462 }
463 unsafe {
464 *dst.add(i) = 0;
465 }
466 }
467
468 while unsafe { *src.add(i) } != 0 {
469 i += 1;
470 }
471
472 i as size_t
473}
474
475#[unsafe(no_mangle)]
482pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
483 unsafe { NulTerminated::new(s) }
484 .map(|s| s.count())
485 .unwrap_or(0)
486}
487
488#[unsafe(no_mangle)]
490pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char {
491 let len = unsafe { strlen(s1.cast()) };
492 let mut i = 0;
493 while i < n {
494 let b = unsafe { *s2.add(i) };
495 if b == 0 {
496 break;
497 }
498
499 unsafe { *s1.add(len + i) = b };
500 i += 1;
501 }
502 unsafe { *s1.add(len + i) = 0 };
503
504 s1
505}
506
507#[unsafe(no_mangle)]
509pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int {
510 for i in 0..n {
511 let a = unsafe { *s1.add(i) } as u8;
513 let b = unsafe { *s2.add(i) } as u8;
514 if a != b || a == 0 {
515 return c_int::from(a) - c_int::from(b);
516 }
517 }
518
519 0
520}
521
522#[unsafe(no_mangle)]
540pub unsafe extern "C" fn strncpy(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char {
541 unsafe { stpncpy(s1, s2, n) };
542 s1
543}
544
545#[unsafe(no_mangle)]
547pub unsafe extern "C" fn strndup(s1: *const c_char, size: size_t) -> *mut c_char {
548 let len = unsafe { strnlen(s1, size) };
549
550 let buffer = unsafe { platform::alloc(len + 1) }.cast::<c_char>();
552 if buffer.is_null() {
553 platform::ERRNO.set(ENOMEM as c_int);
554 } else {
555 for i in 0..len {
557 unsafe { *buffer.add(i) = *s1.add(i) };
558 }
559 unsafe { *buffer.add(len) = 0 };
560 }
561
562 buffer
563}
564
565#[unsafe(no_mangle)]
567pub unsafe extern "C" fn strnlen(s: *const c_char, size: size_t) -> size_t {
568 unsafe { NulTerminated::new(s).unwrap() }.take(size).count()
569}
570
571#[unsafe(no_mangle)]
573pub unsafe extern "C" fn strnlen_s(s: *const c_char, size: size_t) -> size_t {
574 if s.is_null() {
575 0
576 } else {
577 unsafe { strnlen(s, size) }
578 }
579}
580
581#[unsafe(no_mangle)]
583pub unsafe extern "C" fn strpbrk(s1: *const c_char, s2: *const c_char) -> *mut c_char {
584 let p = unsafe { s1.add(strcspn(s1, s2)) };
585 if unsafe { *p } != 0 {
586 p.cast_mut()
587 } else {
588 ptr::null_mut()
589 }
590}
591
592#[unsafe(no_mangle)]
594pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
595 let len = unsafe { strlen(s) } as isize;
596 let c = c as c_char;
597 let mut i = len - 1;
598 while i >= 0 {
599 if unsafe { *s.offset(i) } == c {
600 return unsafe { s.offset(i) }.cast_mut();
601 }
602 i -= 1;
603 }
604 ptr::null_mut()
605}
606
607#[unsafe(no_mangle)]
609pub unsafe extern "C" fn strsignal(sig: c_int) -> *mut c_char {
610 signal::SIGNAL_STRINGS
611 .get(sig as usize)
612 .unwrap_or(&signal::SIGNAL_STRINGS[0]) .as_ptr() as *mut c_char
614}
615
616#[unsafe(no_mangle)]
618pub unsafe extern "C" fn strspn(s1: *const c_char, s2: *const c_char) -> size_t {
619 unsafe { inner_strspn(s1, s2, true) }
620}
621
622unsafe fn inner_strstr(
623 mut haystack: *const c_char,
624 needle: *const c_char,
625 mask: c_char,
626) -> *mut c_char {
627 while unsafe { *haystack } != 0 {
628 let mut i = 0;
629 loop {
630 if unsafe { *needle.offset(i) } == 0 {
631 return haystack.cast_mut();
633 }
634 if unsafe { *haystack.offset(i) } & mask != unsafe { *needle.offset(i) } & mask {
635 break;
636 }
637
638 i += 1;
639 }
640
641 haystack = unsafe { haystack.offset(1) };
642 }
643 ptr::null_mut()
644}
645
646#[unsafe(no_mangle)]
648pub unsafe extern "C" fn strstr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
649 unsafe { inner_strstr(haystack, needle, !0) }
650}
651
652#[unsafe(no_mangle)]
654pub unsafe extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char {
655 static mut HAYSTACK: *mut c_char = ptr::null_mut();
656 unsafe { strtok_r(s1, delimiter, &raw mut HAYSTACK) }
657}
658
659#[unsafe(no_mangle)]
661pub unsafe extern "C" fn strtok_r(
662 s: *mut c_char,
663 delimiter: *const c_char,
664 lasts: *mut *mut c_char,
665) -> *mut c_char {
666 let mut haystack = s;
668 if haystack.is_null() {
669 if (unsafe { *lasts }).is_null() {
670 return ptr::null_mut();
671 }
672 haystack = unsafe { *lasts };
673 }
674
675 haystack = unsafe { haystack.add(strspn(haystack, delimiter)) };
677 if unsafe { *haystack } == 0 {
678 unsafe { *lasts = haystack };
679 return ptr::null_mut();
680 }
681
682 let token = haystack;
684 haystack = unsafe { strpbrk(token, delimiter) };
685 if !haystack.is_null() {
686 unsafe { haystack.write(0) };
687 haystack = unsafe { haystack.add(1) };
688 unsafe { *lasts = haystack };
689 } else {
690 unsafe { *lasts = token.add(strlen(token)) };
691 }
692
693 token
694}
695
696#[unsafe(no_mangle)]
698pub unsafe extern "C" fn strxfrm_l(
699 s1: *mut c_char,
700 s2: *const c_char,
701 n: size_t,
702 _loc: locale_t,
703) -> size_t {
704 let len = unsafe { strlen(s2) };
706 if len < n {
707 unsafe { strcpy(s1, s2) };
708 }
709 len
710}
711
712#[unsafe(no_mangle)]
714pub unsafe extern "C" fn strxfrm(s1: *mut c_char, s2: *const c_char, n: size_t) -> size_t {
715 unsafe { strxfrm_l(s1, s2, n, THREAD_LOCALE as locale_t) }
716}