ucx update

Fri, 16 Oct 2015 19:23:49 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 16 Oct 2015 19:23:49 +0200
changeset 99
b9a6af0ae41a
parent 98
59656cd16411
child 100
e9bb8449df02

ucx update

src/server/config/conf.c file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/keyfile_auth.c file | annotate | diff | comparison | revisions
src/server/daemon/log.c file | annotate | diff | comparison | revisions
src/server/daemon/request.h file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
src/ucx/Makefile file | annotate | diff | comparison | revisions
src/ucx/allocator.c file | annotate | diff | comparison | revisions
src/ucx/allocator.h file | annotate | diff | comparison | revisions
src/ucx/avl.c file | annotate | diff | comparison | revisions
src/ucx/avl.h file | annotate | diff | comparison | revisions
src/ucx/buffer.c file | annotate | diff | comparison | revisions
src/ucx/buffer.h file | annotate | diff | comparison | revisions
src/ucx/list.c file | annotate | diff | comparison | revisions
src/ucx/list.h file | annotate | diff | comparison | revisions
src/ucx/logging.c file | annotate | diff | comparison | revisions
src/ucx/logging.h file | annotate | diff | comparison | revisions
src/ucx/map.c file | annotate | diff | comparison | revisions
src/ucx/map.h file | annotate | diff | comparison | revisions
src/ucx/mempool.c file | annotate | diff | comparison | revisions
src/ucx/mempool.h file | annotate | diff | comparison | revisions
src/ucx/properties.c file | annotate | diff | comparison | revisions
src/ucx/properties.h file | annotate | diff | comparison | revisions
src/ucx/stack.c file | annotate | diff | comparison | revisions
src/ucx/stack.h file | annotate | diff | comparison | revisions
src/ucx/string.c file | annotate | diff | comparison | revisions
src/ucx/string.h file | annotate | diff | comparison | revisions
src/ucx/test.c file | annotate | diff | comparison | revisions
src/ucx/test.h file | annotate | diff | comparison | revisions
src/ucx/ucx.c file | annotate | diff | comparison | revisions
src/ucx/ucx.h file | annotate | diff | comparison | revisions
src/ucx/utils.c file | annotate | diff | comparison | revisions
src/ucx/utils.h file | annotate | diff | comparison | revisions
--- 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;
--- 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 <sys/mman.h>
 
 #include <ucx/string.h>
+#include <ucx/utils.h>
 
 #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
--- 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;i<ngroups;i++) {
         user->groups[i] = sstrdup(groups[i]);
-        //sstrdup(groups[i]); // wtf?
     }
     
     // add to keyfile
--- 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);
--- 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
 
--- 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);
--- 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 --- */
--- 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))
 
--- 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:
--- 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 <code>struct</code> definition.
  */
 #define UCX_ALLOCATOR_DEFAULT {NULL, \
--- /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);
+}
--- /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 <stdint.h>
+
+#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 <code>NULL</code>, 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 <code>NULL</code>, 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 */
+
--- 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 <stdlib.h>
 #include <string.h>
 
-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;
     }
     
--- 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 <code>NULL</code> 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 <code>whence</code>
@@ -182,12 +185,12 @@
  * the buffer capacity is doubled, as long as it would not hold the current
  * content plus the additional required bytes.
  * 
- * <b>Attention:</b> the argument provided is the count of <i>additional</i>
- * bytes the buffer shall hold. It is <b>NOT</b> the total count of bytes the
+ * <b>Attention:</b> the argument provided is the number of <i>additional</i>
+ * bytes the buffer shall hold. It is <b>NOT</b> 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
  * <i>at least</i> 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);
--- 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;
 }
--- 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 <code>NULL</code> to
@@ -273,7 +273,7 @@
  * @return the element at the specified index or <code>NULL</code>, 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 @@
  * <code>mylist = ucx_list_remove(mylist, myelem);</code>.
  * 
  * @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 <code>NULL</code>, 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 <code>NULL</code>, if the list
  * @see ucx_list_remove()
  */
--- 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++] = ' ';
--- 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: <code>"%F %T %z "</code>).
      * @see UCX_LOGGER_TIMESTAMP
      */
@@ -162,7 +162,8 @@
  * <code>[LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message</code>
  * 
  * <b>Attention:</b> the message (including automatically generated information)
- * <b>MUST NOT</b> 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
--- 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--;
                 }
 
--- 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.
  * 
- * <b>Note:</b> the contents are <b>not</b> freed, use an UcxMempool for that
- * purpose.
+ * <b>Note:</b> the contents are <b>not</b> 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.
+ * 
+ * <b>Note:</b> the contents are <b>not</b> 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.
  * 
  * <b>Note:</b> The destination map does not need to be empty. However, if it
--- 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;
-}
--- 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
--- 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;
         }
     }
--- 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:
--- /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 <string.h>
+
+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;
+    }
+}
--- /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 <stdint.h>
+#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 (<code>NULL</code> 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 <code>
+ * dest</code>, if specified.
+ * 
+ * Use #ucx_stack_topsize()# to get the amount of memory that must be available
+ * at the location of <code>dest</code>.
+ * 
+ * @param stack a pointer to the stack
+ * @param dest the location where the contents shall be written to, or <code>
+ * NULL</code>, 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 <code>
+ * dest</code>.
+ * 
+ * In contrast to #ucx_stack_pop() the <code>dest</code> pointer <code>MUST
+ * NOT</code> be <code>NULL</code>.
+ * 
+ * @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 <code>dest</code>
+ * @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 */
+
--- 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 <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <ctype.h>
 
 #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<count;i++) {
+        sstr_t s = va_arg (ap, sstr_t);
+        strings[i] = s;
+        strlen += s.length;
+    }
     
-    memcpy(ptr, c1.ptr, cplen);
-    len -= cplen;
-    ptr += cplen;
-    for (size_t i = 1 ; i < n ; i++) {
-        sstr_t str = va_arg (ap, sstr_t);
-        cplen = str.length > 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<count;i++) {
+        sstr_t s = strings[i];
+        memcpy(str.ptr + pos, s.ptr, s.length);
+        pos += s.length;
     }
+    
+    str.ptr[str.length] = '\0';
+    
+    free(strings);
+    
+    return str;
+}
+
+sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...) {
+    va_list ap;
+    va_start(ap, s2);
+    sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, s2, ap);
     va_end(ap);
-    s.length = ptr - s.ptr;
+    return s;
+}
 
+sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...) {
+    va_list ap;
+    va_start(ap, s2);
+    sstr_t s = sstrvcat_a(a, count, s1, s2, ap);
+    va_end(ap);
     return s;
 }
 
@@ -97,13 +137,15 @@
 sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) {
     sstr_t new_sstr;
     if (start >= 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<string.length;i++) {
-        char c = string.ptr[i];
-        if(c > 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;
+}
--- 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 <code>malloc()</code>. 
+ * So developers <b>MUST</b> pass the sstr_t.ptr to <code>free()</code>.
+ * 
+ * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
+ * 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 <i>never</i> copies data beyond the capacity and
- * does not modify any of the source strings.
+ * Concatenates two or more strings using an UcxAllocator.
  * 
- * <b>Attention:</b>
- * <ul>
- *   <li>Any content in the destination string will be overwritten</li>
- *   <li>The destination sstr_t.ptr is <b>NOT</b>
- *       <code>NULL</code>-terminated</li>
- *   <li>The destination sstr_t.length is set to the total length of the
- *       concatenated strings</li>
- *   <li><i>Hint:</i> get a <code>NULL</code>-terminated string by performing
- *       <code>mystring.ptr[mystring.length]='\0'</code> after calling this
- *       function</li>
- * </ul>
+ * 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 <code>dest</code> 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 @@
  * </ul>
  * 
  * The integer referenced by <code>count</code> 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 <code>count</code> is also used as output and is
@@ -237,36 +235,36 @@
  *   <li>-1, if either the string or the delimiter is an empty string</li>
  *   <li>0, if the string equals the delimiter</li>
  *   <li>1, if the string does not contain the delimiter</li>
- *   <li>the count of list items, otherwise</li>
+ *   <li>the count of array items, otherwise</li>
  * </ul>
  * 
  * 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.
  * 
- * <b>Attention:</b> All list items <b>AND</b> all sstr_t.ptr of the list
+ * <b>Attention:</b> The array pointer <b>AND</b> all sstr_t.ptr of the array
  * items must be manually passed to <code>free()</code>. 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
  *         <code>NULL</code> 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.
  * 
  * <i>Read the description of sstrsplit() for details.</i>
  * 
- * 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
  *         <code>NULL</code> 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 <code>memcmp()</code>.
@@ -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
--- 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:
--- 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 <code>__func__</code> preprocessor macro.
- * Some compilers use <code>__func__</code> and others use __FUNC__.
- * We use __FUNC__ so we define it for those compilers which use
+ * Some compilers use <code>__func__</code> and others use __FUNCTION__.
+ * We use __FUNCTION__ so we define it for those compilers which use
  * <code>__func__</code>.
  */
 #define __FUNCTION__ __func__
--- 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 @@
  * 
  * <h2>LICENCE</h2>
  * 
- * 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:
--- 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.
--- 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;
     }
--- 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__)
+
 /**
  * <code>va_list</code> version of ucx_asprintf().
  * 

mercurial