use core::{
ffi::{c_char, c_int},
ptr, usize,
};
type size_t = usize;
#[no_mangle]
pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
let c = c as c_char;
while *s != 0 {
if *s == c {
return s as *mut c_char;
}
s = s.offset(1);
}
ptr::null_mut()
}
#[no_mangle]
pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
strncmp(s1, s2, usize::MAX)
}
#[no_mangle]
pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
strcmp(s1, s2)
}
#[no_mangle]
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
let mut i = 0;
loop {
let byte = *src.offset(i);
*dst.offset(i) = byte;
if byte == 0 {
break;
}
i += 1;
}
dst
}
#[no_mangle]
pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
strnlen(s, usize::MAX)
}
#[no_mangle]
pub unsafe extern "C" fn strnlen(s: *const c_char, size: size_t) -> size_t {
let mut i = 0;
while i < size {
if *s.add(i) == 0 {
break;
}
i += 1;
}
i as size_t
}
#[no_mangle]
pub unsafe extern "C" fn strnlen_s(s: *const c_char, size: size_t) -> size_t {
if s.is_null() {
0
} else {
strnlen(s, size)
}
}
#[no_mangle]
pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
strncat(s1, s2, usize::MAX)
}
#[no_mangle]
pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char {
let len = strlen(s1 as *const c_char);
let mut i = 0;
while i < n {
let b = *s2.add(i);
if b == 0 {
break;
}
*s1.add(len + i) = b;
i += 1;
}
*s1.add(len + i) = 0;
s1
}
#[no_mangle]
pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int {
let mut i = 0;
while i < n {
let c1 = *s1.add(i);
let c2 = *s2.add(i);
if c1 != c2 || c1 == 0 {
return (c1 as c_int) - (c2 as c_int);
}
i += 1;
}
0
}
#[no_mangle]
pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char {
let mut i = 0;
while *src.add(i) != 0 && i < n {
*dst.add(i) = *src.add(i);
i += 1;
}
for i in i..n {
*dst.add(i) = 0;
}
dst
}
#[no_mangle]
pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
let len = strlen(s) as isize;
let c = c as c_char;
let mut i = len - 1;
while i >= 0 {
if *s.offset(i) == c {
return s.offset(i) as *mut c_char;
}
i -= 1;
}
ptr::null_mut()
}
#[cfg(test)]
mod tests {
use crate::string_impl::{strcmp, strncmp};
#[test]
fn strcmp_test() {
unsafe {
let s1 = [1, 2, 0].as_ptr();
let s2 = [1, 2, 3, 0].as_ptr();
assert!(strncmp(s1, s2, 0) == 0);
assert!(strncmp(s1, s2, 1) == 0);
assert!(strncmp(s1, s2, 2) == 0);
assert!(strncmp(s1, s2, 3) < 0);
assert!(strncmp(s2, s1, 3) > 0);
assert!(strncmp(s1, s2, 4) < 0);
assert!(strncmp(s2, s1, 4) > 0);
assert!(strcmp(s1, s2) < 0);
assert!(strcmp(s2, s1) > 0);
}
}
}