use crate::libc;
pub unsafe fn strlcat(dst: *mut u8, src: *const u8, size: usize) -> usize {
unsafe {
let dst_strlen = libc::strnlen(dst, size);
let src_strlen = libc::strnlen(src, size.saturating_sub(dst_strlen).saturating_sub(1));
core::ptr::copy_nonoverlapping(src, dst.add(dst_strlen), src_strlen);
*dst.add(dst_strlen + src_strlen) = b'\0';
dst_strlen + src_strlen
}
}
#[expect(clippy::disallowed_methods)]
pub unsafe fn strlcat_(dst: *mut u8, src: &str, size: usize) -> usize {
unsafe {
let dst_strlen = libc::strnlen(dst, size);
let src_strlen = src
.len()
.min(size.saturating_sub(dst_strlen).saturating_sub(1));
core::ptr::copy_nonoverlapping(src.as_ptr(), dst.add(dst_strlen), src_strlen);
*dst.add(dst_strlen + src_strlen) = b'\0';
dst_strlen + src_strlen
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strlcat_append() {
let mut dst = [0u8; 10];
dst[..3].copy_from_slice(b"foo");
let src = crate::c!("bar");
let ret = unsafe { strlcat(dst.as_mut_ptr(), src, dst.len()) };
assert_eq!(ret, 6);
assert_eq!(&dst[..7], b"foobar\0");
}
#[test]
fn test_strlcat_truncation() {
let mut dst = [0u8; 10];
dst[..3].copy_from_slice(b"foo");
let src = crate::c!("bar");
let ret = unsafe { strlcat(dst.as_mut_ptr(), src, 5) };
assert_eq!(ret, 4);
assert_eq!(&dst[..5], b"foob\0");
}
#[test]
fn test_strlcat_empty_dst() {
let mut dst = [0u8; 10];
let src = crate::c!("hi");
let ret = unsafe { strlcat(dst.as_mut_ptr(), src, dst.len()) };
assert_eq!(ret, 2);
assert_eq!(&dst[..3], b"hi\0");
}
}