ucx update

Mon, 15 Dec 2014 09:57:35 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 15 Dec 2014 09:57:35 +0100
changeset 70
88092b88ec00
parent 69
0dbdd7e8c1fc
child 71
c9aff0a0093d

ucx update

dav/main.c file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/utils.c file | annotate | diff | comparison | revisions
ucx/Makefile file | annotate | diff | comparison | revisions
ucx/allocator.c file | annotate | diff | comparison | revisions
ucx/allocator.h file | annotate | diff | comparison | revisions
ucx/buffer.c file | annotate | diff | comparison | revisions
ucx/buffer.h file | annotate | diff | comparison | revisions
ucx/list.c file | annotate | diff | comparison | revisions
ucx/list.h file | annotate | diff | comparison | revisions
ucx/logging.c file | annotate | diff | comparison | revisions
ucx/logging.h file | annotate | diff | comparison | revisions
ucx/map.c file | annotate | diff | comparison | revisions
ucx/map.h file | annotate | diff | comparison | revisions
ucx/mempool.c file | annotate | diff | comparison | revisions
ucx/mempool.h file | annotate | diff | comparison | revisions
ucx/properties.c file | annotate | diff | comparison | revisions
ucx/properties.h file | annotate | diff | comparison | revisions
ucx/stack.c file | annotate | diff | comparison | revisions
ucx/stack.h file | annotate | diff | comparison | revisions
ucx/string.c file | annotate | diff | comparison | revisions
ucx/string.h file | annotate | diff | comparison | revisions
ucx/test.c file | annotate | diff | comparison | revisions
ucx/test.h file | annotate | diff | comparison | revisions
ucx/ucx.c file | annotate | diff | comparison | revisions
ucx/ucx.h file | annotate | diff | comparison | revisions
ucx/utils.c file | annotate | diff | comparison | revisions
ucx/utils.h file | annotate | diff | comparison | revisions
--- a/dav/main.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/dav/main.c	Mon Dec 15 09:57:35 2014 +0100
@@ -221,10 +221,16 @@
         *path = sstrdup(p).ptr;
     } else {
         repo = calloc(1, sizeof(Repository));
-        repo->name = "";
-        repo->url = strdup(url);
+        repo->name = strdup("");
         repo->decrypt_content = true;
-        *path = strdup("/");
+        if(url[ulen-1] == '/') {
+            repo->url = strdup(url);
+            *path = strdup("/");
+        } else {
+            repo->url = util_parent_path(url);
+            // TODO: check/fix
+            *path = strdup(util_resource_name(url)-1);
+        }
     }
     
     return repo;
--- a/libidav/resource.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/libidav/resource.c	Mon Dec 15 09:57:35 2014 +0100
@@ -245,9 +245,7 @@
     sstr_t name_str = sstr(name);
     
     sstr_t key;
-    key.length = ns_str.length + name_str.length + 1;
-    key.ptr = malloc(key.length + 1);
-    key = sstrncat(key, 3, ns_str, S(" "), name_str);
+    key = sstrcat(3, ns_str, S(" "), name_str);
     
     return ucx_key(key.ptr, key.length);
 }
--- a/libidav/utils.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/libidav/utils.c	Mon Dec 15 09:57:35 2014 +0100
@@ -172,14 +172,10 @@
     }
     
     sstr_t url;
-    url.length = base.length + path.length + add_separator;
-    url.ptr = malloc(url.length + 1);
-    url.ptr[url.length] = '\0';
-    
     if(add_separator) {
-        url = sstrncat(url, 3, base, sstr("/"), path);
+        url = sstrcat(3, base, sstr("/"), path);
     } else {
-        url = sstrncat(url, 2, base, path);
+        url = sstrcat(2, base, path);
     }
     
     return url.ptr;
@@ -192,11 +188,7 @@
     char *base_path = util_url_path(sn->base_url);
     base.length -= strlen(base_path);
     
-    sstr_t url;
-    url.length = base.length + href_str.length;
-    url.ptr = malloc(url.length + 1);
-    url.ptr[url.length] = '\0';
-    url = sstrncat(url, 2, base, href_str);
+    sstr_t url = sstrcat(2, base, href_str);
     
     curl_easy_setopt(sn->handle, CURLOPT_URL, url);
     free(url.ptr);
--- a/ucx/Makefile	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/Makefile	Mon Dec 15 09:57:35 2014 +0100
@@ -39,6 +39,7 @@
 SRC += allocator.c
 SRC += logging.c
 SRC += buffer.c
+SRC += stack.c
 
 OBJ = $(SRC:%.c=../build/ucx/%$(OBJ_EXT))
 
--- a/ucx/allocator.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/allocator.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/allocator.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/allocator.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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, \
--- a/ucx/buffer.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/buffer.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/buffer.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/buffer.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/list.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/list.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/list.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/list.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/logging.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/logging.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/logging.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/logging.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/map.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/map.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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;
@@ -70,18 +68,18 @@
         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);
+    alfree(map->allocator, map->map);
 }
 
 void ucx_map_free(UcxMap *map) {
     ucx_map_free_elmlist(map);
-    map->allocator->free(map->allocator->pool, map);
+    alfree(map->allocator, map);
 }
 
 int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to,
@@ -116,10 +114,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;
@@ -150,9 +146,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 +162,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 +195,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/ucx/map.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/map.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/mempool.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/mempool.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/mempool.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/mempool.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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:
@@ -121,7 +121,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
@@ -142,7 +142,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);
--- a/ucx/properties.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/properties.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/properties.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/properties.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/stack.c	Mon Dec 15 09:57:35 2014 +0100
@@ -0,0 +1,143 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 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/ucx/stack.h	Mon Dec 15 09:57:35 2014 +0100
@@ -0,0 +1,233 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 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/ucx/string.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/string.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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:
@@ -61,32 +61,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,16 +136,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;
-        return new_sstr;
+    } 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;
 }
 
@@ -136,18 +174,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 = 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 */
@@ -182,18 +220,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;
@@ -234,7 +281,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;
--- a/ucx/string.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/string.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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>.
--- a/ucx/test.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/test.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/test.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/test.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/ucx.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/ucx.c	Mon Dec 15 09:57:35 2014 +0100
@@ -9,7 +9,7 @@
  * 
  * <h2>LICENCE</h2>
  * 
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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/ucx/ucx.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/ucx.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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
--- a/ucx/utils.c	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/utils.c	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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;
 }
 
@@ -212,30 +219,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/ucx/utils.h	Fri Dec 12 15:48:54 2014 +0100
+++ b/ucx/utils.h	Mon Dec 15 09:57:35 2014 +0100
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2013 Olaf Wintermann. All rights reserved.
+ * Copyright 2014 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:

mercurial