diff --git a/.gitignore b/.gitignore index b83d22266a..431845ed05 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 49bfe11be9..9ab7818826 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -323,8 +323,37 @@ 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 { + // Loosely based on GLIBC implementation + unsafe { + static mut HAYSTACK: *mut c_char = ptr::null_mut(); + if !s1.is_null() { + HAYSTACK = s1; + } else if HAYSTACK.is_null() { + return ptr::null_mut(); + } + + // Skip past any extra delimiter left over from previous call + HAYSTACK = HAYSTACK.add(strspn(HAYSTACK, delimiter)); + if *HAYSTACK == 0 { + HAYSTACK = 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 as c_char); + HAYSTACK = HAYSTACK.add(1); + } else { + HAYSTACK = ptr::null_mut(); + } + + return token; + } + + ptr::null_mut() } #[no_mangle] diff --git a/tests/Makefile b/tests/Makefile index c2aad5593a..c492f3b791 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -29,6 +29,7 @@ EXPECT_BINS=\ string/strspn \ string/strstr \ string/strpbrk \ + string/strtok \ unlink \ waitpid \ write diff --git a/tests/expected/string/strtok.stderr b/tests/expected/string/strtok.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/string/strtok.stdout b/tests/expected/string/strtok.stdout new file mode 100644 index 0000000000..4e58193c85 --- /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. \ No newline at end of file diff --git a/tests/string/strtok.c b/tests/string/strtok.c new file mode 100644 index 0000000000..59abe9eca1 --- /dev/null +++ b/tests/string/strtok.c @@ -0,0 +1,15 @@ +#include +#include + +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); + token = strtok(NULL, " "); + } + + return 0; +}