# HG changeset patch # User Olaf Wintermann # Date 1445016229 -7200 # Node ID b9a6af0ae41a32546f8810ce429da881687ab22d # Parent 59656cd164110a48f9b3567a7839beff4a68c3b7 ucx update diff -r 59656cd16411 -r b9a6af0ae41a src/server/config/conf.c --- a/src/server/config/conf.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/config/conf.c Fri Oct 16 19:23:49 2015 +0200 @@ -33,7 +33,7 @@ int cfg_parse_basic_file(ConfigParser *parser, FILE *in) { parser->lines = NULL; UcxMempool *mp = ucx_mempool_new(512); - parser->mp = ucx_mempool_allocator(mp); + parser->mp = mp->allocator; // one logical line over many lines sstr_t mline; diff -r 59656cd16411 -r b9a6af0ae41a src/server/daemon/config.c --- a/src/server/daemon/config.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/daemon/config.c Fri Oct 16 19:23:49 2015 +0200 @@ -38,6 +38,7 @@ #include #include +#include #include "httplistener.h" #include "config.h" @@ -301,14 +302,9 @@ } // mime file - sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile")); - - sstr_t base = sstr("config/"); - sstr_t file; - file.length = base.length + mf.length; - file.ptr = alloca(file.length + 1); - file.ptr[file.length] = 0; - file = sstrncat(file, 2, base, mf); + sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile")); + sstr_t base = sstr("config/"); + sstr_t file = sstrcat(2, base, mf); ConfigFile *f = cfgmgr_get_file(file); if(f == NULL) { @@ -323,6 +319,8 @@ if(cfgmgr_reload_file(f, cfg, NULL)) { free(f->file.ptr); free(f); + + free(file.ptr); return -1; } cfgmgr_attach_file(f); @@ -330,6 +328,7 @@ cfg->mimetypes = f->data; + free(file.ptr); return 0; } @@ -606,11 +605,8 @@ // load the object config file sstr_t base = sstr("config/"); - sstr_t file; - file.length = base.length + objfile.length + 1; - file.ptr = alloca(file.length); - file.ptr[file.length] = 0; - file = sstrncat(file, 2, base, objfile); + sstr_t file = sstrcat(2, base, objfile); + file = sstrcat(2, base, objfile); // the file is managed by the configuration manager ConfigFile *f = cfgmgr_get_file(file); @@ -624,18 +620,19 @@ if(cfgmgr_reload_file(f, cfg, NULL)) { free(f->file.ptr); free(f); + + free(file.ptr); return -1; } cfgmgr_attach_file(f); } vs->objectfile = sstrdup(file); vs->objects = (HTTPObjectConfig*)f->data; + free(file.ptr); + // load acl config file - file.length = base.length + aclfile.length + 1; - file.ptr = alloca(file.length); - file.ptr[file.length] = 0; - file = sstrncat(file, 2, base, aclfile); + file = sstrcat(2, base, aclfile); ConfigFile *aclf = cfgmgr_get_file(file); if(aclf == NULL) { @@ -648,11 +645,14 @@ if(cfgmgr_reload_file(aclf, cfg, NULL)) { free(aclf->file.ptr); free(aclf); + + free(file.ptr); return -1; } cfgmgr_attach_file(aclf); } vs->acls = aclf->data; + free(file.ptr); // set the access log for the virtual server // TODO: don't use always the default diff -r 59656cd16411 -r b9a6af0ae41a src/server/daemon/keyfile_auth.c --- a/src/server/daemon/keyfile_auth.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/daemon/keyfile_auth.c Fri Oct 16 19:23:49 2015 +0200 @@ -98,7 +98,6 @@ user->groups = calloc(ngroups, sizeof(sstr_t)); for(int i=0;igroups[i] = sstrdup(groups[i]); - //sstrdup(groups[i]); // wtf? } // add to keyfile diff -r 59656cd16411 -r b9a6af0ae41a src/server/daemon/log.c --- a/src/server/daemon/log.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/daemon/log.c Fri Oct 16 19:23:49 2015 +0200 @@ -233,11 +233,7 @@ lmsg.length = len; /* create message string */ - sstr_t message; - message.length = lpre.length + len; - message.ptr = malloc(message.length + 1); - - message = sstrncat(message, 2, lpre, lmsg); + sstr_t message = sstrcat(2, lpre, lmsg); /* write message to the log file */ log_file_writeln(message.ptr, message.length); diff -r 59656cd16411 -r b9a6af0ae41a src/server/daemon/request.h --- a/src/server/daemon/request.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/daemon/request.h Fri Oct 16 19:23:49 2015 +0200 @@ -46,7 +46,7 @@ void *jvm_context; }; -/* macros for short context access */ +/* macros for context access */ #define NCX_OI(rq) rq->context.objset_index #define NCX_DI(rq) rq->context.dtable_index diff -r 59656cd16411 -r b9a6af0ae41a src/server/util/util.c --- a/src/server/util/util.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/util/util.c Fri Oct 16 19:23:49 2015 +0200 @@ -472,27 +472,14 @@ sstr_t newstr; sstr_t s; - s.length = 0; - s.ptr = NULL; - newstr.length = parent.length + child.length; - if(parent.ptr[parent.length - 1] != '/') { - s = sstrn("/", 1); - newstr.length++; + + UcxAllocator a = util_pool_allocator(pool); + if(s.length == 1) { + newstr = sstrcat_a(&a, 3, parent, s, child); + } else { + newstr = sstrcat_a(&a, 2, parent, child); } - newstr.ptr = pool_malloc(pool, newstr.length + 1); - if(!newstr.ptr) { - // TODO: error - newstr.length = 0; - return newstr; - } - if(s.length == 1) { - newstr = sstrncat(newstr, 3, parent, s, child); - } else { - newstr = sstrncat(newstr, 2, parent, child); - } - newstr.ptr[newstr.length] = '\0'; - return newstr; } @@ -515,21 +502,33 @@ void util_add_ppath(sstr_t root, sstr_t path, pblock *vars) { // concat path - sstr_t translated_path; - translated_path.length = root.length + path.length; - translated_path.ptr = alloca(translated_path.length); + size_t length = root.length + path.length; + char *translated_path = alloca(length); - translated_path = sstrncat(translated_path, 2, root, path); + memcpy(translated_path, root.ptr, root.length); + memcpy(translated_path + root.length, path.ptr, path.length); + // add path to specified pblock pblock_kvinsert( pb_key_ppath, - translated_path.ptr, - translated_path.length, + translated_path, + length, vars); } +UcxAllocator util_pool_allocator(pool_handle_t *pool) { + UcxAllocator a; + a.malloc = (ucx_allocator_malloc)pool_malloc; + a.calloc = (ucx_allocator_calloc)pool_calloc; + a.realloc = (ucx_allocator_realloc)pool_realloc; + a.free = (ucx_allocator_free)pool_free; + a.pool = pool; + return a; +} + + // new - code in parts from params.cpp NSAPI_PUBLIC pblock* util_parse_param(pool_handle_t *pool, char *query) { pblock *pb = pblock_create_pool(pool, 32); diff -r 59656cd16411 -r b9a6af0ae41a src/server/util/util.h --- a/src/server/util/util.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/server/util/util.h Fri Oct 16 19:23:49 2015 +0200 @@ -233,6 +233,9 @@ NSAPI_PUBLIC void util_add_ppath(sstr_t root, sstr_t path, pblock *vars); +/* ucx utils */ +UcxAllocator util_pool_allocator(pool_handle_t *pool); + /* --- End common function prototypes --- */ /* --- Begin Unix-only function prototypes --- */ diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/Makefile --- a/src/ucx/Makefile Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/Makefile Fri Oct 16 19:23:49 2015 +0200 @@ -34,6 +34,7 @@ SRC = utils.c SRC += list.c SRC += map.c +SRC += avl.c SRC += properties.c SRC += mempool.c SRC += string.c @@ -41,6 +42,7 @@ SRC += allocator.c SRC += logging.c SRC += buffer.c +SRC += stack.c OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/ucx/%$(OBJ_EXT)) diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/allocator.c --- a/src/ucx/allocator.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/allocator.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/allocator.h --- a/src/ucx/allocator.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/allocator.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -157,6 +157,41 @@ void ucx_default_free(void *ignore, void *data); /** + * Shorthand for calling an allocators malloc function. + * @param allocator the allocator to use + * @param n size of space to allocate + * @return a pointer to the allocated memory area + */ +#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n)) + +/** + * Shorthand for calling an allocators calloc function. + * @param allocator the allocator to use + * @param n the count of elements the space should be allocated for + * @param size the size of each element + * @return a pointer to the allocated memory area + */ +#define alcalloc(allocator, n, size) \ + ((allocator)->calloc((allocator)->pool, n, size)) + +/** + * Shorthand for calling an allocators realloc function. + * @param allocator the allocator to use + * @param ptr the pointer to the memory area that shall be reallocated + * @param n the new size of the allocated memory area + * @return a pointer to the reallocated memory area + */ +#define alrealloc(allocator, ptr, n) \ + ((allocator)->realloc((allocator)->pool, ptr, n)) + +/** + * Shorthand for calling an allocators free function. + * @param allocator the allocator to use + * @param ptr the pointer to the memory area that shall be freed + */ +#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr)) + +/** * Convenient macro for a default allocator struct definition. */ #define UCX_ALLOCATOR_DEFAULT {NULL, \ diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/avl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/avl.c Fri Oct 16 19:23:49 2015 +0200 @@ -0,0 +1,272 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "avl.h" + +#define ptrcast(ptr) ((void*)(ptr)) + +static void ucx_avl_connect(UcxAVLTree *tree, + UcxAVLNode *node, UcxAVLNode *child, intptr_t nullkey) { + if (child) { + child->parent = node; + } + // if child is NULL, nullkey decides if left or right pointer is cleared + if (tree->cmpfunc( + ptrcast(child ? child->key : nullkey), + ptrcast(node->key), tree->userdata) > 0) { + node->right = child; + } else { + node->left = child; + } + size_t lh = node->left ? node->left->height : 0; + size_t rh = node->right ? node->right->height : 0; + node->height = 1 + (lh > rh ? lh : rh); +} + +#define avlheight(node) ((node) ? (node)->height : 0) + +static UcxAVLNode* avl_rotright(UcxAVLTree *tree, UcxAVLNode *l0) { + UcxAVLNode *p = l0->parent; + UcxAVLNode *l1 = l0->left; + if (p) { + ucx_avl_connect(tree, p, l1, 0); + } else { + l1->parent = NULL; + } + ucx_avl_connect(tree, l0, l1->right, l1->key); + ucx_avl_connect(tree, l1, l0, 0); + return l1; +} + +static UcxAVLNode* avl_rotleft(UcxAVLTree *tree, UcxAVLNode *l0) { + UcxAVLNode *p = l0->parent; + UcxAVLNode *l1 = l0->right; + if (p) { + ucx_avl_connect(tree, p, l1, 0); + } else { + l1->parent = NULL; + } + ucx_avl_connect(tree, l0, l1->left, l1->key); + ucx_avl_connect(tree, l1, l0, 0); + return l1; +} + +static void ucx_avl_balance(UcxAVLTree *tree, UcxAVLNode *n) { + int lh = avlheight(n->left); + int rh = avlheight(n->right); + n->height = 1 + (lh > rh ? lh : rh); + + if (lh - rh == 2) { + UcxAVLNode *c = n->left; + if (avlheight(c->right) - avlheight(c->left) == 1) { + avl_rotleft(tree, c); + } + n = avl_rotright(tree, n); + } else if (rh - lh == 2) { + UcxAVLNode *c = n->right; + if (avlheight(c->left) - avlheight(c->right) == 1) { + avl_rotright(tree, c); + } + n = avl_rotleft(tree, n); + } + + if (n->parent) { + ucx_avl_balance(tree, n->parent); + } else { + tree->root = n; + } +} + +UcxAVLTree *ucx_avl_new(cmp_func cmpfunc) { + return ucx_avl_new_a(cmpfunc, ucx_default_allocator()); +} + +UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator) { + UcxAVLTree *tree = almalloc(allocator, sizeof(UcxAVLTree)); + if (tree) { + tree->allocator = allocator; + tree->cmpfunc = cmpfunc; + tree->root = NULL; + tree->userdata = NULL; + } + + return tree; +} + +static void ucx_avl_free_node(UcxAllocator *al, UcxAVLNode *node) { + if (node) { + ucx_avl_free_node(al, node->left); + ucx_avl_free_node(al, node->right); + alfree(al, node); + } +} + +void ucx_avl_free(UcxAVLTree *tree) { + UcxAllocator *al = tree->allocator; + ucx_avl_free_node(al, tree->root); + alfree(al, tree); +} + +UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) { + UcxAVLNode *n = tree->root; + int cmpresult; + while (n && (cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + n = cmpresult > 0 ? n->right : n->left; + } + return n; +} + +void *ucx_avl_get(UcxAVLTree *tree, intptr_t key) { + UcxAVLNode *n = ucx_avl_get_node(tree, key); + return n ? n->value : NULL; +} + +int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value) { + return ucx_avl_put_s(tree, key, value, NULL); +} + +int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, + void **oldvalue) { + if (tree->root) { + UcxAVLNode *n = tree->root; + int cmpresult; + while ((cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + UcxAVLNode *m = cmpresult > 0 ? n->right : n->left; + if (m) { + n = m; + } else { + break; + } + } + + if (cmpresult) { + UcxAVLNode *e = almalloc(tree->allocator, sizeof(UcxAVLNode)); + if (e) { + e->key = key; e->value = value; e->height = 1; + e->parent = e->left = e->right = NULL; + ucx_avl_connect(tree, n, e, 0); + ucx_avl_balance(tree, n); + return 0; + } else { + return 1; + } + } else { + if (oldvalue) { + *oldvalue = n->value; + } + n->value = value; + return 0; + } + } else { + tree->root = almalloc(tree->allocator, sizeof(UcxAVLNode)); + if (tree->root) { + tree->root->key = key; tree->root->value = value; + tree->root->height = 1; + tree->root->parent = tree->root->left = tree->root->right = NULL; + + if (oldvalue) { + *oldvalue = NULL; + } + + return 0; + } else { + return 1; + } + } +} + +int ucx_avl_remove(UcxAVLTree *tree, intptr_t key) { + return ucx_avl_remove_s(tree, key, NULL, NULL); +} + +int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node) { + return ucx_avl_remove_s(tree, node->key, NULL, NULL); +} + +int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, + intptr_t *oldkey, void **oldvalue) { + + UcxAVLNode *n = tree->root; + int cmpresult; + while (n && (cmpresult = tree->cmpfunc( + ptrcast(key), ptrcast(n->key), tree->userdata))) { + n = cmpresult > 0 ? n->right : n->left; + } + if (n) { + if (oldkey) { + *oldkey = n->key; + } + if (oldvalue) { + *oldvalue = n->value; + } + + UcxAVLNode *p = n->parent; + if (n->left && n->right) { + UcxAVLNode *s = n->right; + while (s->left) { + s = s->left; + } + ucx_avl_connect(tree, s->parent, s->right, s->key); + n->key = s->key; n->value = s->value; + p = s->parent; + alfree(tree->allocator, s); + } else { + if (p) { + ucx_avl_connect(tree, p, n->right ? n->right:n->left, n->key); + } else { + tree->root = n->right ? n->right : n->left; + if (tree->root) { + tree->root->parent = NULL; + } + } + alfree(tree->allocator, n); + } + + if (p) { + ucx_avl_balance(tree, p); + } + + return 0; + } else { + return 1; + } +} + +static size_t ucx_avl_countn(UcxAVLNode *node) { + if (node) { + return 1 + ucx_avl_countn(node->left) + ucx_avl_countn(node->right); + } else { + return 0; + } +} + +size_t ucx_avl_count(UcxAVLTree *tree) { + return ucx_avl_countn(tree->root); +} diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/avl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/avl.h Fri Oct 16 19:23:49 2015 +0200 @@ -0,0 +1,249 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @file avl.h + * + * AVL tree implementation. + * + * This binary search tree implementation allows average O(1) insertion and + * removal of elements (excluding binary search time). + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_AVL_H +#define UCX_AVL_H + +#include "ucx.h" +#include "allocator.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX AVL Node type. + * + * @see UcxAVLNode + */ +typedef struct UcxAVLNode UcxAVLNode; + +/** + * UCX AVL Node. + */ +struct UcxAVLNode { + /** + * The key for this node. + */ + intptr_t key; + /** + * Data contained by this node. + */ + void *value; + /** + * The height of this (sub)-tree. + */ + size_t height; + /** + * Parent node. + */ + UcxAVLNode *parent; + /** + * Root node of left subtree. + */ + UcxAVLNode *left; + /** + * Root node of right subtree. + */ + UcxAVLNode *right; +}; + +/** + * UCX AVL Tree. + */ +typedef struct { + /** + * The UcxAllocator that shall be used to manage the memory for node data. + */ + UcxAllocator *allocator; + /** + * Root node of the tree. + */ + UcxAVLNode *root; + /** + * Compare function that shall be used to compare the UcxAVLNode keys. + * @see UcxAVLNode.key + */ + cmp_func cmpfunc; + /** + * Custom user data. + * This data will also be provided to the cmpfunc. + */ + void *userdata; +} UcxAVLTree; + +/** + * Initializes a new UcxAVLTree with a default allocator. + * + * @param cmpfunc the compare function that shall be used + * @return a new UcxAVLTree object + * @see ucx_avl_new_a() + */ +UcxAVLTree *ucx_avl_new(cmp_func cmpfunc); + +/** + * Initializes a new UcxAVLTree with the specified allocator. + * + * The cmpfunc should be capable of comparing two keys within this AVL tree. + * So if you want to use null terminated strings as keys, you could use the + * ucx_strcmp() function here. + * + * @param cmpfunc the compare function that shall be used + * @param allocator the UcxAllocator that shall be used + * @return a new UcxAVLTree object + */ +UcxAVLTree *ucx_avl_new_a(cmp_func cmpfunc, UcxAllocator *allocator); + +/** + * Destroys an UcxAVLTree. + * @param tree the tree to destroy + */ +void ucx_avl_free(UcxAVLTree *tree); + +/** + * Macro for initializing a new UcxAVLTree with the default allocator and a + * ucx_ptrcmp() compare function. + * + * @return a new default UcxAVLTree object + */ +#define ucx_avl_default_new() ucx_avl_new_a(ucx_ptrcmp, ucx_default_allocator()) + +/** + * Gets the node from the tree, that is associated with the specified key. + * @param tree the UcxAVLTree + * @param key the key + * @return the node (or NULL, if the key is not present) + */ +UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key); + +/** + * Gets the value from the tree, that is associated with the specified key. + * @param tree the UcxAVLTree + * @param key the key + * @return the value (or NULL, if the key is not present) + */ +void *ucx_avl_get(UcxAVLTree *tree, intptr_t key); + +/** + * Puts a key/value pair into the tree. + * + * Attention: use this function only, if a possible old value does not need + * to be preserved. + * + * @param tree the UcxAVLTree + * @param key the key + * @param value the new value + * @return zero, if and only if the operation succeeded + */ +int ucx_avl_put(UcxAVLTree *tree, intptr_t key, void *value); + +/** + * Puts a key/value pair into the tree. + * + * This is a secure function which saves the old value to the variable pointed + * at by oldvalue. + * + * @param tree the UcxAVLTree + * @param key the key + * @param value the new value + * @param oldvalue optional: a pointer to the location where a possible old + * value shall be stored + * @return zero, if and only if the operation succeeded + */ +int ucx_avl_put_s(UcxAVLTree *tree, intptr_t key, void *value, void **oldvalue); + +/** + * Removes a node from the AVL tree. + * + * Note: the specified node is logically removed. The tree implementation + * decides which memory area is freed. In most cases the here provided node + * is freed, so it's further use is generally undefined. + * + * @param tree the UcxAVLTree + * @param node the node to remove + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove_node(UcxAVLTree *tree, UcxAVLNode *node); + +/** + * Removes an element from the AVL tree. + * + * @param tree the UcxAVLTree + * @param key the key + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove(UcxAVLTree *tree, intptr_t key); + +/** + * Removes an element from the AVL tree. + * + * This is a secure function which saves the old key and value data from node + * to the variables at the location of oldkey and oldvalue (if specified), so + * they can be freed afterwards (if necessary). + * + * Note: the returned key in oldkey is possibly not the same as the provided + * key for the lookup (in terms of memory location). + * + * @param tree the UcxAVLTree + * @param key the key of the element to remove + * @param oldkey optional: a pointer to the location where the old key shall be + * stored + * @param oldvalue optional: a pointer to the location where the old value + * shall be stored + * @return zero, if and only if an element has been removed + */ +int ucx_avl_remove_s(UcxAVLTree *tree, intptr_t key, + intptr_t *oldkey, void **oldvalue); + +/** + * Counts the nodes in the specified UcxAVLTree. + * @param tree the AVL tree + * @return the node count + */ +size_t ucx_avl_count(UcxAVLTree *tree); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_AVL_H */ + diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/buffer.c --- a/src/ucx/buffer.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/buffer.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,22 +31,22 @@ #include #include -UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags) { +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) { UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); if (buffer) { buffer->flags = flags; if (!space) { - buffer->space = (char*)malloc(size); + buffer->space = (char*)malloc(capacity); if (!buffer->space) { free(buffer); return NULL; } - memset(buffer->space, 0, size); + memset(buffer->space, 0, capacity); buffer->flags |= UCX_BUFFER_AUTOFREE; } else { buffer->space = (char*)space; } - buffer->capacity = size; + buffer->capacity = capacity; buffer->size = 0; buffer->pos = 0; @@ -64,13 +64,8 @@ UcxBuffer* ucx_buffer_extract( UcxBuffer *src, size_t start, size_t length, int flags) { - if(src->size == 0) { - return NULL; - } - if (length == 0) { - length = src->size - start; - } - if (start+length > src->size) { + + if (src->size == 0 || length == 0 || start+length > src->capacity) { return NULL; } @@ -99,13 +94,21 @@ case SEEK_END: npos = buffer->size; break; + case SEEK_SET: + npos = 0; + break; default: - npos = 0; + return -1; } + size_t opos = npos; npos += offset; - if (npos > buffer->size) { + if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { + return -1; + } + + if (npos >= buffer->size) { return -1; } else { buffer->pos = npos; @@ -120,7 +123,17 @@ int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { size_t newcap = buffer->capacity; - while (buffer->pos + len > newcap) newcap <<= 1; + + if (buffer->capacity + len < buffer->capacity) { + return -1; + } + + while (buffer->capacity + len > newcap) { + newcap <<= 1; + if (newcap < buffer->capacity) { + return -1; + } + } char *newspace = (char*)realloc(buffer->space, newcap); if (newspace) { @@ -137,18 +150,25 @@ size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, UcxBuffer *buffer) { size_t len = size * nitems; - if (buffer->pos + len > buffer->capacity) { + size_t required = buffer->pos + len; + if (buffer->pos > required) { + return 0; + } + + if (required > buffer->capacity) { if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - if(ucx_buffer_extend(buffer, len)) { - return -1; + if (ucx_buffer_extend(buffer, required - buffer->capacity)) { + return 0; } } else { len = buffer->capacity - buffer->pos; - if (size > 1) len -= len%size; + if (size > 1) { + len -= len%size; + } } } - if (len <= 0) { + if (len == 0) { return len; } diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/buffer.h --- a/src/ucx/buffer.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/buffer.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -97,11 +97,11 @@ * * @param space pointer to the memory area, or NULL to allocate * new memory - * @param size the size of the buffer + * @param capacity the capacity of the buffer * @param flags buffer features (see UcxBuffer.flags) * @return the new buffer */ -UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags); +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); /** * Destroys a buffer. @@ -120,10 +120,9 @@ * * @param src the source buffer * @param start the start position of extraction - * @param length the count of bytes to extract or 0 if all of the remaining - * bytes shall be extracted + * @param length the count of bytes to extract (must not be zero) * @param flags feature mask for the new buffer - * @return + * @return a new buffer containing the extraction */ UcxBuffer* ucx_buffer_extract(UcxBuffer *src, size_t start, size_t length, int flags); @@ -136,7 +135,7 @@ * @return a new buffer with the extracted content */ #define ucx_buffer_clone(src,flags) \ - ucx_buffer_extract(src, 0, 0, flags) + ucx_buffer_extract(src, 0, (src)->capacity, flags) /** * Moves the position of the buffer. @@ -145,7 +144,11 @@ * * SEEK_SET marks the start of the buffer. * SEEK_CUR marks the current position. - * SEEK_END marks the first 0-byte in the buffer. + * SEEK_END marks the end of the buffer. + * + * With an offset of zero, this function sets the buffer position to zero + * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position + * unchanged (SEEK_CUR). * * @param buffer * @param offset position offset relative to whence @@ -182,12 +185,12 @@ * the buffer capacity is doubled, as long as it would not hold the current * content plus the additional required bytes. * - * Attention: the argument provided is the count of additional - * bytes the buffer shall hold. It is NOT the total count of bytes the + * Attention: the argument provided is the number of additional + * bytes the buffer shall hold. It is NOT the total number of bytes the * buffer shall hold. * * @param buffer the buffer to extend - * @param additional_bytes the count of additional bytes the buffer shall + * @param additional_bytes the number of additional bytes the buffer shall * at least hold * @return 0 on success or a non-zero value on failure */ @@ -216,7 +219,7 @@ * @param size the length of one element * @param nitems the element count * @param buffer the UcxBuffer to read from - * @return the total count of bytes read + * @return the total number of elements read */ size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, UcxBuffer *buffer); diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/list.c --- a/src/ucx/list.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/list.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -72,7 +72,7 @@ while (e != NULL) { f = e; e = e->next; - alloc->free(alloc->pool, f); + alfree(alloc, f); } } @@ -81,7 +81,7 @@ } UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { - UcxList *nl = (UcxList*) alloc->malloc(alloc->pool, sizeof(UcxList)); + UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList)); if (!nl) { return NULL; } @@ -121,7 +121,9 @@ if (l1) { UcxList *last = ucx_list_last(l1); last->next = l2; - l2->prev = last; + if (l2) { + l2->prev = last; + } return l1; } else { return l2; @@ -150,7 +152,7 @@ return -1; } -UcxList *ucx_list_get(const UcxList *l, int index) { +UcxList *ucx_list_get(const UcxList *l, size_t index) { if (l == NULL) return NULL; const UcxList *e = l; @@ -196,7 +198,7 @@ return s; } -UcxList *ucx_list_sort_merge(int length, +static UcxList *ucx_list_sort_merge(int length, UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, cmp_func fnc, void* data) { @@ -248,6 +250,8 @@ int ln = 1; UcxList *restrict ls = l, *restrict le, *restrict re; + + // check how many elements are already sorted lc = ls; while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { lc = lc->next; @@ -261,27 +265,30 @@ UcxList *rc; int rn = 1; rc = le; + // skip already sorted elements while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { rc = rc->next; rn++; } re = rc->next; - // Something left? Sort it! - UcxList *remainder = re; - size_t remainder_length = ucx_list_size(remainder); - if (remainder != NULL) { - remainder = ucx_list_sort(remainder, fnc, data); - } - // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them UcxList *sorted = ucx_list_sort_merge(ln+rn, ls, le, re, fnc, data); + + // Something left? Sort it! + size_t remainder_length = ucx_list_size(re); + if (remainder_length > 0) { + UcxList *remainder = ucx_list_sort(re, fnc, data); - // merge sorted list with (also sorted) remainder - l = ucx_list_sort_merge(ln+rn+remainder_length, - sorted, remainder, NULL, fnc, data); + // merge sorted list with (also sorted) remainder + l = ucx_list_sort_merge(ln+rn+remainder_length, + sorted, remainder, NULL, fnc, data); + } else { + // no remainder - we've got our sorted list + l = sorted; + } return l; } @@ -304,18 +311,18 @@ } UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) { - if (e->prev == NULL) { - if(e->next != NULL) { - e->next->prev = NULL; - l = e->next; - } else { - l = NULL; - } - - } else { - e->prev->next = e->next; + if (l == e) { + l = e->next; + } + + if (e->next) { e->next->prev = e->prev; } - alloc->free(alloc->pool, e); + + if (e->prev) { + e->prev->next = e->next; + } + + alfree(alloc, e); return l; } diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/list.h --- a/src/ucx/list.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/list.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -169,7 +169,7 @@ /** * Inserts an element at the end of the list. * - * This is generally an O(n) operation, as the end of the list is seeked with + * This is generally an O(n) operation, as the end of the list is retrieved with * ucx_list_last(). * * @param list the list where to append the data, or NULL to @@ -273,7 +273,7 @@ * @return the element at the specified index or NULL, if the * index is greater than the list size */ -UcxList *ucx_list_get(const UcxList *list, int index); +UcxList *ucx_list_get(const UcxList *list, size_t index); /** * Returns the index of an element. @@ -350,7 +350,7 @@ * mylist = ucx_list_remove(mylist, myelem);. * * @param list the list from which the element shall be removed - * @param element the element to removed + * @param element the element to remove * @return returns the updated list pointer or NULL, if the list * is now empty */ @@ -363,7 +363,7 @@ * * @param allocator the allocator to use * @param list the list from which the element shall be removed - * @param element the element to removed + * @param element the element to remove * @return returns the updated list pointer or NULL, if the list * @see ucx_list_remove() */ diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/logging.c --- a/src/ucx/logging.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/logging.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -75,6 +75,7 @@ if ((logger->mask & UCX_LOGGER_LEVEL) > 0) { text = (char*) ucx_map_int_get(logger->levels, level); n = strlen(text); + n = n > 256 ? 256 : n; memcpy(msg+k, text, n); k += n; msg[k++] = ' '; @@ -87,11 +88,7 @@ n = strlen(file); memcpy(msg+k, file, n); k += n; -#ifdef _WIN32 - k += _snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line); -#else - k += snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line); -#endif /* _WIN32 */ + k += sprintf(msg+k, ":%u ", line); } msg[k++] = '-'; msg[k++] = ' '; diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/logging.h --- a/src/ucx/logging.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/logging.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -97,7 +97,7 @@ write_func writer; /** - * The date format for timestamp outputs + * The date format for timestamp outputs including the delimiter * (default: "%F %T %z "). * @see UCX_LOGGER_TIMESTAMP */ @@ -162,7 +162,8 @@ * [LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message * * Attention: the message (including automatically generated information) - * MUST NOT exceed the size of 4 KB. + * is limited to 4096 characters. The level description is limited to + * 256 characters and the timestamp string is limited to 128 characters. * * @param logger the logger to use * @param level the level to log on diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/map.c --- a/src/ucx/map.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/map.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,18 +44,16 @@ allocator = ucx_default_allocator(); } - UcxMap *map = (UcxMap*)allocator->malloc(allocator->pool, sizeof(UcxMap)); + UcxMap *map = (UcxMap*)almalloc(allocator, sizeof(UcxMap)); if (!map) { return NULL; } map->allocator = allocator; - map->map = (UcxMapElement**)allocator->calloc( - allocator->pool, - size, - sizeof(UcxMapElement*)); + map->map = (UcxMapElement**)alcalloc( + allocator, size, sizeof(UcxMapElement*)); if(map->map == NULL) { - allocator->free(allocator->pool, map); + alfree(allocator, map); return NULL; } map->size = size; @@ -64,24 +62,41 @@ return map; } -static void ucx_map_free_elmlist(UcxMap *map) { +static void ucx_map_free_elmlist_contents(UcxMap *map) { for (size_t n = 0 ; n < map->size ; n++) { UcxMapElement *elem = map->map[n]; if (elem != NULL) { do { UcxMapElement *next = elem->next; - map->allocator->free(map->allocator->pool, elem->key.data); - map->allocator->free(map->allocator->pool, elem); + alfree(map->allocator, elem->key.data); + alfree(map->allocator, elem); elem = next; } while (elem != NULL); } } - map->allocator->free(map->allocator->pool, map->map); } void ucx_map_free(UcxMap *map) { - ucx_map_free_elmlist(map); - map->allocator->free(map->allocator->pool, map); + ucx_map_free_elmlist_contents(map); + alfree(map->allocator, map->map); + alfree(map->allocator, map); +} + +void ucx_map_free_content(UcxMap *map, ucx_destructor destr) { + UcxMapIterator iter = ucx_map_iterator(map); + void *val; + UCX_MAP_FOREACH(key, val, iter) { + destr(val); + } +} + +void ucx_map_clear(UcxMap *map) { + if (map->count == 0) { + return; // nothing to do + } + ucx_map_free_elmlist_contents(map); + memset(map->map, 0, map->size*sizeof(UcxMapElement*)); + map->count = 0; } int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, @@ -116,10 +131,8 @@ oldmap.allocator = map->allocator; map->size = (map->count * 5) >> 1; - map->map = (UcxMapElement**)map->allocator->calloc( - map->allocator->pool, - map->size, - sizeof(UcxMapElement*)); + map->map = (UcxMapElement**)alcalloc( + map->allocator, map->size, sizeof(UcxMapElement*)); if (!map->map) { *map = oldmap; return 1; @@ -128,7 +141,8 @@ ucx_map_copy(&oldmap, map, NULL, NULL); /* free the UcxMapElement list of oldmap */ - ucx_map_free_elmlist(&oldmap); + ucx_map_free_elmlist_contents(&oldmap); + alfree(map->allocator, oldmap.map); } return 0; } @@ -150,9 +164,8 @@ } if (!elm || elm->key.hash != key.hash) { - UcxMapElement *e = (UcxMapElement*)allocator->malloc( - allocator->pool, - sizeof(UcxMapElement)); + UcxMapElement *e = (UcxMapElement*)almalloc( + allocator, sizeof(UcxMapElement)); if (!e) { return -1; } @@ -167,7 +180,7 @@ } if (!elm->key.data) { - void *kd = allocator->malloc(allocator->pool, key.len); + void *kd = almalloc(allocator, key.len); if (!kd) { return -1; } @@ -200,8 +213,8 @@ } else { map->map[slot] = elm->next; } - map->allocator->free(map->allocator->pool, elm->key.data); - map->allocator->free(map->allocator->pool, elm); + alfree(map->allocator, elm->key.data); + alfree(map->allocator, elm); map->count--; } diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/map.h --- a/src/ucx/map.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/map.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -146,14 +146,45 @@ /** * Frees a hash map. * - * Note: the contents are not freed, use an UcxMempool for that - * purpose. + * Note: the contents are not freed, use ucx_map_free_content() + * before calling this function to achieve that. * * @param map the map to be freed + * @see ucx_map_free_content() */ void ucx_map_free(UcxMap *map); /** + * Frees the contents of a hash map. + * + * This is a convenience function that iterates over the map and passes all + * values to the specified destructor function (e.g. stdlib free()). + * + * You must ensure, that it is valid to pass each value in the map to the same + * destructor function. + * + * You should free or clear the map afterwards, as the contents will be invalid. + * + * @param map for which the contents shall be freed + * @param destr pointer to the destructor function + * @see ucx_map_free() + * @see ucx_map_clear() + */ +void ucx_map_free_content(UcxMap *map, ucx_destructor destr); + +/** + * Clears a hash map. + * + * Note: the contents are not freed, use ucx_map_free_content() + * before calling this function to achieve that. + * + * @param map the map to be cleared + * @see ucx_map_free_content() + */ +void ucx_map_clear(UcxMap *map); + + +/** * Copies contents from a map to another map using a copy function. * * Note: The destination map does not need to be empty. However, if it diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/mempool.c --- a/src/ucx/mempool.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/mempool.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -75,6 +75,20 @@ pool->ndata = 0; pool->size = n; + + UcxAllocator *allocator = (UcxAllocator*)malloc(sizeof(UcxAllocator)); + if(!allocator) { + free(pool->data); + free(pool); + return NULL; + } + allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; + allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; + allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; + allocator->free = (ucx_allocator_free)ucx_mempool_free; + allocator->pool = pool; + pool->allocator = allocator; + return pool; } @@ -173,6 +187,7 @@ } } free(pool->data); + free(pool->allocator); free(pool); } @@ -189,16 +204,3 @@ ucx_mempool_set_destr(rd, ucx_mempool_shared_destr); } -UcxAllocator* ucx_mempool_allocator(UcxMempool *pool) { - UcxAllocator *allocator = (UcxAllocator*)ucx_mempool_malloc( - pool, sizeof(UcxAllocator)); - if(!allocator) { - return NULL; - } - allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; - allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; - allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; - allocator->free = (ucx_allocator_free)ucx_mempool_free; - allocator->pool = pool; - return allocator; -} diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/mempool.h --- a/src/ucx/mempool.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/mempool.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -47,24 +47,20 @@ #endif /** - * A function pointer to a destructor function. - * @see ucx_mempool_setdestr() - * @see ucx_mempool_regdestr() - */ -typedef void(*ucx_destructor)(void*); - -/** * UCX mempool structure. */ typedef struct { + /** UcxAllocator based on this pool */ + UcxAllocator *allocator; + /** List of pointers to pooled memory. */ - void **data; + void **data; /** Count of pooled memory items. */ - size_t ndata; + size_t ndata; /** Memory pool size. */ - size_t size; + size_t size; } UcxMempool; /** Shorthand for a new default memory pool with a capacity of 16 elements. */ @@ -118,7 +114,7 @@ /** * Allocates a pooled memory array. * - * The contents of the allocated memory is set to zero. + * The content of the allocated memory is set to zero. * * @param pool the memory pool * @param nelem amount of elements to allocate @@ -139,7 +135,7 @@ * @param pool the memory pool * @param ptr a pointer to the memory that shall be reallocated * @param n the new size of the memory - * @return a pointer to the the location of the memory + * @return a pointer to the new location of the memory * @see ucx_allocator_realloc() */ void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); @@ -210,14 +206,6 @@ */ void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); -/** - * Creates an UcxAllocator based on an UcxMempool. - * - * @param pool the mempool to create the UcxAllocator for - * @return a new UcxAllocator based on the specified pool - */ -UcxAllocator* ucx_mempool_allocator(UcxMempool *pool); - #ifdef __cplusplus } #endif diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/properties.c --- a/src/ucx/properties.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/properties.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -206,7 +206,7 @@ return 1; } if(ucx_map_sstr_put(map, name, value.ptr)) { - map->allocator->free(map->allocator->pool, value.ptr); + alfree(map->allocator, value.ptr); return 1; } } diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/properties.h --- a/src/ucx/properties.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/properties.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/stack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/stack.c Fri Oct 16 19:23:49 2015 +0200 @@ -0,0 +1,143 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stack.h" +#include + +static size_t ucx_stack_align(size_t n) { + int align = n % sizeof(void*); + if (align) { + n += sizeof(void*) - align; + } + return n; +} + +void ucx_stack_init(UcxStack *stack, char* space, size_t size) { + stack->size = size - size % sizeof(void*); + stack->space = space; + stack->top = NULL; + + stack->allocator.pool = stack; + stack->allocator.malloc = (ucx_allocator_malloc) ucx_stack_malloc; + stack->allocator.calloc = (ucx_allocator_calloc) ucx_stack_calloc; + stack->allocator.realloc = (ucx_allocator_realloc) ucx_stack_realloc; + stack->allocator.free = (ucx_allocator_free) ucx_stack_free; +} + +void *ucx_stack_malloc(UcxStack *stack, size_t n) { + + if (ucx_stack_avail(stack) < ucx_stack_align(n)) { + return NULL; + } else { + char *prev = stack->top; + if (stack->top) { + stack->top += ucx_stack_align(ucx_stack_topsize(stack)); + } else { + stack->top = stack->space; + } + + ((struct ucx_stack_metadata*)stack->top)->prev = prev; + ((struct ucx_stack_metadata*)stack->top)->size = n; + stack->top += sizeof(struct ucx_stack_metadata); + + return stack->top; + } +} + +void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize) { + void *mem = ucx_stack_malloc(stack, nelem*elsize); + memset(mem, 0, nelem*elsize); + return mem; +} + +void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n) { + if (ptr == stack->top) { + if (stack->size - (stack->top - stack->space) < ucx_stack_align(n)) { + return NULL; + } else { + ((struct ucx_stack_metadata*)stack->top - 1)->size = n; + return ptr; + } + } else { + if (ucx_stack_align(((struct ucx_stack_metadata*)ptr - 1)->size) < + ucx_stack_align(n)) { + void *nptr = ucx_stack_malloc(stack, n); + if (nptr) { + memcpy(nptr, ptr, n); + ucx_stack_free(stack, ptr); + + return nptr; + } else { + return NULL; + } + } else { + ((struct ucx_stack_metadata*)ptr - 1)->size = n; + return ptr; + } + } +} + +void ucx_stack_free(UcxStack *stack, void *ptr) { + if (ptr == stack->top) { + stack->top = ((struct ucx_stack_metadata*) stack->top - 1)->prev; + } else { + struct ucx_stack_metadata *next = (struct ucx_stack_metadata*)( + (char*)ptr + + ucx_stack_align(((struct ucx_stack_metadata*) ptr - 1)->size) + ); + next->prev = ((struct ucx_stack_metadata*) ptr - 1)->prev; + } +} + +void ucx_stack_popn(UcxStack *stack, void *dest, size_t n) { + if (ucx_stack_empty(stack)) { + return; + } + + size_t len = ucx_stack_topsize(stack); + if (len > n) { + len = n; + } + + memcpy(dest, stack->top, len); + + ucx_stack_free(stack, stack->top); +} + +size_t ucx_stack_avail(UcxStack *stack) { + size_t avail = ((stack->top ? (stack->size + - (stack->top - stack->space) + - ucx_stack_align(ucx_stack_topsize(stack))) + : stack->size)); + + if (avail > sizeof(struct ucx_stack_metadata)) { + return avail - sizeof(struct ucx_stack_metadata); + } else { + return 0; + } +} diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/stack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/stack.h Fri Oct 16 19:23:49 2015 +0200 @@ -0,0 +1,233 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file stack.h + * + * Default stack memory allocation implementation. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_STACK_H +#define UCX_STACK_H + +#include "ucx.h" +#include +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * UCX stack structure. + */ +typedef struct { + /** UcxAllocator based on this stack */ + UcxAllocator allocator; + + /** Stack size. */ + size_t size; + + /** Pointer to the bottom of the stack */ + char *space; + + /** Pointer to the top of the stack */ + char *top; +} UcxStack; + +/** + * Metadata for each UCX stack element. + */ +struct ucx_stack_metadata { + /** + * Location of the previous element (NULL if this is the first) + */ + char *prev; + + /** Size of this element */ + size_t size; +}; + +/** + * Initializes UcxStack structure with memory. + * + * @param stack a pointer to an uninitialized stack structure + * @param space the memory area that shall be managed + * @param size size of the memory area + * @return a new UcxStack structure + */ +void ucx_stack_init(UcxStack *stack, char* space, size_t size); + +/** + * Allocates stack memory. + * + * @param stack a pointer to the stack + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_allocator_malloc() + */ +void *ucx_stack_malloc(UcxStack *stack, size_t n); + +/** + * Alias for #ucx_stack_malloc(). + * @param stack a pointer to the stack + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_stack_malloc + */ +#define ucx_stack_push(stack, n) ucx_stack_malloc(stack, n) + +/** + * Allocates an array of stack memory + * + * The content of the allocated memory is set to zero. + * + * @param stack a pointer to the stack + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_allocator_calloc() + */ +void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize); + +/** + * Alias for #ucx_stack_calloc(). + * + * @param stack a pointer to the stack + * @param n amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_stack_calloc + */ +#define ucx_stack_pusharr(stack,n,elsize) ucx_stack_calloc(stack,n,elssize) + +/** + * Reallocates memory on the stack. + * + * Shrinking memory is always safe. Extending memory can be very expensive. + * + * @param stack the stack + * @param ptr a pointer to the memory that shall be reallocated + * @param n the new size of the memory + * @return a pointer to the new location of the memory + * @see ucx_allocator_realloc() + */ +void *ucx_stack_realloc(UcxStack *stack, void *ptr, size_t n); + +/** + * Frees memory on the stack. + * + * Freeing stack memory behaves in a special way. + * + * If the element, that should be freed, is the top most element of the stack, + * it is removed from the stack. Otherwise it is marked as freed. Marked + * elements are removed, when they become the top most elements of the stack. + * + * @param stack a pointer to the stack + * @param ptr a pointer to the memory that shall be freed + */ +void ucx_stack_free(UcxStack *stack, void *ptr); + + +/** + * Returns the size of the top most element. + * @param stack a pointer to the stack + * @return the size of the top most element + */ +#define ucx_stack_topsize(stack) ((stack)->top ? ((struct ucx_stack_metadata*)\ + (stack)->top - 1)->size : 0) + +/** + * Removes the top most element from the stack and copies the content to + * dest, if specified. + * + * Use #ucx_stack_topsize()# to get the amount of memory that must be available + * at the location of dest. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to, or + * NULL, if the element shall only be removed. + * @see ucx_stack_free + * @see ucx_stack_popn + */ +#define ucx_stack_pop(stack, dest) ucx_stack_popn(stack, dest, SIZE_MAX) + +/** + * Removes the top most element from the stack and copies the content to + * dest. + * + * In contrast to #ucx_stack_pop() the dest pointer MUST + * NOT be NULL. + * + * @param stack a pointer to the stack + * @param dest the location where the contents shall be written to + * @param n copies at most n elements to dest + * @see ucx_stack_pop + */ +void ucx_stack_popn(UcxStack *stack, void *dest, size_t n); + +/** + * Returns the remaining available memory on the specified stack. + * + * @param stack a pointer to the stack + * @return the remaining available memory + */ +size_t ucx_stack_avail(UcxStack *stack); + +/** + * Checks, if the stack is empty. + * + * @param stack a pointer to the stack + * @return nonzero, if the stack is empty, zero otherwise + */ +#define ucx_stack_empty(stack) (!(stack)->top) + +/** + * Computes a recommended size for the stack memory area. Note, that + * reallocations have not been taken into account, so you might need to reserve + * twice as much memory to allow many reallocations. + * + * @param size the approximate payload + * @param elems the approximate count of element allocations + * @return a recommended size for the stack space based on the information + * provided + */ +#define ucx_stack_dim(size, elems) (size+sizeof(struct ucx_stack_metadata) * \ + (elems + 1)) + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_STACK_H */ + diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/string.c --- a/src/ucx/string.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/string.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,6 +29,7 @@ #include #include #include +#include #include "string.h" #include "allocator.h" @@ -61,32 +62,71 @@ return size; } -sstr_t sstrncat(sstr_t s, size_t n, sstr_t c1, ...) { - va_list ap; - va_start(ap, c1); - s.ptr[0] = 0; +static sstr_t sstrvcat_a( + UcxAllocator *a, + size_t count, + sstr_t s1, + sstr_t s2, + va_list ap) { + sstr_t str; + str.ptr = NULL; + str.length = 0; + if(count < 2) { + return str; + } - size_t len = s.length; - size_t cplen = c1.length > len ? len : c1.length; - char *ptr = s.ptr; + sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t)); + if(!strings) { + return str; + } + + // get all args and overall length + strings[0] = s1; + strings[1] = s2; + size_t strlen = s1.length + s2.length; + for (size_t i=2;i len ? len : str.length; - if(cplen <= 0) { - va_end(ap); - return s; - } - memcpy(ptr, str.ptr, cplen); - len -= cplen; - ptr += cplen; + // create new string + str.ptr = (char*) almalloc(a, strlen + 1); + str.length = strlen; + if(!str.ptr) { + free(strings); + str.length = 0; + return str; + } + + // concatenate strings + size_t pos = 0; + for (size_t i=0;i= s.length) { - return s; + new_sstr.ptr = NULL; + new_sstr.length = 0; + } else { + if (length > s.length-start) { + length = s.length-start; + } + new_sstr.ptr = &s.ptr[start]; + new_sstr.length = length; } - if (length > s.length-start) { - length = s.length-start; - } - new_sstr.ptr = &s.ptr[start]; - new_sstr.length = length; return new_sstr; } @@ -133,18 +175,18 @@ return n; } -sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) { +sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { return sstrsplit_a(ucx_default_allocator(), s, d, n); } -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, size_t *n) { +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) { if (s.length == 0 || d.length == 0) { *n = -1; return NULL; } sstr_t* result; - size_t nmax = *n; + ssize_t nmax = *n; *n = 1; /* special case: exact match - no processing needed */ @@ -179,18 +221,27 @@ } if ((*n) == nmax) break; } - result = (sstr_t*) allocator->malloc(allocator->pool, sizeof(sstr_t)*(*n)); + result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)*(*n)); if (result) { char *pptr = sv.ptr; - for (size_t i = 0 ; i < *n ; i++) { + for (ssize_t i = 0 ; i < *n ; i++) { size_t l = strlen(pptr); - char* ptr = (char*) allocator->malloc(allocator->pool, l + 1); - memcpy(ptr, pptr, l); - ptr[l] = 0; + char* ptr = (char*) almalloc(allocator, l + 1); + if (ptr) { + memcpy(ptr, pptr, l); + ptr[l] = 0; - result[i] = sstrn(ptr, l); - pptr += l + d.length; + result[i] = sstrn(ptr, l); + pptr += l + d.length; + } else { + for (ssize_t j = i-1 ; j >= 0 ; j--) { + alfree(allocator, result[j].ptr); + } + alfree(allocator, result); + *n = -2; + break; + } } } else { *n = -2; @@ -231,7 +282,7 @@ sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { sstr_t newstring; - newstring.ptr = (char*)allocator->malloc(allocator->pool, s.length + 1); + newstring.ptr = (char*)almalloc(allocator, s.length + 1); if (newstring.ptr) { newstring.length = s.length; newstring.ptr[newstring.length] = 0; @@ -246,38 +297,15 @@ sstr_t sstrtrim(sstr_t string) { sstr_t newstr = string; - if (string.length == 0) { - return newstr; - } - size_t i; - for(i=0;i 32) { - break; - } + while (newstr.length > 0 && isspace(*newstr.ptr)) { + newstr.ptr++; + newstr.length--; } - newstr.ptr = &string.ptr[i]; - newstr.length = string.length - i; - - if(newstr.length == 0) { - return newstr; + while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) { + newstr.length--; } - i = newstr.length - 1; - for(;;) { - char c = newstr.ptr[i]; - if(c > 32) { - break; - } - if(i > 0) { - i--; - } else { - break; - } - } - newstr.length = i + 1; - return newstr; } @@ -311,3 +339,35 @@ suffix.ptr, suffix.length) == 0; } } + +sstr_t sstrlower(sstr_t string) { + sstr_t ret = sstrdup(string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = tolower(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) { + sstr_t ret = sstrdup_a(allocator, string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = tolower(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrupper(sstr_t string) { + sstr_t ret = sstrdup(string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = toupper(ret.ptr[i]); + } + return ret; +} + +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) { + sstr_t ret = sstrdup_a(allocator, string); + for (size_t i = 0; i < ret.length ; i++) { + ret.ptr[i] = toupper(ret.ptr[i]); + } + return ret; +} diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/string.h --- a/src/ucx/string.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/string.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -119,38 +119,36 @@ */ size_t sstrnlen(size_t count, sstr_t string, ...); +/** + * Concatenates two or more strings. + * + * The resulting string will be allocated by standard malloc(). + * So developers MUST pass the sstr_t.ptr to free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param count the total number of strings to concatenate + * @param s1 first string + * @param s2 second string + * @param ... all remaining strings + * @return the concatenated string + */ +sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); /** - * Concatenates strings. - * - * At least one string must be specified and there must be enough memory - * available referenced by the destination sstr_t.ptr for this function to - * successfully concatenate all specified strings. - * - * The sstr_t.length of the destination string specifies the capacity and - * should match the total memory available referenced by the destination - * sstr_t.ptr. This function never copies data beyond the capacity and - * does not modify any of the source strings. + * Concatenates two or more strings using an UcxAllocator. * - * Attention: - *
    - *
  • Any content in the destination string will be overwritten
  • - *
  • The destination sstr_t.ptr is NOT - * NULL-terminated
  • - *
  • The destination sstr_t.length is set to the total length of the - * concatenated strings
  • - *
  • Hint: get a NULL-terminated string by performing - * mystring.ptr[mystring.length]='\0' after calling this - * function
  • - *
+ * See sstrcat() for details. * - * @param dest new sstr_t with capacity information and allocated memory + * @param a the allocator to use * @param count the total number of strings to concatenate - * @param src the first string - * @param ... all other strings - * @return the argument for dest is returned + * @param s1 first string + * @param s2 second string + * @param ... all remaining strings + * @return the concatenated string */ -sstr_t sstrncat(sstr_t dest, size_t count, sstr_t src, ...); +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...); /** @@ -227,7 +225,7 @@ * * * The integer referenced by count is used as input and determines - * the maximum size of the resulting list, i.e. the maximum count of splits to + * the maximum size of the resulting array, i.e. the maximum count of splits to * perform + 1. * * The integer referenced by count is also used as output and is @@ -237,36 +235,36 @@ *
  • -1, if either the string or the delimiter is an empty string
  • *
  • 0, if the string equals the delimiter
  • *
  • 1, if the string does not contain the delimiter
  • - *
  • the count of list items, otherwise
  • + *
  • the count of array items, otherwise
  • * * * If the string starts with the delimiter, the first item of the resulting - * list will be an empty string. + * array will be an empty string. * * If the string ends with the delimiter and the maximum list size is not - * exceeded, the last list item will be an empty string. + * exceeded, the last array item will be an empty string. * - * Attention: All list items AND all sstr_t.ptr of the list + * Attention: The array pointer AND all sstr_t.ptr of the array * items must be manually passed to free(). Use sstrsplit_a() with * an allocator to managed memory, to avoid this. * * @param string the string to split * @param delim the delimiter string - * @param count IN: the maximum size of the resulting list (0 for an - * unbounded list), OUT: the actual size of the list - * @return a list of the split strings as sstr_t array or + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or * NULL on error * * @see sstrsplit_a() */ -sstr_t* sstrsplit(sstr_t string, sstr_t delim, size_t *count); +sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); /** * Performing sstrsplit() using an UcxAllocator. * * Read the description of sstrsplit() for details. * - * The memory for the sstr_t.ptr pointers of the list items and the memory for + * The memory for the sstr_t.ptr pointers of the array items and the memory for * the sstr_t array itself are allocated by using the UcxAllocator.malloc() * function. * @@ -276,15 +274,15 @@ * @param allocator the UcxAllocator used for allocating memory * @param string the string to split * @param delim the delimiter string - * @param count IN: the maximum size of the resulting list (0 for an - * unbounded list), OUT: the actual size of the list - * @return a list of the split strings as sstr_t array or + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or * NULL on error * * @see sstrsplit() */ sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, - size_t *count); + ssize_t *count); /** * Compares two UCX strings with standard memcmp(). @@ -385,6 +383,56 @@ */ int sstrsuffix(sstr_t string, sstr_t suffix); +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup() for the implications. + * + * @param string the input string + * @return the resulting lower case string + * @see sstrdup() + */ +sstr_t sstrlower(sstr_t string); + +/** + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup_a() for the implications. + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting lower case string + * @see sstrdup_a() + */ +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string); + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup() for the implications. + * + * @param string the input string + * @return the resulting upper case string + * @see sstrdup() + */ +sstr_t sstrupper(sstr_t string); + +/** + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first. See the + * documentation of sstrdup_a() for the implications. + * + * @param allocator the allocator used for duplicating the string + * @param string the input string + * @return the resulting upper case string + * @see sstrdup_a() + */ +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string); + #ifdef __cplusplus } #endif diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/test.c --- a/src/ucx/test.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/test.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/test.h --- a/src/ucx/test.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/test.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -84,8 +84,8 @@ /** * Alias for the __func__ preprocessor macro. - * Some compilers use __func__ and others use __FUNC__. - * We use __FUNC__ so we define it for those compilers which use + * Some compilers use __func__ and others use __FUNCTION__. + * We use __FUNCTION__ so we define it for those compilers which use * __func__. */ #define __FUNCTION__ __func__ diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/ucx.c --- a/src/ucx/ucx.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/ucx.c Fri Oct 16 19:23:49 2015 +0200 @@ -9,7 +9,7 @@ * *

    LICENCE

    * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/ucx.h --- a/src/ucx/ucx.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/ucx.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,10 +37,10 @@ #define UCX_H /** Major UCX version as integer constant. */ -#define UCX_VERSION_MAJOR 1 +#define UCX_VERSION_MAJOR 0 /** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 0 +#define UCX_VERSION_MINOR 9 /** The UCX version in format [major].[minor] */ #define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR @@ -70,6 +70,14 @@ /** Pointless in C. */ #define UCX_EXTERN #endif + + +/** + * A function pointer to a destructor function. + * @see ucx_mempool_setdestr() + * @see ucx_mempool_regdestr() + */ +typedef void(*ucx_destructor)(void*); /** * Function pointer to a compare function. diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/utils.c --- a/src/ucx/utils.c Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/utils.c Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -54,18 +54,22 @@ return 0; } + char *lbuf; size_t ncp = 0; - if (!buf) { - buf = (char*)malloc(bufsize); - if(buf == NULL) { + + if(buf) { + lbuf = buf; + } else { + lbuf = (char*)malloc(bufsize); + if(lbuf == NULL) { return 0; } } size_t r; size_t rn = bufsize > n ? n : bufsize; - while((r = readfnc(buf, 1, rn, src)) != 0) { - r = writefnc(buf, 1, r, dest); + while((r = readfnc(lbuf, 1, rn, src)) != 0) { + r = writefnc(lbuf, 1, r, dest); ncp += r; n -= r; rn = bufsize > n ? n : bufsize; @@ -74,7 +78,10 @@ } } - free(buf); + if (lbuf != buf) { + free(lbuf); + } + return ncp; } @@ -121,10 +128,12 @@ } int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) { - if (ptr1 == ptr2) { + intptr_t p1 = (intptr_t) ptr1; + intptr_t p2 = (intptr_t) ptr2; + if (p1 == p2) { return 0; } else { - return ptr1 < ptr2 ? -1 : 1; + return p1 < p2 ? -1 : 1; } } @@ -212,30 +221,36 @@ va_copy(ap2, ap); int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)a->malloc(a->pool, ret + 1); - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; + s.ptr = (char*)almalloc(a, ret + 1); + if (s.ptr) { + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } } else if (ret == INT_MAX) { errno = ENOMEM; } else { int len = ret + 1; - s.ptr = (char*)a->malloc(a->pool, len); - ret = vsnprintf(s.ptr, len, fmt, ap2); - if (ret < 0) { - free(s.ptr); - s.ptr = NULL; - } else { - s.length = (size_t)ret; + s.ptr = (char*)almalloc(a, len); + if (s.ptr) { + ret = vsnprintf(s.ptr, len, fmt, ap2); + if (ret < 0) { + free(s.ptr); + s.ptr = NULL; + } else { + s.length = (size_t)ret; + } } } #else int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)a->malloc(a->pool, ret + 1); - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; + s.ptr = (char*)almalloc(a, ret + 1); + if (s.ptr) { + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } } else { errno = ENOMEM; } diff -r 59656cd16411 -r b9a6af0ae41a src/ucx/utils.h --- a/src/ucx/utils.h Mon Apr 06 16:36:25 2015 +0200 +++ b/src/ucx/utils.h Fri Oct 16 19:23:49 2015 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2013 Olaf Wintermann. All rights reserved. + * Copyright 2015 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -219,6 +219,10 @@ */ sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); +/** Shortcut for ucx_asprintf() with default allocator. */ +#define ucx_sprintf(fmt, ...) \ + ucx_asprintf(ucx_default_allocator(), fmt, __VA_ARGS__) + /** * va_list version of ucx_asprintf(). *