ucx update

Mon, 04 Feb 2019 17:17:48 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 04 Feb 2019 17:17:48 +0100
changeset 505
481802342fdf
parent 504
bf3695fee719
child 506
ceed7714846a

ucx update

dav/sync.c file | annotate | diff | comparison | revisions
libidav/crypto.c file | annotate | diff | comparison | revisions
libidav/crypto.h file | annotate | diff | comparison | revisions
libidav/davqlexec.c file | annotate | diff | comparison | revisions
libidav/methods.c file | annotate | diff | comparison | revisions
libidav/methods.h file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/resource.h file | annotate | diff | comparison | revisions
libidav/session.c file | annotate | diff | comparison | revisions
libidav/utils.c file | annotate | diff | comparison | revisions
libidav/utils.h file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
ucx/allocator.c file | annotate | diff | comparison | revisions
ucx/avl.c file | annotate | diff | comparison | revisions
ucx/buffer.c file | annotate | diff | comparison | revisions
ucx/list.c file | annotate | diff | comparison | revisions
ucx/logging.c file | annotate | diff | comparison | revisions
ucx/map.c file | annotate | diff | comparison | revisions
ucx/mempool.c file | annotate | diff | comparison | revisions
ucx/stack.c file | annotate | diff | comparison | revisions
ucx/string.c file | annotate | diff | comparison | revisions
ucx/ucx.c file | annotate | diff | comparison | revisions
ucx/ucx/avl.h file | annotate | diff | comparison | revisions
ucx/ucx/buffer.h file | annotate | diff | comparison | revisions
ucx/ucx/list.h file | annotate | diff | comparison | revisions
ucx/ucx/logging.h file | annotate | diff | comparison | revisions
ucx/ucx/map.h file | annotate | diff | comparison | revisions
ucx/ucx/mempool.h file | annotate | diff | comparison | revisions
ucx/ucx/properties.h file | annotate | diff | comparison | revisions
ucx/ucx/stack.h file | annotate | diff | comparison | revisions
ucx/ucx/string.h file | annotate | diff | comparison | revisions
ucx/ucx/test.h file | annotate | diff | comparison | revisions
ucx/ucx/ucx.h file | annotate | diff | comparison | revisions
ucx/ucx/utils.h file | annotate | diff | comparison | revisions
ucx/utils.c file | annotate | diff | comparison | revisions
--- a/dav/sync.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/dav/sync.c	Mon Feb 04 17:17:48 2019 +0100
@@ -3142,8 +3142,7 @@
         UcxMapIterator iter = scfg_directory_iterator();
         SyncDirectory *dir;
         UCX_MAP_FOREACH(key, dir, iter) {
-            reponames = ucx_list_append_once(reponames,
-                    dir->repository, ucx_strcmp, NULL);
+            reponames = ucx_list_append(reponames, dir->repository);
         }
     }
 
--- a/libidav/crypto.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/crypto.c	Mon Feb 04 17:17:48 2019 +0100
@@ -257,7 +257,7 @@
 }
 
 
-char* aes_encrypt(char *in, size_t len, DavKey *key) {
+char* aes_encrypt(const char *in, size_t len, DavKey *key) {
     unsigned char iv[16];
     if(!RAND_bytes(iv, 16)) {
         return NULL;
@@ -304,7 +304,7 @@
     return out;
 }
 
-char* aes_decrypt(char *in, size_t *length, DavKey *key) {
+char* aes_decrypt(const char *in, size_t *length, DavKey *key) {
     int len;
     unsigned char *buf = (unsigned char*)util_base64decode_len(in, &len);
     
@@ -660,7 +660,7 @@
     free(enc);
 }
 
-char* aes_encrypt(char *in, size_t len, DavKey *key) {
+char* aes_encrypt(const char *in, size_t len, DavKey *key) {
     unsigned char iv[16];
     if(dav_rand_bytes(iv, 16)) {
         return NULL;
@@ -715,7 +715,7 @@
     return b64enc;
 }
 
-char* aes_decrypt(char *in, size_t *len, DavKey *key) {
+char* aes_decrypt(const char *in, size_t *len, DavKey *key) {
     int inlen;
     unsigned char *buf = (unsigned char*)util_base64decode_len(in, &inlen);
     
--- a/libidav/crypto.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/crypto.h	Mon Feb 04 17:17:48 2019 +0100
@@ -109,8 +109,8 @@
 void aes_encrypter_close(AESEncrypter *enc);
 int aes_encrypter_reset(AESEncrypter  *enc, curl_off_t offset, int origin);
 
-char* aes_encrypt(char *in, size_t len, DavKey *key);
-char* aes_decrypt(char *in, size_t *len, DavKey *key);
+char* aes_encrypt(const char *in, size_t len, DavKey *key);
+char* aes_decrypt(const char *in, size_t *len, DavKey *key);
 
 void dav_get_hash(DAV_SHA_CTX *sha256, unsigned char *buf);
 
--- a/libidav/davqlexec.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/davqlexec.c	Mon Feb 04 17:17:48 2019 +0100
@@ -311,49 +311,57 @@
     // add basic properties
     char *value;
     
-    UcxKey cl_key = dav_property_key("DAV:", "getcontentlength");
+    sstr_t cl_keystr = dav_property_key("DAV:", "getcontentlength");
+    UcxKey cl_key = ucx_key(cl_keystr.ptr, cl_keystr.length);
     value = ucx_map_get(data->properties, cl_key);
     if(value) {
         ucx_map_put(new_properties, cl_key, value);
     }
     
-    UcxKey cd_key = dav_property_key("DAV:", "creationdate");
+    sstr_t cd_keystr = dav_property_key("DAV:", "creationdate");
+    UcxKey cd_key = ucx_key(cd_keystr.ptr, cd_keystr.length);
     value = ucx_map_get(data->properties, cd_key);
     if(value) {
         ucx_map_put(new_properties, cd_key, value);
     }
     
-    UcxKey lm_key = dav_property_key("DAV:", "getlastmodified");
+    sstr_t lm_keystr = dav_property_key("DAV:", "getlastmodified");
+    UcxKey lm_key = ucx_key(lm_keystr.ptr, lm_keystr.length);
     value = ucx_map_get(data->properties, lm_key);
     if(value) {
         ucx_map_put(new_properties, lm_key, value);
     }
     
-    UcxKey ct_key = dav_property_key("DAV:", "getcontenttype");
+    sstr_t ct_keystr = dav_property_key("DAV:", "getcontenttype");
+    UcxKey ct_key = ucx_key(ct_keystr.ptr, ct_keystr.length);
     value = ucx_map_get(data->properties, ct_key);
     if(value) {
         ucx_map_put(new_properties, ct_key, value);
     }
     
-    UcxKey rt_key = dav_property_key("DAV:", "resourcetype");
+    sstr_t rt_keystr = dav_property_key("DAV:", "resourcetype");
+    UcxKey rt_key = ucx_key(rt_keystr.ptr, rt_keystr.length);
     value = ucx_map_get(data->properties, rt_key);
     if(value) {
         ucx_map_put(new_properties, rt_key, value);
     }
     
-    UcxKey cn_key = dav_property_key(DAV_NS, "crypto-name");
+    sstr_t cn_keystr = dav_property_key(DAV_NS, "crypto-name");
+    UcxKey cn_key = ucx_key(cn_keystr.ptr, cn_keystr.length);
     value = ucx_map_get(data->properties, cn_key);
     if(value) {
         ucx_map_put(new_properties, cn_key, value);
     }
     
-    UcxKey ck_key = dav_property_key(DAV_NS, "crypto-key");
+    sstr_t ck_keystr = dav_property_key(DAV_NS, "crypto-key");
+    UcxKey ck_key = ucx_key(ck_keystr.ptr, ck_keystr.length);
     value = ucx_map_get(data->properties, ck_key);
     if(value) {
         ucx_map_put(new_properties, ck_key, value);
     }
     
-    UcxKey ch_key = dav_property_key(DAV_NS, "crypto-hash");
+    sstr_t ch_keystr = dav_property_key(DAV_NS, "crypto-hash");
+    UcxKey ch_key = ucx_key(ch_keystr.ptr, ch_keystr.length);
     value = ucx_map_get(data->properties, ch_key);
     if(value) {
         ucx_map_put(new_properties, ch_key, value);
@@ -395,9 +403,9 @@
                 node->contentlength = str.length;
             }
             if(node) {
-                UcxKey key = dav_property_key(field->ns, field->name);
-                ucx_map_put(new_properties, key, node);
-                free(key.data);
+                sstr_t key = dav_property_key(field->ns, field->name);
+                ucx_map_sstr_put(new_properties, key, node);
+                free(key.ptr);
             }
         } else {
             // TODO: error
@@ -418,14 +426,14 @@
     resource_free_properties(sn, data->properties);
     data->properties = new_properties;
     
-    free(cl_key.data);
-    free(cd_key.data);
-    free(lm_key.data);
-    free(ct_key.data);
-    free(rt_key.data);
-    free(cn_key.data);
-    free(ck_key.data);
-    free(ch_key.data);
+    free(cl_keystr.ptr);
+    free(cd_keystr.ptr);
+    free(lm_keystr.ptr);
+    free(ct_keystr.ptr);
+    free(rt_keystr.ptr);
+    free(cn_keystr.ptr);
+    free(ck_keystr.ptr);
+    free(ch_keystr.ptr);
     
     return 0;
 }
@@ -534,7 +542,8 @@
                 if(ns && name) {
                     DavOrderCriterion *cr = ucx_mempool_malloc(mp, sizeof(DavOrderCriterion));
                     cr->type = 1;
-                    cr->column.property = dav_property_key_a(mp->allocator, ns, name);
+                    sstr_t keystr = dav_property_key_a(mp->allocator, ns, name);
+                    cr->column.property = ucx_key(keystr.ptr, keystr.length);
                     cr->descending = oc->descending;
                     ordercr = ucx_list_append_a(mp->allocator, ordercr, cr);
                 } else {
--- a/libidav/methods.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/methods.c	Mon Feb 04 17:17:48 2019 +0100
@@ -755,7 +755,7 @@
 
 UcxBuffer* create_proppatch_request(DavResourceData *data) {
     UcxBuffer *buf = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
-    sstr_t s;
+    scstr_t s;
     
     UcxMap *namespaces = ucx_map_new(8);
     char prefix[8];
@@ -775,32 +775,32 @@
         }
     }
     
-    s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
+    s = SC("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
     ucx_buffer_write(s.ptr, 1, s.length, buf);
     
     // write root element and namespaces
-    s = S("<D:propertyupdate xmlns:D=\"DAV:\"");
+    s = SC("<D:propertyupdate xmlns:D=\"DAV:\"");
     ucx_buffer_write(s.ptr, 1, s.length, buf);
     UcxMapIterator mapi = ucx_map_iterator(namespaces);
     UcxKey key;
     char *pfxval;
     UCX_MAP_FOREACH(key, pfxval, mapi) {
-        s = S(" xmlns:");
+        s = SC(" xmlns:");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
-        s = sstr(pfxval);
+        s = scstr(pfxval);
         ucx_buffer_write(s.ptr, 1, s.length, buf);
-        s = S("=\"");
+        s = SC("=\"");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
-        s = sstrn(key.data, key.len);
+        s = scstrn(key.data, key.len);
         ucx_buffer_write(s.ptr, 1, s.length, buf);
-        s = S("\"");
+        s = SC("\"");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
     }
-    s = S(">\n");
+    s = SC(">\n");
     ucx_buffer_write(s.ptr, 1, s.length, buf);
     
     if(data->set) {
-        s = S("<D:set>\n<D:prop>\n");
+        s = SC("<D:set>\n<D:prop>\n");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
         UCX_FOREACH(elm, data->set) {
             DavProperty *property = elm->data;
@@ -810,15 +810,15 @@
             }
             
             // begin tag
-            s = S("<");
+            s = SC("<");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = sstr(prefix);
+            s = scstr(prefix);
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = S(":");
+            s = SC(":");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = sstr(property->name);
+            s = scstr(property->name);
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = S(">");
+            s = SC(">");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
             
             // content
@@ -830,43 +830,43 @@
             }
             
             // end tag
-            s = S("</");
+            s = SC("</");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = sstr(prefix);
+            s = scstr(prefix);
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = S(":");
+            s = SC(":");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = sstr(property->name);
+            s = scstr(property->name);
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = S(">\n");
+            s = SC(">\n");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
         }
-        s = S("</D:prop>\n</D:set>\n");
+        s = SC("</D:prop>\n</D:set>\n");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
     }
     if(data->remove) {
-        s = S("<D:remove>\n<D:prop>\n");
+        s = SC("<D:remove>\n<D:prop>\n");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
         UCX_FOREACH(elm, data->remove) {
             DavProperty *property = elm->data;
             char *prefix = ucx_map_cstr_get(namespaces, property->ns->name);
             
-            s = S("<");
+            s = SC("<");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = sstr(prefix);
+            s = scstr(prefix);
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = S(":");
+            s = SC(":");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = sstr(property->name);
+            s = scstr(property->name);
             ucx_buffer_write(s.ptr, 1, s.length, buf);
-            s = S(" />\n");
+            s = SC(" />\n");
             ucx_buffer_write(s.ptr, 1, s.length, buf);
         }
-        s = S("</D:prop>\n</D:remove>\n");
+        s = SC("</D:prop>\n</D:remove>\n");
         ucx_buffer_write(s.ptr, 1, s.length, buf);
     }
     
-    s = S("</D:propertyupdate>\n");
+    s = SC("</D:propertyupdate>\n");
     ucx_buffer_write(s.ptr, 1, s.length, buf);
     
     // cleanup namespace map
@@ -876,7 +876,7 @@
     return buf;
 }
 
-UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, char *name, char *hash) {
+UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, const char *name, const char *hash) {
     UcxBuffer *buf = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND);
     sstr_t s;
     
--- a/libidav/methods.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/methods.h	Mon Feb 04 17:17:48 2019 +0100
@@ -106,7 +106,7 @@
 int parse_resource_type(xmlNode *node);
 
 UcxBuffer* create_proppatch_request(DavResourceData *data);
-UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, char *name, char *hash);
+UcxBuffer* create_crypto_proppatch_request(DavSession *sn, DavKey *key, const char *name, const char *hash);
 
 CURLcode do_delete_request(DavSession *sn, char *lock, UcxBuffer *response);
 
--- a/libidav/resource.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/resource.c	Mon Feb 04 17:17:48 2019 +0100
@@ -239,15 +239,15 @@
     return resource->href;
 }
 
-void resource_add_property(DavResource *res, char *ns, char *name, xmlNode *val) {
+void resource_add_property(DavResource *res, const char *ns, const char *name, xmlNode *val) {
     if(!val) {
         return;
     }
     
-    UcxKey key = dav_property_key(ns, name);
+    sstr_t key = dav_property_key(ns, name);
     DavXmlNode *v = dav_convert_xml(res->session, val);
-    ucx_map_put(((DavResourceData*)res->data)->properties, key, v);
-    free(key.data);
+    ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v);
+    free(key.ptr);
 }
 
 void resource_add_string_property(DavResource *res, char *ns, char *name, char *val) {
@@ -255,16 +255,17 @@
         return;
     }
     
-    UcxKey key = dav_property_key(ns, name);
+    sstr_t key = dav_property_key(ns, name);
     DavXmlNode *v = dav_text_node(res->session, val);
-    ucx_map_put(((DavResourceData*)res->data)->properties, key, v);
-    free(key.data);
+    ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v);
+    free(key.ptr);
 }
 
-DavXmlNode* resource_get_property(DavResource *res, char *ns, char *name) {
-    UcxKey key = dav_property_key(ns, name);
+DavXmlNode* resource_get_property(DavResource *res, const char *ns, const char *name) {
+    sstr_t keystr = dav_property_key(ns, name);
+    UcxKey key = ucx_key(keystr.ptr, keystr.length);
     DavXmlNode *property = resource_get_property_k(res, key);
-    free(key.data);
+    free(keystr.ptr);
     return property;
 }
 
@@ -273,18 +274,15 @@
     return ucx_map_get(data->properties, key);
 }
 
-UcxKey dav_property_key(char *ns, char *name) {
+sstr_t dav_property_key(const char *ns, const char *name) {
     return dav_property_key_a(ucx_default_allocator(), ns, name);
 }
 
-UcxKey dav_property_key_a(UcxAllocator *a, char *ns, char *name) {
-    sstr_t ns_str = sstr(ns);
-    sstr_t name_str = sstr(name);
+sstr_t dav_property_key_a(UcxAllocator *a, const char *ns, const char *name) {
+    scstr_t ns_str = scstr(ns);
+    scstr_t name_str = scstr(name);
     
-    sstr_t key;
-    key = sstrcat_a(a, 4, ns_str, S("\0"), name_str, S("\0"));
-    
-    return ucx_key(key.ptr, key.length);
+    return sstrcat_a(a, 4, ns_str, S("\0"), name_str, S("\0"));
 }
 
 
@@ -447,7 +445,7 @@
     return dav_get_property_ns(res, pns, pname);
 }
 
-DavXmlNode* dav_get_property_ns(DavResource *res, char *ns, char *name) {
+DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name) {
     if(!ns || !name) {
         return NULL;
     }
@@ -585,7 +583,7 @@
     UCX_MAP_FOREACH(key, value, i) {
         DavPropName *name = &names[j];
         // the map key is namespace + '\0' + name
-        name->ns = key.data;
+        name->ns = (char*)key.data;
         for(int k=0;j<key.len;k++) {
             if(((char*)key.data)[k] == '\0') {
                 name->name = (char*)key.data + k + 1;
@@ -1180,7 +1178,7 @@
 }
 
 
-int resource_add_crypto_info(DavSession *sn, char *href, char *name, char *hash) {
+int resource_add_crypto_info(DavSession *sn, const char *href, const char *name, const char *hash) {
     if(!DAV_IS_ENCRYPTED(sn)) {
         return 0;
     }
--- a/libidav/resource.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/resource.h	Mon Feb 04 17:17:48 2019 +0100
@@ -74,14 +74,14 @@
 
 void resource_set_info(DavResource *res, char *href_str);
 DavResourceData* resource_data_new(DavSession *sn);
-void resource_add_property(DavResource *res, char *ns, char *name, xmlNode *val);
-DavXmlNode* resource_get_property(DavResource *res, char *ns, char *name);
+void resource_add_property(DavResource *res, const char *ns, const char *name, xmlNode *val);
+DavXmlNode* resource_get_property(DavResource *res, const char *ns, const char *name);
 DavXmlNode* resource_get_property_k(DavResource *res, UcxKey key);
 void resource_add_child(DavResource *parent, DavResource *child);
 void resource_add_ordered_child(DavResource *parent, DavResource *child, UcxList *ordercr);
-int resource_add_crypto_info(DavSession *sn, char *href, char *name, char *hash);
+int resource_add_crypto_info(DavSession *sn, const char *href, const char *name, const char *hash);
 
-UcxKey dav_property_key_a(UcxAllocator *a, char *ns, char *name);
+sstr_t dav_property_key_a(UcxAllocator *a, const char *ns, const char *name);
 
 #ifdef	__cplusplus
 }
--- a/libidav/session.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/session.c	Mon Feb 04 17:17:48 2019 +0100
@@ -273,7 +273,7 @@
 void dav_session_destroy(DavSession *sn) { 
     // remove session from context
     UcxList *sessions = sn->context->sessions;
-    ssize_t i = ucx_list_find(sessions, sn, ucx_ptrcmp, NULL);
+    ssize_t i = ucx_list_find(sessions, sn, ucx_cmp_ptr, NULL);
     if(i >= 0)  {
         UcxList *elm = ucx_list_get(sessions, i);
         if(elm) {
--- a/libidav/utils.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/utils.c	Mon Feb 04 17:17:48 2019 +0100
@@ -387,9 +387,9 @@
     return url.ptr;
 }
 
-char* util_get_url(DavSession *sn, char *href) {
-    sstr_t base = sstr(sn->base_url);
-    sstr_t href_str = sstr(href);
+char* util_get_url(DavSession *sn, const char *href) {
+    scstr_t base = scstr(sn->base_url);
+    scstr_t href_str = scstr(href);
     
     char *base_path = util_url_path(sn->base_url);
     base.length -= strlen(base_path);
@@ -398,7 +398,7 @@
     return url.ptr;
 }
 
-void util_set_url(DavSession *sn, char *href) {
+void util_set_url(DavSession *sn, const char *href) {
     char *url = util_get_url(sn, href);
     curl_easy_setopt(sn->handle, CURLOPT_URL, url);
     free(url);
@@ -463,7 +463,7 @@
 }
 
 
-char* util_base64decode(char *in) {
+char* util_base64decode(const char *in) {
     int len = 0;
     return util_base64decode_len(in, &len);
 }
@@ -484,7 +484,7 @@
     66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
     66,66,66,66,66,66
 };
-char* util_base64decode_len(char* in, int *outlen) {
+char* util_base64decode_len(const char* in, int *outlen) {
     /* code is mostly from wikibooks */
     
     size_t inlen = strlen(in);
@@ -494,7 +494,7 @@
     
     unsigned char *out = (unsigned char*)outbuf;
     
-    char *end = in + inlen;
+    const char *end = in + inlen;
     char iter = 0;
     uint32_t buf = 0;
     size_t len = 0;
@@ -559,7 +559,7 @@
 
 
 static char* b64enctable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-char* util_base64encode(char *in, size_t len) {
+char* util_base64encode(const char *in, size_t len) {
     // calculate length of base64 output and create buffer
     size_t outlen = 4 * ((len + 2) / 3);
     int pad = len % 3;
--- a/libidav/utils.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/utils.h	Mon Feb 04 17:17:48 2019 +0100
@@ -69,8 +69,8 @@
 char* util_url_decode(DavSession *sn, char *url);
 char* util_resource_name(char *url);
 char* util_concat_path(const char *url_base, const char *path);
-char* util_get_url(DavSession *sn, char *href);
-void util_set_url(DavSession *sn, char *href);
+char* util_get_url(DavSession *sn, const char *href);
+void util_set_url(DavSession *sn, const char *href);
 
 void util_capture_header(CURL *handle, UcxMap* map);
 
@@ -82,9 +82,9 @@
 
 char* util_xml_get_text(const xmlNode *elm);
 
-char* util_base64decode(char *in);
-char* util_base64decode_len(char *in, int *outlen);
-char* util_base64encode(char *in, size_t len);
+char* util_base64decode(const char *in);
+char* util_base64decode_len(const char *in, int *outlen);
+char* util_base64encode(const char *in, size_t len);
 
 char* util_encrypt_str(DavSession *sn, char *str, char *key);
 char* util_encrypt_str_k(DavSession *sn, char *str, DavKey *key);
--- a/libidav/webdav.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/libidav/webdav.h	Mon Feb 04 17:17:48 2019 +0100
@@ -249,7 +249,7 @@
 
 DavResource* dav_query(DavSession *sn, char *query, ...);
 
-UcxKey dav_property_key(char *ns, char *name);
+sstr_t dav_property_key(const char *ns, const char *name);
 void dav_get_property_namespace_str(
         DavContext *ctx,
         char *prefixed_name,
@@ -288,7 +288,7 @@
 int dav_unlock(DavResource *res);
 
 DavXmlNode* dav_get_property(DavResource *res, char *name);
-DavXmlNode* dav_get_property_ns(DavResource *res, char *ns, char *name);
+DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name);
 char* dav_get_string_property(DavResource *res, char *name);
 char* dav_get_string_property_ns(DavResource *res, char *ns, char *name);
 void dav_set_string_property(DavResource *res, char *name, char *value);
--- a/ucx/allocator.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/allocator.c	Mon Feb 04 17:17:48 2019 +0100
@@ -30,7 +30,7 @@
 
 #include <stdlib.h>
 
-UcxAllocator default_allocator = {
+static UcxAllocator default_allocator = {
     NULL,
     ucx_default_malloc,
     ucx_default_calloc,
--- a/ucx/avl.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/avl.c	Mon Feb 04 17:17:48 2019 +0100
@@ -136,6 +136,23 @@
     alfree(al, tree);
 }
 
+static void ucx_avl_free_content_node(UcxAllocator *al, UcxAVLNode *node,
+        ucx_destructor destr) {
+    if (node) {
+        ucx_avl_free_content_node(al, node->left, destr);
+        ucx_avl_free_content_node(al, node->right, destr);
+        if (destr) {
+            destr(node->value);
+        } else {
+            alfree(al, node->value);
+        }
+    }
+}
+
+void ucx_avl_free_content(UcxAVLTree *tree, ucx_destructor destr) {
+    ucx_avl_free_content_node(tree->allocator, tree->root, destr);
+}
+
 UcxAVLNode *ucx_avl_get_node(UcxAVLTree *tree, intptr_t key) {
     UcxAVLNode *n = tree->root;
     int cmpresult;
--- a/ucx/buffer.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/buffer.c	Mon Feb 04 17:17:48 2019 +0100
@@ -151,7 +151,10 @@
 
 size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
         UcxBuffer *buffer) {
-    size_t len = size * nitems;
+    size_t len;
+    if(ucx_szmul(size, nitems, &len)) {
+        return 0;
+    }
     size_t required = buffer->pos + len;
     if (buffer->pos > required) {
         return 0;
@@ -185,7 +188,10 @@
 
 size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
         UcxBuffer *buffer) {
-    size_t len = size * nitems;
+    size_t len;
+    if(ucx_szmul(size, nitems, &len)) {
+        return 0;
+    }
     if (buffer->pos + len > buffer->size) {
         len = buffer->size - buffer->pos;
         if (size > 1) len -= len%size;
@@ -225,12 +231,67 @@
     if (ucx_buffer_eof(buffer)) {
         return EOF;
     } else {
-        int c = buffer->space[buffer->pos];
+        int c = ((unsigned char*)buffer->space)[buffer->pos];
         buffer->pos++;
         return c;
     }
 }
 
-size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) {
+size_t ucx_buffer_puts(UcxBuffer *buffer, const char *str) {
     return ucx_buffer_write((const void*)str, 1, strlen(str), buffer);
 }
+
+int ucx_buffer_shift_left(UcxBuffer* buffer, size_t shift) {
+    if (shift >= buffer->size) {
+        buffer->pos = buffer->size = 0;
+    } else {
+        memmove(buffer->space, buffer->space + shift, buffer->size - shift);
+        buffer->size -= shift;
+        
+        if (buffer->pos >= shift) {
+            buffer->pos -= shift;
+        } else {
+            buffer->pos = 0;
+        }
+    }
+    return 0;
+}
+
+int ucx_buffer_shift_right(UcxBuffer* buffer, size_t shift) {
+    size_t req_capacity = buffer->size + shift;
+    size_t movebytes;
+    
+    // auto extend buffer, if required and enabled
+    if (buffer->capacity < req_capacity) {
+        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
+            if (ucx_buffer_extend(buffer, req_capacity - buffer->capacity)) {
+                return 1;
+            }
+            movebytes = buffer->size;
+        } else {
+            movebytes = buffer->capacity - shift;
+        }
+    } else {
+        movebytes = buffer->size;
+    }
+    
+    memmove(buffer->space + shift, buffer->space, movebytes);
+    buffer->size = shift+movebytes;
+    
+    buffer->pos += shift;
+    if (buffer->pos > buffer->size) {
+        buffer->pos = buffer->size;
+    }
+    
+    return 0;
+}
+
+int ucx_buffer_shift(UcxBuffer* buffer, off_t shift) {
+    if (shift < 0) {
+        return ucx_buffer_shift_left(buffer, (size_t) (-shift));
+    } else if (shift > 0) {
+        return ucx_buffer_shift_right(buffer, (size_t) shift);
+    } else {
+        return 0;
+    }
+}
--- a/ucx/list.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/list.c	Mon Feb 04 17:17:48 2019 +0100
@@ -77,6 +77,7 @@
 }
 
 void ucx_list_free_content(UcxList* list, ucx_destructor destr) {
+    if (!destr) destr = free;
     while (list != NULL) {
         destr(list->data);
         list = list->next;
@@ -106,41 +107,6 @@
     }
 }
 
-UcxList *ucx_list_append_once(UcxList *l, void *data,
-        cmp_func cmpfnc, void *cmpdata) {
-    return ucx_list_append_once_a(ucx_default_allocator(), l,
-            data, cmpfnc, cmpdata);
-}
-
-UcxList *ucx_list_append_once_a(UcxAllocator *alloc, UcxList *l, void *data,
-        cmp_func cmpfnc, void *cmpdata) {
-
-    UcxList *last = NULL;
-    {
-        UcxList *e = l;
-        while (e) {
-            if (cmpfnc(e->data, data, cmpdata) == 0) {
-                return l;
-            }
-            last = e;
-            e = e->next;
-        }
-    }
-    
-    UcxList *nl = ucx_list_append_a(alloc, NULL, data);
-    if (!nl) {
-        return NULL;
-    }
-
-    if (last == NULL) {
-        return nl;
-    } else {
-        nl->prev = last;
-        last->next = nl;
-        return l;
-    }
-}
-
 UcxList *ucx_list_prepend(UcxList *l, void *data) {
     return ucx_list_prepend_a(ucx_default_allocator(), l, data);
 }
--- a/ucx/logging.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/logging.c	Mon Feb 04 17:17:48 2019 +0100
@@ -50,6 +50,8 @@
         ucx_map_int_put(logger->levels, l, (void*) "[WARNING]");
         l = UCX_LOGGER_INFO;
         ucx_map_int_put(logger->levels, l, (void*) "[INFO]");
+        l = UCX_LOGGER_DEBUG;
+        ucx_map_int_put(logger->levels, l, (void*) "[DEBUG]");
         l = UCX_LOGGER_TRACE;
         ucx_map_int_put(logger->levels, l, (void*) "[TRACE]");
     }
@@ -69,12 +71,15 @@
         const unsigned int line, const char *format, ...) {
     if (level <= logger->level) {
         char msg[UCX_LOGGER_MSGMAX];
-        char *text;
+        const char *text;
         size_t k = 0;
         size_t n;
         
         if ((logger->mask & UCX_LOGGER_LEVEL) > 0) {
-            text = (char*) ucx_map_int_get(logger->levels, level);
+            text = (const char*) ucx_map_int_get(logger->levels, level);
+            if (!text) {
+                text = "[UNKNOWN]";
+            }
             n = strlen(text);
             n = n > 256 ? 256 : n;
             memcpy(msg+k, text, n);
@@ -92,7 +97,9 @@
             k += sprintf(msg+k, ":%u ", line);
         }
         
-        msg[k++] = '-'; msg[k++] = ' ';
+        if (k > 0) {
+            msg[k++] = '-'; msg[k++] = ' ';
+        }
         
         va_list args;
         va_start (args, format);
--- a/ucx/map.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/map.c	Mon Feb 04 17:17:48 2019 +0100
@@ -86,7 +86,11 @@
     UcxMapIterator iter = ucx_map_iterator(map);
     void *val;
     UCX_MAP_FOREACH(key, val, iter) {
-        destr(val);
+        if (destr) {
+            destr(val);
+        } else {
+            alfree(map->allocator, val);
+        }
     }
 }
 
@@ -150,19 +154,22 @@
     UcxAllocator *allocator = map->allocator;
     
     if (key.hash == 0) {
-        key.hash = ucx_hash((char*)key.data, key.len);
+        key.hash = ucx_hash((const char*)key.data, key.len);
     }
+    
+    struct UcxMapKey mapkey;
+    mapkey.hash = key.hash;
 
-    size_t slot = key.hash%map->size;
+    size_t slot = mapkey.hash%map->size;
     UcxMapElement *elm = map->map[slot];
     UcxMapElement *prev = NULL;
 
-    while (elm && elm->key.hash < key.hash) {
+    while (elm && elm->key.hash < mapkey.hash) {
         prev = elm;
         elm = elm->next;
     }
     
-    if (!elm || elm->key.hash != key.hash) {
+    if (!elm || elm->key.hash != mapkey.hash) {
         UcxMapElement *e = (UcxMapElement*)almalloc(
                 allocator, sizeof(UcxMapElement));
         if (!e) {
@@ -184,8 +191,9 @@
             return -1;
         }
         memcpy(kd, key.data, key.len);
-        key.data = kd;
-        elm->key = key;
+        mapkey.data = kd;
+        mapkey.len = key.len;
+        elm->key = mapkey;
         map->count++;
     }
     elm->data = data;
@@ -195,7 +203,7 @@
 
 static void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, int remove) {
     if(key.hash == 0) {
-        key.hash = ucx_hash((char*)key.data, key.len);
+        key.hash = ucx_hash((const char*)key.data, key.len);
     }
     
     size_t slot = key.hash%map->size;
@@ -235,11 +243,11 @@
     return ucx_map_get_and_remove(map, key, 1);
 }
 
-UcxKey ucx_key(void *data, size_t len) {
+UcxKey ucx_key(const void *data, size_t len) {
     UcxKey key;
     key.data = data;
     key.len = len;
-    key.hash = ucx_hash((const char*) data, len);
+    key.hash = ucx_hash((const char*)data, len);
     return key;
 }
 
@@ -308,7 +316,9 @@
             if (e->data) {
                 i->cur = e;
                 *elm = e->data;
-                *key = e->key;
+                key->data = e->key.data;
+                key->hash = e->key.hash;
+                key->len = e->key.len;
                 return 1;
             }
 
--- a/ucx/mempool.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/mempool.c	Mon Feb 04 17:17:48 2019 +0100
@@ -65,12 +65,17 @@
 }
 
 UcxMempool *ucx_mempool_new(size_t n) {
+    size_t poolsz;
+    if(ucx_szmul(n, sizeof(void*), &poolsz)) {
+        return NULL;
+    }
+    
     UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool));
     if (!pool) {
         return NULL;
     }
     
-    pool->data = (void**) malloc(n * sizeof(void*));
+    pool->data = (void**) malloc(poolsz);
     if (pool->data == NULL) {
         free(pool);
         return NULL;
@@ -100,7 +105,12 @@
         return 1;
     }
     
-    void **data = (void**) realloc(pool->data, newcap*sizeof(void*));
+    size_t newcapsz;
+    if(ucx_szmul(newcap, sizeof(void*), &newcapsz)) {
+        return 1;
+    }
+    
+    void **data = (void**) realloc(pool->data, newcapsz);
     if (data) {
         pool->data = data; 
         pool->size = newcap;
@@ -111,6 +121,10 @@
 }
 
 void *ucx_mempool_malloc(UcxMempool *pool, size_t n) {
+    if(((size_t)-1) - sizeof(ucx_destructor) < n) {
+        return NULL;
+    }
+    
     if (pool->ndata >= pool->size) {
         size_t newcap = pool->size*2;
         if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) {
@@ -132,7 +146,12 @@
 }
 
 void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) {
-    void *ptr = ucx_mempool_malloc(pool, nelem*elsize);
+    size_t msz;
+    if(ucx_szmul(nelem, elsize, &msz)) {
+        return NULL;
+    }
+    
+    void *ptr = ucx_mempool_malloc(pool, msz);
     if (!ptr) {
         return NULL;
     }
@@ -141,6 +160,10 @@
 }
 
 void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) {
+    if(((size_t)-1) - sizeof(ucx_destructor) < n) {
+        return NULL;
+    }
+    
     char *mem = ((char*)ptr) - sizeof(ucx_destructor);
     char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor));
     if (!newm) {
--- a/ucx/stack.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/stack.c	Mon Feb 04 17:17:48 2019 +0100
@@ -120,13 +120,15 @@
         return;
     }
     
-    size_t len = ucx_stack_topsize(stack);
-    if (len > n) {
-        len = n;
+    if (dest) {
+        size_t len = ucx_stack_topsize(stack);
+        if (len > n) {
+            len = n;
+        }
+
+        memcpy(dest, stack->top, len);
     }
     
-    memcpy(dest, stack->top, len);
-    
     ucx_stack_free(stack, stack->top);
 }
 
@@ -142,3 +144,22 @@
         return 0;
     }
 }
+
+void *ucx_stack_push(UcxStack *stack, size_t n, const void *data) {
+    void *space = ucx_stack_malloc(stack, n);
+    if (space) {
+        memcpy(space, data, n);
+    }
+    return space;
+}
+
+void *ucx_stack_pusharr(UcxStack *stack,
+        size_t nelem, size_t elsize, const void *data) {
+    
+    // skip the memset by using malloc
+    void *space = ucx_stack_malloc(stack, nelem*elsize);
+    if (space) {
+        memcpy(space, data, nelem*elsize);
+    }
+    return space;
+}
--- a/ucx/string.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/string.c	Mon Feb 04 17:17:48 2019 +0100
@@ -50,13 +50,33 @@
     return string;
 }
 
-size_t sstrnlen(size_t n, sstr_t s, ...) {
+scstr_t scstr(const char *cstring) {
+    scstr_t string;
+    string.ptr = cstring;
+    string.length = strlen(cstring);
+    return string;
+}
+
+scstr_t scstrn(const char *cstring, size_t length) {
+    scstr_t string;
+    string.ptr = cstring;
+    string.length = length;
+    return string;
+}
+
+
+size_t scstrnlen(size_t n, ...) {
     va_list ap;
-    size_t size = s.length;
-    va_start(ap, s);
+    va_start(ap, n);
+    
+    size_t size = 0;
 
-    for (size_t i = 1 ; i < n ; i++) {
-        sstr_t str = va_arg(ap, sstr_t);
+    for (size_t i = 0 ; i < n ; i++) {
+        scstr_t str = va_arg(ap, scstr_t);
+        if(SIZE_MAX - str.length < size) {
+            size = SIZE_MAX;
+            break;
+        }
         size += str.length;
     }
     va_end(ap);
@@ -67,8 +87,7 @@
 static sstr_t sstrvcat_a(
         UcxAllocator *a,
         size_t count,
-        sstr_t s1,
-        sstr_t s2,
+        scstr_t s1,
         va_list ap) {
     sstr_t str;
     str.ptr = NULL;
@@ -77,7 +96,13 @@
         return str;
     }
     
-    sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t));
+    scstr_t s2 = va_arg (ap, scstr_t);
+    
+    if(((size_t)-1) - s1.length < s2.length) {
+        return str;
+    }
+    
+    scstr_t *strings = (scstr_t*) calloc(count, sizeof(scstr_t));
     if(!strings) {
         return str;
     }
@@ -85,16 +110,25 @@
     // get all args and overall length
     strings[0] = s1;
     strings[1] = s2;
-    size_t strlen = s1.length + s2.length;
+    size_t slen = s1.length + s2.length;
+    int error = 0;
     for (size_t i=2;i<count;i++) {
-        sstr_t s = va_arg (ap, sstr_t);
+        scstr_t s = va_arg (ap, scstr_t);
         strings[i] = s;
-        strlen += s.length;
+        if(((size_t)-1) - s.length < slen) {
+            error = 1;
+            break;
+        }
+        slen += s.length;
+    }
+    if(error) {
+        free(strings);
+        return str;
     }
     
     // create new string
-    str.ptr = (char*) almalloc(a, strlen + 1);
-    str.length = strlen;
+    str.ptr = (char*) almalloc(a, slen + 1);
+    str.length = slen;
     if(!str.ptr) {
         free(strings);
         str.length = 0;
@@ -104,7 +138,7 @@
     // concatenate strings
     size_t pos = 0;
     for (size_t i=0;i<count;i++) {
-        sstr_t s = strings[i];
+        scstr_t s = strings[i];
         memcpy(str.ptr + pos, s.ptr, s.length);
         pos += s.length;
     }
@@ -116,20 +150,42 @@
     return str;
 }
 
-sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...) {
+sstr_t scstrcat(size_t count, scstr_t s1, ...) {
     va_list ap;
-    va_start(ap, s2);
-    sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, s2, ap);
+    va_start(ap, s1);
+    sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, ap);
+    va_end(ap);
+    return s;
+}
+
+sstr_t scstrcat_a(UcxAllocator *a, size_t count, scstr_t s1, ...) {
+    va_list ap;
+    va_start(ap, s1);
+    sstr_t s = sstrvcat_a(a, count, s1, ap);
     va_end(ap);
     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;
+static int ucx_substring(
+        size_t str_length,
+        size_t start,
+        size_t length,
+        size_t *newlen,
+        size_t *newpos)
+{
+    *newlen = 0;
+    *newpos = 0;
+    
+    if(start > str_length) {
+        return 0;
+    }
+    
+    if(length > str_length - start) {
+        length = str_length - start;
+    }
+    *newlen = length;
+    *newpos = start;
+    return 1;
 }
 
 sstr_t sstrsubs(sstr_t s, size_t start) {
@@ -137,44 +193,80 @@
 }
 
 sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) {
-    sstr_t new_sstr;
-    if (start >= s.length) {
-        new_sstr.ptr = NULL;
-        new_sstr.length = 0;
-    } else {
-        if (length > s.length-start) {
-            length = s.length-start;
+    size_t pos;
+    sstr_t ret = { NULL, 0 };
+    if(ucx_substring(s.length, start, length, &ret.length, &pos)) {
+        ret.ptr = s.ptr + pos;
+    }
+    return ret;
+}
+
+scstr_t scstrsubs(scstr_t string, size_t start) {
+    return scstrsubsl(string, start, string.length-start);
+}
+
+scstr_t scstrsubsl(scstr_t s, size_t start, size_t length) {
+    size_t pos;
+    scstr_t ret = { NULL, 0 };
+    if(ucx_substring(s.length, start, length, &ret.length, &pos)) {
+        ret.ptr = s.ptr + pos;
+    }
+    return ret;
+}
+
+
+static int ucx_strchr(const char *str, size_t length, int chr, size_t *pos) {
+    for(size_t i=0;i<length;i++) {
+        if(str[i] == chr) {
+            *pos = i;
+            return 1;
         }
-        new_sstr.ptr = &s.ptr[start];
-        new_sstr.length = length;
     }
-    return new_sstr;
+    return 0;
+}
+
+static int ucx_strrchr(const char *str, size_t length, int chr, size_t *pos) {
+    if(length > 0) {
+        for(size_t i=length ; i>0 ; i--) {
+            if(str[i-1] == chr) {
+                *pos = i-1;
+                return 1;
+            }
+        }
+    }
+    return 0;
 }
 
 sstr_t sstrchr(sstr_t s, int c) {
-    for(size_t i=0;i<s.length;i++) {
-        if(s.ptr[i] == c) {
-            return sstrsubs(s, i);
-        }
+    size_t pos = 0;
+    if(ucx_strchr(s.ptr, s.length, c, &pos)) {
+        return sstrsubs(s, pos);
     }
-    sstr_t n;
-    n.ptr = NULL;
-    n.length = 0;
-    return n;
+    return sstrn(NULL, 0);
 }
 
 sstr_t sstrrchr(sstr_t s, int c) {
-    if (s.length > 0) {
-        for(size_t i=s.length;i>0;i--) {
-            if(s.ptr[i-1] == c) {
-                return sstrsubs(s, i-1);
-            }
-        }
+    size_t pos = 0;
+    if(ucx_strrchr(s.ptr, s.length, c, &pos)) {
+        return sstrsubs(s, pos);
     }
-    sstr_t n;
-    n.ptr = NULL;
-    n.length = 0;
-    return n;
+    return sstrn(NULL, 0);
+}
+
+scstr_t scstrchr(scstr_t s, int c) {
+    size_t pos = 0;
+    if(ucx_strchr(s.ptr, s.length, c, &pos)) {
+        return scstrsubs(s, pos);
+    }
+    return scstrn(NULL, 0);
+}
+
+scstr_t scstrrchr(scstr_t s, int c) {
+    size_t pos = 0;
+    if(ucx_strrchr(s.ptr, s.length, c, &pos)) {
+        return scstrsubs(s, pos);
+    }
+    return scstrn(NULL, 0);
 }
 
 #define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \
@@ -185,13 +277,21 @@
     else ((size_t*)ptable)[index] = src;\
     } while (0);
 
-sstr_t sstrstr(sstr_t string, sstr_t match) {
-    if (match.length == 0) {
-        return string;
+
+static const char* ucx_strstr(
+        const char *str,
+        size_t length,
+        const char *match,
+        size_t matchlen,
+        size_t *newlen)
+{
+    *newlen = length;
+    if (matchlen == 0) {
+        return str;
     }
     
-    /* prepare default return value in case of no match */
-    sstr_t result = sstrn(NULL, 0);
+    const char *result = NULL;
+    size_t resultlen = 0;
     
     /*
      * IMPORTANT:
@@ -206,9 +306,9 @@
     
     /* check pattern length and use appropriate prefix table */
     /* if the pattern exceeds static prefix table, allocate on the heap */
-    register int useheap = match.length > 255;
+    register int useheap = matchlen > 255;
     register void* ptable = useheap ?
-        calloc(match.length+1, sizeof(size_t)): s_prefix_table;
+        calloc(matchlen+1, sizeof(size_t)): s_prefix_table;
     
     /* keep counter in registers */
     register size_t i, j;
@@ -216,8 +316,8 @@
     /* fill prefix table */
     i = 0; j = 0;
     ptable_w(useheap, ptable, i, j);
-    while (i < match.length) {
-        while (j >= 1 && match.ptr[j-1] != match.ptr[i]) {
+    while (i < matchlen) {
+        while (j >= 1 && match[j-1] != match[i]) {
             ptable_r(j, useheap, ptable, j-1);
         }
         i++; j++;
@@ -226,15 +326,15 @@
 
     /* search */
     i = 0; j = 1;
-    while (i < string.length) {
-        while (j >= 1 && string.ptr[i] != match.ptr[j-1]) {
+    while (i < length) {
+        while (j >= 1 && str[i] != match[j-1]) {
             ptable_r(j, useheap, ptable, j-1);
         }
         i++; j++;
-        if (j-1 == match.length) {
-            size_t start = i - match.length;
-            result.ptr = string.ptr + start;
-            result.length = string.length - start;
+        if (j-1 == matchlen) {
+            size_t start = i - matchlen;
+            result = str + start;
+            resultlen = length - start;
             break;
         }
     }
@@ -244,17 +344,54 @@
         free(ptable);
     }
     
+    *newlen = resultlen;
+    return result;
+}
+
+sstr_t scstrsstr(sstr_t string, scstr_t match) {
+    sstr_t result;
+    
+    size_t reslen;
+    const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen);
+    if(!resstr) {
+        result.ptr = NULL;
+        result.length = 0;
+        return result;
+    }
+    
+    size_t pos = resstr - string.ptr;
+    result.ptr = string.ptr + pos;
+    result.length = reslen;
+    
+    return result;
+}
+
+scstr_t scstrscstr(scstr_t string, scstr_t match) {
+    scstr_t result;
+    
+    size_t reslen;
+    const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen);
+    if(!resstr) {
+        result.ptr = NULL;
+        result.length = 0;
+        return result;
+    }
+    
+    size_t pos = resstr - string.ptr;
+    result.ptr = string.ptr + pos;
+    result.length = reslen;
+    
     return result;
 }
 
 #undef ptable_r
 #undef ptable_w
 
-sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) {
-    return sstrsplit_a(ucx_default_allocator(), s, d, n);
+sstr_t* scstrsplit(scstr_t s, scstr_t d, ssize_t *n) {
+    return scstrsplit_a(ucx_default_allocator(), s, d, n);
 }
 
-sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) {
+sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t s, scstr_t d, ssize_t *n) {
     if (s.length == 0 || d.length == 0) {
         *n = -1;
         return NULL;
@@ -269,20 +406,24 @@
         } else /* no match possible */ {
             *n = 1;
             sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t));
-            *result = sstrdup_a(allocator, s);
+            if(result) {
+                *result = sstrdup_a(allocator, s);
+            } else {
+                *n = -2;
+            }
             return result;
         }
     }
     
     ssize_t nmax = *n;
     size_t arrlen = 16;
-    sstr_t* result = (sstr_t*) almalloc(allocator, arrlen*sizeof(sstr_t));
+    sstr_t* result = (sstr_t*) alcalloc(allocator, arrlen, sizeof(sstr_t));
 
     if (result) {
-        sstr_t curpos = s;
+        scstr_t curpos = s;
         ssize_t j = 1;
         while (1) {
-            sstr_t match;
+            scstr_t match;
             /* optimize for one byte delimiters */
             if (d.length == 1) {
                 match = curpos;
@@ -294,13 +435,13 @@
                     match.length--;
                 }
             } else {
-                match = sstrstr(curpos, d);
+                match = scstrscstr(curpos, d);
             }
             if (match.length > 0) {
                 /* is this our last try? */
                 if (nmax == 0 || j < nmax) {
                     /* copy the current string to the array */
-                    sstr_t item = sstrn(curpos.ptr, match.ptr - curpos.ptr);
+                    scstr_t item = scstrn(curpos.ptr, match.ptr - curpos.ptr);
                     result[j-1] = sstrdup_a(allocator, item);
                     size_t processed = item.length + d.length;
                     curpos.ptr += processed;
@@ -310,8 +451,12 @@
                     j++;
                     if (j > arrlen) {
                         arrlen *= 2;
-                        sstr_t* reallocated = (sstr_t*) alrealloc(
-                                allocator, result, arrlen*sizeof(sstr_t));
+                        size_t reallocsz;
+                        sstr_t* reallocated = NULL;
+                        if(!ucx_szmul(arrlen, sizeof(sstr_t), &reallocsz)) {
+                            reallocated = (sstr_t*) alrealloc(
+                                    allocator, result, reallocsz);
+                        }
                         if (reallocated) {
                             result = reallocated;
                         } else {
@@ -342,7 +487,7 @@
     return result;
 }
 
-int sstrcmp(sstr_t s1, sstr_t s2) {
+int scstrcmp(scstr_t s1, scstr_t s2) {
     if (s1.length == s2.length) {
         return memcmp(s1.ptr, s2.ptr, s1.length);
     } else if (s1.length > s2.length) {
@@ -352,7 +497,7 @@
     }
 }
 
-int sstrcasecmp(sstr_t s1, sstr_t s2) {
+int scstrcasecmp(scstr_t s1, scstr_t s2) {
     if (s1.length == s2.length) {
 #ifdef _WIN32
         return _strnicmp(s1.ptr, s2.ptr, s1.length);
@@ -366,11 +511,11 @@
     }
 }
 
-sstr_t sstrdup(sstr_t s) {
+sstr_t scstrdup(scstr_t s) {
     return sstrdup_a(ucx_default_allocator(), s);
 }
 
-sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) {
+sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t s) {
     sstr_t newstring;
     newstring.ptr = (char*)almalloc(allocator, s.length + 1);
     if (newstring.ptr) {
@@ -385,21 +530,38 @@
     return newstring;
 }
 
-sstr_t sstrtrim(sstr_t string) {
-    sstr_t newstr = string;
+
+static size_t ucx_strtrim(const char *s, size_t len, size_t *newlen) {
+    const char *newptr = s;
+    size_t length = len;
     
-    while (newstr.length > 0 && isspace(*newstr.ptr)) {
-        newstr.ptr++;
-        newstr.length--;
+    while(length > 0 && isspace(*newptr)) {
+        newptr++;
+        length--;
     }
-    while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) {
-        newstr.length--;
+    while(length > 0 && isspace(newptr[length-1])) {
+        length--;
     }
     
+    *newlen = length;
+    return newptr - s;
+}
+
+sstr_t sstrtrim(sstr_t string) {
+    sstr_t newstr;
+    newstr.ptr = string.ptr
+                 + ucx_strtrim(string.ptr, string.length, &newstr.length);
     return newstr;
 }
 
-int sstrprefix(sstr_t string, sstr_t prefix) {
+scstr_t scstrtrim(scstr_t string) {
+    scstr_t newstr;
+    newstr.ptr = string.ptr
+                 + ucx_strtrim(string.ptr, string.length, &newstr.length);
+    return newstr;
+}
+
+int scstrprefix(scstr_t string, scstr_t prefix) {
     if (string.length == 0) {
         return prefix.length == 0;
     }
@@ -414,7 +576,7 @@
     }
 }
 
-int sstrsuffix(sstr_t string, sstr_t suffix) {
+int scstrsuffix(scstr_t string, scstr_t suffix) {
     if (string.length == 0) {
         return suffix.length == 0;
     }
@@ -430,7 +592,7 @@
     }
 }
 
-sstr_t sstrlower(sstr_t string) {
+sstr_t scstrlower(scstr_t string) {
     sstr_t ret = sstrdup(string);
     for (size_t i = 0; i < ret.length ; i++) {
         ret.ptr[i] = tolower(ret.ptr[i]);
@@ -438,7 +600,7 @@
     return ret;
 }
 
-sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) {
+sstr_t scstrlower_a(UcxAllocator *allocator, scstr_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]);
@@ -446,7 +608,7 @@
     return ret;
 }
 
-sstr_t sstrupper(sstr_t string) {
+sstr_t scstrupper(scstr_t string) {
     sstr_t ret = sstrdup(string);
     for (size_t i = 0; i < ret.length ; i++) {
         ret.ptr[i] = toupper(ret.ptr[i]);
@@ -454,10 +616,24 @@
     return ret;
 }
 
-sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) {
+sstr_t scstrupper_a(UcxAllocator *allocator, scstr_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;
 }
+
+// type adjustment functions
+scstr_t ucx_sc2sc(scstr_t str) {
+    return str;
+}
+scstr_t ucx_ss2sc(sstr_t str) {
+    scstr_t cs;
+    cs.ptr = str.ptr;
+    cs.length = str.length;
+    return cs;
+}
+scstr_t ucx_ss2c_s(scstr_t c) {
+    return c;
+}
--- a/ucx/ucx.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx.c	Mon Feb 04 17:17:48 2019 +0100
@@ -44,3 +44,19 @@
  */
 
 #include "ucx/ucx.h"
+
+int ucx_szmul_impl(size_t a, size_t b, size_t *result) {
+    if(a == 0 || b == 0) {
+        *result = 0;
+        return 0;
+    }
+    size_t r = a * b;
+    if(r / b == a) {
+        *result = r;
+        return 0;
+    } else {
+        *result = 0;
+        return 1;
+    }
+}
+
--- a/ucx/ucx/avl.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/avl.h	Mon Feb 04 17:17:48 2019 +0100
@@ -125,7 +125,7 @@
  * 
  * 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.
+ * ucx_cmp_str() function here.
  * 
  * @param cmpfunc the compare function that shall be used
  * @param allocator the UcxAllocator that shall be used
@@ -135,17 +135,43 @@
 
 /**
  * Destroys a UcxAVLTree.
+ * 
+ * Note, that the contents are not automatically freed.
+ * Use may use #ucx_avl_free_content() before calling this function.
+ * 
  * @param tree the tree to destroy
+ * @see ucx_avl_free_content()
  */
 void ucx_avl_free(UcxAVLTree *tree);
 
 /**
+ * Frees the contents of a UcxAVLTree.
+ * 
+ * This is a convenience function that iterates over the tree and passes all
+ * values to the specified destructor function.
+ * 
+ * If no destructor is specified (<code>NULL</code>), the free() function of
+ * the tree's own allocator is used.
+ * 
+ * You must ensure, that it is valid to pass each value in the map to the same
+ * destructor function.
+ * 
+ * You should free the entire tree afterwards, as the contents will be invalid.
+ * 
+ * @param tree for which the contents shall be freed
+ * @param destr optional pointer to a destructor function
+ * @see ucx_avl_free()
+ */
+void ucx_avl_free_content(UcxAVLTree *tree, ucx_destructor destr);
+
+/**
  * Macro for initializing a new UcxAVLTree with the default allocator and a
- * ucx_ptrcmp() compare function.
+ * ucx_cmp_ptr() compare function.
  * 
  * @return a new default UcxAVLTree object
  */
-#define ucx_avl_default_new() ucx_avl_new_a(ucx_ptrcmp, ucx_default_allocator())
+#define ucx_avl_default_new() \
+    ucx_avl_new_a(ucx_cmp_ptr, ucx_default_allocator())
 
 /**
  * Gets the node from the tree, that is associated with the specified key.
--- a/ucx/ucx/buffer.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/buffer.h	Mon Feb 04 17:17:48 2019 +0100
@@ -137,6 +137,67 @@
 #define ucx_buffer_clone(src,flags) \
     ucx_buffer_extract(src, 0, (src)->capacity, flags)
 
+
+/**
+ * Shifts the contents of the buffer by the given offset.
+ * 
+ * If the offset is positive, the contents are shifted to the right.
+ * If auto extension is enabled, the buffer grows, if necessary.
+ * In case the auto extension fails, this function returns a non-zero value and
+ * no contents are changed.
+ * If auto extension is disabled, the contents that do not fit into the buffer
+ * are discarded.
+ * 
+ * If the offset is negative, the contents are shifted to the left where the
+ * first <code>shift</code> bytes are discarded.
+ * The new size of the buffer is the old size minus
+ * the absolute shift value.
+ * If this value is larger than the buffer size, the buffer is emptied (but
+ * not cleared, see the security note below).
+ * 
+ * The buffer position gets shifted alongside with the content but is kept
+ * within the boundaries of the buffer.
+ * 
+ * <b>Security note:</b> the shifting operation does <em>not</em> erase the
+ * previously occupied memory cells. You can easily do that manually, e.g. by
+ * calling <code>memset(buffer->space, 0, shift)</code> for a right shift or
+ * <code>memset(buffer->size, 0, buffer->capacity-buffer->size)</code>
+ * for a left shift.
+ * 
+ * @param buffer the buffer
+ * @param shift the shift offset (negative means left shift)
+ * @return 0 on success, non-zero if a required auto-extension fails
+ */
+int ucx_buffer_shift(UcxBuffer* buffer, off_t shift);
+
+/**
+ * Shifts the buffer to the right.
+ * See ucx_buffer_shift() for details.
+ * 
+ * @param buffer the buffer
+ * @param shift the shift offset
+ * @return 0 on success, non-zero if a required auto-extension fails
+ * @see ucx_buffer_shift()
+ */
+int ucx_buffer_shift_right(UcxBuffer* buffer, size_t shift);
+
+/**
+ * Shifts the buffer to the left.
+ * 
+ * See ucx_buffer_shift() for details. Note, however, that this method expects
+ * a positive shift offset.
+ * 
+ * Since a left shift cannot fail due to memory allocation problems, this
+ * function always returns zero.
+ * 
+ * @param buffer the buffer
+ * @param shift the shift offset
+ * @return always zero
+ * @see ucx_buffer_shift()
+ */
+int ucx_buffer_shift_left(UcxBuffer* buffer, size_t shift);
+
+
 /**
  * Moves the position of the buffer.
  * 
@@ -165,8 +226,8 @@
  * 
  * @param buffer the buffer to be cleared
  */
-#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \
-        buffer->size = 0; buffer->pos = 0;
+#define ucx_buffer_clear(buffer) memset((buffer)->space, 0, (buffer)->size); \
+        (buffer)->size = 0; (buffer)->pos = 0;
 
 /**
  * Tests, if the buffer position has exceeded the buffer capacity.
@@ -260,7 +321,15 @@
  * @param str the string
  * @return the number of bytes written
  */
-size_t ucx_buffer_puts(UcxBuffer *buffer, char *str);
+size_t ucx_buffer_puts(UcxBuffer *buffer, const char *str);
+
+/**
+ * Returns the complete buffer content as sstr_t.
+ * @param buffer the buffer
+ * @return the result of <code>sstrn()</code> with the buffer space and size
+ * as arguments
+ */
+#define ucx_buffer_to_sstr(buffer) sstrn((buffer)->space, (buffer)->size)
 
 #ifdef	__cplusplus
 }
--- a/ucx/ucx/list.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/list.h	Mon Feb 04 17:17:48 2019 +0100
@@ -173,9 +173,11 @@
  * 
  * Note, that the contents are not usable afterwards and the list should be
  * destroyed with ucx_list_free().
+ *
+ * If no destructor is specified (<code>NULL</code>), stdlib's free() is used.
  * 
  * @param list the list for which the contents shall be freed
- * @param destr the destructor function (e.g. stdlib free())
+ * @param destr optional destructor function
  * @see ucx_list_free()
  */
 void ucx_list_free_content(UcxList* list, ucx_destructor destr);
@@ -210,40 +212,6 @@
  */
 UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data);
 
-/**
- * Inserts an element at the end of the list, if it is not present in the list.
- * 
- * 
- * @param list the list where to append the data, or <code>NULL</code> to
- * create a new list
- * @param data the data to insert
- * @param cmpfnc the compare function
- * @param cmpdata additional data for the compare function
- * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to
- * the newly created list otherwise
- * @see ucx_list_append()
- */
-UcxList *ucx_list_append_once(UcxList *list, void *data,
-        cmp_func cmpfnc, void *cmpdata);
-
-/**
- * Inserts an element at the end of the list, if it is not present in the list,
- * using a UcxAllocator.
- * 
- * See ucx_list_append() for details.
- * 
- * @param allocator the allocator to use
- * @param list the list where to append the data, or <code>NULL</code> to
- * create a new list
- * @param data the data to insert
- * @param cmpfnc the compare function
- * @param cmpdata additional data for the compare function
- * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to
- * the newly created list otherwise
- * @see ucx_list_append_a()
- */
-UcxList *ucx_list_append_once_a(UcxAllocator *allocator,
-        UcxList *list, void *data, cmp_func cmpfnc, void *cmpdata);
 
 /**
  * Inserts an element at the beginning of the list.
--- a/ucx/ucx/logging.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/logging.h	Mon Feb 04 17:17:48 2019 +0100
@@ -177,6 +177,18 @@
         const unsigned int line, const char* format, ...);
 
 /**
+ * Registers a custom log level.
+ * @param logger the logger
+ * @param level the log level as unsigned integer
+ * @param name a string literal describing the level
+ */
+#define ucx_logger_register_level(logger, level, name) {\
+        unsigned int l; \
+            l = level; \
+            ucx_map_int_put(logger->levels, l, (void*) "[" name "]"); \
+        } while (0);
+
+/**
  * Logs a message at the specified level.
  * @param logger the logger to use
  * @param level the level to log the message on
--- a/ucx/ucx/map.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/map.h	Mon Feb 04 17:17:48 2019 +0100
@@ -89,26 +89,36 @@
     size_t        count;
 };
 
-/** Structure for a key of a UcxMap. */
+/** Structure to publicly denote a key of a UcxMap. */
 struct UcxKey {
     /** The key data. */
-    void   *data;
+    const void *data;
     /** The length of the key data. */
-    size_t len;
+    size_t     len;
+    /** A cache for the hash value of the key data. */
+    int        hash;
+};
+
+/** Internal structure for a key of a UcxMap. */
+struct UcxMapKey {
+    /** The key data. */
+    void    *data;
+    /** The length of the key data. */
+    size_t  len;
     /** The hash value of the key data. */
-    int    hash;
+    int     hash;
 };
 
 /** Structure for an element of a UcxMap. */
 struct UcxMapElement {
     /** The value data. */
-    void          *data;
+    void              *data;
     
     /** A pointer to the next element in the current list. */
-    UcxMapElement *next;
+    UcxMapElement     *next;
     
     /** The corresponding key. */
-    UcxKey        key;
+    struct UcxMapKey  key;
 };
 
 /** Structure for an iterator over a UcxMap. */
@@ -158,7 +168,10 @@
  * 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()).
+ * values to the specified destructor function.
+ * 
+ * If no destructor is specified (<code>NULL</code>), the free() function of
+ * the map's own allocator is used.
  * 
  * You must ensure, that it is valid to pass each value in the map to the same
  * destructor function.
@@ -166,7 +179,7 @@
  * 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
+ * @param destr optional pointer to a destructor function
  * @see ucx_map_free()
  * @see ucx_map_clear()
  */
@@ -282,7 +295,7 @@
  * @see ucx_map_put()
  */
 #define ucx_map_cstr_put(map, key, value) \
-    ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value)
+    ucx_map_put(map, ucx_key(key, strlen(key)), (void*)value)
 
 /**
  * Shorthand for putting data with an integer key into the map.
@@ -293,7 +306,7 @@
  * @see ucx_map_put()
  */
 #define ucx_map_int_put(map, key, value) \
-    ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value)
+    ucx_map_put(map, ucx_key(&key, sizeof(key)), (void*)value)
 
 /**
  * Shorthand for getting data from the map with a sstr_t key.
@@ -313,7 +326,7 @@
  * @see ucx_map_get()
  */
 #define ucx_map_cstr_get(map, key) \
-    ucx_map_get(map, ucx_key((void*)key, strlen(key)))
+    ucx_map_get(map, ucx_key(key, strlen(key)))
 
 /**
  * Shorthand for getting data from the map with an integer key.
@@ -323,7 +336,7 @@
  * @see ucx_map_get()
  */
 #define ucx_map_int_get(map, key) \
-    ucx_map_get(map, ucx_key((void*)&key, sizeof(int)))
+    ucx_map_get(map, ucx_key(&key, sizeof(int)))
 
 /**
  * Shorthand for removing data from the map with a sstr_t key.
@@ -343,7 +356,7 @@
  * @see ucx_map_remove()
  */
 #define ucx_map_cstr_remove(map, key) \
-    ucx_map_remove(map, ucx_key((void*)key, strlen(key)))
+    ucx_map_remove(map, ucx_key(key, strlen(key)))
 
 /**
  * Shorthand for removing data from the map with an integer key.
@@ -353,7 +366,7 @@
  * @see ucx_map_remove()
  */
 #define ucx_map_int_remove(map, key) \
-    ucx_map_remove(map, ucx_key((void*)&key, sizeof(key)))
+    ucx_map_remove(map, ucx_key(&key, sizeof(key)))
 
 /**
  * Creates a UcxKey based on the given data.
@@ -365,7 +378,7 @@
  * @return a UcxKey with implicitly computed hash
  * @see ucx_hash()
  */
-UcxKey ucx_key(void *data, size_t len);
+UcxKey ucx_key(const void *data, size_t len);
 
 /**
  * Computes a murmur hash-2.
--- a/ucx/ucx/mempool.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/mempool.h	Mon Feb 04 17:17:48 2019 +0100
@@ -164,6 +164,9 @@
  * 
  * The destructor is automatically called when the memory is freed or the
  * pool is destroyed.
+ * A destructor for pooled memory <b>MUST NOT</b> free the memory itself,
+ * as this is done by the pool. Use a destructor to free any resources
+ * managed by the pooled object.
  * 
  * The only requirement for the specified memory is, that it <b>MUST</b> be
  * pooled memory by a UcxMempool or an element-compatible mempool. The pointer
@@ -179,12 +182,18 @@
 
 /**
  * Registers a destructor function for the specified (non-pooled) memory.
- * 
+ *
  * This is useful, if you have memory that has not been allocated by a mempool,
  * but shall be managed by a mempool.
  * 
  * This function creates an entry in the specified mempool and the memory will
  * therefore (logically) convert to pooled memory.
+ * <b>However, this does not cause the memory to be freed automatically!</b>.
+ * If you want to use this function, make the memory pool free non-pooled
+ * memory, the specified destructor function must call <code>free()</code>
+ * by itself. But keep in mind, that you then MUST NOT use this destructor
+ * function with pooled memory (e.g. in ucx_mempool_set_destr()), as it
+ * would cause a double-free.
  * 
  * @param pool the memory pool
  * @param ptr data the destructor is registered for
--- a/ucx/ucx/properties.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/properties.h	Mon Feb 04 17:17:48 2019 +0100
@@ -173,12 +173,15 @@
  * Retrieves all available key/value-pairs and puts them into a UcxMap.
  * 
  * This is done by successive calls to ucx_properties_next() until no more
- * key/value-pairs can be retrieved. 
+ * key/value-pairs can be retrieved.
+ * 
+ * The memory for the map values is allocated by the map's own allocator.
  * 
  * @param prop the UcxProperties object
  * @param map the target map
  * @return The UcxProperties.error code (i.e. 0 on success).
  * @see ucx_properties_fill()
+ * @see UcxMap.allocator
  */
 int ucx_properties2map(UcxProperties *prop, UcxMap *map);
 
--- a/ucx/ucx/stack.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/stack.h	Mon Feb 04 17:17:48 2019 +0100
@@ -91,19 +91,23 @@
  * 
  * @param stack a pointer to the stack
  * @param n amount of memory to allocate
- * @return a pointer to the allocated memory
+ * @return a pointer to the allocated memory or <code>NULL</code> on stack
+ * overflow
  * @see ucx_allocator_malloc()
  */
 void *ucx_stack_malloc(UcxStack *stack, size_t n);
 
 /**
- * Alias for #ucx_stack_malloc().
+ * Allocates memory with #ucx_stack_malloc() and copies the specified data if
+ * the allocation was successful.
+ * 
  * @param stack a pointer to the stack
  * @param n amount of memory to allocate
+ * @param data a pointer to the data to copy
  * @return a pointer to the allocated memory
  * @see ucx_stack_malloc
  */
-#define ucx_stack_push(stack, n) ucx_stack_malloc(stack, n)
+void *ucx_stack_push(UcxStack *stack, size_t n, const void *data);
 
 /**
  * Allocates an array of stack memory
@@ -119,15 +123,18 @@
 void *ucx_stack_calloc(UcxStack *stack, size_t nelem, size_t elsize);
 
 /**
- * Alias for #ucx_stack_calloc().
+ * Allocates memory with #ucx_stack_calloc() and copies the specified data if
+ * the allocation was successful.
  * 
  * @param stack a pointer to the stack
- * @param n amount of elements to allocate
+ * @param nelem amount of elements to allocate
  * @param elsize amount of memory per element
+ * @param data a pointer to the data
  * @return a pointer to the allocated memory
  * @see ucx_stack_calloc
  */
-#define ucx_stack_pusharr(stack,n,elsize) ucx_stack_calloc(stack,n,elssize)
+void *ucx_stack_pusharr(UcxStack *stack,
+        size_t nelem, size_t elsize, const void *data);
 
 /**
  * Reallocates memory on the stack.
@@ -184,12 +191,13 @@
  * 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>.
+ * This function copies at most <code>n</code> bytes to the destination, but
+ * the element is always freed as a whole.
+ * If the element was larger than <code>n</code>, the remaining data is lost.
  * 
  * @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>
+ * @param n copies at most n bytes to <code>dest</code>
  * @see ucx_stack_pop
  */
 void ucx_stack_popn(UcxStack *stack, void *dest, size_t n);
--- a/ucx/ucx/string.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/string.h	Mon Feb 04 17:17:48 2019 +0100
@@ -52,26 +52,192 @@
 #include "allocator.h"
 #include <stddef.h>
 
-/** Shortcut for a <code>sstr_t struct</code> literal. */
-#define ST(s) { (char*)s, sizeof(s)-1 }
+/*
+ * Use this macro to disable the shortcuts if you experience macro collision.
+ */
+#ifndef UCX_NO_SSTR_SHORTCUTS
+/**
+ * Shortcut for a <code>sstr_t struct</code>
+ * or <code>scstr_t struct</code> literal.
+ */
+#define ST(s) { s, sizeof(s)-1 }
 
 /** Shortcut for the conversion of a C string to a <code>sstr_t</code>. */
-#define S(s) sstrn((char*)s, sizeof(s)-1)
+#define S(s) sstrn(s, sizeof(s)-1)
+
+/** Shortcut for the conversion of a C string to a <code>scstr_t</code>. */
+#define SC(s) scstrn(s, sizeof(s)-1)
+#endif /* UCX_NO_SSTR_SHORTCUTS */
+
+/*
+ * Use this macro to disable the format macros.
+ */
+#ifndef UCX_NO_SSTR_FORMAT_MACROS
+/** Expands a sstr_t or scstr_t to printf arguments. */
+#define SFMT(s) (int) (s).length, (s).ptr
+
+/** Format specifier for a sstr_t or scstr_t. */
+#define PRIsstr ".*s"
+#endif /* UCX_NO_SSTR_FORMAT_MACROS */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+/**
+ * The UCX string structure.
+ */
+typedef struct {
+   /** A pointer to the string
+    * (<b>not necessarily <code>NULL</code>-terminated</b>) */
+    char *ptr;
+    /** The length of the string */
+    size_t length;
+} sstr_t;
+
+/**
+ * The UCX string structure for immutable (constant) strings.
+ */
+typedef struct {
+    /** A constant pointer to the immutable string
+     * (<b>not necessarily <code>NULL</code>-terminated</b>) */
+    const char *ptr;
+    /** The length of the string */
+    size_t length;
+} scstr_t;
+
+#ifdef	__cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+/**
+ * One of two type adjustment functions that return a scstr_t.
+ * 
+ * Used <b>internally</b> to convert a UCX string to an immutable UCX string.
+ * 
+ * <b>Do not use this function manually.</b>
+ * 
+ * @param str some sstr_t
+ * @return an immutable (scstr_t) version of the provided string.
+ */
+inline scstr_t s2scstr(sstr_t s) {
+    scstr_t c;
+    c.ptr = s.ptr;
+    c.length = s.length;
+    return c;
+}
+
+/**
+ * One of two type adjustment functions that return a scstr_t.
+ * 
+ * Used <b>internally</b> to convert a UCX string to an immutable UCX string.
+ * This variant is used, when the string is already immutable and no operation
+ * needs to be performed.
+ * 
+ * <b>Do not use this function manually.</b>
+ * 
+ * @param str some scstr_t
+ * @return the argument itself
+ */
+inline scstr_t s2scstr(scstr_t str) {
+    return str;
+}
+
+/**
+ * Converts a UCX string to an immutable UCX string (scstr_t).
+ * @param str some UCX string
+ * @return the an immutable version of the provided string
+ */
+#define SCSTR(s) s2scstr(s)
+#else
+
+/**
+ * One of two type adjustment functions that return a scstr_t.
+ * 
+ * Used <b>internally</b> to convert a UCX string to an immutable UCX string.
+ * This variant is used, when the string is already immutable and no operation
+ * needs to be performed.
+ * 
+ * <b>Do not use this function manually.</b>
+ * 
+ * @param str some scstr_t
+ * @return the argument itself
+ */
+scstr_t ucx_sc2sc(scstr_t str);
+
+/**
+ * One of two type adjustment functions that return a scstr_t.
+ * 
+ * Used <b>internally</b> to convert a UCX string to an immutable UCX string.
+ * 
+ * <b>Do not use this function manually.</b>
+ * 
+ * @param str some sstr_t
+ * @return an immutable (scstr_t) version of the provided string.
+ */
+scstr_t ucx_ss2sc(sstr_t str);
+
+#if __STDC_VERSION__ >= 201112L
+/**
+ * Converts a UCX string to an immutable UCX string (scstr_t).
+ * @param str some UCX string
+ * @return the an immutable version of the provided string
+ */
+#define SCSTR(str) _Generic(str, sstr_t: ucx_ss2sc, scstr_t: ucx_sc2sc)(str)
+
+#elif defined(__GNUC__) || defined(__clang__)
+
+/**
+ * Converts a UCX string to an immutable UCX string (scstr_t).
+ * @param str some UCX string
+ * @return the an immutable version of the provided string
+ */
+#define SCSTR(str) __builtin_choose_expr( \
+        __builtin_types_compatible_p(typeof(str), sstr_t), \
+        ucx_ss2sc, \
+        ucx_sc2sc)(str)
+
+#elif defined(__sun)
+
+/**
+ * Converts a UCX string to an immutable UCX string (scstr_t).
+ * @param str some UCX string
+ * @return the an immutable version of the provided string
+ */
+#define SCSTR(str) ({typeof(str) ucx_tmp_var_str = str; \
+	scstr_t ucx_tmp_var_c; \
+	ucx_tmp_var_c.ptr = ucx_tmp_var_str.ptr;\
+	ucx_tmp_var_c.length = ucx_tmp_var_str.length;\
+	ucx_tmp_var_c; })
+#else /* no generics and no builtins */
+
+/**
+ * Converts a UCX string to an immutable UCX string (scstr_t).
+ * 
+ * This <b>internal</b> function (ab)uses the C standard an expects one single
+ * argument which is then implicitly converted to scstr_t without a warning.
+ * 
+ * <b>Do not use this function manually.</b>
+ * 
+ * @return the an immutable version of the provided string
+ */
+scstr_t ucx_ss2c_s();
+
+/**
+ * Converts a UCX string to an immutable UCX string (scstr_t).
+ * @param str some UCX string
+ * @return the an immutable version of the provided string
+ */
+#define SCSTR(str) ucx_ss2c_s(str)
+#endif /* C11 feature test */
+
+#endif /* C++ */
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-/**
- * The UCX string structure.
- */
-typedef struct {
-   /** A reference to the string (<b>not necessarily  <code>NULL</code>
-    * -terminated</b>) */
-    char   *ptr;
-    /** The length of the string */
-    size_t length;
-} sstr_t;
 
 /**
  * Creates a new sstr_t based on a C string.
@@ -81,6 +247,8 @@
  * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you
  * do want a copy, use sstrdup() on the return value of this function.
  * 
+ * If you need to wrap a constant string, use scstr().
+ * 
  * @param cstring the C string to wrap
  * @return a new sstr_t containing the C string
  * 
@@ -94,6 +262,8 @@
  * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you
  * do want a copy, use sstrdup() on the return value of this function.
  * 
+ * If you need to wrap a constant string, use scstrn().
+ * 
  * @param cstring  the C string to wrap
  * @param length   the length of the string
  * @return a new sstr_t containing the C string
@@ -103,21 +273,57 @@
  */
 sstr_t sstrn(char *cstring, size_t length);
 
+/**
+ * Creates a new scstr_t based on a constant C string.
+ * 
+ * The length is implicitly inferred by using a call to <code>strlen()</code>.
+ *
+ * <b>Note:</b> the scstr_t will hold a <i>reference</i> to the C string. If you
+ * do want a copy, use scstrdup() on the return value of this function.
+ * 
+ * @param cstring the C string to wrap
+ * @return a new scstr_t containing the C string
+ * 
+ * @see scstrn()
+ */
+scstr_t scstr(const char *cstring);
+
+
+/**
+ * Creates a new scstr_t of the specified length based on a constant C string.
+ *
+ * <b>Note:</b> the scstr_t will hold a <i>reference</i> to the C string. If you
+ * do want a copy, use scstrdup() on the return value of this function.
+ * 
+ * 
+ * @param cstring  the C string to wrap
+ * @param length   the length of the string
+ * @return a new scstr_t containing the C string
+ * 
+ * @see scstr()
+ */
+scstr_t scstrn(const char *cstring, size_t length);
 
 /**
  * Returns the cumulated length of all specified strings.
- *
- * At least one string must be specified.
  * 
  * <b>Attention:</b> if the count argument does not match the count of the
  * specified strings, the behavior is undefined.
  *
  * @param count    the total number of specified strings (so at least 1)
- * @param string   the first string
- * @param ...      all other strings
+ * @param ...      all strings
  * @return the cumulated length of all strings
  */
-size_t sstrnlen(size_t count, sstr_t string, ...);
+size_t scstrnlen(size_t count, ...);
+
+/**
+ * Alias for scstrnlen() which automatically converts the arguments.
+ * 
+ * @param count    the total number of specified strings (so at least 1)
+ * @param ...      all strings
+ * @return the cumulated length of all strings
+ */
+#define sstrnlen(count, ...) scstrnlen(count, __VA_ARGS__)
 
 /**
  * Concatenates two or more strings.
@@ -130,26 +336,47 @@
  *
  * @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 scstrcat(size_t count, scstr_t s1, ...);
+
+/**
+ * Alias for scstrcat() which automatically converts the arguments.
+ * 
+ * @param count   the total number of strings to concatenate
+ * @param s1      first string
  * @param ...     all remaining strings
  * @return the concatenated string
  */
-sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...);
+#define sstrcat(count, s1, ...) scstrcat(count, SCSTR(s1), __VA_ARGS__)
 
 /**
  * Concatenates two or more strings using a UcxAllocator.
  * 
+ * See scstrcat() for details.
+ *
+ * @param a       the allocator to use
+ * @param count   the total number of strings to concatenate
+ * @param s1      first string
+ * @param ...     all remaining strings
+ * @return the concatenated string
+ */
+sstr_t scstrcat_a(UcxAllocator *a, size_t count, scstr_t s1, ...);
+
+/**
+ * Alias for scstrcat_a() which automatically converts the arguments.
+ * 
  * See sstrcat() for details.
  *
  * @param a       the allocator to use
  * @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_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...);
-
+#define sstrcat_a(a, count, s1, ...) \
+    scstrcat_a(a, count, SCSTR(s1), __VA_ARGS__)
 
 /**
  * Returns a substring starting at the specified location.
@@ -186,6 +413,42 @@
 sstr_t sstrsubsl(sstr_t string, size_t start, size_t length);
 
 /**
+ * Returns a substring of an immutable string starting at the specified
+ * location.
+ * 
+ * <b>Attention:</b> the new string references the same memory area as the
+ * input string and will <b>NOT</b> be <code>NULL</code>-terminated.
+ * Use scstrdup() to get a copy.
+ * 
+ * @param string input string
+ * @param start  start location of the substring
+ * @return a substring of <code>string</code> starting at <code>start</code>
+ * 
+ * @see scstrsubsl()
+ * @see scstrchr()
+ */
+scstr_t scstrsubs(scstr_t string, size_t start);
+
+/**
+ * Returns a substring of an immutable string with a maximum length starting
+ * at the specified location.
+ * 
+ * <b>Attention:</b> the new string references the same memory area as the
+ * input string and will <b>NOT</b> be <code>NULL</code>-terminated.
+ * Use scstrdup() to get a copy.
+ * 
+ * @param string input string
+ * @param start  start location of the substring
+ * @param length the maximum length of the substring
+ * @return a substring of <code>string</code> starting at <code>start</code>
+ * with a maximum length of <code>length</code>
+ * 
+ * @see scstrsubs()
+ * @see scstrchr()
+ */
+scstr_t scstrsubsl(scstr_t string, size_t start, size_t length);
+
+/**
  * Returns a substring starting at the location of the first occurrence of the
  * specified character.
  * 
@@ -214,6 +477,34 @@
 sstr_t sstrrchr(sstr_t string, int chr);
 
 /**
+ * Returns an immutable substring starting at the location of the first
+ * occurrence of the specified character.
+ * 
+ * If the string does not contain the character, an empty string is returned.
+ * 
+ * @param string the string where to locate the character
+ * @param chr    the character to locate
+ * @return       a substring starting at the first location of <code>chr</code>
+ * 
+ * @see scstrsubs()
+ */
+scstr_t scstrchr(scstr_t string, int chr);
+
+/**
+ * Returns an immutable substring starting at the location of the last
+ * occurrence of the specified character.
+ * 
+ * If the string does not contain the character, an empty string is returned.
+ * 
+ * @param string the string where to locate the character
+ * @param chr    the character to locate
+ * @return       a substring starting at the last location of <code>chr</code>
+ * 
+ * @see scstrsubs()
+ */
+scstr_t scstrrchr(scstr_t string, int chr);
+
+/**
  * Returns a substring starting at the location of the first occurrence of the
  * specified string.
  * 
@@ -228,7 +519,46 @@
  *               <code>match</code>, or an empty string, if the sequence is not
  *               present in <code>string</code>
  */
-sstr_t sstrstr(sstr_t string, sstr_t match);
+sstr_t scstrsstr(sstr_t string, scstr_t match);
+
+/**
+ * Alias for scstrsstr() which automatically converts the match string.
+ * 
+ * @param string the string to be scanned
+ * @param match  string containing the sequence of characters to match
+ * @return       a substring starting at the first occurrence of
+ *               <code>match</code>, or an empty string, if the sequence is not
+ *               present in <code>string</code>
+ */
+#define sstrstr(string, match) scstrsstr(string, SCSTR(match))
+
+/**
+ * Returns an immutable substring starting at the location of the
+ * first occurrence of the specified immutable string.
+ * 
+ * If the string does not contain the other string, an empty string is returned.
+ * 
+ * If <code>match</code> is an empty string, the complete <code>string</code> is
+ * returned.
+ * 
+ * @param string the string to be scanned
+ * @param match  string containing the sequence of characters to match
+ * @return       a substring starting at the first occurrence of
+ *               <code>match</code>, or an empty string, if the sequence is not
+ *               present in <code>string</code>
+ */
+scstr_t scstrscstr(scstr_t string, scstr_t match);
+
+/**
+ * Alias for scstrscstr() which automatically converts the match string.
+ * 
+ * @param string the string to be scanned
+ * @param match  string containing the sequence of characters to match
+ * @return       a substring starting at the first occurrence of
+ *               <code>match</code>, or an empty string, if the sequence is not
+ *               present in <code>string</code>
+ */
+#define sstrscstr(string, match) scstrscstr(string, SCSTR(match))
 
 /**
  * Splits a string into parts by using a delimiter string.
@@ -273,16 +603,31 @@
  * @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
+ * <code>NULL</code> on error
+ * 
+ * @see scstrsplit_a()
+ */
+sstr_t* scstrsplit(scstr_t string, scstr_t delim, ssize_t *count);
+
+/**
+ * Alias for scstrsplit() which automatically converts the arguments.
+ * 
+ * @param string the string to split
+ * @param delim  the delimiter string
+ * @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, ssize_t *count);
+#define sstrsplit(string, delim, count) \
+    scstrsplit(SCSTR(string), SCSTR(delim), count)
 
 /**
- * Performing sstrsplit() using a UcxAllocator.
+ * Performing scstrsplit() using a UcxAllocator.
  * 
- * <i>Read the description of sstrsplit() for details.</i>
+ * <i>Read the description of scstrsplit() for details.</i>
  * 
  * 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()
@@ -297,17 +642,33 @@
  * @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
+ * <code>NULL</code> on error
+ * 
+ * @see scstrsplit()
+ */
+sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t string, scstr_t delim,
+        ssize_t *count);
+
+/**
+ * Alias for scstrsplit_a() which automatically converts the arguments.
+ * 
+ * @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 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,
-        ssize_t *count);
+#define sstrsplit_a(allocator, string, delim, count) \
+    scstrsplit_a(allocator, SCSTR(string), SCSTR(delim), count)
 
 /**
  * Compares two UCX strings with standard <code>memcmp()</code>.
  * 
- * At first it compares the sstr_t.length attribute of the two strings. The
+ * At first it compares the scstr_t.length attribute of the two strings. The
  * <code>memcmp()</code> function is called, if and only if the lengths match.
  * 
  * @param s1 the first string
@@ -316,23 +677,44 @@
  * length of s1 is greater than the length of s2 or the result of
  * <code>memcmp()</code> otherwise (i.e. 0 if the strings match)
  */
-int sstrcmp(sstr_t s1, sstr_t s2);
+int scstrcmp(scstr_t s1, scstr_t s2);
+
+/**
+ * Alias for scstrcmp() which automatically converts its arguments.
+ * 
+ * @param s1 the first string
+ * @param s2 the second string
+ * @return -1, if the length of s1 is less than the length of s2 or 1, if the 
+ * length of s1 is greater than the length of s2 or the result of
+ * <code>memcmp()</code> otherwise (i.e. 0 if the strings match)
+ */
+#define sstrcmp(s1, s2) scstrcmp(SCSTR(s1), SCSTR(s2))
 
 /**
  * Compares two UCX strings ignoring the case.
  * 
- * At first it compares the sstr_t.length attribute of the two strings. If and
+ * At first it compares the scstr_t.length attribute of the two strings. If and
  * only if the lengths match, both strings are compared char by char ignoring
  * the case.
  * 
  * @param s1 the first string
  * @param s2 the second string
  * @return -1, if the length of s1 is less than the length of s2 or 1, if the 
- * length of s1 is greater than the length of s2 or the difference between the
- * first two differing characters otherwise (i.e. 0 if the strings match and
- * no characters differ)
+ * length of s1 is greater than the length of s2 or the result of the platform
+ * specific string comparison function ignoring the case.
  */
-int sstrcasecmp(sstr_t s1, sstr_t s2);
+int scstrcasecmp(scstr_t s1, scstr_t s2);
+
+/**
+ * Alias for scstrcasecmp() which automatically converts the arguments.
+ * 
+ * @param s1 the first string
+ * @param s2 the second string
+ * @return -1, if the length of s1 is less than the length of s2 or 1, if the 
+ * length of s1 is greater than the length of s2 or the result of the platform
+ * specific string comparison function ignoring the case.
+ */
+#define sstrcasecmp(s1, s2) scstrcasecmp(SCSTR(s1), SCSTR(s2))
 
 /**
  * Creates a duplicate of the specified string.
@@ -342,31 +724,51 @@
  * <code>free()</code>.
  * 
  * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
- * terminated.
+ * terminated and mutable, regardless of the argument.
+ * 
+ * @param string the string to duplicate
+ * @return a duplicate of the string
+ * @see scstrdup_a()
+ */
+sstr_t scstrdup(scstr_t string);
+
+/**
+ * Alias for scstrdup() which automatically converts the argument.
  * 
  * @param string the string to duplicate
  * @return a duplicate of the string
  * @see sstrdup_a()
  */
-sstr_t sstrdup(sstr_t string);
+#define sstrdup(string) scstrdup(SCSTR(string))
 
 /**
  * Creates a duplicate of the specified string using a UcxAllocator.
  * 
  * The new sstr_t will contain a copy allocated by the allocators
- * ucx_allocator_malloc function. So it is implementation depended, whether the
+ * UcxAllocator.malloc() function. So it is implementation depended, whether the
  * returned sstr_t.ptr pointer must be passed to the allocators
- * ucx_allocator_free function manually.
+ * UcxAllocator.free() function manually.
  * 
  * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
- * terminated.
+ * terminated and mutable, regardless of the argument.
  * 
  * @param allocator a valid instance of a UcxAllocator
  * @param string the string to duplicate
  * @return a duplicate of the string
- * @see sstrdup()
+ * @see scstrdup()
  */
-sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string);
+sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t string);
+
+/**
+ * Alias for scstrdup_a() which automatically converts the argument.
+ * 
+ * @param allocator a valid instance of a UcxAllocator
+ * @param string the string to duplicate
+ * @return a duplicate of the string
+ * @see scstrdup()
+ */
+#define sstrdup_a(allocator, string) scstrdup_a(allocator, SCSTR(string))
+
 
 /**
  * Omits leading and trailing spaces.
@@ -388,12 +790,40 @@
 sstr_t sstrtrim(sstr_t string);
 
 /**
+ * Omits leading and trailing spaces.
+ * 
+ * This function returns a new scstr_t containing a trimmed version of the
+ * specified string.
+ * 
+ * <b>Note:</b> the new scstr_t references the same memory, thus you
+ * <b>MUST NOT</b> pass the scstr_t.ptr of the return value to
+ * <code>free()</code>. It is also highly recommended to avoid assignments like
+ * <code>mystr = scstrtrim(mystr);</code> as you lose the reference to the
+ * source string. Assignments of this type are only permitted, if the
+ * scstr_t.ptr of the source string does not need to be freed or if another
+ * reference to the source string exists.
+ * 
+ * @param string the string that shall be trimmed
+ * @return a new scstr_t containing the trimmed string
+ */
+scstr_t scstrtrim(scstr_t string);
+
+/**
  * Checks, if a string has a specific prefix.
  * @param string the string to check
  * @param prefix the prefix the string should have
  * @return 1, if and only if the string has the specified prefix, 0 otherwise
  */
-int sstrprefix(sstr_t string, sstr_t prefix);
+int scstrprefix(scstr_t string, scstr_t prefix);
+
+/**
+ * Alias for scstrprefix() which automatically converts the arguments.
+ * 
+ * @param string the string to check
+ * @param prefix the prefix the string should have
+ * @return 1, if and only if the string has the specified prefix, 0 otherwise
+ */
+#define sstrprefix(string, prefix) scstrprefix(SCSTR(string), SCSTR(prefix))
 
 /**
  * Checks, if a string has a specific suffix.
@@ -401,57 +831,101 @@
  * @param suffix the suffix the string should have
  * @return 1, if and only if the string has the specified suffix, 0 otherwise
  */
-int sstrsuffix(sstr_t string, sstr_t suffix);
+int scstrsuffix(scstr_t string, scstr_t suffix);
+
+/**
+ * Alias for scstrsuffix() which automatically converts the arguments.
+ *
+ * @param string the string to check
+ * @param suffix the suffix the string should have
+ * @return 1, if and only if the string has the specified suffix, 0 otherwise
+ */
+#define sstrsuffix(string, suffix) scstrsuffix(SCSTR(string), SCSTR(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.
+ * documentation of scstrdup() for the implications.
  * 
  * @param string the input string
  * @return the resulting lower case string
- * @see sstrdup()
+ * @see scstrdup()
  */
-sstr_t sstrlower(sstr_t string);
+sstr_t scstrlower(scstr_t string);
+
+/**
+ * Alias for scstrlower() which automatically converts the argument.
+ * 
+ * @param string the input string
+ * @return the resulting lower case string
+ */
+#define sstrlower(string) scstrlower(SCSTR(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.
+ * documentation of scstrdup_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()
+ * @see scstrdup_a()
  */
-sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string);
+sstr_t scstrlower_a(UcxAllocator *allocator, scstr_t string);
+
+
+/**
+ * Alias for scstrlower_a() which automatically converts the argument.
+ * 
+ * @param allocator the allocator used for duplicating the string
+ * @param string the input string
+ * @return the resulting lower case string
+ */
+#define sstrlower_a(allocator, string) scstrlower_a(allocator, SCSTR(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.
+ * documentation of scstrdup() for the implications.
  * 
  * @param string the input string
  * @return the resulting upper case string
- * @see sstrdup()
+ * @see scstrdup()
  */
-sstr_t sstrupper(sstr_t string);
+sstr_t scstrupper(scstr_t string);
+
+/**
+ * Alias for scstrupper() which automatically converts the argument.
+ * 
+ * @param string the input string
+ * @return the resulting upper case string
+ */
+#define sstrupper(string) scstrupper(SCSTR(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.
+ * documentation of scstrdup_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()
+ * @see scstrdup_a()
  */
-sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string);
+sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string);
+
+/**
+ * Alias for scstrupper_a() which automatically converts the argument.
+ * 
+ * @param allocator the allocator used for duplicating the string
+ * @param string the input string
+ * @return the resulting upper case string
+ */
+#define sstrupper_a(allocator, string) scstrupper_a(allocator, string)
 
 #ifdef	__cplusplus
 }
--- a/ucx/ucx/test.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/test.h	Mon Feb 04 17:17:48 2019 +0100
@@ -36,8 +36,8 @@
  * **** IN HEADER FILE: ****
  *
  * <pre>
- * UCX_TEST(function_name)
- * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional
+ * UCX_TEST(function_name);
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist); // optional
  * </pre>
  *
  * **** IN SOURCE FILE: ****
--- a/ucx/ucx/ucx.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/ucx.h	Mon Feb 04 17:17:48 2019 +0100
@@ -37,7 +37,7 @@
 #define	UCX_H
 
 /** Major UCX version as integer constant. */
-#define UCX_VERSION_MAJOR   1
+#define UCX_VERSION_MAJOR   2
 
 /** Minor UCX version as integer constant. */
 #define UCX_VERSION_MINOR   0
@@ -131,6 +131,62 @@
  */
 typedef size_t(*read_func)(void*, size_t, size_t, void*);
 
+
+
+#if __GNUC__ >= 5 || defined(__clang__)
+#define UCX_MUL_BUILTIN
+
+#if __WORDSIZE == 32
+/**
+ * Alias for <code>__builtin_umul_overflow</code>.
+ * 
+ * Performs a multiplication of size_t values and checks for overflow.
+ * 
+ * @param a first operand
+ * @param b second operand
+ * @param result a pointer to a size_t, where the result should
+ * be stored
+ * @return zero, if no overflow occurred and the result is correct, non-zero
+ * otherwise
+ */
+#define ucx_szmul(a, b, result) __builtin_umul_overflow(a, b, result)
+#else /* __WORDSIZE != 32 */
+/**
+ * Alias for <code>__builtin_umull_overflow</code>.
+ * 
+ * Performs a multiplication of size_t values and checks for overflow.
+ * 
+ * @param a first operand
+ * @param b second operand
+ * @param result a pointer to a size_t, where the result should
+ * be stored
+ * @return zero, if no overflow occurred and the result is correct, non-zero
+ * otherwise
+ */
+#define ucx_szmul(a, b, result) __builtin_umull_overflow(a, b, result)
+#endif /* __WORDSIZE */
+
+#else /* no GNUC or clang bultin */
+
+/**
+ * Performs a multiplication of size_t values and checks for overflow.
+ * 
+ * This is a custom implementation in case there is no compiler builtin
+ * available.
+ * 
+ * @param a first operand
+ * @param b second operand
+ * @param result a pointer to a size_t, where the result should
+ * be stored
+ * @return zero, if no overflow occurred and the result is correct, non-zero
+ * otherwise
+ */
+#define ucx_szmul(a, b, result) ucx_szmul_impl(a, b, result)
+
+int ucx_szmul_impl(size_t a, size_t b, size_t *result);
+
+#endif
+
 #ifdef	__cplusplus
 }
 #endif
--- a/ucx/ucx/utils.h	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/ucx/utils.h	Mon Feb 04 17:17:48 2019 +0100
@@ -38,10 +38,6 @@
 #ifndef UCX_UTILS_H
 #define UCX_UTILS_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "ucx.h"
 #include "string.h"
 #include "allocator.h"
@@ -49,6 +45,10 @@
 #include <string.h>
 #include <stdarg.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  * Default buffer size for ucx_stream_copy() and ucx_stream_ncopy().
  */
@@ -144,7 +144,7 @@
  * @param data omitted
  * @return the result of strcmp(s1, s2)
  */
-int ucx_strcmp(const void *s1, const void *s2, void *data);
+int ucx_cmp_str(const void *s1, const void *s2, void *data);
 
 /**
  * Wraps the strncmp function.
@@ -153,7 +153,16 @@
  * @param n a pointer to the size_t containing the third strncmp parameter
  * @return the result of strncmp(s1, s2, *n)
  */
-int ucx_strncmp(const void *s1, const void *s2, void *n);
+int ucx_cmp_strn(const void *s1, const void *s2, void *n);
+
+/**
+ * Wraps the sstrcmp function.
+ * @param s1 sstr one
+ * @param s2 sstr two
+ * @param data ignored
+ * @return the result of sstrcmp(s1, s2)
+ */
+int ucx_cmp_sstr(const void *s1, const void *s2, void *data);
 
 /**
  * Compares two integers of type int.
@@ -163,7 +172,36 @@
  * @return -1, if *i1 is less than *i2, 0 if both are equal,
  * 1 if *i1 is greater than *i2
  */
-int ucx_intcmp(const void *i1, const void *i2, void *data);
+int ucx_cmp_int(const void *i1, const void *i2, void *data);
+
+/**
+ * Compares two integers of type long int.
+ * @param i1 pointer to long integer one
+ * @param i2 pointer to long integer two
+ * @param data omitted
+ * @return -1, if *i1 is less than *i2, 0 if both are equal,
+ * 1 if *i1 is greater than *i2
+ */
+int ucx_cmp_longint(const void *i1, const void *i2, void *data);
+
+
+/**
+ * Distance function for integers of type int.
+ * @param i1 pointer to integer one
+ * @param i2 pointer to integer two
+ * @param data omitted
+ * @return i1 minus i2
+ */
+intmax_t ucx_dist_int(const void *i1, const void *i2, void *data);
+
+/**
+ * Distance function for integers of type long int.
+ * @param i1 pointer to long integer one
+ * @param i2 pointer to long integer two
+ * @param data omitted
+ * @return i1 minus i2
+ */
+intmax_t ucx_dist_longint(const void *i1, const void *i2, void *data);
 
 /**
  * Compares two real numbers of type float.
@@ -174,7 +212,7 @@
  * 1 if *f1 is greater than *f2
  */
 
-int ucx_floatcmp(const void *f1, const void *f2, void *data);
+int ucx_cmp_float(const void *f1, const void *f2, void *data);
 
 /**
  * Compares two real numbers of type double.
@@ -184,7 +222,7 @@
  * @return -1, if *d1 is less than *d2, 0 if both are equal,
  * 1 if *d1 is greater than *d2
  */
-int ucx_doublecmp(const void *d1, const void *d2, void *data);
+int ucx_cmp_double(const void *d1, const void *d2, void *data);
 
 /**
  * Compares two pointers.
@@ -194,7 +232,7 @@
  * @return -1 if ptr1 is less than ptr2, 0 if both are equal,
  * 1 if ptr1 is greater than ptr2
  */
-int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data);
+int ucx_cmp_ptr(const void *ptr1, const void *ptr2, void *data);
 
 /**
  * Compares two memory areas.
@@ -203,7 +241,7 @@
  * @param n a pointer to the size_t containing the third parameter for memcmp
  * @return the result of memcmp(ptr1, ptr2, *n)
  */
-int ucx_memcmp(const void *ptr1, const void *ptr2, void *n);
+int ucx_cmp_mem(const void *ptr1, const void *ptr2, void *n);
 
 /**
  * A <code>printf()</code> like function which writes the output to a stream by
--- a/ucx/utils.c	Mon Feb 04 14:11:57 2019 +0100
+++ b/ucx/utils.c	Mon Feb 04 17:17:48 2019 +0100
@@ -88,15 +88,21 @@
 
 /* COMPARE FUNCTIONS */
 
-int ucx_strcmp(const void *s1, const void *s2, void *data) {
+int ucx_cmp_str(const void *s1, const void *s2, void *data) {
     return strcmp((const char*)s1, (const char*)s2);
 }
 
-int ucx_strncmp(const void *s1, const void *s2, void *n) {
+int ucx_cmp_strn(const void *s1, const void *s2, void *n) {
     return strncmp((const char*)s1, (const char*)s2, *((size_t*) n));
 }
 
-int ucx_intcmp(const void *i1, const void *i2, void *data) {
+int ucx_cmp_sstr(const void *s1, const void *s2, void *data) {
+    sstr_t a = *(const sstr_t*) s1;
+    sstr_t b = *(const sstr_t*) s2;
+    return sstrcmp(a, b);
+}
+
+int ucx_cmp_int(const void *i1, const void *i2, void *data) {
    int a = *((const int*) i1);
    int b = *((const int*) i2);
    if (a == b) {
@@ -106,7 +112,29 @@
    }
 }
 
-int ucx_floatcmp(const void *f1, const void *f2, void *epsilon) {
+int ucx_cmp_longint(const void *i1, const void *i2, void *data) {
+   int a = *((const long int*) i1);
+   int b = *((const long int*) i2);
+   if (a == b) {
+       return 0;
+   } else {
+       return a < b ? -1 : 1;
+   }
+}
+
+intmax_t ucx_dist_int(const void *i1, const void *i2, void *data) {
+   intmax_t a = *((const int*) i1);
+   intmax_t b = *((const int*) i2);
+   return a - b;
+}
+
+intmax_t ucx_dist_longint(const void *i1, const void *i2, void *data) {
+   intmax_t a = *((const long int*) i1);
+   intmax_t b = *((const long int*) i2);
+   return a - b;
+}
+
+int ucx_cmp_float(const void *f1, const void *f2, void *epsilon) {
    float a = *((const float*) f1);
    float b = *((const float*) f2);
    float e = !epsilon ? 1e-6f : *((float*)epsilon);
@@ -117,7 +145,7 @@
    }
 }
 
-int ucx_doublecmp(const void *d1, const void *d2, void *epsilon) {
+int ucx_cmp_double(const void *d1, const void *d2, void *epsilon) {
    double a = *((const double*) d1);
    double b = *((const double*) d2);
    double e = !epsilon ? 1e-14 : *((double*)epsilon);
@@ -128,7 +156,7 @@
    }
 }
 
-int ucx_ptrcmp(const void *ptr1, const void *ptr2, void *data) {
+int ucx_cmp_ptr(const void *ptr1, const void *ptr2, void *data) {
     const intptr_t p1 = (const intptr_t) ptr1;
     const intptr_t p2 = (const intptr_t) ptr2;
     if (p1 == p2) {
@@ -138,7 +166,7 @@
     }
 }
 
-int ucx_memcmp(const void *ptr1, const void *ptr2, void *n) {
+int ucx_cmp_mem(const void *ptr1, const void *ptr2, void *n) {
     return memcmp(ptr1, ptr2, *((size_t*)n));
 }
 

mercurial