blob: dac59f37b6c5fe88bfdd5434e102b525d4c37c99 [file] [log] [blame]
/*
* 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 <string.h>
#include <assert.h>
#include <stdarg.h>
#include "utils.h"
#include "celix_utils.h"
#include "celix_utils_private_constants.h"
#ifdef __APPLE__
#include "memstream/open_memstream.h"
#else
#include <stdio.h>
#endif
unsigned int utils_stringHash(const void* strPtr) {
return celix_utils_stringHash((const char*)strPtr);
}
int utils_stringEquals(const void* string, const void* toCompare) {
return celix_utils_stringEquals((const char*)string, (const char*)toCompare);
}
unsigned int celix_utils_stringHash(const char* string) {
if (string == NULL) {
return 0;
}
unsigned int hc = 5381;
char ch;
while((ch = *string++) != '\0'){
hc = (hc << 5) + hc + ch;
}
return hc;
}
bool celix_utils_stringEquals(const char* a, const char* b) {
if (a == b) {
return true;
} else if (a == NULL || b == NULL) {
return false;
} else {
return strncmp(a, b, CELIX_UTILS_MAX_STRLEN) == 0;
}
}
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 = celix_utils_strlen(s);
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;
if (len <= n) {
return strdup(s);
}
ret = malloc(n + 1);
strncpy(ret, s, n);
ret[n] = '\0';
return ret;
}
static char* celix_utilsTrimInternal(char* string) {
if (string == NULL) {
return NULL;
}
char* begin = string; //save begin to correctly free in the end.
char *end;
// Trim leading space
while (isspace(*string)) {
string++;
}
// Trim trailing space
end = string + strlen(string) - 1;
while(end > string && isspace(*end)) {
*(end) = '\0';
end--;
}
if (string != begin) {
//beginning whitespaces -> move char in copy to to begin string
//This to ensure free still works on the same pointer.
char* nstring = begin;
while(*string != '\0') {
*(nstring++) = *(string++);
}
(*nstring) = '\0';
}
return begin;
}
char* celix_utils_trim(const char* string) {
return celix_utilsTrimInternal(celix_utils_strdup(string));
}
char* celix_utils_trimInPlace(char* string) {
return celix_utilsTrimInternal(string);
}
char* utils_stringTrim(char* string) {
return celix_utilsTrimInternal(string);
}
bool utils_isStringEmptyOrNull(const char * const str) {
bool empty = true;
if (str != NULL) {
int i;
for (i = 0; i < celix_utils_strlen(str); i += 1) {
if (!isspace(str[i])) {
empty = false;
break;
}
}
}
return empty;
}
char* celix_utils_writeOrCreateString(char* buffer, size_t bufferSize, const char* format, ...) {
char *ret = NULL;
va_list args;
va_start(args, format);
ret = celix_utils_writeOrCreateVString(buffer, bufferSize, format, args);
va_end(args);
return ret;
}
char* celix_utils_writeOrCreateVString(char* buffer, size_t bufferSize, const char* format, va_list formatArgs) {
va_list argCopy;
va_copy(argCopy, formatArgs);
int written = vsnprintf(buffer, bufferSize, format, argCopy);
va_end(argCopy);
if (written < 0 || written >= bufferSize) {
//buffer to small, create new string
char* newStr = NULL;
int rc = vasprintf(&newStr, format, formatArgs);
return rc == -1 ? NULL : newStr;
}
return buffer;
}
void celix_utils_freeStringIfNotEqual(const char* buffer, char* str) {
if (str != buffer) {
free(str);
}
}
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) {
celix_status_t status = CELIX_SUCCESS;
*ret = true;
while(*number) {
if(!isdigit(*number) && *number != '.') {
*ret = false;
break;
}
number++;
}
return status;
}
int utils_compareServiceIdsAndRanking(long svcIdA, long svcRankA, long svcIdB, long svcRankB) {
return celix_utils_compareServiceIdsAndRanking(svcIdA, svcRankA, svcIdB, svcRankB);
}
int celix_utils_compareServiceIdsAndRanking(long svcIdA, long svcRankA, long svcIdB, long svcRankB) {
int result;
if (svcIdA == svcIdB) {
result = 0;
} else if (svcRankA != svcRankB) {
result = svcRankA < svcRankB ? 1 : -1;
} else { //equal service rank, compare service ids
result = svcIdA < svcIdB ? -1 : 1;
}
return result;
}
double celix_difftime(const struct timespec *tBegin, const struct timespec *tEnd) {
struct timespec diff;
if ((tEnd->tv_nsec - tBegin->tv_nsec) < 0) {
diff.tv_sec = tEnd->tv_sec - tBegin->tv_sec - 1;
diff.tv_nsec = tEnd->tv_nsec - tBegin->tv_nsec + CELIX_NS_IN_SEC;
} else {
diff.tv_sec = tEnd->tv_sec - tBegin->tv_sec;
diff.tv_nsec = tEnd->tv_nsec - tBegin->tv_nsec;
}
return ((double)diff.tv_sec) + diff.tv_nsec * 1.0 / CELIX_NS_IN_SEC;
}
struct timespec celix_gettime(clockid_t clockId) {
struct timespec t;
errno = 0;
int rc = clock_gettime(clockId, &t);
if (rc != 0) {
fprintf(stderr, "Cannot get time from clock_gettime. Error is %s\n", strerror(errno));
}
return t;
}
struct timespec celix_delayedTimespec(const struct timespec* time, double delayInSeconds) {
struct timespec delayedTime;
if (time != NULL) {
delayedTime = *time;
} else {
delayedTime.tv_nsec = 0;
delayedTime.tv_sec = 0;
}
long seconds = (long)delayInSeconds;
double nanoseconds = (delayInSeconds - (double)seconds) * CELIX_NS_IN_SEC;
delayedTime.tv_sec += seconds;
delayedTime.tv_nsec += (long)nanoseconds;
if (delayedTime.tv_nsec >= CELIX_NS_IN_SEC) {
delayedTime.tv_sec += 1;
delayedTime.tv_nsec -= CELIX_NS_IN_SEC;
} else if (delayedTime.tv_nsec < 0) {
delayedTime.tv_sec -= 1;
delayedTime.tv_nsec += CELIX_NS_IN_SEC;
}
return delayedTime;
}
double celix_elapsedtime(clockid_t clockId, struct timespec startTime) {
struct timespec now = celix_gettime(clockId);
return celix_difftime(&startTime, &now);
}
int celix_compareTime(const struct timespec *a, const struct timespec *b) {
if (a->tv_sec == b->tv_sec && a->tv_nsec == b->tv_nsec) {
return 0;
}
double diff = celix_difftime(a, b);
if (diff < 0) {
return 1;
}
return -1;
}
char* celix_utils_strdup(const char *str) {
if (str != NULL) {
return strndup(str, CELIX_UTILS_MAX_STRLEN);
} else {
return NULL;
}
}
size_t celix_utils_strlen(const char *str) {
return str ? strnlen(str, CELIX_UTILS_MAX_STRLEN) : 0;
}
void celix_utils_extractLocalNameAndNamespaceFromFullyQualifiedName(const char *fullyQualifiedName, const char *namespaceSeparator, char **outLocalName, char **outNamespace) {
assert(namespaceSeparator != NULL);
if (fullyQualifiedName == NULL) {
*outLocalName = NULL;
*outNamespace = NULL;
return;
}
char *cpy = celix_utils_strdup(fullyQualifiedName);
char *local = NULL;
char *namespace = NULL;
size_t namespaceLen;
FILE *namespaceStream = open_memstream(&namespace, &namespaceLen);
char *savePtr = NULL;
char *nextSubStr = NULL;
char *currentSubStr = strtok_r(cpy, namespaceSeparator, &savePtr);
bool firstNamespaceEntry = true;
while (currentSubStr != NULL) {
nextSubStr = strtok_r(NULL, namespaceSeparator, &savePtr);
if (nextSubStr != NULL) {
//still more, so last is part of the namespace
if (firstNamespaceEntry) {
firstNamespaceEntry = false;
} else {
fprintf(namespaceStream, "%s", namespaceSeparator);
}
fprintf(namespaceStream, "%s", currentSubStr);
} else {
//end reached current is local name
local = celix_utils_strdup(currentSubStr);
}
currentSubStr = nextSubStr;
}
fclose(namespaceStream);
free(cpy);
*outLocalName = local;
if (namespace == NULL) {
*outNamespace = NULL;
} else if (strncmp("", namespace, 1) == 0) {
//empty string -> set to NULL
*outNamespace = NULL;
free(namespace);
} else {
*outNamespace = namespace;
}
}