new webdav api + repository and key configuration + aes encryption

Mon, 12 Aug 2013 14:40:19 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 12 Aug 2013 14:40:19 +0200
changeset 5
88625853ae74
parent 4
ae5a98f0545c
child 6
9c64d2a3d101

new webdav api + repository and key configuration + aes encryption

Makefile file | annotate | diff | comparison | revisions
dav/Makefile file | annotate | diff | comparison | revisions
dav/config.c file | annotate | diff | comparison | revisions
dav/config.h file | annotate | diff | comparison | revisions
dav/crypto.c file | annotate | diff | comparison | revisions
dav/crypto.h file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
dav/main.h file | annotate | diff | comparison | revisions
dav/methods.c file | annotate | diff | comparison | revisions
dav/methods.h file | annotate | diff | comparison | revisions
dav/propfind.c file | annotate | diff | comparison | revisions
dav/propfind.h file | annotate | diff | comparison | revisions
dav/utils.c file | annotate | diff | comparison | revisions
dav/utils.h file | annotate | diff | comparison | revisions
dav/webdav.c file | annotate | diff | comparison | revisions
dav/webdav.h file | annotate | diff | comparison | revisions
suncc.mk file | annotate | diff | comparison | revisions
ucx/Makefile file | annotate | diff | comparison | revisions
ucx/allocator.c file | annotate | diff | comparison | revisions
ucx/allocator.h file | annotate | diff | comparison | revisions
ucx/buffer.c file | annotate | diff | comparison | revisions
ucx/buffer.h file | annotate | diff | comparison | revisions
ucx/dlist.c file | annotate | diff | comparison | revisions
ucx/dlist.h file | annotate | diff | comparison | revisions
ucx/list.c file | annotate | diff | comparison | revisions
ucx/list.h file | annotate | diff | comparison | revisions
ucx/logging.c file | annotate | diff | comparison | revisions
ucx/logging.h file | annotate | diff | comparison | revisions
ucx/map.c file | annotate | diff | comparison | revisions
ucx/map.h file | annotate | diff | comparison | revisions
ucx/mempool.c file | annotate | diff | comparison | revisions
ucx/mempool.h file | annotate | diff | comparison | revisions
ucx/properties.c file | annotate | diff | comparison | revisions
ucx/properties.h file | annotate | diff | comparison | revisions
ucx/string.c file | annotate | diff | comparison | revisions
ucx/string.h file | annotate | diff | comparison | revisions
ucx/test.c file | annotate | diff | comparison | revisions
ucx/test.h file | annotate | diff | comparison | revisions
ucx/ucx.c file | annotate | diff | comparison | revisions
ucx/ucx.h file | annotate | diff | comparison | revisions
ucx/utils.c file | annotate | diff | comparison | revisions
ucx/utils.h file | annotate | diff | comparison | revisions
--- a/Makefile	Sat Dec 01 20:34:55 2012 +0100
+++ b/Makefile	Mon Aug 12 14:40:19 2013 +0200
@@ -35,16 +35,14 @@
 #   osx
 #
 
-#ifndef CONF
-	CONF=gcc
-#endif
+CONF=gcc
 
 include $(CONF).mk
 
-all: build ucx dav
+all: build/tool ucx dav
 
-build:
-	mkdir build
+build/tool:
+	mkdir -p build/tool
 
 ucx: FORCE build
 	cd ucx; $(MAKE) CONF=$(CONF) all
@@ -56,7 +54,7 @@
 	./build/dav$(APP_EXT)
 
 clean: FORCE
-	$(RM) $(RMFLAGS) build/*.${OBJ_EXT}
+	$(RM) $(RMFLAGS) build/*.${OBJ_EXT} build/tool/*.${OBJ_EXT}
 
 FORCE:
 
--- a/dav/Makefile	Sat Dec 01 20:34:55 2012 +0100
+++ b/dav/Makefile	Mon Aug 12 14:40:19 2013 +0200
@@ -28,15 +28,18 @@
 
 include ../$(CONF).mk
 
-CFLAGS += `xml2-config --cflags`
-LDFLAGS += `curl-config --libs` `xml2-config --libs`
+CFLAGS += `curl-config --cflags` `pkg-config --cflags openssl libxml-2.0`
+LDFLAGS += `curl-config --libs` `pkg-config --libs openssl libxml-2.0` 
 
 SRC  = main.c
-SRC += propfind.c
 SRC += utils.c
+SRC += webdav.c
+SRC += methods.c
+SRC += config.c
+SRC += crypto.c
 
 
-OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT))
+OBJ = $(SRC:%.c=../build/tool/%.$(OBJ_EXT))
 
 all: ../build/dav
 
@@ -44,8 +47,6 @@
 	$(LD) -o ../build/dav$(APP_EXT) $(OBJ) \
 		../build/libucx.$(LIB_EXT) $(LDFLAGS)
 
-../build/%.$(OBJ_EXT): %.c ../build
+../build/tool/%.$(OBJ_EXT): %.c 
 	$(CC) $(CFLAGS) -I../ -o $@ $<
 
-../build:
-	mkdir -p build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/config.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,197 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucx/map.h>
+#include <libxml/tree.h>
+
+#include "config.h"
+#include "utils.h"
+
+#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
+
+static UcxMap *repos;
+static UcxMap *keys;
+
+void load_config() {
+    repos = ucx_map_new(16);
+    keys = ucx_map_new(16);
+    
+    char *file = util_concat_path(getenv("HOME"), ".dav/config.xml");
+    xmlDoc *doc = xmlReadFile(file, NULL, 0);
+    free(file);
+    
+    xmlNode *xml_root = xmlDocGetRootElement(doc);
+    xmlNode *node = xml_root->children;
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            if(xstreq(node->name, "repository")) {
+                load_repository(node);
+            } else if(xstreq(node->name, "key")) {
+                load_key(node);
+            }
+        }
+        node = node->next;
+    }
+    
+    // TODO: free doc
+}
+
+void load_repository(xmlNode *reponode) {
+    xmlNode *node = reponode->children;
+    Repository *repo = calloc(1, sizeof(Repository));
+    repo->store_key_property = true;
+    repo->decrypt = true;
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            char *value = util_xml_get_text(node);
+            if(!value) {
+                // next
+            } else if(xstreq(node->name, "name")) {
+                repo->name = strdup(value);
+            } else if(xstreq(node->name, "url")) {
+                repo->url = strdup(value);
+            } else if(xstreq(node->name, "user")) {
+                repo->user = strdup(value);
+            } else if(xstreq(node->name, "password")) {
+                // TODO: use base64
+                repo->password = strdup(value);
+            } else if(xstreq(node->name, "default-key")) {
+                repo->default_key = strdup(value);
+            } else if(xstreq(node->name, "encrypt")) {
+                repo->encrypt = util_getboolean(value);
+            } else if(xstreq(node->name, "decrypt")) {
+                repo->decrypt = util_getboolean(value);
+            } else if(xstreq(node->name, "store-key-property")) {
+                repo->store_key_property = util_getboolean(value);
+            }
+        }
+        node = node->next;
+    }
+    
+    if(repo->name) {
+        ucx_map_cstr_put(repos, repo->name, repo);
+    } else {
+        // TODO: free
+    }
+}
+
+void load_key(xmlNode *keynode) {
+    xmlNode *node = keynode->children;
+    Key *key = calloc(1, sizeof(Key));
+    key->type = KEY_AES256;
+    
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            char *value = util_xml_get_text(node);
+            if(!value) {
+                // next
+            } else if(xstreq(node->name, "name")) {
+                key->name = strdup(value);
+            } else if(xstreq(node->name, "file")) {
+                // load key file
+                sstr_t key_data = load_key_file(value);
+                if(key_data.length > 0) {
+                    key->data = key_data.ptr;
+                    key->length = key_data.length;
+                }
+            } else if(xstreq(node->name, "type")) {
+                if(!strcmp(value, "aes128")) {
+                    key->type = KEY_AES128;
+                } else if(!strcmp(value, "aes256")) {
+                    key->type = KEY_AES256;
+                }
+            }
+                
+        }
+        node = node->next;
+    }
+    
+    if(key->name) {
+        if(key->type == KEY_AES128) {
+            if(key->length < 16) {
+                return;
+            }
+            key->length = 16;
+        }
+        if(key->type == KEY_AES256) {
+            if(key->length < 32) {
+                return;
+            }
+            key->length = 32;
+        }
+        ucx_map_cstr_put(keys, key->name, key);
+    } else {
+        // TODO: free
+    }
+}
+
+sstr_t load_key_file(char *filename) {
+    sstr_t k;
+    k.ptr = NULL;
+    k.length = 0;
+    
+    FILE *file = NULL;
+    if(filename[0] == '/') {
+        file = fopen(filename, "r");
+    } else {
+        char *path = util_concat_path(getenv("HOME"), ".dav/");
+        char *p2 = util_concat_path(path, filename);
+        file = fopen(p2, "r");
+        free(path);
+        free(p2);
+    }
+    
+    if(!file) {
+        return k;
+    }
+    
+    char *data = malloc(256);
+    size_t r = fread(data, 1, 256, file);
+    k.ptr = data;
+    k.length = r;
+    
+    fclose(file);
+    return k;
+} 
+
+Repository* get_repository(char *name) {
+    if(!name) {
+        return NULL;
+    }
+    return ucx_map_cstr_get(repos, name);
+}
+
+Key* get_key(char *name) {
+    if(!name) {
+        return NULL;
+    }
+    return ucx_map_cstr_get(keys, name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/config.h	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,80 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CONFIG_H
+#define	CONFIG_H
+
+#include <stdbool.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct Repository Repository;
+typedef struct Key        Key;
+
+enum key_type {
+    KEY_AES128 = 0,
+    KEY_AES256,
+    KEY_PASSWORD
+};
+
+typedef enum key_type KeyType;
+
+struct Repository {
+    char *name;
+    char *url;
+    char *user;
+    char *password;
+    char *default_key;
+    bool encrypt;
+    bool decrypt;
+    bool store_key_property;
+};
+
+struct Key {
+    char    *name;
+    KeyType type;
+    void    *data;
+    size_t  length;
+};
+    
+void load_config();
+void load_repository(xmlNode *reponode);
+void load_key(xmlNode *keynode);
+sstr_t load_key_file(char *filename);
+
+Repository* get_repository(char *name);
+Key* get_key(char *name);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* CONFIG_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/crypto.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,142 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crypto.h"
+
+AESDecrypter* aes_decrypter_new(Key *key, void *stream, dav_write_func write_func) {
+    AESDecrypter *dec = malloc(sizeof(AESDecrypter));
+    dec->stream = stream;
+    dec->write = write_func;
+    
+    EVP_CIPHER_CTX_init(&dec->ctx);
+    if(key->type == KEY_AES128) {
+        EVP_DecryptInit_ex(&dec->ctx, EVP_aes_128_cbc(), NULL, key->data, NULL);
+    } else if(key->type == KEY_AES256) {
+        EVP_DecryptInit_ex(&dec->ctx, EVP_aes_256_cbc(), NULL, key->data, NULL);
+    } else {
+        fprintf(stderr, "unknown key type\n");
+        exit(-1);
+    }
+    return dec;
+}
+
+size_t aes_write(const void *buf, size_t s, size_t n, AESDecrypter *dec) {
+    int len = s*n;
+    int outlen = len + AES_BLOCK_SIZE;
+    unsigned char *out = malloc(outlen);
+    EVP_DecryptUpdate(&dec->ctx, out, &len, buf, len);
+    dec->write(out, 1, len, dec->stream);
+    free(out);
+    return (s*n) / s;
+}
+
+void aes_decrypter_close(AESDecrypter *dec) {
+    void *out = malloc(128);
+    int len = 0;
+    EVP_DecryptFinal_ex(&dec->ctx, out, &len);
+    dec->write(out, 1, len, dec->stream);
+    free(out);
+    EVP_CIPHER_CTX_cleanup(&dec->ctx);
+    free(dec);
+}
+
+
+AESEncrypter* aes_encrypter_new(Key *key, void *stream, dav_read_func read_func) {
+    AESEncrypter *enc = malloc(sizeof(AESEncrypter));
+    enc->stream = stream;
+    enc->read = read_func;
+    enc->tmp = NULL;
+    enc->tmplen = 0;
+    enc->tmpoff = 0;
+    enc->end = 0;
+    
+    EVP_CIPHER_CTX_init(&enc->ctx);
+    if(key->type == KEY_AES128) {
+        EVP_EncryptInit_ex(&enc->ctx, EVP_aes_128_cbc(), NULL, key->data, NULL);
+    } else if(key->type == KEY_AES256) {
+        EVP_EncryptInit_ex(&enc->ctx, EVP_aes_256_cbc(), NULL, key->data, NULL);
+    } else {
+        fprintf(stderr, "unknown key type\n");
+        exit(-1);
+    }
+    return enc;
+}
+
+size_t aes_read(void *buf, size_t s, size_t n, AESEncrypter *enc) {
+    size_t len = s*n;
+    if(enc->tmp) {
+        size_t tmp_diff = enc->tmplen - enc->tmpoff;
+        size_t cp_len = tmp_diff > len ? len : tmp_diff;
+        memcpy(buf, enc->tmp + enc->tmpoff, cp_len);
+        enc->tmpoff += cp_len;
+        if(enc->tmpoff >= enc->tmplen) {
+            free(enc->tmp);
+            enc->tmp = NULL;
+            enc->tmplen = 0;
+            enc->tmpoff = 0;
+        }
+        return cp_len / s;
+    }
+    
+    if(enc->end) {
+        return 0;
+    }
+    
+    void *in = malloc(len);
+    size_t in_len = enc->read(in, 1, len, enc->stream);
+    
+    void *out = NULL;
+    int outlen = 0;
+    if(in_len != 0) {
+        outlen = len + AES_BLOCK_SIZE;
+        out = malloc(outlen);
+        EVP_EncryptUpdate(&enc->ctx, out, &outlen, in, in_len);
+        //out = (char*)aes_encrypt(enc->ctx, (unsigned char*)in, (int*)&in_len);
+    } else {
+        out = malloc(AES_BLOCK_SIZE);
+        EVP_EncryptFinal_ex(&enc->ctx, out, &outlen);
+        enc->end = 1;
+    }
+    enc->tmp = out;
+    enc->tmplen = outlen;
+    enc->tmpoff = 0;
+    
+    return aes_read(buf, s, n, enc);
+}
+
+void aes_encrypter_close(AESEncrypter *enc) {
+    if(enc->tmp) {
+        free(enc->tmp);
+    }
+    EVP_CIPHER_CTX_cleanup(&enc->ctx);
+    free(enc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/crypto.h	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DAV_CRYPTO_H
+#define	DAV_CRYPTO_H
+
+#include "webdav.h"
+#include "config.h"
+#include <openssl/evp.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    EVP_CIPHER_CTX ctx;
+    void           *stream;
+    dav_write_func write;
+} AESDecrypter;
+
+typedef struct {
+    EVP_CIPHER_CTX ctx;
+    void           *stream;
+    dav_read_func  read;
+    char           *tmp;
+    size_t         tmplen;
+    size_t         tmpoff;
+    int            end;
+} AESEncrypter;
+
+AESDecrypter* aes_decrypter_new(Key *key, void *stream, dav_write_func write_func);
+size_t aes_write(const void *buf, size_t s, size_t n, AESDecrypter *dec);
+void aes_decrypter_close(AESDecrypter *dec);
+void aes_decrypter_close2(EVP_CIPHER_CTX *ctx);
+
+AESEncrypter* aes_encrypter_new(Key *key, void *stream, dav_read_func read_func);
+size_t aes_read(void *buf, size_t s, size_t n, AESEncrypter *enc);
+void aes_encrypter_close(AESEncrypter *enc);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* DAV_CRYPTO_H */
+
--- a/dav/main.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/dav/main.c	Mon Aug 12 14:40:19 2013 +0200
@@ -29,13 +29,17 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <unistd.h>
 #include <libxml/xmlerror.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <ucx/string.h>
 
-#include "propfind.h"
+#include "webdav.h"
 #include "utils.h"
+#include "config.h"
+#include "crypto.h"
 #include "main.h"
 
 void xmlerrorfnc(void * ctx, const char * msg, ... ) {
@@ -43,8 +47,9 @@
 }
 
 int main(int argc, char **argv) {
-    xmlGenericErrorFunc fnc = xmlerrorfnc;
+   xmlGenericErrorFunc fnc = xmlerrorfnc;
     initGenericErrorDefaultFunc(&fnc);
+    load_config();
     
     if(argc < 2) {
         print_usage();
@@ -67,94 +72,71 @@
     
 }
 
-void get_file(CURL *curl, char *url, char *path) {
-    curl_easy_setopt(curl, CURLOPT_URL, url);
-    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
-    
-    FILE *out = fopen(path, "w");
+void url_get_parts(char *url, char **root, char **path) {
+    size_t ulen = strlen(url);
+    *root = NULL;
+    *path = NULL;
     
-    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
-    curl_easy_setopt(curl, CURLOPT_WRITEDATA, out);
-    
-    CURLcode res = curl_easy_perform(curl);
+    int s;
+    if(ulen > 7 && !strncmp(url, "http://", 7)) {
+        s = 7;
+    } else if(ulen > 8 && !strncmp(url, "https://", 8)) {
+        s = 8;
+    } else {
+        s = 1;
+    }
     
-    fclose(out);
-    // handle some errors (http://curl.haxx.se/libcurl/c/libcurl-errors.html)
-    switch(res) {
-        case CURLE_OK: {
+    for(int i=s;i<ulen;i++) {
+        char c = url[i];
+        if(c == '/') {
+            sstr_t r = sstrn(url, i);
+            sstr_t p = sstrsubs(sstr(url), i);
+            if(p.length == 0) {
+                p = sstrn("/", 1);
+            }
+            *root = sstrdup(r).ptr;
+            *path = sstrdup(p).ptr;
             return;
         }
-        case CURLE_REMOTE_ACCESS_DENIED: {
-            
-            break;
-        }
-        case CURLE_SSL_CONNECT_ERROR: {
-            
-            break;
-        }
-        case CURLE_LOGIN_DENIED: {
-            
-            break;
-        }
-        case CURLE_REMOTE_FILE_NOT_FOUND: {
-            
-            break;
-        }
-        default: {
-            
-            break;
-        }
     }
     
-    unlink(path);
+    *root = strdup(url);
+    *path = strdup("/");
 }
 
-void put_file(CURL *curl, char *url, char *path) {
-    curl_easy_setopt(curl, CURLOPT_URL, url);
-    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
-    
-    curl_easy_setopt(curl, CURLOPT_PUT, 1L);
-    
-    struct stat s;
-    if(stat(path, &s) != 0) {
-        perror("stat");
-        fprintf(stderr, "file: %s\n", path);
-        return;
-    }
-    
-    FILE *in = fopen(path, "r");
-    
-    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
-    curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread);
-    curl_easy_setopt(curl, CURLOPT_READDATA, in);
-    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)s.st_size);
-    
-    CURLcode res = curl_easy_perform(curl);
-    fclose(in);
-    
-    if(res != CURLE_OK) {
-        fprintf(stderr, "put_file: %s\n", curl_easy_strerror(res));
-    }
-}
 
 int cmd_list(int argc, char **argv) {
     if(argc == 0) {
         return -1;
     }
     
-    char *url = argv[0]; // TODO: use arg as url or alias
     
-    CURL *curl = curl_easy_init();
-    curl_easy_setopt(curl, CURLOPT_URL, url);
-    Propfind *propfind = dav_propfind(curl);
+    DavContext *ctx = dav_context_new();
+    DavSession *sn = NULL;
+    char *url = argv[0];
+    char *root = NULL;
+    char *path = NULL;
+    url_get_parts(url, &root, &path);
     
-    UCX_FOREACH(UcxDlist*, propfind->children, ch) {
-        DavResource *resource = ch->data;
-        printf("%s\n", resource->name);
+    Repository *repo = get_repository(root);
+    if(repo) {
+        sn = dav_session_new_auth(ctx, repo->url, repo->user, repo->password);
+    } else {
+        sn = dav_session_new(ctx, root);
     }
     
-    // TODO: free propfind stuff
-    curl_easy_cleanup(curl);
+    //printf("baseurl: %s\n", sn->base_url);
+    
+    DavResource *ls = dav_get(sn, path, NULL);
+    if(!ls) {
+        fprintf(stderr, "error\n");
+        return -1;
+    }
+    DavResource *child = ls->children;
+    while(child) {
+        printf("%s\n", child->name);
+        child = child->next;
+    }
     
     return 0;
 }
@@ -164,51 +146,107 @@
         return -1;
     }
     
-    char *url = argv[0]; // TODO: use arg as url or alias
-    
-    CURL *curl = curl_easy_init();
-    curl_easy_setopt(curl, CURLOPT_URL, url);
-    Propfind *propfind = dav_propfind(curl);
+    DavContext *ctx = dav_context_new();
+    dav_add_namespace(ctx, "U", "http://www.uap-core.de/");
+    DavSession *sn = NULL;
+    char *url = argv[0];
+    char *root = NULL;
+    char *path = NULL;
+    url_get_parts(url, &root, &path);
     
-    if(propfind->resource->collection) {
-        UCX_FOREACH(UcxDlist*, propfind->children, chd) {
-            DavResource *resource = chd->data;
-            if(!resource->collection) {
-                char *resurl = util_child_url(propfind->url, resource->href);
-                get_file(curl, resurl, resource->name);
-            }
-        }
+    Repository *repo = get_repository(root);
+    if(repo) {
+        sn = dav_session_new_auth(ctx, repo->url, repo->user, repo->password);
     } else {
-        get_file(curl, propfind->url, propfind->resource->name);
+        sn = dav_session_new(ctx, root);
     }
     
-    // TODO: free propfind stuff
-    curl_easy_cleanup(curl);
+    DavResource *res = dav_get(sn, path, "U:crypto-key");
+    if(!res) {
+        fprintf(stderr, "error\n");
+        return -1;
+    }
+    FILE *out = fopen(res->name, "w");
+    if(!out) {
+        fprintf(stderr, "cannot open output file\n");
+        return -1;
+    }
+    
+    AESDecrypter *dec = NULL;
+    char *keyprop = dav_get_property_ns(res, "http://www.uap-core.de/", "crypto-key");
+    if(repo) {
+        Key *key = get_key(keyprop);
+        if(repo->encrypt && key) {
+            dec = aes_decrypter_new(key, out, (dav_write_func)fwrite);
+        }
+    }
+    
+    int ret;
+    if(dec && keyprop) {
+        ret = dav_get_content(res, dec, (dav_write_func)aes_write);
+    } else {
+        ret = dav_get_content(res, out, (dav_write_func)fwrite);
+    }
+    if(dec) {
+        aes_decrypter_close(dec);
+    }
+    fclose(out);
+    if(ret) {
+        unlink(res->name);
+    }
     
     return 0;
 }
 
 int cmd_put(int argc, char **argv) {
-    if(argc == 0) {
+    if(argc < 2) {
         return -1;
     }
     
-    char *url = argv[0]; // TODO: use arg as url or alias
-    char *path;
-    if(argc > 0) {
-        path = argv[1];
+    DavContext *ctx = dav_context_new();
+    DavSession *sn = NULL;
+    char *url = argv[0];
+    char *file = argv[1];
+    char *root = NULL;
+    char *path = NULL;
+    url_get_parts(url, &root, &path);
+    
+    Repository *repo = get_repository(root);
+    if(repo) {
+        sn = dav_session_new_auth(ctx, repo->url, repo->user, repo->password);
     } else {
-        fprintf(stderr, "put: missing file argument\n");
-        return -1;
+        sn = dav_session_new(ctx, root);
     }
     
-    char *uploadurl = util_upload_url(url, path);
-    
-    CURL *curl = curl_easy_init();
+    DavResource *res = dav_resource_new(sn, path);
+    if(!res) {
+        fprintf(stderr, "error\n");
+        return -1;
+    }
+    FILE *in = fopen(file, "r");
+    if(!in) {
+        fprintf(stderr, "cannot open input file\n");
+        return -1;
+    }
+    AESEncrypter *enc = NULL;
+    if(repo) {
+        Key *key = get_key(repo->default_key);
+        if(repo->encrypt && key) {
+            enc = aes_encrypter_new(key, in, (dav_read_func)fread);
+        }
+    }
+    if(enc) {
+        dav_set_content(res, enc, (dav_read_func)aes_read);
+        dav_set_property_ns(res, "http://www.uap-core.de/", "crypto-key", repo->default_key);
+    } else {
+        dav_set_content(res, in, (dav_read_func)fread);
+    }
     
-    // TODO: check possible name conflicts
-    
-    put_file(curl, uploadurl, path);
-    
-    curl_easy_cleanup(curl);
+    if(dav_store(res)) {
+        fprintf(stderr, "cannot upload file\n");
+        fclose(in);
+        return -1;
+    }
+    fclose(in);
+    return 0;
 }
--- a/dav/main.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/dav/main.h	Mon Aug 12 14:40:19 2013 +0200
@@ -30,7 +30,6 @@
 #define	MAIN_H
 
 #include <curl/curl.h>
-#include "propfind.h"
 
 #ifdef	__cplusplus
 extern "C" {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/methods.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,458 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils.h"
+#include "methods.h"
+
+#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
+
+/* ----------------------------- PROPFIND ----------------------------- */
+
+CURLcode do_propfind_request(
+        CURL *handle,
+        UcxBuffer *request,
+        UcxBuffer *response)
+{
+    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
+    
+    struct curl_slist *headers = NULL;
+    headers = curl_slist_append(headers, "Content-Type: text/xml");
+    headers = curl_slist_append(headers, "Depth: 1");
+    curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+    
+    curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+    
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); 
+    curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read);
+    curl_easy_setopt(handle, CURLOPT_READDATA, request); 
+    curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size);
+    
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+    
+    ucx_buffer_seek(request, 0, SEEK_SET);
+    return curl_easy_perform(handle);
+}
+
+UcxBuffer* create_allprop_propfind_request() {
+    UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0);
+    sstr_t s;
+    
+    s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("<D:propfind xmlns:D=\"DAV:\">\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("<D:allprop/></D:propfind>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    return buf;
+}
+
+UcxBuffer* create_propfind_request(UcxList *properties) {
+    UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0);
+    sstr_t s;
+    
+    UcxMap *namespaces = ucx_map_new(8);
+    UCX_FOREACH(elm, properties) {
+        DavProperty *p = elm->data;
+        if(strcmp(p->ns->name, "DAV:")) {
+            ucx_map_cstr_put(namespaces, p->ns->prefix, p->ns);
+        }
+    }
+    
+    s = S("<?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:propfind xmlns:D=\"DAV:\"");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    UcxMapIterator mapi = ucx_map_iterator(namespaces);
+    UcxKey key;
+    DavNamespace *ns;
+    UCX_MAP_FOREACH(key, ns, mapi) {
+        s = S(" xmlns:");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = sstr(ns->prefix);
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = S("=\"");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = sstr(ns->name);
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = S("\"");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+    }
+    s = S(">\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    // default properties
+    s = S("<D:prop>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("<D:creationdate />\n<D:getlastmodified />\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("<D:getcontentlength />\n<D:getcontenttype />\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    s = S("<D:resourcetype />\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    // extra properties
+    UCX_FOREACH(elm, properties) {
+        DavProperty *prop = elm->data;
+        s = S("<");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = sstr(prop->ns->prefix);
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = S(":");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = sstr(prop->name);
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = S(" />\n");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+    }
+    
+    // end
+    s = S("</D:prop>\n</D:propfind>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    return buf;
+}
+
+DavResource* parse_propfind_response(DavSession *sn, UcxBuffer *response) {
+    char *url = NULL;
+    curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &url);
+    DavResource *root = resource_new_href(sn, util_url_path(url));
+    
+    xmlDoc *doc = xmlReadMemory(response->space, response->size, url, NULL, 0);
+    if(!doc) {
+        // TODO: free stuff
+        return NULL;
+    }
+    
+    xmlNode *xml_root = xmlDocGetRootElement(doc);
+    xmlNode *node = xml_root->children;
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            if(xstreq(node->name, "response")) {
+                parse_response_tag(root, node);
+            }
+        }
+        
+        node = node->next;
+    }
+    
+    return root;
+}
+
+int parse_response_tag(DavResource *resource, xmlNode *node) {
+    DavResource *res = resource;
+    node = node->children;
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            if(xstreq(node->name, "href")) {
+                xmlNode *href_content = node->children;
+                if(href_content->type != XML_TEXT_NODE) {
+                    // error
+                    return 1;
+                }
+                if(xstreq(resource->href, href_content->content)) {
+                    res = resource;
+                } else {
+                    res = resource_new_href(resource->session, (char*)href_content->content);
+                    resource_add_child(resource, res);
+                }
+            } else if(xstreq(node->name, "propstat")) {
+                xmlNode *n = node->children;
+                xmlNode *prop_node = NULL;
+                int ok = 0;
+                // get the status code
+                while(n) {
+                    if(n->type == XML_ELEMENT_NODE) {
+                        if(xstreq(n->name, "prop")) {
+                            prop_node = n;
+                        } else if(xstreq(n->name, "status")) {
+                            xmlNode *status_node = n->children;
+                            if(status_node->type != XML_TEXT_NODE) {
+                                return 1;
+                            }
+                            sstr_t status_str = sstr((char*)status_node->content);
+                            if(status_str.length < 13) {
+                                return 1;
+                            }
+                            status_str = sstrsubsl(status_str, 9, 3);
+                            if(!sstrcmp(status_str, S("200"))) {
+                                ok = 1;
+                            }
+                        }
+                    }    
+                    n = n->next;
+                }
+                // if status is ok, get all properties
+                if(ok) {
+                    n = prop_node->children;
+                    while(n) {
+                        if(n->type == XML_ELEMENT_NODE) {
+                            if(xstreq(n->name, "resourcetype")) {
+                                xmlNode *rsnode = n->children;
+                                if(rsnode && rsnode->type == XML_ELEMENT_NODE) {
+                                    // TODO: this is a ugly lazy hack
+                                    resource_add_property(res, "DAV:", (char*)n->name, "collection");
+                                    res->iscollection = 1;
+                                }
+                            } else {
+                                xmlNode *content = n->children;
+                                if(content) {
+                                    resource_add_property(
+                                            res,
+                                            (char*)n->ns->href,
+                                            (char*)n->name,
+                                            (char*)content->content);
+                                }
+                            }
+                        }
+                        n = n->next;
+                    }
+                }
+            }
+        }
+        
+        node = node->next;
+    }
+    
+    set_davprops(res);
+    
+    return 0;
+}
+
+void set_davprops(DavResource *res) {
+    char *cl = dav_get_property_ns(res, "DAV:", "getcontentlength");
+    char *ct = dav_get_property_ns(res, "DAV:", "getcontenttype");
+    char *cd = dav_get_property_ns(res, "DAV:", "creationdate");
+    char *lm = dav_get_property_ns(res, "DAV:", "getlastmodified");
+    
+    res->contenttype = ct;
+    if(cl) {
+        char *end = NULL;
+        res->contentlength = strtoull(cl, &end, 0);
+    }
+    res->creationdate = util_parse_creationdate(cd);
+    res->lastmodified = util_parse_lastmodified(lm);
+}
+
+
+/* ----------------------------- PROPPATCH ----------------------------- */
+
+CURLcode do_proppatch_request(
+        CURL *handle,
+        UcxBuffer *request,
+        UcxBuffer *response)
+{
+    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPPATCH");
+    
+    struct curl_slist *headers = NULL;
+    headers = curl_slist_append(headers, "Content-Type: text/xml");
+    curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+    
+    curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+    
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); 
+    curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read);
+    curl_easy_setopt(handle, CURLOPT_READDATA, request); 
+    curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size);
+    
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, response);
+    
+    ucx_buffer_seek(request, 0, SEEK_SET);
+    return curl_easy_perform(handle);
+}
+
+UcxBuffer* create_proppatch_request(DavNodeData *data) {
+    UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0);
+    sstr_t s;
+    
+    UcxMap *namespaces = ucx_map_new(8);
+    char prefix[8];
+    int pfxnum = 0;
+    UCX_FOREACH(elm, data->set) {
+        DavProperty *p = elm->data;
+        if(strcmp(p->ns->name, "DAV:")) {
+            snprintf(prefix, 8, "x%d\0", pfxnum++);
+            ucx_map_cstr_put(namespaces, p->ns->name, prefix);
+        }
+    }
+    UCX_FOREACH(elm, data->remove) {
+        DavProperty *p = elm->data;
+        if(strcmp(p->ns->name, "DAV:")) {
+            snprintf(prefix, 8, "x%d\0", pfxnum++);
+            ucx_map_cstr_put(namespaces, p->ns->name, prefix);
+        }
+    }
+    
+    s = S("<?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:\"");
+    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:");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = sstr(pfxval);
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = S("=\"");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = sstrn(key.data, key.len);
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        s = S("\"");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+    }
+    s = S(">\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    if(data->set) {
+        s = S("<D:set>\n<D:prop>\n");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        UCX_FOREACH(elm, data->set) {
+            DavProperty *property = elm->data;
+            char *prefix = ucx_map_cstr_get(namespaces, property->ns->name);
+            
+            s = S("<");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(prefix);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(":");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(property->name);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(">");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(property->value);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S("</");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(prefix);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(":");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(property->name);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(">\n");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+        }
+        s = S("</D:prop>\n</D:set>\n");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+    }
+    if(data->remove) {
+        s = S("<D:set>\n<D:prop>\n");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+        UCX_FOREACH(elm, data->set) {
+            DavProperty *property = elm->data;
+            char *prefix = ucx_map_cstr_get(namespaces, property->ns->name);
+            
+            s = S("<");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(prefix);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(":");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(property->name);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(">");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(property->value);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S("</");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(prefix);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(":");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = sstr(property->name);
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+            s = S(">\n");
+            ucx_buffer_write(s.ptr, 1, s.length, buf);
+        }
+        s = S("</D:prop>\n</D:set>\n");
+        ucx_buffer_write(s.ptr, 1, s.length, buf);
+    }
+    
+    s = S("</D:propertyupdate>\n");
+    ucx_buffer_write(s.ptr, 1, s.length, buf);
+    
+    return buf;
+}
+
+/* ----------------------------- PUT ----------------------------- */
+
+static size_t dummy_write(void *buf, size_t s, size_t n, void *data) {
+    return s*n;
+}
+
+CURLcode do_put_request(CURL *handle, void *data, dav_read_func read_func, size_t length) {
+    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, NULL);
+    curl_easy_setopt(handle, CURLOPT_PUT, 1L);  
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L);
+    curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+    
+    UcxBuffer *buf = NULL;
+    if(!read_func) {
+        buf = ucx_buffer_new(data, length, 0);
+        buf->size = length;
+        data = buf;
+        read_func = (dav_read_func)ucx_buffer_read;
+        curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length);
+    } else if(length == 0) {
+        struct curl_slist *headers = NULL;
+        headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
+        curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
+    }
+    
+    curl_easy_setopt(handle, CURLOPT_READFUNCTION, read_func);
+    curl_easy_setopt(handle, CURLOPT_READDATA, data);
+    
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
+    
+    CURLcode res = curl_easy_perform(handle);
+    if(buf) {
+        ucx_buffer_free(buf);
+    }
+    return res;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/methods.h	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef METHODS_H
+#define	METHODS_H
+
+#include "webdav.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+CURLcode do_propfind_request(
+        CURL *handle,
+        UcxBuffer *request,
+        UcxBuffer *response);
+
+CURLcode do_proppatch_request(
+        CURL *handle,
+        UcxBuffer *request,
+        UcxBuffer *response);
+
+CURLcode do_put_request(
+        CURL *handle,
+        void *data,
+        dav_read_func read_func,
+        size_t length);
+
+UcxBuffer* create_allprop_propfind_request();
+UcxBuffer* create_propfind_request(UcxList *properties);
+DavResource* parse_propfind_response(DavSession *sn, UcxBuffer *response);
+int parse_response_tag(DavResource *resource, xmlNode *node);
+void set_davprops(DavResource *res);
+
+UcxBuffer* create_proppatch_request(DavNodeData *data);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* METHODS_H */
+
--- a/dav/propfind.c	Sat Dec 01 20:34:55 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "utils.h"
-#include "propfind.h"
-
-Propfind* dav_propfind(CURL *handle) {
-    Propfind *response = malloc(sizeof(Propfind));
-    response->resource = NULL;
-    response->children = NULL;
-    
-    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
-    
-    struct curl_slist *headers = NULL;
-    headers = curl_slist_append(headers, "Content-Type: text/xml");
-    headers = curl_slist_append(headers, "Depth: 1");
-    curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
-    
-    UcxBuffer *rqbuf = create_propfind_request_body();
-    UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
-    //printf("request\n%s\n", body->space);
-    
-    curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
-    
-    curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); 
-    curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read);
-    curl_easy_setopt(handle, CURLOPT_READDATA, rqbuf); 
-    curl_easy_setopt(handle, CURLOPT_INFILESIZE, rqbuf->size);
-    
-    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write);
-    curl_easy_setopt(handle, CURLOPT_WRITEDATA, rpbuf);
-    
-    ucx_buffer_seek(rqbuf, 0, SEEK_SET);
-    CURLcode res = curl_easy_perform(handle);
-    if(res == CURLE_OK) {
-        printf("response\n%s\n", rpbuf->space);
-        
-        char *url = NULL;
-        curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url);
-        response->url = util_url_path(url);
-        
-        parse_propfind(response, rpbuf);
-        
-        response->url = strdup(url);
-    }
-    curl_easy_reset(handle);
-    
-    return response;
-}
-
-UcxBuffer* create_propfind_request_body() {
-    UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0);
-    sstr_t s;
-    
-    s = ST("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    s = ST("<D:propfind xmlns:D=\"DAV:\">\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    s = ST("<D:prop>\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    s = ST("<D:creationdate />\n<D:getlastmodified />\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    s = ST("<D:getcontentlength />\n<D:getcontenttype />\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    s = ST("<D:resourcetype />\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    s = ST("</D:prop>\n</D:propfind>\n");
-    ucx_buffer_write(s.ptr, 1, s.length, buf);
-    
-    return buf;
-}
-
-int parse_propfind(Propfind *propfind, UcxBuffer *response) {
-    xmlTextReaderPtr reader = xmlReaderForMemory(
-            response->space,
-            response->size,
-            propfind->url,
-            NULL,
-            0);
-    
-    int ret = 0;
-    if(reader != NULL) {
-        int r;
-        while((r = xmlTextReaderRead(reader)) == 1) {
-            int nodetype = xmlTextReaderNodeType(reader);
-            if(nodetype == XML_READER_TYPE_ELEMENT) {
-                const xmlChar *name = xmlTextReaderConstLocalName(reader);
-                if(!xmlStrcmp(name, BAD_CAST "response")) {
-                    r = parse_response(reader, propfind);
-                    if(r != 0) {
-                        ret = -1;
-                        break;
-                    }
-                }
-            }
-        }
-        xmlFreeTextReader(reader);
-    }
-    
-    return ret;
-}
-
-int parse_response(xmlTextReaderPtr reader, Propfind *propfind) {
-    DavResource *res = calloc(sizeof(DavResource), 1);
-    if(res == NULL) {
-        return -1;
-    }
-    
-    /*
-     * 0: href
-     * 1: creationdate
-     * 2: getlastmodified
-     * 3: getcontentlength
-     * 4: getcontenttype
-     * 5: resourcetype
-     */
-    int valuetype = -1;
-    
-    int r;
-    while((r = xmlTextReaderRead(reader)) == 1) {
-        int nodetype = xmlTextReaderNodeType(reader);
-        
-        if(nodetype == XML_READER_TYPE_END_ELEMENT) {
-            const xmlChar *name = xmlTextReaderConstLocalName(reader);
-            if(!xmlStrcmp(name, BAD_CAST "response")) {
-                break;
-            }
-        }
-        
-        switch(nodetype) {
-            case XML_READER_TYPE_ELEMENT: {
-                const xmlChar *name = xmlTextReaderConstLocalName(reader);
-                if(!xmlStrcmp(name, BAD_CAST "href")) {
-                    valuetype = 0;
-                } else if(!xmlStrcmp(name, BAD_CAST "creationdate")) {
-                    valuetype = 1;
-                } else if(!xmlStrcmp(name, BAD_CAST "getlastmodified")) {
-                    valuetype = 2;
-                } else if(!xmlStrcmp(name, BAD_CAST "getcontentlength")) {
-                    valuetype = 3;
-                } else if(!xmlStrcmp(name, BAD_CAST "getcontenttype")) {
-                    valuetype = 4;
-                } else if(!xmlStrcmp(name, BAD_CAST "resourcetype")) {
-                    valuetype = 5;
-                } else if(!xmlStrcmp(name, BAD_CAST "collection") 
-                        && valuetype == 5) {
-                    res->collection = 1;
-                } else {
-                    valuetype = -1;
-                }
-                break;
-            }
-            case XML_READER_TYPE_TEXT: {
-                const xmlChar *cvalue = xmlTextReaderConstValue(reader);
-                if(cvalue == NULL) {
-                    break;
-                }
-                char *value = strdup((char*)cvalue);
-                switch(valuetype) {
-                    case 0: {
-                        res->href = value;
-                        res->name = util_resource_name(value);
-                        break;
-                    }
-                    case 1: {
-                        res->creationdate = 0; // TODO
-                        break;
-                    }
-                    case 2: {
-                        res->lastmodified = 0; // TODO
-                        break;
-                    }
-                    case 3: {
-                        res->contentlength = atoi(value);
-                        break;
-                    }
-                    case 4: {
-                        res->contenttype = value;
-                        //break;
-                    }
-                }
-                //break;
-            }
-        }
-    }
-    
-    if(!strcmp(res->href, propfind->url)) {
-        propfind->resource = res;
-    } else {
-        propfind->children = ucx_dlist_append(propfind->children, res);
-    }
-    
-    return 0;
-}
--- a/dav/propfind.h	Sat Dec 01 20:34:55 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2012 Olaf Wintermann. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef PROPFIND_H
-#define	PROPFIND_H
-
-#include <inttypes.h>
-#include <ucx/string.h>
-#include <ucx/dlist.h>
-#include <ucx/buffer.h>
-#include <curl/curl.h>
-
-#include <libxml/xmlreader.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-typedef struct {
-    char        *name;
-    char        *href;
-    uint64_t    contentlength;
-    char        *contenttype;
-    time_t      creationdate;
-    time_t      lastmodified;
-    int         collection;
-} DavResource;
-
-typedef struct {
-    char        *url;
-    DavResource *resource;
-    UcxDlist    *children;
-} Propfind;
-
-Propfind* dav_propfind(CURL *handle);
-
-UcxBuffer* create_propfind_request_body();
-
-int parse_propfind(Propfind *propfind, UcxBuffer *response);
-int parse_response(xmlTextReaderPtr reader, Propfind *propfind);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* PROPFIND_H */
-
--- a/dav/utils.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/dav/utils.c	Mon Aug 12 14:40:19 2013 +0200
@@ -31,24 +31,36 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ucx/string.h>
+#include <libxml/tree.h>
+#include <curl/curl.h>
 
 #include "utils.h"
 
 
-time_t parse_creationdate(char *str) {
+time_t util_parse_creationdate(char *str) {
     // example: 2012-11-29T21:35:35Z
-    
+    if(!str) {
+        return 0;
+    }
     // TODO
-    return 1234;
+    return 0;
 }
 
-time_t parse_lastmodified(char *str) {
+time_t util_parse_lastmodified(char *str) {
     // example: Thu, 29 Nov 2012 21:35:35 GMT
-    
-    // TODO
-    return 1234;
+    if(!str) {
+        return 0;
+    } else {
+        return curl_getdate(str, NULL);
+    }
 }
 
+int util_getboolean(char *v) {
+    if(v[0] == 'T' || v[0] == 't') {
+        return 1;
+    }
+    return 0;
+}
 
 char* util_url_path(char *url) { 
     char *path = NULL;
@@ -92,50 +104,49 @@
     return name;
 }
 
-char* util_child_url(char *base, char *path) {
-    char *basepath = util_url_path(base);
-    int baselen = basepath - base;
-    int pathlen = strlen(path);
-    
-    int len = baselen + pathlen + 1;
-    char *url = malloc(len);
-    url[len - 1] = 0;
-    url[len - 2] = 0;
-    
-    if(url == NULL) {
-        return NULL;
+char* util_concat_path(char *url_base, char *p) {
+    sstr_t base = sstr(url_base);
+    sstr_t path;
+    if(p) {
+        path = sstr(p);
+    } else {
+        path = sstrn("", 0);
     }
     
-    memcpy(url, base, baselen);
-    memcpy(url + baselen, path, pathlen);
-    
-    return url;
-}
-
-char* util_upload_url(char *url, char *filepath) {
-    int urllen = strlen(url);
-    int filepathlen = strlen(filepath);
-    
-    for(int i=filepathlen-1;i>=0;i--) {
-        if(filepath[i] == '/') {
-            filepath = filepath + i + 1;
-            break;
+    int add_separator = 0;
+    if(base.ptr[base.length-1] == '/') {
+        if(path.ptr[0] == '/') {
+            base.length--;
+        }
+    } else {
+        if(path.length == 0 || path.ptr[0] != '/') {
+            add_separator = 1;
         }
     }
     
-    int pathlen = urllen + filepathlen;
-    char *path = malloc(pathlen + 2);
+    sstr_t url;
+    url.length = base.length + path.length + add_separator;
+    url.ptr = malloc(url.length + 1);
+    url.ptr[url.length] = '\0';
     
-    int j = urllen;
-    memcpy(path, url, urllen);
-    if(url[urllen - 1] != '/') {
-        path[j] = '/';
-        j++;
+    if(add_separator) {
+        url = sstrncat(url, 3, base, sstr("/"), path);
+    } else {
+        url = sstrncat(url, 2, base, path);
     }
-    memcpy(path + j, filepath, filepathlen);
-    j += filepathlen;
-    path[j] = 0;
     
-    return path;
+    return url.ptr;
 }
 
+
+char* util_xml_get_text(xmlNode *elm) {
+    xmlNode *node = elm->children;
+    while(node) {
+        if(node->type == XML_TEXT_NODE) {
+            return (char*)node->content;
+        }
+        node = node->next;
+    }
+    return NULL;
+}
+
--- a/dav/utils.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/dav/utils.h	Mon Aug 12 14:40:19 2013 +0200
@@ -30,21 +30,22 @@
 #define	UTILS_H
 
 #include <sys/types.h>
+#include <libxml/tree.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-time_t parse_creationdate(char *str);
-time_t parse_lastmodified(char *str);
+time_t util_parse_creationdate(char *str);
+time_t util_parse_lastmodified(char *str);
 
 char* util_url_path(char *url);
-
 char* util_resource_name(char *url);
+char* util_concat_path(char *url_base, char *path);
 
-char* util_child_url(char *url, char *href);
+int util_getboolean(char *v);
 
-char* util_upload_url(char *url, char *filepath);
+char* util_xml_get_text(xmlNode *elm);
 
 #ifdef	__cplusplus
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/webdav.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,471 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libxml/tree.h>
+
+#include "utils.h"
+#include "webdav.h"
+#include "methods.h"
+#include "ucx/buffer.h"
+
+#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
+
+DavContext* dav_context_new() {
+    DavContext *context = malloc(sizeof(DavContext));
+    if(!context) {
+        return NULL;
+    }
+    context->namespaces = ucx_map_new(16);
+    if(!context->namespaces) {
+        free(context);
+        return NULL;
+    }
+    DavNamespace *davns = malloc(sizeof(DavNamespace));
+    if(!davns) {
+        ucx_map_free(context->namespaces);
+        free(context);
+        return NULL;
+    }
+    davns->prefix = "D";
+    davns->name = "DAV:";
+    if(ucx_map_cstr_put(context->namespaces, "D", davns)) {
+        free(davns);
+        ucx_map_free(context->namespaces);
+        free(context);
+        return NULL;
+    }
+    
+    return context;
+}
+
+int dav_add_namespace(DavContext *context, char *prefix, char *name) {
+    DavNamespace *namespace = malloc(sizeof(DavNamespace));
+    if(!namespace) {
+        return 1;
+    }
+    namespace->prefix = strdup(prefix);
+    namespace->name = strdup(name);
+    return ucx_map_cstr_put(context->namespaces, prefix, namespace);
+}
+
+DavNamespace* dav_get_namespace(DavContext *context, char *prefix) {
+    return ucx_map_cstr_get(context->namespaces, prefix);
+}
+
+DavNamespace* dav_get_namespace_s(DavContext *context, sstr_t prefix) {
+    return ucx_map_sstr_get(context->namespaces, prefix);
+}
+
+DavSession* dav_session_new(DavContext *context, char *base_url) {
+    if(!base_url) {
+        return NULL;
+    }
+    sstr_t url = sstr(base_url);
+    if(url.length == 0) {
+        return NULL;
+    }
+    DavSession *sn = malloc(sizeof(DavSession));
+    if(url.ptr[url.length - 1] == '/') {
+        sn->base_url = strdup(base_url);
+    } else {
+        char *url_str = malloc(url.length + 2);
+        memcpy(url_str, base_url, url.length);
+        url_str[url.length]     = '/';
+        url_str[url.length + 1] = '\0';
+        sn->base_url = url_str;
+    }
+    sn->context = context;
+    sn->handle = curl_easy_init();
+    curl_easy_setopt(sn->handle, CURLOPT_URL, base_url);
+    
+    sn->mp = ucx_mempool_new(1024);
+    sn->allocator = ucx_mempool_allocator(sn->mp);
+    
+    return sn;
+}
+
+DavSession* dav_session_new_auth(DavContext *context, char *base_url, char *user, char *password) {
+    DavSession *sn = dav_session_new(context, base_url);
+    if(!sn) {
+        return NULL;
+    }
+    dav_session_set_auth(sn, user, password);
+    return sn;
+}
+
+void dav_session_set_auth(DavSession *sn, char *user, char *password) {
+    if(user && password) {
+        size_t ulen = strlen(user);
+        size_t plen = strlen(password);
+        size_t upwdlen = ulen + plen + 2;
+        char *upwdbuf = malloc(upwdlen);
+        snprintf(upwdbuf, upwdlen, "%s:%s\0", user, password);
+        curl_easy_setopt(sn->handle, CURLOPT_USERPWD, upwdbuf);
+        free(upwdbuf);
+    }
+}
+
+DavResource* dav_get(DavSession *sn, char *path, char *properties) {
+    char *url = util_concat_path(sn->base_url, path);
+    
+    CURL *handle = sn->handle;
+    curl_easy_setopt(handle, CURLOPT_URL, url);
+    free(url);
+    
+    UcxList *proplist = NULL;
+    if(properties) {
+        proplist = parse_properties_string(sn->context, sstr(properties));
+    }
+    UcxBuffer *rqbuf = create_propfind_request(proplist);
+    UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
+    
+    //fwrite(rqbuf->space, 1, rqbuf->size, stdout);
+    //printf("\n");
+    
+    DavResource *resource = NULL;
+    CURLcode ret = do_propfind_request(handle, rqbuf, rpbuf);
+    int status = 0;
+    curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
+    if(ret == CURLE_OK && status == 207) {
+        //printf("response\n%s\n", rpbuf->space); 
+        resource = parse_propfind_response(sn, rpbuf);
+    }
+    return resource;
+}
+
+UcxList* parse_properties_string(DavContext *context, sstr_t str) {
+    UcxList *proplist = NULL;
+    size_t nprops;
+    sstr_t *props = sstrsplit(str, S(","), &nprops);
+    for(int i=0;i<nprops;i++) {
+        sstr_t s = props[i];
+        sstr_t nsname = sstrchr(s, ':');
+        if(nsname.length > 0) {
+            sstr_t nspre = sstrsubsl(s, 0, nsname.ptr - s.ptr);
+            nsname.ptr++;
+            nsname.length--;
+            
+            DavProperty *dp = malloc(sizeof(DavProperty));
+            sstr_t pre = sstrdup(sstrtrim(nspre));
+            dp->ns = dav_get_namespace(context, pre.ptr);
+            free(pre.ptr);
+            dp->name = sstrdup(nsname).ptr;
+            if(dp->ns && dp->name) {
+                proplist = ucx_list_append(proplist, dp);
+            } else {
+                free(dp->name);
+                free(dp);
+            }
+        }
+        free(s.ptr);
+    }
+    free(props);
+    return proplist;
+}
+
+
+
+
+DavResource* dav_resource_new(DavSession *sn, char *path) {
+    char *url = util_concat_path(sn->base_url, path);
+    char *href = util_url_path(url);
+    DavResource *res = resource_new_href(sn, href);
+    free(url);
+    return res;
+}
+
+DavResource* resource_new_href(DavSession *sn, char *href) {
+    UcxMempool *mp = sn->mp;
+    UcxAllocator *a = sn->allocator;
+    
+    DavResource *res = ucx_mempool_calloc(mp, 1, sizeof(DavResource));
+    res->session = sn;
+    
+    // set name, path and href
+    resource_set_info(res, href);
+    
+    // initialize node data
+    res->data = node_data_new(sn);
+    
+    return res;
+}
+
+void resource_add_property(DavResource *res, char *ns, char *name, char *value) {
+    if(!value) {
+        return;
+    }
+    UcxMempool *mp = res->session->mp;
+    UcxAllocator *a = res->session->allocator;
+    
+    UcxKey key = dav_property_key(ns, name);
+    sstr_t v = sstrdup_a(a, sstr(value));
+    ucx_map_put(res->data->properties, key, v.ptr);
+    free(key.data);
+}
+
+char* resource_get_property(DavResource *res, char *ns, char *name) {
+    UcxKey key = dav_property_key(ns, name);
+    return ucx_map_get(res->data->properties, key);
+}
+
+UcxKey dav_property_key(char *ns, char *name) {
+    sstr_t ns_str = sstr(ns);
+    sstr_t name_str = sstr(name);
+    
+    sstr_t key;
+    key.length = ns_str.length + name_str.length + 1;
+    key.ptr = malloc(key.length + 1);
+    key = sstrncat(key, 3, ns_str, S(" "), name_str);
+    
+    return ucx_key(key.ptr, key.length);
+}
+
+void resource_add_child(DavResource *parent, DavResource *child) {
+    child->next = NULL;
+    if(parent->children) {
+        DavResource *last = parent->children;
+        while(last->next) {
+            last = last->next;
+        }
+        last->next = child;
+        child->prev = last;
+    } else {
+        child->prev = NULL;
+        parent->children = child;
+    }
+}
+
+void resource_set_info(DavResource *res, char *href_str) {
+    char *url_str = NULL;
+    curl_easy_getinfo(res->session->handle, CURLINFO_EFFECTIVE_URL, &url_str);
+    sstr_t name = sstr(util_resource_name(href_str));
+    sstr_t href = sstr(href_str);
+    
+    sstr_t base_href = sstr(util_url_path(res->session->base_url));
+    sstr_t path = sstrsubs(href, base_href.length - 1);
+    
+    UcxAllocator *a = res->session->allocator;
+    res->name = sstrdup_a(a, name).ptr;
+    res->href = sstrdup_a(a, href).ptr;
+    res->path = sstrdup_a(a, path).ptr;
+}
+
+DavNodeData* node_data_new(DavSession *sn) {
+    DavNodeData *data = ucx_mempool_malloc(sn->mp, sizeof(DavNodeData));
+    if(!data) {
+        return NULL;
+    }
+    data->properties = ucx_map_new_a(sn->allocator, 32);
+    data->set = NULL;
+    data->remove = NULL;
+    data->content = NULL;
+    data->read = NULL;
+    data->length = 0;
+    return data;
+}
+
+int dav_load(DavResource *res) {
+    DavSession *sn = res->session;
+    // clean map
+    UcxKey key;
+    void *value;
+    UcxMapIterator i = ucx_map_iterator(res->data->properties);
+    UCX_MAP_FOREACH(key, value, i) {
+        ucx_map_remove(res->data->properties, key);
+    }
+    
+    char *url = util_concat_path(sn->base_url, res->path);
+    
+    CURL *handle = sn->handle;
+    curl_easy_setopt(handle, CURLOPT_URL, url);
+    free(url);
+    
+    UcxBuffer *rqbuf = create_allprop_propfind_request();
+    UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
+    
+    //fwrite(rpbuf->space, 1, rpbuf->size, stdout);
+    //printf("\n");
+    
+    CURLcode ret = do_propfind_request(handle, rqbuf, rpbuf);
+    if(ret == CURLE_OK) {
+        //printf("response\n%s\n", rpbuf->space);
+        
+        xmlDoc *doc = xmlReadMemory(rpbuf->space, rpbuf->size, url, NULL, 0);
+        if(!doc) {
+            return 1;
+        }
+
+        xmlNode *xml_root = xmlDocGetRootElement(doc);
+        xmlNode *node = xml_root->children;
+        while(node) {
+            if(node->type == XML_ELEMENT_NODE) {
+                if(xstreq(node->name, "response")) {
+                    parse_response_tag(res, node);
+                }
+            }
+            node = node->next;
+        }
+    }
+    return 0;
+}
+
+int dav_store(DavResource *res) {
+    DavSession *sn = res->session;
+    
+    char *url = util_concat_path(sn->base_url, res->path);
+    CURL *handle = res->session->handle;
+    curl_easy_setopt(handle, CURLOPT_URL, url);
+    free(url);
+    
+    DavNodeData *data = res->data;
+    
+    // store content
+    if(data->content) {
+        CURLcode ret = do_put_request(handle, data->content, data->read, data->length);
+        int status = 0;
+        curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &status);
+        if(ret == CURLE_OK && (status >= 200 && status < 300)) {
+            res->session->error = 0;
+            // cleanup node data
+            if(!data->read) {
+                ucx_mempool_free(sn->mp, data->content);
+            }
+            data->content = NULL;
+            data->read = NULL;
+            data->length = 0;
+        } else {
+            res->session->error = 1;
+            return 1;
+        }
+    }
+    
+    // store properties
+    if(data->set || data->remove) {
+        UcxBuffer *request = create_proppatch_request(data);
+        UcxBuffer *response = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
+
+        CURLcode ret = do_proppatch_request(handle, request, response);
+        int status = 0;
+        curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
+        if(ret == CURLE_OK && status == 207) {
+            //printf("%s\n", response->space);
+            // TODO: parse response
+            // TODO: cleanup node data correctly
+            data->set = NULL;
+            data->remove = NULL;
+        } else {
+            res->session->error = 1;
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+char* dav_get_property_ns(DavResource *res, char *ns, char *name) {
+    char *property = resource_get_property(res, ns, name);
+    if(property && res->data->remove) {
+        // TODO
+    } else if(!property && res->data->set) {
+        // TODO
+    }
+    return property;
+}
+
+void dav_set_property_ns(DavResource *res, char *ns, char *name, char *value) {
+    UcxAllocator *a = res->session->allocator;
+    
+    DavProperty *property = a->malloc(a->pool, sizeof(DavProperty));
+    property->name = sstrdup_a(a, sstr(name)).ptr;
+    property->value = sstrdup_a(a, sstr(value)).ptr;
+    DavNamespace *namespace = a->malloc(a->pool, sizeof(DavNamespace));
+    namespace->prefix = NULL;
+    namespace->name = sstrdup_a(a, sstr(ns)).ptr;
+    property->ns = namespace;
+    
+    res->data->set = ucx_list_append_a(a, res->data->set, property);
+}
+
+void dav_remove_property_ns(DavResource *res, char *ns, char *name, char *value) {
+    UcxAllocator *a = res->session->allocator;
+    
+    DavProperty *property = a->malloc(a->pool, sizeof(DavProperty));
+    property->name = sstrdup_a(a, sstr(name)).ptr;
+    property->value = NULL;
+    DavNamespace *namespace = a->malloc(a->pool, sizeof(DavNamespace));
+    namespace->prefix = NULL;
+    namespace->name = sstrdup_a(a, sstr(ns)).ptr;
+    property->ns = namespace;
+    
+    res->data->remove = ucx_list_append_a(a, res->data->remove, property);
+}
+
+
+void dav_set_content(DavResource *res, void *stream, dav_read_func read_func) {
+    DavNodeData *data = res->data;
+    data->content = stream;
+    data->read = read_func;
+    data->length = 0;
+}
+
+void dav_set_content_data(DavResource *res, char *content, size_t length) {
+    DavSession *sn = res->session;
+    DavNodeData *data = res->data;
+    data->content = content;
+    data->read = NULL;
+    data->length = length;
+}
+
+int dav_get_content(DavResource *res, void *stream, dav_write_func write_func) { 
+    char *url = util_concat_path(res->session->base_url, res->path);
+    CURL *handle = res->session->handle;
+    curl_easy_setopt(handle, CURLOPT_URL, url);
+    free(url);
+    
+    curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+    curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, NULL);
+    curl_easy_setopt(handle, CURLOPT_PUT, 0L);
+    curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L);
+    
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, stream);
+    
+    CURLcode ret = curl_easy_perform(handle);
+    
+    int status = 0;
+    curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
+    if(ret == CURLE_OK && (status >= 200 && status < 300)) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/webdav.h	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,166 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NODE_H
+#define	NODE_H
+
+#include <inttypes.h>
+#include <ucx/map.h>
+#include <ucx/mempool.h>
+#include <ucx/list.h>
+#include <ucx/buffer.h>
+#include <curl/curl.h>
+#include <libxml/tree.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct DavContext    DavContext;
+typedef struct DavSession    DavSession;
+typedef struct DavResource   DavResource;
+typedef struct DavRequest    DavRequest;
+typedef struct DavNamespace  DavNamespace;
+typedef struct DavNodeData   DavNodeData;
+typedef struct DavProperty   DavProperty;
+
+typedef size_t(*dav_read_func)(void*, size_t, size_t, void*);
+typedef size_t(*dav_write_func)(const void*, size_t, size_t, void*);
+
+struct DavNamespace {
+    char *prefix;
+    char *name;
+};
+
+struct DavResource {
+    DavSession    *session;
+    DavResource   *prev;
+    DavResource   *next;
+    DavResource   *parent;
+    DavResource   *children;
+    char          *name;
+    char          *path;
+    char          *href;
+    uint64_t      contentlength;
+    char          *contenttype;
+    time_t        creationdate;
+    time_t        lastmodified;
+    DavNodeData   *data;
+    int           iscollection;
+};
+
+struct DavSession {
+    DavContext    *context;
+    CURL          *handle;
+    char          *base_url;
+    UcxMempool    *mp;
+    UcxAllocator  *allocator;
+    int           error;
+};
+
+struct DavContext {
+    UcxMap *namespaces;
+};
+
+struct dav_content_data {
+    char   *data;
+    size_t length;
+};
+
+struct dav_content_stream {
+    void      *stream;
+    read_func read;
+};
+
+struct DavNodeData {
+    UcxMap  *properties;
+    UcxList *set;
+    UcxList *remove;
+    
+    /*
+     * char* or stream
+     */
+    void      *content;
+    /*
+     * if NULL, content is a char*
+     */
+    read_func read;
+    /*
+     * content length
+     */
+    size_t    length;
+};
+
+struct DavProperty {
+    DavNamespace *ns;
+    char         *name;
+    char         *value;
+};
+
+DavContext* dav_context_new();
+int dav_add_namespace(DavContext *context, char *prefix, char *ns);
+DavNamespace* dav_get_namespace(DavContext *context, char *prefix);
+
+DavSession* dav_session_new(DavContext *context, char *base_url);
+DavSession* dav_session_new_auth(DavContext *context, char *base_url, char *user, char *password);
+void dav_session_set_auth(DavSession *sn, char *user, char *password);
+
+DavResource* dav_get(DavSession *sn, char *path, char *properties);
+
+UcxList* parse_properties_string(DavContext *context, sstr_t str);
+
+
+DavResource* dav_resource_new(DavSession *sn, char *path);
+DavResource* resource_new_href(DavSession *sn, char *href);
+
+void resource_add_property(DavResource *res, char *ns, char *name, char *value);
+void resource_add_child(DavResource *parent, DavResource *child);
+UcxKey dav_property_key(char *ns, char *name);
+void resource_set_info(DavResource *res, char *href);
+DavNodeData* node_data_new(DavSession *sn);
+
+int dav_load(DavResource *res);
+int dav_store(DavResource *res);
+
+char* dav_get_property_ns(DavResource *res, char *ns, char *name);
+void dav_set_property_ns(DavResource *res, char *ns, char *name, char *value);
+void dav_remove_property_ns(DavResource *res, char *ns, char *name, char *value);
+
+
+
+void dav_set_content(DavResource *res, void *stream, dav_read_func read_func);
+void dav_set_content_data(DavResource *res, char *content, size_t length);
+
+int dav_get_content(DavResource *res, void *stream, dav_write_func write_func);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* NODE_H */
+
--- a/suncc.mk	Sat Dec 01 20:34:55 2012 +0100
+++ b/suncc.mk	Mon Aug 12 14:40:19 2013 +0200
@@ -31,7 +31,7 @@
 AR = ar
 RM = rm
 
-CFLAGS  = -g -c
+CFLAGS  = -g -c -xc99
 COFLAGS = -o
 LDFLAGS =
 LOFLAGS = -o
--- a/ucx/Makefile	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/Makefile	Mon Aug 12 14:40:19 2013 +0200
@@ -1,7 +1,7 @@
 #
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 #
-# Copyright 2011 Olaf Wintermann. All rights reserved.
+# Copyright 2013 Olaf Wintermann. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
@@ -29,9 +29,10 @@
 include ../$(CONF).mk
 
 # list of source files
-SRC  = list.c 
-SRC += dlist.c
+SRC  = utils.c
+SRC += list.c
 SRC += map.c
+SRC += properties.c
 SRC += mempool.c
 SRC += string.c
 SRC += test.c
--- a/ucx/allocator.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/allocator.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,6 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include <stdlib.h>
 #include "allocator.h"
 
+UcxAllocator default_allocator = {
+    NULL,
+    ucx_default_malloc,
+    ucx_default_calloc,
+    ucx_default_realloc,
+    ucx_default_free
+};
+
+UcxAllocator *ucx_default_allocator() {
+    UcxAllocator *allocator = &default_allocator;
+    return allocator;
+}
+
 void *ucx_default_malloc(void *ignore, size_t n) {
     return malloc(n);
 }
@@ -12,3 +53,7 @@
 void *ucx_default_realloc(void *ignore, void *data, size_t n) {
     return realloc(data, n);
 }
+
+void ucx_default_free(void *ignore, void *data) {
+    free(data);
+}
--- a/ucx/allocator.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/allocator.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,5 +1,56 @@
-#ifndef ALLOCATOR_H
-#define	ALLOCATOR_H
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Allocator for custom memory management.
+ * 
+ * An UCX allocator consists of a pointer to the memory area / pool and four
+ * function pointers to memory management functions operating on this memory
+ * area / pool. These functions shall behave equivalent to the standard libc
+ * functions <code>malloc(), calloc(), realloc()</code> and <code>free()</code>.
+ * 
+ * The signature of the memory management functions is based on the signature
+ * of the respective libc function but each of them takes the pointer to the
+ * memory area / pool as first argument.
+ * 
+ * As the pointer to the memory area / pool can be arbitrarily chosen, any data
+ * can be provided to the memory management functions. An UcxMempool is just
+ * one example.
+ * 
+ * @see mempool.h
+ * @see UcxMap
+ * 
+ * @file   allocator.h
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_ALLOCATOR_H
+#define	UCX_ALLOCATOR_H
 
 #include "ucx.h"
 
@@ -7,27 +58,111 @@
 extern "C" {
 #endif
 
+/**
+ * A function pointer to the allocators <code>malloc()</code> function.
+ * @see UcxAllocator
+ */
 typedef void*(*ucx_allocator_malloc)(void *pool, size_t n);
+/**
+ * A function pointer to the allocators <code>calloc()</code> function.
+ * @see UcxAllocator
+ */
 typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size);
+/**
+ * A function pointer to the allocators <code>realloc()</code> function.
+ * @see UcxAllocator
+ */
 typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n);
+/**
+ * A function pointer to the allocators <code>free()</code> function.
+ * @see UcxAllocator
+ */
+typedef void(*ucx_allocator_free)(void *pool, void *data);
 
+/**
+ * UCX allocator data structure containing memory management functions.
+ */
 typedef struct {
+    /** Pointer to an area of memory or a complex memory pool.
+     * This pointer will be passed to any memory management function as first
+     * argument.
+     */
     void *pool;
-    ucx_allocator_malloc malloc;
-    ucx_allocator_calloc calloc;
+    /**
+     * The <code>malloc()</code> function for this allocator.
+     */
+    ucx_allocator_malloc  malloc;
+    /**
+     * The <code>calloc()</code> function for this allocator.
+     */
+    ucx_allocator_calloc  calloc;
+    /**
+     * The <code>realloc()</code> function for this allocator.
+     */
     ucx_allocator_realloc realloc;
+    /**
+     * The <code>free()</code> function for this allocator.
+     */
+    ucx_allocator_free    free;
 } UcxAllocator;
 
+/**
+ * Returns a pointer to the default allocator.
+ * 
+ * The default allocator contains wrappers to the standard libc memory
+ * management functions. Use this function to get a pointer to a globally
+ * available allocator. You may also define an own UcxAllocator by assigning
+ * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable
+ * to any function that takes an UcxAllocator as argument. Note that using
+ * this function is the recommended way of passing a default allocator, thus
+ * it never runs out of scope.
+ * 
+ * @return a pointer to the default allocator
+ * 
+ * @see UCX_ALLOCATOR_DEFAULT
+ */
+UcxAllocator *ucx_default_allocator();
+
+/**
+ * A wrapper for the standard libc <code>malloc()</code> function.
+ * @param ignore ignored (may be used by allocators for pooled memory)
+ * @param n argument passed to <code>malloc()</code>
+ * @return return value of <code>malloc()</code>
+ */
 void *ucx_default_malloc(void *ignore, size_t n);
+/**
+ * A wrapper for the standard libc <code>calloc()</code> function.
+ * @param ignore ignored (may be used by allocators for pooled memory)
+ * @param n argument passed to <code>calloc()</code>
+ * @param size  argument passed to <code>calloc()</code>
+ * @return return value of <code>calloc()</code>
+ */
 void *ucx_default_calloc(void *ignore, size_t n, size_t size);
+/**
+ * A wrapper for the standard libc <code>realloc()</code> function.
+ * @param ignore ignored (may be used by allocators for pooled memory)
+ * @param data argumend passed to <code>realloc()</code>
+ * @param n argument passed to <code>realloc()</code>
+ * @return return value of <code>realloc()</code>
+ */
 void *ucx_default_realloc(void *ignore, void *data, size_t n);
+/**
+ * A wrapper for the standard libc <code>free()</code> function.
+ * @param ignore ignored (may be used by allocators for pooled memory)
+ * @param data argument passed to <code>free()</code>
+ */
+void ucx_default_free(void *ignore, void *data);
 
+/**
+ * Convenient macro for a default allocator <code>struct</code> definition.
+ */
 #define UCX_ALLOCATOR_DEFAULT {NULL, \
-        ucx_default_malloc, ucx_default_calloc, ucx_default_realloc}
+        ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \
+        ucx_default_free }
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* ALLOCATOR_H */
+#endif	/* UCX_ALLOCATOR_H */
 
--- a/ucx/buffer.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/buffer.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,3 +1,31 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "buffer.h"
 #include <stdarg.h>
 #include <stdlib.h>
@@ -8,7 +36,7 @@
     if (buffer) {
         buffer->flags = flags;
         if (!space) {
-            buffer->space = malloc(size);
+            buffer->space = (char*)malloc(size);
             if (!buffer->space) {
                 free(buffer);
                 return NULL;
@@ -16,7 +44,7 @@
             memset(buffer->space, 0, size);
             buffer->flags |= UCX_BUFFER_AUTOFREE;
         } else {
-            buffer->space = space;
+            buffer->space = (char*)space;
         }
         buffer->capacity = size;
         buffer->size = 0;
@@ -48,7 +76,7 @@
 
     UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer));
     if (dst) {
-        dst->space = malloc(length);
+        dst->space = (char*)malloc(length);
         if (!dst->space) {
             free(dst);
             return NULL;
@@ -63,7 +91,7 @@
 }
 
 int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) {
-    off_t npos;
+    size_t npos = 0;
     switch (whence) {
     case SEEK_SET:
         npos = 0;
@@ -78,7 +106,7 @@
 
     npos += offset;
     
-    if (npos < 0 || npos > buffer->size) {
+    if (npos > buffer->size) {
         return -1;
     } else {
         buffer->pos = npos;
@@ -95,7 +123,7 @@
     size_t newcap = buffer->capacity;
     while (buffer->pos + len > newcap) newcap <<= 1;
     
-    char *newspace = realloc(buffer->space, newcap);
+    char *newspace = (char*)realloc(buffer->space, newcap);
     if (newspace) {
         memset(newspace+buffer->size, 0, newcap-buffer->size);
         buffer->space = newspace;
@@ -185,7 +213,7 @@
 size_t ucx_buffer_generic_copy(void *s1, void *s2,
         read_func readfnc, write_func writefnc, size_t bufsize) {
     size_t ncp = 0;
-    char *buf = malloc(bufsize);
+    char *buf = (char*)malloc(bufsize);
     if(buf == NULL) {
         return 0;
     }
@@ -202,3 +230,31 @@
     free(buf);
     return ncp;
 }
+
+size_t ucx_buffer_generic_ncopy(void *s1, void *s2,
+        read_func readfnc, write_func writefnc, size_t bufsize, size_t n) {
+    if(n == 0) {
+        return 0;
+    }
+    
+    size_t ncp = 0;
+    char *buf = (char*)malloc(bufsize);
+    if(buf == NULL) {
+        return 0;
+    }
+    
+    size_t r;
+    size_t rn = bufsize > n ? n : bufsize;
+    while((r = readfnc(buf, 1, rn, s1)) != 0) {
+        r = writefnc(buf, 1, r, s2);
+        ncp += r;
+        n -= r;
+        rn = bufsize > n ? n : bufsize;
+        if(r == 0 || n == 0) {
+            break;
+        }
+    }
+    
+    free(buf);
+    return ncp;
+}
--- a/ucx/buffer.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/buffer.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,5 +1,33 @@
-#ifndef BUFFER_H
-#define	BUFFER_H
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UCX_BUFFER_H
+#define	UCX_BUFFER_H
 
 #include "ucx.h"
 #include <sys/types.h>
@@ -9,7 +37,9 @@
 extern "C" {
 #endif
 
+/* no autoextend or autofree behaviour */
 #define UCX_BUFFER_DEFAULT      0x00
+/* the buffer shall free the occupied memory space */
 #define UCX_BUFFER_AUTOFREE     0x01
 /* the buffer may automatically double its size on write operations */
 #define UCX_BUFFER_AUTOEXTEND   0x02
@@ -44,13 +74,16 @@
  * SEEK_CUR marks the current position
  * SEEK_END marks the first 0-byte in the buffer
  *
- * ucx_memseek returns 0 on success and -1 if the new position is beyond the
+ * ucx_buffer_seek returns 0 on success and -1 if the new position is beyond the
  * bounds of the allocated buffer. In that case the position of the buffer
  * remains unchanged.
  *
  */
 int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence);
 
+#define ucx_buffer_clear(buffer)    memset(buffer->space, 0, buffer->size); \
+                                    buffer->size = 0; buffer->pos = 0;
+
 /*
  * returns non-zero, if the current buffer position has exceeded the last
  * available byte of the underlying buffer
@@ -67,11 +100,6 @@
 size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
         UcxBuffer *buffer);
 
-/* when autoextend is enabled, ensure you get the latest pointer to the data */
-//define ucx_buffer_write(data, itemsize, nitems, buffer) \
-//    ucx_bufio(data, itemsize, nitems, buffer, 0)
-//define ucx_buffer_read(data, itemsize, nitems, buffer) \
-//        ucx_bufio(data, itemsize, nitems, buffer, 1)
 int ucx_buffer_putc(UcxBuffer *b, int c);
 int ucx_buffer_getc(UcxBuffer *b);
 
@@ -85,16 +113,22 @@
 size_t ucx_buffer_generic_copy(void *s1, void *s2, read_func r, write_func w,
         size_t bufsize);
 
+size_t ucx_buffer_generic_ncopy(void *s1, void *s2, read_func r, write_func w,
+        size_t bufsize, size_t n);
 
-#define UCX_DEFAULT_BUFFER_SIZE 0x4000000
+#define UCX_DEFAULT_BUFFER_SIZE 0x1000
 
 #define ucx_buffer_copy(s1,s2,r,w) \
     ucx_buffer_generic_copy(s1, s2, (read_func)r, (write_func)w, \
     UCX_DEFAULT_BUFFER_SIZE)
 
+#define ucx_buffer_ncopy(s1,s2,r,w, n) \
+    ucx_buffer_generic_ncopy(s1, s2, (read_func)r, (write_func)w, \
+    UCX_DEFAULT_BUFFER_SIZE, n)
+
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* BUFFER_H */
+#endif	/* UCX_BUFFER_H */
 
--- a/ucx/dlist.c	Sat Dec 01 20:34:55 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,234 +0,0 @@
-#include "dlist.h"
-
-UcxDlist *restrict ucx_dlist_clone(UcxDlist *restrict l,
-        copy_func fnc, void *data) {
-    UcxDlist *ret = NULL;
-    while (l != NULL) {
-        if (fnc != NULL) {
-            ret = ucx_dlist_append(ret, fnc(l->data, data));
-        } else {
-            ret = ucx_dlist_append(ret, l->data);
-        }
-        l = l->next;
-    }
-    return ret;
-}
-
-int ucx_dlist_equals(const UcxDlist *l1, const UcxDlist *l2,
-        cmp_func fnc, void* data) {
-    if (l1 == l2) return 1;
-    
-    while (l1 != NULL && l2 != NULL) {
-        if (fnc == NULL) {
-            if (l1->data != l2->data) return 0;
-        } else {
-            if (fnc(l1->data, l2->data, data) != 0) return 0;
-        }
-        l1 = l1->next;
-        l2 = l2->next;
-    }
-    
-    return (l1 == NULL && l2 == NULL);
-}
-
-void ucx_dlist_free(UcxDlist *l) {
-    UcxDlist *e = l, *f;
-    while (e != NULL) {
-        f = e;
-        e = e->next;
-        free(f);
-    }
-}
-
-UcxDlist *ucx_dlist_append(UcxDlist *l, void *data)  {
-    UcxDlist *nl = (UcxDlist*) malloc(sizeof(UcxDlist));
-    if (nl == NULL) return NULL;
-    
-    nl->data = data;
-    nl->next = NULL;
-    if (l == NULL) {
-        nl->prev = NULL;
-        return nl;
-    } else {
-        UcxDlist *t = ucx_dlist_last(l);
-        t->next = nl;
-        nl->prev = t;
-        return l;
-    }
-}
-
-UcxDlist *ucx_dlist_prepend(UcxDlist *l, void *data) {
-    UcxDlist *nl = ucx_dlist_append(NULL, data);
-    if (nl == NULL) return NULL;
-    
-    if (l != NULL) {
-        nl->next = l;
-        l->prev = nl;
-    }
-    return nl;
-}
-
-UcxDlist *ucx_dlist_concat(UcxDlist *restrict l1, UcxDlist *restrict l2) {
-    if (l1 == NULL) {
-        return l2;
-    } else {
-        UcxDlist *last = ucx_dlist_last(l1);
-        last->next = l2;
-        l2->prev = last;
-        return l1;
-    }
-}
-
-UcxDlist *ucx_dlist_last(const UcxDlist *l) {
-    if (l == NULL) return NULL;
-    
-    const UcxDlist *e = l;
-    while (e->next != NULL) {
-        e = e->next;
-    }
-    return (UcxDlist*)e;
-}
-
-UcxDlist *ucx_dlist_get(const UcxDlist *l, int index) {
-    if (l == NULL) return NULL;
-
-    const UcxDlist *e = l;
-    while (e->next != NULL && index > 0) {
-        e = e->next;
-        index--;
-    }
-    
-    return (UcxDlist*)(index == 0 ? e : NULL);
-}
-
-size_t ucx_dlist_size(const UcxDlist *l) {
-    if (l == NULL) return 0;
-    
-    const UcxDlist *e = l;
-    size_t s = 1;
-    while (e->next != NULL) {
-        e = e->next;
-        s++;
-    }
-
-    return s;
-}
-
-UcxDlist *ucx_dlist_sort_merge(int length,
-        UcxDlist* restrict ls, UcxDlist* restrict le, UcxDlist* restrict re,
-        cmp_func fnc, void* data) {
-
-    UcxDlist** sorted = (UcxDlist**) malloc(sizeof(UcxDlist*)*length);
-    UcxDlist *rc, *lc;
-
-    lc = ls; rc = le;
-    int n = 0;
-    while (lc && lc != le && rc != re) {
-        if (fnc(lc->data, rc->data, data) <= 0) {
-            sorted[n] = lc;
-            lc = lc->next;
-        } else {
-            sorted[n] = rc;
-            rc = rc->next;
-        }
-        n++;
-    }
-    while (lc && lc != le) {
-        sorted[n] = lc;
-        lc = lc->next;
-        n++;
-    }
-    while (rc && rc != re) {
-        sorted[n] = rc;
-        rc = rc->next;
-        n++;
-    }
-
-    // Update pointer
-    sorted[0]->prev = NULL;
-    for (int i = 0 ; i < length-1 ; i++) {
-        sorted[i]->next = sorted[i+1];
-        sorted[i+1]->prev = sorted[i];
-    }
-    sorted[length-1]->next = NULL;
-
-    UcxDlist *ret = sorted[0];
-    free(sorted);
-    return ret;
-}
-
-UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data) {
-    if (l == NULL) {
-        return NULL;
-    }
-
-    UcxDlist *lc;
-    int ln = 1;
-
-    UcxDlist *restrict ls = l, *restrict le, *restrict re;
-    lc = ls;
-    while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) {
-        lc = lc->next;
-        ln++;
-    }
-    le = lc->next;
-
-    if (le == NULL) {
-        return l; // this list is already sorted :)
-    } else {
-        UcxDlist *rc;
-        int rn = 1;
-        rc = le;
-        while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) {
-            rc = rc->next;
-            rn++;
-        }
-        re = rc->next;
-
-        // Something left? Sort it!
-        UcxDlist *remainder = re;
-        size_t remainder_length = ucx_dlist_size(remainder);
-        if (remainder != NULL) {
-            remainder = ucx_dlist_sort(remainder, fnc, data);
-        }
-
-        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
-        UcxDlist *sorted = ucx_dlist_sort_merge(ln+rn,
-                ls, le, re,
-                fnc, data);
-
-        // merge sorted list with (also sorted) remainder
-        l = ucx_dlist_sort_merge(ln+rn+remainder_length,
-                sorted, remainder, NULL, fnc, data);
-
-        return l;
-    }
-}
-
-/* dlist specific functions */
-UcxDlist *ucx_dlist_first(const UcxDlist *l) {
-    if (l == NULL) return NULL;
-    
-    const UcxDlist *e = l;
-    while (e->prev != NULL) {
-        e = e->prev;
-    }
-    return (UcxDlist *)e;
-}
-
-UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e) {
-    if (e->prev == NULL) {
-        if(e->next != NULL) {
-            e->next->prev = NULL;
-            l = e->next;
-        } else {
-            l = NULL;
-        }
-        
-    } else {
-        e->prev->next = e->next;
-        e->next->prev = e->prev;
-    }
-    free(e);
-    return l;
-}
--- a/ucx/dlist.h	Sat Dec 01 20:34:55 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/* 
- * 
- */
-
-#ifndef DLIST_H
-#define	DLIST_H
-
-#include "ucx.h"
-#include <stddef.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-typedef struct UcxDlist UcxDlist;
-struct UcxDlist {
-    void     *data;
-    UcxDlist *restrict next;
-    UcxDlist *restrict prev;
-};
-
-UcxDlist *restrict ucx_dlist_clone(UcxDlist *restrict l,
-        copy_func fnc, void* data);
-int ucx_dlist_equals(const UcxDlist *l1, const UcxDlist *l2,
-        cmp_func fnc, void* data);
-
-void ucx_dlist_free(UcxDlist *l);
-UcxDlist *ucx_dlist_append(UcxDlist *l, void *data);
-UcxDlist *ucx_dlist_prepend(UcxDlist *l, void *data);
-UcxDlist *ucx_dlist_concat(UcxDlist *restrict l1, UcxDlist *restrict l2);
-UcxDlist *ucx_dlist_last(const UcxDlist *l);
-UcxDlist *ucx_dlist_get(const UcxDlist *l, int index);
-size_t ucx_dlist_size(const UcxDlist *l);
-
-UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data);
-
-/* dlist specific functions */
-UcxDlist *ucx_dlist_first(const UcxDlist *l);
-UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* DLIST_H */
-
--- a/ucx/list.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/list.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,13 +1,45 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "list.h"
 
-UcxList *restrict ucx_list_clone(UcxList *restrict l,
+UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) {
+    return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data);
+}
+
+UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l,
         copy_func fnc, void *data) {
     UcxList *ret = NULL;
-    while (l != NULL) {
-        if (fnc != NULL) {
-            ret = ucx_list_append(ret, fnc(l->data, data));
+    while (l) {
+        if (fnc) {
+            ret = ucx_list_append_a(alloc, ret, fnc(l->data, data));
         } else {
-            ret = ucx_list_append(ret, l->data);
+            ret = ucx_list_append_a(alloc, ret, l->data);
         }
         l = l->next;
     }
@@ -32,46 +64,67 @@
 }
 
 void ucx_list_free(UcxList *l) {
+    ucx_list_free_a(ucx_default_allocator(), l);
+}
+
+void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) {
     UcxList *e = l, *f;
     while (e != NULL) {
         f = e;
         e = e->next;
-        free(f);
+        alloc->free(alloc->pool, f);
     }
 }
 
 UcxList *ucx_list_append(UcxList *l, void *data)  {
-    UcxList *nl = (UcxList*) malloc(sizeof(UcxList));
-    if (nl == NULL) return NULL;
+    return ucx_list_append_a(ucx_default_allocator(), l, data);
+}
+
+UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data)  {
+    UcxList *nl = (UcxList*) alloc->malloc(alloc->pool, sizeof(UcxList));
+    if (!nl) {
+        return NULL;
+    }
     
     nl->data = data;
     nl->next = NULL;
-    if (l == NULL) {
-        return nl;
-    } else {
+    if (l) {
         UcxList *t = ucx_list_last(l);
         t->next = nl;
+        nl->prev = t;
         return l;
+    } else {
+        nl->prev = NULL;
+        return nl;
     }
 }
 
 UcxList *ucx_list_prepend(UcxList *l, void *data) {
-    UcxList *nl = ucx_list_append(NULL, data);
-    if (nl == NULL) return NULL;
+    return ucx_list_prepend_a(ucx_default_allocator(), l, data);
+}
+
+UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) {
+    UcxList *nl = ucx_list_append_a(alloc, NULL, data);
+    if (!nl) {
+        return NULL;
+    }
+    l = ucx_list_first(l);
     
-    if (l != NULL) {
+    if (l) {
         nl->next = l;
+        l->prev = nl;
     }
     return nl;
 }
 
-UcxList *ucx_list_concat(UcxList *restrict l1, UcxList *restrict l2) {
-    if (l1 == NULL) {
-        return l2;
-    } else {
+UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) {
+    if (l1) {
         UcxList *last = ucx_list_last(l1);
         last->next = l2;
+        l2->prev = last;
         return l1;
+    } else {
+        return l2;
     }
 }
 
@@ -85,11 +138,23 @@
     return (UcxList*)e;
 }
 
+ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) {
+    ssize_t index = 0;
+    while (list) {
+        if (list == elem) {
+            return index;
+        }
+        list = list->next;
+        index++;
+    }
+    return -1;
+}
+
 UcxList *ucx_list_get(const UcxList *l, int index) {
     if (l == NULL) return NULL;
 
     const UcxList *e = l;
-    while (e->next != NULL && index > 0) {
+    while (e->next && index > 0) {
         e = e->next;
         index--;
     }
@@ -97,6 +162,27 @@
     return (UcxList*)(index == 0 ? e : NULL);
 }
 
+ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) {
+    ssize_t index = 0;
+    UCX_FOREACH(e, l) {
+        if (fnc) {
+            if (fnc(elem, e->data, cmpdata) == 0) {
+                return index;
+            }
+        } else {
+            if (elem == e->data) {
+                return index;
+            }
+        }
+        index++;
+    }
+    return -1;
+}
+
+int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) {
+    return ucx_list_find(l, elem, fnc, cmpdata) > -1;
+}
+
 size_t ucx_list_size(const UcxList *l) {
     if (l == NULL) return 0;
     
@@ -141,8 +227,10 @@
     }
 
     // Update pointer
+    sorted[0]->prev = NULL;
     for (int i = 0 ; i < length-1 ; i++) {
         sorted[i]->next = sorted[i+1];
+        sorted[i+1]->prev = sorted[i];
     }
     sorted[length-1]->next = NULL;
 
@@ -199,21 +287,35 @@
     }
 }
 
-/* list specific functions */
+UcxList *ucx_list_first(const UcxList *l) {
+    if (!l) {
+        return NULL;
+    }
+    
+    const UcxList *e = l;
+    while (e->prev) {
+        e = e->prev;
+    }
+    return (UcxList *)e;
+}
+
 UcxList *ucx_list_remove(UcxList *l, UcxList *e) {
-    if (e == l) {
-        l = e->next;
-        free(e);
+    return ucx_list_remove_a(ucx_default_allocator(), l, e);
+}
+    
+UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) {
+    if (e->prev == NULL) {
+        if(e->next != NULL) {
+            e->next->prev = NULL;
+            l = e->next;
+        } else {
+            l = NULL;
+        }
+        
     } else {
-        UcxList *f = l;
-        while (f->next != NULL && f->next != e) {
-            f = f->next;
-        }
-        /* perform remove if this element is found in this list */
-        if (f->next == e) {
-            f->next = e->next;
-            free(e);
-        }
+        e->prev->next = e->next;
+        e->next->prev = e->prev;
     }
+    alloc->free(alloc->pool, e);
     return l;
 }
--- a/ucx/list.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/list.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,44 +1,362 @@
 /*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Doubly linked list implementation.
  * 
+ * @file   list.h
+ * @author Mike Becker
+ * @author Olaf Wintermann
  */
 
-#ifndef LIST_H
-#define	LIST_H
+#ifndef UCX_LIST_H
+#define	UCX_LIST_H
 
 #include "ucx.h"
-#include <stddef.h>
+#include "allocator.h"
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
-    
+
+/**
+ * Loop statement for UCX lists.
+ * 
+ * The first argument is a pointer to the list. In most cases this will be the
+ * pointer to the first element of the list, but it may also be an arbitrary
+ * element of the list. The iteration will then start with that element.
+ * 
+ * The second argument is the name of the iteration variable. The scope of
+ * this variable is limited to the <code>UCX_FOREACH</code> statement.
+ * 
+ * @param list The first element of the list
+ * @param elem The variable name of the element
+ */
+#define UCX_FOREACH(elem,list) \
+        for (UcxList* elem = list ; elem != NULL ; elem = elem->next)
+
+/**
+ * UCX list type.
+ * @see UcxList
+ */
 typedef struct UcxList UcxList;
+/**
+ * UCX list structure.
+ */
 struct UcxList {
+    /**
+     * List element payload.
+     */
     void    *data;
+    /**
+     * Pointer to the next list element or <code>NULL</code>, if this is the
+     * last element.
+     */
     UcxList *next;
+    /**
+     * Pointer to the previous list element or <code>NULL</code>, if this is
+     * the first element.
+     */
+    UcxList *prev;
 };
 
-UcxList *restrict ucx_list_clone(UcxList *restrict l,
-        copy_func fnc, void *data);
-int ucx_list_equals(const UcxList *l1, const UcxList *l2,
-        cmp_func fnc, void *data);
+/**
+ * Creates an element-wise copy of a list.
+ * 
+ * This function clones the specified list by creating new list elements and
+ * copying the data with the specified copy_func(). If no copy_func() is
+ * specified, a shallow copy is created and the new list will reference the
+ * same data as the source list.
+ * 
+ * @param list the list to copy
+ * @param cpyfnc a pointer to the function that shall copy an element (may be
+ * <code>NULL</code>)
+ * @param data additional data for the copy_func()
+ * @return a pointer to the copy
+ */
+UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data);
+/**
+ * Creates an element-wise copy of a list using an UcxAllocator.
+ * 
+ * See ucx_list_clone() for details.
+ * 
+ * Keep in mind, that you might want to pass the allocator as an (part of the)
+ * argument for the <code>data</code> parameter, if you want the copy_func() to
+ * make use of the allocator.
+ * 
+ * @param allocator the allocator to use
+ * @param list the list to copy
+ * @param cpyfnc a pointer to the function that shall copy an element (may be
+ * <code>NULL</code>)
+ * @param data additional data for the copy_func()
+ * @return a pointer to the copy
+ * @see ucx_list_clone()
+ */
+UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list,
+        copy_func cpyfnc, void* data);
+
+/**
+ * Compares two UCX lists element-wise by using a compare function.
+ * 
+ * Each element of the two specified lists are compared by using the specified
+ * compare function and the additional data. The type and content of this
+ * additional data depends on the cmp_func() used.
+ * 
+ * If the list pointers denote elements within a list, the lists are compared
+ * starting with the denoted elements. Thus any previous elements are not taken
+ * into account. This might be useful to check, if certain list tails match
+ * each other.
+ * 
+ * @param list1 the first list
+ * @param list2 the second list
+ * @param cmpfnc the compare function
+ * @param data additional data for the compare function
+ * @return 1, if and only if the two lists equal element-wise, 0 otherwise
+ */
+int ucx_list_equals(const UcxList *list1, const UcxList *list2,
+        cmp_func cmpfnc, void* data);
 
-void ucx_list_free(UcxList *l);
-UcxList *ucx_list_append(UcxList *l, void *data);
-UcxList *ucx_list_prepend(UcxList *l, void *data);
-UcxList *ucx_list_concat(UcxList *restrict l1, UcxList *restrict l2);
-UcxList *ucx_list_last(const UcxList *l);
-UcxList *ucx_list_get(const UcxList *l, int index);
-size_t ucx_list_size(const UcxList *l);
+/**
+ * Destroys the entire list.
+ * 
+ * The members of the list are not automatically freed, so ensure they are
+ * otherwise referenced or a memory leak will occur.
+ * 
+ * <b>Caution:</b> the argument <b>MUST</b> denote an entire list (i.e. a call
+ * to ucx_list_first() on the argument must return the argument itself)
+ * 
+ * @param list the list to free
+ */
+void ucx_list_free(UcxList *list);
+/**
+ * Destroys the entire list using an UcxAllocator.
+ * 
+ * See ucx_list_free() for details.
+ * 
+ * @param allocator the allocator to use
+ * @param list the list to free
+ * @see ucx_list_free()
+ */
+void ucx_list_free_a(UcxAllocator *allocator, UcxList *list);
+/**
+ * Inserts an element at the end of the list.
+ * 
+ * This is generally an O(n) operation, as the end of the list is seeked with
+ * ucx_list_last().
+ * 
+ * @param list the list where to append the data, or <code>NULL</code> to
+ * create a new list
+ * @param data the data to insert
+ * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to
+ * the newly created list otherwise
+ */
+UcxList *ucx_list_append(UcxList *list, void *data);
+/**
+ * Inserts an element at the end of the list using an 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
+ * @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_a(UcxAllocator *allocator, UcxList *list, void *data);
+/**
+ * Inserts an element at the beginning of the list.
+ * 
+ * You <i>should</i> overwrite the old list pointer by calling
+ * <code>mylist = ucx_list_prepend(mylist, mydata);</code>. However, you may
+ * also perform successive calls of ucx_list_prepend() on the same list pointer,
+ * as this function always searchs for the head of the list with
+ * ucx_list_first().
+ * 
+ * @param list the list where to insert the data or <code>NULL</code> to create
+ * a new list
+ * @param data the data to insert
+ * @return a pointer to the new list head
+ */
+UcxList *ucx_list_prepend(UcxList *list, void *data);
+/**
+ * Inserts an element at the beginning of the list using an UcxAllocator.
+ * 
+ * See ucx_list_prepend() for details.
+ * 
+ * @param allocator the allocator to use
+ * @param list the list where to insert the data or <code>NULL</code> to create
+ * a new list
+ * @param data the data to insert
+ * @return a pointer to the new list head
+ * @see ucx_list_prepend()
+ */
+UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data);
+/**
+ * Concatenates two lists.
+ * 
+ * Either of the two arguments may be <code>NULL</code>.
+ * 
+ * This function modifies the references to the next/previous element of
+ * the last/first element of <code>list1</code>/<code>
+ * list2</code>.
+ * 
+ * @param list1 first list
+ * @param list2 second list
+ * @return if <code>list1</code> is <code>NULL</code>, <code>list2</code> is
+ * returned, otherwise <code>list1</code> is returned
+ */
+UcxList *ucx_list_concat(UcxList *list1, UcxList *list2);
+/**
+ * Returns the first element of a list.
+ * 
+ * If the argument is the list pointer, it is directly returned. Otherwise
+ * this function traverses to the first element of the list and returns the
+ * list pointer.
+ * 
+ * @param elem one element of the list
+ * @return the first element of the list, the specified element is a member of
+ */
+UcxList *ucx_list_first(const UcxList *elem);
+/**
+ * Returns the last element of a list.
+ * 
+ * If the argument has no successor, it is the last element and therefore
+ * directly returned. Otherwise this function traverses to the last element of
+ * the list and returns it.
+ * 
+ * @param elem one element of the list
+ * @return the last element of the list, the specified element is a member of
+ */
+UcxList *ucx_list_last(const UcxList *elem);
+/**
+ * Returns the list element at the specified index.
+ * 
+ * @param list the list to retrieve the element from
+ * @param index index of the element to return
+ * @return the element at the specified index or <code>NULL</code>, if the
+ * index is greater than the list size
+ */
+UcxList *ucx_list_get(const UcxList *list, int index);
+/**
+ * Returns the index of an element.
+ * 
+ * @param list the list where to search for the element
+ * @param elem the element to find
+ * @return the index of the element or -1 if the list does not contain the
+ * element
+ */
+ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem);
+/**
+ * Returns the element count of the list.
+ * 
+ * @param list the list whose elements are counted
+ * @return the element count
+ */
+size_t ucx_list_size(const UcxList *list);
+/**
+ * Returns the index of an element containing the specified data.
+ *
+ * This function uses a cmp_func() to compare the data of each list element
+ * with the specified data. If no cmp_func is provided, the pointers are
+ * compared.
+ * 
+ * If the list contains the data more than once, the index of the first
+ * occurrence is returned.
+ *  
+ * @param list the list where to search for the data
+ * @param elem the element data
+ * @param cmpfnc the compare function
+ * @param data additional data for the compare function
+ * @return the index of the element containing the specified data or -1 if the
+ * data is not found in this list
+ */
+ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data);
+/**
+ * Checks, if a list contains a specific element.
+ * 
+ * An element is found, if ucx_list_find() returns a value greater than -1.
+ * 
+ * @param list the list where to search for the data
+ * @param elem the element data
+ * @param cmpfnc the compare function
+ * @param data additional data for the compare function
+ * @return 1, if and only if the list contains the specified element data
+ * @see ucx_list_find()
+ */
+int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data);
 
-UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data);
+/**
+ * Sorts an UcxList with natural merge sort.
+ * 
+ * This function uses O(n) additional temporary memory for merge operations
+ * that is automatically freed after each merge.
+ * 
+ * As the head of the list might change, you <b>MUST</b> call this function
+ * as follows: <code>mylist = ucx_list_sort(mylist, mycmpfnc, mydata);</code>.
+ * 
+ * @param list the list to sort
+ * @param cmpfnc the function that shall be used to compare the element data
+ * @param data additional data for the cmp_func()
+ * @return the sorted list
+ */
+UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data);
 
-/* list specific functions */
-UcxList *ucx_list_remove(UcxList *l, UcxList *e);
+/**
+ * Removes an element from the list.
+ * 
+ * If the first element is removed, the list pointer changes. So it is
+ * <i>highly recommended</i> to <i>always</i> update the pointer by calling
+ * <code>mylist = ucx_list_remove(mylist, myelem);</code>.
+ * 
+ * @param list the list from which the element shall be removed
+ * @param element the element to removed
+ * @return returns the updated list pointer or <code>NULL</code>, if the list
+ * is now empty
+ */
+UcxList *ucx_list_remove(UcxList *list, UcxList *element);
+/**
+ * Removes an element from the list using an UcxAllocator.
+ * 
+ * See ucx_list_remove() for details.
+ * 
+ * @param allocator the allocator to use
+ * @param list the list from which the element shall be removed
+ * @param element the element to removed
+ * @return returns the updated list pointer or <code>NULL</code>, if the list
+ * @see ucx_list_remove()
+ */
+UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list,
+        UcxList *element);
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* LIST_H */
+#endif	/* UCX_LIST_H */
 
--- a/ucx/logging.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/logging.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,20 +1,102 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "logging.h"
 #include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
 
-UcxLogger *ucx_logger_new(FILE *stream, unsigned int level) {
+UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask) {
     UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger));
     if (logger != NULL) {
         logger->stream = stream;
+        logger->writer = (write_func)fwrite;
+        logger->dateformat = (char*) "%F %T %z ";
         logger->level = level;
+        logger->mask = mask;
+        logger->levels = ucx_map_new(8);
+        
+        unsigned int l;
+        l = UCX_LOGGER_ERROR;
+        ucx_map_int_put(logger->levels, l, (void*) "[ERROR]");
+        l = UCX_LOGGER_WARN;
+        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_TRACE;
+        ucx_map_int_put(logger->levels, l, (void*) "[TRACE]");
     }
 
     return logger;
 }
 
-void ucx_logger_log(UcxLogger *logger, unsigned int level,
-        const sstr_t message) {
+void ucx_logger_free(UcxLogger *logger) {
+    ucx_map_free(logger->levels);
+    free(logger);
+}
+
+void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file,
+        const unsigned int line, const char *format, ...) {
     if (level <= logger->level) {
-        fwrite(message.ptr, 1, message.length, logger->stream);
-        fflush(logger->stream);
+        const size_t max = 4096; // estimated maximum message length
+        char msg[max];
+        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);
+            n = strlen(text);
+            memcpy(msg+k, text, n);
+            k += n;
+            msg[k++] = ' ';
+        }
+        if ((logger->mask & UCX_LOGGER_TIMESTAMP) > 0) {
+            time_t now = time(NULL);
+            k += strftime(msg+k, 128, logger->dateformat, localtime(&now));
+        }
+        if ((logger->mask & UCX_LOGGER_SOURCE) > 0) {
+            n = strlen(file);
+            memcpy(msg+k, file, n);
+            k += n;
+            k += sprintf(msg+k, ":%d ", line);
+        }
+        
+        msg[k++] = '-'; msg[k++] = ' ';
+        
+        va_list args;
+        va_start (args, format);
+        k += vsnprintf(msg+k, max-k-1, format, args);
+        va_end (args);        
+        
+        msg[k++] = '\n';
+        
+        logger->writer(msg, 1, k, logger->stream);
     }
 }
--- a/ucx/logging.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/logging.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,7 +1,41 @@
-#ifndef LOGGING_H
-#define LOGGING_H
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Logging API.
+ * 
+ * @file   logging.h
+ * @author Mike Becker, Olaf Wintermann
+ */
+#ifndef UCX_LOGGING_H
+#define UCX_LOGGING_H
 
 #include "ucx.h"
+#include "map.h"
 #include "string.h"
 #include <stdio.h>
 
@@ -10,28 +44,174 @@
 #endif
 
 /* leave enough space for custom log levels */
-#define UCX_LOGGER_ERROR    0x00
-#define UCX_LOGGER_WARN     0x10
-#define UCX_LOGGER_INFO     0x20
-#define UCX_LOGGER_TRACE    0x30
+/** Log level for error messages. */
+#define UCX_LOGGER_ERROR        0x00
+/** Log level for warning messages. */
+#define UCX_LOGGER_WARN         0x10
+/** Log level for information messages. */
+#define UCX_LOGGER_INFO         0x20
+/** Log level for debug messages. */
+#define UCX_LOGGER_DEBUG        0x30
+/** Log level for trace messages. */
+#define UCX_LOGGER_TRACE        0x40
+
+/**
+ * Output flag for the log level. 
+ * If this flag is set, the log message will contain the log level.
+ * @see UcxLogger.mask
+ */
+#define UCX_LOGGER_LEVEL        0x01
+/**
+ * Output flag for the timestmap.
+ * If this flag is set, the log message will contain the timestmap.
+ * @see UcxLogger.mask
+ */
+#define UCX_LOGGER_TIMESTAMP    0x02
+/**
+ * Output flag for the source.
+ * If this flag is set, the log message will contain the source file and line
+ * number.
+ * @see UcxLogger.mask
+ */
+#define UCX_LOGGER_SOURCE       0x04
 
+/**
+ * The UCX Logger object.
+ */
 typedef struct {
-    FILE *stream;
+    /** The stream this logger writes its messages to.*/
+    void *stream;
+    /**
+     * The write function that shall be used.
+     * For standard file or stdout loggers this might be standard fwrite
+     * (default).
+     */
+    write_func writer;
+    /**
+     * The date format for timestamp outputs
+     * (default: <code>"%F %T %z "</code>).
+     * @see UCX_LOGGER_TIMESTAMP
+     */
+    char *dateformat;
+    /**
+     * The level, this logger operates on.
+     * If a log command is issued, the message will only be logged, if the log
+     * level of the message is less or equal than the log level of the logger.
+     */
     unsigned int level;
+    /**
+     * A configuration mask for automatic output. 
+     * For each flag that is set, the logger automatically outputs some extra
+     * information like the timestamp or the source file and line number.
+     * See the documentation for the flags for details.
+     */
+    unsigned int mask;
+    /**
+     * A map of valid log levels for this logger.
+     * 
+     * The keys represent all valid log levels and the values provide string
+     * representations, that are used, if the UCX_LOGGER_LEVEL flag is set.
+     * 
+     * The exact data types are <code>unsigned int</code> for the key and
+     * <code>const char*</code> for the value.
+     * 
+     * @see UCX_LOGGER_LEVEL
+     */
+    UcxMap* levels;
 } UcxLogger;
 
-UcxLogger *ucx_logger_new(FILE *stream, unsigned int level);
-/* neither provide a free function nor a parameter for an allocator */
+/**
+ * Creates a new logger.
+ * @param stream the stream, which the logger shall write to
+ * @param level the level on which the logger shall operate
+ * @param mask configuration mask (cf. UcxLogger.mask)
+ * @return a new logger object
+ */
+UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask);
+/**
+ * Destroys the logger.
+ * 
+ * The map containing the valid log levels is also automatically destroyed.
+ * 
+ * @param logger the logger to destroy
+ */
+void ucx_logger_free(UcxLogger* logger);
+
+/**
+ * Internal log function - use macros instead.
+ * 
+ * This function uses the <code>format</code> and variadic arguments for a
+ * printf()-style output of the log message.
+ * 
+ * Dependent on the UcxLogger.mask some information is prepended. The complete
+ * format is:
+ * 
+ * <code>[LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message</code>
+ * 
+ * @param logger the logger to use
+ * @param level the level to log on
+ * @param file information about the source file
+ * @param line information about the source line number
+ * @param format format string
+ * @param ... arguments
+ * @see ucx_logger_log()
+ */
+void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file,
+        const unsigned int line, const char* format, ...);
 
-void ucx_logger_log(UcxLogger *logger, unsigned int level,
-        const sstr_t message);
-#define ucx_logger_error(l,m) ucx_logger_log(l, UCX_LOGGER_ERROR, m)
-#define ucx_logger_info(l,m) ucx_logger_log(l, UCX_LOGGER_INFO, m)
-#define ucx_logger_warn(l,m) ucx_logger_log(l, UCX_LOGGER_WARN, m)
-#define ucx_logger_trace(l,m) ucx_logger_log(l, UCX_LOGGER_TRACE, m)
+/**
+ * Logs a message at the specified level.
+ * @param logger the logger to use
+ * @param level the level to log the message on
+ * @param ... format string and arguments
+ * @see ucx_logger_logf()
+ */
+#define ucx_logger_log(logger, level, ...) \
+    ucx_logger_logf(logger, level, __FILE__, __LINE__, __VA_ARGS__)
+
+/**
+ * Shortcut for logging an error message.
+ * @param logger the logger to use
+ * @param ... format string and arguments
+ * @see ucx_logger_logf()
+ */
+#define ucx_logger_error(logger, ...) \
+    ucx_logger_log(logger, UCX_LOGGER_ERROR, __VA_ARGS__)
+/**
+ * Shortcut for logging an information message.
+ * @param logger the logger to use
+ * @param ... format string and arguments
+ * @see ucx_logger_logf()
+ */
+#define ucx_logger_info(logger, ...) \
+    ucx_logger_log(logger, UCX_LOGGER_INFO, __VA_ARGS__)
+/**
+ * Shortcut for logging a warning message.
+ * @param logger the logger to use
+ * @param ... format string and arguments
+ * @see ucx_logger_logf()
+ */
+#define ucx_logger_warn(logger, ...) \
+    ucx_logger_log(logger, UCX_LOGGER_WARN, __VA_ARGS__)
+/**
+ * Shortcut for logging a debug message.
+ * @param logger the logger to use
+ * @param ... format string and arguments
+ * @see ucx_logger_logf()
+ */
+#define ucx_logger_debug(logger, ...) \
+    ucx_logger_log(logger, UCX_LOGGER_DEBUG, __VA_ARGS__)
+/**
+ * Shortcut for logging a trace message.
+ * @param logger the logger to use
+ * @param ... format string and arguments
+ * @see ucx_logger_logf()
+ */
+#define ucx_logger_trace(logger, ...) \
+    ucx_logger_log(logger, UCX_LOGGER_TRACE, __VA_ARGS__)
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* LOGGING_H */
+#endif /* UCX_LOGGING_H */
--- a/ucx/map.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/map.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,5 +1,29 @@
 /*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <stdlib.h>
@@ -8,18 +32,30 @@
 #include "map.h"
 
 UcxMap *ucx_map_new(size_t size) {
+    return ucx_map_new_a(NULL, size);
+}
+
+UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size) {
     if(size == 0) {
         size = 16;
     }
+       
+    if(!allocator) {
+        allocator = ucx_default_allocator();
+    }
     
-    UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap));
+    UcxMap *map = (UcxMap*)allocator->malloc(allocator->pool, sizeof(UcxMap));
     if(map == NULL) {
         return NULL;
     }
-
-    map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*));
+    
+    map->allocator = allocator;
+    map->map = (UcxMapElement**)allocator->calloc(
+            allocator->pool,
+            size,
+            sizeof(UcxMapElement*));
     if(map->map == NULL) {
-        free(map);
+        allocator->free(allocator->pool, map);
         return NULL;
     }
     map->size = size;
@@ -28,31 +64,31 @@
     return map;
 }
 
-void ucx_map_free_elmlist(UcxMap *map) {
+static void ucx_map_free_elmlist(UcxMap *map) {
     for (size_t n = 0 ; n < map->size ; n++) {
         UcxMapElement *elem = map->map[n];
         if (elem != NULL) {
             do {
                 UcxMapElement *next = elem->next;
-                free(elem->key.data);
-                free(elem);
+                map->allocator->free(map->allocator->pool, elem->key.data);
+                map->allocator->free(map->allocator->pool, elem);
                 elem = next;
             } while (elem != NULL);
         }
     }
-    free(map->map);
+    map->allocator->free(map->allocator->pool, map->map);
 }
 
 void ucx_map_free(UcxMap *map) {
     ucx_map_free_elmlist(map);
-    free(map);
+    map->allocator->free(map->allocator->pool, map);
 }
 
 int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to,
         copy_func fnc, void *data) {
     UcxMapIterator i = ucx_map_iterator(from);
     void *value;
-    UCX_MAP_FOREACH(value, i) {
+    UCX_MAP_FOREACH(key, value, i) {
         int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value);
         if(ret != 0) {
             return 1;
@@ -78,9 +114,13 @@
         oldmap.map = map->map;
         oldmap.size = map->size;
         oldmap.count = map->count;
+        oldmap.allocator = map->allocator;
         
         map->size = (map->count * 5) >> 1;
-        map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*));
+        map->map = (UcxMapElement**)map->allocator->calloc(
+                map->allocator->pool,
+                map->size,
+                sizeof(UcxMapElement*));
         if(map->map == NULL) {
             *map = oldmap;
             return 1;
@@ -95,6 +135,8 @@
 }
 
 int ucx_map_put(UcxMap *map, UcxKey key, void *data) {
+    UcxAllocator *allocator = map->allocator;
+    
     if(key.hash == 0) {
         key.hash = ucx_hash((char*)key.data, key.len);
     }
@@ -109,7 +151,9 @@
     }
     
     if (elm == NULL || elm->key.hash != key.hash) {
-        UcxMapElement *e = (UcxMapElement*)malloc(sizeof(UcxMapElement));
+        UcxMapElement *e = (UcxMapElement*)allocator->malloc(
+                allocator->pool,
+                sizeof(UcxMapElement));
         if(e == NULL) {
             return -1;
         }
@@ -124,7 +168,7 @@
     }
     
     if(elm->key.data == NULL) {
-        void *kd = malloc(key.len);
+        void *kd = allocator->malloc(allocator->pool, key.len);
         if (kd == NULL) {
             return -1;
         }
@@ -157,7 +201,7 @@
                     } else {
                         map->map[slot] = elm->next;
                     }
-                    free(elm);
+                    map->allocator->free(map->allocator->pool, elm);
                     map->count--;
                 }
 
@@ -238,7 +282,7 @@
     return i;
 }
 
-int ucx_map_iter_next(UcxMapIterator *i, void **elm) {
+int ucx_map_iter_next(UcxMapIterator *i, UcxKey *key, void **elm) {
     UcxMapElement *e = i->cur;
     
     if(e == NULL) {
@@ -252,6 +296,7 @@
             if(e->data != NULL) {
                 i->cur = e;
                 *elm = e->data;
+                *key = e->key;
                 return 0;
             }
 
@@ -268,123 +313,3 @@
     return 1;
 }
 
-int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator,
-        ucx_map_coder decoder, void* decdata) {
-
-    int c; int r, n;
-
-    char *key, *value;
-
-    while ((c = fgetc(f)) > 0) {
-        /* Discard leading spaces and comments */
-        if (c < 33) continue;
-        if (c == '#' || c == '!') {
-            while ((c = (char) fgetc(f)) > 0) {
-                if (c == '\n') break;
-            }
-            continue;
-        }
-
-        /* read into key buffer */
-        n = 16;
-        key = (char*) malloc(n);
-        r = 0;
-        do {
-            if (c == '=') break;
-            if (r > n - 2) {
-                n *= 2;
-                key = (char*) realloc(key, n);
-            }
-            key[r] = c;
-            r++;
-        } while ((c = fgetc(f)) > 0);
-        if (c <= 0) {
-            free(key);
-            return 1;
-        }
-        key[r] = 0;
-        while (key[--r] == ' ') key[r] = 0;
-
-        /* skip whitespaces */
-        while ((c = fgetc(f)) > 0) {
-            if (c > 32) break;
-        }
-        if (c <= 0) {
-            free(key);
-            return 1;
-        }
-
-        /* read into value buffer */
-        n = 64;
-        value = (char*) malloc(n);
-        r = 0;
-        do {
-            if (c == '\n') break;
-            if (r > n - 2) {
-                n *= 2;
-                value = (char*) realloc(value, n);
-            }
-            value[r] = c;
-            r++;
-        } while ((c = fgetc(f)) > 0);
-        value[r] = 0;
-        while (value[--r] < 33) value[r] = 0;
-
-        if (decoder) {
-            size_t decodedSize;
-            void *decoded = decoder(value, decdata, &decodedSize);
-            free(value);
-            value = (char*) decoded;
-            r = decodedSize;
-        } else {
-            r += 2;
-            value = (char*) realloc(value, r);
-        }
-
-        if (allocator.pool) {
-            void *pooledValue = allocator.malloc(allocator.pool, r);
-            memcpy(pooledValue, value, r);
-            free(value);
-            value = (char*) pooledValue;
-        }
-
-        ucx_map_cstr_put(map, key, value);
-        free(key);
-    }
-
-    return 0;
-}
-
-int ucx_map_store_enc(UcxMap *map, FILE *f,
-        ucx_map_coder encoder, void *encdata) {
-    UcxMapIterator iter = ucx_map_iterator(map);
-    char *k, *v;
-    sstr_t key, value;
-    int written;
-
-    UCX_MAP_FOREACH(v, iter) {
-        k = (char*) iter.cur->key.data;
-        key = sstr(k);
-        if (encoder) {
-            size_t encodedSize;
-            void *encoded = encoder(v, encdata, &encodedSize);
-            value = sstrn((char*) encoded,encodedSize - 1);
-        } else {
-            value = sstr(v);
-        }
-
-        written = 0;
-        written += fwrite(key.ptr, 1, key.length, f);
-        written += fwrite(" = ", 1, 3, f);
-        written += fwrite(value.ptr, 1, value.length, f);
-        written += fwrite("\n", 1, 1, f);
-
-        if (encoder) {
-            free(value.ptr);
-        }
-
-        if (written != key.length + value.length + 4) return 1;
-    }
-
-    return 0;
-}
--- a/ucx/map.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/map.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,36 +1,65 @@
 /*
- * 
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef MAP_H
-#define	MAP_H
+/**
+ * @file map.h
+ * 
+ * Hash map implementation.
+ * 
+ * This implementation uses murmur hash 2 and separate chaining with linked
+ * lists.
+ * 
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_MAP_H
+#define	UCX_MAP_H
 
 #include "ucx.h"
 #include "string.h"
-#include "mempool.h"
+#include "allocator.h"
 #include <stdio.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-#define UCX_MAP_FOREACH(elm,iter) \
-        for(;ucx_map_iter_next(&iter,(void**)&elm)==0;)
+#define UCX_MAP_FOREACH(key,elm,iter) \
+        for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&elm)==0;)
 
 typedef struct UcxMap          UcxMap;
 typedef struct UcxKey          UcxKey;
 typedef struct UcxMapElement   UcxMapElement;
 typedef struct UcxMapIterator  UcxMapIterator;
 
-/*
- * param 1: element
- * param 2: additional data
- * param 3: size of encoded data will be stored here
- * returns encoded / decoded string or NULL on failure
- */
-typedef void*(*ucx_map_coder)(void*,void*,size_t*);
-
 struct UcxMap {
+    UcxAllocator  *allocator;
     UcxMapElement **map;
     size_t        size;
     size_t        count;
@@ -51,12 +80,34 @@
 struct UcxMapIterator {
     UcxMap        *map;
     UcxMapElement *cur;
-    int           index;
+    size_t        index;
 };
 
-
+/**
+ * Creates a new hash map with the specified size.
+ * @param size the size of the hash map
+ * @return a pointer to the new hash map
+ */
 UcxMap *ucx_map_new(size_t size);
+
+/**
+ * Creates a new hash map with the specified size using an UcxAllocator.
+ * @param allocator the allocator to use
+ * @param size the size of the hash map
+ * @return a pointer to the new hash map
+ */
+UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size);
+
+/**
+ * Frees a hash map.
+ * 
+ * <b>Note:</b> the contents are <b>not</b> freed, use an UcxMempool for that
+ * purpose.
+ * 
+ * @param map the map to be freed
+ */
 void ucx_map_free(UcxMap *map);
+
 /* you cannot clone maps with more than 390 mio entries */
 int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to,
         copy_func fnc, void *data);
@@ -67,18 +118,81 @@
 void* ucx_map_get(UcxMap *map, UcxKey key);
 void* ucx_map_remove(UcxMap *map, UcxKey key);
 
-#define ucx_map_sstr_put(m, s, d) \
-    ucx_map_put(m, ucx_key((void*)s.ptr, s.length), d)
-#define ucx_map_cstr_put(m, s, d) \
-    ucx_map_put(m, ucx_key((void*)s, 1+strlen(s)), d)
-#define ucx_map_sstr_get(m, s) \
-    ucx_map_get(m, ucx_key((void*)s.ptr, s.length))
-#define ucx_map_cstr_get(m, s) \
-    ucx_map_get(m, ucx_key((void*)s, 1+strlen(s)))
-#define ucx_map_sstr_remove(m, s) \
-    ucx_map_remove(m, ucx_key((void*)s.ptr, s.length))
-#define ucx_map_cstr_remove(m, s) \
-    ucx_map_remove(m, ucx_key((void*)s, 1+strlen(s)))
+/**
+ * Shorthand for putting data with a sstr_t key into the map.
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @see ucx_map_put()
+ */
+#define ucx_map_sstr_put(map, key, value) \
+    ucx_map_put(map, ucx_key(key.ptr, key.length), (void*)value)
+/**
+ * Shorthand for putting data with a C string key into the map.
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @see ucx_map_put()
+ */
+#define ucx_map_cstr_put(map, key, value) \
+    ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value)
+/**
+ * Shorthand for putting data with an integer key into the map.
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @see ucx_map_put()
+ */
+#define ucx_map_int_put(map, key, value) \
+    ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value)
+
+
+/**
+ * Shorthand for getting data from the map with a sstr_t key.
+ * @param map the map
+ * @param key the key
+ * @see ucx_map_get()
+ */
+#define ucx_map_sstr_get(map, key) \
+    ucx_map_get(map, ucx_key(key.ptr, key.length))
+/**
+ * Shorthand for getting data from the map with a C string key.
+ * @see ucx_map_get()
+ */
+#define ucx_map_cstr_get(map, key) \
+    ucx_map_get(map, ucx_key((void*)key, strlen(key)))
+/**
+ * Shorthand for getting data from the map with an integer key.
+ * @param map the map
+ * @param key the key
+ * @see ucx_map_get()
+ */
+#define ucx_map_int_get(map, key) \
+    ucx_map_get(map, ucx_key((void*)&key, sizeof(int)))
+/**
+ * Shorthand for removing data from the map with a sstr_t key.
+ * @param map the map
+ * @param key the key
+ * @see ucx_map_remove()
+ */
+#define ucx_map_sstr_remove(map, key) \
+    ucx_map_remove(map, ucx_key(key.ptr, key.length))
+/**
+ * Shorthand for removing data from the map with a C string key.
+ * @param map the map
+ * @param key the key
+ * @see ucx_map_remove()
+ */
+#define ucx_map_cstr_remove(map, key) \
+    ucx_map_remove(map, ucx_key((void*)key, strlen(key)))
+/**
+ * Shorthand for removing data from the map with an integer key.
+ * @param map the map
+ * @param key the key
+ * @see ucx_map_remove()
+ */
+#define ucx_map_int_remove(map, key) \
+    ucx_map_remove(map, ucx_key((void*)&key, sizeof(key)))
 
 UcxKey ucx_key(void *data, size_t len);
 
@@ -86,21 +200,12 @@
 
 UcxMapIterator ucx_map_iterator(UcxMap *map);
 
-int ucx_map_iter_next(UcxMapIterator *i, void **elm);
-
-/* use macros for string maps only, values are not encoded */
-#define ucx_map_load(map, f, alloc) ucx_map_load_enc(map, f, alloc, NULL, NULL)
-#define ucx_map_store(map, f) ucx_map_store_enc(map, f, NULL, NULL)
+int ucx_map_iter_next(UcxMapIterator *i, UcxKey *key, void **elm);
 
-int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator,
-        ucx_map_coder decoder, void* decdata);
-/* encoders shall provide null terminated strings*/
-int ucx_map_store_enc(UcxMap *map, FILE *f,
-        ucx_map_coder encoder, void* encdata);
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* MAP_H */
+#endif	/* UCX_MAP_H */
 
--- a/ucx/mempool.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/mempool.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,10 +1,37 @@
 /*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#ifdef __cplusplus
+#define __STDC_FORMAT_MACROS
+#endif
 #include <inttypes.h>
 
 #include "mempool.h"
@@ -19,14 +46,16 @@
     void           *ptr;
 } ucx_regdestr;
 
-void ucx_mempool_shared_destr(void* ptr) {
+UCX_EXTERN void ucx_mempool_shared_destr(void* ptr) {
     ucx_regdestr *rd = (ucx_regdestr*)ptr;
     rd->destructor(rd->ptr);
 }
 
 UcxMempool *ucx_mempool_new(size_t n) {
     UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool));
-    if (pool == NULL) return NULL;
+    if (!pool) {
+        return NULL;
+    }
     
     pool->data = (void**) malloc(n * sizeof(void*));
     if (pool->data == NULL) {
@@ -41,20 +70,23 @@
 
 int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) {
     void **data = (void**) realloc(pool->data, newcap*sizeof(void*));
-    if (data == NULL) {
-        return 1;
-    } else {
+    if (data) {
         pool->data = data; 
         pool->size = newcap;
         return EXIT_SUCCESS;
+    } else {
+        return EXIT_FAILURE;
     }
 }
 
 void *ucx_mempool_malloc(UcxMempool *pool, size_t n) {
     ucx_memchunk *mem = (ucx_memchunk*)malloc(sizeof(ucx_destructor) + n);
-    if (mem == NULL) return NULL;
+    if (!mem) {
+        return NULL;
+    }
 
     if (pool->ndata >= pool->size) {
+        // The hard coded 16 is documented for this function and ucx_mempool_new
         ucx_mempool_chcap(pool, pool->size + 16);
      }
 
@@ -62,12 +94,12 @@
     pool->data[pool->ndata] = mem;
     pool->ndata++;
 
-    return &mem->c;
+    return &(mem->c);
 }
 
 void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) {
     void *ptr = ucx_mempool_malloc(pool, nelem*elsize);
-    if(ptr == NULL) {
+    if (!ptr) {
         return NULL;
     }
     memset(ptr, 0, nelem * elsize);
@@ -77,15 +109,17 @@
 void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) {
     char *mem = ((char*)ptr) - sizeof(ucx_destructor);
     char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor));
-    if (newm == NULL) return NULL;
+    if (!newm) {
+        return NULL;
+    }
     if (mem != newm) {
-        for(int i=0;i<pool->ndata;i++) {
+        for(size_t i=0 ; i < pool->ndata ; i++) {
             if(pool->data[i] == mem) {
                 pool->data[i] = newm;
                 return newm + sizeof(ucx_destructor);
             }
         }
-        fprintf(stderr, "FATAL: 0x%08"PRIxPTR" not in mpool 0x%08"PRIxPTR"\n",
+        fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n",
           (intptr_t)ptr, (intptr_t)pool);
         exit(1);
     } else {
@@ -93,14 +127,37 @@
     }
 }
 
-void ucx_mempool_free(UcxMempool *pool) {
+void ucx_mempool_free(UcxMempool *pool, void *ptr) {
+    ucx_memchunk *chunk = (ucx_memchunk*)((char*)ptr-sizeof(ucx_destructor));
+    for(size_t i=0 ; i<pool->ndata ; i++) {
+        if(chunk == pool->data[i]) {
+            if(chunk->destructor != NULL) {
+                chunk->destructor(&chunk->c);
+            }
+            free(chunk);
+            size_t last_index = pool->ndata - 1;
+            if(i != last_index) {
+                pool->data[i] = pool->data[last_index];
+            }
+            pool->ndata--;
+            return;
+        }
+    }
+    fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n",
+            (intptr_t)ptr, (intptr_t)pool);
+    exit(EXIT_FAILURE);
+}
+
+void ucx_mempool_destroy(UcxMempool *pool) {
     ucx_memchunk *chunk;
-    for(int i=0;i<pool->ndata;i++) {
+    for(size_t i=0 ; i<pool->ndata ; i++) {
         chunk = (ucx_memchunk*) pool->data[i];
-        if(chunk->destructor != NULL) {
-            chunk->destructor(&chunk->c);
+        if(chunk) {
+            if(chunk->destructor) {
+                chunk->destructor(&(chunk->c));
+            }
+            free(chunk);
         }
-        free(chunk);
     }
     free(pool->data);
     free(pool);
@@ -118,3 +175,17 @@
     rd->ptr = ptr;
     ucx_mempool_set_destr(rd, ucx_mempool_shared_destr);
 }
+
+UcxAllocator* ucx_mempool_allocator(UcxMempool *pool) {
+    UcxAllocator *allocator = (UcxAllocator*)ucx_mempool_malloc(
+            pool, sizeof(UcxAllocator));
+    if(!allocator) {
+        return NULL;
+    }
+    allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc;
+    allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc;
+    allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc;
+    allocator->free = (ucx_allocator_free)ucx_mempool_free;
+    allocator->pool = pool;
+    return allocator;
+}
--- a/ucx/mempool.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/mempool.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,9 +1,42 @@
-/* 
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
  *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef MPOOL_H
-#define	MPOOL_H
+/**
+ * @file mempool.h
+ * 
+ * Memory pool implementation.
+ * 
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_MEMPOOL_H
+#define	UCX_MEMPOOL_H
 
 #include "ucx.h"
 #include <stddef.h>
@@ -13,36 +46,159 @@
 extern "C" {
 #endif
 
+/**
+ * A function pointer to a destructor function.
+ * @see ucx_mempool_setdestr()
+ * @see ucx_mempool_regdestr()
+ */
 typedef void(*ucx_destructor)(void*);
 
+/**
+ * UCX mempool structure.
+ */
 typedef struct {
+    /** List of pointers to pooled memory. */
     void   **data;
+    /** Count of pooled memory items. */
     size_t ndata;
+    /** Memory pool size. */
     size_t size;
 } UcxMempool;
 
-#define UCX_ALLOCATOR_MEMPOOL(pool) {pool, \
-    (ucx_allocator_malloc) ucx_mempool_malloc, \
-    (ucx_allocator_calloc) ucx_mempool_calloc, \
-    (ucx_allocator_realloc) ucx_mempool_realloc}
+/** Shorthand for a new default memory pool with a capacity of 16 elements. */
+#define ucx_mempool_new_default() ucx_mempool_new(16)
+
 
-#define ucx_mempool_new_default() ucx_mempool_new(16)
+/**
+ * Creates a memory pool with the specified initial size.
+ * 
+ * As the created memory pool automatically grows in size by 16 elements, when
+ * trying to allocate memory on a full pool, it is recommended that you use
+ * a multiple of 16 for the initial size.
+ * 
+ * @param n initial pool size (should be a multiple of 16)
+ * @return a pointer to the new memory pool
+ */
 UcxMempool *ucx_mempool_new(size_t n);
+
+/**
+ * Resizes a memory pool.
+ * 
+ * @param pool the pool to resize
+ * @param newcap the new capacity
+ * @return <code>EXIT_SUCCESS</code> on success or
+ * <code>EXIT_FAILURE</code> on failure
+ */
 int ucx_mempool_chcap(UcxMempool *pool, size_t newcap);
 
+/**
+ * Allocates pooled memory.
+ * 
+ * @param pool the memory pool
+ * @param n amount of memory to allocate
+ * @return a pointer to the allocated memory
+ * @see ucx_allocator_malloc()
+ */
 void *ucx_mempool_malloc(UcxMempool *pool, size_t n);
+/**
+ * Allocates a pooled memory array.
+ * 
+ * The contents of the allocated memory is set to zero.
+ * 
+ * @param pool the memory pool
+ * @param nelem amount of elements to allocate
+ * @param elsize amount of memory per element
+ * @return a pointer to the allocated memory
+ * @see ucx_allocator_calloc()
+ */
 void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize);
+/**
+ * Reallocates pooled memory.
+ * 
+ * @param pool the memory pool
+ * @param ptr a pointer to the memory that shall be reallocated
+ * @param n the new size of the memory
+ * @return a pointer to the the location of the memory
+ * @see ucx_allocator_realloc()
+ */
 void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n);
+/**
+ * Frees pooled memory.
+ * 
+ * Before freeing the memory, the specified destructor function (if any)
+ * is called.
+ * 
+ * If you specify memory, that is not pooled by the specified memory pool, this
+ * is considered as a severe error and an error message is written to
+ * <code>stderr</code> and the application is shut down with code
+ * <code>EXIT_FAILURE</code>.
+ * 
+ * @param pool the memory pool
+ * @param ptr a pointer to the memory that shall be freed
+ * @see ucx_mempool_set_destr()
+ */
+void ucx_mempool_free(UcxMempool *pool, void *ptr);
 
-void ucx_mempool_free(UcxMempool *pool);
+/**
+ * Destroys a memory pool.
+ * 
+ * For each element the destructor function (if any) is called and the element
+ * is freed.
+ * 
+ * Each of the registered destructor function that has no corresponding element
+ * within the pool (namely those registered by ucx_mempool_reg_destr) is
+ * called interleaving with the element destruction, but with guarantee to the
+ * order in which they were registered (FIFO order).
+ * 
+ * 
+ * @param pool the mempool to destroy
+ */
+void ucx_mempool_destroy(UcxMempool *pool);
 
+/**
+ * Sets a destructor function for the specified memory.
+ * 
+ * The destructor is automatically called when the memory is freed or the
+ * pool is destroyed.
+ * 
+ * The only requirement for the specified memory is, that it <b>MUST</b> be
+ * pooled memory by an UcxMempool or an element-compatible mempool. The pointer
+ * to the destructor function is saved in a reserved area before the actual
+ * memory.
+ * 
+ * @param ptr pooled memory
+ * @param func a pointer to the destructor function
+ * @see ucx_mempool_free()
+ * @see ucx_mempool_destroy()
+ */
 void ucx_mempool_set_destr(void *ptr, ucx_destructor func);
+
+/**
+ * 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.
+ * 
+ * @param pool the memory pool
+ * @param ptr data the destructor is registered for
+ * @param destr a pointer to the destructor function
+ */
 void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr);
 
+/**
+ * Creates an UcxAllocator based on an UcxMempool.
+ * 
+ * @param pool the mempool to create the UcxAllocator for
+ * @return a new UcxAllocator based on the specified pool
+ */
+UcxAllocator* ucx_mempool_allocator(UcxMempool *pool);
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* MPOOL_H */
+#endif	/* UCX_MEMPOOL_H */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/properties.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "properties.h"
+
+UcxProperties *ucx_properties_new() {
+    UcxProperties *parser = (UcxProperties*)malloc(
+            sizeof(UcxProperties));
+    if(!parser) {
+        return NULL;
+    }
+    
+    parser->buffer = NULL;
+    parser->buflen = 0;
+    parser->pos = 0;
+    parser->tmp = NULL;
+    parser->tmplen = 0;
+    parser->tmpcap = 0;
+    parser->error = 0;
+    parser->delimiter = '=';
+    parser->comment1 = '#';
+    parser->comment2 = 0;
+    parser->comment3 = 0;   
+    
+    return parser;
+}
+
+void ucx_properties_free(UcxProperties *parser) {
+    if(parser->tmp) {
+        free(parser->tmp);
+    }
+    free(parser);
+}
+
+void ucx_properties_fill(UcxProperties *parser, char *buf, size_t len) {
+    parser->buffer = buf;
+    parser->buflen = len;
+    parser->pos = 0;
+}
+
+static void parser_tmp_append(UcxProperties *parser, char *buf, size_t len) {
+    if(parser->tmpcap - parser->tmplen < len) {
+        size_t newcap = parser->tmpcap + len + 64;
+        parser->tmp = (char*)realloc(parser->tmp, newcap);
+        parser->tmpcap = newcap;
+    }
+    memcpy(parser->tmp + parser->tmplen, buf, len);
+    parser->tmplen += len;
+}
+
+int ucx_properties_next(UcxProperties *parser, sstr_t *name, sstr_t *value)  {   
+    if(parser->tmplen > 0) {
+        char *buf = parser->buffer + parser->pos;
+        size_t len = parser->buflen - parser->pos;
+        sstr_t str = sstrn(buf, len);
+        sstr_t nl = sstrchr(str, '\n');
+        if(nl.ptr) {
+            size_t newlen = (size_t)(nl.ptr - buf) + 1;
+            parser_tmp_append(parser, buf, newlen);
+            // the tmp buffer contains exactly one line now
+            
+            char *orig_buf = parser->buffer;
+            size_t orig_len = parser->buflen;
+            
+            parser->buffer = parser->tmp;
+            parser->buflen = parser->tmplen;
+            parser->pos = 0;    
+            parser->tmp = NULL;
+            parser->tmpcap = 0;
+            parser->tmplen = 0;
+            // run ucx_properties_next with the tmp buffer as main buffer
+            int ret = ucx_properties_next(parser, name, value);
+            
+            // restore original buffer
+            parser->tmp = parser->buffer;
+            parser->buffer = orig_buf;
+            parser->buflen = orig_len;
+            parser->pos = newlen;
+            
+            /*
+             * if ret == 0 the tmp buffer contained just space or a comment
+             * we parse again with the original buffer to get a name/value
+             * or a new tmp buffer
+             */
+            return ret ? ret : ucx_properties_next(parser, name, value);
+        } else {
+            parser_tmp_append(parser, buf, len);
+            return 0;
+        }
+    } else if(parser->tmp) {
+        free(parser->tmp);
+        parser->tmp = NULL;
+    }
+    
+    char comment1 = parser->comment1;
+    char comment2 = parser->comment2;
+    char comment3 = parser->comment3;
+    char delimiter = parser->delimiter;
+    
+    // get one line and parse it
+    while(parser->pos < parser->buflen) {
+        char *buf = parser->buffer + parser->pos;
+        size_t len = parser->buflen - parser->pos;
+        
+        /*
+         * First we check if we have at least one line. We also get indices of
+         * delimiter and comment chars
+         */
+        size_t delimiter_index = 0;
+        size_t comment_index = 0;
+        int has_comment = 0;
+
+        size_t i = 0;
+        char c = 0;
+        for(;i<len;i++) {
+            c = buf[i];
+            if(c == comment1 || c == comment2 || c == comment3) {
+                if(comment_index == 0) {
+                    comment_index = i;
+                    has_comment = 1;
+                }
+            } else if(c == delimiter) {
+                if(delimiter_index == 0 && !has_comment) {
+                    delimiter_index = i;
+                }
+            } else if(c == '\n') {
+                break;
+            }
+        }
+
+        if(c != '\n') {
+            // we don't have enough data for a line
+            // store remaining bytes in temporary buffer for next round
+            parser->tmpcap = len + 128;
+            parser->tmp = (char*)malloc(parser->tmpcap);
+            parser->tmplen = len;
+            memcpy(parser->tmp, buf, len);
+            return 0;
+        }
+        
+        sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i);
+        // check line
+        if(delimiter_index == 0) {
+            line = sstrtrim(line);
+            if(line.length != 0) {
+                parser->error = 1;
+            }
+        } else {
+            sstr_t n = sstrn(buf, delimiter_index);
+            sstr_t v = sstrn(
+                    buf + delimiter_index + 1,
+                    line.length - delimiter_index - 1); 
+            n = sstrtrim(n);
+            v = sstrtrim(v);
+            if(n.length != 0 || v.length != 0) {
+                *name = n;
+                *value = v;
+                parser->pos += i + 1;
+                return 1;
+            } else {
+                parser->error = 1;
+            }
+        }
+        
+        parser->pos += i + 1;
+    }
+    
+    return 0;
+}
+
+int ucx_properties2map(UcxProperties *parser, UcxMap *map) {
+    sstr_t name;
+    sstr_t value;
+    while(ucx_properties_next(parser, &name, &value)) {
+        value = sstrdup_a(map->allocator, value);
+        if(!value.ptr) {
+            return 1;
+        }
+        if(ucx_map_sstr_put(map, name, value.ptr)) {
+            map->allocator->free(map->allocator->pool, value.ptr);
+            return 1;
+        }
+    }
+    if (parser->error) {
+        return parser->error;
+    } else {
+        return 0;
+    }
+}
+
+int ucx_properties_load(UcxMap *map, FILE *file) {
+    UcxProperties *parser = ucx_properties_new();
+    if(!(parser && map && file)) {
+        return 1;
+    }
+    
+    // buffer size is documented - change doc, when you change bufsize!
+    const size_t bufsize = 1024;
+    
+    int error = 0;
+    size_t r;
+    char buf[bufsize];
+    while((r = fread(buf, 1, bufsize, file)) != 0) {
+        ucx_properties_fill(parser, buf, r);
+        error = ucx_properties2map(parser, map);
+        if (error) {
+            break;
+        }
+    }
+    
+    ucx_properties_free(parser);
+    return error;
+}
+
+int ucx_properties_store(UcxMap *map, FILE *file) {
+    UcxMapIterator iter = ucx_map_iterator(map);
+    char *v;
+    sstr_t value;
+    size_t written;
+
+    UCX_MAP_FOREACH(k, v, iter) {
+        value = sstr(v);
+
+        written = 0;
+        written += fwrite(k.data, 1, k.len, file);
+        written += fwrite(" = ", 1, 3, file);
+        written += fwrite(value.ptr, 1, value.length, file);
+        written += fwrite("\n", 1, 1, file);
+
+        if (written != k.len + value.length + 4) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/properties.h	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,205 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @file properties.h
+ * 
+ * Load / store utilities for properties files.
+ * 
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_PROPERTIES_H
+#define	UCX_PROPERTIES_H
+
+#include "ucx.h"
+#include "map.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/**
+ * UcxProperties object for parsing properties data.
+ * Most of the fields are for internal use only. You may configure the
+ * properties parser, e.g. by changing the used delimiter or specifying 
+ * up to three different characters that shall introduce comments.
+ */
+typedef struct {
+    /**
+     * Input buffer (don't set manually).
+     * Automatically set by calls to ucx_properties_fill().
+     */
+    char   *buffer;
+    /**
+     * Length of the input buffer (don't set manually).
+     * Automatically set by calls to ucx_properties_fill().
+     */
+    size_t buflen;
+    /**
+     * Current buffer position (don't set manually).
+     * Used by ucx_properties_next().
+     */
+    size_t pos;
+    /**
+     * Internal temporary buffer (don't set manually).
+     * Used by ucx_properties_next().
+     */
+    char   *tmp;
+    /**
+     * Internal temporary buffer length (don't set manually).
+     * Used by ucx_properties_next().
+     */
+    size_t tmplen;
+    /**
+     * Internal temporary buffer capacity (don't set manually).
+     * Used by ucx_properties_next().
+     */
+    size_t tmpcap;
+    /**
+     * Parser error code.
+     * This is always 0 on success and a nonzero value on syntax errors.
+     * The value is set by ucx_properties_next().
+     */
+    int    error;
+    /**
+     * The delimiter that shall be used.
+     * This is '=' by default.
+     */
+    char   delimiter;
+    /**
+     * The first comment character.
+     * This is '#' by default.
+     */
+    char   comment1;
+    /**
+     * The second comment character.
+     * This is not set by default.
+     */
+    char   comment2;
+    /**
+     * The third comment character.
+     * This is not set by default.
+     */
+    char   comment3;
+} UcxProperties;
+
+
+/**
+ * Constructs a new UcxProperties object.
+ * @return a pointer to the new UcxProperties object
+ */
+UcxProperties *ucx_properties_new();
+/**
+ * Destroys an UcxProperties object.
+ * @param prop the UcxProperties object to destroy
+ */
+void ucx_properties_free(UcxProperties *prop);
+/**
+ * Sets the input buffer for the properties parser.
+ * 
+ * After calling this function, you may parse the data by calling
+ * ucx_properties_next() until it returns 0. The function ucx_properties2map()
+ * is a convenience function that performs these successive calls of
+ * ucx_properties_next() within a while loop and puts the properties to a map.
+ * 
+ * 
+ * @param prop the UcxProperties object
+ * @param buf a pointer to the new buffer
+ * @param len the payload length of the buffer
+ * @see ucx_properties_next()
+ * @see ucx_properties2map()
+ */
+void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len);
+/**
+ * Retrieves the next key/value-pair.
+ * 
+ * This function returns a nonzero value as long as there are key/value-pairs
+ * found. If no more key/value-pairs are found, you may refill the input buffer
+ * with ucx_properties_fill().
+ * 
+ * <b>Attention:</b> the sstr_t.ptr pointers of the output parameters point to
+ * memory within the input buffer of the parser and will get invalid some time.
+ * If you want long term copies of the key/value-pairs, use sstrdup() after
+ * calling this function.
+ * 
+ * @param prop the UcxProperties object
+ * @param name a pointer to the sstr_t that shall contain the property name
+ * @param value a pointer to the sstr_t that shall contain the property value
+ * @return Nonzero, if a key/value-pair was successfully retrieved
+ * @see ucx_properties_fill()
+ */
+int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value);
+/**
+ * Retrieves all available key/value-pairs and puts them into an UcxMap.
+ * 
+ * This is done by successive calls to ucx_properties_next() until no more
+ * key/value-pairs can be retrieved. 
+ * 
+ * @param prop the UcxProperties object
+ * @param map the target map
+ * @return The UcxProperties.error code (i.e. 0 on success).
+ * @see ucx_properties_fill()
+ */
+int ucx_properties2map(UcxProperties *prop, UcxMap *map);
+
+/**
+ * Loads a properties file to an UcxMap.
+ * 
+ * This is a convenience function that reads chunks of 1 KB from an input
+ * stream until the end of the stream is reached.
+ * 
+ * An UcxProperties object is implicitly created and destroyed.
+ * 
+ * @param map the map object to write the key/value-pairs to
+ * @param file the <code>FILE*</code> stream to read from
+ * @return 0 on success, or a non-zero value on error
+ * 
+ * @see ucx_properties_fill()
+ * @see ucx_properties2map()
+ */
+int ucx_properties_load(UcxMap *map, FILE *file);
+/**
+ * Stores an UcxMap to a file.
+ * 
+ * The key/value-pairs are written by using the following format:
+ * 
+ * <code>[key] = [value]\\n</code>
+ * 
+ * @param map the map to store
+ * @param file the <code>FILE*</code> stream to write to
+ * @return 0 on success, or a non-zero value on error
+ */
+int ucx_properties_store(UcxMap *map, FILE *file);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_PROPERTIES_H */
+
--- a/ucx/string.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/string.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,8 +1,29 @@
 /*
- * File:   sstring.c
- * Author: olaf
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
  *
- * Created on 17. Juni 2010, 13:27
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <stdlib.h>
@@ -10,18 +31,19 @@
 #include <stdarg.h>
 
 #include "string.h"
+#include "allocator.h"
 
-sstr_t sstr(char *s) {
+sstr_t sstr(char *cstring) {
     sstr_t string;
-    string.ptr = s;
-    string.length = strlen(s);
+    string.ptr = cstring;
+    string.length = strlen(cstring);
     return string;
 }
 
-sstr_t sstrn(char *s, size_t n) {
+sstr_t sstrn(char *cstring, size_t length) {
     sstr_t string;
-    string.ptr = s;
-    string.length = n;
+    string.ptr = cstring;
+    string.length = length;
     return string;
 }
 
@@ -30,7 +52,7 @@
     size_t size = s.length;
     va_start(ap, s);
 
-    for (int i=0;i<n-1;i++) {
+    for (size_t i = 1 ; i < n ; i++) {
         sstr_t str = va_arg(ap, sstr_t);
         size += str.length;
     }
@@ -39,22 +61,7 @@
     return size;
 }
 
-sstr_t sstrcat(sstr_t s, ...) {
-    va_list ap;
-    va_start(ap, s);
-    s.ptr[0] = 0;
-
-    sstr_t str = va_arg (ap, sstr_t);
-    while (str.ptr != NULL) {
-        s.ptr = strncat (s.ptr, str.ptr, s.length);
-        str = va_arg (ap, sstr_t);
-    }
-    va_end(ap);
-
-    return s;
-}
-
-sstr_t sstrncat(size_t n, sstr_t s, sstr_t c1, ...) {
+sstr_t sstrncat(sstr_t s, size_t n, sstr_t c1, ...) {
     va_list ap;
     va_start(ap, c1);
     s.ptr[0] = 0;
@@ -66,7 +73,7 @@
     memcpy(ptr, c1.ptr, cplen);
     len -= cplen;
     ptr += cplen;
-    for (int i=0;i<n-1;i++) {
+    for (size_t i = 1 ; i < n ; i++) {
         sstr_t str = va_arg (ap, sstr_t);
         cplen = str.length > len ? len : str.length;
         if(cplen <= 0) {
@@ -78,6 +85,7 @@
         ptr += cplen;
     }
     va_end(ap);
+    s.length = ptr - s.ptr;
 
     return s;
 }
@@ -88,7 +96,7 @@
 
 sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) {
     sstr_t new_sstr;
-    if (start < 0 || start >= s.length || length < 0) {
+    if (start >= s.length) {
         return s;
     }
     if (length > s.length-start) {
@@ -99,8 +107,25 @@
     return new_sstr;
 }
 
+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);
+        }
+    }
+    sstr_t n;
+    n.ptr = NULL;
+    n.length = 0;
+    return n;
+}
+
 sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) {
-    if (d.length == 0) {
+    return sstrsplit_a(ucx_default_allocator(), s, d, n);
+}
+
+sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, size_t *n) {
+    if (s.length == 0 || d.length == 0) {
+        *n = -1;
         return NULL;
     }
 
@@ -109,16 +134,20 @@
     *n = 1;
 
     /* special case: exact match - no processing needed */
-    if (s.length == d.length && strncmp(s.ptr, d.ptr, s.length) == 0) {
+    if (sstrcmp(s, d) == 0) {
         *n = 0;
         return NULL;
     }
     sstr_t sv = sstrdup(s);
+    if (sv.length == 0) {
+        *n = -2;
+        return NULL;
+    }
 
-    for (int i = 0 ; i < s.length ; i++) {
+    for (size_t i = 0 ; i < s.length ; i++) {
         if (sv.ptr[i] == d.ptr[0]) {
             _Bool match = 1;
-            for (int j = 1 ; j < d.length ; j++) {
+            for (size_t j = 1 ; j < d.length ; j++) {
                 if (j+i < s.length) {
                     match &= (sv.ptr[i+j] == d.ptr[j]);
                 } else {
@@ -128,7 +157,7 @@
             }
             if (match) {
                 (*n)++;
-                for (int j = 0 ; j < d.length ; j++) {
+                for (size_t j = 0 ; j < d.length ; j++) {
                     sv.ptr[i+j] = 0;
                 }
                 i += d.length;
@@ -136,37 +165,90 @@
         }
         if ((*n) == nmax) break;
     }
-    result = (sstr_t*) malloc(sizeof(sstr_t) * (*n));
+    result = (sstr_t*) allocator->malloc(allocator->pool, sizeof(sstr_t)*(*n));
 
-    char *pptr = sv.ptr;
-    for (int i = 0 ; i < *n ; i++) {
-        size_t l = strlen(pptr);
-        char* ptr = (char*) malloc(l + 1);
-        memcpy(ptr, pptr, l);
-        ptr[l] = 0;
+    if (result) {
+        char *pptr = sv.ptr;
+        for (size_t i = 0 ; i < *n ; i++) {
+            size_t l = strlen(pptr);
+            char* ptr = (char*) allocator->malloc(allocator->pool, l + 1);
+            memcpy(ptr, pptr, l);
+            ptr[l] = 0;
 
-        result[i] = sstrn(ptr, l);
-        pptr += l + d.length;
+            result[i] = sstrn(ptr, l);
+            pptr += l + d.length;
+        }
+    } else {
+        *n = -2;
     }
-
+    
     free(sv.ptr);
 
     return result;
 }
 
 int sstrcmp(sstr_t s1, sstr_t s2) {
-    return strncmp(s1.ptr, s2.ptr, s1.length>s2.length ? s2.length: s1.length);
+    if (s1.length == s2.length) {
+        return memcmp(s1.ptr, s2.ptr, s1.length);
+    } else if (s1.length > s2.length) {
+        return 1;
+    } else {
+        return -1;
+    }
 }
 
 sstr_t sstrdup(sstr_t s) {
+    return sstrdup_a(ucx_default_allocator(), s);
+}
+
+sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) {
     sstr_t newstring;
-    newstring.ptr = (char*) malloc(s.length + 1);
-    if (newstring.ptr != NULL) {
+    newstring.ptr = (char*)allocator->malloc(allocator->pool, s.length + 1);
+    if (newstring.ptr) {
         newstring.length = s.length;
         newstring.ptr[newstring.length] = 0;
-
+        
         memcpy(newstring.ptr, s.ptr, s.length);
+    } else {
+        newstring.length = 0;
     }
-
+    
     return newstring;
 }
+
+sstr_t sstrtrim(sstr_t string) {
+    sstr_t newstr = string;
+    if (string.length == 0) {
+        return newstr;
+    }
+    
+    size_t i;
+    for(i=0;i<string.length;i++) {
+        char c = string.ptr[i];
+        if(c > 32) {
+            break;
+        }
+    }
+    newstr.ptr = &string.ptr[i];
+    newstr.length = string.length - i;
+    
+    if(newstr.length == 0) {
+        return newstr;
+    }
+    
+    i = newstr.length - 1;
+    for(;;) {
+        char c = newstr.ptr[i];
+        if(c > 32) {
+            break;
+        }
+        if(i > 0) {
+            i--;
+        } else {
+            break;
+        }
+    }
+    newstr.length = i + 1;
+    
+    return newstr;
+}
--- a/ucx/string.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/string.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,99 +1,345 @@
 /*
- * File:   sstring.h
- * Author: olaf
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
  *
- * Created on 17. Juni 2010, 13:26
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Bounded string implementation.
+ * 
+ * The UCX strings (<code>sstr_t</code>) provide an alternative to C strings.
+ * The main difference to C strings is, that <code>sstr_t</code> does <b>not
+ * need to be <code>NULL</code>-terminated</b>. Instead the length is stored
+ * within the structure.
+ * 
+ * When using <code>sstr_t</code>, developers must be full aware of what type
+ * of string (<code>NULL</code>-terminated) or not) they are using, when 
+ * accessing the <code>char* ptr</code> directly.
+ * 
+ * The UCX string module provides some common string functions, known from
+ * standard libc, working with <code>sstr_t</code>.
+ * 
+ * @file   string.h
+ * @author Mike Becker
+ * @author Olaf Wintermann
  */
 
-#ifndef _SSTRING_H
-#define	_SSTRING_H
+#ifndef UCX_STRING_H
+#define	UCX_STRING_H
 
 #include "ucx.h"
+#include "allocator.h"
 #include <stddef.h>
 
-/* use macros for literals only */
-#define S(s) { (char*)s, sizeof(s)-1 }
-#define ST(s) sstrn((char*)s, sizeof(s)-1)
+/** Shortcut for a <code>sstr_t struct</code> literal. */
+#define ST(s) { (char*)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)
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-typedef struct sstring {
+/**
+ * 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 from a null terminated string
+/**
+ * Creates a new sstr_t based on a C string.
+ * 
+ * The length is implicitly inferred by using a call to <code>strlen()</code>.
  *
- * s  null terminated string
+ * <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.
+ * 
+ * @param cstring the C string to wrap
+ * @return a new sstr_t containing the C string
+ * 
+ * @see sstrn()
  */
-sstr_t sstr(char *s);
+sstr_t sstr(char *cstring);
 
-/*
- * creates a new sstr_t from a string and length
+/**
+ * Creates a new sstr_t of the specified length based on a C string.
  *
- * s  string
- * n  length of string
+ * <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.
+ * 
+ * @param cstring  the C string to wrap
+ * @param length   the length of the string
+ * @return a new sstr_t containing the C string
+ * 
+ * @see sstr()
+ * @see S()
  */
-sstr_t sstrn(char *s, size_t n);
+sstr_t sstrn(char *cstring, size_t length);
 
 
-/*
- * gets the length of n sstr_t strings
+/**
+ * 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.
  *
- * n    number of strings
- * s    string
- * ...  strings
+ * @param count    the total number of specified strings (so at least 1)
+ * @param string   the first string
+ * @param ...      all other strings
+ * @return the cumulated length of all strings
  */
-size_t sstrnlen(size_t n, sstr_t s, ...);
+size_t sstrnlen(size_t count, sstr_t string, ...);
+
+
+/**
+ * Concatenates strings.
+ * 
+ * At least one string must be specified and there must be enough memory
+ * available referenced by the destination sstr_t.ptr for this function to
+ * successfully concatenate all specified strings.
+ * 
+ * The sstr_t.length of the destination string specifies the capacity and
+ * should match the total memory available referenced by the destination
+ * sstr_t.ptr. This function <i>never</i> copies data beyond the capacity and
+ * does not modify any of the source strings.
+ * 
+ * <b>Attention:</b>
+ * <ul>
+ *   <li>Any content in the destination string will be overwritten</li>
+ *   <li>The destination sstr_t.ptr is <b>NOT</b>
+ *       <code>NULL</code>-terminated</li>
+ *   <li>The destination sstr_t.length is set to the total length of the
+ *       concatenated strings</li>
+ *   <li><i>Hint:</i> get a <code>NULL</code>-terminated string by performing
+ *       <code>mystring.ptr[mystring.length]='\0'</code> after calling this
+ *       function</li>
+ * </ul>
+ *
+ * @param dest    new sstr_t with capacity information and allocated memory
+ * @param count   the total number of strings to concatenate
+ * @param src     the first string
+ * @param ...     all other strings
+ * @return the argument for <code>dest</code> is returned
+ */
+sstr_t sstrncat(sstr_t dest, size_t count, sstr_t src, ...);
 
 
-/*
- * concatenates n strings
- *
- * n    number of strings
- * s    new string with enough memory allocated
- * ...  strings
+/**
+ * Returns a substring 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 sstrdup() 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 sstrsubsl()
+ * @see sstrchr()
  */
-sstr_t sstrncat(size_t n, sstr_t s, sstr_t c1, ...);
+sstr_t sstrsubs(sstr_t string, size_t start);
 
-
-/*
- *
+/**
+ * Returns a substring 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 sstrdup() 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 sstrsubs()
+ * @see sstrchr()
  */
-sstr_t sstrsubs(sstr_t s, size_t start);
+sstr_t sstrsubsl(sstr_t string, size_t start, size_t length);
 
-/*
- *
+/**
+ * Returns a 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 least location of <code>chr</code>
+ * 
+ * @see sstrsubs()
  */
-sstr_t sstrsubsl(sstr_t s, size_t start, size_t length);
+sstr_t sstrchr(sstr_t string, int chr);
 
-/*
- * splits s into n parts
+/**
+ * Splits a string into parts by using a delimiter string.
+ * 
+ * This function will return <code>NULL</code>, if one of the following happens:
+ * <ul>
+ *   <li>the string length is zero</li>
+ *   <li>the delimeter length is zero</li>
+ *   <li>the string equals the delimeter</li>
+ *   <li>memory allocation fails</li>
+ * </ul>
+ * 
+ * The integer referenced by <code>count</code> is used as input and determines
+ * the maximum size of the resulting list, i.e. the maximum count of splits to
+ * perform + 1.
+ * 
+ * The integer referenced by <code>count</code> is also used as output and is
+ * set to
+ * <ul>
+ *   <li>-2, on memory allocation errors</li>
+ *   <li>-1, if either the string or the delimiter is an empty string</li>
+ *   <li>0, if the string equals the delimiter</li>
+ *   <li>1, if the string does not contain the delimiter</li>
+ *   <li>the count of list items, otherwise</li>
+ * </ul>
+ * 
+ * If the string starts with the delimiter, the first item of the resulting
+ * list will be an empty string.
+ * 
+ * If the string ends with the delimiter and the maximum list size is not
+ * exceeded, the last list item will be an empty string.
+ * 
+ * <b>Attention:</b> All list items <b>AND</b> all sstr_t.ptr of the list
+ * items must be manually passed to <code>free()</code>. Use sstrsplit_a() with
+ * an allocator to managed memory, to avoid this.
  *
- * s    the string to split
- * d    the delimiter string
- * n    the maximum size of the resulting list
- *      a size of 0 indicates an unbounded list size
- *      the actual size of the list will be stored here
- *
- *      Hint: use this value to avoid dynamic reallocation of the result list
- *
- * Returns a list of the split strings
- * NOTE: this list needs to be freed manually after usage
- *
- * Returns NULL on error
+ * @param string the string to split
+ * @param delim  the delimiter string
+ * @param count  IN: the maximum size of the resulting list (0 for an
+ *               unbounded list), OUT: the actual size of the list
+ * @return a list of the split strings as sstr_t array or
+ *         <code>NULL</code> on error
+ * 
+ * @see sstrsplit_a()
  */
-sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n);
+sstr_t* sstrsplit(sstr_t string, sstr_t delim, size_t *count);
 
+/**
+ * Performing sstrsplit() using an UcxAllocator.
+ * 
+ * <i>Read the description of sstrsplit() for details.</i>
+ * 
+ * The memory for the sstr_t.ptr pointers of the list items and the memory for
+ * the sstr_t array itself are allocated by using the UcxAllocator.malloc()
+ * function.
+ * 
+ * <b>Note:</b> the allocator is not used for memory that is freed within the
+ * same call of this function (locally scoped variables).
+ * 
+ * @param allocator the UcxAllocator used for allocating memory
+ * @param string the string to split
+ * @param delim  the delimiter string
+ * @param count  IN: the maximum size of the resulting list (0 for an
+ *               unbounded list), OUT: the actual size of the list
+ * @return a list of the split strings as sstr_t array or
+ *         <code>NULL</code> on error
+ * 
+ * @see sstrsplit()
+ */
+sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim,
+        size_t *count);
+
+/**
+ * Compares two UCX strings with standard <code>memcmp()</code>.
+ * 
+ * At first it compares the sstr_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
+ * @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)
+ */
 int sstrcmp(sstr_t s1, sstr_t s2);
 
-sstr_t sstrdup(sstr_t s);
+/**
+ * Creates a duplicate of the specified string.
+ * 
+ * The new sstr_t will contain a copy allocated by standard
+ * <code>malloc()</code>. So developers <b>MUST</b> pass the sstr_t.ptr to
+ * <code>free()</code>.
+ * 
+ * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
+ * terminated.
+ * 
+ * @param string the string to duplicate
+ * @return a duplicate of the string
+ * @see sstrdup_a()
+ */
+sstr_t sstrdup(sstr_t string);
+
+/**
+ * Creates a duplicate of the specified string using an UcxAllocator.
+ * 
+ * The new sstr_t will contain a copy allocated by the allocators
+ * ucx_allocator_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.
+ * 
+ * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
+ * terminated.
+ * 
+ * @param allocator a valid instance of an UcxAllocator
+ * @param string the string to duplicate
+ * @return a duplicate of the string
+ * @see sstrdup()
+ */
+sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string);
+
+/**
+ * Omits leading and trailing spaces.
+ * 
+ * This function returns a new sstr_t containing a trimmed version of the
+ * specified string.
+ * 
+ * <b>Note:</b> the new sstr_t references the same memory, thus you
+ * <b>MUST NOT</b> pass the sstr_t.ptr of the return value to
+ * <code>free()</code>. It is also highly recommended to avoid assignments like
+ * <code>mystr = sstrtrim(mystr);</code> as you lose the reference to the
+ * source string. Assignments of this type are only permitted, if the
+ * sstr_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 sstr_t containing the trimmed string
+ */
+sstr_t sstrtrim(sstr_t string);
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* _SSTRING_H */
+#endif	/* UCX_STRING_H */
--- a/ucx/test.c	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/test.c	Mon Aug 12 14:40:19 2013 +0200
@@ -1,12 +1,39 @@
-/* 
- * File:   test.c
- * Author: Mike
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
  *
- * Created on 18. Februar 2012, 14:15
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "test.h"
 
+    
+struct UcxTestList{
+    UcxTest test;
+    UcxTestList *next;
+};
+
 UcxTestSuite* ucx_test_suite_new() {
     UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite));
     if (suite != NULL) {
@@ -14,24 +41,55 @@
         suite->failure = 0;
         suite->tests = NULL;
     }
+
     return suite;
 }
 
 void ucx_test_suite_free(UcxTestSuite* suite) {
-    ucx_list_free(suite->tests);
+    UcxTestList *l = suite->tests;
+    while (l != NULL) {
+        UcxTestList *e = l;
+        l = l->next;
+        free(e);
+    }
     free(suite);
 }
 
-void ucx_test_register(UcxTestSuite* suite, UcxTest test) {
-    suite->tests = ucx_list_append(suite->tests, (void*) test);
+int ucx_test_register(UcxTestSuite* suite, UcxTest test) {
+    if (suite->tests) {
+        UcxTestList *newelem = (UcxTestList*) malloc(sizeof(UcxTestList));
+        if (newelem) {
+            newelem->test = test;
+            newelem->next = NULL;
+            
+            UcxTestList *last = suite->tests;
+            while (last->next) {
+                last = last->next;
+            }
+            last->next = newelem;
+            
+            return EXIT_SUCCESS;
+        } else {
+            return EXIT_FAILURE;
+        }
+    } else {
+        suite->tests = (UcxTestList*) malloc(sizeof(UcxTestList));
+        if (suite->tests) {
+            suite->tests->test = test;
+            suite->tests->next = NULL;
+            
+            return EXIT_SUCCESS;
+        } else {
+            return EXIT_FAILURE;
+        }
+    }
 }
 
 void ucx_test_run(UcxTestSuite* suite, FILE* output) {
     suite->success = 0;
     suite->failure = 0;
-    UCX_FOREACH (UcxList*, suite->tests, e) {
-        UcxTest test = (UcxTest) (e->data);
-        test(suite, output);
+    for (UcxTestList* elem = suite->tests ; elem ; elem = elem->next) {
+        elem->test(suite, output);
     }
     fwrite("\nAll test completed.\n", 1, 21, output);
     fprintf(output, "  Total:   %d\n  Success: %d\n  Failure: %d\n",
--- a/ucx/test.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/test.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,90 +1,223 @@
-/* 
- * File:   test.h
- * Author: Mike
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
  *
- * Created on 18. Februar 2012, 14:15
- *
- *
- *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+/**
+ * @file: test.h
+ * 
+ * UCX Test Framework.
+ * 
  * Usage of this test framework:
  *
  * **** IN HEADER FILE: ****
  *
- * UCX_TEST_DECLARE(function_name)
+ * <pre>
+ * UCX_TEST(function_name)
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional
+ * </pre>
  *
  * **** IN SOURCE FILE: ****
+ * <pre>
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) {
+ *   // tests with UCX_TEST_ASSERT()
+ * }
+ * 
+ * UCX_TEST(function_name) {
+ *   // memory allocation and other stuff here
+ *   #UCX_TEST_BEGIN
+ *   // tests with UCX_TEST_ASSERT() and/or
+ *   // calls with UCX_TEST_CALL_SUBROUTINE() here
+ *   #UCX_TEST_END
+ *   // cleanup of memory here
+ * }
+ * </pre>
  *
- * UCX_TEST_IMPLEMENT(function_name) {
- *  <memory allocation and other stuff here>
- *  UCX_TEST_BEGIN
- *  <tests with UCX_TEST_ASSERT here>
- *  UCX_TEST_END
- *  <cleanup of memory here>
- * }
+ * <b>Note:</b> if a test fails, a longjump is performed
+ * back to the #UCX_TEST_BEGIN macro!
+ * 
+ * <b>Attention:</b> Do not call own functions within a test, that use
+ * UCX_TEST_ASSERT() macros and are not defined by using UCX_TEST_SUBROUTINE().
+ * 
  *
- * PLEASE NOTE: if a test fails, a longjump is performed
- * back to the UCX_TEST_BEGIN macro!
- *
- * You may use multiple BEGIN-END blocks if you are aware of the
- * longjmp behaviour.
+ * @author Mike Becker
+ * @author Olaf Wintermann
  *
  */
 
-#ifndef TEST_H
-#define	TEST_H
+#ifndef UCX_TEST_H
+#define	UCX_TEST_H
 
 #include "ucx.h"
 #include <stdio.h>
 #include <string.h>
 #include <setjmp.h>
-#include "list.h"
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 #ifndef __FUNCTION__
+/**
+ * Alias for the <code>__func__</code> preprocessor macro.
+ * Some compilers use <code>__func__</code> and others use __FUNC__.
+ * We use __FUNC__ so we define it for those compilers which use
+ * <code>__func__</code>.
+ */
 #define __FUNCTION__ __func__
 #endif
 
-typedef struct {
-    unsigned int success;
-    unsigned int failure;
-    UcxList *tests;
-} UcxTestSuite;
-
+/** Type for the internal list of test cases. */
+typedef struct UcxTestList UcxTestList;
+/** Type for the UcxTestSuite. */
+typedef struct UcxTestSuite UcxTestSuite;
+/** Pointer to a test function. */
 typedef void(*UcxTest)(UcxTestSuite*,FILE*);
 
+/**
+ * A test suite containing multiple test cases.
+ */
+struct UcxTestSuite {
+    /** The number of successful tests after the suite has been run. */
+    unsigned int success;
+    /** The number of failed tests after the suite has been run. */
+    unsigned int failure;
+    /**
+     * Internal list of test cases.
+     * Use ucx_test_register() to add tests to this list.
+     */
+    UcxTestList *tests;
+};
+
+/**
+ * Creates a new test suite.
+ * @return a new test suite
+ */
 UcxTestSuite* ucx_test_suite_new();
-void ucx_test_suite_free(UcxTestSuite*);
+/**
+ * Destroys a test suite.
+ * @param the test suite to destroy
+ */
+void ucx_test_suite_free(UcxTestSuite* suite);
 
-void ucx_test_register(UcxTestSuite*, UcxTest);
-void ucx_test_run(UcxTestSuite*, FILE*);
+/**
+ * Registers a test function with the specified test suite.
+ * 
+ * @param suite the suite, the test function shall be added to
+ * @param test the test function to register
+ * @return <code>EXIT_SUCCESS</code> on success or
+ * <code>EXIT_FAILURE</code> on failure
+ */
+int ucx_test_register(UcxTestSuite* suite, UcxTest test);
+/**
+ * Runs a test suite and writes the test log to the specified stream.
+ * @param suite the test suite to run
+ * @param outstream the stream the log shall be written to
+ */
+void ucx_test_run(UcxTestSuite* suite, FILE* outstream);
 
-#define UCX_TEST_DECLARE(name) void name(UcxTestSuite*,FILE *)
-#define UCX_TEST_IMPLEMENT(name) void name(UcxTestSuite* _suite_,FILE *_output_)
+/**
+ * Macro for a #UcxTest function header.
+ * 
+ * Use this macro to declare and/or define an #UcxTest function.
+ * 
+ * @param name the name of the test function
+ */
+#define UCX_TEST(name) void name(UcxTestSuite* _suite_,FILE *_output_)
 
+/**
+ * Marks the begin of a test.
+ * <b>Note:</b> Any UCX_TEST_ASSERT() calls must be performed <b>after</b>
+ * #UCX_TEST_BEGIN.
+ * 
+ * @see #UCX_TEST_END
+ */
 #define UCX_TEST_BEGIN fwrite("Running ", 1, 8, _output_);\
         fwrite(__FUNCTION__, 1, strlen(__FUNCTION__), _output_);\
         fwrite("... ", 1, 4, _output_);\
         jmp_buf _env_; \
         if (!setjmp(_env_)) {
 
+/**
+ * Checks a test assertion.
+ * If the assertion is correct, the test carries on. If the assertion is not
+ * correct, the specified message (terminated by a dot and a line break) is
+ * written to the test suites output stream.
+ * @param condition the condition to check
+ * @param message the message that shall be printed out on failure
+ */
 #define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \
         fwrite(message".\n", 1, 2+strlen(message), _output_); \
         _suite_->failure++; \
         longjmp(_env_, 1);\
     }
 
-#define UCX_TEST_SUBROUTINE(name,data) void name(UcxTestSuite* _suite_,\
-        FILE *_output_, jmp_buf _env_, void* data)
-#define UCX_TEST_CALL_SUBROUTINE(name,data) name(_suite_,_output_,_env_,data);
+/**
+ * Macro for a test subroutine function header.
+ * 
+ * Use this to declare and/or define an subroutine that can be called by using
+ * UCX_TEST_CALL_SUBROUTINE().
+ * 
+ * @param name the name of the subroutine
+ * @param ... the parameter list
+ * 
+ * @see UCX_TEST_CALL_SUBROUTINE()
+ */
+#define UCX_TEST_SUBROUTINE(name,...) void name(UcxTestSuite* _suite_,\
+        FILE *_output_, jmp_buf _env_, __VA_ARGS__)
 
+/**
+ * Macro for calling a test subroutine.
+ * 
+ * Subroutines declared with UCX_TEST_SUBROUTINE() can be called by using this
+ * macro.
+ * 
+ * <b>Note:</b> You may <b>only</b> call subroutines within a #UCX_TEST_BEGIN-
+ * #UCX_TEST_END-block.
+ * 
+ * @param name the name of the subroutine
+ * @param ... the argument list
+ * 
+ * @see UCX_TEST_SUBROUTINE()
+ */
+#define UCX_TEST_CALL_SUBROUTINE(name,...) \
+        name(_suite_,_output_,_env_,__VA_ARGS__);
+
+/**
+ * Marks the end of a test.
+ * <b>Note:</b> Any UCX_TEST_ASSERT() calls must be performed <b>before</b>
+ * #UCX_TEST_END.
+ * 
+ * @see #UCX_TEST_BEGIN
+ */
 #define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;}
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* TEST_H */
+#endif	/* UCX_TEST_H */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/ucx.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,37 @@
+/**
+ * @mainpage UAP Common Extensions
+ * Library with common and useful functions, macros and data structures.
+ * <p>
+ * Latest available source:<br/>
+ * <a href="https://develop.uap-core.de/hg/ucx">
+ * https://develop.uap-core.de/hg/ucx</a>
+ * </p>
+ * 
+ * <h2>LICENCE</h2>
+ * 
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ucx.h"
--- a/ucx/ucx.h	Sat Dec 01 20:34:55 2012 +0100
+++ b/ucx/ucx.h	Mon Aug 12 14:40:19 2013 +0200
@@ -1,8 +1,36 @@
-/* 
- * File:   ucx.h
- * Author: olaf
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
  *
- * Created on 31. Dezember 2011, 17:17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * Main UCX Header providing most common definitions.
+ * 
+ * @file   ucx.h
+ * @author Mike Becker
+ * @author Olaf Wintermann
  */
 
 #ifndef UCX_H
@@ -10,37 +38,77 @@
 
 #include <stdlib.h>
 
+#ifdef _WIN32
+#if !(defined __ssize_t_defined || defined _SSIZE_T_)
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#define __ssize_t_defined
+#define _SSIZE_T_
+#endif /* __ssize_t_defined and _SSIZE_T */
+#else /* !_WIN32 */
+#include <sys/types.h>
+#endif /* _WIN32 */
+
 #ifdef	__cplusplus
 #ifndef _Bool
 #define _Bool bool
 #define restrict
 #endif
+#define UCX_EXTERN extern "C"
 extern "C" {
+#else
+#define UCX_EXTERN
 #endif
 
-#define UCX_FOREACH(type,list,elem) \
-        for (type elem = list ; elem != NULL ; elem = elem->next)
-
-#ifdef __cplusplus
-#define ucx_dynarray_new(type,identifier,length)\
-    type* identifier; identifier = new type[length]
-#define ucx_dynarray_free(identifier) delete [] identifier
-#else
-#define ucx_dynarray_new(type,identifier,length)\
-    type identifier[length]
-#define ucx_dynarray_free(identifier)
-#endif
-    
-/* element1,element2,custom data -> {-1,0,1} */
+/**
+ * Function pointer to a compare function.
+ * 
+ * The compare function shall take three arguments: the two values that shall be
+ * compared and optional additional data.
+ * The function shall then return -1 if the first argument is less than the
+ * second argument, 1 if the first argument is greater than the second argument
+ * and 0 if both arguments are equal. If the third argument is
+ * <code>NULL</code>, it shall be ignored.
+ */
 typedef int(*cmp_func)(void*,void*,void*);
 
-/* element,custom data -> copy of element */
+/**
+ * Function pointer to a copy function.
+ * 
+ * The copy function shall create a copy of the first argument and may use
+ * additional data provided by the second argument. If the second argument is
+ * <code>NULL</code>, it shall be ignored.
+
+ * <b>Attention:</b> if pointers returned by functions of this type may be
+ * passed to <code>free()</code> depends on the implementation of the
+ * respective <code>copy_func</code>.
+ */
 typedef void*(*copy_func)(void*,void*);
 
-/* buffer, element size, element count, stream */
+/**
+ * Function pointer to a write function.
+ * 
+ * The signature of the write function shall be compatible to the signature
+ * of standard <code>fwrite</code>, though it may use arbitrary data types for
+ * source and destination.
+ * 
+ * The arguments shall contain (in ascending order): a pointer to the source,
+ * the length of one element, the element count and a pointer to the
+ * destination.
+ */
 typedef size_t(*write_func)(const void*, size_t, size_t, void*);
 
-/* buffer, element size, element count, stream */
+/**
+ * Function pointer to a read function.
+ * 
+ * The signature of the read function shall be compatible to the signature
+ * of standard <code>fread</code>, though it may use arbitrary data types for
+ * source and destination.
+ * 
+ * The arguments shall contain (in ascending order): a pointer to the
+ * destination, the length of one element, the element count and a pointer to
+ * the source.
+ */
 typedef size_t(*read_func)(void*, size_t, size_t, void*);
 
 #ifdef	__cplusplus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/utils.c	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,100 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils.h"
+#include "math.h"
+
+/* COPY FUCNTIONS */
+void* ucx_strcpy(void* s, void* data) {
+    char *str = (char*) s;
+    size_t n = 1+strlen(str);
+    char *cpy = (char*) malloc(n);
+    memcpy(cpy, str, n);
+    return cpy;
+}
+
+void* ucx_memcpy(void* m, void* n) {
+    size_t k = *((size_t*)n);
+    void *cpy = malloc(k);
+    memcpy(cpy, m, k);
+    return cpy;
+}
+
+/* COMPARE FUNCTION */
+
+int ucx_strcmp(void *s1, void *s2, void *data) {
+    return strcmp((char*)s1, (char*)s2);
+}
+
+int ucx_strncmp(void *s1, void *s2, void *n) {
+    return strncmp((char*)s1, (char*)s2, *((size_t*) n));
+}
+
+int ucx_intcmp(void *i1, void *i2, void *data) {
+   int a = *((int*) i1);
+   int b = *((int*) i2);
+   if (a == b) {
+       return 0;
+   } else {
+       return a < b ? -1 : 1;
+   }
+}
+
+int ucx_floatcmp(void *f1, void *f2, void *epsilon) {
+   float a = *((float*) f1);
+   float b = *((float*) f2);
+   float e = !epsilon ? 1e-6f : *((float*)epsilon);
+   if (fabsf(a - b) < e) {
+       return 0;
+   } else {
+       return a < b ? -1 : 1;
+   }
+}
+
+int ucx_doublecmp(void *d1, void *d2, void *epsilon) {
+   double a = *((float*) d1);
+   double b = *((float*) d2);
+   double e = !epsilon ? 1e-14 : *((double*)epsilon);
+   if (fabs(a - b) < e) {
+       return 0;
+   } else {
+       return a < b ? -1 : 1;
+   }
+}
+
+int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) {
+    if (ptr1 == ptr2) {
+        return 0;
+    } else {
+        return ptr1 < ptr2 ? -1 : 1;
+    }
+}
+
+int ucx_memcmp(void *ptr1, void *ptr2, void *n) {
+    return memcmp(ptr1, ptr2, *((size_t*)n));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/utils.h	Mon Aug 12 14:40:19 2013 +0200
@@ -0,0 +1,140 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file utils.h
+ * 
+ * Common utilities like compare and copy functions.
+ * 
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_UTILS_H
+#define	UCX_UTILS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include "ucx.h"
+#include <string.h>
+
+/**
+ * Copies a string.
+ * @param s the string to copy
+ * @param data omitted
+ * @return a pointer to a copy of s1 that can be passed to free(void*)
+ */
+void *ucx_strcpy(void *s, void *data);
+
+/**
+ * Copies a memory area.
+ * @param m a pointer to the memory area
+ * @param n a pointer to the size_t containing the size of the memory area
+ * @return a pointer to a copy of the specified memory area that can
+ * be passed to free(void*)
+ */
+void *ucx_memcpy(void *m, void *n);
+
+/**
+ * Wraps the strcmp function.
+ * @param s1 string one
+ * @param s2 string two
+ * @param data omitted
+ * @return the result of strcmp(s1, s2)
+ */
+int ucx_strcmp(void *s1, void *s2, void *data);
+
+/**
+ * Wraps the strncmp function.
+ * @param s1 string one
+ * @param s2 string two
+ * @param n a pointer to the size_t containing the third strncmp parameter
+ * @return the result of strncmp(s1, s2, *n)
+ */
+int ucx_strncmp(void *s1, void *s2, void *n);
+
+/**
+ * Compares two integers of type int.
+ * @param i1 pointer to integer one
+ * @param i2 pointer to 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_intcmp(void *i1, void *i2, void *data);
+
+/**
+ * Compares two real numbers of type float.
+ * @param f1 pointer to float one
+ * @param f2 pointer to float two
+ * @param if provided: a pointer to precision (default: 1e-6f)
+ * @return -1, if *f1 is less than *f2, 0 if both are equal,
+ * 1 if *f1 is greater than *f2
+ */
+
+int ucx_floatcmp(void *f1, void *f2, void *data);
+
+/**
+ * Compares two real numbers of type double.
+ * @param f1 pointer to double one
+ * @param f2 pointer to double two
+* @param if provided: a pointer to precision (default: 1e-14)
+ * @return -1, if *d1 is less than *d2, 0 if both are equal,
+ * 1 if *d1 is greater than *d2
+ */
+
+int ucx_doublecmp(void *d1, void *d2, void *data);
+
+/**
+ * Compares two pointers.
+ * @param ptr1 pointer one
+ * @param ptr2 pointer two
+ * @param data omitted
+ * @return -1 if ptr1 is less than ptr2, 0 if both are equal,
+ * 1 if ptr1 is greater than ptr2
+ */
+int ucx_ptrcmp(void *ptr1, void *ptr2, void *data);
+
+/**
+ * Compares two memory areas.
+ * @param ptr1 pointer one
+ * @param ptr2 pointer two
+ * @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(void *ptr1, void *ptr2, void *n);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_UTILS_H */
+

mercurial