From f60fafe8fbfd671606ccac9ae16ca60a4dd58c95 Mon Sep 17 00:00:00 2001 From: Timothy Bess Date: Sat, 17 Mar 2018 02:58:08 -0400 Subject: [PATCH 1/5] * create basic strtok * add test and expected output --- .gitignore | 1 + src/string/src/lib.rs | 33 +++++++++++++++++++++++++++-- tests/Makefile | 1 + tests/expected/string/strtok.stderr | 0 tests/expected/string/strtok.stdout | 2 ++ tests/string/strtok.c | 15 +++++++++++++ 6 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/expected/string/strtok.stderr create mode 100644 tests/expected/string/strtok.stdout create mode 100644 tests/string/strtok.c 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; +} From 898cf98ccc56f8e41fb4b0c69359c72cca0045cd Mon Sep 17 00:00:00 2001 From: Timothy Bess Date: Sat, 17 Mar 2018 03:06:59 -0400 Subject: [PATCH 2/5] * fix test case a bit * remove unnecessary cast --- src/string/src/lib.rs | 2 +- tests/expected/string/strtok.stdout | 2 +- tests/string/strtok.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index 9ab7818826..f2bb99ac5d 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -344,7 +344,7 @@ pub extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_ch let token = HAYSTACK; HAYSTACK = strpbrk(token, delimiter); if !HAYSTACK.is_null() { - HAYSTACK.write(0 as c_char); + HAYSTACK.write(0); HAYSTACK = HAYSTACK.add(1); } else { HAYSTACK = ptr::null_mut(); diff --git a/tests/expected/string/strtok.stdout b/tests/expected/string/strtok.stdout index 4e58193c85..201357e8cb 100644 --- a/tests/expected/string/strtok.stdout +++ b/tests/expected/string/strtok.stdout @@ -1,2 +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 +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 index 59abe9eca1..9809fdf054 100644 --- a/tests/string/strtok.c +++ b/tests/string/strtok.c @@ -7,8 +7,10 @@ int main(int argc, char* argv[]) { char* token = strtok(source, " "); while (token) { - printf("%s_", token); - token = strtok(NULL, " "); + printf("%s", token); + if (token = strtok(NULL, " ")) { + printf("_"); + } } return 0; From e91891625fd73a250a2755d66e89745caf633377 Mon Sep 17 00:00:00 2001 From: Timothy Bess Date: Sat, 17 Mar 2018 03:56:40 -0400 Subject: [PATCH 3/5] * add strtok_r --- src/string/src/lib.rs | 37 ++++++++++++++++++++++++--- tests/Makefile | 1 + tests/expected/string/strtok_r.stderr | 0 tests/expected/string/strtok_r.stdout | 2 ++ tests/string/strtok_r.c | 18 +++++++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/expected/string/strtok_r.stderr create mode 100644 tests/expected/string/strtok_r.stdout create mode 100644 tests/string/strtok_r.c diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index f2bb99ac5d..f70fdebb64 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -352,17 +352,46 @@ pub extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_ch return token; } - - ptr::null_mut() } #[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 { + haystack = ptr::null_mut(); + *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 { + haystack = ptr::null_mut(); + *lasts = ptr::null_mut(); + } + + return token; + } } #[no_mangle] diff --git a/tests/Makefile b/tests/Makefile index c492f3b791..ab820592e4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,6 +30,7 @@ EXPECT_BINS=\ string/strstr \ string/strpbrk \ string/strtok \ + string/strtok_r \ unlink \ waitpid \ write diff --git a/tests/expected/string/strtok_r.stderr b/tests/expected/string/strtok_r.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/string/strtok_r.stdout b/tests/expected/string/strtok_r.stdout new file mode 100644 index 0000000000..201357e8cb --- /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_r.c b/tests/string/strtok_r.c new file mode 100644 index 0000000000..36becfe296 --- /dev/null +++ b/tests/string/strtok_r.c @@ -0,0 +1,18 @@ +#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* sp; + + char* token = strtok_r(source, " ", &sp); + while (token) { + printf("%s", token); + if (token = strtok_r(NULL, " ", &sp)) { + printf("_"); + } + } + + return 0; +} From 06de920be6c3b381f5f5d57df32e882d579d22f3 Mon Sep 17 00:00:00 2001 From: Timothy Bess Date: Sat, 17 Mar 2018 12:58:10 -0400 Subject: [PATCH 4/5] * remove unnecessary assignments --- src/string/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index f70fdebb64..c795ee160b 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -373,7 +373,6 @@ pub extern "C" fn strtok_r( // Skip past any extra delimiter left over from previous call haystack = haystack.add(strspn(haystack, delimiter)); if *haystack == 0 { - haystack = ptr::null_mut(); *lasts = ptr::null_mut(); return ptr::null_mut(); } @@ -386,7 +385,6 @@ pub extern "C" fn strtok_r( haystack = haystack.add(1); *lasts = haystack; } else { - haystack = ptr::null_mut(); *lasts = ptr::null_mut(); } From 3a89f66cfd0d00972a8f49fddd0d21d34b0c2748 Mon Sep 17 00:00:00 2001 From: Timothy Bess Date: Sun, 18 Mar 2018 00:05:13 -0400 Subject: [PATCH 5/5] * simplify strtok implementation --- src/string/src/lib.rs | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs index c795ee160b..c97302b92b 100644 --- a/src/string/src/lib.rs +++ b/src/string/src/lib.rs @@ -324,33 +324,9 @@ 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, delimiter: *const c_char) -> *mut c_char { - // Loosely based on GLIBC implementation + static mut HAYSTACK: *mut c_char = ptr::null_mut(); 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); - HAYSTACK = HAYSTACK.add(1); - } else { - HAYSTACK = ptr::null_mut(); - } - - return token; + return strtok_r(s1, delimiter, &mut HAYSTACK); } }