fix freebsd build webdav

Sat, 24 Oct 2020 17:34:32 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 24 Oct 2020 17:34:32 +0200
branch
webdav
changeset 260
4779a6fb4fbe
parent 259
0b8692959d37
child 261
f2c772336ecd

fix freebsd build

configure file | annotate | diff | comparison | revisions
make/configure.vm file | annotate | diff | comparison | revisions
make/project.xml file | annotate | diff | comparison | revisions
make/toolchain.sh file | annotate | diff | comparison | revisions
src/server/daemon/acl.c 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/event_bsd.c file | annotate | diff | comparison | revisions
src/server/daemon/objs.mk file | annotate | diff | comparison | revisions
src/server/daemon/request.h file | annotate | diff | comparison | revisions
src/server/daemon/resourcepool.c file | annotate | diff | comparison | revisions
src/server/daemon/resourcepool.h file | annotate | diff | comparison | revisions
src/server/public/nsapi.h file | annotate | diff | comparison | revisions
src/ucx/array.c file | annotate | diff | comparison | revisions
src/ucx/list.c file | annotate | diff | comparison | revisions
src/ucx/logging.c file | annotate | diff | comparison | revisions
src/ucx/map.c file | annotate | diff | comparison | revisions
src/ucx/string.c file | annotate | diff | comparison | revisions
src/ucx/ucx/array.h file | annotate | diff | comparison | revisions
src/ucx/ucx/list.h file | annotate | diff | comparison | revisions
src/ucx/ucx/logging.h file | annotate | diff | comparison | revisions
src/ucx/ucx/map.h file | annotate | diff | comparison | revisions
src/ucx/ucx/string.h file | annotate | diff | comparison | revisions
src/ucx/ucx/ucx.h file | annotate | diff | comparison | revisions
--- a/configure	Tue Aug 25 12:07:56 2020 +0200
+++ b/configure	Sat Oct 24 17:34:32 2020 +0200
@@ -292,6 +292,14 @@
         return 0
     done
 	
+    # dependency openssl 
+    while true
+    do
+        LDFLAGS="$LDFLAGS -lssl -lcrypto"    
+		echo yes
+        return 0
+    done
+	
 	echo no
 	return 1
 }
@@ -360,7 +368,7 @@
     while true
     do
         
-        CFLAGS="$CFLAGS -DBSD"    
+        CFLAGS="$CFLAGS -DBSD -I/usr/local/include"    
         LDFLAGS="$LDFLAGS -lpthread -lm -lldap"    
 		cat >> $TEMP_DIR/make.mk << __EOF__
 # platform dependend source files
@@ -498,7 +506,7 @@
 if [ $ERROR -ne 0 ]; then
 	echo
 	echo "Error: Unresolved dependencies"
-	echo $DEPENCIES_FAILED
+	echo $DEPENDENCIES_FAILED
 	rm -Rf $TEMP_DIR
 	exit 1
 fi
--- a/make/configure.vm	Tue Aug 25 12:07:56 2020 +0200
+++ b/make/configure.vm	Sat Oct 24 17:34:32 2020 +0200
@@ -610,7 +610,7 @@
 if [ $ERROR -ne 0 ]; then
 	echo
 	echo "Error: Unresolved dependencies"
-	echo $DEPENCIES_FAILED
+	echo $DEPENDENCIES_FAILED
 	rm -Rf $TEMP_DIR
 	exit 1
 fi
--- a/make/project.xml	Tue Aug 25 12:07:56 2020 +0200
+++ b/make/project.xml	Sat Oct 24 17:34:32 2020 +0200
@@ -23,7 +23,7 @@
 	</dependency>
 	
 	<dependency platform="bsd" not="macos">
-		<cflags>-DBSD</cflags>
+		<cflags>-DBSD -I/usr/local/include</cflags>
 		<ldflags>-lpthread -lm -lldap</ldflags>
 		<make>
 # platform dependend source files
@@ -73,6 +73,10 @@
 		<pkgconfig>openssl</pkgconfig>
 	</dependency>
 	
+	<dependency name="openssl">
+		<ldflags>-lssl -lcrypto</ldflags>
+	</dependency>
+	
 	<!-- optional dependencies -->
 	<dependency name="libpq">
 		<pkgconfig>libpq</pkgconfig>
--- a/make/toolchain.sh	Tue Aug 25 12:07:56 2020 +0200
+++ b/make/toolchain.sh	Sat Oct 24 17:34:32 2020 +0200
@@ -11,161 +11,171 @@
 
 check_c_compiler()
 {
-    cat > $TEMP_DIR/test.c << __EOF__
+	cat > $TEMP_DIR/test.c << __EOF__
 /* test file */
 #include <stdio.h>
 int main(int argc, char **argv) {
-#if defined(__GNUC__)
-    printf("gcc\n");
-#elif defined(__clang__)
-    printf("clang\n");
+#if defined(__clang__)
+	printf("clang\n");
+#elif defined(__GNUC__)
+	printf("gcc\n");
 #elif defined(__sun)
-    printf("suncc\n");
+	printf("suncc\n");
 #else
-    printf("unknown\n");
+	printf("unknown\n");
 #endif
-    return 0;
+	return 0;
 }
 __EOF__
-    rm -f $TEMP_DIR/checkcc
-    $1 -o $TEMP_DIR/checkcc $CFLAGS $LDFLAGS $TEMP_DIR/test.c 2> /dev/null
-    
-    if [ $? -ne 0 ]; then
-        return 1
-    fi
-    return 0
+	rm -f $TEMP_DIR/checkcc
+	$1 -o $TEMP_DIR/checkcc $CFLAGS $LDFLAGS $TEMP_DIR/test.c 2> /dev/null
+	
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+	return 0
 }
 
 check_cpp_compiler()
 {
-    cat > $TEMP_DIR/test.cpp << __EOF__
+	cat > $TEMP_DIR/test.cpp << __EOF__
 /* test file */
 #include <iostream>
 int main(int argc, char **argv) {
-#if defined(__GNUC__)
-    std::cout << "gcc" << std::endl;
-#elif defined(__clang__)
-    std::cout << "clang" << std::endl;
+#if defined(__clang__)
+	std::cout << "clang" << std::endl;
+#elif defined(__GNUC__)
+	std::cout << "gcc" << std::endl;
 #elif defined(__sun)
 	std::cout << "suncc" << std::endl;
 #else
-    std::cout << "unknown" << std::endl;
+	std::cout << "unknown" << std::endl;
 #endif
-    return 0;
+	return 0;
 }
 __EOF__
-    rm -f $TEMP_DIR/checkcc
-    $1 -o $TEMP_DIR/checkcc $CXXFLAGS $LDFLAGS $TEMP_DIR/test.cpp 2> /dev/null
-    
-    if [ $? -ne 0 ]; then
-        return 1
-    fi
-    return 0
+	rm -f $TEMP_DIR/checkcc
+	$1 -o $TEMP_DIR/checkcc $CXXFLAGS $LDFLAGS $TEMP_DIR/test.cpp 2> /dev/null
+	
+	if [ $? -ne 0 ]; then
+		return 1
+	fi
+	return 0
 }
 
 printf "detect C compiler... "
 
 for COMP in $C_COMPILERS
 do
-    check_c_compiler $COMP
-    if [ $? -ne 0 ]; then
-	    if [ ! -z "$CC" ]; then
-        	if [ $COMP = $CC ]; then
-            	echo "$CC is not a working C Compiler"
-            	TOOLCHAIN_DETECTION_ERROR="error"
-            	break
-        	fi
+	check_c_compiler $COMP
+	if [ $? -ne 0 ]; then
+		if [ ! -z "$CC" ]; then
+			if [ $COMP = $CC ]; then
+				echo "$CC is not a working C Compiler"
+				TOOLCHAIN_DETECTION_ERROR="error"
+				break
+			fi
 		fi
-    else
-        TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
+	else
+		TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
+		USE_TOOLCHAIN=$TOOLCHAIN_NAME
 		if [ $COMP = "cc" ]; then
-		   # we have found a working compiler, but in case
-		   # the compiler is gcc or clang, we try to use
-		   # these commands and not 'cc'
-		   TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
-		   if [ $TOOLCHAIN_NAME = "gcc" ]; then
-		       check_c_compiler "gcc"
-			   if [ $? -eq 0 ]; then
-			       COMP=gcc
-			   fi
-		   fi
-		   if [ $TOOLCHAIN_NAME = "clang" ]; then
-		       check_c_compiler "clang"
-			   if [ $? -eq 0 ]; then
-			       COMP=clang
-			   fi
-		   fi
+			# we have found a working compiler, but in case
+			# the compiler is gcc or clang, we try to use
+			# these commands and not 'cc'
+			TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
+			if [ $TOOLCHAIN_NAME = "gcc" ]; then
+				check_c_compiler "gcc"
+				if [ $? -eq 0 ]; then
+					COMP=gcc
+					USE_TOOLCHAIN="gcc"
+				fi
+			fi
+			if [ $TOOLCHAIN_NAME = "clang" ]; then
+				check_c_compiler "clang"
+				if [ $? -eq 0 ]; then
+					COMP=clang
+					USE_TOOLCHAIN="clang"
+				fi
+			fi
 		fi
 		
-		TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
-        TOOLCHAIN_CC=$COMP
-        echo $COMP
-        break
-    fi
+		TOOLCHAIN_NAME=$USE_TOOLCHAIN
+		TOOLCHAIN_CC=$COMP
+		echo $COMP
+		break
+	fi
 done
 if [ -z $TOOLCHAIN_CC ]; then
-    echo "not found"
+	echo "not found"
 fi
 
 printf "detect C++ compiler... "
 
 for COMP in $CPP_COMPILERS
 do
-    check_cpp_compiler $COMP
-    if [ $? -ne 0 ]; then
+	check_cpp_compiler $COMP
+	if [ $? -ne 0 ]; then
 		if [ ! -z "$CXX" ]; then
-        	if [ $COMP = $CXX ]; then
-                echo "$CC is not a working C++ Compiler"
-                TOOLCHAIN_DETECTION_ERROR="error"
-                break
-            fi
+			if [ $COMP = $CXX ]; then
+				echo "$CC is not a working C++ Compiler"
+				TOOLCHAIN_DETECTION_ERROR="error"
+				break
+			fi
 		fi
-    else
-        if [ $COMP = "CC" ]; then
-		   # we have found a working compiler, but in case
-		   # the compiler is gcc or clang, we try to use
-		   # these commands and not 'cc'
-		   TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
-		   if [ $TOOLCHAIN_NAME = "gcc" ]; then
-		       check_cpp_compiler "g++"
-			   if [ $? -eq 0 ]; then
-			       COMP=g++
-			   fi
-		   fi
-		   if [ $TOOLCHAIN_NAME = "clang" ]; then
-		       check_cpp_compiler "clang++"
-			   if [ $? -eq 0 ]; then
-			       COMP=clang++
-			   fi
-		   fi
+	else
+		if [ $COMP = "CC" ]; then
+			# we have found a working compiler, but in case
+			# the compiler is gcc or clang, we try to use
+			# these commands and not 'cc'
+			TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
+			USE_TOOLCHAIN=$TOOLCHAIN_NAME
+			if [ $TOOLCHAIN_NAME = "gcc" ]; then
+				check_cpp_compiler "g++"
+				if [ $? -eq 0 ]; then
+				   COMP=g++
+				   USE_TOOLCHAIN="gcc"
+				fi
+			fi
+			if [ $TOOLCHAIN_NAME = "clang" ]; then
+				check_cpp_compiler "clang++"
+				if [ $? -eq 0 ]; then
+				   COMP=clang++
+				   USE_TOOLCHAIN="clang"
+				fi
+			fi
 		fi
 		
-		TOOLCHAIN_NAME=`$TEMP_DIR/checkcc`
-        TOOLCHAIN_CXX=$COMP
-        echo $COMP
-        break
-    fi
+		TOOLCHAIN_NAME=$USE_TOOLCHAIN
+		TOOLCHAIN_CXX=$COMP
+		echo $COMP
+		break
+	fi
 done
 if [ -z $TOOLCHAIN_CXX ]; then
-    echo "not found"
+	echo "not found"
 fi
 
 TOOLCHAIN_LD=$TOOLCHAIN_CC
 
 if [ -z "$TOOLCHAIN_NAME" ]; then
-    TOOLCHAIN_DETECTION_ERROR="error"
+	TOOLCHAIN_DETECTION_ERROR="error"
 else
-    cat >> $TEMP_DIR/config.mk << __EOF__
+	cat >> $TEMP_DIR/config.mk << __EOF__
 # toolchain
 __EOF__
 	echo "CC = ${TOOLCHAIN_CC}" >> $TEMP_DIR/config.mk
 	if [ ! -z "$TOOLCHAIN_CXX" ]; then
 		echo "CXX = ${TOOLCHAIN_CXX}" >> $TEMP_DIR/config.mk
 	fi
-    echo "LD = ${TOOLCHAIN_LD}" >> $TEMP_DIR/config.mk
-    
+	echo "LD = ${TOOLCHAIN_LD}" >> $TEMP_DIR/config.mk
+	echo >> $TEMP_DIR/config.mk
+	
 	cat "make/${TOOLCHAIN_NAME}.mk" > /dev/null 2>&1
-    if [ $? -eq 0 ]; then 
-        echo "include \$(BUILD_ROOT)/make/${TOOLCHAIN_NAME}.mk" >> $TEMP_DIR/config.mk
-    fi
+	if [ $? -eq 0 ]; then 
+		echo "include \$(BUILD_ROOT)/make/${TOOLCHAIN_NAME}.mk" >> $TEMP_DIR/config.mk
+	else
+		echo "SHLIB_CFLAGS = -fPIC" >> $TEMP_DIR/config.mk
+		echo "SHLIB_LDFLAGS = -shared" >> $TEMP_DIR/config.mk
+	fi
 fi
--- a/src/server/daemon/acl.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/daemon/acl.c	Sat Oct 24 17:34:32 2020 +0200
@@ -589,7 +589,7 @@
 
 #ifdef BSD
 
-int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) {
+int fs_acl_check(SysACL *acl, User *user, const char *path, uint32_t access_mask) {
     return 1;
 }
 
@@ -608,7 +608,7 @@
 
 #include <sys/fsuid.h>
 
-int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) {
+int fs_acl_check(SysACL *acl, User *user, const char *path, uint32_t access_mask) {
     struct passwd *ws_pw = conf_getglobals()->Vuserpw;
     if(!ws_pw) {
         log_ereport(LOG_FAILURE, "fs_acl_check: unknown webserver uid/gid");
--- a/src/server/daemon/config.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/daemon/config.c	Sat Oct 24 17:34:32 2020 +0200
@@ -140,14 +140,18 @@
     ServerConfiguration *serverconfig = pool_calloc(pool, 1, sizeof(ServerConfiguration));
     serverconfig->ref = 1;
     serverconfig->pool = pool;
-    serverconfig->listeners = NULL;
-    serverconfig->host_vs = ucx_map_new(16);
-    serverconfig->authdbs = ucx_map_new(16);
     
     UcxAllocator allocator = util_pool_allocator(serverconfig->pool);
     serverconfig->a = pool_malloc(pool, sizeof(UcxAllocator));
     *serverconfig->a = allocator;
     
+    serverconfig->listeners = NULL;
+    serverconfig->host_vs = ucx_map_new_a(&allocator, 16);
+    serverconfig->authdbs = ucx_map_new_a(&allocator, 16);
+    serverconfig->resources = ucx_map_new_a(&allocator, 16);
+    
+    
+    
     // TODO: init serverconfig stuff
     
     
--- a/src/server/daemon/config.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/daemon/config.h	Sat Oct 24 17:34:32 2020 +0200
@@ -65,6 +65,7 @@
     AccessLog       *default_log;
     UcxMap          *authdbs;
     MimeMap         *mimetypes;
+    UcxMap          *resources;
     sstr_t          tmp;
     sstr_t          user;
     uint32_t        ref;        // reference counter
--- a/src/server/daemon/event_bsd.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/daemon/event_bsd.c	Sat Oct 24 17:34:32 2020 +0200
@@ -122,6 +122,30 @@
     return kevent(h->kqueue, &kev, 1, NULL, 0, NULL);
 }
 
+int ev_remove_poll(EventHandler *h, int fd) {
+    // TODO:
+    return 0;
+}
+
 int event_send(EventHandler *h, Event *event) {
     return 0;
 }
+
+// TODO: remove this fake aio
+int ev_aioread(int fd, aiocb_s *cb) {
+    ssize_t result = pread(fd, cb->buf, cb->nbytes, cb->offset);
+    cb->result = result;
+    if(result < 0) {
+        cb->result_errno = errno;
+    }
+    return event_send(cb->evhandler, cb->event);
+}
+
+int ev_aiowrite(int fd, aiocb_s *cb) {
+    ssize_t result = pwrite(fd, cb->buf, cb->nbytes, cb->offset);
+    cb->result = result;
+    if(result < 0) {
+        cb->result_errno = errno;
+    }
+    return event_send(cb->evhandler, cb->event);
+}
--- a/src/server/daemon/objs.mk	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/daemon/objs.mk	Sat Oct 24 17:34:32 2020 +0200
@@ -56,6 +56,7 @@
 DAEMONOBJ += acl.o
 DAEMONOBJ += acldata.o
 DAEMONOBJ += vfs.o
+DAEMONOBJ += resourcepool.o
 
 # add additional platform dependend objects
 # defined in generated config.mk
--- a/src/server/daemon/request.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/daemon/request.h	Sat Oct 24 17:34:32 2020 +0200
@@ -32,6 +32,8 @@
 #include "../public/nsapi.h"
 #include "../util/object.h"
 
+#include <ucx/map.h>
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -46,6 +48,7 @@
     uint16_t       port;
     NSAPIContext   context;
     void           *jvm_context;
+    UcxMap         *resources;
 };
 
 /* macros for context access */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/resourcepool.c	Sat Oct 24 17:34:32 2020 +0200
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2020 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 "resourcepool.h"
+#include "request.h"
+#include "session.h"
+
+ResourceData* resourcepool_lookup(Session *sn, Request *rq, const char *name, int flags) {
+    NSAPIRequest *request = (NSAPIRequest*)rq;
+    NSAPISession *session = (NSAPISession*)sn;
+    ServerConfiguration *cfg = session->config;
+    
+    ResourceDataPrivate *res = NULL;
+    
+    // was this resource already used by this request?
+    if(request->resources) {
+        res = ucx_map_cstr_get(request->resources, name);
+        if(res) {
+            return (ResourceData*)res;
+        }
+    }
+    
+    // TODO: get cached resource
+    
+    ResourceType *type = ucx_map_cstr_get(cfg->resources, name);
+    if(!type) {
+        return NULL;
+    }
+}
+
+void resourcepool_free(ResourceData *data) {
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/resourcepool.h	Sat Oct 24 17:34:32 2020 +0200
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2020 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WS_RESOURCEPOOL_H
+#define WS_RESOURCEPOOL_H
+
+#include "../public/nsapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ResourcePool        ResourcePool;
+typedef struct ResourceDataPrivate ResourceDataPrivate;
+
+struct ResourceDataPrivate {
+    ResourceData data;
+    Request      *rq;
+    ResourceType *type;
+};
+
+struct ResourcePool {
+    ResourceType *type;
+    
+    
+    
+    int min;
+    int max;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WS_RESOURCEPOOL_H */
+
--- a/src/server/public/nsapi.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/server/public/nsapi.h	Sat Oct 24 17:34:32 2020 +0200
@@ -767,6 +767,22 @@
 
 typedef struct _http_listener HttpListener;
 
+typedef struct ResourceType ResourceType;
+typedef struct ResourceData    ResourceData;
+
+struct ResourceType {
+    ResourceType * (*init)(pool_handle_t *, pblock *);
+    void           (*destroy)(ResourceType *);
+    
+    void *         (*createresource)(ResourceType *, pblock *);
+    void           (*freeresource)(ResourceType *, void *);
+};
+
+struct ResourceData {
+    void *data;
+};
+
+
 //////
 /*
  * VSInitFunc, VSDestroyFunc, VSDirectiveInitFunc and VSDirectiveDestroyFunc
@@ -1581,6 +1597,10 @@
 int event_removepoll(EventHandler *ev, SYS_NETFD fd);
 int event_send(EventHandler *ev, Event *event);
 
+// resource pool
+ResourceData* resourcepool_lookup(Session *sn, Request *rq, const char *name, int flags);
+void resourcepool_free(ResourceData *data);
+
 // assert
 void ws_log_assert(const char *file, const char *func, int line);
 #ifdef _DEBUG
--- a/src/ucx/array.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/array.c	Sat Oct 24 17:34:32 2020 +0200
@@ -70,7 +70,7 @@
 }
 
 int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity,
-    size_t elmsize, size_t index, ...) {
+    size_t elmsize, size_t index, void* data) {
     
     if(!alloc || !capacity || !array) {
         errno = EINVAL;
@@ -104,16 +104,18 @@
     
     char* dest = *array;
     dest += elmsize*index;
-
-    va_list ap;
-    va_start(ap, index);
-    int elem = va_arg(ap, int);    
-    memcpy(dest, &elem, elmsize);
-    va_end(ap);
+    memcpy(dest, data, elmsize);
     
     return 0;
 }
 
+int ucx_array_util_setptr_a(UcxAllocator* alloc, void** array, size_t* capacity,
+    size_t index, void* data) {
+    
+    return ucx_array_util_set_a(alloc, array, capacity, sizeof(void*),
+            index, &data);
+}
+
 UcxArray* ucx_array_new(size_t capacity, size_t elemsize) {
     return ucx_array_new_a(capacity, elemsize, ucx_default_allocator());
 }
@@ -254,33 +256,6 @@
     return 0;
 }
 
-int ucx_array_appendv(UcxArray *array, ...) {
-    va_list ap;
-    va_start(ap, array);
-    int elem = va_arg(ap, int);
-    int ret = ucx_array_append_from(array, &elem, 1);
-    va_end(ap);
-    return ret;
-}
-
-int ucx_array_prependv(UcxArray *array, ...) {
-    va_list ap;
-    va_start(ap, array);
-    int elem = va_arg(ap, int);
-    int ret = ucx_array_prepend_from(array, &elem, 1);
-    va_end(ap);
-    return ret;
-}
-
-int ucx_array_setv(UcxArray *array, size_t index, ...) {
-    va_list ap;
-    va_start(ap, index);
-    int elem = va_arg(ap, int);
-    int ret = ucx_array_set_from(array, index, &elem, 1);
-    va_end(ap);
-    return ret;
-}
-
 int ucx_array_concat(UcxArray *array1, const UcxArray *array2) {
     
     if (array1->elemsize != array2->elemsize)
@@ -404,7 +379,7 @@
 };
 
 static int cmp_func_swap_args(void *data, const void *x, const void *y) {
-    cmpfnc_swapargs_info* info = data;
+    struct cmpfnc_swapargs_info* info = data;
     return info->func(x, y, info->data);
 }
 
@@ -486,3 +461,7 @@
         }
     }
 }
+
+int ucx_array_grow(UcxArray* array, size_t count) {
+    return ucx_array_reserve(array, array->size+count);
+}
--- a/src/ucx/list.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/list.c	Sat Oct 24 17:34:32 2020 +0200
@@ -28,11 +28,11 @@
 
 #include "ucx/list.h"
 
-UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) {
+UcxList *ucx_list_clone(const 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,
+UcxList *ucx_list_clone_a(UcxAllocator *alloc, const UcxList *l,
         copy_func fnc, void *data) {
     UcxList *ret = NULL;
     while (l) {
@@ -172,7 +172,8 @@
     return (UcxList*)(index == 0 ? e : NULL);
 }
 
-ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) {
+ssize_t ucx_list_find(const UcxList *l, void *elem,
+        cmp_func fnc, void *cmpdata) {
     ssize_t index = 0;
     UCX_FOREACH(e, l) {
         if (fnc) {
@@ -189,7 +190,8 @@
     return -1;
 }
 
-int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) {
+int ucx_list_contains(const UcxList *l, void *elem,
+        cmp_func fnc, void *cmpdata) {
     return ucx_list_find(l, elem, fnc, cmpdata) > -1;
 }
 
@@ -334,3 +336,93 @@
     alfree(alloc, e);
     return l;
 }
+
+
+static UcxList* ucx_list_setoperation_a(UcxAllocator *allocator,
+        UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata,
+        int op) {
+    
+    UcxList *res = NULL;
+    UcxList *cur = NULL;
+    const UcxList *src = left;
+    
+    do {
+        UCX_FOREACH(node, src) {
+            void* elem = node->data;
+            if (
+                (op == 0 && !ucx_list_contains(res, elem, cmpfnc, cmpdata)) ||
+                (op == 1 && ucx_list_contains(right, elem, cmpfnc, cmpdata)) ||
+                (op == 2 && !ucx_list_contains(right, elem, cmpfnc, cmpdata))) {
+                UcxList *nl = almalloc(allocator, sizeof(UcxList));
+                nl->prev = cur;
+                nl->next = NULL;
+                if (cpfnc) {
+                    nl->data = cpfnc(elem, cpdata);
+                } else {
+                    nl->data = elem;
+                }
+                if (cur != NULL)
+                    cur->next = nl;
+                cur = nl;
+                if (res == NULL)
+                    res = cur;
+            }
+        }
+        if (op == 0 && src == left)
+            src = right;
+        else
+            src = NULL;
+    } while (src != NULL);
+    
+    return res;
+}
+
+UcxList* ucx_list_union(UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata) {
+    return ucx_list_union_a(ucx_default_allocator(),
+            left, right, cmpfnc, cmpdata, cpfnc, cpdata);
+}
+
+UcxList* ucx_list_union_a(UcxAllocator *allocator,
+        UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata) {
+    
+    return ucx_list_setoperation_a(allocator, left, right,
+            cmpfnc, cmpdata, cpfnc, cpdata, 0);
+}
+
+UcxList* ucx_list_intersection(UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata) {
+    return ucx_list_intersection_a(ucx_default_allocator(), left, right,
+            cmpfnc, cmpdata, cpfnc, cpdata);
+}
+
+UcxList* ucx_list_intersection_a(UcxAllocator *allocator,
+        UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata) {
+    
+    return ucx_list_setoperation_a(allocator, left, right,
+            cmpfnc, cmpdata, cpfnc, cpdata, 1);
+}
+
+UcxList* ucx_list_difference(UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata) {
+    return ucx_list_difference_a(ucx_default_allocator(), left, right,
+            cmpfnc, cmpdata, cpfnc, cpdata);
+}
+
+UcxList* ucx_list_difference_a(UcxAllocator *allocator,
+        UcxList const *left, UcxList const *right,
+        cmp_func cmpfnc, void* cmpdata,
+        copy_func cpfnc, void* cpdata) {
+    
+    return ucx_list_setoperation_a(allocator, left, right,
+            cmpfnc, cmpdata, cpfnc, cpdata, 2);
+}
--- a/src/ucx/logging.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/logging.c	Sat Oct 24 17:34:32 2020 +0200
@@ -91,6 +91,10 @@
             k += strftime(msg+k, 128, logger->dateformat, localtime(&now));
         }
         if ((logger->mask & UCX_LOGGER_SOURCE) > 0) {
+            char *fpart = strrchr(file, '/');
+            if (fpart) file = fpart+1;
+            fpart = strrchr(file, '\\');
+            if (fpart) file = fpart+1;
             n = strlen(file);
             memcpy(msg+k, file, n);
             k += n;
--- a/src/ucx/map.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/map.c	Sat Oct 24 17:34:32 2020 +0200
@@ -103,7 +103,7 @@
     map->count = 0;
 }
 
-int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data) {
+int ucx_map_copy(UcxMap const *from, UcxMap *to, copy_func fnc, void *data) {
     UcxMapIterator i = ucx_map_iterator(from);
     void *value;
     UCX_MAP_FOREACH(key, value, i) {
@@ -114,9 +114,14 @@
     return 0;
 }
 
-UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) {
+UcxMap *ucx_map_clone(UcxMap const *map, copy_func fnc, void *data) {
+    return ucx_map_clone_a(ucx_default_allocator(), map, fnc, data);
+}
+
+UcxMap *ucx_map_clone_a(UcxAllocator *allocator,
+        UcxMap const *map, copy_func fnc, void *data) {
     size_t bs = (map->count * 5) >> 1;
-    UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size);
+    UcxMap *newmap = ucx_map_new_a(allocator, bs > map->size ? bs : map->size);
     if (!newmap) {
         return NULL;
     }
@@ -235,8 +240,8 @@
     return NULL;
 }
 
-void *ucx_map_get(UcxMap *map, UcxKey key) {
-    return ucx_map_get_and_remove(map, key, 0);
+void *ucx_map_get(UcxMap const *map, UcxKey key) {
+    return ucx_map_get_and_remove((UcxMap *)map, key, 0);
 }
 
 void *ucx_map_remove(UcxMap *map, UcxKey key) {
@@ -294,7 +299,7 @@
     return h;
 }
 
-UcxMapIterator ucx_map_iterator(UcxMap *map) {
+UcxMapIterator ucx_map_iterator(UcxMap const *map) {
     UcxMapIterator i;
     i.map = map;
     i.cur = NULL;
@@ -335,3 +340,63 @@
     return 0;
 }
 
+UcxMap* ucx_map_union(const UcxMap *first, const UcxMap *second,
+                      copy_func cpfnc, void* cpdata) {
+    return ucx_map_union_a(ucx_default_allocator(),
+            first, second, cpfnc, cpdata);
+}
+
+UcxMap* ucx_map_union_a(UcxAllocator *allocator,
+                        const UcxMap *first, const UcxMap *second,
+                        copy_func cpfnc, void* cpdata) {
+    UcxMap* result = ucx_map_clone_a(allocator, first, cpfnc, cpdata);
+    ucx_map_copy(second, result, cpfnc, cpdata);
+    return result;
+}
+
+UcxMap* ucx_map_intersection(const UcxMap *first, const UcxMap *second,
+                             copy_func cpfnc, void* cpdata) {
+    return ucx_map_intersection_a(ucx_default_allocator(),
+            first, second, cpfnc, cpdata);
+}
+
+UcxMap* ucx_map_intersection_a(UcxAllocator *allocator,
+                               const UcxMap *first, const UcxMap *second,
+                               copy_func cpfnc, void* cpdata) {
+    UcxMap *result = ucx_map_new_a(allocator, first->size < second->size ?
+            first->size : second->size);
+
+    UcxMapIterator iter = ucx_map_iterator(first);
+    void* value;
+    UCX_MAP_FOREACH(key, value, iter) {
+        if (ucx_map_get(second, key)) {
+            ucx_map_put(result, key, cpfnc ? cpfnc(value, cpdata) : value);
+        }
+    }
+
+    return result;
+}
+
+UcxMap* ucx_map_difference(const UcxMap *first, const UcxMap *second,
+                           copy_func cpfnc, void* cpdata) {
+    return ucx_map_difference_a(ucx_default_allocator(),
+            first, second, cpfnc, cpdata);
+}
+
+UcxMap* ucx_map_difference_a(UcxAllocator *allocator,
+                             const UcxMap *first, const UcxMap *second,
+                             copy_func cpfnc, void* cpdata) {
+
+    UcxMap *result = ucx_map_new_a(allocator, first->size - second->count);
+
+    UcxMapIterator iter = ucx_map_iterator(first);
+    void* value;
+    UCX_MAP_FOREACH(key, value, iter) {
+        if (!ucx_map_get(second, key)) {
+            ucx_map_put(result, key, cpfnc ? cpfnc(value, cpdata) : value);
+        }
+    }
+
+    ucx_map_rehash(result);
+    return result;
+}
\ No newline at end of file
--- a/src/ucx/string.c	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/string.c	Sat Oct 24 17:34:32 2020 +0200
@@ -662,6 +662,136 @@
     return ret;
 }
 
+#define REPLACE_INDEX_BUFFER_MAX 100
+
+struct scstrreplace_ibuf {
+    size_t* buf;
+    unsigned int len; /* small indices */
+    struct scstrreplace_ibuf* next;
+};
+
+static void scstrrepl_free_ibuf(struct scstrreplace_ibuf *buf) {
+    while (buf) {
+        struct scstrreplace_ibuf *next = buf->next;
+        free(buf->buf);
+        free(buf);
+        buf = next;
+    }
+}
+
+sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str,
+                     scstr_t pattern, scstr_t replacement, size_t replmax) {
+
+    if (pattern.length == 0 || pattern.length > str.length || replmax == 0)
+        return sstrdup(str);
+
+    /* Compute expected buffer length */
+    size_t ibufmax = str.length / pattern.length;
+    size_t ibuflen = replmax < ibufmax ? replmax : ibufmax;
+    if (ibuflen > REPLACE_INDEX_BUFFER_MAX) {
+        ibuflen = REPLACE_INDEX_BUFFER_MAX;
+    }
+
+    /* Allocate first index buffer */
+    struct scstrreplace_ibuf *firstbuf, *curbuf;
+    firstbuf = curbuf = calloc(1, sizeof(struct scstrreplace_ibuf));
+    if (!firstbuf) return sstrn(NULL, 0);
+    firstbuf->buf = calloc(ibuflen, sizeof(size_t));
+    if (!firstbuf->buf) {
+        free(firstbuf);
+        return sstrn(NULL, 0);
+    }
+
+    /* Search occurrences */
+    scstr_t searchstr = str;
+    size_t found = 0;
+    do {
+        scstr_t match = scstrscstr(searchstr, pattern);
+        if (match.length > 0) {
+            /* Allocate next buffer in chain, if required */
+            if (curbuf->len == ibuflen) {
+                struct scstrreplace_ibuf *nextbuf =
+                        calloc(1, sizeof(struct scstrreplace_ibuf));
+                if (!nextbuf) {
+                    scstrrepl_free_ibuf(firstbuf);
+                    return sstrn(NULL, 0);
+                }
+                nextbuf->buf = calloc(ibuflen, sizeof(size_t));
+                if (!nextbuf->buf) {
+                    free(nextbuf);
+                    scstrrepl_free_ibuf(firstbuf);
+                    return sstrn(NULL, 0);
+                }
+                curbuf->next = nextbuf;
+                curbuf = nextbuf;
+            }
+
+            /* Record match index */
+            found++;
+            size_t idx = match.ptr - str.ptr;
+            curbuf->buf[curbuf->len++] = idx;
+            searchstr.ptr = match.ptr + pattern.length;
+            searchstr.length = str.length - idx - pattern.length;
+        } else {
+            break;
+        }
+    } while (searchstr.length > 0 && found < replmax);
+
+    /* Allocate result string */
+    sstr_t result;
+    {
+        ssize_t adjlen = (ssize_t) replacement.length - (ssize_t) pattern.length;
+        size_t rcount = 0;
+        curbuf = firstbuf;
+        do {
+            rcount += curbuf->len;
+            curbuf = curbuf->next;
+        } while (curbuf);
+        result.length = str.length + rcount * adjlen;
+        result.ptr = almalloc(allocator, result.length);
+        if (!result.ptr) {
+            scstrrepl_free_ibuf(firstbuf);
+            return sstrn(NULL, 0);
+        }
+    }
+
+    /* Build result string */
+    curbuf = firstbuf;
+    size_t srcidx = 0;
+    char* destptr = result.ptr;
+    do {
+        for (size_t i = 0; i < curbuf->len; i++) {
+            /* Copy source part up to next match*/
+            size_t idx = curbuf->buf[i];
+            size_t srclen = idx - srcidx;
+            if (srclen > 0) {
+                memcpy(destptr, str.ptr+srcidx, srclen);
+                destptr += srclen;
+                srcidx += srclen;
+            }
+
+            /* Copy the replacement and skip the source pattern */
+            srcidx += pattern.length;
+            memcpy(destptr, replacement.ptr, replacement.length);
+            destptr += replacement.length;
+        }
+        curbuf = curbuf->next;
+    } while (curbuf);
+    memcpy(destptr, str.ptr+srcidx, str.length-srcidx);
+
+    /* Free index buffer */
+    scstrrepl_free_ibuf(firstbuf);
+
+    return result;
+}
+
+sstr_t scstrreplacen(scstr_t str, scstr_t pattern,
+        scstr_t replacement, size_t replmax) {
+    return scstrreplacen_a(ucx_default_allocator(),
+            str, pattern, replacement, replmax);
+}
+
+
 // type adjustment functions
 scstr_t ucx_sc2sc(scstr_t str) {
     return str;
--- a/src/ucx/ucx/array.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/ucx/array.h	Sat Oct 24 17:34:32 2020 +0200
@@ -71,6 +71,7 @@
 
 /**
  * Sets an element in an arbitrary user defined array.
+ * The data is copied from the specified data location.
  * 
  * If the capacity is insufficient, the array is automatically reallocated and
  * the possibly new pointer is stored in the <code>array</code> argument.
@@ -82,7 +83,7 @@
  * @param capacity a pointer to the capacity
  * @param elmsize the size of each element
  * @param idx the index of the element to set
- * @param data the element data
+ * @param data a pointer to the element data
  * @return zero on success or non-zero on error (errno will be set)
  */
 #define ucx_array_util_set(array, capacity, elmsize, idx, data) \
@@ -90,22 +91,8 @@
                          elmsize, idx, data)
 
 /**
- * Convenience macro for ucx_array_util_set() which automatically computes
- * <code>sizeof(data)</code>.
- * 
- * @param array a pointer to location of the array pointer
- * @param capacity a pointer to the capacity
- * @param idx the index of the element to set
- * @param data the element data
- * @return zero on success or non-zero on error (errno will be set)
- * @see ucx_array_util_set()
- */
-#define UCX_ARRAY_UTIL_SET(array, capacity, idx, data) \
-    ucx_array_util_set_a(ucx_default_allocator(), (void**)(array), capacity, \
-                         sizeof(data), idx, data)
-
-/**
  * Sets an element in an arbitrary user defined array.
+ * The data is copied from the specified data location.
  * 
  * If the capacity is insufficient, the array is automatically reallocated
  * using the specified allocator and the possibly new pointer is stored in
@@ -119,27 +106,53 @@
  * @param capacity a pointer to the capacity
  * @param elmsize the size of each element
  * @param idx the index of the element to set
- * @param ... the element data
+ * @param data a pointer to the element data
  * @return zero on success or non-zero on error (errno will be set)
  */
 int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity,
-    size_t elmsize, size_t idx, ...);
-
+    size_t elmsize, size_t idx, void* data);
 
 /**
- * Convenience macro for ucx_array_util_set_a() which automatically computes
- * <code>sizeof(data)</code>.
+ * Stores a pointer in an arbitrary user defined array.
+ * The element size of the array must be sizeof(void*).
+ * 
+ * If the capacity is insufficient, the array is automatically reallocated and
+ * the possibly new pointer is stored in the <code>array</code> argument.
+ * 
+ * On reallocation the capacity of the array is doubled until it is sufficient.
+ * The new capacity is stored back to <code>capacity</code>.
+ *  
+ * @param array a pointer to location of the array pointer
+ * @param capacity a pointer to the capacity
+ * @param idx the index of the element to set
+ * @param ptr the pointer to store
+ * @return zero on success or non-zero on error (errno will be set)
+ */
+#define ucx_array_util_setptr(array, capacity, idx, ptr) \
+    ucx_array_util_setptr_a(ucx_default_allocator(), (void**)(array), \
+                            capacity, idx, ptr)
+
+/**
+ * Stores a pointer in an arbitrary user defined array.
+ * The element size of the array must be sizeof(void*).
+ * 
+ * If the capacity is insufficient, the array is automatically reallocated
+ * using the specified allocator and the possibly new pointer is stored in
+ * the <code>array</code> argument.
+ * 
+ * On reallocation the capacity of the array is doubled until it is sufficient.
+ * The new capacity is stored back to <code>capacity</code>. 
  * 
  * @param alloc the allocator that shall be used to reallocate the array
  * @param array a pointer to location of the array pointer
  * @param capacity a pointer to the capacity
  * @param idx the index of the element to set
- * @param data the element data
+ * @param ptr the pointer to store
  * @return zero on success or non-zero on error (errno will be set)
- * @see ucx_array_util_set_a()
  */
-#define UCX_ARRAY_UTIL_SET_A(alloc, array, capacity, idx, data) \
-    ucx_array_util_set_a(alloc, capacity, sizeof(data), idx, data)
+int ucx_array_util_setptr_a(UcxAllocator* alloc, void** array, size_t* capacity,
+    size_t idx, void* ptr);
+
 
 /**
  * Creates a new UCX array with the given capacity and element size.
@@ -291,88 +304,6 @@
 int ucx_array_set_from(UcxArray *array, size_t index, void *data, size_t count);
 
 /**
- * Inserts an element at the end of the array.
- * 
- * This is an O(1) operation.
- * The array will automatically grow, if the capacity is exceeded.
- * If the type of the argument has a different size than the element size of
- * this array, the behavior is undefined.
- * 
- * @param array a pointer the array where to append the data
- * @param elem the value to insert
- * @return zero on success, non-zero if a reallocation was necessary but failed
- * @see ucx_array_append_from()
- * @see ucx_array_set()
- */
-#define ucx_array_append(array, elem) ucx_array_appendv(array, elem)
-
-/**
- * For internal use.
- * Use ucx_array_append()
- * 
- * @param array
- * @param ... 
- * @return 
- * @see ucx_array_append()
- */
-int ucx_array_appendv(UcxArray *array, ...);
-
-
-/**
- * Inserts an element at the beginning of the array.
- * 
- * This is an expensive operation, because the contents must be moved.
- * If there is no particular reason to prepend data, you should use
- * ucx_array_append() instead.
- * 
- * @param array a pointer the array where to prepend the data
- * @param elem the value to insert
- * @return zero on success, non-zero if a reallocation was necessary but failed
- * @see ucx_array_append()
- * @see ucx_array_set_from()
- * @see ucx_array_prepend_from()
- */
-#define ucx_array_prepend(array, elem) ucx_array_prependv(array, elem)
-
-/**
- * For internal use.
- * Use ucx_array_prepend()
- * 
- * @param array
- * @param ... 
- * @return 
- * @see ucx_array_prepend()
- */
-int ucx_array_prependv(UcxArray *array, ...);
-
-
-/**
- * Sets an element at the specified index.
- * 
- * If the any index is out of bounds, the array automatically grows.
- * 
- * @param array a pointer the array where to set the data
- * @param index the index of the element to set
- * @param elem the value to set
- * @return zero on success, non-zero if a reallocation was necessary but failed
- * @see ucx_array_append()
- * @see ucx_array_set_from()
- */
-#define ucx_array_set(array, index, elem) ucx_array_setv(array, index, elem)
-
-/**
- * For internal use.
- * Use ucx_array_set()
- * 
- * @param array
- * @param index
- * @param ... 
- * @return 
- * @see ucx_array_set()
- */
-int ucx_array_setv(UcxArray *array, size_t index, ...);
-
-/**
  * Concatenates two arrays.
  * 
  * The contents of the second array are appended to the first array in one
@@ -507,6 +438,18 @@
  */
 int ucx_array_reserve(UcxArray* array, size_t capacity);
 
+/**
+ * Resizes the capacity, if the specified number of elements would not fit.
+ * 
+ * A call to ucx_array_grow(array, count) is effectively the same as
+ * ucx_array_reserve(array, array->size+count).
+ * 
+ * @param array a pointer to the array
+ * @param count the number of elements that should additionally fit
+ * into the array
+ * @return zero on success, non-zero if reallocation failed
+ */
+int ucx_array_grow(UcxArray* array, size_t count);
 
 
 #ifdef	__cplusplus
--- a/src/ucx/ucx/list.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/ucx/list.h	Sat Oct 24 17:34:32 2020 +0200
@@ -57,7 +57,7 @@
  * @param elem The variable name of the element
  */
 #define UCX_FOREACH(elem,list) \
-        for (UcxList* elem = list ; elem != NULL ; elem = elem->next)
+        for (UcxList* elem = (UcxList*) list ; elem != NULL ; elem = elem->next)
 
 /**
  * UCX list type.
@@ -99,7 +99,7 @@
  * @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);
+UcxList *ucx_list_clone(const UcxList *list, copy_func cpyfnc, void* data);
 
 /**
  * Creates an element-wise copy of a list using a UcxAllocator.
@@ -117,7 +117,7 @@
  * @return a pointer to the copy
  * @see ucx_list_clone()
  */
-UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list,
+UcxList *ucx_list_clone_a(UcxAllocator *allocator, const UcxList *list,
         copy_func cpyfnc, void* data);
 
 /**
@@ -328,7 +328,8 @@
  * @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);
+ssize_t ucx_list_find(const UcxList *list, void *elem,
+    cmp_func cmpfnc, void *data);
 
 /**
  * Checks, if a list contains a specific element.
@@ -342,7 +343,8 @@
  * @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);
+int ucx_list_contains(const UcxList *list, void *elem,
+    cmp_func cmpfnc, void *data);
 
 /**
  * Sorts a UcxList with natural merge sort.
@@ -388,6 +390,120 @@
 UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list,
         UcxList *element);
 
+/**
+ * Returns the union of two lists.
+ * 
+ * The union is a list of unique elements regarding cmpfnc obtained from
+ * both source lists.
+ * 
+ * @param left the left source list
+ * @param right the right source list
+ * @param cmpfnc a function to compare elements
+ * @param cmpdata additional data for the compare function
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the union
+ */
+UcxList* ucx_list_union(const UcxList *left, const UcxList *right,
+    cmp_func cmpfnc, void* cmpdata,
+    copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the union of two lists.
+ * 
+ * The union is a list of unique elements regarding cmpfnc obtained from
+ * both source lists.
+ * 
+ * @param allocator allocates the new list elements
+ * @param left the left source list
+ * @param right the right source list
+ * @param cmpfnc a function to compare elements
+ * @param cmpdata additional data for the compare function
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the union
+ */
+UcxList* ucx_list_union_a(UcxAllocator *allocator,
+    const UcxList *left, const UcxList *right,
+    cmp_func cmpfnc, void* cmpdata,
+    copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the intersection of two lists.
+ * 
+ * The intersection contains all elements of the left list
+ * (including duplicates) that can be found in the right list.
+ * 
+ * @param left the left source list
+ * @param right the right source list
+ * @param cmpfnc a function to compare elements
+ * @param cmpdata additional data for the compare function
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the intersection
+ */
+UcxList* ucx_list_intersection(const UcxList *left, const UcxList *right,
+    cmp_func cmpfnc, void* cmpdata,
+    copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the intersection of two lists.
+ * 
+ * The intersection contains all elements of the left list
+ * (including duplicates) that can be found in the right list.
+ * 
+ * @param allocator allocates the new list elements
+ * @param left the left source list
+ * @param right the right source list
+ * @param cmpfnc a function to compare elements
+ * @param cmpdata additional data for the compare function
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the intersection
+ */
+UcxList* ucx_list_intersection_a(UcxAllocator *allocator,
+    const UcxList *left, const UcxList *right,
+    cmp_func cmpfnc, void* cmpdata,
+    copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the difference of two lists.
+ * 
+ * The difference contains all elements of the left list
+ * (including duplicates) that are not equal to any element of the right list.
+ * 
+ * @param left the left source list
+ * @param right the right source list
+ * @param cmpfnc a function to compare elements
+ * @param cmpdata additional data for the compare function
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the difference
+ */
+UcxList* ucx_list_difference(const UcxList *left, const UcxList *right,
+    cmp_func cmpfnc, void* cmpdata,
+    copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the difference of two lists.
+ * 
+ * The difference contains all elements of the left list
+ * (including duplicates) that are not equal to any element of the right list.
+ * 
+ * @param allocator allocates the new list elements
+ * @param left the left source list
+ * @param right the right source list
+ * @param cmpfnc a function to compare elements
+ * @param cmpdata additional data for the compare function
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the difference
+ */
+UcxList* ucx_list_difference_a(UcxAllocator *allocator,
+    const UcxList *left, const UcxList *right,
+    cmp_func cmpfnc, void* cmpdata,
+    copy_func cpfnc, void* cpdata);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/src/ucx/ucx/logging.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/ucx/logging.h	Sat Oct 24 17:34:32 2020 +0200
@@ -160,7 +160,10 @@
  * format is:
  * 
  * <code>[LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message</code>
- * 
+ *
+ * The source file name is reduced to the actual file name. This is necessary to
+ * get consistent behavior over different definitions of the __FILE__ macro.
+ *
  * <b>Attention:</b> the message (including automatically generated information)
  * is limited to 4096 characters. The level description is limited to
  * 256 characters and the timestamp string is limited to 128 characters.
--- a/src/ucx/ucx/map.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/ucx/map.h	Sat Oct 24 17:34:32 2020 +0200
@@ -124,7 +124,7 @@
 /** Structure for an iterator over a UcxMap. */
 struct UcxMapIterator {
     /** The map to iterate over. */
-    UcxMap        *map;
+    UcxMap const  *map;
     
     /** The current map element. */
     UcxMapElement *cur;
@@ -211,7 +211,7 @@
  * @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 *from, UcxMap *to, copy_func fnc, void *data);
+int ucx_map_copy(UcxMap const *from, UcxMap *to, copy_func fnc, void *data);
 
 /**
  * Clones the map and rehashes if necessary.
@@ -227,7 +227,25 @@
  * @return the cloned map
  * @see ucx_map_copy()
  */
-UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data);
+UcxMap *ucx_map_clone(UcxMap const *map, 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 allocator the allocator to use for the cloned map
+ * @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_a(UcxAllocator *allocator,
+                        UcxMap const *map, copy_func fnc, void *data);
 
 /**
  * Increases size of the hash map, if necessary.
@@ -264,7 +282,7 @@
  * @param key the key
  * @return the value
  */
-void* ucx_map_get(UcxMap *map, UcxKey key);
+void* ucx_map_get(UcxMap const *map, UcxKey key);
 
 /**
  * Removes a key/value-pair from the map by using the key.
@@ -276,51 +294,6 @@
 void* ucx_map_remove(UcxMap *map, UcxKey key);
 
 /**
- * Creates a new map containing all elements from the maps a and b.
- * 
- * If a key exists in both maps, the value is taken from map a.
- * 
- * @param a map a
- * @param b map b
- * @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 new union map
- * @see ucx_map_copy()
- */
-UcxMap *ucx_map_union(UcxMap *a, UcxMap *b, copy_func fnc, void *data);
-
-/**
- * intersection
- * 
- * If a key exists in both maps, the value is taken from map a.
- * 
- * @param a map a
- * @param b map b
- * @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 new intersection map
- * @see ucx_map_copy()
- */
-UcxMap *ucx_map_intersection(UcxMap *a, UcxMap *b, copy_func fnc, void *data);
-
-/**
- * relative complement
- * 
- * If a key exists in both maps, the value is taken from map a.
- * 
- * @param a map a
- * @param b map b
- * @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 new intersection map
- * @see ucx_map_copy()
- */
-UcxMap *ucx_map_relcomplement(UcxMap *a, UcxMap *b, copy_func fnc, void *data);
-
-/**
  * Shorthand for putting data with a sstr_t key into the map.
  * @param map the map
  * @param key the key
@@ -451,7 +424,7 @@
  * first element list
  * @see ucx_map_iter_next()
  */
-UcxMapIterator ucx_map_iterator(UcxMap *map);
+UcxMapIterator ucx_map_iterator(UcxMap const *map);
 
 /**
  * Proceeds to the next element of the map (if any).
@@ -471,6 +444,102 @@
  */
 int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value);
 
+/**
+ * Returns the union of two maps.
+ *
+ * The union is a fresh map which is filled by two successive calls of
+ * ucx_map_copy() on the two input maps.
+ *
+ * @param first the first source map
+ * @param second the second source map
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new map containing the union
+ */
+UcxMap* ucx_map_union(const UcxMap *first, const UcxMap *second,
+                      copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the union of two maps.
+ *
+ * The union is a fresh map which is filled by two successive calls of
+ * ucx_map_copy() on the two input maps.
+ *
+ * @param allocator the allocator that shall be used by the new map
+ * @param first the first source map
+ * @param second the second source map
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new map containing the union
+ */
+UcxMap* ucx_map_union_a(UcxAllocator *allocator,
+                        const UcxMap *first, const UcxMap *second,
+                        copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the intersection of two maps.
+ *
+ * The intersection is defined as a copy of the first map with every element
+ * removed that has no valid key in the second map.
+ *
+ * @param first the first source map
+ * @param second the second source map
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new map containing the intersection
+ */
+UcxMap* ucx_map_intersection(const UcxMap *first, const UcxMap *second,
+                             copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the intersection of two maps.
+ *
+ * The intersection is defined as a copy of the first map with every element
+ * removed that has no valid key in the second map.
+ *
+ * @param allocator the allocator that shall be used by the new map
+ * @param first the first source map
+ * @param second the second source map
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new map containing the intersection
+ */
+UcxMap* ucx_map_intersection_a(UcxAllocator *allocator,
+                               const UcxMap *first, const UcxMap *second,
+                               copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the difference of two maps.
+ *
+ * The difference contains a copy of all elements of the first map
+ * for which the corresponding keys cannot be found in the second map.
+ *
+ * @param first the first source map
+ * @param second the second source map
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the difference
+ */
+UcxMap* ucx_map_difference(const UcxMap *first, const UcxMap *second,
+                           copy_func cpfnc, void* cpdata);
+
+/**
+ * Returns the difference of two maps.
+ *
+ * The difference contains a copy of all elements of the first map
+ * for which the corresponding keys cannot be found in the second map.
+ *
+ * @param allocator the allocator that shall be used by the new map
+ * @param first the first source map
+ * @param second the second source map
+ * @param cpfnc a function to copy the elements
+ * @param cpdata additional data for the copy function
+ * @return a new list containing the difference
+ */
+UcxMap* ucx_map_difference_a(UcxAllocator *allocator,
+                             const UcxMap *first, const UcxMap *second,
+                             copy_func cpfnc, void* cpdata);
+
 
 #ifdef	__cplusplus
 }
--- a/src/ucx/ucx/string.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/ucx/string.h	Sat Oct 24 17:34:32 2020 +0200
@@ -1072,6 +1072,128 @@
  */
 #define sstrupper_a(allocator, string) scstrupper_a(allocator, string)
 
+
+/**
+ * Replaces a pattern in a string with another string.
+ *
+ * The pattern is taken literally and is no regular expression.
+ * Replaces at most <code>replmax</code> occurrences.
+ *
+ * The resulting string is allocated by the specified allocator. I.e. it
+ * depends on the used allocator, whether the sstr_t.ptr must be freed
+ * manually.
+ *
+ * If allocation fails, the sstr_t.ptr of the return value is NULL.
+ *
+ * @param allocator the allocator to use
+ * @param str the string where replacements should be applied
+ * @param pattern the pattern to search for
+ * @param replacement the replacement string
+ * @param replmax maximum number of replacements
+ * @return the resulting string after applying the replacements
+ */
+sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str,
+        scstr_t pattern, scstr_t replacement, size_t replmax);
+
+/**
+ * Replaces a pattern in a string with another string.
+ *
+ * The pattern is taken literally and is no regular expression.
+ * Replaces at most <code>replmax</code> occurrences.
+ *
+ * The sstr_t.ptr of the resulting string must be freed manually.
+ *
+ * If allocation fails, the sstr_t.ptr of the return value is NULL.
+ *
+ * @param str the string where replacements should be applied
+ * @param pattern the pattern to search for
+ * @param replacement the replacement string
+ * @param replmax maximum number of replacements
+ * @return the resulting string after applying the replacements
+ */
+sstr_t scstrreplacen(scstr_t str, scstr_t pattern,
+        scstr_t replacement, size_t replmax);
+
+/**
+ * Replaces a pattern in a string with another string.
+ *
+ * The pattern is taken literally and is no regular expression.
+ * Replaces at most <code>replmax</code> occurrences.
+ *
+ * The resulting string is allocated by the specified allocator. I.e. it
+ * depends on the used allocator, whether the sstr_t.ptr must be freed
+ * manually.
+ *
+ * @param allocator the allocator to use
+ * @param str the string where replacements should be applied
+ * @param pattern the pattern to search for
+ * @param replacement the replacement string
+ * @param replmax maximum number of replacements
+ * @return the resulting string after applying the replacements
+ */
+#define sstrreplacen_a(allocator, str, pattern, replacement, replmax) \
+        scstrreplacen_a(allocator, SCSTR(str), SCSTR(pattern), \
+            SCSTR(replacement), replmax)
+
+/**
+ * Replaces a pattern in a string with another string.
+ *
+ * The pattern is taken literally and is no regular expression.
+ * Replaces at most <code>replmax</code> occurrences.
+ *
+ * The sstr_t.ptr of the resulting string must be freed manually.
+ *
+ * If allocation fails, the sstr_t.ptr of the return value is NULL.
+ *
+ * @param str the string where replacements should be applied
+ * @param pattern the pattern to search for
+ * @param replacement the replacement string
+ * @param replmax maximum number of replacements
+ * @return the resulting string after applying the replacements
+ */
+#define sstrreplacen(str, pattern, replacement, replmax) \
+        scstrreplacen(SCSTR(str), SCSTR(pattern), SCSTR(replacement), replmax)
+
+/**
+ * Replaces a pattern in a string with another string.
+ *
+ * The pattern is taken literally and is no regular expression.
+ * Replaces at most <code>replmax</code> occurrences.
+ *
+ * The resulting string is allocated by the specified allocator. I.e. it
+ * depends on the used allocator, whether the sstr_t.ptr must be freed
+ * manually.
+ *
+ * If allocation fails, the sstr_t.ptr of the return value is NULL.
+ *
+ * @param allocator the allocator to use
+ * @param str the string where replacements should be applied
+ * @param pattern the pattern to search for
+ * @param replacement the replacement string
+ * @return the resulting string after applying the replacements
+ */
+#define sstrreplace_a(allocator, str, pattern, replacement) \
+        scstrreplacen_a(allocator, SCSTR(str), SCSTR(pattern), \
+            SCSTR(replacement), SIZE_MAX)
+
+/**
+ * Replaces a pattern in a string with another string.
+ *
+ * The pattern is taken literally and is no regular expression.
+ * Replaces at most <code>replmax</code> occurrences.
+ *
+ * The sstr_t.ptr of the resulting string must be freed manually.
+ *
+ * If allocation fails, the sstr_t.ptr of the return value is NULL.
+ *
+ * @param str the string where replacements should be applied
+ * @param pattern the pattern to search for
+ * @param replacement the replacement string
+ * @return the resulting string after applying the replacements
+ */
+#define sstrreplace(str, pattern, replacement) \
+        scstrreplacen(SCSTR(str), SCSTR(pattern), SCSTR(replacement), SIZE_MAX)
+
 #ifdef	__cplusplus
 }
 #endif
--- a/src/ucx/ucx/ucx.h	Tue Aug 25 12:07:56 2020 +0200
+++ b/src/ucx/ucx/ucx.h	Sat Oct 24 17:34:32 2020 +0200
@@ -170,10 +170,7 @@
 
 /**
  * Performs a multiplication of size_t values and checks for overflow.
- * 
- * This is a custom implementation in case there is no compiler builtin
- * available.
- * 
+  *
  * @param a first operand
  * @param b second operand
  * @param result a pointer to a size_t, where the result should
@@ -183,6 +180,18 @@
  */
 #define ucx_szmul(a, b, result) ucx_szmul_impl(a, b, result)
 
+/**
+ * Performs a multiplication of size_t values and checks for overflow.
+ *
+ * This is a custom implementation in case there is no compiler builtin
+ * available.
+ *
+ * @param a first operand
+ * @param b second operand
+ * @param result a pointer to a size_t where the result should be stored
+ * @return zero, if no overflow occurred and the result is correct, non-zero
+ * otherwise
+ */
 int ucx_szmul_impl(size_t a, size_t b, size_t *result);
 
 #endif

mercurial