This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/refactor_bundle_cache in repository https://gitbox.apache.org/repos/asf/celix.git
commit 16b119bdaec1270602573cc9393ea5d589d0da61 Author: Pepijn Noltes <[email protected]> AuthorDate: Tue Jan 31 21:18:32 2023 +0100 Improve utils lib with string convert, file touch and file modified functions. Also moves some cpputest to gtests --- libs/framework/src/celix_errorcodes.c | 2 + libs/utils/CMakeLists.txt | 7 +- libs/utils/gtest/CMakeLists.txt | 2 + libs/utils/gtest/src/CelixUtilsTestSuite.cc | 317 +++++++++++++++++++++ libs/utils/gtest/src/ConvertUtilsTestSuite.cc | 159 +++++++++++ libs/utils/include/celix_convert_utils.h | 80 ++++++ libs/utils/include/celix_file_utils.h | 18 ++ libs/utils/include/celix_threads.h | 6 + libs/utils/include/celix_utils.h | 42 +++ libs/utils/private/test/utils_test.cpp | 383 -------------------------- libs/utils/src/celix_convert_utils.c | 99 +++++++ libs/utils/src/celix_file_utils.c | 27 +- libs/utils/src/utils.c | 63 ++++- 13 files changed, 809 insertions(+), 396 deletions(-) diff --git a/libs/framework/src/celix_errorcodes.c b/libs/framework/src/celix_errorcodes.c index 9879a829..d3a01eb6 100644 --- a/libs/framework/src/celix_errorcodes.c +++ b/libs/framework/src/celix_errorcodes.c @@ -42,6 +42,8 @@ const char* celix_strerror(celix_status_t status) { return "File I/O exception"; case CELIX_SERVICE_EXCEPTION: return "Service exception"; + case CELIX_ENOMEM: + return "Out of memory"; default: return "Unknown code"; } diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index d1aa4bdc..ff498e66 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(utils SHARED src/celix_log_utils.c src/celix_hash_map.c src/celix_file_utils.c + src/celix_convert_utils.c ${MEMSTREAM_SOURCES} ) set_target_properties(utils PROPERTIES OUTPUT_NAME "celix_utils") @@ -118,10 +119,6 @@ if (ENABLE_TESTING) target_include_directories(properties_test PRIVATE include_deprecated) target_link_libraries(properties_test CppUTest::CppUTest CppUTest::CppUTestExt Celix::utils pthread) - add_executable(utils_test private/test/utils_test.cpp) - target_include_directories(utils_test PRIVATE include_deprecated) - target_link_libraries(utils_test CppUTest::CppUTest Celix::utils pthread) - add_executable(ip_utils_test private/test/ip_utils_test.cpp) target_include_directories(ip_utils_test PRIVATE include_deprecated) target_link_libraries(ip_utils_test CppUTest::CppUTest Celix::utils pthread) @@ -141,7 +138,6 @@ if (ENABLE_TESTING) add_test(NAME run_celix_threads_test COMMAND celix_threads_test) add_test(NAME run_linked_list_test COMMAND linked_list_test) add_test(NAME run_properties_test COMMAND properties_test) - add_test(NAME run_utils_test COMMAND utils_test) add_test(NAME run_ip_utils_test COMMAND ip_utils_test) add_test(NAME filter_test COMMAND filter_test) add_test(NAME version_test COMMAND version_test) @@ -151,7 +147,6 @@ if (ENABLE_TESTING) setup_target_for_coverage(celix_threads_test) setup_target_for_coverage(linked_list_test) setup_target_for_coverage(properties_test) - setup_target_for_coverage(utils_test) setup_target_for_coverage(ip_utils_test) setup_target_for_coverage(filter_test) setup_target_for_coverage(version_test) diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index 7440357c..4b871129 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -30,6 +30,8 @@ add_executable(test_utils src/HashMapTestSuite.cc src/ArrayListTestSuite.cc src/FileUtilsTestSuite.cc + src/CelixUtilsTestSuite.cc + src/ConvertUtilsTestSuite.cc ${CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS} ) diff --git a/libs/utils/gtest/src/CelixUtilsTestSuite.cc b/libs/utils/gtest/src/CelixUtilsTestSuite.cc new file mode 100644 index 00000000..de2a78a5 --- /dev/null +++ b/libs/utils/gtest/src/CelixUtilsTestSuite.cc @@ -0,0 +1,317 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <gtest/gtest.h> + +#include "celix_utils.h" +#include "utils.h" + +class UtilsTestSuite : public ::testing::Test { +public: +}; + + +TEST_F(UtilsTestSuite, CompareServiceIdsAndRankingTest){ + int ret; + //service 1 is higher ranked and has a irrelevant ID, so result is -1 (smaller -> sorted before service 2) + ret = celix_utils_compareServiceIdsAndRanking(2,2,1,1); + EXPECT_EQ(-1, ret); + + //service 1 is equally ranked and has a lower ID. so result is -1 (smaller -> sorted before service 2) + ret = celix_utils_compareServiceIdsAndRanking(1,1,2,1); + EXPECT_EQ(-1, ret); + + //service 1 is equally ranked and has a higher ID, so result is 1 (larger -> sorted after service 2) + ret = celix_utils_compareServiceIdsAndRanking(2,1,1,1); + EXPECT_EQ(1, ret); + + //service 1 is lower ranked and has a irrelevant ID, so result is -1 (larger -> sorted after service 2) + ret = celix_utils_compareServiceIdsAndRanking(1,1,2,2); + EXPECT_EQ(1, ret); + + //service 1 is equal in ID and irrelevantly ranked + //note ensure that also the call without celix_ is tested + ret = celix_utils_compareServiceIdsAndRanking(1,1,1,1); + EXPECT_EQ(0, ret); + + +} + +TEST_F(UtilsTestSuite, ExtractLocalNameAndNamespaceTest) { + const char *input = "lb"; + char* name = nullptr; + char *ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "::", &name, &ns); + EXPECT_STREQ("lb", name); + EXPECT_TRUE(ns == nullptr); + free(name); + free(ns); + + input = "celix::lb"; + name = nullptr; + ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "::", &name, &ns); + EXPECT_STREQ("lb", name); + EXPECT_STREQ("celix", ns); + free(name); + free(ns); + + input = "celix::extra::namespace::entries::lb"; + name = nullptr; + ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "::", &name, &ns); + EXPECT_STREQ("lb", name); + EXPECT_STREQ("celix::extra::namespace::entries", ns); + free(name); + free(ns); + + input = "celix.extra.namespace.entries.lb"; + name = nullptr; + ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, ".", &name, &ns); + EXPECT_STREQ("lb", name); + EXPECT_STREQ("celix.extra.namespace.entries", ns); + free(name); + free(ns); + + //testing with non existing namespace + input = "celix.extra.namespace.entries.lb"; + name = nullptr; + ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "??", &name, &ns); + EXPECT_STREQ("celix.extra.namespace.entries.lb", name); + EXPECT_TRUE(ns == nullptr); + free(name); + free(ns); + + //wrong input check + input = nullptr; + name = nullptr; + ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "??", &name, &ns); + EXPECT_TRUE(name == nullptr); + EXPECT_TRUE(ns == nullptr); + free(name); + free(ns); + + + //empty namespace check + input = "celix.extra.namespace.entries.lb"; + name = nullptr; + ns = nullptr; + celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "", &name, &ns); + EXPECT_STREQ("celix.extra.namespace.entries.lb", name); + EXPECT_TRUE(ns == nullptr); + free(name); + free(ns); +} + +TEST_F(UtilsTestSuite, IsStringnullptrOrEmptyTest) { + bool empty = celix_utils_isStringNullOrEmpty(nullptr); + EXPECT_TRUE(empty); + empty = celix_utils_isStringNullOrEmpty(""); + EXPECT_TRUE(empty); + empty = celix_utils_isStringNullOrEmpty(" "); + EXPECT_FALSE(empty); + empty = celix_utils_isStringNullOrEmpty("foo"); + EXPECT_FALSE(empty); +} + +TEST_F(UtilsTestSuite, ContainsWhitespaceTest) { + EXPECT_FALSE(celix_utils_containsWhitespace(nullptr)); + EXPECT_FALSE(celix_utils_containsWhitespace("")); + EXPECT_TRUE(celix_utils_containsWhitespace(" ")); + EXPECT_FALSE(celix_utils_containsWhitespace("abcd")); + EXPECT_TRUE(celix_utils_containsWhitespace("ab cd")); + EXPECT_TRUE(celix_utils_containsWhitespace("ab\tcd")); + EXPECT_TRUE(celix_utils_containsWhitespace("ab\ncd")); + EXPECT_TRUE(celix_utils_containsWhitespace("abcd ")); +} + +TEST_F(UtilsTestSuite, MakeCIdentifierTest) { + //When a string is already a c identifier the result is equal to the input + char* id = celix_utils_makeCIdentifier("abcd"); + EXPECT_STREQ(id, "abcd"); + free(id); + + //When a string is already a c identifier the result is equal to the input + id = celix_utils_makeCIdentifier("abcdABCD1234"); + EXPECT_STREQ(id, "abcdABCD1234"); + free(id); + + //When a string start with a digit a _ is prefixed + id = celix_utils_makeCIdentifier("1234abcdABCD"); + EXPECT_STREQ(id, "_1234abcdABCD"); + free(id); + + //When a string contains non isalnum characters, those are replaced with _ + id = celix_utils_makeCIdentifier("$%ab \tcd^&"); + EXPECT_STREQ(id, "__ab__cd__"); + free(id); + + //When a string is empty or null, null will be returned + EXPECT_EQ(celix_utils_makeCIdentifier(nullptr), nullptr); + EXPECT_EQ(celix_utils_makeCIdentifier(""), nullptr); +} + + +TEST_F(UtilsTestSuite, StringHashTest) { + + + unsigned long hash = celix_utils_stringHash("abc"); + EXPECT_EQ(193485963, hash); + + hash = celix_utils_stringHash("abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"); + EXPECT_EQ(1532304168, hash); + + hash = celix_utils_stringHash(nullptr); + EXPECT_EQ(0, hash); + + //test deprecated api + hash = utils_stringHash("abc"); + EXPECT_EQ(193485963, hash); +} + +TEST_F(UtilsTestSuite, StringEqualsTest) { + //refactor StringEqualsTest to use gtest methods instead of cpputest + EXPECT_TRUE(celix_utils_stringEquals("abc", "abc")); + EXPECT_FALSE(celix_utils_stringEquals("abc", "def")); + EXPECT_FALSE(celix_utils_stringEquals("abc", nullptr)); + EXPECT_FALSE(celix_utils_stringEquals(nullptr, "abc")); + EXPECT_TRUE(celix_utils_stringEquals(nullptr, nullptr)); + EXPECT_TRUE(celix_utils_stringEquals("", "")); + EXPECT_FALSE(celix_utils_stringEquals("", nullptr)); + + //test deprecated api + EXPECT_TRUE(utils_stringEquals("abc", "abc")); +} + +TEST_F(UtilsTestSuite, IsNumericTest) { + //test deprecated api + + // Check numeric string + bool result; + celix_status_t status = utils_isNumeric("42", &result); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_TRUE(result); + + // Check non numeric string + status = utils_isNumeric("42b", &result); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_FALSE(result); +} + +TEST_F(UtilsTestSuite, ThreadEqualSelfTest) { + celix_thread thread = celixThread_self(); + bool equal; + + celix_status_t status = thread_equalsSelf(thread, &equal); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_TRUE(equal); + + + thread.thread = (pthread_t) 0x42; + status = thread_equalsSelf(thread, &equal); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_FALSE(equal); +} + +TEST_F(UtilsTestSuite, StringTrimTest) { + // Multiple whitespaces, before, after and in between + auto* trimmed = celix_utils_trim(" a b c "); + EXPECT_STREQ("a b c", trimmed); + free(trimmed); + + // No whitespaces + trimmed = celix_utils_trim("abc"); + EXPECT_STREQ("abc", trimmed); + free(trimmed); + + // Only whitespace before + trimmed = celix_utils_trim(" \tabc"); + EXPECT_STREQ("abc", trimmed); + free(trimmed); + + // Only whitespace after + trimmed = celix_utils_trim("abc \t"); + EXPECT_STREQ("abc", trimmed); + free(trimmed); + + // Whitespace other than space (tab, cr..). + trimmed = celix_utils_trim("\tabc \n asdf \n"); + EXPECT_STREQ("abc \n asdf", trimmed); + free(trimmed); + + // Empty string + trimmed = utils_stringTrim(celix_utils_strdup(" abc ")); + EXPECT_STREQ("abc", trimmed); + free(trimmed); +} + +TEST_F(UtilsTestSuite, StringNBdupTest){ + // test deprecated api + + // Compare with equal strings + const char * org = "abc"; + char * cmp = nullptr; + + cmp = string_ndup(org, 3); + EXPECT_STREQ(org, cmp); + free(cmp); + + org = "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"; + cmp = string_ndup(org, 50); + EXPECT_STREQ(org, cmp); + free(cmp); + + cmp = string_ndup(org, 25); + EXPECT_EQ(25, strlen(cmp)); + free(cmp); +} + +TEST_F(UtilsTestSuite, WriteOrCreateStringTest) { + //Buffer big enough, write to stack buffer + char buffer[16]; + char* out = celix_utils_writeOrCreateString(buffer, sizeof(buffer), "abc"); + EXPECT_EQ(buffer, out); + EXPECT_STREQ("abc", out); + celix_utils_freeStringIfNeeded(buffer, out); + + //Buffer not big enough, malloc new string + out = celix_utils_writeOrCreateString(buffer, sizeof(buffer), "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"); + EXPECT_NE(buffer, out); + EXPECT_STREQ("abc123def456ghi789jkl012mno345pqr678stu901vwx234yz", out); + celix_utils_freeStringIfNeeded(buffer, out); + + //same test, but with long, int and short format args + //Buffer big enough, write to stack buffer + char buffer2[64]; + char* out2 = celix_utils_writeOrCreateString(buffer2, sizeof(buffer2), "long %ld, int %d, short %hd", 1234567890L, 123456789, (short)12345); + EXPECT_EQ(buffer2, out2); + EXPECT_STREQ("long 1234567890, int 123456789, short 12345", out2); + celix_utils_freeStringIfNeeded(buffer2, out2); + + //Buffer not big enough, malloc new string + out2 = celix_utils_writeOrCreateString(buffer2, sizeof(buffer2), "long %ld, int %d, short %hd. abc123def456ghi789jkl012mno345pqr678stu901vwx234yz", 1234567890123456789L, 123456789, (short)12345); + EXPECT_NE(buffer2, out2); + EXPECT_STREQ("long 1234567890123456789, int 123456789, short 12345. abc123def456ghi789jkl012mno345pqr678stu901vwx234yz", out2); + celix_utils_freeStringIfNeeded(buffer2, out2); +} + + diff --git a/libs/utils/gtest/src/ConvertUtilsTestSuite.cc b/libs/utils/gtest/src/ConvertUtilsTestSuite.cc new file mode 100644 index 00000000..5754d1af --- /dev/null +++ b/libs/utils/gtest/src/ConvertUtilsTestSuite.cc @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <gtest/gtest.h> + +#include "celix_convert_utils.h" + +class ConvertUtilsTestSuite : public ::testing::Test { +public: + void checkVersion(const celix_version_t* version, int major, int minor, int micro, const char* qualifier) { + EXPECT_TRUE(version != nullptr); + if (version) { + EXPECT_EQ(major, celix_version_getMajor(version)); + EXPECT_EQ(minor, celix_version_getMinor(version)); + EXPECT_EQ(micro, celix_version_getMicro(version)); + if (qualifier) { + EXPECT_STREQ(qualifier, celix_version_getQualifier(version)); + } else { + EXPECT_STREQ("", celix_version_getQualifier(version)); + } + } + } +}; + +TEST_F(ConvertUtilsTestSuite, ConvertToLongTest) { + bool converted; + //test for a valid string + long result = celix_utils_convertStringToLong("10", 0, &converted); + EXPECT_EQ(10, result); + EXPECT_TRUE(converted); + + //test for an invalid string + result = celix_utils_convertStringToLong("A", 0, &converted); + EXPECT_EQ(0, result); + EXPECT_FALSE(converted); + + //test for a string with a number + result = celix_utils_convertStringToLong("10A", 0, &converted); + EXPECT_EQ(10, result); + EXPECT_TRUE(converted); + + //test for a string with a number and a negative sign + result = celix_utils_convertStringToLong("-10", 0, &converted); + EXPECT_EQ(-10, result); + EXPECT_TRUE(converted); + + //test for a string with a number and a positive sign + result = celix_utils_convertStringToLong("+10", 0, &converted); + EXPECT_EQ(10, result); + EXPECT_TRUE(converted); + + //test for a convert with a nullptr for the converted parameter + result = celix_utils_convertStringToLong("10", 0, nullptr); + EXPECT_EQ(10, result); +} + +TEST_F(ConvertUtilsTestSuite, ConvertToDoubleTest) { + bool converted; + //test for a valid string + double result = celix_utils_convertStringToDouble("10.5", 0, &converted); + EXPECT_EQ(10.5, result); + EXPECT_TRUE(converted); + + //test for an invalid string + result = celix_utils_convertStringToDouble("A", 0, &converted); + EXPECT_EQ(0, result); + EXPECT_FALSE(converted); + + //test for a string with a number + result = celix_utils_convertStringToDouble("10.5A", 0, &converted); + EXPECT_EQ(10.5, result); + EXPECT_TRUE(converted); + + //test for a string with a number and a negative sign + result = celix_utils_convertStringToDouble("-10.5", 0, &converted); + EXPECT_EQ(-10.5, result); + EXPECT_TRUE(converted); + + //test for a string with a number and a positive sign + result = celix_utils_convertStringToDouble("+10.5", 0, &converted); + EXPECT_EQ(10.5, result); + EXPECT_TRUE(converted); + + //test for a string with a scientific notation + result = celix_utils_convertStringToDouble("1.0e-10", 0, &converted); + EXPECT_EQ(1.0e-10, result); + EXPECT_TRUE(converted); + + //test for a convert with a nullptr for the converted parameter + result = celix_utils_convertStringToDouble("10.5", 0, nullptr); + EXPECT_EQ(10.5, result); +} + +TEST_F(ConvertUtilsTestSuite, ConvertToBoolTest) { + bool converted; + //test for a valid string + bool result = celix_utils_convertStringToBool("true", false, &converted); + EXPECT_EQ(true, result); + EXPECT_TRUE(converted); + + //test for an invalid string + result = celix_utils_convertStringToBool("A", false, &converted); + EXPECT_EQ(false, result); + EXPECT_FALSE(converted); + + //test for a almost valid string + result = celix_utils_convertStringToBool("trueA", false, &converted); + EXPECT_EQ(false, result); + EXPECT_FALSE(converted); + + //test for a almost valid string + result = celix_utils_convertStringToBool("falseA", true, &converted); + EXPECT_EQ(true, result); + EXPECT_FALSE(converted); + + //test for a convert with a nullptr for the converted parameter + result = celix_utils_convertStringToBool("true", false, nullptr); + EXPECT_EQ(true, result); +} + +TEST_F(ConvertUtilsTestSuite, ConvertToVersionTest) { + //test for a valid string + celix_version_t* result = celix_utils_convertStringToVersion("1.2.3"); + checkVersion(result, 1, 2, 3, nullptr); + celix_version_destroy(result); + + //test for an invalid string + result = celix_utils_convertStringToVersion("A"); + EXPECT_EQ(nullptr, result); + + //test for a string with a number + result = celix_utils_convertStringToVersion("1.2.3.A"); + checkVersion(result, 1, 2, 3, "A"); + celix_version_destroy(result); + + //test for a string with a partly (strict) version + result = celix_utils_convertStringToVersion("1"); + EXPECT_EQ(nullptr, result); + + //test for a string with a partly (strict) version + result = celix_utils_convertStringToVersion("1.2"); + EXPECT_EQ(nullptr, result); +} \ No newline at end of file diff --git a/libs/utils/include/celix_convert_utils.h b/libs/utils/include/celix_convert_utils.h new file mode 100644 index 00000000..3d5101b0 --- /dev/null +++ b/libs/utils/include/celix_convert_utils.h @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 CELIX_CELIX_CONVERT_UTILS_H +#define CELIX_CELIX_CONVERT_UTILS_H + +#include <stdbool.h> +#include "celix_version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file celix_convert_utils.h + * @brief The celix_convert_utils.h file contains utility functions to convert strings to other types. + */ + +/** + * @brief Convert a string to a boolean. + * + * @param[in] val The string to convert. + * @param[in] defaultValue The default value if the string is not a valid boolean. + * @param[out] converted If not NULL, will be set to true if the string is a valid boolean, otherwise false. + * @return The boolean value. + */ +bool celix_utils_convertStringToBool(const char* val, bool defaultValue, bool* converted); + +/** + * @brief Convert a string to a double. + * + * @param[in] val The string to convert. + * @param[in] defaultValue The default value if the string is not a valid double. + * @param[out] converted If not NULL, will be set to true if the string is a valid double, otherwise false. + * @return The double value. + */ +double celix_utils_convertStringToDouble(const char* val, double defaultValue, bool* converted); + +/** + * @brief Convert a string to a long. + * + * @param[in] val The string to convert. + * @param[in] defaultValue The default value if the string is not a valid long. + * @param[out] converted If not NULL, will be set to true if the string is a valid long, otherwise false. + * @return The long value. + */ +long celix_utils_convertStringToLong(const char* val, long defaultValue, bool* converted); + +/** + * @brief Convert a string to a celix_version_t. + * + * @note This convert function will only convert version strings in the format major.minor.micro(.qualifier)?. + * So the major, minor and micro are required, the qualifier is optional. + * + * @param val The string to convert. + * @return A new celix_version_t* if the string is a valid version, otherwise NULL. + */ +celix_version_t* celix_utils_convertStringToVersion(const char* val); + +#ifdef __cplusplus +} +#endif + +#endif //CELIX_CELIX_CONVERT_UTILS_H diff --git a/libs/utils/include/celix_file_utils.h b/libs/utils/include/celix_file_utils.h index 6524ed3d..4f4dc84e 100644 --- a/libs/utils/include/celix_file_utils.h +++ b/libs/utils/include/celix_file_utils.h @@ -21,6 +21,7 @@ #define CELIX_FILE_UTILS_H #include <stdbool.h> +#include <sys/time.h> #include "celix_errno.h" #ifdef __cplusplus @@ -81,6 +82,23 @@ celix_status_t celix_utils_extractZipFile(const char* zipPath, const char* extra */ celix_status_t celix_utils_extractZipData(const void *zipData, size_t zipDataSize, const char* extractToDir, const char** errorOut); +/** + * @brief Returns the last modified time of the file at path. + * + * @param[in] path The path to the file. + * @param[out] lastModified The last modified time of the file. + * @return CELIX_SUCCESS if the last modified time was successfully retrieved. + */ +celix_status_t celix_utils_getLastModified(const char* path, struct timespec* lastModified); + +/** + * @brief Touch the file at path and thus update the last modified time. + * @param path The path to the file. + * @return CELIX_SUCCESS if the last modified time was successfully updated. + */ +celix_status_t celix_utils_touch(const char* path); + + #ifdef __cplusplus } #endif diff --git a/libs/utils/include/celix_threads.h b/libs/utils/include/celix_threads.h index ba02bfd0..f9458cba 100644 --- a/libs/utils/include/celix_threads.h +++ b/libs/utils/include/celix_threads.h @@ -69,6 +69,12 @@ celix_status_t celixThread_kill(celix_thread_t thread, int sig); celix_thread_t celixThread_self(void); +/** + * Return true - as int - if the threads are equals + * @param[in] thread1 + * @param[in] thread2 + * @return non-zero if the thread IDs t1 and t2 correspond to the same thread, otherwise it will return zero. + */ int celixThread_equals(celix_thread_t thread1, celix_thread_t thread2); bool celixThread_initialized(celix_thread_t thread); diff --git a/libs/utils/include/celix_utils.h b/libs/utils/include/celix_utils.h index e0db2731..14ac0307 100644 --- a/libs/utils/include/celix_utils.h +++ b/libs/utils/include/celix_utils.h @@ -46,11 +46,42 @@ char* celix_utils_strdup(const char *str); */ unsigned int celix_utils_stringHash(const char* string); +/** + * The proposed buffer size to use for celix_utils_writeOrCreateString with a buffer on the stcck. + */ +#define CELIX_DEFAULT_STRING_CREATE_BUFFER_SIZE 512 + +/**` + * @brief Format a string to the provided buffer or a newly allocated buffer if the provided buffer is to small. + * @param[in,out] buffer The buffer to write the formatted string to. + * @param[in] bufferSize The size of the buffer. + * @param[in] format The format string. + * @param[in] ... The arguments for the format string. + * @return The formatted string in the provided buffer or a newly allocated buffer if the provided buffer is to small. + */ +char* celix_utils_writeOrCreateString(char* buffer, size_t bufferSize, const char* format, ...) + __attribute__((format(printf, 3, 4))); + +/** + * @brief Free the provided str if the str is not equal to the provided buffer. + * @note This function is useful combined with celix_utils_writeOrCreateString. + * @param buffer The buffer to compare the str to. + * @param str The string to free if it is not equal to the buffer. + */ +void celix_utils_freeStringIfNeeded(const char* buffer, char* str); + + /** * @brief Compares two strings and returns true if the strings are equal. */ bool celix_utils_stringEquals(const char* a, const char* b); +/** + * Check if the provided string contains a whitespace (spaces, tabs, etc). + * The check is based on `isspace`. + */ +bool celix_utils_containsWhitespace(const char* s); + /** * @brief Returns a trimmed string. * @@ -64,6 +95,17 @@ char* celix_utils_trim(const char* string); */ bool celix_utils_isStringNullOrEmpty(const char* s); +/** @brief create a C identifier from the provided string by replacing each non-alphanumeric character with a + * underscore. + * + * If the first character is a digit, a prefix underscore will also be added. + * Will return NULL if the input is NULL or an empty string. + * + * @param string the input string to make a C identifier for. + * @return new newly allocated string or NULL if the input was wrong. The caller is owner of the returned string. + */ +char* celix_utils_makeCIdentifier(const char* s); + /** * @brief Extract a local name and namespace from a fully qualified name using the provided namespace separator. diff --git a/libs/utils/private/test/utils_test.cpp b/libs/utils/private/test/utils_test.cpp deleted file mode 100644 index 0bd37172..00000000 --- a/libs/utils/private/test/utils_test.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 "string.h" -#include <stdlib.h> -#include <string.h> - -#include "CppUTest/TestHarness.h" -#include "CppUTest/TestHarness_c.h" -#include "CppUTest/CommandLineTestRunner.h" -#include "celix_utils.h" - -extern "C" -{ -#include "utils.h" -} - -int main(int argc, char** argv) { - MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); - return RUN_ALL_TESTS(argc, argv); -} - -TEST_GROUP(utils) { - - void setup(void) { - } - - void teardown() { - } -}; - -static char* my_strdup(const char* s){ - if(s==NULL){ - return NULL; - } - - size_t len = strlen(s); - - char *d = (char*) calloc (len + 1,sizeof(char)); - - if (d == NULL){ - return NULL; - } - - strncpy (d,s,len); - return d; -} - -TEST(utils, stringHash) { - char * toHash = my_strdup("abc"); - unsigned int hash; - hash = utils_stringHash((void *) toHash); - LONGS_EQUAL(193485963, hash); - - free(toHash); - toHash = my_strdup("abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"); - hash = utils_stringHash((void *) toHash); - LONGS_EQUAL(1532304168, hash); - - free(toHash); - toHash = my_strdup("abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"); - hash = utils_stringHash((void *) toHash); - LONGS_EQUAL(3721605959, hash); - free(toHash); - - hash = utils_stringHash(NULL); - LONGS_EQUAL(0, hash); -} - -TEST(utils, stringEquals) { - // Compare with equal strings - char * org = my_strdup("abc"); - char * cmp = my_strdup("abc"); - - int result = utils_stringEquals((void *) org, (void *) cmp); - CHECK(result); - - // Compare with no equal strings - free(cmp); - cmp = my_strdup("abcd"); - - result = utils_stringEquals((void *) org, (void *) cmp); - CHECK_FALSE(result); - - // Compare with numeric strings - free(org); - free(cmp); - org = my_strdup("123"); - cmp = my_strdup("123"); - - result = utils_stringEquals((void *) org, (void *) cmp); - CHECK(result); - - // Compare with long strings - free(org); - free(cmp); - org = my_strdup("abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"); - cmp = my_strdup("abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"); - - result = utils_stringEquals((void *) org, (void *) cmp); - CHECK(result); - - free(org); - free(cmp); -} - -TEST(utils, string_ndup){ - // Compare with equal strings - const char * org = "abc"; - char * cmp = NULL; - - cmp = string_ndup(org, 3); - STRCMP_EQUAL(org, cmp); - free(cmp); - - org = "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"; - cmp = string_ndup(org, 50); - STRCMP_EQUAL(org, cmp); - free(cmp); - - cmp = string_ndup(org, 25); - LONGS_EQUAL(25, strlen(cmp)); - free(cmp); -} - -TEST(utils, stringTrim) { - // Multiple whitespaces, before, after and in between - char * toTrim = my_strdup(" a b c "); - char * result = utils_stringTrim(toTrim); - - STRCMP_EQUAL("a b c", result); - - // No whitespaces - free(toTrim); - toTrim = my_strdup("abc"); - result = utils_stringTrim(toTrim); - - STRCMP_EQUAL("abc", result); - - // Only whitespace before - free(toTrim); - toTrim = my_strdup(" abc"); - result = utils_stringTrim(toTrim); - - STRCMP_EQUAL("abc", result); - - // Only whitespace after - free(toTrim); - toTrim = my_strdup("abc "); - result = utils_stringTrim(toTrim); - - STRCMP_EQUAL("abc", result); - - // Whitespace other than space (tab, cr..). - free(toTrim); - toTrim = my_strdup("\tabc \n asdf \n"); - result = utils_stringTrim(toTrim); - - STRCMP_EQUAL("abc \n asdf", result); - - free(toTrim); - - char* trimmed = celix_utils_trim(" abc "); - STRCMP_EQUAL("abc", trimmed); - free(trimmed); -} - -TEST(utils, thread_equalsSelf){ - celix_thread thread = celixThread_self(); - bool get; - - LONGS_EQUAL(CELIX_SUCCESS, thread_equalsSelf(thread, &get)); - CHECK(get); - - thread.thread = (pthread_t) 0x42; - LONGS_EQUAL(CELIX_SUCCESS, thread_equalsSelf(thread, &get)); - CHECK_FALSE(get); -} - -TEST(utils, isNumeric) { - // Check numeric string - char * toCheck = my_strdup("42"); - - bool result; - celix_status_t status = utils_isNumeric(toCheck, &result); - LONGS_EQUAL(CELIX_SUCCESS, status); - CHECK_C(result); - - // Check non numeric string - free(toCheck); - toCheck = my_strdup("42b"); - status = utils_isNumeric(toCheck, &result); - LONGS_EQUAL(CELIX_SUCCESS, status); - CHECK_C(!result); - - free(toCheck); -} - -TEST(utils, compareServiceIdsAndRanking){ - int ret; - //service 1 is higher ranked and has a irrelevant ID, so result is -1 (smaller -> sorted before service 2) - ret = celix_utils_compareServiceIdsAndRanking(2,2,1,1); - LONGS_EQUAL(-1, ret); - - //service 1 is equally ranked and has a lower ID. so result is -1 (smaller -> sorted before service 2) - ret = celix_utils_compareServiceIdsAndRanking(1,1,2,1); - LONGS_EQUAL(-1, ret); - - //service 1 is equally ranked and has a higher ID, so result is 1 (larger -> sorted after service 2) - ret = celix_utils_compareServiceIdsAndRanking(2,1,1,1); - LONGS_EQUAL(1, ret); - - //service 1 is lower ranked and has a irrelevant ID, so result is -1 (larger -> sorted after service 2) - ret = celix_utils_compareServiceIdsAndRanking(1,1,2,2); - LONGS_EQUAL(1, ret); - - //service 1 is equal in ID and irrelevantly ranked - //note ensure that also the call without celix_ is tested - ret = utils_compareServiceIdsAndRanking(1,1,1,1); - LONGS_EQUAL(0, ret); - - -} - -TEST(utils, extractLocalNameAndNamespaceTest) { - const char *input = "lb"; - char* name = NULL; - char *ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "::", &name, &ns); - CHECK_EQUAL_C_STRING("lb", name); - CHECK_TRUE(ns == NULL); - free(name); - free(ns); - - input = "celix::lb"; - name = NULL; - ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "::", &name, &ns); - CHECK_EQUAL_C_STRING("lb", name); - CHECK_EQUAL_C_STRING("celix", ns); - free(name); - free(ns); - - input = "celix::extra::namespace::entries::lb"; - name = NULL; - ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "::", &name, &ns); - CHECK_EQUAL_C_STRING("lb", name); - CHECK_EQUAL_C_STRING("celix::extra::namespace::entries", ns); - free(name); - free(ns); - - input = "celix.extra.namespace.entries.lb"; - name = NULL; - ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, ".", &name, &ns); - CHECK_EQUAL_C_STRING("lb", name); - CHECK_EQUAL_C_STRING("celix.extra.namespace.entries", ns); - free(name); - free(ns); - - //testing with non existing namespace - input = "celix.extra.namespace.entries.lb"; - name = NULL; - ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "??", &name, &ns); - CHECK_EQUAL_C_STRING("celix.extra.namespace.entries.lb", name); - CHECK_TRUE(ns == NULL); - free(name); - free(ns); - - //wrong input check - input = NULL; - name = NULL; - ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "??", &name, &ns); - CHECK_TRUE(name == NULL); - CHECK_TRUE(ns == NULL); - free(name); - free(ns); - - - //empty namespace check - input = "celix.extra.namespace.entries.lb"; - name = NULL; - ns = NULL; - celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(input, "", &name, &ns); - CHECK_EQUAL_C_STRING("celix.extra.namespace.entries.lb", name); - CHECK_TRUE(ns == NULL); - free(name); - free(ns); -} - -TEST(utils, isStringNullOrEmpty) { - bool empty = celix_utils_isStringNullOrEmpty(nullptr); - CHECK_TRUE(empty); - empty = celix_utils_isStringNullOrEmpty(""); - CHECK_TRUE(empty); - empty = celix_utils_isStringNullOrEmpty(" "); - CHECK_FALSE(empty); - empty = celix_utils_isStringNullOrEmpty("foo"); - CHECK_FALSE(empty); -} \ No newline at end of file diff --git a/libs/utils/src/celix_convert_utils.c b/libs/utils/src/celix_convert_utils.c new file mode 100644 index 00000000..de945c33 --- /dev/null +++ b/libs/utils/src/celix_convert_utils.c @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "utils.h" +#include "celix_utils.h" +#include "celix_version.h" + +bool celix_utils_convertStringToBool(const char* val, bool defaultValue, bool* converted) { + bool result = defaultValue; + if (converted != NULL) { + *converted = false; + } + if (val != NULL) { + char buf[32]; + snprintf(buf, 32, "%s", val); + char *trimmed = utils_stringTrim(buf); + if (strncasecmp("true", trimmed, 5) == 0) { + result = true; + if (converted) { + *converted = true; + } + } else if (strncasecmp("false", trimmed, 6) == 0) { + result = false; + if (converted) { + *converted = true; + } + } + } + return result; +} + +double celix_utils_convertStringToDouble(const char* val, double defaultValue, bool* converted) { + double result = defaultValue; + if (converted != NULL) { + *converted = false; + } + if (val != NULL) { + char *endptr; + double d = strtod(val, &endptr); + if (endptr != val) { + result = d; + if (converted) { + *converted = true; + } + } + } + return result; +} + +long celix_utils_convertStringToLong(const char* val, long defaultValue, bool* converted) { + long result = defaultValue; + if (converted != NULL) { + *converted = false; + } + if (val != NULL) { + char *endptr; + long l = strtol(val, &endptr, 10); + if (endptr != val) { + result = l; + if (converted) { + *converted = true; + } + } + } + return result; +} + +celix_version_t* celix_utils_convertStringToVersion(const char* val) { + celix_version_t* result = NULL; + if (val != NULL) { + //check if string has two dots ('.'), and only try to create string if it has two dots + char* firstDot = strchr(val, '.'); + char* lastDot = strrchr(val, '.'); + if (firstDot != NULL && lastDot != NULL && firstDot != lastDot) { + result = celix_version_createVersionFromString(val); + } + } + return result; +} diff --git a/libs/utils/src/celix_file_utils.c b/libs/utils/src/celix_file_utils.c index d66d06ba..ac0b2224 100644 --- a/libs/utils/src/celix_file_utils.c +++ b/libs/utils/src/celix_file_utils.c @@ -25,6 +25,7 @@ #include <dirent.h> #include <stdlib.h> #include <zip.h> +#include <sys/time.h> #include "celix_utils.h" @@ -235,7 +236,7 @@ celix_status_t celix_utils_extractZipFile(const char* zipPath, const char* extra status = celix_utils_extractZipInternal(zip, extractToDir, errorOut); zip_close(zip); } else { - //note libzip can give more info with zip_error_to_str if needed (but this requires a allocated string buf). + //note libzip can give more info with zip_error_to_str if needed (but this requires an allocated string buf). status = CELIX_FILE_IO_EXCEPTION; *errorOut = ERROR_OPENING_ZIP; } @@ -277,4 +278,28 @@ celix_status_t celix_utils_extractZipData(const void *zipData, size_t zipDataSiz return status; } +celix_status_t celix_utils_getLastModified(const char* path, struct timespec* lastModified) { + celix_status_t status = CELIX_SUCCESS; + struct stat st; + if (stat(path, &st) == 0) { +#ifdef __APPLE__ + *lastModified = st.st_mtimespec; +#else + *lastModified = st.st_mtim; +#endif + } else { + lastModified->tv_sec = 0; + lastModified->tv_nsec = 0; + status = CELIX_FILE_IO_EXCEPTION; + } + return status; +} +celix_status_t celix_utils_touch(const char* path) { + celix_status_t status = CELIX_SUCCESS; + int rc = utimes(path, NULL); + if (rc != 0) { + status = CELIX_FILE_IO_EXCEPTION; + } + return status; +} diff --git a/libs/utils/src/utils.c b/libs/utils/src/utils.c index 4ebb938c..292daa1b 100644 --- a/libs/utils/src/utils.c +++ b/libs/utils/src/utils.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <stdarg.h> #include "utils.h" #include "celix_utils.h" @@ -64,10 +65,43 @@ bool celix_utils_stringEquals(const char* a, const char* b) { } } +bool celix_utils_containsWhitespace(const char* s) { + if (!celix_utils_isStringNullOrEmpty(s)) { + for (int i = 0; s[i] != '\0'; ++i) { + if (isspace(s[i])) { + return true; + } + } + } + return false; +}; + bool celix_utils_isStringNullOrEmpty(const char* s) { return s == NULL || s[0] == '\0'; } +char* celix_utils_makeCIdentifier(const char* s) { + if (celix_utils_isStringNullOrEmpty(s)) { + return NULL; + } + size_t len = strnlen(s, CELIX_UTILS_MAX_STRLEN); + char* ns = malloc(len + 2); //+2 for '\0' and an extra _ prefix if needed. + int i = 0; + if (isdigit(s[0])) { + ns[i++] = '_'; + } + for (size_t j = 0; j < len; j++) { + if (isalnum(s[j])) { + ns[i++] = s[j]; + } else { + ns[i++] = '_'; + } + } + ns[i] = '\0'; + return ns; +} + + char * string_ndup(const char *s, size_t n) { size_t len = strlen(s); char *ret; @@ -138,15 +172,32 @@ bool utils_isStringEmptyOrNull(const char * const str) { return empty; } -celix_status_t thread_equalsSelf(celix_thread_t thread, bool *equals) { - celix_status_t status = CELIX_SUCCESS; +char* celix_utils_writeOrCreateString(char* buffer, size_t bufferSize, const char* format, ...) { + va_list args; + va_start(args, format); + int written = vsnprintf(buffer, bufferSize, format, args); + va_end(args); + if (written < 0 || written >= bufferSize) { + //buffer to small, create new string + char* newStr = NULL; + va_start(args, format); + vasprintf(&newStr, format, args); + va_end(args); + return newStr; + } + return buffer; +} - celix_thread_t self = celixThread_self(); - if (status == CELIX_SUCCESS) { - *equals = celixThread_equals(self, thread); +void celix_utils_freeStringIfNeeded(const char* buffer, char* str) { + if (str != buffer) { + free(str); } +} - return status; +celix_status_t thread_equalsSelf(celix_thread_t thread, bool *equals) { + celix_thread_t self = celixThread_self(); + *equals = celixThread_equals(self, thread); + return CELIX_SUCCESS; } celix_status_t utils_isNumeric(const char *number, bool *ret) {
