diff --git a/Cargo.toml b/Cargo.toml index 3a4e29b..f34333e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ all = [ "strncmp", "strncpy", "strrchr", + "strspn", "strstr", "strtoimax", "strtol", @@ -71,6 +72,7 @@ strncasecmp = [] strncmp = [] strncpy = [] strrchr = [] +strspn = [] strstr = [] strtoimax = [] strtol = [] diff --git a/src/lib.rs b/src/lib.rs index 7ff3df7..687b0b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ mod strncasecmp; mod strncmp; mod strncpy; mod strrchr; +mod strspn; mod strstr; mod strtol; @@ -79,6 +80,8 @@ pub use self::strncmp::strncmp; pub use self::strncpy::strncpy; #[cfg(feature = "strrchr")] pub use self::strrchr::strrchr; +#[cfg(feature = "strspn")] +pub use self::strspn::strspn; #[cfg(feature = "strstr")] pub use self::strstr::strstr; #[cfg(feature = "strtoimax")] diff --git a/src/strspn.rs b/src/strspn.rs new file mode 100644 index 0000000..937a1ed --- /dev/null +++ b/src/strspn.rs @@ -0,0 +1,83 @@ +//! Rust implementation of C library function `strspn` +//! +//! Copyright (c) Ferrous Systems UK Ltd +//! Licensed under the Blue Oak Model Licence 1.0.0 + +use crate::{CChar, CInt}; + +/// Rust implementation of C library function `strspn` +#[cfg_attr(feature = "strspn", no_mangle)] +pub unsafe extern "C" fn strspn(s: *const CChar, charset: *const CChar) -> usize { + if s.is_null() { + return 0; + } + if charset.is_null() { + return 0; + } + + let s = unsafe { core::ffi::CStr::from_ptr(s.cast()) }; + + let charset = unsafe { core::ffi::CStr::from_ptr(charset.cast()) }; + + for (idx, b) in s.to_bytes().iter().enumerate() { + if !is_c_in_charset(*b, charset) { + return idx; + } + } + + s.count_bytes() +} + +fn is_c_in_charset(c: u8, charset: &core::ffi::CStr) -> bool { + for b in charset.to_bytes() { + if c == *b { + return true; + } + } + false +} + +#[cfg(test)] +mod test { + #[test] + fn complete() { + let charset = c"0123456789"; + let s = c"987654321"; + assert_eq!( + unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) }, + 9 + ); + } + + #[test] + fn subset() { + let charset = c"0123456789"; + let s = c"98xx7654321"; + assert_eq!( + unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) }, + 2 + ); + } + + #[test] + fn empty_charset() { + let charset = c""; + let s = c"AABBCCDD"; + assert_eq!( + unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) }, + 0 + ); + } + + #[test] + fn empty_string() { + let charset = c"0123456789"; + let s = c""; + assert_eq!( + unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) }, + 0 + ); + } +} + +// End of file