diff --git a/CMakeLists.txt b/CMakeLists.txt index 65fbc686..b96bfd0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ set(rcutils_sources src/shared_library.c src/snprintf.c src/split.c + src/strcasecmp.c src/strdup.c src/strerror.c src/string_array.c @@ -401,6 +402,13 @@ if(BUILD_TESTING) target_link_libraries(test_snprintf ${PROJECT_NAME}) endif() + rcutils_custom_add_gtest(test_strcasecmp + test/test_strcasecmp.cpp + ) + if(TARGET test_strcasecmp) + target_link_libraries(test_strcasecmp ${PROJECT_NAME}) + endif() + rcutils_custom_add_gtest(test_uint8_array test/test_uint8_array.cpp ) diff --git a/include/rcutils/strcasecmp.h b/include/rcutils/strcasecmp.h new file mode 100644 index 00000000..bdb90649 --- /dev/null +++ b/include/rcutils/strcasecmp.h @@ -0,0 +1,76 @@ +// Copyright 2020 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef RCUTILS__STRCASECMP_H_ +#define RCUTILS__STRCASECMP_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "rcutils/macros.h" +#include "rcutils/visibility_control.h" + +/// Case insensitive string compare. +/** + * This function compares two strings ignoring case in a portable way. + * This performs a byte-by-byte comparison of the strings s1 and s2, + * ignoring the case of the characters. + * + * \param[in] s1 Null terminated string to compare. + * \param[in] s2 Null terminated string to compare. + * \param[out] value Pointer to comparison result. + * An integer less than, equal to, or greater than zero if s1 is, after + * ignoring case, found to be less than, to match, or be greater than s2, + * respectively. + * \return 0 if method succeeded , -1 if failed. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +int +rcutils_strcasecmp( + const char * s1, + const char * s2, + int * value); + +/// Case insensitive string compare up to count characters. +/** + * This function compares two strings ignoring case in a portable way. + * This performs a byte-by-byte comparison of the strings s1 and s2 up to count + * characters of s1 and s2, ignoring the case of the characters. + * + * \param[in] s1 First string to compare. + * \param[in] s2 Second string to compare. + * \param[in] n Count of characters to compare. + * \param[out] value Pointer to comparison result. + * An integer less than, equal to, or greater than zero if s1 is, after + * ignoring case, found to be less than, to match, or be greater than s2, + * respectively. + * \return 0 if method succeeded , -1 if failed. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +int +rcutils_strncasecmp( + const char * s1, + const char * s2, + size_t n, + int * value); + +#ifdef __cplusplus +} +#endif + +#endif // RCUTILS__STRCASECMP_H_ diff --git a/src/strcasecmp.c b/src/strcasecmp.c new file mode 100644 index 00000000..941919a6 --- /dev/null +++ b/src/strcasecmp.c @@ -0,0 +1,62 @@ +// Copyright 2020 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +#include "rcutils/strcasecmp.h" + +int +rcutils_strcasecmp( + const char * s1, + const char * s2, + int * value) +{ + if (s1 == NULL || s2 == NULL || value == NULL) { + return -1; + } +#ifndef _WIN32 + *value = strcasecmp(s1, s2); +#else + *value = _stricmp(s1, s2); +#endif + return 0; +} + +int +rcutils_strncasecmp( + const char * s1, + const char * s2, + size_t n, + int * value) +{ + if (s1 == NULL || s2 == NULL || value == NULL) { + return -1; + } +#ifndef _WIN32 + *value = strncasecmp(s1, s2, n); +#else + *value = _strnicmp(s1, s2, n); +#endif + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/test_strcasecmp.cpp b/test/test_strcasecmp.cpp new file mode 100644 index 00000000..8fc614dc --- /dev/null +++ b/test/test_strcasecmp.cpp @@ -0,0 +1,195 @@ +// Copyright 2020 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "rcutils/strcasecmp.h" + +// Tests the rcutils_strcasecmp() function. +TEST(TestStrcasecmp, test_strcasecmp) { + int value; + EXPECT_EQ(-1, rcutils_strcasecmp(NULL, NULL, NULL)); + EXPECT_EQ(-1, rcutils_strcasecmp(NULL, "", &value)); + EXPECT_EQ(-1, rcutils_strcasecmp("", NULL, &value)); + EXPECT_EQ(-1, rcutils_strcasecmp("", "", NULL)); + EXPECT_EQ(-1, rcutils_strcasecmp(NULL, NULL, &value)); + EXPECT_EQ(-1, rcutils_strcasecmp("", NULL, NULL)); + EXPECT_EQ(-1, rcutils_strcasecmp(NULL, "", NULL)); + + EXPECT_EQ(0, rcutils_strcasecmp("", "", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("ABC", "ABC", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("1abc", "1abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abc1", "abc1", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("1ABC", "1ABC", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("ABC1", "ABC1", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("ABC", "abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "ABC", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("Abc", "abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "Abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("Abc", "Abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("aBc", "abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "aBc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("aBc", "aBc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abC", "abc", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "abC", &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strcasecmp("abC", "abC", &value)); + EXPECT_EQ(0, value); + + EXPECT_EQ(0, rcutils_strcasecmp("", "abc", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abcd", "abc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "abcd", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abcD", "abc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "abcD", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("1abc", "abc", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "1abc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc1", "abc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "abc1", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("ABCd", "abc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "ABCd", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("1Abc", "abc", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "1Abc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("a1Bc", "abc", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "a1Bc", &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("ab1C", "abc", &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strcasecmp("abc", "ab1C", &value)); + EXPECT_GT(value, 0); +} + +// Tests the rcutils_strncasecmp() function. +TEST(TestStrcasecmp, test_strncasecmp) { + int value; + EXPECT_EQ(-1, rcutils_strncasecmp(NULL, NULL, 0, NULL)); + EXPECT_EQ(-1, rcutils_strncasecmp(NULL, "", 1, &value)); + EXPECT_EQ(-1, rcutils_strncasecmp("", NULL, 1, &value)); + EXPECT_EQ(-1, rcutils_strncasecmp("", "", 1, NULL)); + EXPECT_EQ(-1, rcutils_strncasecmp(NULL, NULL, 0, &value)); + EXPECT_EQ(-1, rcutils_strncasecmp("", NULL, 0, NULL)); + EXPECT_EQ(-1, rcutils_strncasecmp(NULL, "", 0, NULL)); + + EXPECT_EQ(0, rcutils_strncasecmp("", "", 0, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("", "", 1, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "", 0, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("", "abc", 0, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "abc", 3, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("ABC", "ABC", 3, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("1abc", "1abc", 4, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc1", "abc1", 4, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("1ABC", "1ABC", 4, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("ABC1", "ABC1", 4, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("ABC", "abc", 1, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "ABC", 1, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("Abc", "abc", 2, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "Abc", 2, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("Abc", "Abc", 2, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("aBc", "abc", 3, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "aBc", 3, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("aBc", "aBc", 3, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abC", "abc", 4, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "abC", 4, &value)); + EXPECT_EQ(0, value); + EXPECT_EQ(0, rcutils_strncasecmp("abC", "abC", 4, &value)); + EXPECT_EQ(0, value); + + EXPECT_EQ(0, rcutils_strncasecmp("", "abc", 1, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "", 1, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abcd", "abc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "abcd", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abcD", "abc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "abcD", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("1abc", "abc", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "1abc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc1", "abc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "abc1", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("ABCd", "abc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "ABCd", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("1Abc", "abc", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "1Abc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("a1Bc", "abc", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "a1Bc", 4, &value)); + EXPECT_GT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("ab1C", "abc", 4, &value)); + EXPECT_LT(value, 0); + EXPECT_EQ(0, rcutils_strncasecmp("abc", "ab1C", 4, &value)); + EXPECT_GT(value, 0); +}