Repository: celix Updated Branches: refs/heads/feature/CELIX-417-cmake-refactor [created] a1c308879
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/linked_list_iterator.c ---------------------------------------------------------------------- diff --git a/utils/src/linked_list_iterator.c b/utils/src/linked_list_iterator.c new file mode 100644 index 0000000..dc0e5c4 --- /dev/null +++ b/utils/src/linked_list_iterator.c @@ -0,0 +1,153 @@ +/** + *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. + */ +/* + * linked_list_iterator.c + * + * \date Jul 16, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdio.h> +#include <stdlib.h> + +#include "linked_list_iterator.h" +#include "linked_list_private.h" + +struct linkedListIterator { + linked_list_entry_pt lastReturned; + linked_list_entry_pt next; + int nextIndex; + linked_list_pt list; + int expectedModificationCount; +}; + +linked_list_iterator_pt linkedListIterator_create(linked_list_pt list, unsigned int index) { + linked_list_iterator_pt iterator; + if (index > list->size) { + return NULL; + } + iterator = (linked_list_iterator_pt) malloc(sizeof(*iterator)); + iterator->lastReturned = list->header; + iterator->list = list; + iterator->expectedModificationCount = list->modificationCount; + if (index < (list->size >> 1)) { + iterator->next = iterator->list->header->next; + for (iterator->nextIndex = 0; iterator->nextIndex < index; iterator->nextIndex++) { + iterator->next = iterator->next->next; + } + } else { + iterator->next = list->header; + for (iterator->nextIndex = list->size; iterator->nextIndex > index; iterator->nextIndex--) { + iterator->next = iterator->next->previous; + } + } + return iterator; +} + +void linkedListIterator_destroy(linked_list_iterator_pt iterator) { + iterator->expectedModificationCount = 0; + iterator->lastReturned = NULL; + iterator->list = NULL; + iterator->next = NULL; + iterator->nextIndex = 0; + free(iterator); +} + +bool linkedListIterator_hasNext(linked_list_iterator_pt iterator) { + return iterator->nextIndex != iterator->list->size; +} + +void * linkedListIterator_next(linked_list_iterator_pt iterator) { + if (iterator->list->modificationCount != iterator->expectedModificationCount) { + return NULL; + } + if (iterator->nextIndex == iterator->list->size) { + return NULL; + } + iterator->lastReturned = iterator->next; + iterator->next = iterator->next->next; + iterator->nextIndex++; + return iterator->lastReturned->element; +} + +bool linkedListIterator_hasPrevious(linked_list_iterator_pt iterator) { + return iterator->nextIndex != 0; +} + +void * linkedListIterator_previous(linked_list_iterator_pt iterator) { + if (iterator->nextIndex == 0) { + return NULL; + } + + iterator->lastReturned = iterator->next = iterator->next->previous; + iterator->nextIndex--; + + if (iterator->list->modificationCount != iterator->expectedModificationCount) { + return NULL; + } + + return iterator->lastReturned->element; +} + +int linkedListIterator_nextIndex(linked_list_iterator_pt iterator) { + return iterator->nextIndex; +} + +int linkedListIterator_previousIndex(linked_list_iterator_pt iterator) { + return iterator->nextIndex-1; +} + +void linkedListIterator_remove(linked_list_iterator_pt iterator) { + linked_list_entry_pt lastNext; + if (iterator->list->modificationCount != iterator->expectedModificationCount) { + return; + } + lastNext = iterator->lastReturned->next; + if (linkedList_removeEntry(iterator->list, iterator->lastReturned) == NULL) { + return; + } + if (iterator->next == iterator->lastReturned) { + iterator->next = lastNext; + } else { + iterator->nextIndex--; + } + iterator->lastReturned = iterator->list->header; + iterator->expectedModificationCount++; +} + +void linkedListIterator_set(linked_list_iterator_pt iterator, void * element) { + if (iterator->lastReturned == iterator->list->header) { + return; + } + if (iterator->list->modificationCount != iterator->expectedModificationCount) { + return; + } + iterator->lastReturned->element = element; +} + +void linkedListIterator_add(linked_list_iterator_pt iterator, void * element) { + if (iterator->list->modificationCount != iterator->expectedModificationCount) { + return; + } + iterator->lastReturned = iterator->list->header; + linkedList_addBefore(iterator->list, element, iterator->next); + iterator->nextIndex++; + iterator->expectedModificationCount++; +} + http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/linked_list_private.h ---------------------------------------------------------------------- diff --git a/utils/src/linked_list_private.h b/utils/src/linked_list_private.h new file mode 100644 index 0000000..dcb0a46 --- /dev/null +++ b/utils/src/linked_list_private.h @@ -0,0 +1,44 @@ +/** + *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. + */ +/* + * linked_list_private.h + * + * \date Jul 16, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + +#ifndef LINKED_LIST_PRIVATE_H_ +#define LINKED_LIST_PRIVATE_H_ + +#include "linked_list.h" + +struct linked_list_entry { + void * element; + struct linked_list_entry * next; + struct linked_list_entry * previous; +}; + +struct linked_list { + linked_list_entry_pt header; + size_t size; + int modificationCount; +}; + +#endif /* LINKED_LIST_PRIVATE_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/memstream/fmemopen.c ---------------------------------------------------------------------- diff --git a/utils/src/memstream/fmemopen.c b/utils/src/memstream/fmemopen.c new file mode 100644 index 0000000..cb1b0c0 --- /dev/null +++ b/utils/src/memstream/fmemopen.c @@ -0,0 +1,76 @@ + +/* + * fmem.c : fmemopen() on top of BSD's funopen() + * 20081017 AF + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct fmem { + size_t pos; + size_t size; + char *buffer; +}; +typedef struct fmem fmem_t; + +static int readfn(void *handler, char *buf, int size) +{ + int count = 0; + fmem_t *mem = handler; + size_t available = mem->size - mem->pos; + + if(size > available) size = available; + for(count=0; count < size; mem->pos++, count++) + buf[count] = mem->buffer[mem->pos]; + + return count; +} + +static int writefn(void *handler, const char *buf, int size) +{ + int count = 0; + fmem_t *mem = handler; + size_t available = mem->size - mem->pos; + + if(size > available) size = available; + for(count=0; count < size; mem->pos++, count++) + mem->buffer[mem->pos] = buf[count]; + + return count; // ? count : size; +} + +static fpos_t seekfn(void *handler, fpos_t offset, int whence) +{ + size_t pos; + fmem_t *mem = handler; + + switch(whence) { + case SEEK_SET: pos = offset; break; + case SEEK_CUR: pos = mem->pos + offset; break; + case SEEK_END: pos = mem->size + offset; break; + default: return -1; + } + + if(pos > mem->size) return -1; + + mem->pos = pos; + return (fpos_t) pos; +} + +static int closefn(void *handler) +{ + free(handler); + return 0; +} + +/* simple, but portable version of fmemopen for OS X / BSD */ +FILE *fmemopen(void *buf, size_t size, const char *mode) +{ + fmem_t *mem = (fmem_t *) malloc(sizeof(fmem_t)); + + memset(mem, 0, sizeof(fmem_t)); + mem->size = size, mem->buffer = buf; + return funopen(mem, readfn, writefn, seekfn, closefn); +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/memstream/open_memstream.c ---------------------------------------------------------------------- diff --git a/utils/src/memstream/open_memstream.c b/utils/src/memstream/open_memstream.c new file mode 100644 index 0000000..6bc4f01 --- /dev/null +++ b/utils/src/memstream/open_memstream.c @@ -0,0 +1,130 @@ +/* Use funopen(3) to provide open_memstream(3) like functionality. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +struct memstream { + char **cp; + size_t *lenp; + size_t offset; +}; + +static void +memstream_grow(struct memstream *ms, size_t newsize) +{ + char *buf; + + if (newsize > *ms->lenp) { + buf = realloc(*ms->cp, newsize + 1); + if (buf != NULL) { +#ifdef DEBUG + fprintf(stderr, "MS: %p growing from %zd to %zd\n", + ms, *ms->lenp, newsize); +#endif + memset(buf + *ms->lenp + 1, 0, newsize - *ms->lenp); + *ms->cp = buf; + *ms->lenp = newsize; + } + } +} + +static int +memstream_read(void *cookie, char *buf, int len) +{ + struct memstream *ms; + int tocopy; + + ms = cookie; + memstream_grow(ms, ms->offset + len); + tocopy = *ms->lenp - ms->offset; + if (len < tocopy) + tocopy = len; + memcpy(buf, *ms->cp + ms->offset, tocopy); + ms->offset += tocopy; +#ifdef DEBUG + fprintf(stderr, "MS: read(%p, %d) = %d\n", ms, len, tocopy); +#endif + return (tocopy); +} + +static int +memstream_write(void *cookie, const char *buf, int len) +{ + struct memstream *ms; + int tocopy; + + ms = cookie; + memstream_grow(ms, ms->offset + len); + tocopy = *ms->lenp - ms->offset; + if (len < tocopy) + tocopy = len; + memcpy(*ms->cp + ms->offset, buf, tocopy); + ms->offset += tocopy; +#ifdef DEBUG + fprintf(stderr, "MS: write(%p, %d) = %d\n", ms, len, tocopy); +#endif + return (tocopy); +} + +static fpos_t +memstream_seek(void *cookie, fpos_t pos, int whence) +{ + struct memstream *ms; +#ifdef DEBUG + size_t old; +#endif + + ms = cookie; +#ifdef DEBUG + old = ms->offset; +#endif + switch (whence) { + case SEEK_SET: + ms->offset = pos; + break; + case SEEK_CUR: + ms->offset += pos; + break; + case SEEK_END: + ms->offset = *ms->lenp + pos; + break; + } +#ifdef DEBUG + fprintf(stderr, "MS: seek(%p, %zd, %d) %zd -> %zd\n", ms, pos, whence, + old, ms->offset); +#endif + return (ms->offset); +} + +static int +memstream_close(void *cookie) +{ + + free(cookie); + return (0); +} + +FILE * +open_memstream(char **cp, size_t *lenp) +{ + struct memstream *ms; + int save_errno; + FILE *fp; + + *cp = NULL; + *lenp = 0; + ms = malloc(sizeof(*ms)); + ms->cp = cp; + ms->lenp = lenp; + ms->offset = 0; + fp = funopen(ms, memstream_read, memstream_write, memstream_seek, + memstream_close); + if (fp == NULL) { + save_errno = errno; + free(ms); + errno = save_errno; + } + return (fp); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/properties.c ---------------------------------------------------------------------- diff --git a/utils/src/properties.c b/utils/src/properties.c new file mode 100644 index 0000000..0bd6dc3 --- /dev/null +++ b/utils/src/properties.c @@ -0,0 +1,302 @@ +/** + *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. + */ +/* + * properties.c + * + * \date Apr 27, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "celixbool.h" +#include "properties.h" +#include "utils.h" + +#define MALLOC_BLOCK_SIZE 5 + +static void parseLine(const char* line, properties_pt props); + +properties_pt properties_create(void) { + return hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals); +} + +void properties_destroy(properties_pt properties) { + hash_map_iterator_pt iter = hashMapIterator_create(properties); + while (hashMapIterator_hasNext(iter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + free(hashMapEntry_getKey(entry)); + free(hashMapEntry_getValue(entry)); + } + hashMapIterator_destroy(iter); + hashMap_destroy(properties, false, false); +} + +properties_pt properties_load(const char* filename) { + FILE *file = fopen(filename, "r"); + if(file==NULL){ + return NULL; + } + properties_pt props = properties_loadWithStream(file); + fclose(file); + return props; +} + +properties_pt properties_loadWithStream(FILE *file) { + properties_pt props = NULL; + + + if (file != NULL ) { + char *saveptr; + char *filebuffer = NULL; + char *line = NULL; + size_t file_size = 0; + + props = properties_create(); + fseek(file, 0, SEEK_END); + file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + if(file_size > 0){ + filebuffer = calloc(file_size + 1, sizeof(char)); + if(filebuffer) { + size_t rs = fread(filebuffer, sizeof(char), file_size, file); + if(rs != file_size){ + fprintf(stderr,"fread read only %lu bytes out of %lu\n",rs,file_size); + } + filebuffer[file_size]='\0'; + line = strtok_r(filebuffer, "\n", &saveptr); + while ( line != NULL ) { + parseLine(line, props); + line = strtok_r(NULL, "\n", &saveptr); + } + free(filebuffer); + } + } + } + + return props; +} + + +/** + * Header is ignored for now, cannot handle comments yet + */ +void properties_store(properties_pt properties, const char* filename, const char* header) { + FILE *file = fopen ( filename, "w+" ); + char *str; + + if (file != NULL) { + if (hashMap_size(properties) > 0) { + hash_map_iterator_pt iterator = hashMapIterator_create(properties); + while (hashMapIterator_hasNext(iterator)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator); + str = hashMapEntry_getKey(entry); + for (int i = 0; i < strlen(str); i += 1) { + if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { + fputc('\\', file); + } + fputc(str[i], file); + } + + fputc('=', file); + + str = hashMapEntry_getValue(entry); + for (int i = 0; i < strlen(str); i += 1) { + if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { + fputc('\\', file); + } + fputc(str[i], file); + } + + fputc('\n', file); + + } + hashMapIterator_destroy(iterator); + } + fclose(file); + } else { + perror("File is null"); + } +} + +celix_status_t properties_copy(properties_pt properties, properties_pt *out) { + celix_status_t status = CELIX_SUCCESS; + properties_pt copy = properties_create(); + + if (copy != NULL) { + hash_map_iterator_pt iter = hashMapIterator_create(properties); + while (hashMapIterator_hasNext(iter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + char *key = hashMapEntry_getKey(entry); + char *value = hashMapEntry_getValue(entry); + properties_set(copy, key, value); + } + hashMapIterator_destroy(iter); + } else { + status = CELIX_ENOMEM; + } + + if (status == CELIX_SUCCESS) { + *out = copy; + } + + return status; +} + +const char* properties_get(properties_pt properties, const char* key) { + return hashMap_get(properties, (void*)key); +} + +const char* properties_getWithDefault(properties_pt properties, const char* key, const char* defaultValue) { + const char* value = properties_get(properties, key); + return value == NULL ? defaultValue : value; +} + +void properties_set(properties_pt properties, const char* key, const char* value) { + hash_map_entry_pt entry = hashMap_getEntry(properties, key); + char* oldValue = NULL; + if (entry != NULL) { + char* oldKey = hashMapEntry_getKey(entry); + oldValue = hashMapEntry_getValue(entry); + hashMap_put(properties, oldKey, strndup(value, 1024*10)); + } else { + hashMap_put(properties, strndup(key, 1024*10), strndup(value, 1024*10)); + } + free(oldValue); +} + +static void updateBuffers(char **key, char ** value, char **output, int outputPos, int *key_len, int *value_len) { + if (*output == *key) { + if (outputPos == (*key_len) - 1) { + (*key_len) += MALLOC_BLOCK_SIZE; + *key = realloc(*key, *key_len); + *output = *key; + } + } + else { + if (outputPos == (*value_len) - 1) { + (*value_len) += MALLOC_BLOCK_SIZE; + *value = realloc(*value, *value_len); + *output = *value; + } + } +} + +static void parseLine(const char* line, properties_pt props) { + int linePos = 0; + bool precedingCharIsBackslash = false; + bool isComment = false; + int outputPos = 0; + char *output = NULL; + int key_len = MALLOC_BLOCK_SIZE; + int value_len = MALLOC_BLOCK_SIZE; + linePos = 0; + precedingCharIsBackslash = false; + isComment = false; + output = NULL; + outputPos = 0; + + //Ignore empty lines + if (line[0] == '\n' && line[1] == '\0') { + return; + } + + char *key = calloc(1, key_len); + char *value = calloc(1, value_len); + key[0] = '\0'; + value[0] = '\0'; + + while (line[linePos] != '\0') { + if (line[linePos] == ' ' || line[linePos] == '\t') { + if (output == NULL) { + //ignore + linePos += 1; + continue; + } + } + else { + if (output == NULL) { + output = key; + } + } + if (line[linePos] == '=' || line[linePos] == ':' || line[linePos] == '#' || line[linePos] == '!') { + if (precedingCharIsBackslash) { + //escaped special character + output[outputPos++] = line[linePos]; + updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); + precedingCharIsBackslash = false; + } + else { + if (line[linePos] == '#' || line[linePos] == '!') { + if (outputPos == 0) { + isComment = true; + break; + } + else { + output[outputPos++] = line[linePos]; + updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); + } + } + else { // = or : + if (output == value) { //already have a seperator + output[outputPos++] = line[linePos]; + updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); + } + else { + output[outputPos++] = '\0'; + updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); + output = value; + outputPos = 0; + } + } + } + } + else if (line[linePos] == '\\') { + if (precedingCharIsBackslash) { //double backslash -> backslash + output[outputPos++] = '\\'; + updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); + } + precedingCharIsBackslash = true; + } + else { //normal character + precedingCharIsBackslash = false; + output[outputPos++] = line[linePos]; + updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); + } + linePos += 1; + } + if (output != NULL) { + output[outputPos] = '\0'; + } + + if (!isComment) { + //printf("putting 'key'/'value' '%s'/'%s' in properties\n", utils_stringTrim(key), utils_stringTrim(value)); + properties_set(props, utils_stringTrim(key), utils_stringTrim(value)); + } + if(key) { + free(key); + } + if(value) { + free(value); + } + +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/thpool.c ---------------------------------------------------------------------- diff --git a/utils/src/thpool.c b/utils/src/thpool.c new file mode 100644 index 0000000..5121fca --- /dev/null +++ b/utils/src/thpool.c @@ -0,0 +1,535 @@ +/* ******************************** + * Author: Johan Hanssen Seferidis + * License: MIT + * Description: Library providing a threading pool where you can add + * work. For usage, check the thpool.h file or README.md + * + *//** @file thpool.h *//* + * + ********************************/ + + +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <errno.h> +#include <time.h> +#include "thpool.h" + +#ifdef THPOOL_DEBUG +#define THPOOL_DEBUG 1 +#else +#define THPOOL_DEBUG 0 +#endif + +static volatile int threads_keepalive; +static volatile int threads_on_hold; + + + +/* ========================== STRUCTURES ============================ */ + + +/* Binary semaphore */ +typedef struct bsem { + pthread_mutex_t mutex; + pthread_cond_t cond; + int v; +} bsem; + + +/* Job */ +typedef struct job{ + struct job* prev; /* pointer to previous job */ + void* (*function)(void* arg); /* function pointer */ + void* arg; /* function's argument */ +} job; + + +/* Job queue */ +typedef struct jobqueue{ + pthread_mutex_t rwmutex; /* used for queue r/w access */ + job *front; /* pointer to front of queue */ + job *rear; /* pointer to rear of queue */ + bsem *has_jobs; /* flag as binary semaphore */ + int len; /* number of jobs in queue */ +} jobqueue; + + +/* Thread */ +typedef struct thread{ + int id; /* friendly id */ + pthread_t pthread; /* pointer to actual thread */ + struct thpool_* thpool_p; /* access to thpool */ +} thread; + + +/* Threadpool */ +typedef struct thpool_{ + thread** threads; /* pointer to threads */ + volatile int num_threads_alive; /* threads currently alive */ + volatile int num_threads_working; /* threads currently working */ + pthread_mutex_t thcount_lock; /* used for thread count etc */ + pthread_cond_t threads_all_idle; /* signal to thpool_wait */ + jobqueue* jobqueue_p; /* pointer to the job queue */ +} thpool_; + + + + + +/* ========================== PROTOTYPES ============================ */ + + +static void thread_init(thpool_* thpool_p, struct thread** thread_p, int id); +static void* thread_do(struct thread* thread_p); +static void thread_hold(); +static void thread_destroy(struct thread* thread_p); + +static int jobqueue_init(thpool_* thpool_p); +static void jobqueue_clear(thpool_* thpool_p); +static void jobqueue_push(thpool_* thpool_p, struct job* newjob_p); +static struct job* jobqueue_pull(thpool_* thpool_p); +static void jobqueue_destroy(thpool_* thpool_p); + +static void bsem_init(struct bsem *bsem_p, int value); +static void bsem_reset(struct bsem *bsem_p); +static void bsem_post(struct bsem *bsem_p); +static void bsem_post_all(struct bsem *bsem_p); +static void bsem_wait(struct bsem *bsem_p); + + + + + +/* ========================== THREADPOOL ============================ */ + + +/* Initialise thread pool */ +struct thpool_* thpool_init(int num_threads){ + + threads_on_hold = 0; + threads_keepalive = 1; + + if ( num_threads < 0){ + num_threads = 0; + } + + /* Make new thread pool */ + thpool_* thpool_p; + thpool_p = (struct thpool_*)malloc(sizeof(struct thpool_)); + if (thpool_p == NULL){ + fprintf(stderr, "thpool_init(): Could not allocate memory for thread pool\n"); + return NULL; + } + thpool_p->num_threads_alive = 0; + thpool_p->num_threads_working = 0; + + /* Initialise the job queue */ + if (jobqueue_init(thpool_p) == -1){ + fprintf(stderr, "thpool_init(): Could not allocate memory for job queue\n"); + free(thpool_p); + return NULL; + } + + /* Make threads in pool */ + thpool_p->threads = (struct thread**)malloc(num_threads * sizeof(struct thread*)); + if (thpool_p->threads == NULL){ + fprintf(stderr, "thpool_init(): Could not allocate memory for threads\n"); + jobqueue_destroy(thpool_p); + free(thpool_p->jobqueue_p); + free(thpool_p); + return NULL; + } + + pthread_mutex_init(&(thpool_p->thcount_lock), NULL); + pthread_cond_init(&thpool_p->threads_all_idle, NULL); + + /* Thread init */ + int n; + for (n=0; n<num_threads; n++){ + thread_init(thpool_p, &thpool_p->threads[n], n); + if (THPOOL_DEBUG) + printf("THPOOL_DEBUG: Created thread %d in pool \n", n); + } + + /* Wait for threads to initialize */ + while (thpool_p->num_threads_alive != num_threads) {} + + return thpool_p; +} + + +/* Add work to the thread pool */ +int thpool_add_work(thpool_* thpool_p, void *(*function_p)(void*), void* arg_p){ + job* newjob; + + newjob=(struct job*)malloc(sizeof(struct job)); + if (newjob==NULL){ + fprintf(stderr, "thpool_add_work(): Could not allocate memory for new job\n"); + return -1; + } + + /* add function and argument */ + newjob->function=function_p; + newjob->arg=arg_p; + + /* add job to queue */ + pthread_mutex_lock(&thpool_p->jobqueue_p->rwmutex); + jobqueue_push(thpool_p, newjob); + pthread_mutex_unlock(&thpool_p->jobqueue_p->rwmutex); + + return 0; +} + + +/* Wait until all jobs have finished */ +void thpool_wait(thpool_* thpool_p){ + pthread_mutex_lock(&thpool_p->thcount_lock); + while (thpool_p->jobqueue_p->len || thpool_p->num_threads_working) { + pthread_cond_wait(&thpool_p->threads_all_idle, &thpool_p->thcount_lock); + } + pthread_mutex_unlock(&thpool_p->thcount_lock); +} + + +/* Destroy the threadpool */ +void thpool_destroy(thpool_* thpool_p){ + + volatile int threads_total = thpool_p->num_threads_alive; + + /* End each thread 's infinite loop */ + threads_keepalive = 0; + + /* Give one second to kill idle threads */ + double TIMEOUT = 1.0; + time_t start, end; + double tpassed = 0.0; + time (&start); + while (tpassed < TIMEOUT && thpool_p->num_threads_alive){ + bsem_post_all(thpool_p->jobqueue_p->has_jobs); + time (&end); + tpassed = difftime(end,start); + } + + /* Poll remaining threads */ + while (thpool_p->num_threads_alive){ + bsem_post_all(thpool_p->jobqueue_p->has_jobs); + sleep(1); + } + + /* Job queue cleanup */ + jobqueue_destroy(thpool_p); + free(thpool_p->jobqueue_p); + + /* Deallocs */ + int n; + for (n=0; n < threads_total; n++){ + thread_destroy(thpool_p->threads[n]); + } + free(thpool_p->threads); + free(thpool_p); +} + + +/* Pause all threads in threadpool */ +void thpool_pause(thpool_* thpool_p) { + int n; + for (n=0; n < thpool_p->num_threads_alive; n++){ + pthread_kill(thpool_p->threads[n]->pthread, SIGUSR1); + } +} + + +/* Resume all threads in threadpool */ +void thpool_resume(thpool_* thpool_p) { + threads_on_hold = 0; +} + + + + + +/* ============================ THREAD ============================== */ + + +/* Initialize a thread in the thread pool + * + * @param thread address to the pointer of the thread to be created + * @param id id to be given to the thread + * + */ +static void thread_init (thpool_* thpool_p, struct thread** thread_p, int id){ + + *thread_p = (struct thread*)malloc(sizeof(struct thread)); + if (*thread_p == NULL){ + fprintf(stderr, "thpool_init(): Could not allocate memory for thread\n"); + exit(1); + } + + (*thread_p)->thpool_p = thpool_p; + (*thread_p)->id = id; + + pthread_create(&(*thread_p)->pthread, NULL, (void *)thread_do, (*thread_p)); + pthread_detach((*thread_p)->pthread); + +} + + +/* Sets the calling thread on hold */ +static void thread_hold () { + threads_on_hold = 1; + while (threads_on_hold){ + sleep(1); + } +} + + +/* What each thread is doing +* +* In principle this is an endless loop. The only time this loop gets interuppted is once +* thpool_destroy() is invoked or the program exits. +* +* @param thread thread that will run this function +* @return nothing +*/ +static void* thread_do(struct thread* thread_p){ + + /* Set thread name for profiling and debuging */ + char thread_name[128] = {0}; + sprintf(thread_name, "thread-pool-%d", thread_p->id); + +#if defined(__linux__) + pthread_setname_np(thread_p->pthread, thread_name); +#elif defined(__APPLE__) && defined(__MACH__) + pthread_setname_np(thread_name); +#else + fprintf(stderr, "thread_do(): pthread_setname_np is not supported on this system"); +#endif + + /* Assure all threads have been created before starting serving */ + thpool_* thpool_p = thread_p->thpool_p; + + /* Register signal handler */ + struct sigaction act; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = thread_hold; + if (sigaction(SIGUSR1, &act, NULL) == -1) { + fprintf(stderr, "thread_do(): cannot handle SIGUSR1"); + } + + /* Mark thread as alive (initialized) */ + pthread_mutex_lock(&thpool_p->thcount_lock); + thpool_p->num_threads_alive += 1; + pthread_mutex_unlock(&thpool_p->thcount_lock); + + while(threads_keepalive){ + + bsem_wait(thpool_p->jobqueue_p->has_jobs); + + if (threads_keepalive){ + + pthread_mutex_lock(&thpool_p->thcount_lock); + thpool_p->num_threads_working++; + pthread_mutex_unlock(&thpool_p->thcount_lock); + + /* Read job from queue and execute it */ + void*(*func_buff)(void* arg); + void* arg_buff; + job* job_p; + pthread_mutex_lock(&thpool_p->jobqueue_p->rwmutex); + job_p = jobqueue_pull(thpool_p); + pthread_mutex_unlock(&thpool_p->jobqueue_p->rwmutex); + if (job_p) { + func_buff = job_p->function; + arg_buff = job_p->arg; + func_buff(arg_buff); + free(job_p); + } + + pthread_mutex_lock(&thpool_p->thcount_lock); + thpool_p->num_threads_working--; + if (!thpool_p->num_threads_working) { + pthread_cond_signal(&thpool_p->threads_all_idle); + } + pthread_mutex_unlock(&thpool_p->thcount_lock); + + } + } + pthread_mutex_lock(&thpool_p->thcount_lock); + thpool_p->num_threads_alive --; + pthread_mutex_unlock(&thpool_p->thcount_lock); + + return NULL; +} + + +/* Frees a thread */ +static void thread_destroy (thread* thread_p){ + free(thread_p); +} + + + + + +/* ============================ JOB QUEUE =========================== */ + + +/* Initialize queue */ +static int jobqueue_init(thpool_* thpool_p){ + + thpool_p->jobqueue_p = (struct jobqueue*)malloc(sizeof(struct jobqueue)); + if (thpool_p->jobqueue_p == NULL){ + return -1; + } + thpool_p->jobqueue_p->len = 0; + thpool_p->jobqueue_p->front = NULL; + thpool_p->jobqueue_p->rear = NULL; + + thpool_p->jobqueue_p->has_jobs = (struct bsem*)malloc(sizeof(struct bsem)); + if (thpool_p->jobqueue_p->has_jobs == NULL){ + return -1; + } + + pthread_mutex_init(&(thpool_p->jobqueue_p->rwmutex), NULL); + bsem_init(thpool_p->jobqueue_p->has_jobs, 0); + + return 0; +} + + +/* Clear the queue */ +static void jobqueue_clear(thpool_* thpool_p){ + + while(thpool_p->jobqueue_p->len){ + free(jobqueue_pull(thpool_p)); + } + + thpool_p->jobqueue_p->front = NULL; + thpool_p->jobqueue_p->rear = NULL; + bsem_reset(thpool_p->jobqueue_p->has_jobs); + thpool_p->jobqueue_p->len = 0; + +} + + +/* Add (allocated) job to queue + * + * Notice: Caller MUST hold a mutex + */ +static void jobqueue_push(thpool_* thpool_p, struct job* newjob){ + + newjob->prev = NULL; + + switch(thpool_p->jobqueue_p->len){ + + case 0: /* if no jobs in queue */ + thpool_p->jobqueue_p->front = newjob; + thpool_p->jobqueue_p->rear = newjob; + break; + + default: /* if jobs in queue */ + thpool_p->jobqueue_p->rear->prev = newjob; + thpool_p->jobqueue_p->rear = newjob; + + } + thpool_p->jobqueue_p->len++; + + bsem_post(thpool_p->jobqueue_p->has_jobs); +} + + +/* Get first job from queue(removes it from queue) + * + * Notice: Caller MUST hold a mutex + */ +static struct job* jobqueue_pull(thpool_* thpool_p){ + + job* job_p; + job_p = thpool_p->jobqueue_p->front; + + switch(thpool_p->jobqueue_p->len){ + + case 0: /* if no jobs in queue */ + break; + + case 1: /* if one job in queue */ + thpool_p->jobqueue_p->front = NULL; + thpool_p->jobqueue_p->rear = NULL; + thpool_p->jobqueue_p->len = 0; + break; + + default: /* if >1 jobs in queue */ + thpool_p->jobqueue_p->front = job_p->prev; + thpool_p->jobqueue_p->len--; + /* more than one job in queue -> post it */ + bsem_post(thpool_p->jobqueue_p->has_jobs); + + } + + return job_p; +} + + +/* Free all queue resources back to the system */ +static void jobqueue_destroy(thpool_* thpool_p){ + jobqueue_clear(thpool_p); + free(thpool_p->jobqueue_p->has_jobs); +} + + + + + +/* ======================== SYNCHRONISATION ========================= */ + + +/* Init semaphore to 1 or 0 */ +static void bsem_init(bsem *bsem_p, int value) { + if (value < 0 || value > 1) { + fprintf(stderr, "bsem_init(): Binary semaphore can take only values 1 or 0"); + exit(1); + } + pthread_mutex_init(&(bsem_p->mutex), NULL); + pthread_cond_init(&(bsem_p->cond), NULL); + bsem_p->v = value; +} + + +/* Reset semaphore to 0 */ +static void bsem_reset(bsem *bsem_p) { + bsem_init(bsem_p, 0); +} + + +/* Post to at least one thread */ +static void bsem_post(bsem *bsem_p) { + pthread_mutex_lock(&bsem_p->mutex); + bsem_p->v = 1; + pthread_cond_signal(&bsem_p->cond); + pthread_mutex_unlock(&bsem_p->mutex); +} + + +/* Post to all threads */ +static void bsem_post_all(bsem *bsem_p) { + pthread_mutex_lock(&bsem_p->mutex); + bsem_p->v = 1; + pthread_cond_broadcast(&bsem_p->cond); + pthread_mutex_unlock(&bsem_p->mutex); +} + + +/* Wait on semaphore until semaphore has value 0 */ +static void bsem_wait(bsem* bsem_p) { + pthread_mutex_lock(&bsem_p->mutex); + while (bsem_p->v != 1) { + pthread_cond_wait(&bsem_p->cond, &bsem_p->mutex); + } + bsem_p->v = 0; + pthread_mutex_unlock(&bsem_p->mutex); +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/utils.c ---------------------------------------------------------------------- diff --git a/utils/src/utils.c b/utils/src/utils.c new file mode 100644 index 0000000..fc4d538 --- /dev/null +++ b/utils/src/utils.c @@ -0,0 +1,141 @@ +/** + *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. + */ +/* + * utils.c + * + * \date Jul 27, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdlib.h> +#include <string.h> + +#include "utils.h" + +unsigned int utils_stringHash(const void* strPtr) { + const char* string = strPtr; + unsigned int hc = 5381; + char ch; + while((ch = *string++) != '\0'){ + hc = (hc << 5) + hc + ch; + } + + return hc; +} + +int utils_stringEquals(const void* string, const void* toCompare) { + return strcmp((const char*)string, (const char*)toCompare) == 0; +} + +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; +} + +char * utils_stringTrim(char * string) { + char* copy = string; + + char *end; + // Trim leading space + while (isspace(*copy)) { + copy++; + } + + // Trim trailing space + end = copy + strlen(copy) - 1; + while(end > copy && isspace(*end)) { + *(end) = '\0'; + end--; + } + + if (copy != string) { + //beginning whitespaces -> move char in copy to to begin string + //This to ensure free still works on the same pointer. + char* nstring = string; + while(*copy != '\0') { + *(nstring++) = *(copy++); + } + (*nstring) = '\0'; + } + + return string; +} + +bool utils_isStringEmptyOrNull(const char * const str) { + bool empty = true; + if (str != NULL) { + int i; + for (i = 0; i < strnlen(str, 1024 * 1024); i += 1) { + if (!isspace(str[i])) { + empty = false; + break; + } + } + } + + return empty; +} + +celix_status_t thread_equalsSelf(celix_thread_t thread, bool *equals) { + celix_status_t status = CELIX_SUCCESS; + + celix_thread_t self = celixThread_self(); + if (status == CELIX_SUCCESS) { + *equals = celixThread_equals(self, thread); + } + + return status; +} + +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(unsigned long servId, long servRank, unsigned long otherServId, long otherServRank) { + int result; + + if (servId == otherServId) { + result = 0; + } else if (servRank != otherServRank) { + result = servRank < otherServRank ? -1 : 1; + } else { //equal service rank, compare service ids + result = servId < otherServId ? 1 : -1; + } + + return result; +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/version.c ---------------------------------------------------------------------- diff --git a/utils/src/version.c b/utils/src/version.c new file mode 100644 index 0000000..cb2703d --- /dev/null +++ b/utils/src/version.c @@ -0,0 +1,264 @@ +/** + *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. + */ +/* + * version.c + * + * \date Jul 12, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "celix_errno.h" +#include "version_private.h" + +celix_status_t version_createVersion(int major, int minor, int micro, char * qualifier, version_pt *version) { + celix_status_t status = CELIX_SUCCESS; + + if (*version != NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + } else { + *version = (version_pt) malloc(sizeof(**version)); + if (!*version) { + status = CELIX_ENOMEM; + } else { + unsigned int i; + + (*version)->major = major; + (*version)->minor = minor; + (*version)->micro = micro; + if (qualifier == NULL) { + qualifier = ""; + } + (*version)->qualifier = strdup(qualifier); + + if (major < 0) { + status = CELIX_ILLEGAL_ARGUMENT; + } + if (minor < 0) { + status = CELIX_ILLEGAL_ARGUMENT; + } + if (micro < 0) { + status = CELIX_ILLEGAL_ARGUMENT; + } + + for (i = 0; i < strlen(qualifier); i++) { + char ch = qualifier[i]; + if (('A' <= ch) && (ch <= 'Z')) { + continue; + } + if (('a' <= ch) && (ch <= 'z')) { + continue; + } + if (('0' <= ch) && (ch <= '9')) { + continue; + } + if ((ch == '_') || (ch == '-')) { + continue; + } + status = CELIX_ILLEGAL_ARGUMENT; + break; + } + } + } + + return status; +} + +celix_status_t version_clone(version_pt version, version_pt *clone) { + return version_createVersion(version->major, version->minor, version->micro, version->qualifier, clone); +} + +celix_status_t version_destroy(version_pt version) { + version->major = 0; + version->minor = 0; + version->micro = 0; + free(version->qualifier); + version->qualifier = NULL; + free(version); + return CELIX_SUCCESS; +} + +celix_status_t version_createVersionFromString(const char * versionStr, version_pt *version) { + celix_status_t status = CELIX_SUCCESS; + + int major = 0; + int minor = 0; + int micro = 0; + char * qualifier = NULL; + + char delims[] = "."; + char *token = NULL; + char *last = NULL; + + int i = 0; + + char* versionWrkStr = strdup(versionStr); + + token = strtok_r(versionWrkStr, delims, &last); + if (token != NULL) { + for (i = 0; i < strlen(token); i++) { + char ch = token[i]; + if (('0' <= ch) && (ch <= '9')) { + continue; + } + status = CELIX_ILLEGAL_ARGUMENT; + break; + } + major = atoi(token); + token = strtok_r(NULL, delims, &last); + if (token != NULL) { + for (i = 0; i < strlen(token); i++) { + char ch = token[i]; + if (('0' <= ch) && (ch <= '9')) { + continue; + } + status = CELIX_ILLEGAL_ARGUMENT; + break; + } + minor = atoi(token); + token = strtok_r(NULL, delims, &last); + if (token != NULL) { + for (i = 0; i < strlen(token); i++) { + char ch = token[i]; + if (('0' <= ch) && (ch <= '9')) { + continue; + } + status = CELIX_ILLEGAL_ARGUMENT; + break; + } + micro = atoi(token); + token = strtok_r(NULL, delims, &last); + if (token != NULL) { + qualifier = strdup(token); + token = strtok_r(NULL, delims, &last); + if (token != NULL) { + *version = NULL; + status = CELIX_ILLEGAL_ARGUMENT; + } + } + } + } + } + + free(versionWrkStr); + + if (status == CELIX_SUCCESS) { + status = version_createVersion(major, minor, micro, qualifier, version); + } + + if (qualifier != NULL) { + free(qualifier); + } + + return status; +} + +celix_status_t version_createEmptyVersion(version_pt *version) { + return version_createVersion(0, 0, 0, "", version); +} + +celix_status_t version_getMajor(version_pt version, int *major) { + celix_status_t status = CELIX_SUCCESS; + *major = version->major; + return status; +} + +celix_status_t version_getMinor(version_pt version, int *minor) { + celix_status_t status = CELIX_SUCCESS; + *minor = version->minor; + return status; +} + +celix_status_t version_getMicro(version_pt version, int *micro) { + celix_status_t status = CELIX_SUCCESS; + *micro = version->micro; + return status; +} + +celix_status_t version_getQualifier(version_pt version, const char **qualifier) { + celix_status_t status = CELIX_SUCCESS; + *qualifier = version->qualifier; + return status; +} + +celix_status_t version_compareTo(version_pt version, version_pt compare, int *result) { + celix_status_t status = CELIX_SUCCESS; + if (compare == version) { + *result = 0; + } else { + int res = version->major - compare->major; + if (res != 0) { + *result = res; + } else { + res = version->minor - compare->minor; + if (res != 0) { + *result = res; + } else { + res = version->micro - compare->micro; + if (res != 0) { + *result = res; + } else { + *result = strcmp(version->qualifier, compare->qualifier); + } + } + } + } + + return status; +} + +celix_status_t version_toString(version_pt version, char **string) { + celix_status_t status = CELIX_SUCCESS; + if (strlen(version->qualifier) > 0) { + char str[512]; + int written = snprintf(str, 512, "%d.%d.%d.%s", version->major, version->minor, version->micro, version->qualifier); + if (written >= 512 || written < 0) { + status = CELIX_BUNDLE_EXCEPTION; + } + *string = strdup(str); + } else { + char str[512]; + int written = snprintf(str, 512, "%d.%d.%d", version->major, version->minor, version->micro); + if (written >= 512 || written < 0) { + status = CELIX_BUNDLE_EXCEPTION; + } + *string = strdup(str); + } + return status; +} + +celix_status_t version_isCompatible(version_pt user, version_pt provider, bool* isCompatible) { + celix_status_t status = CELIX_SUCCESS; + bool result = false; + + if (user == NULL || provider == NULL) { + return CELIX_ILLEGAL_ARGUMENT; + } + + if (user->major == provider->major) { + result = (provider->minor >= user->minor); + } + + *isCompatible = result; + + return status; +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/version_private.h ---------------------------------------------------------------------- diff --git a/utils/src/version_private.h b/utils/src/version_private.h new file mode 100644 index 0000000..15e5c89 --- /dev/null +++ b/utils/src/version_private.h @@ -0,0 +1,41 @@ +/** + *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. + */ +/* + * version_private.h + * + * \date Dec 18, 2012 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + + +#ifndef VERSION_PRIVATE_H_ +#define VERSION_PRIVATE_H_ + +#include "version.h" + +struct version { + int major; + int minor; + int micro; + char *qualifier; +}; + + +#endif /* VERSION_PRIVATE_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/version_range.c ---------------------------------------------------------------------- diff --git a/utils/src/version_range.c b/utils/src/version_range.c new file mode 100644 index 0000000..ed681fd --- /dev/null +++ b/utils/src/version_range.c @@ -0,0 +1,233 @@ +/** + *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. + */ +/* + * version_range.c + * + * \date Jul 12, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + +#include <stdlib.h> +#include <string.h> + +#include "version_range_private.h" + +celix_status_t versionRange_createVersionRange(version_pt low, bool isLowInclusive, + version_pt high, bool isHighInclusive, version_range_pt *range) { + celix_status_t status = CELIX_SUCCESS; + *range = (version_range_pt) malloc(sizeof(**range)); + if (!*range) { + status = CELIX_ENOMEM; + } else { + (*range)->low = low; + (*range)->isLowInclusive = isLowInclusive; + (*range)->high = high; + (*range)->isHighInclusive = isHighInclusive; + } + + return status; +} + +celix_status_t versionRange_destroy(version_range_pt range) { + if (range->high != NULL) { + version_destroy(range->high); + } + if (range->low != NULL) { + version_destroy(range->low); + } + + range->high = NULL; + range->isHighInclusive = false; + range->low = NULL; + range->isLowInclusive = false; + + free(range); + + return CELIX_SUCCESS; +} + +celix_status_t versionRange_createInfiniteVersionRange(version_range_pt *range) { + celix_status_t status; + + version_pt version = NULL; + status = version_createEmptyVersion(&version); + if (status == CELIX_SUCCESS) { + status = versionRange_createVersionRange(version, true, NULL, true, range); + } + + return status; +} + +celix_status_t versionRange_isInRange(version_range_pt versionRange, version_pt version, bool *inRange) { + celix_status_t status; + if (versionRange->high == NULL) { + int cmp; + status = version_compareTo(version, versionRange->low, &cmp); + if (status == CELIX_SUCCESS) { + *inRange = (cmp >= 0); + } + } else if (versionRange->isLowInclusive && versionRange->isHighInclusive) { + int low, high; + status = version_compareTo(version, versionRange->low, &low); + if (status == CELIX_SUCCESS) { + status = version_compareTo(version, versionRange->high, &high); + if (status == CELIX_SUCCESS) { + *inRange = (low >= 0) && (high <= 0); + } + } + } else if (versionRange->isHighInclusive) { + int low, high; + status = version_compareTo(version, versionRange->low, &low); + if (status == CELIX_SUCCESS) { + status = version_compareTo(version, versionRange->high, &high); + if (status == CELIX_SUCCESS) { + *inRange = (low > 0) && (high <= 0); + } + } + } else if (versionRange->isLowInclusive) { + int low, high; + status = version_compareTo(version, versionRange->low, &low); + if (status == CELIX_SUCCESS) { + status = version_compareTo(version, versionRange->high, &high); + if (status == CELIX_SUCCESS) { + *inRange = (low >= 0) && (high < 0); + } + } + } else { + int low, high; + status = version_compareTo(version, versionRange->low, &low); + if (status == CELIX_SUCCESS) { + status = version_compareTo(version, versionRange->high, &high); + if (status == CELIX_SUCCESS) { + *inRange = (low > 0) && (high < 0); + } + } + } + + return status; +} + +celix_status_t versionRange_getLowVersion(version_range_pt versionRange, version_pt *lowVersion) { + celix_status_t status = CELIX_SUCCESS; + + if (versionRange == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + } + else { + *lowVersion = versionRange->low; + } + + return status; +} + +celix_status_t versionRange_isLowInclusive(version_range_pt versionRange, bool *isLowInclusive) { + celix_status_t status = CELIX_SUCCESS; + + if (versionRange == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + } + else { + *isLowInclusive = versionRange->isLowInclusive; + } + + return status; +} + +celix_status_t versionRange_getHighVersion(version_range_pt versionRange, version_pt *highVersion) { + celix_status_t status = CELIX_SUCCESS; + + if (versionRange == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + } + else { + *highVersion = versionRange->high; + } + + return status; +} + +celix_status_t versionRange_isHighInclusive(version_range_pt versionRange, bool *isHighInclusive) { + celix_status_t status = CELIX_SUCCESS; + + if (versionRange == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + } + else { + *isHighInclusive = versionRange->isHighInclusive; + } + + return status; +} + + +celix_status_t versionRange_parse(const char * rangeStr, version_range_pt *range) { + celix_status_t status; + if (strchr(rangeStr, ',') != NULL) { + int vlowL = strcspn(rangeStr+1, ","); + char * vlow = (char *) malloc(sizeof(char) * (vlowL + 1)); + if (!vlow) { + status = CELIX_ENOMEM; + } else { + int vhighL; + char * vhigh; + vlow = strncpy(vlow, rangeStr+1, vlowL); + vlow[vlowL] = '\0'; + vhighL = strlen(rangeStr+1) - vlowL - 2; + vhigh = (char *) malloc(sizeof(char) * (vhighL+1)); + if (!vhigh) { + status = CELIX_ENOMEM; + } else { + version_pt versionLow = NULL; + int rangeL = strlen(rangeStr); + char start = rangeStr[0]; + char end = rangeStr[rangeL-1]; + + vhigh = strncpy(vhigh, rangeStr+vlowL+2, vhighL); + vhigh[vhighL] = '\0'; + status = version_createVersionFromString(vlow, &versionLow); + if (status == CELIX_SUCCESS) { + version_pt versionHigh = NULL; + status = version_createVersionFromString(vhigh, &versionHigh); + if (status == CELIX_SUCCESS) { + status = versionRange_createVersionRange( + versionLow, + start == '[', + versionHigh, + end ==']', + range + ); + } + } + free(vhigh); + } + free(vlow); + + } + } else { + version_pt version = NULL; + status = version_createVersionFromString(rangeStr, &version); + if (status == CELIX_SUCCESS) { + status = versionRange_createVersionRange(version, true, NULL, false, range); + } + } + + return status; +} + http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/utils/src/version_range_private.h ---------------------------------------------------------------------- diff --git a/utils/src/version_range_private.h b/utils/src/version_range_private.h new file mode 100644 index 0000000..dfccd59 --- /dev/null +++ b/utils/src/version_range_private.h @@ -0,0 +1,41 @@ +/** + *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. + */ +/* + * version_range_private.h + * + * \date Dec 18, 2012 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + + +#ifndef VERSION_RANGE_PRIVATE_H_ +#define VERSION_RANGE_PRIVATE_H_ + +#include "version_range.h" + +struct versionRange { + version_pt low; + bool isLowInclusive; + version_pt high; + bool isHighInclusive; + +}; + +#endif /* VERSION_RANGE_PRIVATE_H_ */
