diff --git a/Cargo.toml b/Cargo.toml index d27a410..ed937e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ all = [ "strncmp", "strncasecmp", "strcpy", + "strcat", "strncpy", "strlen", "strtol", @@ -35,6 +36,7 @@ all = [ "strtoumax", "strstr", "strchr", + "strrchr", "atoi", "utoa", "itoa", @@ -51,6 +53,7 @@ strcmp = [] strncmp = [] strncasecmp = [] strcpy = [] +strcat = [] strncpy = [] strlen = [] strtol = [] @@ -61,6 +64,7 @@ strtoimax = [] strtoumax = [] strstr = [] strchr = [] +strrchr = [] atoi = [] utoa = [] itoa = [] diff --git a/README.md b/README.md index 5f02ccd..ca09ba4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This crate basically came about so that the [nrfxlib](https://github.com/NordicP * strcmp * strncmp * strncasecmp +* strcat * strcpy * strncpy * strlen @@ -30,6 +31,7 @@ This crate basically came about so that the [nrfxlib](https://github.com/NordicP * strtoumax * strstr * strchr +* strrchr * snprintf * vsnprintf * qsort diff --git a/src/lib.rs b/src/lib.rs index 4532aa6..8198eef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,10 @@ mod strlen; #[cfg(feature = "strlen")] pub use self::strlen::strlen; +mod strcat; +#[cfg(feature = "strcat")] +pub use self::strcat::strcat; + mod strtol; #[cfg(feature = "atoi")] pub use self::strtol::atoi; @@ -82,6 +86,10 @@ 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; diff --git a/src/strcat.rs b/src/strcat.rs new file mode 100644 index 0000000..7731067 --- /dev/null +++ b/src/strcat.rs @@ -0,0 +1,29 @@ +//! Rust implementation of C library function `strcat` +//! +//! Licensed under the Blue Oak Model Licence 1.0.0 + +use crate::CChar; + +/// Rust implementation of C library function `strcat`. Passing NULL +/// (core::ptr::null()) gives undefined behaviour. +#[cfg_attr(feature = "strcat", no_mangle)] +pub unsafe extern "C" fn strcat(dest: *mut CChar, src: *const CChar) -> *const CChar { + crate::strcpy::strcpy(dest.add(crate::strlen::strlen(dest)), src); + dest +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn simple() { + let mut dest = *b"hello\0\0\0\0\0\0\0\0"; + let src = *b" world\0"; + let result = unsafe { strcat(dest.as_mut_ptr(), src.as_ptr()) }; + assert_eq!( + unsafe { core::slice::from_raw_parts(result, 12) }, + b"hello world\0" + ); + } +} diff --git a/src/strchr.rs b/src/strchr.rs index 063c96a..23efe0a 100644 --- a/src/strchr.rs +++ b/src/strchr.rs @@ -25,37 +25,37 @@ mod test { use super::*; #[test] - fn no_match() { - let haystack = b"haystack\0".as_ptr(); + fn strchr_no_match() { + let haystack = b"hayyystack\0".as_ptr(); let result = unsafe { strchr(haystack, b'X' as CInt) }; assert_eq!(result, core::ptr::null()); } #[test] - fn null() { - let haystack = b"haystack\0".as_ptr(); + fn strchr_null() { + let haystack = b"hayyystack\0".as_ptr(); let result = unsafe { strchr(haystack, 0) }; - assert_eq!(result, unsafe { haystack.offset(8) }); + assert_eq!(result, unsafe { haystack.offset(10) }); } #[test] - fn start() { - let haystack = b"haystack\0".as_ptr(); + fn strchr_start() { + let haystack = b"hayyystack\0".as_ptr(); let result = unsafe { strchr(haystack, b'h' as CInt) }; assert_eq!(result, haystack); } #[test] - fn middle() { - let haystack = b"haystack\0".as_ptr(); + fn strchr_middle() { + let haystack = b"hayyystack\0".as_ptr(); let result = unsafe { strchr(haystack, b'y' as CInt) }; assert_eq!(result, unsafe { haystack.offset(2) }); } #[test] - fn end() { - let haystack = b"haystack\0".as_ptr(); + fn strchr_end() { + let haystack = b"hayyystack\0".as_ptr(); let result = unsafe { strchr(haystack, b'k' as CInt) }; - assert_eq!(result, unsafe { haystack.offset(7) }); + assert_eq!(result, unsafe { haystack.offset(9) }); } } diff --git a/src/strrchr.rs b/src/strrchr.rs new file mode 100644 index 0000000..2cf42fb --- /dev/null +++ b/src/strrchr.rs @@ -0,0 +1,62 @@ +//! Rust implementation of C library function `strchr` +//! +//! Copyright (c) 42 Technology Ltd +//! Licensed under the Blue Oak Model Licence 1.0.0 + +use crate::{CChar, CInt}; + +/// Rust implementation of C library function `strrchr` +#[cfg_attr(feature = "strrchr", no_mangle)] +pub unsafe extern "C" fn strrchr(haystack: *const CChar, needle: CInt) -> *const CChar { + let mut last = core::ptr::null(); + for idx in 0.. { + let ptr = haystack.offset(idx); + if needle == (*ptr) as CInt { + last = ptr; + } + if (*ptr) == 0 { + break; + } + } + last +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn strrchr_no_match() { + let haystack = b"hayyystack\0".as_ptr(); + let result = unsafe { strrchr(haystack, b'X' as CInt) }; + assert_eq!(result, core::ptr::null()); + } + + #[test] + fn strrchr_null() { + let haystack = b"hayyystack\0".as_ptr(); + let result = unsafe { strrchr(haystack, 0) }; + assert_eq!(result, unsafe { haystack.offset(10) }); + } + + #[test] + fn strrchr_start() { + let haystack = b"hayhay\0".as_ptr(); + let result = unsafe { strrchr(haystack, b'h' as CInt) }; + assert_eq!(result, unsafe { haystack.offset(3) }); + } + + #[test] + fn strrchr_middle() { + let haystack = b"hayyystack\0".as_ptr(); + let result = unsafe { strrchr(haystack, b'y' as CInt) }; + assert_eq!(result, unsafe { haystack.offset(4) }); + } + + #[test] + fn strrchr_end() { + let haystack = b"hayyystack\0".as_ptr(); + let result = unsafe { strrchr(haystack, b'k' as CInt) }; + assert_eq!(result, unsafe { haystack.offset(9) }); + } +}