ucx update

Sun, 08 Sep 2013 23:27:07 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 08 Sep 2013 23:27:07 +0200
changeset 91
fac51f87def0
parent 90
279f343bbf6c
child 92
382bff43c6eb

ucx update

Makefile file | annotate | diff | comparison | revisions
make/clang.mk file | annotate | diff | comparison | revisions
make/gcc.mk file | annotate | diff | comparison | revisions
make/install.mk file | annotate | diff | comparison | revisions
make/linux.mk file | annotate | diff | comparison | revisions
make/osx.mk file | annotate | diff | comparison | revisions
make/solaris.mk file | annotate | diff | comparison | revisions
make/suncc.mk file | annotate | diff | comparison | revisions
src/Makefile file | annotate | diff | comparison | revisions
src/server/Makefile file | annotate | diff | comparison | revisions
src/server/config/acl.c file | annotate | diff | comparison | revisions
src/server/config/conf.c file | annotate | diff | comparison | revisions
src/server/config/conf.h file | annotate | diff | comparison | revisions
src/server/config/initconf.c file | annotate | diff | comparison | revisions
src/server/config/initconf.h file | annotate | diff | comparison | revisions
src/server/config/keyfile.c file | annotate | diff | comparison | revisions
src/server/config/mimeconf.c file | annotate | diff | comparison | revisions
src/server/config/objconf.c file | annotate | diff | comparison | revisions
src/server/config/objconf.h file | annotate | diff | comparison | revisions
src/server/config/serverconf.c file | annotate | diff | comparison | revisions
src/server/config/serverconf.h file | annotate | diff | comparison | revisions
src/server/daemon/acldata.h file | annotate | diff | comparison | revisions
src/server/daemon/auth.c file | annotate | diff | comparison | revisions
src/server/daemon/auth.h file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/configmanager.c file | annotate | diff | comparison | revisions
src/server/daemon/configmanager.h file | annotate | diff | comparison | revisions
src/server/daemon/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/keyfile_auth.h file | annotate | diff | comparison | revisions
src/server/daemon/ldap_auth.c file | annotate | diff | comparison | revisions
src/server/daemon/log.c file | annotate | diff | comparison | revisions
src/server/daemon/log.h file | annotate | diff | comparison | revisions
src/server/public/webdav.h file | annotate | diff | comparison | revisions
src/server/util/object.c file | annotate | diff | comparison | revisions
src/server/util/pool.c file | annotate | diff | comparison | revisions
src/server/util/pool.h file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
src/server/webdav/davparser.cpp file | annotate | diff | comparison | revisions
src/server/webdav/davparser.h file | annotate | diff | comparison | revisions
src/server/webdav/parser.c file | annotate | diff | comparison | revisions
src/server/webdav/saxhandler.cpp file | annotate | diff | comparison | revisions
src/server/webdav/saxhandler.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
src/server/webdav/webdav.h file | annotate | diff | comparison | revisions
src/ucx/Makefile file | annotate | diff | comparison | revisions
src/ucx/allocator.c file | annotate | diff | comparison | revisions
src/ucx/allocator.h file | annotate | diff | comparison | revisions
src/ucx/buffer.c file | annotate | diff | comparison | revisions
src/ucx/buffer.h file | annotate | diff | comparison | revisions
src/ucx/list.c file | annotate | diff | comparison | revisions
src/ucx/list.h file | annotate | diff | comparison | revisions
src/ucx/logging.c file | annotate | diff | comparison | revisions
src/ucx/logging.h file | annotate | diff | comparison | revisions
src/ucx/map.c file | annotate | diff | comparison | revisions
src/ucx/map.h file | annotate | diff | comparison | revisions
src/ucx/mempool.c file | annotate | diff | comparison | revisions
src/ucx/mempool.h file | annotate | diff | comparison | revisions
src/ucx/properties.c file | annotate | diff | comparison | revisions
src/ucx/properties.h file | annotate | diff | comparison | revisions
src/ucx/string.c file | annotate | diff | comparison | revisions
src/ucx/string.h file | annotate | diff | comparison | revisions
src/ucx/test.c file | annotate | diff | comparison | revisions
src/ucx/test.h file | annotate | diff | comparison | revisions
src/ucx/ucx.c file | annotate | diff | comparison | revisions
src/ucx/ucx.h file | annotate | diff | comparison | revisions
src/ucx/utils.c file | annotate | diff | comparison | revisions
src/ucx/utils.h file | annotate | diff | comparison | revisions
--- a/Makefile	Wed Jul 31 13:02:06 2013 +0200
+++ b/Makefile	Sun Sep 08 23:27:07 2013 +0200
@@ -26,10 +26,16 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-all: config.mk
+all: config.mk build/bin build/lib
 	@echo "build server"
 	cd src; $(MAKE) all
 
+build/bin:
+	mkdir -p build/bin
+
+build/lib:
+	mkdir -p build/lib
+
 config.mk:
 	@echo "create config"
 	./configure
@@ -37,11 +43,6 @@
 clean:
 	@echo "clean"
 	rm -f -R build
-	rm -f -R work
-
-cleanbuild:
-	@echo "clean build"
-	rm -f -R build
 
 cleanall:
 	@echo "clean all"
--- a/make/clang.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/clang.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -32,3 +32,4 @@
 CXX = c++
 LD = cc
 
+SHLIB_FLAGS = -shared
--- a/make/gcc.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/gcc.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -26,9 +26,13 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-CFLAGS = -std=gnu99 
+CFLAGS = -std=gnu99 -g
+LDFLAGS = -Wl,-R,'$$ORIGIN/../lib'
 
 CC  = gcc
 CXX = g++
 LD = gcc
 
+SHLIB_CFLAGS = -fPIC
+SHLIB_LDFLAGS = -shared
+
--- a/make/install.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/install.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -45,9 +45,8 @@
 	cp ../templates/config/acl.conf $(INSTALL_DIR)/config/acl.conf
 	sed s:%%WS_HOST%%:$(HOST):g ../templates/config/server.template > $(INSTALL_DIR)/config/server.conf
 	@echo "copy binaries"
-	mv ../work/bin/webservd ../work/bin/webservd.bin
-	cp ../work/bin/webservd.bin $(INSTALL_DIR)/bin/webservd
-	rm ../work/bin/webservd.bin
+	cp ../build/bin/webservd$(APP_EXT) $(INSTALL_DIR)/bin/
+	cp ../build/lib/libucx$(LIB_EXT) $(INSTALL_DIR)/lib/
 	@echo "copy includes"
 	cp ../src/server/public/nsapi.h $(INSTALL_DIR)/include/nsapi.h
 	cp ../src/server/public/auth.h $(INSTALL_DIR)/include/auth.h
--- a/make/linux.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/linux.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -35,4 +35,8 @@
 # platform dependend source files
 PLATFORM_DAEMONOBJ = event_linux.o
 
+# platform dependend vars
+OBJ_EXT = .o
+LIB_EXT = .so
+APP_EXT =
 
--- a/make/osx.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/osx.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -35,4 +35,8 @@
 # platform dependend source files
 PLATFORM_DAEMONOBJ = event_bsd.o
 
+# platform dependend vars
+OBJ_EXT = .o
+LIB_EXT = .dylib
+APP_EXT =
 
--- a/make/solaris.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/solaris.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -37,4 +37,8 @@
 # platform dependend source files
 PLATFORM_DAEMONOBJ = event_solaris.o
 
+# platform dependend vars
+OBJ_EXT = .o
+LIB_EXT = .so
+APP_EXT =
 
--- a/make/suncc.mk	Wed Jul 31 13:02:06 2013 +0200
+++ b/make/suncc.mk	Sun Sep 08 23:27:07 2013 +0200
@@ -27,8 +27,11 @@
 #
 
 CFLAGS += -xc99 -g -D_REENTRANT
+LDFLAGS += -R../lib
 
 CC  = cc
 CXX = CC
 LD = cc
 
+SHLIB_CFLAGS = -Kpic
+SHLIB_FLAGS = -G
--- a/src/Makefile	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/Makefile	Sun Sep 08 23:27:07 2013 +0200
@@ -28,5 +28,11 @@
 
 BUILD_ROOT = ../
 
-all:
-	cd server; $(MAKE) all
+all: _ucx _server
+	
+
+_ucx:
+	cd ucx; $(MAKE) 
+
+_server:
+	cd server; $(MAKE) 
--- a/src/server/Makefile	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/Makefile	Sun Sep 08 23:27:07 2013 +0200
@@ -33,11 +33,11 @@
 
 OBJ_DIR = $(BUILD_ROOT)/build/
 
-MAIN_TARGET = $(BUILD_ROOT)/work/bin/webservd
+MAIN_TARGET = $(BUILD_ROOT)/build/bin/webservd
 
 all: preparation $(MAIN_TARGET) $(PLUGINS)
 
-include ucx/objs.mk
+#include ucx/objs.mk
 include util/objs.mk
 include safs/objs.mk
 include webdav/objs.mk
@@ -45,7 +45,6 @@
 include config/objs.mk
 include admin/objs.mk
 
-include ucx/Makefile
 include util/Makefile
 include safs/Makefile
 include webdav/Makefile
@@ -57,9 +56,8 @@
 
 OBJ_DIRS = daemon safs ucx util webdav config admin plugins
 MK_OBJ_DIRS = $(OBJ_DIRS:%=$(OBJ_DIR)server/%)
-MK_OBJ_DIRS += $(BUILD_ROOT)/work/bin
 
-include ucx/Makefile
+LDFLAGS += -lucx
 
 preparation: $(MK_OBJ_DIRS)
 	
@@ -67,7 +65,7 @@
 	mkdir -p $@
 
 $(MAIN_TARGET): $(MAINOBJS)
-	$(CXX) -o $(MAIN_TARGET) $(MAINOBJS) $(LDFLAGS)
+	$(CXX) -o $(MAIN_TARGET) $(MAINOBJS) -L$(BUILD_ROOT)/build/lib $(LDFLAGS)
 
 
 ../../build/server/ucx/%.o: %.c
--- a/src/server/config/acl.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/acl.c	Sun Sep 08 23:27:07 2013 +0200
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "acl.h"
 
@@ -44,10 +45,6 @@
     conf->pathACLs = NULL;
     
     int r = cfg_parse_basic_file((ConfigParser*)conf, in);
-    UcxMempool *mp = conf->parser.mp;
-    cfg_list_destr(mp, conf->namedACLs);
-    cfg_list_destr(mp, conf->uriACLs);
-    cfg_list_destr(mp, conf->pathACLs);
     if(r != 0) {
         free_acl_file(conf);
         return NULL;
@@ -59,15 +56,15 @@
 }
 
 void free_acl_file(ACLFile *conf) {
-    ucx_mempool_destroy(conf->parser.mp);
+    ucx_mempool_destroy(conf->parser.mp->pool);
     free(conf);
 }
 
 int acl_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
     ACLFile *aclf = p;
-    UcxMempool *mp = aclf->parser.mp;
+    UcxAllocator *mp = aclf->parser.mp;
     
-    if(sstr_startswith(line, sstr("ACL "))) {
+    if(sstrsuffix(line, sstr("ACL "))) {
         sstr_t param = sstrsubs(line, 4);
         UcxList *plist = cfg_param_list(param, mp); 
         ACLConfig *acl = OBJ_NEW(mp, ACLConfig);
@@ -83,19 +80,19 @@
         
         if(name.ptr) {
             acl->id = name;
-            aclf->namedACLs = ucx_list_append(aclf->namedACLs, acl);
+            aclf->namedACLs = ucx_list_append_a(mp, aclf->namedACLs, acl);
         } else if(path.ptr) {
             acl->id = path;
-            aclf->pathACLs = ucx_list_append(aclf->pathACLs, acl);
+            aclf->pathACLs = ucx_list_append_a(mp, aclf->pathACLs, acl);
         } else if(uri.ptr) {
             acl->id = uri;
-            aclf->uriACLs = ucx_list_append(aclf->uriACLs, acl);
+            aclf->uriACLs = ucx_list_append_a(mp, aclf->uriACLs, acl);
         }
         
         if(type.ptr) {
             acl->type = type;
         }
-    } else if(sstr_startswith(line, sstr("Authenticate "))) {
+    } else if(sstrsuffix(line, sstr("Authenticate "))) {
         sstr_t param = sstrsubs(line, 13);
         UcxList *plist = cfg_param_list(param, mp); 
         aclf->cur->authparam = plist;
@@ -111,7 +108,7 @@
 
 int parse_ace(ACLFile *f, sstr_t line) {
     ACLConfig *cur = f->cur;
-    UcxMempool *mp = f->parser.mp;
+    UcxAllocator *mp = f->parser.mp;
     
     size_t tkn = 0;
     sstr_t *tk = sstrsplit(line, sstr(":"), &tkn);
@@ -133,12 +130,12 @@
         // next token is the user name
         s = tk[1];
         n++;
-        ace->who = sstrdup_mp(mp, s);
+        ace->who = sstrdup_a(mp, s);
     } else if(!sstrcmp(s, sstr("group"))) {
         // next token is the group name
         s = tk[1];
         n++;
-        ace->who = sstrdup_mp(mp, s);
+        ace->who = sstrdup_a(mp, s);
         ace->flags = ACLCFG_IDENTIFIER_GROUP;
     } else if(!sstrcmp(s, sstr("owner@"))) {
         ace->flags = ACLCFG_OWNER;
@@ -148,7 +145,7 @@
         ace->flags = ACLCFG_EVERYONE;
     } else {
         // you can specify only the user name in the ace
-        ace->who = sstrdup_mp(mp, s);
+        ace->who = sstrdup_a(mp, s);
     }
     
     n++; //next token
@@ -219,7 +216,7 @@
         return 1;
     }
     
-    cur->entries = ucx_list_append(cur->entries, ace);
+    cur->entries = ucx_list_append_a(mp, cur->entries, ace);
     
     return 0;
 }
--- a/src/server/config/conf.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/conf.c	Sun Sep 08 23:27:07 2013 +0200
@@ -32,7 +32,8 @@
 
 int cfg_parse_basic_file(ConfigParser *parser, FILE *in) {
     parser->lines = NULL;
-    parser->mp = ucx_mempool_new(512);
+    UcxMempool *mp = ucx_mempool_new(512);
+    parser->mp = ucx_mempool_allocator(mp);
 
     // one logical line over many lines
     sstr_t mline;
@@ -48,14 +49,13 @@
         
         // put the line to the list
         ConfigLine *line = OBJ_NEW(parser->mp, ConfigLine);
-        line->line = sstrdup_mp(parser->mp, l); // TODO: check for 0-len str
+        line->line = sstrdup_a(parser->mp, l); // TODO: check for 0-len str
         line->object = NULL;
         line->type = LINE_OTHER;
         if(parser->lines) {
-            parser->lines = ucx_dlist_append(parser->lines, line);
+            parser->lines = ucx_list_append_a(parser->mp, parser->lines, line);
         } else {
-            parser->lines = ucx_dlist_append(parser->lines, line);
-            cfg_dlist_destr(parser->mp, parser->lines);
+            parser->lines = ucx_list_append_a(parser->mp, parser->lines, line);
         }
 
         // check if the line contains something
@@ -67,7 +67,7 @@
             if(mline.ptr != NULL) {
                 // concate lines
                 char *ptr = ucx_mempool_malloc(
-                        parser->mp,
+                        mp,
                         mline.length + l.length + 1);
                 
                 memcpy(ptr, mline.ptr, mline.length);
@@ -83,7 +83,7 @@
             }
             if(l.ptr[l.length - 1] == '\\') {
                 if(mline.ptr == NULL) {
-                    mline = sstrdup_mp(parser->mp, l);
+                    mline = sstrdup_a(parser->mp, l);
                     start_line = line;
                 }
             } else {
@@ -277,7 +277,7 @@
  * parses a line containing a directive and returns a ConfigDirective object
  * or NULL if an error occurs
  */
-ConfigDirective* cfg_parse_directive(sstr_t line, UcxMempool *mp) {
+ConfigDirective* cfg_parse_directive(sstr_t line, UcxAllocator *mp) {
     if(line.length < 6) {
         printf("line too short\n");
         return NULL; // line too short
@@ -296,7 +296,7 @@
 
     // create directive object
     ConfigDirective *directive = OBJ_NEW(mp, ConfigDirective);
-    directive->directive_type = sstrdup_mp(mp, name);
+    directive->directive_type = sstrdup_a(mp, name);
     directive->type_num = cfg_get_directive_type_num(name);
     directive->condition = NULL; // set later by main parsing function
     //directive->param = NULL;
@@ -305,7 +305,7 @@
     param_str.ptr = name.ptr + i;
     param_str.length = line.length - i;
     param_str = sstrtrim(param_str);
-    directive->value = sstrdup_mp(mp, param_str);
+    directive->value = sstrdup_a(mp, param_str);
     
     /*
     sstr_t pname;
@@ -337,7 +337,7 @@
     return directive;
 }
 
-UcxList* cfg_param_list(sstr_t param_str, UcxMempool *mp) {
+UcxList* cfg_param_list(sstr_t param_str, UcxAllocator *mp) {
     sstr_t pname;
     sstr_t pvalue;
     UcxList *plist = NULL;
@@ -349,19 +349,18 @@
 
         // create param object
         ConfigParam *param = OBJ_NEW(mp, ConfigParam);
-        param->name = sstrdup_mp(mp, pname);
+        param->name = sstrdup_a(mp, pname);
 
         if(pvalue.length > 0) {
-            param->value = sstrdup_mp(mp, pvalue);
+            param->value = sstrdup_a(mp, pvalue);
         } else {
             param->value.ptr = NULL;
             param->value.length = 0;
         }
 
         // add param to list
-        plist = ucx_list_append(plist, param);
+        plist = ucx_list_append_a(mp, plist, param);
     }
-    cfg_list_destr(mp, plist);
     return plist;
 }
 
@@ -477,7 +476,7 @@
     return sstrtrim(name);
 }
 
-ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxMempool *mp) {
+ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxAllocator *mp) {
     if(line.length < 4) {
         return NULL; // this line can't contain a valid tag
     }
@@ -501,7 +500,7 @@
 
     // create tag object
     ConfigTag *tag = OBJ_NEW(mp, ConfigTag);
-    tag->name = sstrdup_mp(mp, name);
+    tag->name = sstrdup_a(mp, name);
     tag->param = NULL;
 
     // parse parameters
@@ -512,7 +511,7 @@
     if(param_str.length == 0) {
         return tag; // no parameters
     }
-    tag->param_str = sstrdup_mp(mp, param_str);
+    tag->param_str = sstrdup_a(mp, param_str);
 
     sstr_t pname;
     sstr_t pvalue;
@@ -524,16 +523,16 @@
 
         // create param object
         ConfigParam *param = OBJ_NEW(mp, ConfigParam);
-        param->name = sstrdup_mp(mp, pname);
+        param->name = sstrdup_a(mp, pname);
         if(pvalue.length > 0) {
-            param->value = sstrdup_mp(mp, pvalue);
+            param->value = sstrdup_a(mp, pvalue);
         } else {
             param->value.ptr = NULL;
             param->value.length = 0;
         }
 
         // add param to list
-        tag->param = cfg_list_append(mp, tag->param, param);
+        tag->param = ucx_list_append_a(mp, tag->param, param);
     }
 
     return tag;
@@ -546,7 +545,7 @@
  * gets a ConfigDirective with a specific name from a List of directives
  * returns a directive or NULL, if the directive cannot be found
  */
-ConfigDirective* cfg_directivelist_get(UcxDlist *dirs, sstr_t name) {
+ConfigDirective* cfg_directivelist_get(UcxList *dirs, sstr_t name) {
     while(dirs != NULL) {
         ConfigDirective *d = dirs->data;
         if(d != NULL) {
@@ -559,7 +558,7 @@
     return NULL;
 }
 
-sstr_t cfg_directivelist_get_str(UcxDlist *dirs, sstr_t name) {
+sstr_t cfg_directivelist_get_str(UcxList *dirs, sstr_t name) {
     ConfigDirective *d = cfg_directivelist_get(dirs, name);
     if(d == NULL) {
         sstr_t n;
@@ -593,24 +592,12 @@
 static void cfg_list_free(void *list) {
     ucx_list_free(list);
 }
-static void cfg_dlist_free(void *dlist) {
-    ucx_dlist_free(dlist);
-}
+
 static void cfg_map_free(void *map) {
     ucx_map_free(map);
 }
 
-void cfg_list_destr(UcxMempool *mp, UcxList *list) {
-    if(list) {
-        ucx_mempool_reg_destr(mp, list, cfg_list_free);
-    }
-}
 
-void cfg_dlist_destr(UcxMempool *mp, UcxDlist *dlist) {
-    if(dlist) {
-        ucx_mempool_reg_destr(mp, dlist, cfg_dlist_free);
-    }
-}
 
 void cfg_map_destr(UcxMempool *mp, UcxMap *map) {
     if(map) {
@@ -618,23 +605,5 @@
     }
 }
 
-UcxList* cfg_list_append(UcxMempool *mp, UcxList *list, void *data) {
-    if(list) {
-        return ucx_list_append(list, data);
-    } else {
-        UcxList *r = ucx_list_append(list, data);
-        cfg_list_destr(mp, r);
-        return r;
-    }
-}
 
-UcxDlist* cfg_dlist_append(UcxMempool *mp, UcxDlist *list, void *data) {
-    if(list) {
-        return ucx_dlist_append(list, data);
-    } else {
-        UcxDlist *r = ucx_dlist_append(list, data);
-        cfg_dlist_destr(mp, r);
-        return r;
-    }
-}
 
--- a/src/server/config/conf.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/conf.h	Sun Sep 08 23:27:07 2013 +0200
@@ -32,19 +32,18 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "../ucx/list.h"
-#include "../ucx/dlist.h"
-#include "../ucx/map.h"
-#include "../ucx/mempool.h"
-#include "../ucx/string.h"
+#include <ucx/list.h>
+#include <ucx/map.h>
+#include <ucx/mempool.h>
+#include <ucx/string.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
    
 // mempool malloc macro
-#define OBJ_NEW(pool, type) (type*)ucx_mempool_malloc(pool, sizeof(type))
-#define OBJ_NEW_N(pool, type) (type*)ucx_mempool_calloc(pool, 1, sizeof(type))
+#define OBJ_NEW(p, type) (type*)(p)->malloc((p)->pool, sizeof(type))
+#define OBJ_NEW_N(p, type) (type*)(p)->calloc((p)->pool, 1, sizeof(type))
 
 // line types
 #define LINE_OTHER      0
@@ -76,8 +75,8 @@
 } ConfigParam;
 
 typedef struct _cfg_parser {
-    UcxMempool    *mp;
-    UcxDlist      *lines;
+    UcxAllocator  *mp;
+    UcxList       *lines;
     cfg_parse_f   parse;
 } ConfigParser;
 
@@ -117,9 +116,9 @@
 
 sstr_t cfg_param_get(UcxList *list, sstr_t name);
 
-ConfigDirective* cfg_parse_directive(sstr_t line, UcxMempool *mp);
+ConfigDirective* cfg_parse_directive(sstr_t line, UcxAllocator *mp);
 
-UcxList* cfg_param_list(sstr_t param_str, UcxMempool *mp);
+UcxList* cfg_param_list(sstr_t param_str, UcxAllocator *mp);
 
 int cfg_get_directive_type_num(sstr_t type);
 
@@ -131,19 +130,15 @@
 
 sstr_t cfg_get_end_tag_name(sstr_t line);
 
-ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxMempool *mp);
+ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxAllocator *mp);
 
-ConfigDirective* cfg_directivelist_get(UcxDlist *dirs, sstr_t name);
+ConfigDirective* cfg_directivelist_get(UcxList *dirs, sstr_t name);
 
-sstr_t cfg_directivelist_get_str(UcxDlist *dirs, sstr_t name);
+sstr_t cfg_directivelist_get_str(UcxList *dirs, sstr_t name);
 
 sstr_t cfg_directive_pstr1(ConfigDirective *dir);
 
-void cfg_list_destr(UcxMempool *mp, UcxList *list);
-void cfg_dlist_destr(UcxMempool *mp, UcxDlist *list);
 void cfg_map_destr(UcxMempool *mp, UcxMap *map);
-UcxList* cfg_list_append(UcxMempool *mp, UcxList *list, void *data);
-UcxDlist* cfg_dlist_append(UcxMempool *mp, UcxDlist *list, void *data);
 
 #ifdef	__cplusplus
 }
--- a/src/server/config/initconf.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/initconf.c	Sun Sep 08 23:27:07 2013 +0200
@@ -44,7 +44,6 @@
     conf->directives = NULL;
 
     int r = cfg_parse_basic_file((ConfigParser*)conf, in);
-    cfg_dlist_destr(conf->parser.mp, conf->directives);
     if(r != 0) {
         free_init_config(conf);
         return NULL;
@@ -55,7 +54,7 @@
 }
 
 void free_init_config(InitConfig *conf) {
-    ucx_mempool_destroy(conf->parser.mp);
+    ucx_mempool_destroy(conf->parser.mp->pool);
     free(conf);
 }
 
@@ -71,7 +70,7 @@
     d->begin = begin;
     d->end = end;
     if(d->type_num == 6) {
-        conf->directives = ucx_dlist_append(conf->directives, d);
+        conf->directives = ucx_list_append(conf->directives, d);
     } else {
         fprintf(stderr, "Warning: Non Init directive in init.conf\n");
     }
--- a/src/server/config/initconf.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/initconf.h	Sun Sep 08 23:27:07 2013 +0200
@@ -38,7 +38,7 @@
 typedef struct _init_conf {
     ConfigParser parser;
     char         *file;
-    UcxDlist     *directives;
+    UcxList      *directives;
 } InitConfig;
 
 InitConfig *load_init_config(char *file);
--- a/src/server/config/keyfile.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/keyfile.c	Sun Sep 08 23:27:07 2013 +0200
@@ -43,7 +43,6 @@
     conf->users = NULL;
 
     int r = cfg_parse_basic_file((ConfigParser*)conf, in);
-    cfg_list_destr(conf->parser.mp, conf->users);
     if(r != 0) {
         // TODO: free
         return NULL;
@@ -58,13 +57,13 @@
     if(conf->users) {
         ucx_list_free(conf->users);
     }
-    ucx_mempool_destroy(conf->parser.mp);
+    ucx_mempool_destroy(conf->parser.mp->pool);
     free(conf);
 }
 
 int keyfile_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
     KeyfileConfig *conf = p;
-    UcxMempool *mp = conf->parser.mp;
+    UcxAllocator *mp = conf->parser.mp;
     
     size_t tkn = 0;
     sstr_t *tk = sstrsplit(line, sstrn(";", 1), &tkn);
@@ -78,7 +77,7 @@
     entry->numgroups = 0;
     
     // get user name
-    entry->name = sstrdup_mp(mp, tk[0]);
+    entry->name = sstrdup_a(mp, tk[0]);
     
     // get hash
     sstr_t hash = sstrtrim(tk[1]);
@@ -105,28 +104,28 @@
         entry->hashtype = KEYFILE_SSHA;
     } else {
         // unkown hash type
-        fprintf(stderr, "unknown hash type: %s\n", sstrdup(hash_type).ptr);
+        fprintf(stderr, "unknown hash type: %s\n", sstrdup_a(mp, hash_type).ptr);
         return 1;
     }
     
-    entry->hashdata = sstrdup_mp(mp, hash_data);
+    entry->hashdata = sstrdup_a(mp, hash_data);
     
     // get groups
     if(tkn == 3) {
         sstr_t groups_str = sstrtrim(tk[2]);
         size_t ngroups = 0;
         sstr_t *groups = sstrsplit(groups_str, sstrn(",", 1), &ngroups);
-        entry->groups = calloc(ngroups, sizeof(sstr_t));
+        entry->groups = mp->calloc(mp->pool, ngroups, sizeof(sstr_t));
         entry->numgroups = ngroups;
         for(int i=0;i<ngroups;i++) {
-            entry->groups[i] = sstrdup_mp(mp, sstrtrim(groups[i]));
+            entry->groups[i] = sstrdup_a(mp, sstrtrim(groups[i]));
             free(groups[i].ptr);
         }
         free(groups);
     }
     
     // add user
-    conf->users = ucx_list_append(conf->users, entry);
+    conf->users = ucx_list_append_a(mp, conf->users, entry);
     
     // free tokens
     for(int i=0;i<tkn;i++) {
--- a/src/server/config/mimeconf.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/mimeconf.c	Sun Sep 08 23:27:07 2013 +0200
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <ucx/mempool.h>
 #include "mimeconf.h"
 
 typedef struct {
@@ -49,7 +50,6 @@
     conf->directives = NULL;
     conf->ntypes = 0;
     int r = cfg_parse_basic_file((ConfigParser*)conf, in);
-    cfg_list_destr(conf->parser.mp, conf->directives);
     if(r != 0) {
         // TODO: free
         return NULL;
@@ -61,19 +61,19 @@
 }
 
 void free_mime_config(MimeConfig *conf) {
-    ucx_mempool_destroy(conf->parser.mp);
+    ucx_mempool_destroy(conf->parser.mp->pool);
     free(conf);
 }
 
 int mimeconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
     MimeConfig *conf = p;
-    UcxMempool *mp = conf->parser.mp;
+    UcxAllocator *mp = conf->parser.mp;
     
     // parse mime directive
-    MimeDirective *dir = ucx_mempool_calloc(mp, 1, sizeof(MimeDirective));
+    MimeDirective *dir = OBJ_NEW_N(mp, MimeDirective);
     
     UcxList *params = cfg_param_list(line, mp);
-    UCX_FOREACH(UcxList*, params, pl) {
+    UCX_FOREACH(pl, params) {
         ConfigParam *param = pl->data;
         
         if(!sstrcmp(param->name, sstr("type"))) {
@@ -84,16 +84,15 @@
             size_t nx = 0;
             sstr_t *exts = sstrsplit(param->value, sstrn(",", 1), &nx);
             for(int i=0;i<nx;i++) {
-                sstr_t extstr = sstrdup_mp(mp, exts[i]);
-                dir->exts = ucx_list_append(dir->exts, extstr.ptr);
+                sstr_t extstr = sstrdup_a(mp, exts[i]);
+                dir->exts = ucx_list_append_a(mp, dir->exts, extstr.ptr);
                 free(exts[i].ptr);
             }
             free(exts);
         }
     }
     
-    cfg_list_destr(mp, dir->exts);
-    conf->directives = ucx_list_append(conf->directives, dir);
+    conf->directives = ucx_list_append_a(mp, conf->directives, dir);
     conf->ntypes++;
 
     return 0;
--- a/src/server/config/objconf.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/objconf.c	Sun Sep 08 23:27:07 2013 +0200
@@ -66,11 +66,11 @@
 void free_object_config(ObjectConfig *conf) {
     // free other lists
     if(conf->levels) {
-        ucx_list_free(conf->levels);
+        //ucx_list_free(conf->levels);
     }
 
     // free mempool
-    ucx_mempool_destroy(conf->parser.mp);
+    ucx_mempool_destroy(conf->parser.mp->pool);
     free(conf);
 }
 
@@ -122,7 +122,7 @@
 }
 
 int objconf_on_begin_tag(ObjectConfig *conf, ConfigTag *tag) {
-    UcxMempool *mp = conf->parser.mp;
+    UcxAllocator *mp = conf->parser.mp;
     if(tag->type_num != TAG_OBJECT) {
         ConfigParserLevel *l = conf->levels->data;
         if(l->tag->type_num != TAG_OBJECT) {
@@ -141,14 +141,14 @@
             obj->ppath = cfg_param_get(tag->param, sstr("ppath"));
 
             conf->obj = obj;
-            conf->objects = cfg_dlist_append(mp, conf->objects, obj);
+            conf->objects = ucx_list_append_a(mp, conf->objects, obj);
 
             // create tree level object
             ConfigParserLevel *lvl = OBJ_NEW(mp, ConfigParserLevel);
             lvl->iftag = NULL;
             lvl->levelnum = 1;
             lvl->tag = tag;
-            conf->levels = ucx_list_prepend(conf->levels, lvl);
+            conf->levels = ucx_list_prepend_a(mp, conf->levels, lvl);
 
             break;
         }
@@ -161,7 +161,7 @@
             lvl->iftag = NULL;
             lvl->levelnum = last_lvl->levelnum + 1;
             lvl->tag = tag;
-            conf->levels = ucx_list_prepend(conf->levels, lvl);
+            conf->levels = ucx_list_prepend_a(mp, conf->levels, lvl);
             last_lvl->iftag = tag;
 
             break;
@@ -211,7 +211,10 @@
         }
 
         // remove level
-        conf->levels = ucx_list_remove(conf->levels, conf->levels);
+        conf->levels = ucx_list_remove_a(
+                conf->parser.mp,
+                conf->levels,
+                conf->levels);
     }
     
     return 0;
@@ -227,7 +230,7 @@
     }
 
     // add directive to current object
-    conf->obj->directives[dir->type_num] = cfg_dlist_append(
+    conf->obj->directives[dir->type_num] = ucx_list_append_a(
             conf->parser.mp,
             conf->obj->directives[dir->type_num],
             dir);
--- a/src/server/config/objconf.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/objconf.h	Sun Sep 08 23:27:07 2013 +0200
@@ -42,7 +42,7 @@
     sstr_t     name;
     sstr_t     ppath;
     // directives
-    UcxDlist   *directives[6];
+    UcxList    *directives[6];
 } ConfigObject;
 
 /*
@@ -58,8 +58,8 @@
     ConfigParser parser;
     char         *file;
     //UcxDlist     *lines;
-    UcxDlist     *conditions;
-    UcxDlist     *objects;
+    UcxList      *conditions;
+    UcxList      *objects;
 
     // private parser temp var
     ConfigObject *obj;     // add directives to this object
--- a/src/server/config/serverconf.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/serverconf.c	Sun Sep 08 23:27:07 2013 +0200
@@ -41,11 +41,11 @@
     ServerConfig *conf = malloc(sizeof(ServerConfig));
     conf->parser.parse = serverconf_parse;
     conf->file = file;
-    conf->objects = ucx_map_new(16);
     conf->obj = NULL;
     
+    conf->objects = ucx_map_new(16);
     int r = cfg_parse_basic_file((ConfigParser*)conf, in);
-    cfg_map_destr(conf->parser.mp, conf->objects);
+    cfg_map_destr(conf->parser.mp->pool, conf->objects);
     if(r != 0) {
         // TODO: free
         return NULL;
@@ -57,13 +57,13 @@
 }
 
 void free_server_config(ServerConfig *conf) {
-    ucx_mempool_destroy(conf->parser.mp);
+    ucx_mempool_destroy(conf->parser.mp->pool);
     free(conf);
 }
 
 int serverconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line){
     ServerConfig *conf = p;
-    UcxMempool *mp = conf->parser.mp;
+    UcxAllocator *mp = conf->parser.mp;
     
     begin->type = cfg_get_line_type(line);
     switch(begin->type) {
@@ -81,7 +81,7 @@
 
             // add object to server config
             UcxList *list = ucx_map_sstr_get(conf->objects, obj->type);
-            list = cfg_list_append(mp, list, obj);
+            list = ucx_list_append_a(mp, list, obj);
             ucx_map_sstr_put(conf->objects, obj->type, list);
             conf->obj = obj;
 
@@ -109,19 +109,19 @@
             d->end = end;
 
             //printf("%s.%s\n", conf->obj->type.ptr, d->directive_type.ptr);
-            conf->obj->directives = cfg_dlist_append(mp, conf->obj->directives, d);
+            conf->obj->directives = ucx_list_append_a(mp, conf->obj->directives, d);
         }
     }
     return 0;
 }
 
 
-UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxMempool *mp, int *error) {
+UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxAllocator *mp, int *error) {
     mp = mp ? mp : cfg->parser.mp;
     
     UcxList *list = ucx_map_sstr_get(cfg->objects, sstrn("Listener", 8));
     UcxList *lslist = NULL;
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         ServerConfigObject *ls = elm->data;
         sstr_t name = cfg_directivelist_get_str(ls->directives, sstr("Name"));
         sstr_t port = cfg_directivelist_get_str(ls->directives, sstr("Port"));
@@ -132,7 +132,7 @@
                 ls->directives,
                 sstr("Threadpool"));
         
-        CfgListener *listener = ucx_mempool_calloc(mp, 1, sizeof(CfgListener));
+        CfgListener *listener = OBJ_NEW_N(mp, CfgListener);
         // threadpool is optional, all other configs must be set
         if(!name.ptr || !port.ptr || !vs.ptr) {
             // TODO: log error
@@ -143,7 +143,7 @@
         }
         
         if(name.ptr) {
-            listener->name = sstrdup_mp(mp, name);
+            listener->name = sstrdup_a(mp, name);
         }
         if(port.ptr) {
             // don't expect that port is null terminated, sstrdup it to be sure
@@ -152,13 +152,13 @@
             free(portdp.ptr);
         }
         if(vs.ptr) {
-            listener->vs = sstrdup_mp(mp, vs);
+            listener->vs = sstrdup_a(mp, vs);
         }
         if(threadpool.ptr) {
-            listener->threadpool = sstrdup_mp(mp, threadpool);
+            listener->threadpool = sstrdup_a(mp, threadpool);
         }
         
-        lslist = cfg_list_append(mp, lslist, listener);
+        lslist = ucx_list_append_a(mp, lslist, listener);
     }
     
     return lslist;
--- a/src/server/config/serverconf.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/config/serverconf.h	Sun Sep 08 23:27:07 2013 +0200
@@ -40,7 +40,7 @@
     ConfigLine   *end;
 
     sstr_t       type;
-    UcxDlist     *directives;
+    UcxList     *directives;
 } ServerConfigObject;
 
 typedef struct _server_conf {
@@ -110,7 +110,7 @@
 int serverconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line);
 
 
-UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxMempool *mp, int *error);
+UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxAllocator *mp, int *error);
 
 
 #ifdef	__cplusplus
--- a/src/server/daemon/acldata.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/acldata.h	Sun Sep 08 23:27:07 2013 +0200
@@ -33,7 +33,6 @@
 #include "../config/acl.h"
 
 #include "../ucx/list.h"
-#include "../ucx/dlist.h"
 #include "../ucx/map.h"
 
 #ifdef	__cplusplus
--- a/src/server/daemon/auth.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/auth.c	Sun Sep 08 23:27:07 2013 +0200
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <pthread.h>
 
 #include "../ucx/map.h"
--- a/src/server/daemon/auth.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/auth.h	Sun Sep 08 23:27:07 2013 +0200
@@ -30,6 +30,7 @@
 #define	AUTH_H
 
 #include <sys/types.h>
+#include <inttypes.h>
 #include "../public/auth.h"
 
 #ifdef	__cplusplus
--- a/src/server/daemon/config.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/config.c	Sun Sep 08 23:27:07 2013 +0200
@@ -66,10 +66,10 @@
         fprintf(stderr, "Cannot load init.conf\n");
         return 1;
     }
-    UcxMempool *mp = cfg->parser.mp;
+    UcxAllocator *mp = cfg->parser.mp;
 
     cfg_pool = pool_create(); // one pool for one Configuration
-    UcxDlist *dirs = cfg->directives;
+    UcxList *dirs = cfg->directives;
     while(dirs != NULL) {
         ConfigDirective *dir = dirs->data;
 
@@ -178,7 +178,7 @@
     }
      
     UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         ServerConfigObject *scfgobj = elm->data;
         if(cfg_handle_runtime(serverconfig, scfgobj)) {
             // error
@@ -187,7 +187,7 @@
     }
     
     list = ucx_map_sstr_get(serverconf->objects, sstrn("Threadpool", 10));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         if(cfg_handle_threadpool(serverconfig, elm->data)) {
             return NULL;
         }
@@ -199,7 +199,7 @@
     }
     
     list = ucx_map_sstr_get(serverconf->objects, sstrn("EventHandler", 12));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         if(cfg_handle_eventhandler(
                 serverconfig, (ServerConfigObject*)elm->data)) {
             // error            
@@ -213,7 +213,7 @@
     }
     
     list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         ServerConfigObject *scfgobj = elm->data;
         if(cfg_handle_accesslog(serverconfig, scfgobj)) {
             return NULL;
@@ -221,7 +221,7 @@
     }
     
     list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         ServerConfigObject *scfgobj = elm->data;
         if(cfg_handle_authdb(serverconfig, scfgobj)) {
             return NULL;
@@ -229,7 +229,7 @@
     }
     
     list = ucx_map_sstr_get(serverconf->objects, sstrn("Listener", 8));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         ServerConfigObject *scfgobj = elm->data;
         if(cfg_handle_listener(serverconfig, scfgobj)) {
             return NULL;
@@ -237,7 +237,7 @@
     }
     
     list = ucx_map_sstr_get(serverconf->objects, sstrn("VirtualServer", 13));
-    UCX_FOREACH(UcxList*, list, elm) {
+    UCX_FOREACH(elm, list) {
         ServerConfigObject *scfgobj = elm->data;
         if(cfg_handle_vs(serverconfig, scfgobj)) {
             return NULL;
@@ -290,7 +290,7 @@
 int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) {
     sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User"));
     if(user.ptr) {
-        cfg->user = sstrdup_pool(cfg->pool, user);
+        //cfg->user = sstrdup_pool(cfg->pool, user);
     }
     sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp"));
     if(tmp.ptr) {
@@ -308,7 +308,7 @@
     file.length = base.length + mf.length;
     file.ptr = alloca(file.length + 1);
     file.ptr[file.length] = 0;
-    file = sstrncat(2, file, base, mf);
+    file = sstrncat(file, 2, base, mf);
     
     ConfigFile *f = cfgmgr_get_file(file);
     if(f == NULL) {
@@ -610,7 +610,7 @@
     file.length = base.length + objfile.length + 1;
     file.ptr = alloca(file.length);
     file.ptr[file.length] = 0;
-    file = sstrncat(2, file, base, objfile);
+    file = sstrncat(file, 2, base, objfile);
 
     // the file is managed by the configuration manager
     ConfigFile *f = cfgmgr_get_file(file);
@@ -635,7 +635,7 @@
     file.length = base.length + aclfile.length + 1;
     file.ptr = alloca(file.length);
     file.ptr[file.length] = 0;
-    file = sstrncat(2, file, base, aclfile);
+    file = sstrncat(file, 2, base, aclfile);
     
     ConfigFile *aclf = cfgmgr_get_file(file);
     if(aclf == NULL) {
@@ -696,7 +696,7 @@
 
     // new conf function test
     ObjectConfig *cfg = load_object_config(file);
-    UcxMempool   *mp = cfg->parser.mp;
+    UcxAllocator *mp = cfg->parser.mp;
     if(cfg == NULL) {
         return NULL;
     }
@@ -709,10 +709,10 @@
     // convert ObjectConfig to HTTPObjectConfig
 
     // add objects
-    conf->nobj = ucx_dlist_size(cfg->objects);
+    conf->nobj = ucx_list_size(cfg->objects);
     conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*));
     
-    UcxDlist *objlist = cfg->objects;
+    UcxList *objlist = cfg->objects;
     int i = 0;
     while(objlist != NULL) {
         ConfigObject *cob = objlist->data;
@@ -735,7 +735,7 @@
 
         // add directives
         for(int i=0;i<6;i++) {
-            UcxDlist *dirs = cob->directives[i];
+            UcxList *dirs = cob->directives[i];
             while(dirs != NULL) {
                 ConfigDirective *cfgdir = dirs->data;
                 
@@ -792,10 +792,10 @@
     mimemap->map = map;
     
     // add ext type pairs
-    UCX_FOREACH(UcxList*, mimecfg->directives, md) {
+    UCX_FOREACH(md, mimecfg->directives) {
         MimeDirective *d = md->data;
         // add the type for each extension to the map
-        UCX_FOREACH(UcxList*, d->exts, xl) {
+        UCX_FOREACH(xl, d->exts) {
             sstr_t ext = sstr(xl->data);
             sstr_t value = sstrdup(d->type);
             ucx_map_sstr_put(map, ext, value.ptr);
@@ -836,7 +836,7 @@
     ACLFile *aclfile = load_acl_file(file->file.ptr);
     
     ACLData *acldata = acl_data_new();
-    UCX_FOREACH(UcxList*, aclfile->namedACLs, elm) {
+    UCX_FOREACH(elm, aclfile->namedACLs) {
         ACLConfig *ac = elm->data;
         ACLList *acl = acl_config_convert(cfg, ac);
         printf("put acl: %s\n", ac->id.ptr);
@@ -874,7 +874,7 @@
     int ei = 0;
     
     // convert entries
-    UCX_FOREACH(UcxList*, acl->entries, elm) {
+    UCX_FOREACH(elm, acl->entries) {
         ACEConfig *acecfg = elm->data;
         
         // copy data
@@ -934,7 +934,7 @@
     
     Keyfile *keyfile = keyfile_new();
     
-    UCX_FOREACH(UcxList*, conf->users, elm) {
+    UCX_FOREACH(elm, conf->users) {
         KeyfileEntry *user = elm->data;
         keyfile_add_user(
                 keyfile,
--- a/src/server/daemon/config.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/config.h	Sun Sep 08 23:27:07 2013 +0200
@@ -44,11 +44,10 @@
 #include "keyfile_auth.h"
 #include "log.h"
 
-#include "../ucx/list.h"
-#include "../ucx/dlist.h"
-#include "../ucx/map.h"
-#include "../ucx/mempool.h"
-#include "../ucx/string.h"
+#include <ucx/list.h>
+#include <ucx/map.h>
+#include <ucx/mempool.h>
+#include <ucx/string.h>
 
 #ifdef	__cplusplus
 extern "C" {
--- a/src/server/daemon/configmanager.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/configmanager.c	Sun Sep 08 23:27:07 2013 +0200
@@ -31,7 +31,7 @@
 
 #include "../public/nsapi.h"
 
-#include "../ucx/string.h"
+#include <ucx/string.h>
 
 #include "httplistener.h"
 #include "log.h"
--- a/src/server/daemon/configmanager.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/configmanager.h	Sun Sep 08 23:27:07 2013 +0200
@@ -33,11 +33,10 @@
 
 #include "vserver.h"
 
-#include "../ucx/list.h"
-#include "../ucx/dlist.h"
-#include "../ucx/map.h"
-#include "../ucx/mempool.h"
-#include "../ucx/string.h"
+#include <ucx/list.h>
+#include <ucx/map.h>
+#include <ucx/mempool.h>
+#include <ucx/string.h>
 
 #include <sys/types.h>
 
--- a/src/server/daemon/httprequest.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/httprequest.c	Sun Sep 08 23:27:07 2013 +0200
@@ -516,7 +516,7 @@
         sstr_t translated;
         translated.length = docroot.length + uri.length;
         translated.ptr = alloca(translated.length + 1);
-        translated = sstrncat(2, translated, docroot, uri);
+        translated = sstrncat(translated, 2, docroot, uri);
 
         pblock_kvinsert(
             pb_key_ppath,
--- a/src/server/daemon/keyfile_auth.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/keyfile_auth.h	Sun Sep 08 23:27:07 2013 +0200
@@ -31,6 +31,7 @@
 
 #include "../public/auth.h"
 #include "../ucx/map.h"
+#include <inttypes.h>
 
 #ifdef	__cplusplus
 extern "C" {
--- a/src/server/daemon/ldap_auth.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/ldap_auth.c	Sun Sep 08 23:27:07 2013 +0200
@@ -40,7 +40,7 @@
 #ifdef SOLARIS
     ldap_unbind(ldap);
 #else
-    ldap_unbind_ext_s(ld, NULL, NULL);
+    ldap_unbind_ext_s(ldap, NULL, NULL);
 #endif
 }
 
--- a/src/server/daemon/log.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/log.c	Sun Sep 08 23:27:07 2013 +0200
@@ -40,9 +40,10 @@
 #include "log.h"
 #include "../util/strbuf.h"
 #include "../util/io.h"
-#include "../ucx/map.h"
 #include "../util/atomic.h"
 
+#include <ucx/map.h>
+
 static int is_initialized = 0;
 
 static int log_file_fd;
@@ -236,7 +237,7 @@
     message.length = lpre.length + len;
     message.ptr = malloc(message.length + 1);
     
-    message = sstrncat(2, message, lpre, lmsg);
+    message = sstrncat(message, 2, lpre, lmsg);
     
     /* write message to the log file */ 
     log_file_writeln(message.ptr, message.length);
--- a/src/server/daemon/log.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/daemon/log.h	Sun Sep 08 23:27:07 2013 +0200
@@ -30,7 +30,7 @@
 #define	LOG_H
 
 #include "../public/nsapi.h"
-#include "../ucx/string.h"
+#include <ucx/string.h>
 
 #include <inttypes.h>
 
--- a/src/server/public/webdav.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/public/webdav.h	Sun Sep 08 23:27:07 2013 +0200
@@ -58,7 +58,7 @@
 
 typedef uint8_t                       xmlch_t;
 
-typedef struct UcxDlist               List;
+typedef struct UcxList                List;
 typedef struct UcxMap                 Map;
 
 typedef struct _strbuf                Buffer;
--- a/src/server/util/object.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/util/object.c	Sun Sep 08 23:27:07 2013 +0200
@@ -344,7 +344,7 @@
     } else if(c == '"' || c == '\'') {
         *type = EXPR_OP_STRING;
         sstr_t s = sstrn(token+1, len-2);
-        s = sstrdup_pool(pool, s);
+        //s = sstrdup_pool(pool, s);
         *val = s.ptr;
     }
 }
--- a/src/server/util/pool.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/util/pool.c	Sun Sep 08 23:27:07 2013 +0200
@@ -703,3 +703,17 @@
 }
 #endif /* PER_POOL_STATISTICS */
 
+// new
+sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s) {
+    sstr_t newstring;
+    newstring.ptr = (char*)pool_malloc(pool, 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;
+}
+
--- a/src/server/util/pool.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/util/pool.h	Sun Sep 08 23:27:07 2013 +0200
@@ -52,6 +52,9 @@
  *
  */
 
+// new
+#include <ucx/string.h>
+
 #ifndef NETSITE_H
 //include "netsite.h"
 #include "../public/nsapi.h"
@@ -80,6 +83,8 @@
 
 NSAPI_PUBLIC int INTpool_init(pblock *pb, Session *sn, Request *rq);
 
+sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s);
+
 #ifdef DEBUG_CACHES
 NSAPI_PUBLIC int INTpool_service_debug(pblock *pb, Session *sn, Request *rq);
 #endif
--- a/src/server/util/util.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/util/util.c	Sun Sep 08 23:27:07 2013 +0200
@@ -53,6 +53,8 @@
 
 #include "../daemon/netsite.h"
 #include "../public/nsapi.h"
+#include <ucx/string.h>
+#include <ucx/mempool.h>
 
 #include "util.h"
 
@@ -484,9 +486,9 @@
         return newstr;
     }
     if(s.length == 1) {
-        newstr = sstrncat(3, newstr, parent, s, child);
+        newstr = sstrncat(newstr, 3, parent, s, child);
     } else {
-        newstr = sstrncat(2, newstr, parent, child);
+        newstr = sstrncat(newstr, 2, parent, child);
     }
     newstr.ptr[newstr.length] = '\0';
     
@@ -568,3 +570,17 @@
 
     return pb;
 }
+
+// TODO: remove
+sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s) {
+    sstr_t newstring;
+    newstring.ptr = (char*)ucx_mempool_malloc(pool, 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;
+}
--- a/src/server/util/util.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/util/util.h	Sun Sep 08 23:27:07 2013 +0200
@@ -35,7 +35,7 @@
 #define BASE_UTIL_H
 
 #include "../daemon/netsite.h"
-#include "../ucx/string.h"
+#include <ucx/string.h>
 #include "pool.h"
 #include <pwd.h>
 
--- a/src/server/webdav/davparser.cpp	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/davparser.cpp	Sun Sep 08 23:27:07 2013 +0200
@@ -98,8 +98,8 @@
 }
 
 void dav_free_propfind(PropfindRequest *rq) {
-    ucx_dlist_free(rq->forbiddenProps);
-    ucx_dlist_free(rq->notFoundProps);
+    ucx_list_free(rq->forbiddenProps);
+    ucx_list_free(rq->notFoundProps);
     //ucx_dlist_free(rq->properties); // uses pool
     sbuf_free(rq->out);
 }
@@ -154,9 +154,9 @@
 }
 
 void dav_free_proppatch(ProppatchRequest *rq) {
-    ucx_dlist_free(rq->removeProps);
-    ucx_dlist_free(rq->setProps);
+    ucx_list_free(rq->removeProps);
+    ucx_list_free(rq->setProps);
     xmlnsmap_free(rq->nsmap);
     ucx_map_free(rq->propstat->map);
-    ucx_dlist_free(rq->propstat->okprop);
+    ucx_list_free(rq->propstat->okprop);
 }
--- a/src/server/webdav/davparser.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/davparser.h	Sun Sep 08 23:27:07 2013 +0200
@@ -31,7 +31,6 @@
 
 #include "../public/nsapi.h"
 
-#include "../ucx/dlist.h"
 #include <inttypes.h>
 #include "webdav.h"
 
--- a/src/server/webdav/parser.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/parser.c	Sun Sep 08 23:27:07 2013 +0200
@@ -114,11 +114,11 @@
         property->name = pool_strdup(pool, (const char*)name);
         
         // add property to DavRequest
-        UcxDlist *elm = pool_malloc(pool, sizeof(UcxDlist));
+        UcxList *elm = pool_malloc(pool, sizeof(UcxList));
         elm->prev = NULL;
         elm->next = NULL;
         elm->data = property;
-        p->rq->properties = ucx_dlist_concat(p->rq->properties, elm);
+        p->rq->properties = ucx_list_concat(p->rq->properties, elm);
     }
     
     return 0;
--- a/src/server/webdav/saxhandler.cpp	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/saxhandler.cpp	Sun Sep 08 23:27:07 2013 +0200
@@ -32,23 +32,23 @@
 #include <iostream>
 
 #include "../ucx/string.h"
-#include "../ucx/dlist.h"
+#include "../ucx/list.h"
 #include "../util/pool.h"
 
 #include "saxhandler.h"
 
 using namespace std;
 
-void xstack_push(UcxDlist **stack, XmlElement *elm) {
-    *stack = ucx_dlist_prepend(*stack, elm);
+void xstack_push(UcxList **stack, XmlElement *elm) {
+    *stack = ucx_list_prepend(*stack, elm);
 }
 
-XmlElement* xstack_pop(UcxDlist **stack) {
+XmlElement* xstack_pop(UcxList **stack) {
     if(*stack == NULL) {
         return NULL;
     }
     XmlElement* ret = (XmlElement*)(*stack)->data;
-    UcxDlist *newstack = ucx_dlist_remove(*stack, *stack);
+    UcxList *newstack = ucx_list_remove(*stack, *stack);
     *stack = newstack;
     return ret;
 }
@@ -121,12 +121,12 @@
         
         if(!strcmp(ns, xmlns) && !strcmp(name, property->name)) {
             // add property to DavRequest
-            UcxDlist *elm = (UcxDlist*)pool_malloc(pool, sizeof(UcxDlist));
+            UcxList *elm = (UcxList*)pool_malloc(pool, sizeof(UcxList));
             elm->prev = NULL;
             elm->next = NULL;
             elm->data = property;
             //printf("saxhandler: add property: {%s}\n", property->name);
-            davrq->properties = ucx_dlist_concat(davrq->properties, elm);
+            davrq->properties = ucx_list_concat(davrq->properties, elm);
             
             property = NULL;
         }
@@ -160,7 +160,7 @@
 }
 
 ProppatchHandler::~ProppatchHandler() {
-    ucx_dlist_free(xmlStack);
+    ucx_list_free(xmlStack);
 }
 
 void ProppatchHandler::startElement(
@@ -236,13 +236,13 @@
             /* add the property to the proppatch request */
             switch(updateMode) {
                 case 0: {
-                    davrq->setProps = ucx_dlist_append(
+                    davrq->setProps = ucx_list_append(
                             davrq->setProps,
                             rootElement);
                     break;
                 }
                 case 1: {
-                    davrq->removeProps = ucx_dlist_append(
+                    davrq->removeProps = ucx_list_append(
                             davrq->removeProps,
                             rootElement);
                     break;
--- a/src/server/webdav/saxhandler.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/saxhandler.h	Sun Sep 08 23:27:07 2013 +0200
@@ -39,8 +39,8 @@
 #define XSTACK_PUSH(elm) xstack_push(&xmlStack, elm)
 #define XSTACK_POP() xstack_pop(&xmlStack)
 #define XSTACK_CUR() (xmlStack) ? (XmlElement*)xmlStack->data : NULL;
-void xstack_push(UcxDlist **stack, XmlElement *elm);
-XmlElement* xstack_pop(UcxDlist **stack);
+void xstack_push(UcxList **stack, XmlElement *elm);
+XmlElement* xstack_pop(UcxList **stack);
 
 class PropfindHandler : public DefaultHandler {
 public:
@@ -100,7 +100,7 @@
     bool             davPropTag;
     XmlElement       *rootElement;
     XmlElement       *newElement; 
-    UcxDlist         *xmlStack;
+    UcxList         *xmlStack;
     
     //DavProperty      *property;
     int              updateMode; /* 0 = set, 1 = remove, -1 = undefined */
--- a/src/server/webdav/webdav.c	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/webdav.c	Sun Sep 08 23:27:07 2013 +0200
@@ -31,7 +31,8 @@
 #include <string.h>
 
 #include "webdav.h"
-#include "../ucx/string.h"
+#include <ucx/list.h>
+#include <ucx/string.h>
 #include "../util/pool.h"
 #include "../util/pblock.h"
 #include "../util/date.h"
@@ -541,7 +542,7 @@
         int error)
 {
     // TODO: different errors
-    davrq->notFoundProps = ucx_dlist_append(davrq->notFoundProps, prop);
+    davrq->notFoundProps = ucx_list_append(davrq->notFoundProps, prop);
 }
 
 
@@ -712,7 +713,7 @@
 
 void xmlelm_add_child(XmlElement *parent, XmlElement *child) {
     if(parent->ctlen == 0) {
-        parent->content = ucx_dlist_append(parent->content, child);
+        parent->content = ucx_list_append(parent->content, child);
     }
 }
 
@@ -728,7 +729,7 @@
                 sbuf_append(out, sstrn(" />", 3));
             } else {
                 sbuf_append(out, sstrn(">", 1));
-                DAV_FOREACH(pr, (UcxDlist*)elm->content) {
+                DAV_FOREACH(pr, (UcxList*)elm->content) {
                     xmlelm_write((XmlElement*)pr->data, out, 1);
                 }
                 sbuf_append(out, sstrn("</", 2));
@@ -764,14 +765,14 @@
 
 void propstat_add(Propstat *propstat, int status, XmlElement *prop) {
     if(status == 200) {
-        propstat->okprop = ucx_dlist_append(propstat->okprop, prop);
+        propstat->okprop = ucx_list_append(propstat->okprop, prop);
     } else {
         UcxKey key;
         key.data = &status;
         key.len = sizeof(int);
 
-        UcxDlist *list = ucx_map_get(propstat->map, key);
-        list = ucx_dlist_append(list, prop);
+        UcxList *list = ucx_map_get(propstat->map, key);
+        list = ucx_list_append(list, prop);
 
         ucx_map_put(propstat->map, key, list);
     }
@@ -790,7 +791,7 @@
     }
     
     UcxMapIterator iter = ucx_map_iterator(propstat->map);
-    UcxDlist *proplist;
+    UcxList *proplist;
     UCX_MAP_FOREACH(key, proplist, iter) { 
         if(proplist) {
             sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
--- a/src/server/webdav/webdav.h	Wed Jul 31 13:02:06 2013 +0200
+++ b/src/server/webdav/webdav.h	Sun Sep 08 23:27:07 2013 +0200
@@ -30,17 +30,17 @@
 #define	WEBDAV_H
 
 #include "../public/webdav.h"
+#include "../util/strbuf.h"
 
-#include "../ucx/map.h"
-#include "../ucx/dlist.h"
-#include "../util/strbuf.h"
+#include <ucx/map.h>
+#include <ucx/list.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
 #define DAV_FOREACH(elem, list) \
-        for (UcxDlist *elem = list ; elem != NULL ; elem = elem->next)
+        for (UcxList *elem = list ; elem != NULL ; elem = elem->next)
 
 int webdav_init(pblock *pb, Session *sn, Request *rq);
 int webdav_setcollection(pblock *pb, Session *sn, Request *rq);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/Makefile	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,56 @@
+#
+# 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.
+#
+
+BUILD_ROOT = ../..
+
+include $(BUILD_ROOT)/config.mk
+
+# list of source files
+SRC  = utils.c
+SRC += list.c
+SRC += map.c
+SRC += properties.c
+SRC += mempool.c
+SRC += string.c
+SRC += test.c
+SRC += allocator.c
+SRC += logging.c
+SRC += buffer.c
+
+OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/ucx/%$(OBJ_EXT))
+
+all: $(BUILD_ROOT)/build/ucx $(BUILD_ROOT)/build/lib/libucx$(LIB_EXT)
+
+$(BUILD_ROOT)/build/lib/libucx$(LIB_EXT): $(OBJ)
+	$(CC) $(SHLIB_LDFLAGS) -o $@ $(OBJ)
+
+$(BUILD_ROOT)/build/ucx/%$(OBJ_EXT): %.c
+	$(CC) $(CFLAGS) $(SHLIB_CFLAGS) -c -o $@ $<
+
+$(BUILD_ROOT)/build/ucx:
+	mkdir -p $(BUILD_ROOT)/build/ucx
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/allocator.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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);
+}
+
+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);
+}
+
+void ucx_default_free(void *ignore, void *data) {
+    free(data);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/allocator.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,171 @@
+/*
+ * 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"
+
+#ifdef	__cplusplus
+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;
+    /**
+     * 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_free }
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_ALLOCATOR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/buffer.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,214 @@
+/*
+ * 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>
+#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 = (char*)malloc(size);
+            if (!buffer->space) {
+                free(buffer);
+                return NULL;
+            }
+            memset(buffer->space, 0, size);
+            buffer->flags |= UCX_BUFFER_AUTOFREE;
+        } else {
+            buffer->space = (char*)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 = (char*)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) {
+    size_t npos;
+    switch (whence) {
+    case SEEK_CUR:
+        npos = buffer->pos;
+        break;
+    case SEEK_END:
+        npos = buffer->size;
+        break;
+    default:
+        npos = 0;
+    }
+
+    npos += offset;
+    
+    if (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 = (char*)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_puts(UcxBuffer *buffer, char *str) {
+    return ucx_buffer_write((const void*)str, 1, strlen(str), buffer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/buffer.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,267 @@
+/*
+ * 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 buffer.h
+ * 
+ * Advanced buffer implementation.
+ * 
+ * Instances of UcxBuffer can be used to read from or to write to like one
+ * would do with a stream. This allows the use of ucx_stream_copy() to copy
+ * contents from one buffer to another.
+ * 
+ * Some features for convenient use of the buffer
+ * can be enabled. See the documentation of the macro constants for more
+ * information.
+ * 
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_BUFFER_H
+#define	UCX_BUFFER_H
+
+#include "ucx.h"
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/**
+ * No buffer features enabled (all flags cleared).
+ */
+#define UCX_BUFFER_DEFAULT      0x00
+
+/**
+ * If this flag is enabled, the buffer will automatically free its contents.
+ */
+#define UCX_BUFFER_AUTOFREE     0x01
+
+/**
+ * If this flag is enabled, the buffer will automatically extends its capacity.
+ */
+#define UCX_BUFFER_AUTOEXTEND   0x02
+
+/** UCX Buffer. */
+typedef struct {
+    /** A pointer to the buffer contents. */
+    char *space;
+    /** Current position of the buffer. */
+    size_t pos;
+    /** Current capacity (i.e. maximum size) of the buffer. */
+    size_t capacity;
+    /** Current size of the buffer content. */
+    size_t size;
+    /**
+     * Flag register for buffer features.
+     * @see #UCX_BUFFER_DEFAULT
+     * @see #UCX_BUFFER_AUTOFREE
+     * @see #UCX_BUFFER_AUTOEXTEND
+     */
+    int flags;
+} UcxBuffer;
+
+/**
+ * Creates a new buffer.
+ * 
+ * <b>Note:</b> you may provide <code>NULL</code> as argument for
+ * <code>space</code>. Then this function will allocate the space and enforce
+ * the #UCX_BUFFER_AUTOFREE flag.
+ * 
+ * @param space pointer to the memory area, or <code>NULL</code> to allocate
+ * new memory
+ * @param size the size of the buffer
+ * @param flags buffer features (see UcxBuffer.flags)
+ * @return the new buffer
+ */
+UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags);
+
+/**
+ * Destroys a buffer.
+ * 
+ * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer
+ * are also freed.
+ * 
+ * @param buffer the buffer to destroy
+ */
+void ucx_buffer_free(UcxBuffer* buffer);
+
+/**
+ * Creates a new buffer and fills it with extracted content from another buffer.
+ * 
+ * <b>Note:</b> the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer.
+ * 
+ * @param src the source buffer
+ * @param start the start position of extraction
+ * @param length the count of bytes to extract or 0 if all of the remaining
+ * bytes shall be extracted
+ * @param flags feature mask for the new buffer
+ * @return 
+ */
+UcxBuffer* ucx_buffer_extract(UcxBuffer *src,
+        size_t start, size_t length, int flags);
+
+/**
+ * A shorthand macro for the full extraction of the buffer.
+ * 
+ * @param src the source buffer
+ * @param flags feature mask for the new buffer
+ * @return a new buffer with the extracted content
+ */
+#define ucx_buffer_clone(src,flags) \
+    ucx_buffer_extract(src, 0, 0, flags)
+
+/**
+ * Moves the position of the buffer.
+ * 
+ * The new position is relative to the <code>whence</code> argument.
+ *
+ * SEEK_SET marks the start of the buffer.
+ * SEEK_CUR marks the current position.
+ * SEEK_END marks the first 0-byte in the buffer.
+ * 
+ * @param buffer
+ * @param offset position offset relative to <code>whence</code>
+ * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END
+ * @return 0 on success, non-zero if the position is invalid
+ *
+ */
+int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence);
+
+/**
+ * Clears the buffer by resetting the position and deleting the data.
+ * 
+ * The data is deleted by a zeroing it with call to <code>memset()</code>.
+ * 
+ * @param buffer the buffer to be cleared
+ */
+#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \
+        buffer->size = 0; buffer->pos = 0;
+
+/**
+ * Tests, if the buffer position has exceeded the buffer capacity.
+ * 
+ * @param buffer the buffer to test
+ * @return non-zero, if the current buffer position has exceeded the last
+ * available byte of the buffer.
+ */
+int ucx_buffer_eof(UcxBuffer *buffer);
+
+
+/**
+ * Extends the capacity of the buffer.
+ * 
+ * <b>Note:</b> The buffer capacity increased by a power of two. I.e.
+ * the buffer capacity is doubled, as long as it would not hold the current
+ * content plus the additional required bytes.
+ * 
+ * <b>Attention:</b> the argument provided is the count of <i>additional</i>
+ * bytes the buffer shall hold. It is <b>NOT</b> the total count of bytes the
+ * buffer shall hold.
+ * 
+ * @param buffer the buffer to extend
+ * @param additional_bytes the count of additional bytes the buffer shall
+ * <i>at least</i> hold
+ * @return 0 on success or a non-zero value on failure
+ */
+int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes);
+
+/**
+ * Writes data to an UcxBuffer.
+ * 
+ * The position of the buffer is increased by the number of bytes read.
+ * 
+ * @param ptr a pointer to the memory area containing the bytes to be written
+ * @param size the length of one element
+ * @param nitems the element count
+ * @param buffer the UcxBuffer to write to
+ * @return the total count of bytes written
+ */
+size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer);
+
+/**
+ * Reads data from an UcxBuffer.
+ * 
+ * The position of the buffer is increased by the number of bytes read.
+ * 
+ * @param ptr a pointer to the memory area where to store the read data
+ * @param size the length of one element
+ * @param nitems the element count
+ * @param buffer the UcxBuffer to read from
+ * @return the total count of bytes read
+ */
+size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
+        UcxBuffer *buffer);
+
+/**
+ * Writes a character to a buffer.
+ * 
+ * The least significant byte of the argument is written to the buffer. If the
+ * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled,
+ * the buffer capacity is extended by ucx_buffer_extend(). If the feature is
+ * disabled or buffer extension fails, <code>EOF</code> is returned.
+ * 
+ * On successful write the position of the buffer is increased.
+ * 
+ * @param buffer the buffer to write to
+ * @param c the character to write as <code>int</code> value
+ * @return the byte that has bean written as <code>int</code> value or
+ * <code>EOF</code> when the end of the stream is reached and automatic
+ * extension is not enabled or not possible
+ */
+int ucx_buffer_putc(UcxBuffer *buffer, int c);
+
+/**
+ * Gets a character from a buffer.
+ * 
+ * The current position of the buffer is increased after a successful read.
+ * 
+ * @param buffer the buffer to read from
+ * @return the character as <code>int</code> value or <code>EOF</code>, if the
+ * end of the buffer is reached
+ */
+int ucx_buffer_getc(UcxBuffer *buffer);
+
+/**
+ * Writes a string to a buffer.
+ * 
+ * @param buffer the buffer
+ * @param str the string
+ * @return the number of bytes written
+ */
+size_t ucx_buffer_puts(UcxBuffer *buffer, char *str);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_BUFFER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/list.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,321 @@
+/*
+ * 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 *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) {
+        if (fnc) {
+            ret = ucx_list_append_a(alloc, ret, fnc(l->data, data));
+        } else {
+            ret = ucx_list_append_a(alloc, 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) {
+    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;
+        alloc->free(alloc->pool, f);
+    }
+}
+
+UcxList *ucx_list_append(UcxList *l, void *data)  {
+    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) {
+        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) {
+    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) {
+        nl->next = l;
+        l->prev = nl;
+    }
+    return nl;
+}
+
+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;
+    }
+}
+
+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;
+}
+
+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 && index > 0) {
+        e = e->next;
+        index--;
+    }
+    
+    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;
+    
+    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
+    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;
+
+    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;
+    }
+}
+
+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) {
+    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 {
+        e->prev->next = e->next;
+        e->next->prev = e->prev;
+    }
+    alloc->free(alloc->pool, e);
+    return l;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/list.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,378 @@
+/*
+ * 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 UCX_LIST_H
+#define	UCX_LIST_H
+
+#include "ucx.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;
+};
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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	/* UCX_LIST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/logging.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,108 @@
+/*
+ * 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(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_free(UcxLogger *logger) {
+    ucx_map_free(logger->levels);
+    free(logger);
+}
+
+// estimated max. message length (documented)
+#define UCX_LOGGER_MSGMAX 4096
+
+void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file,
+        const unsigned int line, const char *format, ...) {
+    if (level <= logger->level) {
+        char msg[UCX_LOGGER_MSGMAX];
+        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;
+#ifdef _WIN32
+            k += _snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line);
+#else
+            k += snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line);
+#endif /* _WIN32 */
+        }
+        
+        msg[k++] = '-'; msg[k++] = ' ';
+        
+        va_list args;
+        va_start (args, format);
+        k += vsnprintf(msg+k, UCX_LOGGER_MSGMAX-k-1, format, args);
+        va_end (args);        
+        
+        msg[k++] = '\n';
+        
+        logger->writer(msg, 1, k, logger->stream);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/logging.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,237 @@
+/*
+ * 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* leave enough space for custom log levels */
+
+/** 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 {
+    /** 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;
+
+/**
+ * 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>
+ * 
+ * <b>Attention:</b> the message (including automatically generated information)
+ * <b>MUST NOT</b> exceed the size of 4 KB.
+ * 
+ * @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, ...);
+
+/**
+ * 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 /* UCX_LOGGING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/map.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,315 @@
+/*
+ * 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 "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*)allocator->malloc(allocator->pool, sizeof(UcxMap));
+    if (!map) {
+        return NULL;
+    }
+    
+    map->allocator = allocator;
+    map->map = (UcxMapElement**)allocator->calloc(
+            allocator->pool,
+            size,
+            sizeof(UcxMapElement*));
+    if(map->map == NULL) {
+        allocator->free(allocator->pool, map);
+        return NULL;
+    }
+    map->size = size;
+    map->count = 0;
+
+    return 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;
+                map->allocator->free(map->allocator->pool, elem->key.data);
+                map->allocator->free(map->allocator->pool, elem);
+                elem = next;
+            } while (elem != NULL);
+        }
+    }
+    map->allocator->free(map->allocator->pool, map->map);
+}
+
+void ucx_map_free(UcxMap *map) {
+    ucx_map_free_elmlist(map);
+    map->allocator->free(map->allocator->pool, map);
+}
+
+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(key, value, i) {
+        if (ucx_map_put(to, key, fnc ? fnc(value, data) : value)) {
+            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) {
+        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;
+        oldmap.allocator = map->allocator;
+        
+        map->size = (map->count * 5) >> 1;
+        map->map = (UcxMapElement**)map->allocator->calloc(
+                map->allocator->pool,
+                map->size,
+                sizeof(UcxMapElement*));
+        if (!map->map) {
+            *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) {
+    UcxAllocator *allocator = map->allocator;
+    
+    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 && elm->key.hash < key.hash) {
+        prev = elm;
+        elm = elm->next;
+    }
+    
+    if (!elm || elm->key.hash != key.hash) {
+        UcxMapElement *e = (UcxMapElement*)allocator->malloc(
+                allocator->pool,
+                sizeof(UcxMapElement));
+        if (!e) {
+            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) {
+        void *kd = allocator->malloc(allocator->pool, key.len);
+        if (!kd) {
+            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;
+                    }
+                    map->allocator->free(map->allocator->pool, elm->key.data);
+                    map->allocator->free(map->allocator->pool, 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, UcxKey *key, void **elm) {
+    UcxMapElement *e = i->cur;
+    
+    if (e) {
+        e = e->next;
+    } else {
+        e = i->map->map[0];
+    }
+    
+    while (i->index < i->map->size) {
+        if (e) {
+            if (e->data) {
+                i->cur = e;
+                *elm = e->data;
+                *key = e->key;
+                return 1;
+            }
+
+            e = e->next;
+        } else {
+            i->index++;
+            
+            if (i->index < i->map->size) {
+                e = i->map->map[i->index];
+            }
+        }
+    }
+    
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/map.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,392 @@
+/*
+ * 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 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 "allocator.h"
+#include <stdio.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/**
+ * Loop statement for UCX maps.
+ * 
+ * The <code>key</code> variable is implicitly defined, but the
+ * <code>value</code> variable must be already declared as type information
+ * cannot be inferred.
+ * 
+ * @param key the variable name for the key
+ * @param value the variable name for the value
+ * @param iter an UcxMapIterator
+ * @see ucx_map_iterator()
+ */
+#define UCX_MAP_FOREACH(key,value,iter) \
+        for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&value);)
+
+/** Type for the UCX map. @see UcxMap */
+typedef struct UcxMap          UcxMap;
+
+/** Type for a key of an UcxMap. @see UcxKey */
+typedef struct UcxKey          UcxKey;
+
+/** Type for an element of an UcxMap. @see UcxMapElement */
+typedef struct UcxMapElement   UcxMapElement;
+
+/** Type for an iterator over an UcxMap. @see UcxMapIterator */
+typedef struct UcxMapIterator  UcxMapIterator;
+
+/** Structure for the UCX map. */
+struct UcxMap {
+    /** An allocator that is used for the map elements. */
+    UcxAllocator  *allocator;
+    /** The array of map element lists. */
+    UcxMapElement **map;
+    /** The size of the map is the length of the element list array. */
+    size_t        size;
+    /** The count of elements currently stored in this map. */
+    size_t        count;
+};
+
+/** Structure for a key of an UcxMap. */
+struct UcxKey {
+    /** The key data. */
+    void   *data;
+    /** The length of the key data. */
+    size_t len;
+    /** The hash value of the key data. */
+    int    hash;
+};
+
+/** Structure for an element of an UcxMap. */
+struct UcxMapElement {
+    /** The value data. */
+    void          *data;
+    
+    /** A pointer to the next element in the current list. */
+    UcxMapElement *next;
+    
+    /** The corresponding key. */
+    UcxKey        key;
+};
+
+/** Structure for an iterator over an UcxMap. */
+struct UcxMapIterator {
+    /** The map to iterate over. */
+    UcxMap        *map;
+    
+    /** The current map element. */
+    UcxMapElement *cur;
+    
+    /**
+     * The current index of the element list array.
+     * <b>Attention: </b> this is <b>NOT</b> the element index! Do <b>NOT</b>
+     * manually iterate over the map by increasing this index. Use
+     * ucx_map_iter_next().
+     * @see UcxMap.map*/
+    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);
+
+/**
+ * Copies contents from a map to another map using a copy function.
+ * 
+ * <b>Note:</b> The destination map does not need to be empty. However, if it
+ * contains data with keys that are also present in the source map, the contents
+ * are overwritten.
+ * 
+ * @param from the source map
+ * @param to the destination map
+ * @param fnc the copy function or <code>NULL</code> if the pointer address
+ * shall be copied
+ * @param data additional data for the copy function
+ * @return 0 on success or a non-zero value on memory allocation errors
+ */
+int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to,
+        copy_func fnc, void *data);
+
+/**
+ * Clones the map and rehashes if necessary.
+ * 
+ * <b>Note:</b> In contrast to ucx_map_rehash() the load factor is irrelevant.
+ * This function <i>always</i> ensures a new UcxMap.size of at least
+ * 2.5*UcxMap.count.
+ * 
+ * @param map the map to clone
+ * @param fnc the copy function to use or <code>NULL</code> if the new and
+ * the old map shall share the data pointers
+ * @param data additional data for the copy function
+ * @return the cloned map
+ * @see ucx_map_copy()
+ */
+UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data);
+
+/**
+ * Increases size of the hash map, if necessary.
+ * 
+ * The load value is 0.75*UcxMap.size. If the element count exceeds the load
+ * value, the map needs to be rehashed. Otherwise no action is performed and
+ * this function simply returns 0.
+ * 
+ * The rehashing process ensures, that the UcxMap.size is at least
+ * 2.5*UcxMap.count. So there is enough room for additional elements without
+ * the need of another soon rehashing.
+ * 
+ * You can use this function to dramatically increase access performance.
+ * 
+ * @param map the map to rehash
+ * @return 1, if a memory allocation error occurred, 0 otherwise
+ */
+int ucx_map_rehash(UcxMap *map);
+
+/**
+ * Puts a key/value-pair into the map.
+ * 
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ */
+int ucx_map_put(UcxMap *map, UcxKey key, void *value);
+
+/**
+ * Retrieves a value by using a key.
+ * 
+ * @param map the map
+ * @param key the key
+ * @return the value
+ */
+void* ucx_map_get(UcxMap *map, UcxKey key);
+
+/**
+ * Removes a key/value-pair from the map by using the key.
+ * 
+ * @param map the map
+ * @param key the key
+ * @return the removed value
+ */
+void* ucx_map_remove(UcxMap *map, UcxKey key);
+
+/**
+ * Shorthand for putting data with a sstr_t key into the map.
+ * @param map the map
+ * @param key the key
+ * @param value the value
+ * @return 0 on success, non-zero value on failure
+ * @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
+ * @return 0 on success, non-zero value on failure
+ * @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
+ * @return 0 on success, non-zero value on failure
+ * @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
+ * @return the value
+ * @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.
+ * @param map the map
+ * @param key the key
+ * @return the value
+ * @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
+ * @return the value
+ * @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
+ * @return the removed value
+ * @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
+ * @return the removed value
+ * @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
+ * @return the removed value
+ * @see ucx_map_remove()
+ */
+#define ucx_map_int_remove(map, key) \
+    ucx_map_remove(map, ucx_key((void*)&key, sizeof(key)))
+
+/**
+ * Creates an UcxKey based on the given data.
+ * 
+ * This function implicitly computes the hash.
+ * 
+ * @param data the data for the key
+ * @param len the length of the data
+ * @return an UcxKey with implicitly computed hash
+ * @see ucx_hash()
+ */
+UcxKey ucx_key(void *data, size_t len);
+
+/**
+ * Computes a murmur hash-2.
+ * 
+ * @param data the data to hash
+ * @param len the length of the data
+ * @return the murmur hash-2 of the data
+ */
+int ucx_hash(const char *data, size_t len);
+
+/**
+ * Creates an iterator for a map.
+ * 
+ * <b>Note:</b> An UcxMapIterator iterates over all elements in all element
+ * lists successively. Therefore the order highly depends on the key hashes and
+ * may vary under different map sizes. So generally you may <b>NOT</b> rely on
+ * the iteration order.
+ * 
+ * <b>Note:</b> The iterator is <b>NOT</b> initialized. You need to call
+ * ucx_map_iter_next() at least once before accessing any information. However,
+ * it is not recommended to access the fields of an UcxMapIterator directly.
+ * 
+ * @param map the map to create the iterator for
+ * @return an iterator initialized on the first element of the
+ * first element list
+ * @see ucx_map_iter_next()
+ */
+UcxMapIterator ucx_map_iterator(UcxMap *map);
+
+/**
+ * Proceeds to the next element of the map (if any).
+ * 
+ * Subsequent calls on the same iterator proceed to the next element and
+ * store the key/value-pair into the memory specified as arguments of this
+ * function.
+ * 
+ * If no further elements are found, this function returns zero and leaves the
+ * last found key/value-pair in memory.
+ * 
+ * @param iterator the iterator to use
+ * @param key a pointer to the memory where to store the key
+ * @param value a pointer to the memory where to store the value
+ * @return 1, if another element was found, 0 if all elements has been processed
+ * @see ucx_map_iterator()
+ */
+int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_MAP_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/mempool.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,204 @@
+/*
+ * 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"
+
+/** Capsule for destructible memory chunks. */
+typedef struct {
+    /** The destructor for the memory chunk. */
+    ucx_destructor destructor;
+    /**
+     * First byte of the memory chunk.
+     * Note, that the address <code>&amp;c</code> is also the address
+     * of the whole memory chunk.
+     */
+    char c;
+} ucx_memchunk;
+
+/** Capsule for data and its destructor. */
+typedef struct {
+    /** The destructor for the data. */
+    ucx_destructor destructor;
+    /** A pointer to the data. */
+    void           *ptr;
+} ucx_regdestr;
+
+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) {
+        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) {
+        pool->data = data; 
+        pool->size = newcap;
+        return EXIT_SUCCESS;
+    } else {
+        return EXIT_FAILURE;
+    }
+}
+
+void *ucx_mempool_malloc(UcxMempool *pool, size_t n) {
+    if (pool->ndata >= pool->size) {
+        // The hard coded 16 is documented for this function and ucx_mempool_new
+        if (ucx_mempool_chcap(pool, pool->size + 16) == EXIT_FAILURE) {
+            return NULL;
+        }
+    }
+
+    ucx_memchunk *mem = (ucx_memchunk*)malloc(sizeof(ucx_destructor) + n);
+    if (!mem) {
+        return NULL;
+    }
+
+    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) {
+        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) {
+        return NULL;
+    }
+    if (mem != newm) {
+        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",
+          (intptr_t)ptr, (intptr_t)pool);
+        exit(EXIT_FAILURE);
+    } else {
+        return newm + sizeof(ucx_destructor);
+    }
+}
+
+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->data[last_index] = NULL;
+            }
+            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(size_t i=0 ; i<pool->ndata ; i++) {
+        chunk = (ucx_memchunk*) pool->data[i];
+        if(chunk) {
+            if(chunk->destructor) {
+                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);
+}
+
+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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/mempool.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,226 @@
+/*
+ * 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 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>
+#include "allocator.h"
+
+#ifdef	__cplusplus
+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;
+
+/** Shorthand for a new default memory pool with a capacity of 16 elements. */
+#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);
+
+/**
+ * Changes the pool size to the next smallest multiple of 16.
+ * 
+ * You may use this macro, to reduce the pool size after freeing
+ * many pooled memory items.
+ * 
+ * @param pool the pool to clamp
+ * @return <code>EXIT_SUCCESS</code> on success or
+ * <code>EXIT_FAILURE</code> on failure
+ */
+#define ucx_mempool_clamp(pool) ucx_mempool_chcap(pool, \
+        (pool->ndata & ~0xF)+0x10)
+
+/**
+ * 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.
+ * 
+ * If the memory to be reallocated is not contained by the specified pool, this
+ * function will possibly fail. In case the memory had to be moved to another
+ * location, this function will print out a message to <code>stderr</code>
+ * and exit the program with error code <code>EXIT_FAILURE</code>.
+ * 
+ * @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);
+
+/**
+ * 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	/* UCX_MEMPOOL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/properties.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,264 @@
+/*
+ * 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;
+    }
+}
+
+// buffer size is documented - change doc, when you change bufsize!
+#define UCX_PROPLOAD_BUFSIZE  1024
+int ucx_properties_load(UcxMap *map, FILE *file) {
+    UcxProperties *parser = ucx_properties_new();
+    if(!(parser && map && file)) {
+        return 1;
+    }
+    
+    int error = 0;
+    size_t r;
+    char buf[UCX_PROPLOAD_BUFSIZE];
+    while((r = fread(buf, 1, UCX_PROPLOAD_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);
+    void *v;
+    sstr_t value;
+    size_t written;
+
+    UCX_MAP_FOREACH(k, v, iter) {
+        value = sstr((char*)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/src/ucx/properties.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,220 @@
+/*
+ * 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 */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/string.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,313 @@
+/*
+ * 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 <stdarg.h>
+
+#include "string.h"
+#include "allocator.h"
+
+sstr_t sstr(char *cstring) {
+    sstr_t string;
+    string.ptr = cstring;
+    string.length = strlen(cstring);
+    return string;
+}
+
+sstr_t sstrn(char *cstring, size_t length) {
+    sstr_t string;
+    string.ptr = cstring;
+    string.length = length;
+    return string;
+}
+
+size_t sstrnlen(size_t n, sstr_t s, ...) {
+    va_list ap;
+    size_t size = s.length;
+    va_start(ap, s);
+
+    for (size_t i = 1 ; i < n ; i++) {
+        sstr_t str = va_arg(ap, sstr_t);
+        size += str.length;
+    }
+    va_end(ap);
+
+    return size;
+}
+
+sstr_t sstrncat(sstr_t s, size_t n, sstr_t c1, ...) {
+    va_list ap;
+    va_start(ap, c1);
+    s.ptr[0] = 0;
+    
+    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 (size_t i = 1 ; i < n ; i++) {
+        sstr_t str = va_arg (ap, sstr_t);
+        cplen = str.length > len ? len : str.length;
+        if(cplen <= 0) {
+            va_end(ap);
+            return s;
+        }
+        memcpy(ptr, str.ptr, cplen);
+        len -= cplen;
+        ptr += cplen;
+    }
+    va_end(ap);
+    s.length = ptr - s.ptr;
+
+    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 >= s.length) {
+        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 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 sstrrchr(sstr_t s, int c) {
+    if (s.length > 0) {
+        for(size_t i=s.length;i>0;i--) {
+            if(s.ptr[i-1] == c) {
+                return sstrsubs(s, i-1);
+            }
+        }
+    }
+    sstr_t n;
+    n.ptr = NULL;
+    n.length = 0;
+    return n;
+}
+
+sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) {
+    return sstrsplit_a(ucx_default_allocator(), s, d, n);
+}
+
+sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, size_t *n) {
+    if (s.length == 0 || d.length == 0) {
+        *n = -1;
+        return NULL;
+    }
+
+    sstr_t* result;
+    size_t nmax = *n;
+    *n = 1;
+
+    /* special case: exact match - no processing needed */
+    if (sstrcmp(s, d) == 0) {
+        *n = 0;
+        return NULL;
+    }
+    sstr_t sv = sstrdup(s);
+    if (sv.length == 0) {
+        *n = -2;
+        return NULL;
+    }
+
+    for (size_t i = 0 ; i < s.length ; i++) {
+        if (sv.ptr[i] == d.ptr[0]) {
+            _Bool match = 1;
+            for (size_t 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 (size_t j = 0 ; j < d.length ; j++) {
+                    sv.ptr[i+j] = 0;
+                }
+                i += d.length;
+            }
+        }
+        if ((*n) == nmax) break;
+    }
+    result = (sstr_t*) allocator->malloc(allocator->pool, sizeof(sstr_t)*(*n));
+
+    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;
+        }
+    } else {
+        *n = -2;
+    }
+    
+    free(sv.ptr);
+
+    return result;
+}
+
+int sstrcmp(sstr_t s1, sstr_t s2) {
+    if (s1.length == s2.length) {
+        return memcmp(s1.ptr, s2.ptr, s1.length);
+    } else if (s1.length > s2.length) {
+        return 1;
+    } else {
+        return -1;
+    }
+}
+
+int sstrcasecmp(sstr_t s1, sstr_t s2) {
+    if (s1.length == s2.length) {
+#ifdef _WIN32
+        return _strnicmp(s1.ptr, s2.ptr, s1.length);
+#else
+        return strncasecmp(s1.ptr, s2.ptr, s1.length);
+#endif
+    } 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*)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;
+}
+
+int sstrprefix(sstr_t string, sstr_t prefix) {
+    if (string.length == 0) {
+        return prefix.length == 0;
+    }
+    if (prefix.length == 0) {
+        return 1;
+    }
+    
+    if (prefix.length > string.length) {
+        return 0;
+    } else {
+        return memcmp(string.ptr, prefix.ptr, prefix.length) == 0;
+    }
+}
+
+int sstrsuffix(sstr_t string, sstr_t suffix) {
+    if (string.length == 0) {
+        return suffix.length == 0;
+    }
+    if (suffix.length == 0) {
+        return 1;
+    }
+    
+    if (suffix.length > string.length) {
+        return 0;
+    } else {
+        return memcmp(string.ptr+string.length-suffix.length,
+            suffix.ptr, suffix.length) == 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/string.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,392 @@
+/*
+ * 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.
+ */
+/**
+ * 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 UCX_STRING_H
+#define	UCX_STRING_H
+
+#include "ucx.h"
+#include "allocator.h"
+#include <stddef.h>
+
+/** 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
+
+/**
+ * The UCX string structure.
+ */
+typedef struct {
+   /** A reference to the string (<b>not necessarily  <code>NULL</code>
+    * -terminated</b>) */
+    char   *ptr;
+    /** The length of the string */
+    size_t length;
+} sstr_t;
+
+/**
+ * Creates a new sstr_t based on a C string.
+ * 
+ * The length is implicitly inferred by using a call to <code>strlen()</code>.
+ *
+ * <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 *cstring);
+
+/**
+ * Creates a new sstr_t of the specified length based on a C 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 *cstring, size_t length);
+
+
+/**
+ * Returns the cumulated length of all specified strings.
+ *
+ * At least one string must be specified.
+ * 
+ * <b>Attention:</b> if the count argument does not match the count of the
+ * specified strings, the behavior is undefined.
+ *
+ * @param count    the total number of specified strings (so at least 1)
+ * @param string   the first string
+ * @param ...      all other strings
+ * @return the cumulated length of all strings
+ */
+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, ...);
+
+
+/**
+ * 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 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 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 first location of <code>chr</code>
+ * 
+ * @see sstrsubs()
+ */
+sstr_t sstrchr(sstr_t string, int chr);
+
+/**
+ * Returns a substring starting at the location of the last occurrence of the
+ * specified character.
+ * 
+ * If the string does not contain the character, an empty string is returned.
+ * 
+ * @param string the string where to locate the character
+ * @param chr    the character to locate
+ * @return       a substring starting at the last location of <code>chr</code>
+ * 
+ * @see sstrsubs()
+ */
+sstr_t sstrrchr(sstr_t string, int chr);
+
+/**
+ * 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.
+ *
+ * @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 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);
+
+/**
+ * Compares two UCX strings ignoring the case.
+ * 
+ * At first it compares the sstr_t.length attribute of the two strings. If and
+ * only if the lengths match, both strings are compared char by char ignoring
+ * the case.
+ * 
+ * @param s1 the first string
+ * @param s2 the second string
+ * @return -1, if the length of s1 is less than the length of s2 or 1, if the 
+ * length of s1 is greater than the length of s2 or the difference between the
+ * first two differing characters otherwise (i.e. 0 if the strings match and
+ * no characters differ)
+ */
+int sstrcasecmp(sstr_t s1, sstr_t s2);
+
+/**
+ * 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);
+
+/**
+ * Checks, if a string has a specific prefix.
+ * @param string the string to check
+ * @param prefix the prefix the string should have
+ * @return 1, if and only if the string has the specified prefix, 0 otherwise
+ */
+int sstrprefix(sstr_t string, sstr_t prefix);
+
+/**
+ * Checks, if a string has a specific suffix.
+ * @param string the string to check
+ * @param suffix the suffix the string should have
+ * @return 1, if and only if the string has the specified suffix, 0 otherwise
+ */
+int sstrsuffix(sstr_t string, sstr_t suffix);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UCX_STRING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/test.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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 "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) {
+    UcxTestList *l = suite->tests;
+    while (l != NULL) {
+        UcxTestList *e = l;
+        l = l->next;
+        free(e);
+    }
+    free(suite);
+}
+
+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;
+    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",
+            suite->success+suite->failure, suite->success, suite->failure);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/test.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,241 @@
+/*
+ * 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: test.h
+ * 
+ * UCX Test Framework.
+ * 
+ * Usage of this test framework:
+ *
+ * **** IN HEADER FILE: ****
+ *
+ * <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>
+ *
+ * <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().
+ * 
+ *
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ *
+ */
+
+#ifndef UCX_TEST_H
+#define	UCX_TEST_H
+
+#include "ucx.h"
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.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
+
+/** Type for the UcxTestSuite. */
+typedef struct UcxTestSuite UcxTestSuite;
+
+/** Pointer to a test function. */
+typedef void(*UcxTest)(UcxTestSuite*,FILE*);
+
+/** Type for the internal list of test cases. */
+typedef struct UcxTestList UcxTestList;
+
+/** Structure for the internal list of test cases. */
+struct UcxTestList {
+    
+    /** Test case. */
+    UcxTest test;
+    
+    /** Pointer to the next list element. */
+    UcxTestList *next;
+};
+
+/**
+ * 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();
+
+/**
+ * Destroys a test suite.
+ * @param suite the test suite to destroy
+ */
+void ucx_test_suite_free(UcxTestSuite* suite);
+
+/**
+ * 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);
+
+/**
+ * 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);\
+    }
+
+/**
+ * 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	/* UCX_TEST_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/ucx.c	Sun Sep 08 23:27:07 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"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/ucx.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+/**
+ * Main UCX Header providing most common definitions.
+ * 
+ * @file   ucx.h
+ * @author Mike Becker
+ * @author Olaf Wintermann
+ */
+
+#ifndef UCX_H
+#define	UCX_H
+
+/** Major UCX version as integer constant. */
+#define UCX_VERSION_MAJOR   1
+
+/** Minor UCX version as integer constant. */
+#define UCX_VERSION_MINOR   0
+
+/** The UCX version in format [major].[minor] */
+#define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR
+
+#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
+/** Use C naming even when compiling with C++.  */
+#define UCX_EXTERN extern "C"
+extern "C" {
+#else
+/** Pointless in C. */
+#define UCX_EXTERN
+#endif
+
+/**
+ * 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*);
+
+/**
+ * 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*);
+
+/**
+ * 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*);
+
+/**
+ * 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
+}
+#endif
+
+#endif	/* UCX_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/utils.c	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,244 @@
+/*
+ * 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>
+#include <stdio.h>
+#include <limits.h>
+#include <errno.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;
+}
+
+size_t ucx_stream_copy(void *src, void *dest, read_func readfnc,
+        write_func writefnc, char* buf, size_t bufsize, size_t n) {
+    if(n == 0 || bufsize == 0) {
+        return 0;
+    }
+    
+    size_t ncp = 0;
+    if (!buf) {
+        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, src)) != 0) {
+        r = writefnc(buf, 1, r, dest);
+        ncp += r;
+        n -= r;
+        rn = bufsize > n ? n : bufsize;
+        if(r == 0 || n == 0) {
+            break;
+        }
+    }
+    
+    free(buf);
+    return ncp;
+}
+
+/* COMPARE FUNCTIONS */
+
+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));
+}
+
+/* PRINTF FUNCTIONS */
+
+#ifdef va_copy
+#define UCX_PRINTF_BUFSIZE 256
+#else
+#pragma message("WARNING: C99 va_copy macro not supported by this platform" \
+                " - limiting ucx_*printf to 2 KiB")
+#define UCX_PRINTF_BUFSIZE 0x800
+#endif
+
+int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) {
+    int ret;
+    va_list ap;
+    va_start(ap, fmt);
+    ret = ucx_vfprintf(stream, wfc, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) {
+    char buf[UCX_PRINTF_BUFSIZE];
+#ifdef va_copy
+    va_list ap2;
+    va_copy(ap2, ap);
+    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
+    if (ret < 0) {
+        return ret;
+    } else if (ret < UCX_PRINTF_BUFSIZE) {
+        return (int)wfc(buf, 1, ret, stream);
+    } else {
+        if (ret == INT_MAX) {
+            errno = ENOMEM;
+            return -1;
+        }
+        
+        int len = ret + 1;
+        char *newbuf = (char*)malloc(len);
+        if (!newbuf) {
+            return -1;
+        }
+        
+        ret = vsnprintf(newbuf, len, fmt, ap2);
+        if (ret > 0) {
+            ret = (int)wfc(newbuf, 1, ret, stream);
+        }
+        free(newbuf);
+    }
+    return ret;
+#else
+    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
+    if (ret < 0) {
+        return ret;
+    } else if (ret < UCX_PRINTF_BUFSIZE) {
+        return (int)wfc(buf, 1, ret, stream);
+    } else {
+        errno = ENOMEM;
+        return -1;
+    }
+#endif
+}
+
+sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) {
+    va_list ap;
+    sstr_t ret;
+    va_start(ap, fmt);
+    ret = ucx_vasprintf(allocator, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) {
+    sstr_t s;
+    s.ptr = NULL;
+    s.length = 0;
+    char buf[UCX_PRINTF_BUFSIZE];
+#ifdef va_copy
+    va_list ap2;
+    va_copy(ap2, ap);
+    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
+    if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
+        s.ptr = (char*)a->malloc(a->pool, ret + 1);
+        s.length = (size_t)ret;
+        memcpy(s.ptr, buf, ret);
+        s.ptr[s.length] = '\0';
+    } else if (ret == INT_MAX) {
+        errno = ENOMEM;
+    } else  {
+        int len = ret + 1;
+        s.ptr = (char*)a->malloc(a->pool, len);
+        ret = vsnprintf(s.ptr, len, fmt, ap2);
+        if (ret < 0) {
+            free(s.ptr);
+            s.ptr = NULL;
+        } else {
+            s.length = (size_t)ret;
+        }
+    }
+#else
+    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
+    if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
+        s.ptr = (char*)a->malloc(a->pool, ret + 1);
+        s.length = (size_t)ret;
+        memcpy(s.ptr, buf, ret);
+        s.ptr[s.length] = '\0';
+    } else {
+        errno = ENOMEM;
+    }
+#endif
+    return s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ucx/utils.h	Sun Sep 08 23:27:07 2013 +0200
@@ -0,0 +1,250 @@
+/*
+ * 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
+ * 
+ * Compare, copy and printf 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"
+#include "allocator.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.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);
+
+
+/**
+ * Reads data from a stream and writes it to another stream.
+ * 
+ * @param src the source stream
+ * @param dest the destination stream
+ * @param rfnc the read function
+ * @param wfnc the write function
+ * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer
+ * shall be implicitly created on the heap
+ * @param bufsize the size of the copy buffer - if <code>NULL</code> was
+ * provided for <code>buf</code>, this is the size of the buffer that shall be
+ * implicitly created
+ * @param n the maximum number of bytes that shall be copied
+ * @return the total number of bytes copied
+  */
+size_t ucx_stream_copy(void *src, void *dest, read_func rfnc, write_func wfnc,
+        char* buf, size_t bufsize, size_t n);
+
+/**
+ * Shorthand for ucx_stream_copy using the default copy buffer.
+ * 
+ * @param src the source stream
+ * @param dest the destination stream
+ * @param rfnc the read function
+ * @param wfnc the write function
+ * @return total number of bytes copied
+ */
+#define ucx_stream_hcopy(src,dest,rfnc,wfnc) ucx_stream_copy(\
+        src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, SIZE_MAX)
+
+/**
+ * Shorthand for ucx_stream_copy using the default copy buffer and a copy limit.
+ * 
+ * @param src the source stream
+ * @param dest the destination stream
+ * @param rfnc the read function
+ * @param wfnc the write function
+ * @param n maximum number of bytes that shall be copied
+ * @return total number of bytes copied
+ */
+#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_copy(\
+        src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, 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 data 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 d1 pointer to double one
+ * @param d2 pointer to double two
+ * @param data 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);
+
+/**
+ * A <code>printf()</code> like function which writes the output to a stream by
+ * using a write_func().
+ * @param stream the stream the data is written to
+ * @param wfc the write function
+ * @param fmt format string
+ * @param ... additional arguments
+ * @return the total number of bytes written
+ */
+int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...);
+
+/**
+ * <code>va_list</code> version of ucx_fprintf().
+ * @param stream the stream the data is written to
+ * @param wfc the write function
+ * @param fmt format string
+ * @param ap argument list
+ * @return the total number of bytes written
+ * @see ucx_fprintf()
+ */
+int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap);
+
+/**
+ * A <code>printf()</code> like function which allocates space for a sstr_t
+ * the result is written to.
+ * 
+ * <b>Attention</b>: The sstr_t data is allocated with the allocators
+ * ucx_allocator_malloc() function. So it is implementation dependent, if
+ * the returned sstr_t.ptr pointer must be passed to the allocators
+ * ucx_allocator_free() function manually.
+ * 
+ * <b>Note</b>: The sstr_t.ptr of the return value will <i>always</i> be
+ * <code>NULL</code>-terminated.
+ * 
+ * @param allocator the UcxAllocator used for allocating the result sstr_t
+ * @param fmt format string
+ * @param ... additional arguments
+ * @return a sstr_t containing the formatted string
+ */
+sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...);
+
+/**
+ * <code>va_list</code> version of ucx_asprintf().
+ * 
+ * @param allocator the UcxAllocator used for allocating the result sstr_t
+ * @param fmt format string
+ * @param ap argument list
+ * @return a sstr_t containing the formatted string
+ * @see ucx_asprintf()
+ */
+sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap);
+
+/**
+ * A <code>printf()</code> like function which writes the output to an
+ * UcxBuffer.
+ * 
+ * @param buffer the buffer the data is written to
+ * @param ... format string and additional arguments
+ * @return the total number of bytes written
+ * @see ucx_fprintf()
+ */
+#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \
+        (write_func)ucx_buffer_write, __VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UCX_UTILS_H */
+

mercurial