Skip to content

Commit

Permalink
Merge pull request #34 from rust-embedded-community/strspn
Browse files Browse the repository at this point in the history
Add strspn
  • Loading branch information
eldruin authored Nov 28, 2024
2 parents 15665a5 + 953143d commit a4981c3
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 67 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

* [#26] - Add `memchr`
* [#27] - Add `qsort`
* [#28] - Add `strcat` and `strchr`
* [#29] - Clean up docs
* [#30] - Add padding in `sprintf`
* [#32] - Add `rand`, `srand` and `rand_r`
* [#34] - Add `strspn` and `strcspn`

[#26]: https://github.com/rust-embedded-community/tinyrlibc/pull/26
[#27]: https://github.com/rust-embedded-community/tinyrlibc/pull/27
[#28]: https://github.com/rust-embedded-community/tinyrlibc/pull/28
[#29]: https://github.com/rust-embedded-community/tinyrlibc/pull/29
[#30]: https://github.com/rust-embedded-community/tinyrlibc/pull/30
[#32]: https://github.com/rust-embedded-community/tinyrlibc/pull/32
[#34]: https://github.com/rust-embedded-community/tinyrlibc/pull/34

## v0.4.0 (2024-03-22)

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ all = [
"strncmp",
"strncpy",
"strrchr",
"strspn",
"strcspn",
"strstr",
"strtoimax",
"strtol",
Expand Down Expand Up @@ -76,6 +78,8 @@ strncasecmp = []
strncmp = []
strncpy = []
strrchr = []
strspn = []
strcspn = []
strstr = []
strtoimax = []
strtol = []
Expand Down
131 changes: 64 additions & 67 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,58 +11,85 @@
#![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 strcspn;
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 = "strcspn")]
pub use self::strcspn::strcspn;
#[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 +112,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::*;
94 changes: 94 additions & 0 deletions src/strcspn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Rust implementation of C library function `strcspn`
//!
//! 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 `strcspn`
#[cfg_attr(feature = "strcspn", no_mangle)]
pub unsafe extern "C" fn strcspn(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"abcdef";
assert_eq!(
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
6
);
}

#[test]
fn subset() {
let charset = c"0123456789";
let s = c"xyz1";
assert_eq!(
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
3
);
}

#[test]
fn none() {
let charset = c"0123456789";
let s = c"567";
assert_eq!(
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
0
);
}

#[test]
fn empty_charset() {
let charset = c"";
let s = c"AABBCCDD";
assert_eq!(
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
8
);
}

#[test]
fn empty_string() {
let charset = c"0123456789";
let s = c"";
assert_eq!(
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
0
);
}
}

// End of file
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

0 comments on commit a4981c3

Please sign in to comment.