# HG changeset patch # User Olaf Wintermann # Date 1603553672 -7200 # Node ID 4779a6fb4fbee50cffa11854e9c80f324c4ea341 # Parent 0b8692959d3708dff17f648a2913dc37ca5cfd0c fix freebsd build diff -r 0b8692959d37 -r 4779a6fb4fbe configure --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe make/configure.vm --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe make/project.xml --- 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 @@ - -DBSD + -DBSD -I/usr/local/include -lpthread -lm -lldap # platform dependend source files @@ -73,6 +73,10 @@ openssl + + -lssl -lcrypto + + libpq diff -r 0b8692959d37 -r 4779a6fb4fbe make/toolchain.sh --- 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 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 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/acl.c --- 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 -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"); diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/config.c --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/config.h --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/event_bsd.c --- 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); +} diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/objs.mk --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/request.h --- 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 + #ifdef __cplusplus extern "C" { #endif @@ -46,6 +48,7 @@ uint16_t port; NSAPIContext context; void *jvm_context; + UcxMap *resources; }; /* macros for context access */ diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/resourcepool.c --- /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) { + +} diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/daemon/resourcepool.h --- /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 */ + diff -r 0b8692959d37 -r 4779a6fb4fbe src/server/public/nsapi.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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/array.c --- 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); +} diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/list.c --- 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); +} diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/logging.c --- 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; diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/map.c --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/string.c --- 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; diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/ucx/array.h --- 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 array 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 - * sizeof(data). - * - * @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 - * sizeof(data). + * 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 array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @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 array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. * * @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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/ucx/list.h --- 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/ucx/logging.h --- 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: * * [LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message - * + * + * 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. + * * Attention: 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. diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/ucx/map.h --- 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. + * + * Note: In contrast to ucx_map_rehash() the load factor is irrelevant. + * This function always 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 NULL 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 NULL 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 NULL 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 NULL 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 } diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/ucx/string.h --- 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 replmax 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 replmax 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 replmax 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 replmax 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 replmax 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 replmax 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 diff -r 0b8692959d37 -r 4779a6fb4fbe src/ucx/ucx/ucx.h --- 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