diff --git a/src/header/string/mod.rs b/src/header/string/mod.rs index d664a231d3..c986850b85 100644 --- a/src/header/string/mod.rs +++ b/src/header/string/mod.rs @@ -52,7 +52,8 @@ pub unsafe extern "C" fn memchr( /// See . #[no_mangle] -pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: size_t) -> c_int { +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int { let (div, rem) = (n / mem::size_of::(), n % mem::size_of::()); let mut a = s1 as *const usize; let mut b = s2 as *const usize; @@ -285,15 +286,44 @@ pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_v } /// See . -// #[no_mangle] -pub extern "C" fn stpcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_char { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn stpcpy(mut s1: *mut c_char, mut s2: *const c_char) -> *mut c_char { + loop { + *s1 = *s2; + + if *s1 == 0 { + break; + } + + s1 = s1.add(1); + s2 = s2.add(1); + } + + s1 } /// See . -// #[no_mangle] -pub extern "C" fn stpncpy(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn stpncpy( + mut s1: *mut c_char, + mut s2: *const c_char, + mut n: size_t, +) -> *mut c_char { + while n > 0 { + *s1 = *s2; + + if *s1 == 0 { + break; + } + + n -= 1; + s1 = s1.add(1); + s2 = s2.add(1); + } + + memset(s1.cast(), 0, n); + + s1 } /// Non-POSIX, see . @@ -330,6 +360,22 @@ pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char { ptr.cast_mut() } +/// Non-POSIX, see . +#[no_mangle] +pub unsafe extern "C" fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char { + let mut s = s.cast_mut(); + loop { + if *s == c as _ { + break; + } + if *s == 0 { + break; + } + s = s.add(1); + } + s +} + /// See . #[no_mangle] pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int { @@ -443,6 +489,23 @@ pub unsafe extern "C" fn strlcat(dst: *mut c_char, src: *const c_char, n: size_t strlcpy(d, src, n) } +#[no_mangle] +pub unsafe extern "C" fn strsep(str_: *mut *mut c_char, sep: *const c_char) -> *mut c_char { + let s = *str_; + if s.is_null() { + return ptr::null_mut(); + } + let mut end = s.add(strcspn(s, sep)); + if *end != 0 { + *end = 0; + end = end.add(1); + } else { + end = ptr::null_mut(); + } + *str_ = end; + s +} + /// See . #[no_mangle] pub unsafe extern "C" fn strlcpy(dst: *mut c_char, src: *const c_char, n: size_t) -> size_t { @@ -467,7 +530,7 @@ pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t { /// See . #[no_mangle] pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char { - let len = strlen(s1 as *const c_char); + let len = strlen(s1.cast()); let mut i = 0; while i < n { let b = *s2.add(i); @@ -486,8 +549,8 @@ pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t) /// See . #[no_mangle] pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int { - let s1 = core::slice::from_raw_parts(s1 as *const c_uchar, n); - let s2 = core::slice::from_raw_parts(s2 as *const c_uchar, n); + let s1 = slice::from_raw_parts(s1 as *const c_uchar, n); + let s2 = slice::from_raw_parts(s2 as *const c_uchar, n); for (&a, &b) in s1.iter().zip(s2.iter()) { let val = (a as c_int) - (b as c_int); @@ -501,19 +564,9 @@ pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t /// See . #[no_mangle] -pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char { - let mut i = 0; - - while *src.add(i) != 0 && i < n { - *dst.add(i) = *src.add(i); - i += 1; - } - - for i in i..n { - *dst.add(i) = 0; - } - - dst +pub unsafe extern "C" fn strncpy(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char { + stpncpy(s1, s2, n); + s1 } /// See . diff --git a/tests/Makefile b/tests/Makefile index 784c1682fc..8deabf2c5c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -80,6 +80,7 @@ EXPECT_NAMES=\ string/memmem \ string/strcat \ string/strchr \ + string/strchrnul \ string/strcpy \ string/strcspn \ string/strlen \ @@ -90,7 +91,10 @@ EXPECT_NAMES=\ string/strstr \ string/strtok \ string/strtok_r \ + string/strsep \ string/strsignal \ + string/stpcpy \ + string/stpncpy \ strings \ sys_mman \ time/asctime \ diff --git a/tests/expected/bins_dynamic/string/stpcpy.stderr b/tests/expected/bins_dynamic/string/stpcpy.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/stpcpy.stdout b/tests/expected/bins_dynamic/string/stpcpy.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/stpncpy.stderr b/tests/expected/bins_dynamic/string/stpncpy.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/stpncpy.stdout b/tests/expected/bins_dynamic/string/stpncpy.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/strchrnul.stderr b/tests/expected/bins_dynamic/string/strchrnul.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/strchrnul.stdout b/tests/expected/bins_dynamic/string/strchrnul.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/strsep.stderr b/tests/expected/bins_dynamic/string/strsep.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_dynamic/string/strsep.stdout b/tests/expected/bins_dynamic/string/strsep.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/stpcpy.stderr b/tests/expected/bins_static/string/stpcpy.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/stpcpy.stdout b/tests/expected/bins_static/string/stpcpy.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/stpncpy.stderr b/tests/expected/bins_static/string/stpncpy.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/stpncpy.stdout b/tests/expected/bins_static/string/stpncpy.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/strchrnul.stderr b/tests/expected/bins_static/string/strchrnul.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/strchrnul.stdout b/tests/expected/bins_static/string/strchrnul.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/strsep.stderr b/tests/expected/bins_static/string/strsep.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/string/strsep.stdout b/tests/expected/bins_static/string/strsep.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/string/stpcpy.c b/tests/string/stpcpy.c new file mode 100644 index 0000000000..9d10d41199 --- /dev/null +++ b/tests/string/stpcpy.c @@ -0,0 +1,26 @@ +#include +#include + +void test_stpcpy(const char *src, char *dest) { + char *end = stpcpy(dest, src); + assert(strcmp(dest, src) == 0); + assert(*end == '\0'); + assert(end == dest + strlen(dest)); +} + +int main() { + char dest[20]; + + test_stpcpy("Hello, World!", dest); + + // Test case 2: Empty string + test_stpcpy("", dest); + + // Test case 3: String with special characters + test_stpcpy("Special chars: !@#$%^&*()", dest); + + // Test case 4: String with spaces + test_stpcpy("A string with spaces", dest); + + return 0; +} diff --git a/tests/string/stpncpy.c b/tests/string/stpncpy.c new file mode 100644 index 0000000000..27b558f088 --- /dev/null +++ b/tests/string/stpncpy.c @@ -0,0 +1,40 @@ +#include +#include + +int main() { + // Define some test strings + const char *src = "Hello, World!"; + char dest[50]; + + // Test 1: Copy exactly 5 characters from src to dest + char *result = stpncpy(dest, src, 5); + dest[5] = '\0'; // Ensure the destination string is null-terminated + assert(strcmp(dest, "Hello") == 0); // Verify the string in dest + assert(result == &dest[5]); // Ensure the return pointer points to the null terminator + + // Test 2: Copy 15 characters from src to dest (more than the length of src) + result = stpncpy(dest, src, 15); + dest[13] = '\0'; // Ensure the destination string is null-terminated + assert(strcmp(dest, "Hello, World!") == 0); // Verify the string in dest + assert(result == &dest[13]); // Ensure the return pointer points to the null terminator + + // Test 3: Copy 3 characters from src to dest + result = stpncpy(dest, src, 3); + dest[3] = '\0'; // Ensure the destination string is null-terminated + assert(strcmp(dest, "Hel") == 0); // Verify the string in dest + assert(result == &dest[3]); // Ensure the return pointer points to the null terminator + + // Test 4: Copy 0 characters from src to dest + result = stpncpy(dest, src, 0); + dest[0] = '\0'; // Ensure the destination is explicitly null-terminated + assert(dest[0] == '\0'); // Ensure the destination is an empty string + assert(result == dest); // Ensure the return pointer points to the start of dest + + // Test 5: Copy exactly the length of the source string + result = stpncpy(dest, src, strlen(src)); + dest[strlen(src)] = '\0'; // Ensure the destination string is null-terminated + assert(strcmp(dest, "Hello, World!") == 0); // Verify the string in dest + assert(result == &dest[strlen(src)]); // Ensure the return pointer points to the null terminator + + return 0; +} diff --git a/tests/string/strchrnul.c b/tests/string/strchrnul.c new file mode 100644 index 0000000000..9911e03608 --- /dev/null +++ b/tests/string/strchrnul.c @@ -0,0 +1,31 @@ +#include +#include + + +int main() { + // Test 1: Character is present in the string + const char *str1 = "Hello, World!"; + const char *result1 = strchrnul(str1, 'o'); + assert(result1 == &str1[4]); // 'o' is at position 4 in "Hello, World!" + + // Test 2: Character is not in the string (should return the null terminator) + const char *str2 = "Hello, World!"; + const char *result2 = strchrnul(str2, 'z'); + assert(result2 == &str2[13]); // 'z' is not present, so it returns the null terminator + + // Test 3: Character is the first character in the string + const char *str3 = "abcdef"; + const char *result3 = strchrnul(str3, 'a'); + assert(result3 == &str3[0]); // 'a' is at position 0 + + // Test 4: Character is the last character in the string + const char *str4 = "abcdef"; + const char *result4 = strchrnul(str4, 'f'); + assert(result4 == &str4[5]); // 'f' is at position 5, the last character + + // Test 5: Searching for the null terminator itself + const char *str5 = "abcdef"; + const char *result5 = strchrnul(str5, '\0'); + assert(result5 == &str5[6]); // The null terminator is at position 6 (end of the string) + return 0; +} diff --git a/tests/string/strsep.c b/tests/string/strsep.c new file mode 100644 index 0000000000..bfa6c4a11b --- /dev/null +++ b/tests/string/strsep.c @@ -0,0 +1,68 @@ +#include +#include + +int main() { + // Test case 1: Basic case with multiple tokens + char str1[] = "apple,orange,banana"; + char *delim = ","; + char *token = str1; + char *result = NULL; + + // First token should be "apple" + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "apple") == 0); + + // Second token should be "orange" + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "orange") == 0); + + // Third token should be "banana" + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "banana") == 0); + + // No more tokens + result = strsep(&token, delim); + assert(result == NULL); + + // Test case 2: Empty string + char str2[] = ""; + token = str2; + result = strsep(&token, delim); + + // Test case 3: String with no delimiter + char str3[] = "apple"; + token = str3; + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "apple") == 0); + assert(token == NULL); // No more tokens + + // Test case 4: String starts with delimiter + char str4[] = ",apple,orange"; + token = str4; + result = strsep(&token, delim); + assert(result != NULL && strlen(result) == 0); // First token should be an empty string ("") + + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "apple") == 0); + + // Test case 5: Multiple delimiters in a row + char str5[] = "apple,,orange"; + token = str5; + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "apple") == 0); + result = strsep(&token, delim); + assert(result != NULL && strlen(result) == 0); // Empty token due to consecutive delimiters + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "orange") == 0); + + // Test case 6: Delimiters at the end of the string + char str6[] = "apple,orange,"; + token = str6; + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "apple") == 0); + result = strsep(&token, delim); + assert(result != NULL && strcmp(result, "orange") == 0); + result = strsep(&token, delim); + + return 0; +}