diff --git a/src/header/strings/mod.rs b/src/header/strings/mod.rs index e501861fea..cc4c17e511 100644 --- a/src/header/strings/mod.rs +++ b/src/header/strings/mod.rs @@ -1,9 +1,14 @@ //! strings implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/strings.h.html -use core::{arch, ptr}; +use core::{ + arch, + iter::{once, zip}, + ptr, +}; use crate::{ header::{ctype, string}, + iter::NulTerminated, platform::types::*, }; @@ -49,25 +54,29 @@ pub unsafe extern "C" fn rindex(s: *const c_char, c: c_int) -> *mut c_char { } #[no_mangle] -pub unsafe extern "C" fn strcasecmp(first: *const c_char, second: *const c_char) -> c_int { - strncasecmp(first, second, size_t::max_value()) +pub unsafe extern "C" fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int { + // SAFETY: the caller must ensure that s1 and s2 point to nul-terminated buffers. + let s1_iter = unsafe { NulTerminated::new(s1) }.chain(once(&0)); + let s2_iter = unsafe { NulTerminated::new(s2) }.chain(once(&0)); + + let zipped = zip(s1_iter, s2_iter); + inner_casecmp(zipped) } #[no_mangle] -pub unsafe extern "C" fn strncasecmp( - mut first: *const c_char, - mut second: *const c_char, - mut n: size_t, -) -> c_int { - while n > 0 && (*first != 0 || *second != 0) { - let cmp = ctype::tolower(*first as c_int) - ctype::tolower(*second as c_int); - if cmp != 0 { - return cmp; - } +pub unsafe extern "C" fn strncasecmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int { + // SAFETY: the caller must ensure that s1 and s2 point to nul-terminated buffers. + let s1_iter = unsafe { NulTerminated::new(s1) }.chain(once(&0)); + let s2_iter = unsafe { NulTerminated::new(s2) }.chain(once(&0)); - first = first.offset(1); - second = second.offset(1); - n -= 1; - } - 0 + let zipped = zip(s1_iter, s2_iter).take(n); + inner_casecmp(zipped) +} + +/// Given two zipped `&c_char` iterators, either find the first comparison != 0, or return 0. +fn inner_casecmp<'a>(iterator: impl Iterator) -> c_int { + let mut cmp_iter = + iterator.map(|(&c1, &c2)| ctype::tolower(c1.into()) - ctype::tolower(c2.into())); + let mut skip_iter = cmp_iter.skip_while(|&cmp| cmp == 0); + skip_iter.next().or(Some(0)).unwrap() }