Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add strspn #34

Merged
merged 6 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ all = [
"strncmp",
"strncpy",
"strrchr",
"strspn",
"strstr",
"strtoimax",
"strtol",
Expand Down Expand Up @@ -76,6 +77,7 @@ strncasecmp = []
strncmp = []
strncpy = []
strrchr = []
strspn = []
strstr = []
strtoimax = []
strtol = []
Expand Down
128 changes: 61 additions & 67 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,58 +11,82 @@
#![allow(clippy::missing_safety_doc)]
#![allow(unused_imports)]

// Useful imports
mod ctype;
pub use self::ctype::*;

// Stateless implementations.
// rustfmt will keep these in alphabetical order.
mod abs;
mod itoa;
mod memchr;
mod qsort;
mod rand_r;
mod snprintf;
mod strcat;
mod strchr;
mod strcmp;
mod strcpy;
mod strlen;
mod strncasecmp;
mod strncmp;
mod strncpy;
mod strrchr;
mod strspn;
mod strstr;
mod strtol;

// Stateful implementations (which hence are optional).
// rustfmt will keep these in alphabetical order.
#[cfg(feature = "alloc")]
mod malloc;
#[cfg(feature = "alloc")]
pub use self::malloc::{calloc, free, malloc, realloc};
#[cfg(feature = "rand")]
mod rand;
#[cfg(feature = "signal")]
mod signal;

mod itoa;
// Public re-exports.
// rustfmt will keep these in alphabetical order.
#[cfg(feature = "abs")]
pub use self::abs::abs;
#[cfg(feature = "itoa")]
pub use self::itoa::itoa;
#[cfg(feature = "utoa")]
pub use self::itoa::utoa;

mod abs;
#[cfg(feature = "abs")]
pub use self::abs::abs;

mod rand_r;
#[cfg(feature = "rand_r")]
pub use self::rand_r::{rand_r, RAND_MAX};
#[cfg(feature = "rand")]
mod rand;
#[cfg(feature = "alloc")]
pub use self::malloc::{calloc, free, malloc, realloc};
#[cfg(feature = "memchr")]
pub use self::memchr::memchr;
#[cfg(feature = "qsort")]
pub use self::qsort::qsort;
#[cfg(feature = "rand")]
pub use self::rand::{rand, srand};

mod strcmp;
#[cfg(feature = "rand_r")]
pub use self::rand_r::{rand_r, RAND_MAX};
#[cfg(feature = "signal")]
pub use self::signal::{abort, raise, signal};
#[cfg(feature = "strcat")]
pub use self::strcat::strcat;
#[cfg(feature = "strchr")]
pub use self::strchr::strchr;
#[cfg(feature = "strcmp")]
pub use self::strcmp::strcmp;

mod strncmp;
#[cfg(feature = "strncmp")]
pub use self::strncmp::strncmp;

mod strncasecmp;
#[cfg(feature = "strncasecmp")]
pub use self::strncasecmp::strncasecmp;

mod strcpy;
#[cfg(feature = "strcpy")]
pub use self::strcpy::strcpy;

mod strncpy;
#[cfg(feature = "strncpy")]
pub use self::strncpy::strncpy;

mod strlen;
#[cfg(feature = "strlen")]
pub use self::strlen::strlen;

mod strcat;
#[cfg(feature = "strcat")]
pub use self::strcat::strcat;

mod strtol;
#[cfg(feature = "strncasecmp")]
pub use self::strncasecmp::strncasecmp;
#[cfg(feature = "strncmp")]
pub use self::strncmp::strncmp;
#[cfg(feature = "strncpy")]
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 = "atoi")]
pub use self::strtol::atoi;
#[cfg(feature = "isalpha")]
Expand All @@ -85,33 +109,3 @@ pub use self::strtol::strtoul;
pub use self::strtol::strtoull;
#[cfg(feature = "strtoumax")]
pub use self::strtol::strtoumax;

mod strstr;
#[cfg(feature = "strstr")]
pub use self::strstr::strstr;

mod strchr;
#[cfg(feature = "strchr")]
pub use self::strchr::strchr;

mod strrchr;
#[cfg(feature = "strrchr")]
pub use self::strrchr::strrchr;

mod qsort;
#[cfg(feature = "qsort")]
pub use self::qsort::qsort;

#[cfg(feature = "signal")]
mod signal;
#[cfg(feature = "signal")]
pub use self::signal::{abort, raise, signal};

mod memchr;
#[cfg(feature = "memchr")]
pub use self::memchr::memchr;

mod snprintf;

mod ctype;
pub use self::ctype::*;
84 changes: 84 additions & 0 deletions src/strspn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! 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()) };

let bytes = s.to_bytes();
for (idx, b) in bytes.iter().enumerate() {
if !is_c_in_charset(*b, charset) {
return idx;
}
}

bytes.len()
}

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
Loading