added existing source code

Fri, 30 Nov 2012 21:18:13 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 30 Nov 2012 21:18:13 +0100
changeset 1
1bcaac272cdf
parent 0
0f94d369bb02
child 2
f7e408d98a83

added existing source code

.hgignore file | annotate | diff | comparison | revisions
Makefile file | annotate | diff | comparison | revisions
dav/Makefile file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
dav/main.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
gcc.mk file | annotate | diff | comparison | revisions
osx.mk 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/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.h file | annotate | diff | comparison | revisions
--- a/.hgignore	Fri Nov 30 21:11:33 2012 +0100
+++ b/.hgignore	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,6 @@
+syntax:regexp
+^nbproject/.*$
+^build/.*$
+core$
+^.c?project$
+^.settings/.*$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,62 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2011 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.
+#
+
+
+#
+# available configurations:
+#   gcc
+#   suncc
+#   windows
+#   osx
+#
+
+#ifndef CONF
+	CONF=gcc
+#endif
+
+include $(CONF).mk
+
+all: build ucx dav
+
+build:
+	mkdir build
+
+ucx: FORCE build
+	cd ucx; $(MAKE) CONF=$(CONF) all
+	
+dav: FORCE ucx
+	cd dav; $(MAKE) CONF=$(CONF) all
+
+run: FORCE dav
+	./build/dav$(APP_EXT)
+
+clean: FORCE
+	$(RM) $(RMFLAGS) build/*.${OBJ_EXT}
+
+FORCE:
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/Makefile	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,51 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2011 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 ../$(CONF).mk
+
+CFLAGS += `xml2-config --cflags`
+LDFLAGS += `curl-config --libs` `xml2-config --libs`
+
+SRC  = main.c
+SRC += propfind.c
+SRC += utils.c
+
+
+OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT))
+
+all: ../build/dav
+
+../build/dav: $(OBJ)
+	$(LD) $(LDFLAGS) $(LOFLAGS)../build/dav$(APP_EXT) $(OBJ) \
+		../build/libucx.$(LIB_EXT)
+
+../build/%.$(OBJ_EXT): %.c ../build
+	$(CC) $(CFLAGS) -I../ $(COFLAGS)$@ $<
+
+../build:
+	mkdir -p build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/main.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,127 @@
+/*
+ * 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 <libxml/xmlerror.h>
+
+#include "propfind.h"
+#include "utils.h"
+#include "main.h"
+
+void xmlerrorfnc(void * ctx, const char * msg, ... ) {
+    // nothing
+}
+
+int main(int argc, char **argv) {
+    xmlGenericErrorFunc fnc = xmlerrorfnc;
+    initGenericErrorDefaultFunc(&fnc);
+    
+    if(argc < 2) {
+        print_usage();
+        return -1;
+    }
+    
+    if(!strcmp(argv[1], "list") || !strcmp(argv[1], "ls")) {
+        return cmd_list(argc - 2, argv + 2);
+    } else if(!strcmp(argv[1], "get")) {
+        return cmd_get(argc - 2, argv + 2);
+    }
+    
+    print_usage();
+    return -1;
+}
+
+void print_usage() {
+    
+}
+
+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);
+    
+    UCX_FOREACH(UcxDlist*, propfind->children, ch) {
+        DavResource *resource = ch->data;
+        printf("%s\n", resource->name);
+    }
+    
+    // TODO: free propfind stuff
+    curl_easy_cleanup(curl);
+    
+    return 0;
+}
+
+int cmd_get(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);
+    
+    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);
+            }
+        }
+    } else {
+        get_file(curl, propfind->url, propfind->resource->name);
+    }
+    
+    // TODO: free propfind stuff
+    curl_easy_cleanup(curl);
+    
+    return 0;
+}
+
+void get_file(CURL *curl, char *url, char *path) {
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+    
+    FILE *out = fopen(path, "w");
+    
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, out);
+    
+    CURLcode res = curl_easy_perform(curl);
+    
+    fclose(out);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/main.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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 MAIN_H
+#define	MAIN_H
+
+#include <curl/curl.h>
+#include "propfind.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+void print_usage();
+int cmd_list(int argc, char **argv);
+int cmd_get(int argc, char **argv);
+
+void get_file(CURL *curl, char *url, char *path);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* MAIN_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/propfind.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,226 @@
+/*
+ * 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");
+    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_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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/propfind.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/utils.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,109 @@
+/*
+ * 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 <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucx/string.h>
+
+#include "utils.h"
+
+
+time_t parse_creationdate(char *str) {
+    // TODO
+    return 1234;
+}
+
+time_t parse_lastmodified(char *str) {
+    // TODO
+    return 1234;
+}
+
+
+char* util_url_path(char *url) { 
+    char *path = NULL;
+    int slashcount = 0;
+    char c;
+    int i = 0;
+    while((c = url[i]) != 0) {
+        if(c == '/') {
+            slashcount++;
+            if(slashcount == 3) {
+                path = url + i;
+                break;
+            }
+        }
+        i++;
+    } 
+    return path;
+}
+
+char* util_resource_name(char *url) {
+    int si = 0;
+    int osi = 0;
+    int i = 0;
+    char c;
+    while((c = url[i]) != 0) {
+        if(c == '/') {
+            osi = si;
+            si = i;
+        }
+        i++;
+    }
+    
+    char *name = url + si + 1;;
+    if(name[0] == 0) {
+        name = url + osi + 1;
+        if(name[0 == 0]) {
+            return url;
+        }
+    }
+    
+    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;
+    }
+    
+    memcpy(url, base, baselen);
+    memcpy(url + baselen, path, pathlen);
+    
+    return url;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/utils.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,53 @@
+/*
+ * 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 UTILS_H
+#define	UTILS_H
+
+#include <sys/types.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+time_t parse_creationdate(char *str);
+time_t parse_lastmodified(char *str);
+
+char* util_url_path(char *url);
+
+char* util_resource_name(char *url);
+
+char* util_child_url(char *url, char *href);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UTILS_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc.mk	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,44 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2011 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.
+#
+
+CC = gcc
+LD = gcc
+AR = ar
+RM = rm
+
+CFLAGS  = -std=gnu99 -g -c
+COFLAGS = -o
+LDFLAGS = 
+LOFLAGS = -o
+ARFLAGS = -r
+RMFLAGS = -f
+
+OBJ_EXT = o
+LIB_EXT = a
+APP_EXT =
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/osx.mk	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,44 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2011 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.
+#
+
+CC = gcc
+LD = gcc
+AR = ar
+RM = rm
+
+CFLAGS  = -std=gnu99 -g -c
+COFLAGS = -o
+LDFLAGS = 
+LOFLAGS = -o
+ARFLAGS = -r
+RMFLAGS = -f
+
+OBJ_EXT = o
+LIB_EXT = a
+APP_EXT =
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/suncc.mk	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,44 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2011 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.
+#
+
+CC = cc
+LD = cc
+AR = ar
+RM = rm
+
+CFLAGS  = -g -c
+COFLAGS = -o
+LDFLAGS =
+LOFLAGS = -o
+ARFLAGS = -r
+RMFLAGS = -f
+
+OBJ_EXT = o
+LIB_EXT = a
+APP_EXT =
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/Makefile	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,53 @@
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2011 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 ../$(CONF).mk
+
+# list of source files
+SRC  = list.c 
+SRC += dlist.c
+SRC += map.c
+SRC += mempool.c
+SRC += string.c
+SRC += test.c
+SRC += allocator.c
+SRC += logging.c
+SRC += buffer.c
+
+OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT))
+
+all: libucx
+
+libucx: $(OBJ)
+	$(AR) $(ARFLAGS) $(AOFLAGS)../build/libucx.$(LIB_EXT) $(OBJ)
+
+../build/%.$(OBJ_EXT): %.c ../build
+	$(CC) $(CFLAGS) $(COFLAGS)$@ $<
+
+../build:
+	mkdir -p ../build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/allocator.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include "allocator.h"
+
+void *ucx_default_malloc(void *ignore, size_t n) {
+    return malloc(n);
+}
+
+void *ucx_default_calloc(void *ignore, size_t n, size_t size) {
+    return calloc(n, size);
+}
+
+void *ucx_default_realloc(void *ignore, void *data, size_t n) {
+    return realloc(data, n);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/allocator.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,33 @@
+#ifndef ALLOCATOR_H
+#define	ALLOCATOR_H
+
+#include "ucx.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef void*(*ucx_allocator_malloc)(void *pool, size_t n);
+typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size);
+typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n);
+
+typedef struct {
+    void *pool;
+    ucx_allocator_malloc malloc;
+    ucx_allocator_calloc calloc;
+    ucx_allocator_realloc realloc;
+} UcxAllocator;
+
+void *ucx_default_malloc(void *ignore, size_t n);
+void *ucx_default_calloc(void *ignore, size_t n, size_t size);
+void *ucx_default_realloc(void *ignore, void *data, size_t n);
+
+#define UCX_ALLOCATOR_DEFAULT {NULL, \
+        ucx_default_malloc, ucx_default_calloc, ucx_default_realloc}
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* ALLOCATOR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/buffer.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,204 @@
+#include "buffer.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags) {
+    UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer));
+    if (buffer) {
+        buffer->flags = flags;
+        if (!space) {
+            buffer->space = malloc(size);
+            if (!buffer->space) {
+                free(buffer);
+                return NULL;
+            }
+            memset(buffer->space, 0, size);
+            buffer->flags |= UCX_BUFFER_AUTOFREE;
+        } else {
+            buffer->space = space;
+        }
+        buffer->capacity = size;
+        buffer->size = 0;
+
+        buffer->pos = 0;
+    }
+
+    return buffer;
+}
+
+void ucx_buffer_free(UcxBuffer *buffer) {
+    if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) {
+        free(buffer->space);
+    }
+    free(buffer);
+}
+
+UcxBuffer* ucx_buffer_extract(
+        UcxBuffer *src, size_t start, size_t length, int flags) {
+    if(src->size == 0) {
+        return NULL;
+    }
+    if (length == 0) {
+        length = src->size - start;
+    }
+    if (start+length > src->size) {
+        return NULL;
+    }
+
+    UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer));
+    if (dst) {
+        dst->space = malloc(length);
+        if (!dst->space) {
+            free(dst);
+            return NULL;
+        }
+        dst->capacity = length;
+        dst->size = length;
+        dst->flags = flags | UCX_BUFFER_AUTOFREE;
+        dst->pos = 0;
+        memcpy(dst->space, src->space+start, length);
+    }
+    return dst;
+}
+
+int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) {
+    off_t npos;
+    switch (whence) {
+    case SEEK_SET:
+        npos = 0;
+        break;
+    case SEEK_CUR:
+        npos = buffer->pos;
+        break;
+    case SEEK_END:
+        npos = buffer->size;
+        break;
+    }
+
+    npos += offset;
+    
+    if (npos < 0 || npos > buffer->size) {
+        return -1;
+    } else {
+        buffer->pos = npos;
+        return 0;
+    }
+
+}
+
+int ucx_buffer_eof(UcxBuffer *buffer) {
+    return buffer->pos >= buffer->size;
+}
+
+int ucx_buffer_extend(UcxBuffer *buffer, size_t len) {
+    size_t newcap = buffer->capacity;
+    while (buffer->pos + len > newcap) newcap <<= 1;
+    
+    char *newspace = realloc(buffer->space, newcap);
+    if (newspace) {
+        memset(newspace+buffer->size, 0, newcap-buffer->size);
+        buffer->space = newspace;
+        buffer->capacity = newcap;
+    } else {
+        return -1;
+    }
+    
+    return 0;
+}
+
+size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer) {
+    size_t len = size * nitems;
+    if (buffer->pos + len > buffer->capacity) {
+        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
+            if(ucx_buffer_extend(buffer, len)) {
+                return -1;
+            }
+        } else {
+            len = buffer->capacity - buffer->pos;
+            if (size > 1) len -= len%size;
+        }
+    }
+    
+    if (len <= 0) {
+        return len;
+    }
+    
+    memcpy(buffer->space + buffer->pos, ptr, len);
+    buffer->pos += len;
+    if(buffer->pos > buffer->size) {
+        buffer->size = buffer->pos;
+    }
+    
+    return len / size;
+}
+
+size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer) {
+    size_t len = size * nitems;
+    if (buffer->pos + len > buffer->size) {
+        len = buffer->size - buffer->pos;
+        if (size > 1) len -= len%size;
+    }
+    
+    if (len <= 0) {
+        return len;
+    }
+    
+    memcpy(ptr, buffer->space + buffer->pos, len);
+    buffer->pos += len;
+    
+    return len / size;
+}
+
+int ucx_buffer_putc(UcxBuffer *buffer, int c) {
+    if(buffer->pos >= buffer->capacity) {
+        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
+            if(ucx_buffer_extend(buffer, 1)) {
+                return EOF;
+            }
+        } else {
+            return EOF;
+        }
+    }
+    
+    c &= 0xFF;
+    buffer->space[buffer->pos] = (char) c;
+    buffer->pos++;
+    if(buffer->pos > buffer->size) {
+        buffer->size = buffer->pos;
+    }
+    return c;
+}
+
+int ucx_buffer_getc(UcxBuffer *buffer) {
+    if (ucx_buffer_eof(buffer)) {
+        return EOF;
+    } else {
+        int c = buffer->space[buffer->pos];
+        buffer->pos++;
+        return c;
+    }
+}
+
+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);
+    if(buf == NULL) {
+        return 0;
+    }
+    
+    size_t r;
+    while((r = readfnc(buf, 1, bufsize, s1)) != 0) {
+        r = writefnc(buf, 1, r, s2);
+        ncp += r;
+        if(r == 0) {
+            break;
+        }
+    }
+    
+    free(buf);
+    return ncp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/buffer.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,100 @@
+#ifndef BUFFER_H
+#define	BUFFER_H
+
+#include "ucx.h"
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define UCX_BUFFER_DEFAULT      0x00
+#define UCX_BUFFER_AUTOFREE     0x01
+/* the buffer may automatically double its size on write operations */
+#define UCX_BUFFER_AUTOEXTEND   0x02
+
+/* the user shall not modify values, but may get the latest pointer */
+typedef struct {
+    char *space;
+    size_t pos;
+    size_t capacity;
+    size_t size;
+    int flags;
+} UcxBuffer;
+
+/* if space is NULL, new space is allocated and the autofree flag is enforced */
+UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags);
+void ucx_buffer_free(UcxBuffer* buffer);
+
+/*
+ * the autofree flag is enforced for the new buffer
+ * if length is zero, the whole remaining buffer shall be extracted
+ * the position of the new buffer is set to zero
+ */
+UcxBuffer* ucx_buffer_extract(UcxBuffer *src,
+        size_t start, size_t length, int flags);
+#define ucx_buffer_clone(src,flags) \
+    ucx_buffer_extract(src, 0, 0, flags)
+
+/*
+ * Moves the position of the buffer to a new position relative to whence.
+ *
+ * SEEK_SET marks the start of the buffer
+ * 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
+ * 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);
+
+/*
+ * returns non-zero, if the current buffer position has exceeded the last
+ * available byte of the underlying buffer
+ *
+ */
+int ucx_buffer_eof(UcxBuffer *buffer);
+
+
+int ucx_buffere_extend(UcxBuffer *buffer, size_t len);
+
+size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer);
+
+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);
+
+
+/*
+ * copies all bytes from s1 to s2
+ * uses the read function r to read from s1 und writes the data using the
+ * write function w to s2
+ * returns the number of bytes copied
+ */
+size_t ucx_buffer_generic_copy(void *s1, void *s2, read_func r, write_func w,
+        size_t bufsize);
+
+
+#define UCX_DEFAULT_BUFFER_SIZE 0x4000000
+
+#define ucx_buffer_copy(s1,s2,r,w) \
+    ucx_buffer_generic_copy(s1, s2, (read_func)r, (write_func)w, \
+    UCX_DEFAULT_BUFFER_SIZE)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* BUFFER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/dlist.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,234 @@
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/dlist.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,46 @@
+/* 
+ * 
+ */
+
+#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 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/list.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,219 @@
+#include "list.h"
+
+UcxList *restrict ucx_list_clone(UcxList *restrict l,
+        copy_func fnc, void *data) {
+    UcxList *ret = NULL;
+    while (l != NULL) {
+        if (fnc != NULL) {
+            ret = ucx_list_append(ret, fnc(l->data, data));
+        } else {
+            ret = ucx_list_append(ret, l->data);
+        }
+        l = l->next;
+    }
+    return ret;
+}
+
+int ucx_list_equals(const UcxList *l1, const UcxList *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_list_free(UcxList *l) {
+    UcxList *e = l, *f;
+    while (e != NULL) {
+        f = e;
+        e = e->next;
+        free(f);
+    }
+}
+
+UcxList *ucx_list_append(UcxList *l, void *data)  {
+    UcxList *nl = (UcxList*) malloc(sizeof(UcxList));
+    if (nl == NULL) return NULL;
+    
+    nl->data = data;
+    nl->next = NULL;
+    if (l == NULL) {
+        return nl;
+    } else {
+        UcxList *t = ucx_list_last(l);
+        t->next = nl;
+        return l;
+    }
+}
+
+UcxList *ucx_list_prepend(UcxList *l, void *data) {
+    UcxList *nl = ucx_list_append(NULL, data);
+    if (nl == NULL) return NULL;
+    
+    if (l != NULL) {
+        nl->next = l;
+    }
+    return nl;
+}
+
+UcxList *ucx_list_concat(UcxList *restrict l1, UcxList *restrict l2) {
+    if (l1 == NULL) {
+        return l2;
+    } else {
+        UcxList *last = ucx_list_last(l1);
+        last->next = l2;
+        return l1;
+    }
+}
+
+UcxList *ucx_list_last(const UcxList *l) {
+    if (l == NULL) return NULL;
+    
+    const UcxList *e = l;
+    while (e->next != NULL) {
+        e = e->next;
+    }
+    return (UcxList*)e;
+}
+
+UcxList *ucx_list_get(const UcxList *l, int index) {
+    if (l == NULL) return NULL;
+
+    const UcxList *e = l;
+    while (e->next != NULL && index > 0) {
+        e = e->next;
+        index--;
+    }
+    
+    return (UcxList*)(index == 0 ? e : NULL);
+}
+
+size_t ucx_list_size(const UcxList *l) {
+    if (l == NULL) return 0;
+    
+    const UcxList *e = l;
+    size_t s = 1;
+    while (e->next != NULL) {
+        e = e->next;
+        s++;
+    }
+
+    return s;
+}
+
+UcxList *ucx_list_sort_merge(int length,
+        UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re,
+        cmp_func fnc, void* data) {
+
+    UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length);
+    UcxList *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
+    for (int i = 0 ; i < length-1 ; i++) {
+        sorted[i]->next = sorted[i+1];
+    }
+    sorted[length-1]->next = NULL;
+
+    UcxList *ret = sorted[0];
+    free(sorted);
+    return ret;
+}
+
+UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) {
+    if (l == NULL) {
+        return NULL;
+    }
+
+    UcxList *lc;
+    int ln = 1;
+
+    UcxList *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 {
+        UcxList *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!
+        UcxList *remainder = re;
+        size_t remainder_length = ucx_list_size(remainder);
+        if (remainder != NULL) {
+            remainder = ucx_list_sort(remainder, fnc, data);
+        }
+
+        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
+        UcxList *sorted = ucx_list_sort_merge(ln+rn,
+                ls, le, re,
+                fnc, data);
+
+        // merge sorted list with (also sorted) remainder
+        l = ucx_list_sort_merge(ln+rn+remainder_length,
+                sorted, remainder, NULL, fnc, data);
+
+        return l;
+    }
+}
+
+/* list specific functions */
+UcxList *ucx_list_remove(UcxList *l, UcxList *e) {
+    if (e == l) {
+        l = e->next;
+        free(e);
+    } 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);
+        }
+    }
+    return l;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/list.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,44 @@
+/*
+ * 
+ */
+
+#ifndef LIST_H
+#define	LIST_H
+
+#include "ucx.h"
+#include <stddef.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+    
+typedef struct UcxList UcxList;
+struct UcxList {
+    void    *data;
+    UcxList *next;
+};
+
+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);
+
+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);
+
+UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data);
+
+/* list specific functions */
+UcxList *ucx_list_remove(UcxList *l, UcxList *e);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* LIST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/logging.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,20 @@
+#include "logging.h"
+#include <stdlib.h>
+
+UcxLogger *ucx_logger_new(FILE *stream, unsigned int level) {
+    UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger));
+    if (logger != NULL) {
+        logger->stream = stream;
+        logger->level = level;
+    }
+
+    return logger;
+}
+
+void ucx_logger_log(UcxLogger *logger, unsigned int level,
+        const sstr_t message) {
+    if (level <= logger->level) {
+        fwrite(message.ptr, 1, message.length, logger->stream);
+        fflush(logger->stream);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/logging.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,37 @@
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include "ucx.h"
+#include "string.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#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
+
+typedef struct {
+    FILE *stream;
+    unsigned int level;
+} UcxLogger;
+
+UcxLogger *ucx_logger_new(FILE *stream, unsigned int level);
+/* neither provide a free function nor a parameter for an allocator */
+
+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)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOGGING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/map.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,390 @@
+/*
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "map.h"
+
+UcxMap *ucx_map_new(size_t size) {
+    if(size == 0) {
+        size = 16;
+    }
+    
+    UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap));
+    if(map == NULL) {
+        return NULL;
+    }
+
+    map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*));
+    if(map->map == NULL) {
+        free(map);
+        return NULL;
+    }
+    map->size = size;
+    map->count = 0;
+
+    return map;
+}
+
+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);
+                elem = next;
+            } while (elem != NULL);
+        }
+    }
+    free(map->map);
+}
+
+void ucx_map_free(UcxMap *map) {
+    ucx_map_free_elmlist(map);
+    free(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) {
+        int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value);
+        if(ret != 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) {
+    size_t bs = (map->count * 5) >> 1;
+    UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size);
+    if(newmap == NULL) {
+        return NULL;
+    }
+    ucx_map_copy(map, newmap, fnc, data);
+    return newmap;
+}
+
+int ucx_map_rehash(UcxMap *map) {
+    size_t load = (map->size * 3) >> 2;
+    if (map->count > load) {
+        UcxMap oldmap;
+        oldmap.map = map->map;
+        oldmap.size = map->size;
+        oldmap.count = map->count;
+        
+        map->size = (map->count * 5) >> 1;
+        map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*));
+        if(map->map == NULL) {
+            *map = oldmap;
+            return 1;
+        }
+        map->count = 0;
+        ucx_map_copy(&oldmap, map, NULL, NULL);
+        
+        /* free the UcxMapElement list of oldmap */
+        ucx_map_free_elmlist(&oldmap);
+    }
+    return 0;
+}
+
+int ucx_map_put(UcxMap *map, UcxKey key, void *data) {
+    if(key.hash == 0) {
+        key.hash = ucx_hash((char*)key.data, key.len);
+    }
+
+    size_t slot = key.hash%map->size;
+    UcxMapElement *restrict elm = map->map[slot];
+    UcxMapElement *restrict prev = NULL;
+
+    while (elm != NULL && elm->key.hash < key.hash) {
+        prev = elm;
+        elm = elm->next;
+    }
+    
+    if (elm == NULL || elm->key.hash != key.hash) {
+        UcxMapElement *e = (UcxMapElement*)malloc(sizeof(UcxMapElement));
+        if(e == NULL) {
+            return -1;
+        }
+        e->key.data = NULL;
+        if (prev) {
+            prev->next = e;
+        } else {
+            map->map[slot] = e;
+        }
+        e->next = elm;
+        elm = e;
+    }
+    
+    if(elm->key.data == NULL) {
+        void *kd = malloc(key.len);
+        if (kd == NULL) {
+            return -1;
+        }
+        memcpy(kd, key.data, key.len);
+        key.data = kd;
+        elm->key = key;
+        map->count++;
+    }
+    elm->data = data;
+
+    return 0;
+}
+
+void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) {
+    if(key.hash == 0) {
+        key.hash = ucx_hash((char*)key.data, key.len);
+    }
+    
+    size_t slot = key.hash%map->size;
+    UcxMapElement *restrict elm = map->map[slot];
+    UcxMapElement *restrict pelm = NULL;
+    while (elm && elm->key.hash <= key.hash) {
+        if(elm->key.hash == key.hash) {
+            int n = (key.len > elm->key.len) ? elm->key.len : key.len;
+            if (memcmp(elm->key.data, key.data, n) == 0) {
+                void *data = elm->data;
+                if (remove) {
+                    if (pelm) {
+                        pelm->next = elm->next;
+                    } else {
+                        map->map[slot] = elm->next;
+                    }
+                    free(elm);
+                    map->count--;
+                }
+
+                return data;
+            }
+        }
+        pelm = elm;
+        elm = pelm->next;
+    }
+
+    return NULL;
+}
+
+void *ucx_map_get(UcxMap *map, UcxKey key) {
+    return ucx_map_get_and_remove(map, key, 0);
+}
+
+void *ucx_map_remove(UcxMap *map, UcxKey key) {
+    return ucx_map_get_and_remove(map, key, 1);
+}
+
+UcxKey ucx_key(void *data, size_t len) {
+    UcxKey key;
+    key.data = data;
+    key.len = len;
+    key.hash = ucx_hash((const char*) data, len);
+    return key;
+}
+
+
+int ucx_hash(const char *data, size_t len) {
+    /* murmur hash 2 */
+
+    int m = 0x5bd1e995;
+    int r = 24;
+
+    int h = 25 ^ len;
+
+    int i = 0;
+    while (len >= 4) {
+        int k = data[i + 0] & 0xFF;
+        k |= (data[i + 1] & 0xFF) << 8;
+        k |= (data[i + 2] & 0xFF) << 16;
+        k |= (data[i + 3] & 0xFF) << 24;
+
+        k *= m;
+        k ^= k >> r;
+        k *= m;
+
+        h *= m;
+        h ^= k;
+
+        i += 4;
+        len -= 4;
+    }
+
+    switch (len) {
+        case 3: h ^= (data[i + 2] & 0xFF) << 16;
+        /* no break */
+        case 2: h ^= (data[i + 1] & 0xFF) << 8;
+        /* no break */
+        case 1: h ^= (data[i + 0] & 0xFF); h *= m;
+        /* no break */
+    }
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+}
+
+UcxMapIterator ucx_map_iterator(UcxMap *map) {
+    UcxMapIterator i;
+    i.map = map;
+    i.cur = NULL;
+    i.index = 0;
+    return i;
+}
+
+int ucx_map_iter_next(UcxMapIterator *i, void **elm) {
+    UcxMapElement *e = i->cur;
+    
+    if(e == NULL) {
+        e = i->map->map[0];
+    } else {
+        e = e->next;
+    }
+    
+    while(i->index < i->map->size) {
+        if(e != NULL) {
+            if(e->data != NULL) {
+                i->cur = e;
+                *elm = e->data;
+                return 0;
+            }
+
+            e = e->next;
+        } else {
+            i->index++;
+            
+            if(i->index < i->map->size) {
+                e = i->map->map[i->index];
+            }
+        }
+    }
+    
+    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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/map.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,106 @@
+/*
+ * 
+ */
+
+#ifndef MAP_H
+#define	MAP_H
+
+#include "ucx.h"
+#include "string.h"
+#include "mempool.h"
+#include <stdio.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define UCX_MAP_FOREACH(elm,iter) \
+        for(;ucx_map_iter_next(&iter,(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 {
+    UcxMapElement **map;
+    size_t        size;
+    size_t        count;
+};
+
+struct UcxKey {
+    void   *data;
+    size_t len;
+    int    hash;
+};
+
+struct UcxMapElement {
+    void          *data;
+    UcxMapElement *next;
+    UcxKey        key;
+};
+
+struct UcxMapIterator {
+    UcxMap        *map;
+    UcxMapElement *cur;
+    int           index;
+};
+
+
+UcxMap *ucx_map_new(size_t size);
+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);
+UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data);
+int ucx_map_rehash(UcxMap *map);
+
+int ucx_map_put(UcxMap *map, UcxKey key, void *data);
+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)))
+
+UcxKey ucx_key(void *data, size_t len);
+
+int ucx_hash(const char *data, size_t len);
+
+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_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 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/mempool.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,120 @@
+/*
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "mempool.h"
+
+typedef struct {
+    ucx_destructor destructor;
+    char c;
+} ucx_memchunk;
+
+typedef struct {
+    ucx_destructor destructor;
+    void           *ptr;
+} ucx_regdestr;
+
+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;
+    
+    pool->data = (void**) malloc(n * sizeof(void*));
+    if (pool->data == NULL) {
+        free(pool);
+        return NULL;
+    }
+    
+    pool->ndata = 0;
+    pool->size = n;
+    return pool;
+}
+
+int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) {
+    void **data = (void**) realloc(pool->data, newcap*sizeof(void*));
+    if (data == NULL) {
+        return 1;
+    } else {
+        pool->data = data; 
+        pool->size = newcap;
+        return EXIT_SUCCESS;
+    }
+}
+
+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 (pool->ndata >= pool->size) {
+        ucx_mempool_chcap(pool, pool->size + 16);
+     }
+
+    mem->destructor = NULL;
+    pool->data[pool->ndata] = mem;
+    pool->ndata++;
+
+    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) {
+        return NULL;
+    }
+    memset(ptr, 0, nelem * elsize);
+    return ptr;
+}
+
+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 (mem != newm) {
+        for(int 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",
+          (intptr_t)ptr, (intptr_t)pool);
+        exit(1);
+    } else {
+        return newm + sizeof(ucx_destructor);
+    }
+}
+
+void ucx_mempool_free(UcxMempool *pool) {
+    ucx_memchunk *chunk;
+    for(int i=0;i<pool->ndata;i++) {
+        chunk = (ucx_memchunk*) pool->data[i];
+        if(chunk->destructor != NULL) {
+            chunk->destructor(&chunk->c);
+        }
+        free(chunk);
+    }
+    free(pool->data);
+    free(pool);
+}
+
+void ucx_mempool_set_destr(void *ptr, ucx_destructor func) {
+    *(ucx_destructor*)((char*)ptr-sizeof(ucx_destructor)) = func;
+}
+
+void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr) {
+    ucx_regdestr *rd = (ucx_regdestr*)ucx_mempool_malloc(
+            pool,
+            sizeof(ucx_regdestr));
+    rd->destructor = destr;
+    rd->ptr = ptr;
+    ucx_mempool_set_destr(rd, ucx_mempool_shared_destr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/mempool.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,48 @@
+/* 
+ *
+ */
+
+#ifndef MPOOL_H
+#define	MPOOL_H
+
+#include "ucx.h"
+#include <stddef.h>
+#include "allocator.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef void(*ucx_destructor)(void*);
+
+typedef struct {
+    void   **data;
+    size_t ndata;
+    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}
+
+#define ucx_mempool_new_default() ucx_mempool_new(16)
+UcxMempool *ucx_mempool_new(size_t n);
+int ucx_mempool_chcap(UcxMempool *pool, size_t newcap);
+
+void *ucx_mempool_malloc(UcxMempool *pool, size_t n);
+void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize);
+void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n);
+
+void ucx_mempool_free(UcxMempool *pool);
+
+void ucx_mempool_set_destr(void *ptr, ucx_destructor func);
+void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* MPOOL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/string.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,172 @@
+/*
+ * File:   sstring.c
+ * Author: olaf
+ *
+ * Created on 17. Juni 2010, 13:27
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "string.h"
+
+sstr_t sstr(char *s) {
+    sstr_t string;
+    string.ptr = s;
+    string.length = strlen(s);
+    return string;
+}
+
+sstr_t sstrn(char *s, size_t n) {
+    sstr_t string;
+    string.ptr = s;
+    string.length = n;
+    return string;
+}
+
+size_t sstrnlen(size_t n, sstr_t s, ...) {
+    va_list ap;
+    size_t size = s.length;
+    va_start(ap, s);
+
+    for (int i=0;i<n-1;i++) {
+        sstr_t str = va_arg(ap, sstr_t);
+        size += str.length;
+    }
+    va_end(ap);
+
+    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, ...) {
+    va_list ap;
+    va_start(ap, c1);
+    s.ptr[0] = 0;
+    
+    size_t len = s.length;
+    size_t cplen = c1.length > len ? len : c1.length;
+    char   *ptr = s.ptr;
+    
+    memcpy(ptr, c1.ptr, cplen);
+    len -= cplen;
+    ptr += cplen;
+    for (int i=0;i<n-1;i++) {
+        sstr_t str = va_arg (ap, sstr_t);
+        cplen = str.length > len ? len : str.length;
+        if(cplen <= 0) {
+            va_end(ap);
+            return s;
+        }
+        memcpy(ptr, str.ptr, cplen);
+        len -= cplen;
+        ptr += cplen;
+    }
+    va_end(ap);
+
+    return s;
+}
+
+sstr_t sstrsubs(sstr_t s, size_t start) {
+    return sstrsubsl (s, start, s.length-start);
+}
+
+sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) {
+    sstr_t new_sstr;
+    if (start < 0 || start >= s.length || length < 0) {
+        return s;
+    }
+    if (length > s.length-start) {
+        length = s.length-start;
+    }
+    new_sstr.ptr = &s.ptr[start];
+    new_sstr.length = length;
+    return new_sstr;
+}
+
+sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) {
+    if (d.length == 0) {
+        return NULL;
+    }
+
+    sstr_t* result;
+    size_t nmax = *n;
+    *n = 1;
+
+    /* special case: exact match - no processing needed */
+    if (s.length == d.length && strncmp(s.ptr, d.ptr, s.length) == 0) {
+        *n = 0;
+        return NULL;
+    }
+    sstr_t sv = sstrdup(s);
+
+    for (int i = 0 ; i < s.length ; i++) {
+        if (sv.ptr[i] == d.ptr[0]) {
+            _Bool match = 1;
+            for (int j = 1 ; j < d.length ; j++) {
+                if (j+i < s.length) {
+                    match &= (sv.ptr[i+j] == d.ptr[j]);
+                } else {
+                    match = 0;
+                    break;
+                }
+            }
+            if (match) {
+                (*n)++;
+                for (int j = 0 ; j < d.length ; j++) {
+                    sv.ptr[i+j] = 0;
+                }
+                i += d.length;
+            }
+        }
+        if ((*n) == nmax) break;
+    }
+    result = (sstr_t*) malloc(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;
+
+        result[i] = sstrn(ptr, l);
+        pptr += l + d.length;
+    }
+
+    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);
+}
+
+sstr_t sstrdup(sstr_t s) {
+    sstr_t newstring;
+    newstring.ptr = (char*) malloc(s.length + 1);
+    if (newstring.ptr != NULL) {
+        newstring.length = s.length;
+        newstring.ptr[newstring.length] = 0;
+
+        memcpy(newstring.ptr, s.ptr, s.length);
+    }
+
+    return newstring;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/string.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,99 @@
+/*
+ * File:   sstring.h
+ * Author: olaf
+ *
+ * Created on 17. Juni 2010, 13:26
+ */
+
+#ifndef _SSTRING_H
+#define	_SSTRING_H
+
+#include "ucx.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)
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct sstring {
+    char   *ptr;
+    size_t length;
+} sstr_t;
+
+/*
+ * creates a new sstr_t from a null terminated string
+ *
+ * s  null terminated string
+ */
+sstr_t sstr(char *s);
+
+/*
+ * creates a new sstr_t from a string and length
+ *
+ * s  string
+ * n  length of string
+ */
+sstr_t sstrn(char *s, size_t n);
+
+
+/*
+ * gets the length of n sstr_t strings
+ *
+ * n    number of strings
+ * s    string
+ * ...  strings
+ */
+size_t sstrnlen(size_t n, sstr_t s, ...);
+
+
+/*
+ * concatenates n strings
+ *
+ * n    number of strings
+ * s    new string with enough memory allocated
+ * ...  strings
+ */
+sstr_t sstrncat(size_t n, sstr_t s, sstr_t c1, ...);
+
+
+/*
+ *
+ */
+sstr_t sstrsubs(sstr_t s, size_t start);
+
+/*
+ *
+ */
+sstr_t sstrsubsl(sstr_t s, size_t start, size_t length);
+
+/*
+ * splits s into n parts
+ *
+ * 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
+ */
+sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n);
+
+int sstrcmp(sstr_t s1, sstr_t s2);
+
+sstr_t sstrdup(sstr_t s);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SSTRING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/test.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,39 @@
+/* 
+ * File:   test.c
+ * Author: Mike
+ *
+ * Created on 18. Februar 2012, 14:15
+ */
+
+#include "test.h"
+
+UcxTestSuite* ucx_test_suite_new() {
+    UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite));
+    if (suite != NULL) {
+        suite->success = 0;
+        suite->failure = 0;
+        suite->tests = NULL;
+    }
+    return suite;
+}
+
+void ucx_test_suite_free(UcxTestSuite* suite) {
+    ucx_list_free(suite->tests);
+    free(suite);
+}
+
+void ucx_test_register(UcxTestSuite* suite, UcxTest test) {
+    suite->tests = ucx_list_append(suite->tests, (void*) test);
+}
+
+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);
+    }
+    fwrite("\nAll test completed.\n", 1, 21, output);
+    fprintf(output, "  Total:   %d\n  Success: %d\n  Failure: %d\n",
+            suite->success+suite->failure, suite->success, suite->failure);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/test.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,90 @@
+/* 
+ * File:   test.h
+ * Author: Mike
+ *
+ * Created on 18. Februar 2012, 14:15
+ *
+ *
+ *
+ * Usage of this test framework:
+ *
+ * **** IN HEADER FILE: ****
+ *
+ * UCX_TEST_DECLARE(function_name)
+ *
+ * **** IN SOURCE FILE: ****
+ *
+ * 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>
+ * }
+ *
+ * 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.
+ *
+ */
+
+#ifndef TEST_H
+#define	TEST_H
+
+#include "ucx.h"
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include "list.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ __func__
+#endif
+
+typedef struct {
+    unsigned int success;
+    unsigned int failure;
+    UcxList *tests;
+} UcxTestSuite;
+
+typedef void(*UcxTest)(UcxTestSuite*,FILE*);
+
+UcxTestSuite* ucx_test_suite_new();
+void ucx_test_suite_free(UcxTestSuite*);
+
+void ucx_test_register(UcxTestSuite*, UcxTest);
+void ucx_test_run(UcxTestSuite*, FILE*);
+
+#define UCX_TEST_DECLARE(name) void name(UcxTestSuite*,FILE *)
+#define UCX_TEST_IMPLEMENT(name) void name(UcxTestSuite* _suite_,FILE *_output_)
+
+#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_)) {
+
+#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);
+
+#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;}
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* TEST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/ucx.h	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,51 @@
+/* 
+ * File:   ucx.h
+ * Author: olaf
+ *
+ * Created on 31. Dezember 2011, 17:17
+ */
+
+#ifndef UCX_H
+#define	UCX_H
+
+#include <stdlib.h>
+
+#ifdef	__cplusplus
+#ifndef _Bool
+#define _Bool bool
+#define restrict
+#endif
+extern "C" {
+#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} */
+typedef int(*cmp_func)(void*,void*,void*);
+
+/* element,custom data -> copy of element */
+typedef void*(*copy_func)(void*,void*);
+
+/* buffer, element size, element count, stream */
+typedef size_t(*write_func)(const void*, size_t, size_t, void*);
+
+/* buffer, element size, element count, stream */
+typedef size_t(*read_func)(void*, size_t, size_t, void*);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_H */
+

mercurial