diff --git a/.gitignore b/.gitignore index b83d22266ac8aa2f8df2edef68082c789727841d..431845ed05927f3a23c9b23d4ae3d7a2626dd668 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target/ +.idea/ diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index 49bfe11be989518b266ec96e7942e38a3c819ad2..c97302b92bf44cefacf6f081c32275c5dc8ecb70 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -323,17 +323,49 @@ pub unsafe extern "C" fn strstr(s1: *const c_char, s2: *const c_char) -> *mut c_ } #[no_mangle] -pub extern "C" fn strtok(s1: *mut c_char, s2: *const c_char) -> *mut c_char { - unimplemented!(); +pub extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char { + static mut HAYSTACK: *mut c_char = ptr::null_mut(); + unsafe { + return strtok_r(s1, delimiter, &mut HAYSTACK); + } } #[no_mangle] pub extern "C" fn strtok_r( s: *mut c_char, - sep: *const c_char, + delimiter: *const c_char, lasts: *mut *mut c_char, ) -> *mut c_char { - unimplemented!(); + // Loosely based on GLIBC implementation + unsafe { + let mut haystack = s; + if haystack.is_null() { + if (*lasts).is_null() { + return ptr::null_mut(); + } + haystack = *lasts; + } + + // Skip past any extra delimiter left over from previous call + haystack = haystack.add(strspn(haystack, delimiter)); + if *haystack == 0 { + *lasts = ptr::null_mut(); + return ptr::null_mut(); + } + + // Build token by injecting null byte into delimiter + let token = haystack; + haystack = strpbrk(token, delimiter); + if !haystack.is_null() { + haystack.write(0); + haystack = haystack.add(1); + *lasts = haystack; + } else { + *lasts = ptr::null_mut(); + } + + return token; + } } #[no_mangle] diff --git a/tests/Makefile b/tests/Makefile index 8dffd5edd5a88d3e05a1954db86492691ce7c3eb..e1b95b1839e1a3d66a2333907fb0470059a5bf99 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,6 +30,8 @@ EXPECT_BINS=\ string/strspn \ string/strstr \ string/strpbrk \ + string/strtok \ + string/strtok_r \ unlink \ waitpid \ write diff --git a/tests/expected/string/strtok.stderr b/tests/expected/string/strtok.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/string/strtok.stdout b/tests/expected/string/strtok.stdout new file mode 100644 index 0000000000000000000000000000000000000000..201357e8cbf62d9b06cde1d92cb068ae08b42c89 --- /dev/null +++ b/tests/expected/string/strtok.stdout @@ -0,0 +1,2 @@ +I'd_just_like_to_interject_for_a_moment.__What_you're_referring_to_as_Linux, +is_in_fact,_GNU/Linux,_or_as_I've_recently_taken_to_calling_it,_GNU_plus_Linux. diff --git a/tests/expected/string/strtok_r.stderr b/tests/expected/string/strtok_r.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/string/strtok_r.stdout b/tests/expected/string/strtok_r.stdout new file mode 100644 index 0000000000000000000000000000000000000000..201357e8cbf62d9b06cde1d92cb068ae08b42c89 --- /dev/null +++ b/tests/expected/string/strtok_r.stdout @@ -0,0 +1,2 @@ +I'd_just_like_to_interject_for_a_moment.__What_you're_referring_to_as_Linux, +is_in_fact,_GNU/Linux,_or_as_I've_recently_taken_to_calling_it,_GNU_plus_Linux. diff --git a/tests/string/strtok.c b/tests/string/strtok.c new file mode 100644 index 0000000000000000000000000000000000000000..9809fdf054f4ca51c77a657e3d30e86af60d5ace --- /dev/null +++ b/tests/string/strtok.c @@ -0,0 +1,17 @@ +#include <string.h> +#include <stdio.h> + +int main(int argc, char* argv[]) { + char source[] = "I'd just like to interject for a moment. What you're referring to as Linux, " + "is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux.\n"; + + char* token = strtok(source, " "); + while (token) { + printf("%s", token); + if (token = strtok(NULL, " ")) { + printf("_"); + } + } + + return 0; +} diff --git a/tests/string/strtok_r.c b/tests/string/strtok_r.c new file mode 100644 index 0000000000000000000000000000000000000000..36becfe2969093dcd80246a1dcef0b03a0892770 --- /dev/null +++ b/tests/string/strtok_r.c @@ -0,0 +1,18 @@ +#include <string.h> +#include <stdio.h> + +int main(int argc, char* argv[]) { + char source[] = "I'd just like to interject for a moment. What you're referring to as Linux, " + "is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux.\n"; + char* sp; + + char* token = strtok_r(source, " ", &sp); + while (token) { + printf("%s", token); + if (token = strtok_r(NULL, " ", &sp)) { + printf("_"); + } + } + + return 0; +}