Skip to content

Commit a4981c3

Browse files
authored
Merge pull request #34 from rust-embedded-community/strspn
Add strspn
2 parents 15665a5 + 953143d commit a4981c3

File tree

5 files changed

+256
-67
lines changed

5 files changed

+256
-67
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,19 @@
44

55
* [#26] - Add `memchr`
66
* [#27] - Add `qsort`
7+
* [#28] - Add `strcat` and `strchr`
8+
* [#29] - Clean up docs
9+
* [#30] - Add padding in `sprintf`
10+
* [#32] - Add `rand`, `srand` and `rand_r`
11+
* [#34] - Add `strspn` and `strcspn`
712

813
[#26]: https://github.com/rust-embedded-community/tinyrlibc/pull/26
914
[#27]: https://github.com/rust-embedded-community/tinyrlibc/pull/27
15+
[#28]: https://github.com/rust-embedded-community/tinyrlibc/pull/28
16+
[#29]: https://github.com/rust-embedded-community/tinyrlibc/pull/29
17+
[#30]: https://github.com/rust-embedded-community/tinyrlibc/pull/30
18+
[#32]: https://github.com/rust-embedded-community/tinyrlibc/pull/32
19+
[#34]: https://github.com/rust-embedded-community/tinyrlibc/pull/34
1020

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

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ all = [
4141
"strncmp",
4242
"strncpy",
4343
"strrchr",
44+
"strspn",
45+
"strcspn",
4446
"strstr",
4547
"strtoimax",
4648
"strtol",
@@ -76,6 +78,8 @@ strncasecmp = []
7678
strncmp = []
7779
strncpy = []
7880
strrchr = []
81+
strspn = []
82+
strcspn = []
7983
strstr = []
8084
strtoimax = []
8185
strtol = []

src/lib.rs

Lines changed: 64 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11,58 +11,85 @@
1111
#![allow(clippy::missing_safety_doc)]
1212
#![allow(unused_imports)]
1313

14+
// Useful imports
15+
mod ctype;
16+
pub use self::ctype::*;
17+
18+
// Stateless implementations.
19+
// rustfmt will keep these in alphabetical order.
20+
mod abs;
21+
mod itoa;
22+
mod memchr;
23+
mod qsort;
24+
mod rand_r;
25+
mod snprintf;
26+
mod strcat;
27+
mod strchr;
28+
mod strcmp;
29+
mod strcpy;
30+
mod strcspn;
31+
mod strlen;
32+
mod strncasecmp;
33+
mod strncmp;
34+
mod strncpy;
35+
mod strrchr;
36+
mod strspn;
37+
mod strstr;
38+
mod strtol;
39+
40+
// Stateful implementations (which hence are optional).
41+
// rustfmt will keep these in alphabetical order.
1442
#[cfg(feature = "alloc")]
1543
mod malloc;
16-
#[cfg(feature = "alloc")]
17-
pub use self::malloc::{calloc, free, malloc, realloc};
44+
#[cfg(feature = "rand")]
45+
mod rand;
46+
#[cfg(feature = "signal")]
47+
mod signal;
1848

19-
mod itoa;
49+
// Public re-exports.
50+
// rustfmt will keep these in alphabetical order.
51+
#[cfg(feature = "abs")]
52+
pub use self::abs::abs;
2053
#[cfg(feature = "itoa")]
2154
pub use self::itoa::itoa;
2255
#[cfg(feature = "utoa")]
2356
pub use self::itoa::utoa;
24-
25-
mod abs;
26-
#[cfg(feature = "abs")]
27-
pub use self::abs::abs;
28-
29-
mod rand_r;
30-
#[cfg(feature = "rand_r")]
31-
pub use self::rand_r::{rand_r, RAND_MAX};
32-
#[cfg(feature = "rand")]
33-
mod rand;
57+
#[cfg(feature = "alloc")]
58+
pub use self::malloc::{calloc, free, malloc, realloc};
59+
#[cfg(feature = "memchr")]
60+
pub use self::memchr::memchr;
61+
#[cfg(feature = "qsort")]
62+
pub use self::qsort::qsort;
3463
#[cfg(feature = "rand")]
3564
pub use self::rand::{rand, srand};
36-
37-
mod strcmp;
65+
#[cfg(feature = "rand_r")]
66+
pub use self::rand_r::{rand_r, RAND_MAX};
67+
#[cfg(feature = "signal")]
68+
pub use self::signal::{abort, raise, signal};
69+
#[cfg(feature = "strcat")]
70+
pub use self::strcat::strcat;
71+
#[cfg(feature = "strchr")]
72+
pub use self::strchr::strchr;
3873
#[cfg(feature = "strcmp")]
3974
pub use self::strcmp::strcmp;
40-
41-
mod strncmp;
42-
#[cfg(feature = "strncmp")]
43-
pub use self::strncmp::strncmp;
44-
45-
mod strncasecmp;
46-
#[cfg(feature = "strncasecmp")]
47-
pub use self::strncasecmp::strncasecmp;
48-
49-
mod strcpy;
5075
#[cfg(feature = "strcpy")]
5176
pub use self::strcpy::strcpy;
52-
53-
mod strncpy;
54-
#[cfg(feature = "strncpy")]
55-
pub use self::strncpy::strncpy;
56-
57-
mod strlen;
77+
#[cfg(feature = "strcspn")]
78+
pub use self::strcspn::strcspn;
5879
#[cfg(feature = "strlen")]
5980
pub use self::strlen::strlen;
60-
61-
mod strcat;
62-
#[cfg(feature = "strcat")]
63-
pub use self::strcat::strcat;
64-
65-
mod strtol;
81+
#[cfg(feature = "strncasecmp")]
82+
pub use self::strncasecmp::strncasecmp;
83+
#[cfg(feature = "strncmp")]
84+
pub use self::strncmp::strncmp;
85+
#[cfg(feature = "strncpy")]
86+
pub use self::strncpy::strncpy;
87+
#[cfg(feature = "strrchr")]
88+
pub use self::strrchr::strrchr;
89+
#[cfg(feature = "strspn")]
90+
pub use self::strspn::strspn;
91+
#[cfg(feature = "strstr")]
92+
pub use self::strstr::strstr;
6693
#[cfg(feature = "atoi")]
6794
pub use self::strtol::atoi;
6895
#[cfg(feature = "isalpha")]
@@ -85,33 +112,3 @@ pub use self::strtol::strtoul;
85112
pub use self::strtol::strtoull;
86113
#[cfg(feature = "strtoumax")]
87114
pub use self::strtol::strtoumax;
88-
89-
mod strstr;
90-
#[cfg(feature = "strstr")]
91-
pub use self::strstr::strstr;
92-
93-
mod strchr;
94-
#[cfg(feature = "strchr")]
95-
pub use self::strchr::strchr;
96-
97-
mod strrchr;
98-
#[cfg(feature = "strrchr")]
99-
pub use self::strrchr::strrchr;
100-
101-
mod qsort;
102-
#[cfg(feature = "qsort")]
103-
pub use self::qsort::qsort;
104-
105-
#[cfg(feature = "signal")]
106-
mod signal;
107-
#[cfg(feature = "signal")]
108-
pub use self::signal::{abort, raise, signal};
109-
110-
mod memchr;
111-
#[cfg(feature = "memchr")]
112-
pub use self::memchr::memchr;
113-
114-
mod snprintf;
115-
116-
mod ctype;
117-
pub use self::ctype::*;

src/strcspn.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! Rust implementation of C library function `strcspn`
2+
//!
3+
//! Copyright (c) Ferrous Systems UK Ltd
4+
//! Licensed under the Blue Oak Model Licence 1.0.0
5+
6+
use crate::{CChar, CInt};
7+
8+
/// Rust implementation of C library function `strcspn`
9+
#[cfg_attr(feature = "strcspn", no_mangle)]
10+
pub unsafe extern "C" fn strcspn(s: *const CChar, charset: *const CChar) -> usize {
11+
if s.is_null() {
12+
return 0;
13+
}
14+
if charset.is_null() {
15+
return 0;
16+
}
17+
18+
let s = unsafe { core::ffi::CStr::from_ptr(s.cast()) };
19+
20+
let charset = unsafe { core::ffi::CStr::from_ptr(charset.cast()) };
21+
22+
let bytes = s.to_bytes();
23+
for (idx, b) in bytes.iter().enumerate() {
24+
if is_c_in_charset(*b, charset) {
25+
return idx;
26+
}
27+
}
28+
29+
bytes.len()
30+
}
31+
32+
fn is_c_in_charset(c: u8, charset: &core::ffi::CStr) -> bool {
33+
for b in charset.to_bytes() {
34+
if c == *b {
35+
return true;
36+
}
37+
}
38+
false
39+
}
40+
41+
#[cfg(test)]
42+
mod test {
43+
#[test]
44+
fn complete() {
45+
let charset = c"0123456789";
46+
let s = c"abcdef";
47+
assert_eq!(
48+
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
49+
6
50+
);
51+
}
52+
53+
#[test]
54+
fn subset() {
55+
let charset = c"0123456789";
56+
let s = c"xyz1";
57+
assert_eq!(
58+
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
59+
3
60+
);
61+
}
62+
63+
#[test]
64+
fn none() {
65+
let charset = c"0123456789";
66+
let s = c"567";
67+
assert_eq!(
68+
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
69+
0
70+
);
71+
}
72+
73+
#[test]
74+
fn empty_charset() {
75+
let charset = c"";
76+
let s = c"AABBCCDD";
77+
assert_eq!(
78+
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
79+
8
80+
);
81+
}
82+
83+
#[test]
84+
fn empty_string() {
85+
let charset = c"0123456789";
86+
let s = c"";
87+
assert_eq!(
88+
unsafe { super::strcspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
89+
0
90+
);
91+
}
92+
}
93+
94+
// End of file

src/strspn.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//! Rust implementation of C library function `strspn`
2+
//!
3+
//! Copyright (c) Ferrous Systems UK Ltd
4+
//! Licensed under the Blue Oak Model Licence 1.0.0
5+
6+
use crate::{CChar, CInt};
7+
8+
/// Rust implementation of C library function `strspn`
9+
#[cfg_attr(feature = "strspn", no_mangle)]
10+
pub unsafe extern "C" fn strspn(s: *const CChar, charset: *const CChar) -> usize {
11+
if s.is_null() {
12+
return 0;
13+
}
14+
if charset.is_null() {
15+
return 0;
16+
}
17+
18+
let s = unsafe { core::ffi::CStr::from_ptr(s.cast()) };
19+
20+
let charset = unsafe { core::ffi::CStr::from_ptr(charset.cast()) };
21+
22+
let bytes = s.to_bytes();
23+
for (idx, b) in bytes.iter().enumerate() {
24+
if !is_c_in_charset(*b, charset) {
25+
return idx;
26+
}
27+
}
28+
29+
bytes.len()
30+
}
31+
32+
fn is_c_in_charset(c: u8, charset: &core::ffi::CStr) -> bool {
33+
for b in charset.to_bytes() {
34+
if c == *b {
35+
return true;
36+
}
37+
}
38+
false
39+
}
40+
41+
#[cfg(test)]
42+
mod test {
43+
#[test]
44+
fn complete() {
45+
let charset = c"0123456789";
46+
let s = c"987654321";
47+
assert_eq!(
48+
unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
49+
9
50+
);
51+
}
52+
53+
#[test]
54+
fn subset() {
55+
let charset = c"0123456789";
56+
let s = c"98xx7654321";
57+
assert_eq!(
58+
unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
59+
2
60+
);
61+
}
62+
63+
#[test]
64+
fn empty_charset() {
65+
let charset = c"";
66+
let s = c"AABBCCDD";
67+
assert_eq!(
68+
unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
69+
0
70+
);
71+
}
72+
73+
#[test]
74+
fn empty_string() {
75+
let charset = c"0123456789";
76+
let s = c"";
77+
assert_eq!(
78+
unsafe { super::strspn(s.as_ptr().cast(), charset.as_ptr().cast()) },
79+
0
80+
);
81+
}
82+
}
83+
84+
// End of file

0 commit comments

Comments
 (0)