diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c50cc56..ee06d4df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ set(uv_sources src/inet.c src/random.c src/strscpy.c + src/strtok.c src/threadpool.c src/timer.c src/uv-common.c @@ -562,6 +563,7 @@ if(LIBUV_BUILD_TESTS) test/test-spawn.c test/test-stdio-over-pipes.c test/test-strscpy.c + test/test-strtok.c test/test-tcp-alloc-cb-fail.c test/test-tcp-bind-error.c test/test-tcp-bind6-error.c diff --git a/Makefile.am b/Makefile.am index 32fccede..a377759f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,7 +43,9 @@ libuv_la_SOURCES = src/fs-poll.c \ src/uv-data-getter-setters.c \ src/uv-common.c \ src/uv-common.h \ - src/version.c + src/version.c \ + src/strtok.c \ + src/strtok.h if SUNOS # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers @@ -250,6 +252,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-spawn.c \ test/test-stdio-over-pipes.c \ test/test-strscpy.c \ + test/test-strtok.c \ test/test-tcp-alloc-cb-fail.c \ test/test-tcp-bind-error.c \ test/test-tcp-bind6-error.c \ diff --git a/src/strtok.c b/src/strtok.c new file mode 100644 index 00000000..45ddea50 --- /dev/null +++ b/src/strtok.c @@ -0,0 +1,52 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include "strtok.h" + +char* uv__strtok(char* str, const char* sep, char** itr) { + const char* sep_itr; + char* tmp; + char* start; + + if (str == NULL) + start = tmp = *itr; + else + start = tmp = str; + + if (tmp == NULL) + return NULL; + + while (*tmp != '\0') { + sep_itr = sep; + while (*sep_itr != '\0') { + if (*tmp == *sep_itr) { + *itr = tmp + 1; + *tmp = '\0'; + return start; + } + sep_itr++; + } + tmp++; + } + *itr = NULL; + return start; +} diff --git a/src/strtok.h b/src/strtok.h new file mode 100644 index 00000000..3799ff55 --- /dev/null +++ b/src/strtok.h @@ -0,0 +1,27 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_STRTOK_H_ +#define UV_STRTOK_H_ + +char* uv__strtok(char* str, const char* sep, char** itr); + +#endif /* UV_STRTOK_H_ */ diff --git a/src/unix/core.c b/src/unix/core.c index aade3b37..edd457a1 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -20,6 +20,7 @@ #include "uv.h" #include "internal.h" +#include "strtok.h" #include /* NULL */ #include /* printf */ @@ -1546,6 +1547,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { char* cloned_path; char* path_env; char* token; + char* itr; if (buf == NULL || buflen == NULL || *buflen == 0) return UV_EINVAL; @@ -1587,7 +1589,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { if (cloned_path == NULL) return UV_ENOMEM; - token = strtok(cloned_path, ":"); + token = uv__strtok(cloned_path, ":", &itr); while (token != NULL) { snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog); if (realpath(trypath, abspath) == abspath) { @@ -1606,7 +1608,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { return 0; } } - token = strtok(NULL, ":"); + token = uv__strtok(NULL, ":", &itr); } uv__free(cloned_path); diff --git a/test/test-list.h b/test/test-list.h index 3d9bc397..44751658 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -423,6 +423,7 @@ TEST_DECLARE (fs_invalid_mkdir_name) #endif TEST_DECLARE (fs_get_system_error) TEST_DECLARE (strscpy) +TEST_DECLARE (strtok) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -1088,6 +1089,7 @@ TASK_LIST_START TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (open_osfhandle_valid_handle) TEST_ENTRY (strscpy) + TEST_ENTRY (strtok) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 60000) diff --git a/test/test-strtok.c b/test/test-strtok.c new file mode 100644 index 00000000..6c3d8359 --- /dev/null +++ b/test/test-strtok.c @@ -0,0 +1,90 @@ +/* Copyright libuv project contributors. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to +* deal in the Software without restriction, including without limitation the +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +* IN THE SOFTWARE. +*/ + +#include "uv.h" +#include "task.h" +#include + +#include "../src/strtok.h" +#include "../src/strtok.c" + +struct strtok_test_case { + const char* str; + const char* sep; +}; + +const char* tokens[] = { + "abc", + NULL, + + "abc", + "abf", + NULL, + + "This", + "is.a", + "test", + "of", + "the", + "string", + "tokenizer", + "function.", + NULL, + + "Hello", + "This-is-a-nice", + "-string", + NULL +}; + +#define ASSERT_STRCMP(x, y) \ + ASSERT((x != NULL && y != NULL && strcmp(x, y) == 0) || (x == y && x == NULL)) + +TEST_IMPL(strtok) { + struct strtok_test_case tests[] = { + { "abc", "" }, + { "abc.abf", "." }, + { "This;is.a:test:of=the/string\\tokenizer-function.", "\\/:;=-" }, + { "Hello This-is-a-nice.-string", " ." }, + }; + size_t tokens_len = ARRAY_SIZE(tokens); + size_t tests_len = ARRAY_SIZE(tests); + size_t i; + size_t j; + char* itr; + char* tok_r; + char current_test[2048]; + + for (i = 0, j = 0; i < tests_len; i += 1) { + ASSERT(j < tokens_len); + snprintf(current_test, sizeof(current_test), "%s", tests[i].str); + tok_r = uv__strtok(current_test, tests[i].sep, &itr); + ASSERT_STRCMP(tok_r, tokens[j]); + j++; + while (tok_r) { + ASSERT(j < tokens_len); + tok_r = uv__strtok(NULL, tests[i].sep, &itr); + ASSERT_STRCMP(tok_r, tokens[j]); + j++; + } + } + return 0; +}