You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2023/01/31 22:21:58 UTC
[celix] 02/05: Improve utils lib with string convert, file touch and file modified functions.
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 <pn...@apache.org>
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) {